Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'zxdrm-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into drm-next

ZTE zxdrm driver support for 4.10:

This is the initial ZTE VOU display controller DRM/KMS driver. There
are still some features to be added, like overlay plane, scaling, and
more output devices support. But it's already useful with dual CRTCs
and HDMI display working.

[airlied: use drm_format_plane_cpp instead of legacy api]
* tag 'zxdrm-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
MAINTAINERS: add an entry for ZTE ZX DRM driver
drm: zte: add initial vou drm driver
dt-bindings: add bindings doc for ZTE VOU display controller

+2372
+84
Documentation/devicetree/bindings/display/zte,vou.txt
··· 1 + ZTE VOU Display Controller 2 + 3 + This is a display controller found on ZTE ZX296718 SoC. It includes multiple 4 + Graphic Layer (GL) and Video Layer (VL), two Mixers/Channels, and a few blocks 5 + handling scaling, color space conversion etc. VOU also integrates the support 6 + for typical output devices, like HDMI, TV Encoder, VGA, and RGB LCD. 7 + 8 + * Master VOU node 9 + 10 + It must be the parent node of all the sub-device nodes. 11 + 12 + Required properties: 13 + - compatible: should be "zte,zx296718-vou" 14 + - #address-cells: should be <1> 15 + - #size-cells: should be <1> 16 + - ranges: list of address translations between VOU and sub-devices 17 + 18 + * VOU DPC device 19 + 20 + Required properties: 21 + - compatible: should be "zte,zx296718-dpc" 22 + - reg: Physical base address and length of DPC register regions, one for each 23 + entry in 'reg-names' 24 + - reg-names: The names of register regions. The following regions are required: 25 + "osd" 26 + "timing_ctrl" 27 + "dtrc" 28 + "vou_ctrl" 29 + "otfppu" 30 + - interrupts: VOU DPC interrupt number to CPU 31 + - clocks: A list of phandle + clock-specifier pairs, one for each entry 32 + in 'clock-names' 33 + - clock-names: A list of clock names. The following clocks are required: 34 + "aclk" 35 + "ppu_wclk" 36 + "main_wclk" 37 + "aux_wclk" 38 + 39 + * HDMI output device 40 + 41 + Required properties: 42 + - compatible: should be "zte,zx296718-hdmi" 43 + - reg: Physical base address and length of the HDMI device IO region 44 + - interrupts : HDMI interrupt number to CPU 45 + - clocks: A list of phandle + clock-specifier pairs, one for each entry 46 + in 'clock-names' 47 + - clock-names: A list of clock names. The following clocks are required: 48 + "osc_cec" 49 + "osc_clk" 50 + "xclk" 51 + 52 + Example: 53 + 54 + vou: vou@1440000 { 55 + compatible = "zte,zx296718-vou"; 56 + #address-cells = <1>; 57 + #size-cells = <1>; 58 + ranges = <0 0x1440000 0x10000>; 59 + 60 + dpc: dpc@0 { 61 + compatible = "zte,zx296718-dpc"; 62 + reg = <0x0000 0x1000>, <0x1000 0x1000>, 63 + <0x5000 0x1000>, <0x6000 0x1000>, 64 + <0xa000 0x1000>; 65 + reg-names = "osd", "timing_ctrl", 66 + "dtrc", "vou_ctrl", 67 + "otfppu"; 68 + interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>; 69 + clocks = <&topcrm VOU_ACLK>, <&topcrm VOU_PPU_WCLK>, 70 + <&topcrm VOU_MAIN_WCLK>, <&topcrm VOU_AUX_WCLK>; 71 + clock-names = "aclk", "ppu_wclk", 72 + "main_wclk", "aux_wclk"; 73 + }; 74 + 75 + hdmi: hdmi@c000 { 76 + compatible = "zte,zx296718-hdmi"; 77 + reg = <0xc000 0x4000>; 78 + interrupts = <GIC_SPI 82 IRQ_TYPE_EDGE_RISING>; 79 + clocks = <&topcrm HDMI_OSC_CEC>, 80 + <&topcrm HDMI_OSC_CLK>, 81 + <&topcrm HDMI_XCLK>; 82 + clock-names = "osc_cec", "osc_clk", "xclk"; 83 + }; 84 + };
+7
MAINTAINERS
··· 4298 4298 F: drivers/gpu/drm/tilcdc/ 4299 4299 F: Documentation/devicetree/bindings/display/tilcdc/ 4300 4300 4301 + DRM DRIVERS FOR ZTE ZX 4302 + M: Shawn Guo <shawnguo@kernel.org> 4303 + L: dri-devel@lists.freedesktop.org 4304 + S: Maintained 4305 + F: drivers/gpu/drm/zte/ 4306 + F: Documentation/devicetree/bindings/display/zte,vou.txt 4307 + 4301 4308 DSBR100 USB FM RADIO DRIVER 4302 4309 M: Alexey Klimov <klimov.linux@gmail.com> 4303 4310 L: linux-media@vger.kernel.org
+2
drivers/gpu/drm/Kconfig
··· 237 237 238 238 source "drivers/gpu/drm/mediatek/Kconfig" 239 239 240 + source "drivers/gpu/drm/zte/Kconfig" 241 + 240 242 # Keep legacy drivers last 241 243 242 244 menuconfig DRM_LEGACY
+1
drivers/gpu/drm/Makefile
··· 87 87 obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/ 88 88 obj-$(CONFIG_DRM_ARCPGU)+= arc/ 89 89 obj-y += hisilicon/ 90 + obj-$(CONFIG_DRM_ZTE) += zte/
+8
drivers/gpu/drm/zte/Kconfig
··· 1 + config DRM_ZTE 2 + tristate "DRM Support for ZTE SoCs" 3 + depends on DRM && ARCH_ZX 4 + select DRM_KMS_CMA_HELPER 5 + select DRM_KMS_FB_HELPER 6 + select DRM_KMS_HELPER 7 + help 8 + Choose this option to enable DRM on ZTE ZX SoCs.
+7
drivers/gpu/drm/zte/Makefile
··· 1 + zxdrm-y := \ 2 + zx_drm_drv.o \ 3 + zx_hdmi.o \ 4 + zx_plane.o \ 5 + zx_vou.o 6 + 7 + obj-$(CONFIG_DRM_ZTE) += zxdrm.o
+267
drivers/gpu/drm/zte/zx_drm_drv.c
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #include <linux/clk.h> 12 + #include <linux/component.h> 13 + #include <linux/list.h> 14 + #include <linux/module.h> 15 + #include <linux/of_graph.h> 16 + #include <linux/of_platform.h> 17 + #include <linux/spinlock.h> 18 + 19 + #include <drm/drm_atomic_helper.h> 20 + #include <drm/drm_crtc.h> 21 + #include <drm/drm_crtc_helper.h> 22 + #include <drm/drm_fb_cma_helper.h> 23 + #include <drm/drm_fb_helper.h> 24 + #include <drm/drm_gem_cma_helper.h> 25 + #include <drm/drm_of.h> 26 + #include <drm/drmP.h> 27 + 28 + #include "zx_drm_drv.h" 29 + #include "zx_vou.h" 30 + 31 + struct zx_drm_private { 32 + struct drm_fbdev_cma *fbdev; 33 + }; 34 + 35 + static void zx_drm_fb_output_poll_changed(struct drm_device *drm) 36 + { 37 + struct zx_drm_private *priv = drm->dev_private; 38 + 39 + drm_fbdev_cma_hotplug_event(priv->fbdev); 40 + } 41 + 42 + static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = { 43 + .fb_create = drm_fb_cma_create, 44 + .output_poll_changed = zx_drm_fb_output_poll_changed, 45 + .atomic_check = drm_atomic_helper_check, 46 + .atomic_commit = drm_atomic_helper_commit, 47 + }; 48 + 49 + static void zx_drm_lastclose(struct drm_device *drm) 50 + { 51 + struct zx_drm_private *priv = drm->dev_private; 52 + 53 + drm_fbdev_cma_restore_mode(priv->fbdev); 54 + } 55 + 56 + static const struct file_operations zx_drm_fops = { 57 + .owner = THIS_MODULE, 58 + .open = drm_open, 59 + .release = drm_release, 60 + .unlocked_ioctl = drm_ioctl, 61 + #ifdef CONFIG_COMPAT 62 + .compat_ioctl = drm_compat_ioctl, 63 + #endif 64 + .poll = drm_poll, 65 + .read = drm_read, 66 + .llseek = noop_llseek, 67 + .mmap = drm_gem_cma_mmap, 68 + }; 69 + 70 + static struct drm_driver zx_drm_driver = { 71 + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | 72 + DRIVER_ATOMIC, 73 + .lastclose = zx_drm_lastclose, 74 + .get_vblank_counter = drm_vblank_no_hw_counter, 75 + .enable_vblank = zx_vou_enable_vblank, 76 + .disable_vblank = zx_vou_disable_vblank, 77 + .gem_free_object = drm_gem_cma_free_object, 78 + .gem_vm_ops = &drm_gem_cma_vm_ops, 79 + .dumb_create = drm_gem_cma_dumb_create, 80 + .dumb_map_offset = drm_gem_cma_dumb_map_offset, 81 + .dumb_destroy = drm_gem_dumb_destroy, 82 + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 83 + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 84 + .gem_prime_export = drm_gem_prime_export, 85 + .gem_prime_import = drm_gem_prime_import, 86 + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 87 + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 88 + .gem_prime_vmap = drm_gem_cma_prime_vmap, 89 + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 90 + .gem_prime_mmap = drm_gem_cma_prime_mmap, 91 + .fops = &zx_drm_fops, 92 + .name = "zx-vou", 93 + .desc = "ZTE VOU Controller DRM", 94 + .date = "20160811", 95 + .major = 1, 96 + .minor = 0, 97 + }; 98 + 99 + static int zx_drm_bind(struct device *dev) 100 + { 101 + struct drm_device *drm; 102 + struct zx_drm_private *priv; 103 + int ret; 104 + 105 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 106 + if (!priv) 107 + return -ENOMEM; 108 + 109 + drm = drm_dev_alloc(&zx_drm_driver, dev); 110 + if (!drm) 111 + return -ENOMEM; 112 + 113 + drm->dev_private = priv; 114 + dev_set_drvdata(dev, drm); 115 + 116 + drm_mode_config_init(drm); 117 + drm->mode_config.min_width = 16; 118 + drm->mode_config.min_height = 16; 119 + drm->mode_config.max_width = 4096; 120 + drm->mode_config.max_height = 4096; 121 + drm->mode_config.funcs = &zx_drm_mode_config_funcs; 122 + 123 + ret = component_bind_all(dev, drm); 124 + if (ret) { 125 + DRM_DEV_ERROR(dev, "failed to bind all components: %d\n", ret); 126 + goto out_unregister; 127 + } 128 + 129 + ret = drm_vblank_init(drm, drm->mode_config.num_crtc); 130 + if (ret < 0) { 131 + DRM_DEV_ERROR(dev, "failed to init vblank: %d\n", ret); 132 + goto out_unbind; 133 + } 134 + 135 + /* 136 + * We will manage irq handler on our own. In this case, irq_enabled 137 + * need to be true for using vblank core support. 138 + */ 139 + drm->irq_enabled = true; 140 + 141 + drm_mode_config_reset(drm); 142 + drm_kms_helper_poll_init(drm); 143 + 144 + priv->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc, 145 + drm->mode_config.num_connector); 146 + if (IS_ERR(priv->fbdev)) { 147 + ret = PTR_ERR(priv->fbdev); 148 + DRM_DEV_ERROR(dev, "failed to init cma fbdev: %d\n", ret); 149 + priv->fbdev = NULL; 150 + goto out_poll_fini; 151 + } 152 + 153 + ret = drm_dev_register(drm, 0); 154 + if (ret) 155 + goto out_fbdev_fini; 156 + 157 + return 0; 158 + 159 + out_fbdev_fini: 160 + if (priv->fbdev) { 161 + drm_fbdev_cma_fini(priv->fbdev); 162 + priv->fbdev = NULL; 163 + } 164 + out_poll_fini: 165 + drm_kms_helper_poll_fini(drm); 166 + drm_mode_config_cleanup(drm); 167 + drm_vblank_cleanup(drm); 168 + out_unbind: 169 + component_unbind_all(dev, drm); 170 + out_unregister: 171 + dev_set_drvdata(dev, NULL); 172 + drm->dev_private = NULL; 173 + drm_dev_unref(drm); 174 + return ret; 175 + } 176 + 177 + static void zx_drm_unbind(struct device *dev) 178 + { 179 + struct drm_device *drm = dev_get_drvdata(dev); 180 + struct zx_drm_private *priv = drm->dev_private; 181 + 182 + drm_dev_unregister(drm); 183 + if (priv->fbdev) { 184 + drm_fbdev_cma_fini(priv->fbdev); 185 + priv->fbdev = NULL; 186 + } 187 + drm_kms_helper_poll_fini(drm); 188 + drm_mode_config_cleanup(drm); 189 + drm_vblank_cleanup(drm); 190 + component_unbind_all(dev, drm); 191 + dev_set_drvdata(dev, NULL); 192 + drm->dev_private = NULL; 193 + drm_dev_unref(drm); 194 + } 195 + 196 + static const struct component_master_ops zx_drm_master_ops = { 197 + .bind = zx_drm_bind, 198 + .unbind = zx_drm_unbind, 199 + }; 200 + 201 + static int compare_of(struct device *dev, void *data) 202 + { 203 + return dev->of_node == data; 204 + } 205 + 206 + static int zx_drm_probe(struct platform_device *pdev) 207 + { 208 + struct device *dev = &pdev->dev; 209 + struct device_node *parent = dev->of_node; 210 + struct device_node *child; 211 + struct component_match *match = NULL; 212 + int ret; 213 + 214 + ret = of_platform_populate(parent, NULL, NULL, dev); 215 + if (ret) 216 + return ret; 217 + 218 + for_each_available_child_of_node(parent, child) { 219 + component_match_add(dev, &match, compare_of, child); 220 + of_node_put(child); 221 + } 222 + 223 + return component_master_add_with_match(dev, &zx_drm_master_ops, match); 224 + } 225 + 226 + static int zx_drm_remove(struct platform_device *pdev) 227 + { 228 + component_master_del(&pdev->dev, &zx_drm_master_ops); 229 + return 0; 230 + } 231 + 232 + static const struct of_device_id zx_drm_of_match[] = { 233 + { .compatible = "zte,zx296718-vou", }, 234 + { /* end */ }, 235 + }; 236 + MODULE_DEVICE_TABLE(of, zx_drm_of_match); 237 + 238 + static struct platform_driver zx_drm_platform_driver = { 239 + .probe = zx_drm_probe, 240 + .remove = zx_drm_remove, 241 + .driver = { 242 + .name = "zx-drm", 243 + .of_match_table = zx_drm_of_match, 244 + }, 245 + }; 246 + 247 + static struct platform_driver *drivers[] = { 248 + &zx_crtc_driver, 249 + &zx_hdmi_driver, 250 + &zx_drm_platform_driver, 251 + }; 252 + 253 + static int zx_drm_init(void) 254 + { 255 + return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); 256 + } 257 + module_init(zx_drm_init); 258 + 259 + static void zx_drm_exit(void) 260 + { 261 + platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); 262 + } 263 + module_exit(zx_drm_exit); 264 + 265 + MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); 266 + MODULE_DESCRIPTION("ZTE ZX VOU DRM driver"); 267 + MODULE_LICENSE("GPL v2");
+36
drivers/gpu/drm/zte/zx_drm_drv.h
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #ifndef __ZX_DRM_DRV_H__ 12 + #define __ZX_DRM_DRV_H__ 13 + 14 + extern struct platform_driver zx_crtc_driver; 15 + extern struct platform_driver zx_hdmi_driver; 16 + 17 + static inline u32 zx_readl(void __iomem *reg) 18 + { 19 + return readl_relaxed(reg); 20 + } 21 + 22 + static inline void zx_writel(void __iomem *reg, u32 val) 23 + { 24 + writel_relaxed(val, reg); 25 + } 26 + 27 + static inline void zx_writel_mask(void __iomem *reg, u32 mask, u32 val) 28 + { 29 + u32 tmp; 30 + 31 + tmp = zx_readl(reg); 32 + tmp = (tmp & ~mask) | (val & mask); 33 + zx_writel(reg, tmp); 34 + } 35 + 36 + #endif /* __ZX_DRM_DRV_H__ */
+624
drivers/gpu/drm/zte/zx_hdmi.c
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #include <linux/clk.h> 12 + #include <linux/component.h> 13 + #include <linux/delay.h> 14 + #include <linux/err.h> 15 + #include <linux/hdmi.h> 16 + #include <linux/irq.h> 17 + #include <linux/mfd/syscon.h> 18 + #include <linux/module.h> 19 + #include <linux/mutex.h> 20 + #include <linux/of_device.h> 21 + 22 + #include <drm/drm_atomic_helper.h> 23 + #include <drm/drm_crtc_helper.h> 24 + #include <drm/drm_edid.h> 25 + #include <drm/drm_of.h> 26 + #include <drm/drmP.h> 27 + 28 + #include "zx_hdmi_regs.h" 29 + #include "zx_vou.h" 30 + 31 + #define ZX_HDMI_INFOFRAME_SIZE 31 32 + #define DDC_SEGMENT_ADDR 0x30 33 + 34 + struct zx_hdmi_i2c { 35 + struct i2c_adapter adap; 36 + struct mutex lock; 37 + }; 38 + 39 + struct zx_hdmi { 40 + struct drm_connector connector; 41 + struct drm_encoder encoder; 42 + struct zx_hdmi_i2c *ddc; 43 + struct device *dev; 44 + struct drm_device *drm; 45 + void __iomem *mmio; 46 + struct clk *cec_clk; 47 + struct clk *osc_clk; 48 + struct clk *xclk; 49 + bool sink_is_hdmi; 50 + bool sink_has_audio; 51 + const struct vou_inf *inf; 52 + }; 53 + 54 + #define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x) 55 + 56 + static const struct vou_inf vou_inf_hdmi = { 57 + .id = VOU_HDMI, 58 + .data_sel = VOU_YUV444, 59 + .clocks_en_bits = BIT(24) | BIT(18) | BIT(6), 60 + .clocks_sel_bits = BIT(13) | BIT(2), 61 + }; 62 + 63 + static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset) 64 + { 65 + return readl_relaxed(hdmi->mmio + offset * 4); 66 + } 67 + 68 + static inline void hdmi_writeb(struct zx_hdmi *hdmi, u16 offset, u8 val) 69 + { 70 + writel_relaxed(val, hdmi->mmio + offset * 4); 71 + } 72 + 73 + static inline void hdmi_writeb_mask(struct zx_hdmi *hdmi, u16 offset, 74 + u8 mask, u8 val) 75 + { 76 + u8 tmp; 77 + 78 + tmp = hdmi_readb(hdmi, offset); 79 + tmp = (tmp & ~mask) | (val & mask); 80 + hdmi_writeb(hdmi, offset, tmp); 81 + } 82 + 83 + static int zx_hdmi_infoframe_trans(struct zx_hdmi *hdmi, 84 + union hdmi_infoframe *frame, u8 fsel) 85 + { 86 + u8 buffer[ZX_HDMI_INFOFRAME_SIZE]; 87 + int num; 88 + int i; 89 + 90 + hdmi_writeb(hdmi, TPI_INFO_FSEL, fsel); 91 + 92 + num = hdmi_infoframe_pack(frame, buffer, ZX_HDMI_INFOFRAME_SIZE); 93 + if (num < 0) { 94 + DRM_DEV_ERROR(hdmi->dev, "failed to pack infoframe: %d\n", num); 95 + return num; 96 + } 97 + 98 + for (i = 0; i < num; i++) 99 + hdmi_writeb(hdmi, TPI_INFO_B0 + i, buffer[i]); 100 + 101 + hdmi_writeb_mask(hdmi, TPI_INFO_EN, TPI_INFO_TRANS_RPT, 102 + TPI_INFO_TRANS_RPT); 103 + hdmi_writeb_mask(hdmi, TPI_INFO_EN, TPI_INFO_TRANS_EN, 104 + TPI_INFO_TRANS_EN); 105 + 106 + return num; 107 + } 108 + 109 + static int zx_hdmi_config_video_vsi(struct zx_hdmi *hdmi, 110 + struct drm_display_mode *mode) 111 + { 112 + union hdmi_infoframe frame; 113 + int ret; 114 + 115 + ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, 116 + mode); 117 + if (ret) { 118 + DRM_DEV_ERROR(hdmi->dev, "failed to get vendor infoframe: %d\n", 119 + ret); 120 + return ret; 121 + } 122 + 123 + return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_VSIF); 124 + } 125 + 126 + static int zx_hdmi_config_video_avi(struct zx_hdmi *hdmi, 127 + struct drm_display_mode *mode) 128 + { 129 + union hdmi_infoframe frame; 130 + int ret; 131 + 132 + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode); 133 + if (ret) { 134 + DRM_DEV_ERROR(hdmi->dev, "failed to get avi infoframe: %d\n", 135 + ret); 136 + return ret; 137 + } 138 + 139 + /* We always use YUV444 for HDMI output. */ 140 + frame.avi.colorspace = HDMI_COLORSPACE_YUV444; 141 + 142 + return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_AVI); 143 + } 144 + 145 + static void zx_hdmi_encoder_mode_set(struct drm_encoder *encoder, 146 + struct drm_display_mode *mode, 147 + struct drm_display_mode *adj_mode) 148 + { 149 + struct zx_hdmi *hdmi = to_zx_hdmi(encoder); 150 + 151 + if (hdmi->sink_is_hdmi) { 152 + zx_hdmi_config_video_avi(hdmi, mode); 153 + zx_hdmi_config_video_vsi(hdmi, mode); 154 + } 155 + } 156 + 157 + static void zx_hdmi_phy_start(struct zx_hdmi *hdmi) 158 + { 159 + /* Copy from ZTE BSP code */ 160 + hdmi_writeb(hdmi, 0x222, 0x0); 161 + hdmi_writeb(hdmi, 0x224, 0x4); 162 + hdmi_writeb(hdmi, 0x909, 0x0); 163 + hdmi_writeb(hdmi, 0x7b0, 0x90); 164 + hdmi_writeb(hdmi, 0x7b1, 0x00); 165 + hdmi_writeb(hdmi, 0x7b2, 0xa7); 166 + hdmi_writeb(hdmi, 0x7b8, 0xaa); 167 + hdmi_writeb(hdmi, 0x7b2, 0xa7); 168 + hdmi_writeb(hdmi, 0x7b3, 0x0f); 169 + hdmi_writeb(hdmi, 0x7b4, 0x0f); 170 + hdmi_writeb(hdmi, 0x7b5, 0x55); 171 + hdmi_writeb(hdmi, 0x7b7, 0x03); 172 + hdmi_writeb(hdmi, 0x7b9, 0x12); 173 + hdmi_writeb(hdmi, 0x7ba, 0x32); 174 + hdmi_writeb(hdmi, 0x7bc, 0x68); 175 + hdmi_writeb(hdmi, 0x7be, 0x40); 176 + hdmi_writeb(hdmi, 0x7bf, 0x84); 177 + hdmi_writeb(hdmi, 0x7c1, 0x0f); 178 + hdmi_writeb(hdmi, 0x7c8, 0x02); 179 + hdmi_writeb(hdmi, 0x7c9, 0x03); 180 + hdmi_writeb(hdmi, 0x7ca, 0x40); 181 + hdmi_writeb(hdmi, 0x7dc, 0x31); 182 + hdmi_writeb(hdmi, 0x7e2, 0x04); 183 + hdmi_writeb(hdmi, 0x7e0, 0x06); 184 + hdmi_writeb(hdmi, 0x7cb, 0x68); 185 + hdmi_writeb(hdmi, 0x7f9, 0x02); 186 + hdmi_writeb(hdmi, 0x7b6, 0x02); 187 + hdmi_writeb(hdmi, 0x7f3, 0x0); 188 + } 189 + 190 + static void zx_hdmi_hw_enable(struct zx_hdmi *hdmi) 191 + { 192 + /* Enable pclk */ 193 + hdmi_writeb_mask(hdmi, CLKPWD, CLKPWD_PDIDCK, CLKPWD_PDIDCK); 194 + 195 + /* Enable HDMI for TX */ 196 + hdmi_writeb_mask(hdmi, FUNC_SEL, FUNC_HDMI_EN, FUNC_HDMI_EN); 197 + 198 + /* Enable deep color packet */ 199 + hdmi_writeb_mask(hdmi, P2T_CTRL, P2T_DC_PKT_EN, P2T_DC_PKT_EN); 200 + 201 + /* Enable HDMI/MHL mode for output */ 202 + hdmi_writeb_mask(hdmi, TEST_TXCTRL, TEST_TXCTRL_HDMI_MODE, 203 + TEST_TXCTRL_HDMI_MODE); 204 + 205 + /* Configure reg_qc_sel */ 206 + hdmi_writeb(hdmi, HDMICTL4, 0x3); 207 + 208 + /* Enable interrupt */ 209 + hdmi_writeb_mask(hdmi, INTR1_MASK, INTR1_MONITOR_DETECT, 210 + INTR1_MONITOR_DETECT); 211 + 212 + /* Start up phy */ 213 + zx_hdmi_phy_start(hdmi); 214 + } 215 + 216 + static void zx_hdmi_hw_disable(struct zx_hdmi *hdmi) 217 + { 218 + /* Disable interrupt */ 219 + hdmi_writeb_mask(hdmi, INTR1_MASK, INTR1_MONITOR_DETECT, 0); 220 + 221 + /* Disable deep color packet */ 222 + hdmi_writeb_mask(hdmi, P2T_CTRL, P2T_DC_PKT_EN, P2T_DC_PKT_EN); 223 + 224 + /* Disable HDMI for TX */ 225 + hdmi_writeb_mask(hdmi, FUNC_SEL, FUNC_HDMI_EN, 0); 226 + 227 + /* Disable pclk */ 228 + hdmi_writeb_mask(hdmi, CLKPWD, CLKPWD_PDIDCK, 0); 229 + } 230 + 231 + static void zx_hdmi_encoder_enable(struct drm_encoder *encoder) 232 + { 233 + struct zx_hdmi *hdmi = to_zx_hdmi(encoder); 234 + 235 + clk_prepare_enable(hdmi->cec_clk); 236 + clk_prepare_enable(hdmi->osc_clk); 237 + clk_prepare_enable(hdmi->xclk); 238 + 239 + zx_hdmi_hw_enable(hdmi); 240 + 241 + vou_inf_enable(hdmi->inf, encoder->crtc); 242 + } 243 + 244 + static void zx_hdmi_encoder_disable(struct drm_encoder *encoder) 245 + { 246 + struct zx_hdmi *hdmi = to_zx_hdmi(encoder); 247 + 248 + vou_inf_disable(hdmi->inf, encoder->crtc); 249 + 250 + zx_hdmi_hw_disable(hdmi); 251 + 252 + clk_disable_unprepare(hdmi->xclk); 253 + clk_disable_unprepare(hdmi->osc_clk); 254 + clk_disable_unprepare(hdmi->cec_clk); 255 + } 256 + 257 + static const struct drm_encoder_helper_funcs zx_hdmi_encoder_helper_funcs = { 258 + .enable = zx_hdmi_encoder_enable, 259 + .disable = zx_hdmi_encoder_disable, 260 + .mode_set = zx_hdmi_encoder_mode_set, 261 + }; 262 + 263 + static const struct drm_encoder_funcs zx_hdmi_encoder_funcs = { 264 + .destroy = drm_encoder_cleanup, 265 + }; 266 + 267 + static int zx_hdmi_connector_get_modes(struct drm_connector *connector) 268 + { 269 + struct zx_hdmi *hdmi = to_zx_hdmi(connector); 270 + struct edid *edid; 271 + int ret; 272 + 273 + edid = drm_get_edid(connector, &hdmi->ddc->adap); 274 + if (!edid) 275 + return 0; 276 + 277 + hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); 278 + hdmi->sink_has_audio = drm_detect_monitor_audio(edid); 279 + drm_mode_connector_update_edid_property(connector, edid); 280 + ret = drm_add_edid_modes(connector, edid); 281 + kfree(edid); 282 + 283 + return ret; 284 + } 285 + 286 + static enum drm_mode_status 287 + zx_hdmi_connector_mode_valid(struct drm_connector *connector, 288 + struct drm_display_mode *mode) 289 + { 290 + return MODE_OK; 291 + } 292 + 293 + static struct drm_connector_helper_funcs zx_hdmi_connector_helper_funcs = { 294 + .get_modes = zx_hdmi_connector_get_modes, 295 + .mode_valid = zx_hdmi_connector_mode_valid, 296 + }; 297 + 298 + static enum drm_connector_status 299 + zx_hdmi_connector_detect(struct drm_connector *connector, bool force) 300 + { 301 + struct zx_hdmi *hdmi = to_zx_hdmi(connector); 302 + 303 + return (hdmi_readb(hdmi, TPI_HPD_RSEN) & TPI_HPD_CONNECTION) ? 304 + connector_status_connected : connector_status_disconnected; 305 + } 306 + 307 + static const struct drm_connector_funcs zx_hdmi_connector_funcs = { 308 + .dpms = drm_atomic_helper_connector_dpms, 309 + .fill_modes = drm_helper_probe_single_connector_modes, 310 + .detect = zx_hdmi_connector_detect, 311 + .destroy = drm_connector_cleanup, 312 + .reset = drm_atomic_helper_connector_reset, 313 + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 314 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 315 + }; 316 + 317 + static int zx_hdmi_register(struct drm_device *drm, struct zx_hdmi *hdmi) 318 + { 319 + struct drm_encoder *encoder = &hdmi->encoder; 320 + 321 + encoder->possible_crtcs = VOU_CRTC_MASK; 322 + 323 + drm_encoder_init(drm, encoder, &zx_hdmi_encoder_funcs, 324 + DRM_MODE_ENCODER_TMDS, NULL); 325 + drm_encoder_helper_add(encoder, &zx_hdmi_encoder_helper_funcs); 326 + 327 + hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; 328 + 329 + drm_connector_init(drm, &hdmi->connector, &zx_hdmi_connector_funcs, 330 + DRM_MODE_CONNECTOR_HDMIA); 331 + drm_connector_helper_add(&hdmi->connector, 332 + &zx_hdmi_connector_helper_funcs); 333 + 334 + drm_mode_connector_attach_encoder(&hdmi->connector, encoder); 335 + 336 + return 0; 337 + } 338 + 339 + static irqreturn_t zx_hdmi_irq_thread(int irq, void *dev_id) 340 + { 341 + struct zx_hdmi *hdmi = dev_id; 342 + 343 + drm_helper_hpd_irq_event(hdmi->connector.dev); 344 + 345 + return IRQ_HANDLED; 346 + } 347 + 348 + static irqreturn_t zx_hdmi_irq_handler(int irq, void *dev_id) 349 + { 350 + struct zx_hdmi *hdmi = dev_id; 351 + u8 lstat; 352 + 353 + lstat = hdmi_readb(hdmi, L1_INTR_STAT); 354 + 355 + /* Monitor detect/HPD interrupt */ 356 + if (lstat & L1_INTR_STAT_INTR1) { 357 + u8 stat; 358 + 359 + stat = hdmi_readb(hdmi, INTR1_STAT); 360 + hdmi_writeb(hdmi, INTR1_STAT, stat); 361 + 362 + if (stat & INTR1_MONITOR_DETECT) 363 + return IRQ_WAKE_THREAD; 364 + } 365 + 366 + return IRQ_NONE; 367 + } 368 + 369 + static int zx_hdmi_i2c_read(struct zx_hdmi *hdmi, struct i2c_msg *msg) 370 + { 371 + int len = msg->len; 372 + u8 *buf = msg->buf; 373 + int retry = 0; 374 + int ret = 0; 375 + 376 + /* Bits [9:8] of bytes */ 377 + hdmi_writeb(hdmi, ZX_DDC_DIN_CNT2, (len >> 8) & 0xff); 378 + /* Bits [7:0] of bytes */ 379 + hdmi_writeb(hdmi, ZX_DDC_DIN_CNT1, len & 0xff); 380 + 381 + /* Clear FIFO */ 382 + hdmi_writeb_mask(hdmi, ZX_DDC_CMD, DDC_CMD_MASK, DDC_CMD_CLEAR_FIFO); 383 + 384 + /* Kick off the read */ 385 + hdmi_writeb_mask(hdmi, ZX_DDC_CMD, DDC_CMD_MASK, 386 + DDC_CMD_SEQUENTIAL_READ); 387 + 388 + while (len > 0) { 389 + int cnt, i; 390 + 391 + /* FIFO needs some time to get ready */ 392 + usleep_range(500, 1000); 393 + 394 + cnt = hdmi_readb(hdmi, ZX_DDC_DOUT_CNT) & DDC_DOUT_CNT_MASK; 395 + if (cnt == 0) { 396 + if (++retry > 5) { 397 + DRM_DEV_ERROR(hdmi->dev, 398 + "DDC FIFO read timed out!"); 399 + return -ETIMEDOUT; 400 + } 401 + continue; 402 + } 403 + 404 + for (i = 0; i < cnt; i++) 405 + *buf++ = hdmi_readb(hdmi, ZX_DDC_DATA); 406 + len -= cnt; 407 + } 408 + 409 + return ret; 410 + } 411 + 412 + static int zx_hdmi_i2c_write(struct zx_hdmi *hdmi, struct i2c_msg *msg) 413 + { 414 + /* 415 + * The DDC I2C adapter is only for reading EDID data, so we assume 416 + * that the write to this adapter must be the EDID data offset. 417 + */ 418 + if ((msg->len != 1) || 419 + ((msg->addr != DDC_ADDR) && (msg->addr != DDC_SEGMENT_ADDR))) 420 + return -EINVAL; 421 + 422 + if (msg->addr == DDC_SEGMENT_ADDR) 423 + hdmi_writeb(hdmi, ZX_DDC_SEGM, msg->addr << 1); 424 + else if (msg->addr == DDC_ADDR) 425 + hdmi_writeb(hdmi, ZX_DDC_ADDR, msg->addr << 1); 426 + 427 + hdmi_writeb(hdmi, ZX_DDC_OFFSET, msg->buf[0]); 428 + 429 + return 0; 430 + } 431 + 432 + static int zx_hdmi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 433 + int num) 434 + { 435 + struct zx_hdmi *hdmi = i2c_get_adapdata(adap); 436 + struct zx_hdmi_i2c *ddc = hdmi->ddc; 437 + int i, ret = 0; 438 + 439 + mutex_lock(&ddc->lock); 440 + 441 + /* Enable DDC master access */ 442 + hdmi_writeb_mask(hdmi, TPI_DDC_MASTER_EN, HW_DDC_MASTER, HW_DDC_MASTER); 443 + 444 + for (i = 0; i < num; i++) { 445 + DRM_DEV_DEBUG(hdmi->dev, 446 + "xfer: num: %d/%d, len: %d, flags: %#x\n", 447 + i + 1, num, msgs[i].len, msgs[i].flags); 448 + 449 + if (msgs[i].flags & I2C_M_RD) 450 + ret = zx_hdmi_i2c_read(hdmi, &msgs[i]); 451 + else 452 + ret = zx_hdmi_i2c_write(hdmi, &msgs[i]); 453 + 454 + if (ret < 0) 455 + break; 456 + } 457 + 458 + if (!ret) 459 + ret = num; 460 + 461 + /* Disable DDC master access */ 462 + hdmi_writeb_mask(hdmi, TPI_DDC_MASTER_EN, HW_DDC_MASTER, 0); 463 + 464 + mutex_unlock(&ddc->lock); 465 + 466 + return ret; 467 + } 468 + 469 + static u32 zx_hdmi_i2c_func(struct i2c_adapter *adapter) 470 + { 471 + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 472 + } 473 + 474 + static const struct i2c_algorithm zx_hdmi_algorithm = { 475 + .master_xfer = zx_hdmi_i2c_xfer, 476 + .functionality = zx_hdmi_i2c_func, 477 + }; 478 + 479 + static int zx_hdmi_ddc_register(struct zx_hdmi *hdmi) 480 + { 481 + struct i2c_adapter *adap; 482 + struct zx_hdmi_i2c *ddc; 483 + int ret; 484 + 485 + ddc = devm_kzalloc(hdmi->dev, sizeof(*ddc), GFP_KERNEL); 486 + if (!ddc) 487 + return -ENOMEM; 488 + 489 + hdmi->ddc = ddc; 490 + mutex_init(&ddc->lock); 491 + 492 + adap = &ddc->adap; 493 + adap->owner = THIS_MODULE; 494 + adap->class = I2C_CLASS_DDC; 495 + adap->dev.parent = hdmi->dev; 496 + adap->algo = &zx_hdmi_algorithm; 497 + snprintf(adap->name, sizeof(adap->name), "zx hdmi i2c"); 498 + 499 + ret = i2c_add_adapter(adap); 500 + if (ret) { 501 + DRM_DEV_ERROR(hdmi->dev, "failed to add I2C adapter: %d\n", 502 + ret); 503 + return ret; 504 + } 505 + 506 + i2c_set_adapdata(adap, hdmi); 507 + 508 + return 0; 509 + } 510 + 511 + static int zx_hdmi_bind(struct device *dev, struct device *master, void *data) 512 + { 513 + struct platform_device *pdev = to_platform_device(dev); 514 + struct drm_device *drm = data; 515 + struct resource *res; 516 + struct zx_hdmi *hdmi; 517 + int irq; 518 + int ret; 519 + 520 + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); 521 + if (!hdmi) 522 + return -ENOMEM; 523 + 524 + hdmi->dev = dev; 525 + hdmi->drm = drm; 526 + hdmi->inf = &vou_inf_hdmi; 527 + 528 + dev_set_drvdata(dev, hdmi); 529 + 530 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 531 + hdmi->mmio = devm_ioremap_resource(dev, res); 532 + if (IS_ERR(hdmi->mmio)) { 533 + ret = PTR_ERR(hdmi->mmio); 534 + DRM_DEV_ERROR(dev, "failed to remap hdmi region: %d\n", ret); 535 + return ret; 536 + } 537 + 538 + irq = platform_get_irq(pdev, 0); 539 + if (irq < 0) 540 + return irq; 541 + 542 + hdmi->cec_clk = devm_clk_get(hdmi->dev, "osc_cec"); 543 + if (IS_ERR(hdmi->cec_clk)) { 544 + ret = PTR_ERR(hdmi->cec_clk); 545 + DRM_DEV_ERROR(dev, "failed to get cec_clk: %d\n", ret); 546 + return ret; 547 + } 548 + 549 + hdmi->osc_clk = devm_clk_get(hdmi->dev, "osc_clk"); 550 + if (IS_ERR(hdmi->osc_clk)) { 551 + ret = PTR_ERR(hdmi->osc_clk); 552 + DRM_DEV_ERROR(dev, "failed to get osc_clk: %d\n", ret); 553 + return ret; 554 + } 555 + 556 + hdmi->xclk = devm_clk_get(hdmi->dev, "xclk"); 557 + if (IS_ERR(hdmi->xclk)) { 558 + ret = PTR_ERR(hdmi->xclk); 559 + DRM_DEV_ERROR(dev, "failed to get xclk: %d\n", ret); 560 + return ret; 561 + } 562 + 563 + ret = zx_hdmi_ddc_register(hdmi); 564 + if (ret) { 565 + DRM_DEV_ERROR(dev, "failed to register ddc: %d\n", ret); 566 + return ret; 567 + } 568 + 569 + ret = zx_hdmi_register(drm, hdmi); 570 + if (ret) { 571 + DRM_DEV_ERROR(dev, "failed to register hdmi: %d\n", ret); 572 + return ret; 573 + } 574 + 575 + ret = devm_request_threaded_irq(dev, irq, zx_hdmi_irq_handler, 576 + zx_hdmi_irq_thread, IRQF_SHARED, 577 + dev_name(dev), hdmi); 578 + if (ret) { 579 + DRM_DEV_ERROR(dev, "failed to request threaded irq: %d\n", ret); 580 + return ret; 581 + } 582 + 583 + return 0; 584 + } 585 + 586 + static void zx_hdmi_unbind(struct device *dev, struct device *master, 587 + void *data) 588 + { 589 + struct zx_hdmi *hdmi = dev_get_drvdata(dev); 590 + 591 + hdmi->connector.funcs->destroy(&hdmi->connector); 592 + hdmi->encoder.funcs->destroy(&hdmi->encoder); 593 + } 594 + 595 + static const struct component_ops zx_hdmi_component_ops = { 596 + .bind = zx_hdmi_bind, 597 + .unbind = zx_hdmi_unbind, 598 + }; 599 + 600 + static int zx_hdmi_probe(struct platform_device *pdev) 601 + { 602 + return component_add(&pdev->dev, &zx_hdmi_component_ops); 603 + } 604 + 605 + static int zx_hdmi_remove(struct platform_device *pdev) 606 + { 607 + component_del(&pdev->dev, &zx_hdmi_component_ops); 608 + return 0; 609 + } 610 + 611 + static const struct of_device_id zx_hdmi_of_match[] = { 612 + { .compatible = "zte,zx296718-hdmi", }, 613 + { /* end */ }, 614 + }; 615 + MODULE_DEVICE_TABLE(of, zx_hdmi_of_match); 616 + 617 + struct platform_driver zx_hdmi_driver = { 618 + .probe = zx_hdmi_probe, 619 + .remove = zx_hdmi_remove, 620 + .driver = { 621 + .name = "zx-hdmi", 622 + .of_match_table = zx_hdmi_of_match, 623 + }, 624 + };
+56
drivers/gpu/drm/zte/zx_hdmi_regs.h
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #ifndef __ZX_HDMI_REGS_H__ 12 + #define __ZX_HDMI_REGS_H__ 13 + 14 + #define FUNC_SEL 0x000b 15 + #define FUNC_HDMI_EN BIT(0) 16 + #define CLKPWD 0x000d 17 + #define CLKPWD_PDIDCK BIT(2) 18 + #define P2T_CTRL 0x0066 19 + #define P2T_DC_PKT_EN BIT(7) 20 + #define L1_INTR_STAT 0x007e 21 + #define L1_INTR_STAT_INTR1 BIT(0) 22 + #define INTR1_STAT 0x008f 23 + #define INTR1_MASK 0x0095 24 + #define INTR1_MONITOR_DETECT (BIT(5) | BIT(6)) 25 + #define ZX_DDC_ADDR 0x00ed 26 + #define ZX_DDC_SEGM 0x00ee 27 + #define ZX_DDC_OFFSET 0x00ef 28 + #define ZX_DDC_DIN_CNT1 0x00f0 29 + #define ZX_DDC_DIN_CNT2 0x00f1 30 + #define ZX_DDC_CMD 0x00f3 31 + #define DDC_CMD_MASK 0xf 32 + #define DDC_CMD_CLEAR_FIFO 0x9 33 + #define DDC_CMD_SEQUENTIAL_READ 0x2 34 + #define ZX_DDC_DATA 0x00f4 35 + #define ZX_DDC_DOUT_CNT 0x00f5 36 + #define DDC_DOUT_CNT_MASK 0x1f 37 + #define TEST_TXCTRL 0x00f7 38 + #define TEST_TXCTRL_HDMI_MODE BIT(1) 39 + #define HDMICTL4 0x0235 40 + #define TPI_HPD_RSEN 0x063b 41 + #define TPI_HPD_CONNECTION (BIT(1) | BIT(2)) 42 + #define TPI_INFO_FSEL 0x06bf 43 + #define FSEL_AVI 0 44 + #define FSEL_GBD 1 45 + #define FSEL_AUDIO 2 46 + #define FSEL_SPD 3 47 + #define FSEL_MPEG 4 48 + #define FSEL_VSIF 5 49 + #define TPI_INFO_B0 0x06c0 50 + #define TPI_INFO_EN 0x06df 51 + #define TPI_INFO_TRANS_EN BIT(7) 52 + #define TPI_INFO_TRANS_RPT BIT(6) 53 + #define TPI_DDC_MASTER_EN 0x06f8 54 + #define HW_DDC_MASTER BIT(7) 55 + 56 + #endif /* __ZX_HDMI_REGS_H__ */
+299
drivers/gpu/drm/zte/zx_plane.c
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #include <drm/drm_atomic.h> 12 + #include <drm/drm_atomic_helper.h> 13 + #include <drm/drm_fb_cma_helper.h> 14 + #include <drm/drm_gem_cma_helper.h> 15 + #include <drm/drm_modeset_helper_vtables.h> 16 + #include <drm/drm_plane_helper.h> 17 + #include <drm/drmP.h> 18 + 19 + #include "zx_drm_drv.h" 20 + #include "zx_plane.h" 21 + #include "zx_plane_regs.h" 22 + #include "zx_vou.h" 23 + 24 + struct zx_plane { 25 + struct drm_plane plane; 26 + void __iomem *layer; 27 + void __iomem *csc; 28 + void __iomem *hbsc; 29 + void __iomem *rsz; 30 + }; 31 + 32 + #define to_zx_plane(plane) container_of(plane, struct zx_plane, plane) 33 + 34 + static const uint32_t gl_formats[] = { 35 + DRM_FORMAT_ARGB8888, 36 + DRM_FORMAT_XRGB8888, 37 + DRM_FORMAT_RGB888, 38 + DRM_FORMAT_RGB565, 39 + DRM_FORMAT_ARGB1555, 40 + DRM_FORMAT_ARGB4444, 41 + }; 42 + 43 + static int zx_gl_plane_atomic_check(struct drm_plane *plane, 44 + struct drm_plane_state *plane_state) 45 + { 46 + struct drm_framebuffer *fb = plane_state->fb; 47 + struct drm_crtc *crtc = plane_state->crtc; 48 + struct drm_crtc_state *crtc_state; 49 + struct drm_rect clip; 50 + 51 + if (!crtc || !fb) 52 + return 0; 53 + 54 + crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state, 55 + crtc); 56 + if (WARN_ON(!crtc_state)) 57 + return -EINVAL; 58 + 59 + /* nothing to check when disabling or disabled */ 60 + if (!crtc_state->enable) 61 + return 0; 62 + 63 + /* plane must be enabled */ 64 + if (!plane_state->crtc) 65 + return -EINVAL; 66 + 67 + clip.x1 = 0; 68 + clip.y1 = 0; 69 + clip.x2 = crtc_state->adjusted_mode.hdisplay; 70 + clip.y2 = crtc_state->adjusted_mode.vdisplay; 71 + 72 + return drm_plane_helper_check_state(plane_state, &clip, 73 + DRM_PLANE_HELPER_NO_SCALING, 74 + DRM_PLANE_HELPER_NO_SCALING, 75 + false, true); 76 + } 77 + 78 + static int zx_gl_get_fmt(uint32_t format) 79 + { 80 + switch (format) { 81 + case DRM_FORMAT_ARGB8888: 82 + case DRM_FORMAT_XRGB8888: 83 + return GL_FMT_ARGB8888; 84 + case DRM_FORMAT_RGB888: 85 + return GL_FMT_RGB888; 86 + case DRM_FORMAT_RGB565: 87 + return GL_FMT_RGB565; 88 + case DRM_FORMAT_ARGB1555: 89 + return GL_FMT_ARGB1555; 90 + case DRM_FORMAT_ARGB4444: 91 + return GL_FMT_ARGB4444; 92 + default: 93 + WARN_ONCE(1, "invalid pixel format %d\n", format); 94 + return -EINVAL; 95 + } 96 + } 97 + 98 + static inline void zx_gl_set_update(struct zx_plane *zplane) 99 + { 100 + void __iomem *layer = zplane->layer; 101 + 102 + zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE); 103 + } 104 + 105 + static inline void zx_gl_rsz_set_update(struct zx_plane *zplane) 106 + { 107 + zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1); 108 + } 109 + 110 + void zx_plane_set_update(struct drm_plane *plane) 111 + { 112 + struct zx_plane *zplane = to_zx_plane(plane); 113 + 114 + zx_gl_rsz_set_update(zplane); 115 + zx_gl_set_update(zplane); 116 + } 117 + 118 + static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h, 119 + u32 dst_w, u32 dst_h) 120 + { 121 + void __iomem *rsz = zplane->rsz; 122 + 123 + zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1)); 124 + zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1)); 125 + 126 + zx_gl_rsz_set_update(zplane); 127 + } 128 + 129 + static void zx_gl_plane_atomic_update(struct drm_plane *plane, 130 + struct drm_plane_state *old_state) 131 + { 132 + struct zx_plane *zplane = to_zx_plane(plane); 133 + struct drm_framebuffer *fb = plane->state->fb; 134 + struct drm_gem_cma_object *cma_obj; 135 + void __iomem *layer = zplane->layer; 136 + void __iomem *csc = zplane->csc; 137 + void __iomem *hbsc = zplane->hbsc; 138 + u32 src_x, src_y, src_w, src_h; 139 + u32 dst_x, dst_y, dst_w, dst_h; 140 + unsigned int bpp; 141 + uint32_t format; 142 + dma_addr_t paddr; 143 + u32 stride; 144 + int fmt; 145 + 146 + if (!fb) 147 + return; 148 + 149 + format = fb->pixel_format; 150 + stride = fb->pitches[0]; 151 + 152 + src_x = plane->state->src_x >> 16; 153 + src_y = plane->state->src_y >> 16; 154 + src_w = plane->state->src_w >> 16; 155 + src_h = plane->state->src_h >> 16; 156 + 157 + dst_x = plane->state->crtc_x; 158 + dst_y = plane->state->crtc_y; 159 + dst_w = plane->state->crtc_w; 160 + dst_h = plane->state->crtc_h; 161 + 162 + bpp = drm_format_plane_cpp(format, 0); 163 + 164 + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 165 + paddr = cma_obj->paddr + fb->offsets[0]; 166 + paddr += src_y * stride + src_x * bpp / 8; 167 + zx_writel(layer + GL_ADDR, paddr); 168 + 169 + /* Set up source height/width register */ 170 + zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h)); 171 + 172 + /* Set up start position register */ 173 + zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y)); 174 + 175 + /* Set up end position register */ 176 + zx_writel(layer + GL_POS_END, 177 + GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h)); 178 + 179 + /* Set up stride register */ 180 + zx_writel(layer + GL_STRIDE, stride & 0xffff); 181 + 182 + /* Set up graphic layer data format */ 183 + fmt = zx_gl_get_fmt(format); 184 + if (fmt >= 0) 185 + zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK, 186 + fmt << GL_DATA_FMT_SHIFT); 187 + 188 + /* Initialize global alpha with a sane value */ 189 + zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK, 190 + 0xff << GL_GLOBAL_ALPHA_SHIFT); 191 + 192 + /* Setup CSC for the GL */ 193 + if (dst_h > 720) 194 + zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK, 195 + CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT); 196 + else 197 + zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK, 198 + CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT); 199 + zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE); 200 + 201 + /* Always use scaler since it exists (set for not bypass) */ 202 + zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE, 203 + GL_SCALER_BYPASS_MODE); 204 + 205 + zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h); 206 + 207 + /* Enable HBSC block */ 208 + zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN); 209 + 210 + zx_gl_set_update(zplane); 211 + } 212 + 213 + static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = { 214 + .atomic_check = zx_gl_plane_atomic_check, 215 + .atomic_update = zx_gl_plane_atomic_update, 216 + }; 217 + 218 + static void zx_plane_destroy(struct drm_plane *plane) 219 + { 220 + drm_plane_helper_disable(plane); 221 + drm_plane_cleanup(plane); 222 + } 223 + 224 + static const struct drm_plane_funcs zx_plane_funcs = { 225 + .update_plane = drm_atomic_helper_update_plane, 226 + .disable_plane = drm_atomic_helper_disable_plane, 227 + .destroy = zx_plane_destroy, 228 + .reset = drm_atomic_helper_plane_reset, 229 + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 230 + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 231 + }; 232 + 233 + static void zx_plane_hbsc_init(struct zx_plane *zplane) 234 + { 235 + void __iomem *hbsc = zplane->hbsc; 236 + 237 + /* 238 + * Initialize HBSC block with a sane configuration per recommedation 239 + * from ZTE BSP code. 240 + */ 241 + zx_writel(hbsc + HBSC_SATURATION, 0x200); 242 + zx_writel(hbsc + HBSC_HUE, 0x0); 243 + zx_writel(hbsc + HBSC_BRIGHT, 0x0); 244 + zx_writel(hbsc + HBSC_CONTRAST, 0x200); 245 + 246 + zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40); 247 + zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40); 248 + zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40); 249 + } 250 + 251 + struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev, 252 + struct zx_layer_data *data, 253 + enum drm_plane_type type) 254 + { 255 + const struct drm_plane_helper_funcs *helper; 256 + struct zx_plane *zplane; 257 + struct drm_plane *plane; 258 + const uint32_t *formats; 259 + unsigned int format_count; 260 + int ret; 261 + 262 + zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL); 263 + if (!zplane) 264 + return ERR_PTR(-ENOMEM); 265 + 266 + plane = &zplane->plane; 267 + 268 + zplane->layer = data->layer; 269 + zplane->hbsc = data->hbsc; 270 + zplane->csc = data->csc; 271 + zplane->rsz = data->rsz; 272 + 273 + zx_plane_hbsc_init(zplane); 274 + 275 + switch (type) { 276 + case DRM_PLANE_TYPE_PRIMARY: 277 + helper = &zx_gl_plane_helper_funcs; 278 + formats = gl_formats; 279 + format_count = ARRAY_SIZE(gl_formats); 280 + break; 281 + case DRM_PLANE_TYPE_OVERLAY: 282 + /* TODO: add video layer (vl) support */ 283 + break; 284 + default: 285 + return ERR_PTR(-ENODEV); 286 + } 287 + 288 + ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK, 289 + &zx_plane_funcs, formats, format_count, 290 + type, NULL); 291 + if (ret) { 292 + DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret); 293 + return ERR_PTR(ret); 294 + } 295 + 296 + drm_plane_helper_add(plane, helper); 297 + 298 + return plane; 299 + }
+26
drivers/gpu/drm/zte/zx_plane.h
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #ifndef __ZX_PLANE_H__ 12 + #define __ZX_PLANE_H__ 13 + 14 + struct zx_layer_data { 15 + void __iomem *layer; 16 + void __iomem *csc; 17 + void __iomem *hbsc; 18 + void __iomem *rsz; 19 + }; 20 + 21 + struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev, 22 + struct zx_layer_data *data, 23 + enum drm_plane_type type); 24 + void zx_plane_set_update(struct drm_plane *plane); 25 + 26 + #endif /* __ZX_PLANE_H__ */
+91
drivers/gpu/drm/zte/zx_plane_regs.h
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #ifndef __ZX_PLANE_REGS_H__ 12 + #define __ZX_PLANE_REGS_H__ 13 + 14 + /* GL registers */ 15 + #define GL_CTRL0 0x00 16 + #define GL_UPDATE BIT(5) 17 + #define GL_CTRL1 0x04 18 + #define GL_DATA_FMT_SHIFT 0 19 + #define GL_DATA_FMT_MASK (0xf << GL_DATA_FMT_SHIFT) 20 + #define GL_FMT_ARGB8888 0 21 + #define GL_FMT_RGB888 1 22 + #define GL_FMT_RGB565 2 23 + #define GL_FMT_ARGB1555 3 24 + #define GL_FMT_ARGB4444 4 25 + #define GL_CTRL2 0x08 26 + #define GL_GLOBAL_ALPHA_SHIFT 8 27 + #define GL_GLOBAL_ALPHA_MASK (0xff << GL_GLOBAL_ALPHA_SHIFT) 28 + #define GL_CTRL3 0x0c 29 + #define GL_SCALER_BYPASS_MODE BIT(0) 30 + #define GL_STRIDE 0x18 31 + #define GL_ADDR 0x1c 32 + #define GL_SRC_SIZE 0x38 33 + #define GL_SRC_W_SHIFT 16 34 + #define GL_SRC_W_MASK (0x3fff << GL_SRC_W_SHIFT) 35 + #define GL_SRC_H_SHIFT 0 36 + #define GL_SRC_H_MASK (0x3fff << GL_SRC_H_SHIFT) 37 + #define GL_POS_START 0x9c 38 + #define GL_POS_END 0xa0 39 + #define GL_POS_X_SHIFT 16 40 + #define GL_POS_X_MASK (0x1fff << GL_POS_X_SHIFT) 41 + #define GL_POS_Y_SHIFT 0 42 + #define GL_POS_Y_MASK (0x1fff << GL_POS_Y_SHIFT) 43 + 44 + #define GL_SRC_W(x) (((x) << GL_SRC_W_SHIFT) & GL_SRC_W_MASK) 45 + #define GL_SRC_H(x) (((x) << GL_SRC_H_SHIFT) & GL_SRC_H_MASK) 46 + #define GL_POS_X(x) (((x) << GL_POS_X_SHIFT) & GL_POS_X_MASK) 47 + #define GL_POS_Y(x) (((x) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK) 48 + 49 + /* CSC registers */ 50 + #define CSC_CTRL0 0x30 51 + #define CSC_COV_MODE_SHIFT 16 52 + #define CSC_COV_MODE_MASK (0xffff << CSC_COV_MODE_SHIFT) 53 + #define CSC_BT601_IMAGE_RGB2YCBCR 0 54 + #define CSC_BT601_IMAGE_YCBCR2RGB 1 55 + #define CSC_BT601_VIDEO_RGB2YCBCR 2 56 + #define CSC_BT601_VIDEO_YCBCR2RGB 3 57 + #define CSC_BT709_IMAGE_RGB2YCBCR 4 58 + #define CSC_BT709_IMAGE_YCBCR2RGB 5 59 + #define CSC_BT709_VIDEO_RGB2YCBCR 6 60 + #define CSC_BT709_VIDEO_YCBCR2RGB 7 61 + #define CSC_BT2020_IMAGE_RGB2YCBCR 8 62 + #define CSC_BT2020_IMAGE_YCBCR2RGB 9 63 + #define CSC_BT2020_VIDEO_RGB2YCBCR 10 64 + #define CSC_BT2020_VIDEO_YCBCR2RGB 11 65 + #define CSC_WORK_ENABLE BIT(0) 66 + 67 + /* RSZ registers */ 68 + #define RSZ_SRC_CFG 0x00 69 + #define RSZ_DEST_CFG 0x04 70 + #define RSZ_ENABLE_CFG 0x14 71 + 72 + #define RSZ_VER_SHIFT 16 73 + #define RSZ_VER_MASK (0xffff << RSZ_VER_SHIFT) 74 + #define RSZ_HOR_SHIFT 0 75 + #define RSZ_HOR_MASK (0xffff << RSZ_HOR_SHIFT) 76 + 77 + #define RSZ_VER(x) (((x) << RSZ_VER_SHIFT) & RSZ_VER_MASK) 78 + #define RSZ_HOR(x) (((x) << RSZ_HOR_SHIFT) & RSZ_HOR_MASK) 79 + 80 + /* HBSC registers */ 81 + #define HBSC_SATURATION 0x00 82 + #define HBSC_HUE 0x04 83 + #define HBSC_BRIGHT 0x08 84 + #define HBSC_CONTRAST 0x0c 85 + #define HBSC_THRESHOLD_COL1 0x10 86 + #define HBSC_THRESHOLD_COL2 0x14 87 + #define HBSC_THRESHOLD_COL3 0x18 88 + #define HBSC_CTRL0 0x28 89 + #define HBSC_CTRL_EN BIT(2) 90 + 91 + #endif /* __ZX_PLANE_REGS_H__ */
+661
drivers/gpu/drm/zte/zx_vou.c
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #include <linux/clk.h> 12 + #include <linux/component.h> 13 + #include <linux/of_address.h> 14 + #include <video/videomode.h> 15 + 16 + #include <drm/drm_atomic_helper.h> 17 + #include <drm/drm_crtc.h> 18 + #include <drm/drm_crtc_helper.h> 19 + #include <drm/drm_fb_cma_helper.h> 20 + #include <drm/drm_fb_helper.h> 21 + #include <drm/drm_gem_cma_helper.h> 22 + #include <drm/drm_of.h> 23 + #include <drm/drm_plane_helper.h> 24 + #include <drm/drmP.h> 25 + 26 + #include "zx_drm_drv.h" 27 + #include "zx_plane.h" 28 + #include "zx_vou.h" 29 + #include "zx_vou_regs.h" 30 + 31 + #define GL_NUM 2 32 + #define VL_NUM 3 33 + 34 + enum vou_chn_type { 35 + VOU_CHN_MAIN, 36 + VOU_CHN_AUX, 37 + }; 38 + 39 + struct zx_crtc_regs { 40 + u32 fir_active; 41 + u32 fir_htiming; 42 + u32 fir_vtiming; 43 + u32 timing_shift; 44 + u32 timing_pi_shift; 45 + }; 46 + 47 + static const struct zx_crtc_regs main_crtc_regs = { 48 + .fir_active = FIR_MAIN_ACTIVE, 49 + .fir_htiming = FIR_MAIN_H_TIMING, 50 + .fir_vtiming = FIR_MAIN_V_TIMING, 51 + .timing_shift = TIMING_MAIN_SHIFT, 52 + .timing_pi_shift = TIMING_MAIN_PI_SHIFT, 53 + }; 54 + 55 + static const struct zx_crtc_regs aux_crtc_regs = { 56 + .fir_active = FIR_AUX_ACTIVE, 57 + .fir_htiming = FIR_AUX_H_TIMING, 58 + .fir_vtiming = FIR_AUX_V_TIMING, 59 + .timing_shift = TIMING_AUX_SHIFT, 60 + .timing_pi_shift = TIMING_AUX_PI_SHIFT, 61 + }; 62 + 63 + struct zx_crtc_bits { 64 + u32 polarity_mask; 65 + u32 polarity_shift; 66 + u32 int_frame_mask; 67 + u32 tc_enable; 68 + u32 gl_enable; 69 + }; 70 + 71 + static const struct zx_crtc_bits main_crtc_bits = { 72 + .polarity_mask = MAIN_POL_MASK, 73 + .polarity_shift = MAIN_POL_SHIFT, 74 + .int_frame_mask = TIMING_INT_MAIN_FRAME, 75 + .tc_enable = MAIN_TC_EN, 76 + .gl_enable = OSD_CTRL0_GL0_EN, 77 + }; 78 + 79 + static const struct zx_crtc_bits aux_crtc_bits = { 80 + .polarity_mask = AUX_POL_MASK, 81 + .polarity_shift = AUX_POL_SHIFT, 82 + .int_frame_mask = TIMING_INT_AUX_FRAME, 83 + .tc_enable = AUX_TC_EN, 84 + .gl_enable = OSD_CTRL0_GL1_EN, 85 + }; 86 + 87 + struct zx_crtc { 88 + struct drm_crtc crtc; 89 + struct drm_plane *primary; 90 + struct zx_vou_hw *vou; 91 + void __iomem *chnreg; 92 + const struct zx_crtc_regs *regs; 93 + const struct zx_crtc_bits *bits; 94 + enum vou_chn_type chn_type; 95 + struct clk *pixclk; 96 + }; 97 + 98 + #define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc) 99 + 100 + struct zx_vou_hw { 101 + struct device *dev; 102 + void __iomem *osd; 103 + void __iomem *timing; 104 + void __iomem *vouctl; 105 + void __iomem *otfppu; 106 + void __iomem *dtrc; 107 + struct clk *axi_clk; 108 + struct clk *ppu_clk; 109 + struct clk *main_clk; 110 + struct clk *aux_clk; 111 + struct zx_crtc *main_crtc; 112 + struct zx_crtc *aux_crtc; 113 + }; 114 + 115 + static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc) 116 + { 117 + struct zx_crtc *zcrtc = to_zx_crtc(crtc); 118 + 119 + return zcrtc->vou; 120 + } 121 + 122 + void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc) 123 + { 124 + struct zx_crtc *zcrtc = to_zx_crtc(crtc); 125 + struct zx_vou_hw *vou = zcrtc->vou; 126 + bool is_main = zcrtc->chn_type == VOU_CHN_MAIN; 127 + u32 data_sel_shift = inf->id << 1; 128 + 129 + /* Select data format */ 130 + zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift, 131 + inf->data_sel << data_sel_shift); 132 + 133 + /* Select channel */ 134 + zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << inf->id, 135 + zcrtc->chn_type << inf->id); 136 + 137 + /* Select interface clocks */ 138 + zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits, 139 + is_main ? 0 : inf->clocks_sel_bits); 140 + 141 + /* Enable interface clocks */ 142 + zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 143 + inf->clocks_en_bits); 144 + 145 + /* Enable the device */ 146 + zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 1 << inf->id); 147 + } 148 + 149 + void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc) 150 + { 151 + struct zx_vou_hw *vou = crtc_to_vou(crtc); 152 + 153 + /* Disable the device */ 154 + zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 0); 155 + 156 + /* Disable interface clocks */ 157 + zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0); 158 + } 159 + 160 + static inline void vou_chn_set_update(struct zx_crtc *zcrtc) 161 + { 162 + zx_writel(zcrtc->chnreg + CHN_UPDATE, 1); 163 + } 164 + 165 + static void zx_crtc_enable(struct drm_crtc *crtc) 166 + { 167 + struct drm_display_mode *mode = &crtc->state->adjusted_mode; 168 + struct zx_crtc *zcrtc = to_zx_crtc(crtc); 169 + struct zx_vou_hw *vou = zcrtc->vou; 170 + const struct zx_crtc_regs *regs = zcrtc->regs; 171 + const struct zx_crtc_bits *bits = zcrtc->bits; 172 + struct videomode vm; 173 + u32 pol = 0; 174 + u32 val; 175 + int ret; 176 + 177 + drm_display_mode_to_videomode(mode, &vm); 178 + 179 + /* Set up timing parameters */ 180 + val = V_ACTIVE(vm.vactive - 1); 181 + val |= H_ACTIVE(vm.hactive - 1); 182 + zx_writel(vou->timing + regs->fir_active, val); 183 + 184 + val = SYNC_WIDE(vm.hsync_len - 1); 185 + val |= BACK_PORCH(vm.hback_porch - 1); 186 + val |= FRONT_PORCH(vm.hfront_porch - 1); 187 + zx_writel(vou->timing + regs->fir_htiming, val); 188 + 189 + val = SYNC_WIDE(vm.vsync_len - 1); 190 + val |= BACK_PORCH(vm.vback_porch - 1); 191 + val |= FRONT_PORCH(vm.vfront_porch - 1); 192 + zx_writel(vou->timing + regs->fir_vtiming, val); 193 + 194 + /* Set up polarities */ 195 + if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW) 196 + pol |= 1 << POL_VSYNC_SHIFT; 197 + if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW) 198 + pol |= 1 << POL_HSYNC_SHIFT; 199 + 200 + zx_writel_mask(vou->timing + TIMING_CTRL, bits->polarity_mask, 201 + pol << bits->polarity_shift); 202 + 203 + /* Setup SHIFT register by following what ZTE BSP does */ 204 + zx_writel(vou->timing + regs->timing_shift, H_SHIFT_VAL); 205 + zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL); 206 + 207 + /* Enable TIMING_CTRL */ 208 + zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable, 209 + bits->tc_enable); 210 + 211 + /* Configure channel screen size */ 212 + zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_W_MASK, 213 + vm.hactive << CHN_SCREEN_W_SHIFT); 214 + zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK, 215 + vm.vactive << CHN_SCREEN_H_SHIFT); 216 + 217 + /* Update channel */ 218 + vou_chn_set_update(zcrtc); 219 + 220 + /* Enable channel */ 221 + zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, CHN_ENABLE); 222 + 223 + /* Enable Graphic Layer */ 224 + zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable, 225 + bits->gl_enable); 226 + 227 + drm_crtc_vblank_on(crtc); 228 + 229 + ret = clk_set_rate(zcrtc->pixclk, mode->clock * 1000); 230 + if (ret) { 231 + DRM_DEV_ERROR(vou->dev, "failed to set pixclk rate: %d\n", ret); 232 + return; 233 + } 234 + 235 + ret = clk_prepare_enable(zcrtc->pixclk); 236 + if (ret) 237 + DRM_DEV_ERROR(vou->dev, "failed to enable pixclk: %d\n", ret); 238 + } 239 + 240 + static void zx_crtc_disable(struct drm_crtc *crtc) 241 + { 242 + struct zx_crtc *zcrtc = to_zx_crtc(crtc); 243 + const struct zx_crtc_bits *bits = zcrtc->bits; 244 + struct zx_vou_hw *vou = zcrtc->vou; 245 + 246 + clk_disable_unprepare(zcrtc->pixclk); 247 + 248 + drm_crtc_vblank_off(crtc); 249 + 250 + /* Disable Graphic Layer */ 251 + zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable, 0); 252 + 253 + /* Disable channel */ 254 + zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, 0); 255 + 256 + /* Disable TIMING_CTRL */ 257 + zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable, 0); 258 + } 259 + 260 + static void zx_crtc_atomic_flush(struct drm_crtc *crtc, 261 + struct drm_crtc_state *old_state) 262 + { 263 + struct drm_pending_vblank_event *event = crtc->state->event; 264 + 265 + if (!event) 266 + return; 267 + 268 + crtc->state->event = NULL; 269 + 270 + spin_lock_irq(&crtc->dev->event_lock); 271 + if (drm_crtc_vblank_get(crtc) == 0) 272 + drm_crtc_arm_vblank_event(crtc, event); 273 + else 274 + drm_crtc_send_vblank_event(crtc, event); 275 + spin_unlock_irq(&crtc->dev->event_lock); 276 + } 277 + 278 + static const struct drm_crtc_helper_funcs zx_crtc_helper_funcs = { 279 + .enable = zx_crtc_enable, 280 + .disable = zx_crtc_disable, 281 + .atomic_flush = zx_crtc_atomic_flush, 282 + }; 283 + 284 + static const struct drm_crtc_funcs zx_crtc_funcs = { 285 + .destroy = drm_crtc_cleanup, 286 + .set_config = drm_atomic_helper_set_config, 287 + .page_flip = drm_atomic_helper_page_flip, 288 + .reset = drm_atomic_helper_crtc_reset, 289 + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 290 + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 291 + }; 292 + 293 + static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou, 294 + enum vou_chn_type chn_type) 295 + { 296 + struct device *dev = vou->dev; 297 + struct zx_layer_data data; 298 + struct zx_crtc *zcrtc; 299 + int ret; 300 + 301 + zcrtc = devm_kzalloc(dev, sizeof(*zcrtc), GFP_KERNEL); 302 + if (!zcrtc) 303 + return -ENOMEM; 304 + 305 + zcrtc->vou = vou; 306 + zcrtc->chn_type = chn_type; 307 + 308 + if (chn_type == VOU_CHN_MAIN) { 309 + data.layer = vou->osd + MAIN_GL_OFFSET; 310 + data.csc = vou->osd + MAIN_CSC_OFFSET; 311 + data.hbsc = vou->osd + MAIN_HBSC_OFFSET; 312 + data.rsz = vou->otfppu + MAIN_RSZ_OFFSET; 313 + zcrtc->chnreg = vou->osd + OSD_MAIN_CHN; 314 + zcrtc->regs = &main_crtc_regs; 315 + zcrtc->bits = &main_crtc_bits; 316 + } else { 317 + data.layer = vou->osd + AUX_GL_OFFSET; 318 + data.csc = vou->osd + AUX_CSC_OFFSET; 319 + data.hbsc = vou->osd + AUX_HBSC_OFFSET; 320 + data.rsz = vou->otfppu + AUX_RSZ_OFFSET; 321 + zcrtc->chnreg = vou->osd + OSD_AUX_CHN; 322 + zcrtc->regs = &aux_crtc_regs; 323 + zcrtc->bits = &aux_crtc_bits; 324 + } 325 + 326 + zcrtc->pixclk = devm_clk_get(dev, (chn_type == VOU_CHN_MAIN) ? 327 + "main_wclk" : "aux_wclk"); 328 + if (IS_ERR(zcrtc->pixclk)) { 329 + ret = PTR_ERR(zcrtc->pixclk); 330 + DRM_DEV_ERROR(dev, "failed to get pix clk: %d\n", ret); 331 + return ret; 332 + } 333 + 334 + zcrtc->primary = zx_plane_init(drm, dev, &data, DRM_PLANE_TYPE_PRIMARY); 335 + if (IS_ERR(zcrtc->primary)) { 336 + ret = PTR_ERR(zcrtc->primary); 337 + DRM_DEV_ERROR(dev, "failed to init primary plane: %d\n", ret); 338 + return ret; 339 + } 340 + 341 + ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL, 342 + &zx_crtc_funcs, NULL); 343 + if (ret) { 344 + DRM_DEV_ERROR(dev, "failed to init drm crtc: %d\n", ret); 345 + return ret; 346 + } 347 + 348 + drm_crtc_helper_add(&zcrtc->crtc, &zx_crtc_helper_funcs); 349 + 350 + if (chn_type == VOU_CHN_MAIN) 351 + vou->main_crtc = zcrtc; 352 + else 353 + vou->aux_crtc = zcrtc; 354 + 355 + return 0; 356 + } 357 + 358 + static inline struct drm_crtc *zx_find_crtc(struct drm_device *drm, int pipe) 359 + { 360 + struct drm_crtc *crtc; 361 + 362 + list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) 363 + if (crtc->index == pipe) 364 + return crtc; 365 + 366 + return NULL; 367 + } 368 + 369 + int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe) 370 + { 371 + struct drm_crtc *crtc; 372 + struct zx_crtc *zcrtc; 373 + struct zx_vou_hw *vou; 374 + u32 int_frame_mask; 375 + 376 + crtc = zx_find_crtc(drm, pipe); 377 + if (!crtc) 378 + return 0; 379 + 380 + vou = crtc_to_vou(crtc); 381 + zcrtc = to_zx_crtc(crtc); 382 + int_frame_mask = zcrtc->bits->int_frame_mask; 383 + 384 + zx_writel_mask(vou->timing + TIMING_INT_CTRL, int_frame_mask, 385 + int_frame_mask); 386 + 387 + return 0; 388 + } 389 + 390 + void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe) 391 + { 392 + struct drm_crtc *crtc; 393 + struct zx_crtc *zcrtc; 394 + struct zx_vou_hw *vou; 395 + 396 + crtc = zx_find_crtc(drm, pipe); 397 + if (!crtc) 398 + return; 399 + 400 + vou = crtc_to_vou(crtc); 401 + zcrtc = to_zx_crtc(crtc); 402 + 403 + zx_writel_mask(vou->timing + TIMING_INT_CTRL, 404 + zcrtc->bits->int_frame_mask, 0); 405 + } 406 + 407 + static irqreturn_t vou_irq_handler(int irq, void *dev_id) 408 + { 409 + struct zx_vou_hw *vou = dev_id; 410 + u32 state; 411 + 412 + /* Handle TIMING_CTRL frame interrupts */ 413 + state = zx_readl(vou->timing + TIMING_INT_STATE); 414 + zx_writel(vou->timing + TIMING_INT_STATE, state); 415 + 416 + if (state & TIMING_INT_MAIN_FRAME) 417 + drm_crtc_handle_vblank(&vou->main_crtc->crtc); 418 + 419 + if (state & TIMING_INT_AUX_FRAME) 420 + drm_crtc_handle_vblank(&vou->aux_crtc->crtc); 421 + 422 + /* Handle OSD interrupts */ 423 + state = zx_readl(vou->osd + OSD_INT_STA); 424 + zx_writel(vou->osd + OSD_INT_CLRSTA, state); 425 + 426 + if (state & OSD_INT_MAIN_UPT) { 427 + vou_chn_set_update(vou->main_crtc); 428 + zx_plane_set_update(vou->main_crtc->primary); 429 + } 430 + 431 + if (state & OSD_INT_AUX_UPT) { 432 + vou_chn_set_update(vou->aux_crtc); 433 + zx_plane_set_update(vou->aux_crtc->primary); 434 + } 435 + 436 + if (state & OSD_INT_ERROR) 437 + DRM_DEV_ERROR(vou->dev, "OSD ERROR: 0x%08x!\n", state); 438 + 439 + return IRQ_HANDLED; 440 + } 441 + 442 + static void vou_dtrc_init(struct zx_vou_hw *vou) 443 + { 444 + /* Clear bit for bypass by ID */ 445 + zx_writel_mask(vou->dtrc + DTRC_DETILE_CTRL, 446 + TILE2RASTESCAN_BYPASS_MODE, 0); 447 + 448 + /* Select ARIDR mode */ 449 + zx_writel_mask(vou->dtrc + DTRC_DETILE_CTRL, DETILE_ARIDR_MODE_MASK, 450 + DETILE_ARID_IN_ARIDR); 451 + 452 + /* Bypass decompression for both frames */ 453 + zx_writel_mask(vou->dtrc + DTRC_F0_CTRL, DTRC_DECOMPRESS_BYPASS, 454 + DTRC_DECOMPRESS_BYPASS); 455 + zx_writel_mask(vou->dtrc + DTRC_F1_CTRL, DTRC_DECOMPRESS_BYPASS, 456 + DTRC_DECOMPRESS_BYPASS); 457 + 458 + /* Set up ARID register */ 459 + zx_writel(vou->dtrc + DTRC_ARID, DTRC_ARID3(0xf) | DTRC_ARID2(0xe) | 460 + DTRC_ARID1(0xf) | DTRC_ARID0(0xe)); 461 + } 462 + 463 + static void vou_hw_init(struct zx_vou_hw *vou) 464 + { 465 + /* Set GL0 to main channel and GL1 to aux channel */ 466 + zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL0_SEL, 0); 467 + zx_writel_mask(vou->osd + OSD_CTRL0, OSD_CTRL0_GL1_SEL, 468 + OSD_CTRL0_GL1_SEL); 469 + 470 + /* Release reset for all VOU modules */ 471 + zx_writel(vou->vouctl + VOU_SOFT_RST, ~0); 472 + 473 + /* Select main clock for GL0 and aux clock for GL1 module */ 474 + zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL0_SEL, 0); 475 + zx_writel_mask(vou->vouctl + VOU_CLK_SEL, VOU_CLK_GL1_SEL, 476 + VOU_CLK_GL1_SEL); 477 + 478 + /* Enable clock auto-gating for all VOU modules */ 479 + zx_writel(vou->vouctl + VOU_CLK_REQEN, ~0); 480 + 481 + /* Enable all VOU module clocks */ 482 + zx_writel(vou->vouctl + VOU_CLK_EN, ~0); 483 + 484 + /* Clear both OSD and TIMING_CTRL interrupt state */ 485 + zx_writel(vou->osd + OSD_INT_CLRSTA, ~0); 486 + zx_writel(vou->timing + TIMING_INT_STATE, ~0); 487 + 488 + /* Enable OSD and TIMING_CTRL interrrupts */ 489 + zx_writel(vou->osd + OSD_INT_MSK, OSD_INT_ENABLE); 490 + zx_writel(vou->timing + TIMING_INT_CTRL, TIMING_INT_ENABLE); 491 + 492 + /* Select GPC as input to gl/vl scaler as a sane default setting */ 493 + zx_writel(vou->otfppu + OTFPPU_RSZ_DATA_SOURCE, 0x2a); 494 + 495 + /* 496 + * Needs to reset channel and layer logic per frame when frame starts 497 + * to get VOU work properly. 498 + */ 499 + zx_writel_mask(vou->osd + OSD_RST_CLR, RST_PER_FRAME, RST_PER_FRAME); 500 + 501 + vou_dtrc_init(vou); 502 + } 503 + 504 + static int zx_crtc_bind(struct device *dev, struct device *master, void *data) 505 + { 506 + struct platform_device *pdev = to_platform_device(dev); 507 + struct drm_device *drm = data; 508 + struct zx_vou_hw *vou; 509 + struct resource *res; 510 + int irq; 511 + int ret; 512 + 513 + vou = devm_kzalloc(dev, sizeof(*vou), GFP_KERNEL); 514 + if (!vou) 515 + return -ENOMEM; 516 + 517 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "osd"); 518 + vou->osd = devm_ioremap_resource(dev, res); 519 + if (IS_ERR(vou->osd)) { 520 + ret = PTR_ERR(vou->osd); 521 + DRM_DEV_ERROR(dev, "failed to remap osd region: %d\n", ret); 522 + return ret; 523 + } 524 + 525 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "timing_ctrl"); 526 + vou->timing = devm_ioremap_resource(dev, res); 527 + if (IS_ERR(vou->timing)) { 528 + ret = PTR_ERR(vou->timing); 529 + DRM_DEV_ERROR(dev, "failed to remap timing_ctrl region: %d\n", 530 + ret); 531 + return ret; 532 + } 533 + 534 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dtrc"); 535 + vou->dtrc = devm_ioremap_resource(dev, res); 536 + if (IS_ERR(vou->dtrc)) { 537 + ret = PTR_ERR(vou->dtrc); 538 + DRM_DEV_ERROR(dev, "failed to remap dtrc region: %d\n", ret); 539 + return ret; 540 + } 541 + 542 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vou_ctrl"); 543 + vou->vouctl = devm_ioremap_resource(dev, res); 544 + if (IS_ERR(vou->vouctl)) { 545 + ret = PTR_ERR(vou->vouctl); 546 + DRM_DEV_ERROR(dev, "failed to remap vou_ctrl region: %d\n", 547 + ret); 548 + return ret; 549 + } 550 + 551 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otfppu"); 552 + vou->otfppu = devm_ioremap_resource(dev, res); 553 + if (IS_ERR(vou->otfppu)) { 554 + ret = PTR_ERR(vou->otfppu); 555 + DRM_DEV_ERROR(dev, "failed to remap otfppu region: %d\n", ret); 556 + return ret; 557 + } 558 + 559 + irq = platform_get_irq(pdev, 0); 560 + if (irq < 0) 561 + return irq; 562 + 563 + vou->axi_clk = devm_clk_get(dev, "aclk"); 564 + if (IS_ERR(vou->axi_clk)) { 565 + ret = PTR_ERR(vou->axi_clk); 566 + DRM_DEV_ERROR(dev, "failed to get axi_clk: %d\n", ret); 567 + return ret; 568 + } 569 + 570 + vou->ppu_clk = devm_clk_get(dev, "ppu_wclk"); 571 + if (IS_ERR(vou->ppu_clk)) { 572 + ret = PTR_ERR(vou->ppu_clk); 573 + DRM_DEV_ERROR(dev, "failed to get ppu_clk: %d\n", ret); 574 + return ret; 575 + } 576 + 577 + ret = clk_prepare_enable(vou->axi_clk); 578 + if (ret) { 579 + DRM_DEV_ERROR(dev, "failed to enable axi_clk: %d\n", ret); 580 + return ret; 581 + } 582 + 583 + clk_prepare_enable(vou->ppu_clk); 584 + if (ret) { 585 + DRM_DEV_ERROR(dev, "failed to enable ppu_clk: %d\n", ret); 586 + goto disable_axi_clk; 587 + } 588 + 589 + vou->dev = dev; 590 + dev_set_drvdata(dev, vou); 591 + 592 + vou_hw_init(vou); 593 + 594 + ret = devm_request_irq(dev, irq, vou_irq_handler, 0, "zx_vou", vou); 595 + if (ret < 0) { 596 + DRM_DEV_ERROR(dev, "failed to request vou irq: %d\n", ret); 597 + goto disable_ppu_clk; 598 + } 599 + 600 + ret = zx_crtc_init(drm, vou, VOU_CHN_MAIN); 601 + if (ret) { 602 + DRM_DEV_ERROR(dev, "failed to init main channel crtc: %d\n", 603 + ret); 604 + goto disable_ppu_clk; 605 + } 606 + 607 + ret = zx_crtc_init(drm, vou, VOU_CHN_AUX); 608 + if (ret) { 609 + DRM_DEV_ERROR(dev, "failed to init aux channel crtc: %d\n", 610 + ret); 611 + goto disable_ppu_clk; 612 + } 613 + 614 + return 0; 615 + 616 + disable_ppu_clk: 617 + clk_disable_unprepare(vou->ppu_clk); 618 + disable_axi_clk: 619 + clk_disable_unprepare(vou->axi_clk); 620 + return ret; 621 + } 622 + 623 + static void zx_crtc_unbind(struct device *dev, struct device *master, 624 + void *data) 625 + { 626 + struct zx_vou_hw *vou = dev_get_drvdata(dev); 627 + 628 + clk_disable_unprepare(vou->axi_clk); 629 + clk_disable_unprepare(vou->ppu_clk); 630 + } 631 + 632 + static const struct component_ops zx_crtc_component_ops = { 633 + .bind = zx_crtc_bind, 634 + .unbind = zx_crtc_unbind, 635 + }; 636 + 637 + static int zx_crtc_probe(struct platform_device *pdev) 638 + { 639 + return component_add(&pdev->dev, &zx_crtc_component_ops); 640 + } 641 + 642 + static int zx_crtc_remove(struct platform_device *pdev) 643 + { 644 + component_del(&pdev->dev, &zx_crtc_component_ops); 645 + return 0; 646 + } 647 + 648 + static const struct of_device_id zx_crtc_of_match[] = { 649 + { .compatible = "zte,zx296718-dpc", }, 650 + { /* end */ }, 651 + }; 652 + MODULE_DEVICE_TABLE(of, zx_crtc_of_match); 653 + 654 + struct platform_driver zx_crtc_driver = { 655 + .probe = zx_crtc_probe, 656 + .remove = zx_crtc_remove, 657 + .driver = { 658 + .name = "zx-crtc", 659 + .of_match_table = zx_crtc_of_match, 660 + }, 661 + };
+46
drivers/gpu/drm/zte/zx_vou.h
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #ifndef __ZX_VOU_H__ 12 + #define __ZX_VOU_H__ 13 + 14 + #define VOU_CRTC_MASK 0x3 15 + 16 + /* VOU output interfaces */ 17 + enum vou_inf_id { 18 + VOU_HDMI = 0, 19 + VOU_RGB_LCD = 1, 20 + VOU_TV_ENC = 2, 21 + VOU_MIPI_DSI = 3, 22 + VOU_LVDS = 4, 23 + VOU_VGA = 5, 24 + }; 25 + 26 + enum vou_inf_data_sel { 27 + VOU_YUV444 = 0, 28 + VOU_RGB_101010 = 1, 29 + VOU_RGB_888 = 2, 30 + VOU_RGB_666 = 3, 31 + }; 32 + 33 + struct vou_inf { 34 + enum vou_inf_id id; 35 + enum vou_inf_data_sel data_sel; 36 + u32 clocks_en_bits; 37 + u32 clocks_sel_bits; 38 + }; 39 + 40 + void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc); 41 + void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc); 42 + 43 + int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe); 44 + void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe); 45 + 46 + #endif /* __ZX_VOU_H__ */
+157
drivers/gpu/drm/zte/zx_vou_regs.h
··· 1 + /* 2 + * Copyright 2016 Linaro Ltd. 3 + * Copyright 2016 ZTE Corporation. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + */ 10 + 11 + #ifndef __ZX_VOU_REGS_H__ 12 + #define __ZX_VOU_REGS_H__ 13 + 14 + /* Sub-module offset */ 15 + #define MAIN_GL_OFFSET 0x130 16 + #define MAIN_CSC_OFFSET 0x580 17 + #define MAIN_HBSC_OFFSET 0x820 18 + #define MAIN_RSZ_OFFSET 0x600 /* OTFPPU sub-module */ 19 + 20 + #define AUX_GL_OFFSET 0x200 21 + #define AUX_CSC_OFFSET 0x5d0 22 + #define AUX_HBSC_OFFSET 0x860 23 + #define AUX_RSZ_OFFSET 0x800 24 + 25 + /* OSD (GPC_GLOBAL) registers */ 26 + #define OSD_INT_STA 0x04 27 + #define OSD_INT_CLRSTA 0x08 28 + #define OSD_INT_MSK 0x0c 29 + #define OSD_INT_AUX_UPT BIT(14) 30 + #define OSD_INT_MAIN_UPT BIT(13) 31 + #define OSD_INT_GL1_LBW BIT(10) 32 + #define OSD_INT_GL0_LBW BIT(9) 33 + #define OSD_INT_VL2_LBW BIT(8) 34 + #define OSD_INT_VL1_LBW BIT(7) 35 + #define OSD_INT_VL0_LBW BIT(6) 36 + #define OSD_INT_BUS_ERR BIT(3) 37 + #define OSD_INT_CFG_ERR BIT(2) 38 + #define OSD_INT_ERROR (\ 39 + OSD_INT_GL1_LBW | OSD_INT_GL0_LBW | \ 40 + OSD_INT_VL2_LBW | OSD_INT_VL1_LBW | OSD_INT_VL0_LBW | \ 41 + OSD_INT_BUS_ERR | OSD_INT_CFG_ERR \ 42 + ) 43 + #define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT) 44 + #define OSD_CTRL0 0x10 45 + #define OSD_CTRL0_GL0_EN BIT(7) 46 + #define OSD_CTRL0_GL0_SEL BIT(6) 47 + #define OSD_CTRL0_GL1_EN BIT(5) 48 + #define OSD_CTRL0_GL1_SEL BIT(4) 49 + #define OSD_RST_CLR 0x1c 50 + #define RST_PER_FRAME BIT(19) 51 + 52 + /* Main/Aux channel registers */ 53 + #define OSD_MAIN_CHN 0x470 54 + #define OSD_AUX_CHN 0x4d0 55 + #define CHN_CTRL0 0x00 56 + #define CHN_ENABLE BIT(0) 57 + #define CHN_CTRL1 0x04 58 + #define CHN_SCREEN_W_SHIFT 18 59 + #define CHN_SCREEN_W_MASK (0x1fff << CHN_SCREEN_W_SHIFT) 60 + #define CHN_SCREEN_H_SHIFT 5 61 + #define CHN_SCREEN_H_MASK (0x1fff << CHN_SCREEN_H_SHIFT) 62 + #define CHN_UPDATE 0x08 63 + 64 + /* TIMING_CTRL registers */ 65 + #define TIMING_TC_ENABLE 0x04 66 + #define AUX_TC_EN BIT(1) 67 + #define MAIN_TC_EN BIT(0) 68 + #define FIR_MAIN_ACTIVE 0x08 69 + #define FIR_AUX_ACTIVE 0x0c 70 + #define V_ACTIVE_SHIFT 16 71 + #define V_ACTIVE_MASK (0xffff << V_ACTIVE_SHIFT) 72 + #define H_ACTIVE_SHIFT 0 73 + #define H_ACTIVE_MASK (0xffff << H_ACTIVE_SHIFT) 74 + #define FIR_MAIN_H_TIMING 0x10 75 + #define FIR_MAIN_V_TIMING 0x14 76 + #define FIR_AUX_H_TIMING 0x18 77 + #define FIR_AUX_V_TIMING 0x1c 78 + #define SYNC_WIDE_SHIFT 22 79 + #define SYNC_WIDE_MASK (0x3ff << SYNC_WIDE_SHIFT) 80 + #define BACK_PORCH_SHIFT 11 81 + #define BACK_PORCH_MASK (0x7ff << BACK_PORCH_SHIFT) 82 + #define FRONT_PORCH_SHIFT 0 83 + #define FRONT_PORCH_MASK (0x7ff << FRONT_PORCH_SHIFT) 84 + #define TIMING_CTRL 0x20 85 + #define AUX_POL_SHIFT 3 86 + #define AUX_POL_MASK (0x7 << AUX_POL_SHIFT) 87 + #define MAIN_POL_SHIFT 0 88 + #define MAIN_POL_MASK (0x7 << MAIN_POL_SHIFT) 89 + #define POL_DE_SHIFT 2 90 + #define POL_VSYNC_SHIFT 1 91 + #define POL_HSYNC_SHIFT 0 92 + #define TIMING_INT_CTRL 0x24 93 + #define TIMING_INT_STATE 0x28 94 + #define TIMING_INT_AUX_FRAME BIT(3) 95 + #define TIMING_INT_MAIN_FRAME BIT(1) 96 + #define TIMING_INT_AUX_FRAME_SEL_VSW (0x2 << 10) 97 + #define TIMING_INT_MAIN_FRAME_SEL_VSW (0x2 << 6) 98 + #define TIMING_INT_ENABLE (\ 99 + TIMING_INT_MAIN_FRAME_SEL_VSW | TIMING_INT_AUX_FRAME_SEL_VSW | \ 100 + TIMING_INT_MAIN_FRAME | TIMING_INT_AUX_FRAME \ 101 + ) 102 + #define TIMING_MAIN_SHIFT 0x2c 103 + #define TIMING_AUX_SHIFT 0x30 104 + #define H_SHIFT_VAL 0x0048 105 + #define TIMING_MAIN_PI_SHIFT 0x68 106 + #define TIMING_AUX_PI_SHIFT 0x6c 107 + #define H_PI_SHIFT_VAL 0x000f 108 + 109 + #define V_ACTIVE(x) (((x) << V_ACTIVE_SHIFT) & V_ACTIVE_MASK) 110 + #define H_ACTIVE(x) (((x) << H_ACTIVE_SHIFT) & H_ACTIVE_MASK) 111 + 112 + #define SYNC_WIDE(x) (((x) << SYNC_WIDE_SHIFT) & SYNC_WIDE_MASK) 113 + #define BACK_PORCH(x) (((x) << BACK_PORCH_SHIFT) & BACK_PORCH_MASK) 114 + #define FRONT_PORCH(x) (((x) << FRONT_PORCH_SHIFT) & FRONT_PORCH_MASK) 115 + 116 + /* DTRC registers */ 117 + #define DTRC_F0_CTRL 0x2c 118 + #define DTRC_F1_CTRL 0x5c 119 + #define DTRC_DECOMPRESS_BYPASS BIT(17) 120 + #define DTRC_DETILE_CTRL 0x68 121 + #define TILE2RASTESCAN_BYPASS_MODE BIT(30) 122 + #define DETILE_ARIDR_MODE_MASK (0x3 << 0) 123 + #define DETILE_ARID_ALL 0 124 + #define DETILE_ARID_IN_ARIDR 1 125 + #define DETILE_ARID_BYP_BUT_ARIDR 2 126 + #define DETILE_ARID_IN_ARIDR2 3 127 + #define DTRC_ARID 0x6c 128 + #define DTRC_ARID3_SHIFT 24 129 + #define DTRC_ARID3_MASK (0xff << DTRC_ARID3_SHIFT) 130 + #define DTRC_ARID2_SHIFT 16 131 + #define DTRC_ARID2_MASK (0xff << DTRC_ARID2_SHIFT) 132 + #define DTRC_ARID1_SHIFT 8 133 + #define DTRC_ARID1_MASK (0xff << DTRC_ARID1_SHIFT) 134 + #define DTRC_ARID0_SHIFT 0 135 + #define DTRC_ARID0_MASK (0xff << DTRC_ARID0_SHIFT) 136 + #define DTRC_DEC2DDR_ARID 0x70 137 + 138 + #define DTRC_ARID3(x) (((x) << DTRC_ARID3_SHIFT) & DTRC_ARID3_MASK) 139 + #define DTRC_ARID2(x) (((x) << DTRC_ARID2_SHIFT) & DTRC_ARID2_MASK) 140 + #define DTRC_ARID1(x) (((x) << DTRC_ARID1_SHIFT) & DTRC_ARID1_MASK) 141 + #define DTRC_ARID0(x) (((x) << DTRC_ARID0_SHIFT) & DTRC_ARID0_MASK) 142 + 143 + /* VOU_CTRL registers */ 144 + #define VOU_INF_EN 0x00 145 + #define VOU_INF_CH_SEL 0x04 146 + #define VOU_INF_DATA_SEL 0x08 147 + #define VOU_SOFT_RST 0x14 148 + #define VOU_CLK_SEL 0x18 149 + #define VOU_CLK_GL1_SEL BIT(5) 150 + #define VOU_CLK_GL0_SEL BIT(4) 151 + #define VOU_CLK_REQEN 0x20 152 + #define VOU_CLK_EN 0x24 153 + 154 + /* OTFPPU_CTRL registers */ 155 + #define OTFPPU_RSZ_DATA_SOURCE 0x04 156 + 157 + #endif /* __ZX_VOU_REGS_H__ */