aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Guo <shawn.guo@linaro.org>2016-09-22 07:52:39 -0400
committerShawn Guo <shawnguo@kernel.org>2016-11-06 22:02:31 -0500
commit0a886f59528aac568cf9e4981167b5dcdd3d1676 (patch)
tree4fe6199418398bdc57ff0cc2079b1d46033e22ad
parentf78dd2c210b508e70d5559d65bf2b64904864919 (diff)
drm: zte: add initial vou drm driver
It adds the initial ZTE VOU display controller DRM 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 monitor working. Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile1
-rw-r--r--drivers/gpu/drm/zte/Kconfig8
-rw-r--r--drivers/gpu/drm/zte/Makefile7
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.c267
-rw-r--r--drivers/gpu/drm/zte/zx_drm_drv.h36
-rw-r--r--drivers/gpu/drm/zte/zx_hdmi.c624
-rw-r--r--drivers/gpu/drm/zte/zx_hdmi_regs.h56
-rw-r--r--drivers/gpu/drm/zte/zx_plane.c299
-rw-r--r--drivers/gpu/drm/zte/zx_plane.h26
-rw-r--r--drivers/gpu/drm/zte/zx_plane_regs.h91
-rw-r--r--drivers/gpu/drm/zte/zx_vou.c661
-rw-r--r--drivers/gpu/drm/zte/zx_vou.h46
-rw-r--r--drivers/gpu/drm/zte/zx_vou_regs.h157
14 files changed, 2281 insertions, 0 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 483059a22b1b..a91f8cecbe0f 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -223,6 +223,8 @@ source "drivers/gpu/drm/hisilicon/Kconfig"
223 223
224source "drivers/gpu/drm/mediatek/Kconfig" 224source "drivers/gpu/drm/mediatek/Kconfig"
225 225
226source "drivers/gpu/drm/zte/Kconfig"
227
226# Keep legacy drivers last 228# Keep legacy drivers last
227 229
228menuconfig DRM_LEGACY 230menuconfig DRM_LEGACY
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 25c720454017..f3251750c92b 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -86,3 +86,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
86obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/ 86obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
87obj-$(CONFIG_DRM_ARCPGU)+= arc/ 87obj-$(CONFIG_DRM_ARCPGU)+= arc/
88obj-y += hisilicon/ 88obj-y += hisilicon/
89obj-$(CONFIG_DRM_ZTE) += zte/
diff --git a/drivers/gpu/drm/zte/Kconfig b/drivers/gpu/drm/zte/Kconfig
new file mode 100644
index 000000000000..4065b2840f1c
--- /dev/null
+++ b/drivers/gpu/drm/zte/Kconfig
@@ -0,0 +1,8 @@
1config 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.
diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile
new file mode 100644
index 000000000000..699180bfd57c
--- /dev/null
+++ b/drivers/gpu/drm/zte/Makefile
@@ -0,0 +1,7 @@
1zxdrm-y := \
2 zx_drm_drv.o \
3 zx_hdmi.o \
4 zx_plane.o \
5 zx_vou.o
6
7obj-$(CONFIG_DRM_ZTE) += zxdrm.o
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
new file mode 100644
index 000000000000..abc8099e6f53
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -0,0 +1,267 @@
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
31struct zx_drm_private {
32 struct drm_fbdev_cma *fbdev;
33};
34
35static 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
42static 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
49static 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
56static 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
70static 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
99static 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
159out_fbdev_fini:
160 if (priv->fbdev) {
161 drm_fbdev_cma_fini(priv->fbdev);
162 priv->fbdev = NULL;
163 }
164out_poll_fini:
165 drm_kms_helper_poll_fini(drm);
166 drm_mode_config_cleanup(drm);
167 drm_vblank_cleanup(drm);
168out_unbind:
169 component_unbind_all(dev, drm);
170out_unregister:
171 dev_set_drvdata(dev, NULL);
172 drm->dev_private = NULL;
173 drm_dev_unref(drm);
174 return ret;
175}
176
177static 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
196static const struct component_master_ops zx_drm_master_ops = {
197 .bind = zx_drm_bind,
198 .unbind = zx_drm_unbind,
199};
200
201static int compare_of(struct device *dev, void *data)
202{
203 return dev->of_node == data;
204}
205
206static 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
226static int zx_drm_remove(struct platform_device *pdev)
227{
228 component_master_del(&pdev->dev, &zx_drm_master_ops);
229 return 0;
230}
231
232static const struct of_device_id zx_drm_of_match[] = {
233 { .compatible = "zte,zx296718-vou", },
234 { /* end */ },
235};
236MODULE_DEVICE_TABLE(of, zx_drm_of_match);
237
238static 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
247static struct platform_driver *drivers[] = {
248 &zx_crtc_driver,
249 &zx_hdmi_driver,
250 &zx_drm_platform_driver,
251};
252
253static int zx_drm_init(void)
254{
255 return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
256}
257module_init(zx_drm_init);
258
259static void zx_drm_exit(void)
260{
261 platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
262}
263module_exit(zx_drm_exit);
264
265MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
266MODULE_DESCRIPTION("ZTE ZX VOU DRM driver");
267MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
new file mode 100644
index 000000000000..e65cd18a6cba
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_drm_drv.h
@@ -0,0 +1,36 @@
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
14extern struct platform_driver zx_crtc_driver;
15extern struct platform_driver zx_hdmi_driver;
16
17static inline u32 zx_readl(void __iomem *reg)
18{
19 return readl_relaxed(reg);
20}
21
22static inline void zx_writel(void __iomem *reg, u32 val)
23{
24 writel_relaxed(val, reg);
25}
26
27static 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__ */
diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
new file mode 100644
index 000000000000..6bf6c364811e
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_hdmi.c
@@ -0,0 +1,624 @@
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
34struct zx_hdmi_i2c {
35 struct i2c_adapter adap;
36 struct mutex lock;
37};
38
39struct 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
56static 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
63static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset)
64{
65 return readl_relaxed(hdmi->mmio + offset * 4);
66}
67
68static inline void hdmi_writeb(struct zx_hdmi *hdmi, u16 offset, u8 val)
69{
70 writel_relaxed(val, hdmi->mmio + offset * 4);
71}
72
73static 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
83static 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
109static 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
126static 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
145static 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
157static 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
190static 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
216static 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
231static 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
244static 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
257static 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
263static const struct drm_encoder_funcs zx_hdmi_encoder_funcs = {
264 .destroy = drm_encoder_cleanup,
265};
266
267static 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
286static enum drm_mode_status
287zx_hdmi_connector_mode_valid(struct drm_connector *connector,
288 struct drm_display_mode *mode)
289{
290 return MODE_OK;
291}
292
293static 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
298static enum drm_connector_status
299zx_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
307static 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
317static 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
339static 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
348static 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
369static 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
412static 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
432static 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
469static u32 zx_hdmi_i2c_func(struct i2c_adapter *adapter)
470{
471 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
472}
473
474static const struct i2c_algorithm zx_hdmi_algorithm = {
475 .master_xfer = zx_hdmi_i2c_xfer,
476 .functionality = zx_hdmi_i2c_func,
477};
478
479static 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
511static 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
586static 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
595static const struct component_ops zx_hdmi_component_ops = {
596 .bind = zx_hdmi_bind,
597 .unbind = zx_hdmi_unbind,
598};
599
600static int zx_hdmi_probe(struct platform_device *pdev)
601{
602 return component_add(&pdev->dev, &zx_hdmi_component_ops);
603}
604
605static int zx_hdmi_remove(struct platform_device *pdev)
606{
607 component_del(&pdev->dev, &zx_hdmi_component_ops);
608 return 0;
609}
610
611static const struct of_device_id zx_hdmi_of_match[] = {
612 { .compatible = "zte,zx296718-hdmi", },
613 { /* end */ },
614};
615MODULE_DEVICE_TABLE(of, zx_hdmi_of_match);
616
617struct 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};
diff --git a/drivers/gpu/drm/zte/zx_hdmi_regs.h b/drivers/gpu/drm/zte/zx_hdmi_regs.h
new file mode 100644
index 000000000000..de911f66b658
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_hdmi_regs.h
@@ -0,0 +1,56 @@
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__ */
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
new file mode 100644
index 000000000000..70dfea9267dd
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_plane.c
@@ -0,0 +1,299 @@
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
24struct 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
34static 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
43static 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
78static 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
98static 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
105static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
106{
107 zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
108}
109
110void 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
118static 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
129static 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 depth, 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 drm_fb_get_bpp_depth(format, &depth, &bpp);
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
213static 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
218static void zx_plane_destroy(struct drm_plane *plane)
219{
220 drm_plane_helper_disable(plane);
221 drm_plane_cleanup(plane);
222}
223
224static 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
233static 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
251struct 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}
diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
new file mode 100644
index 000000000000..2b82cd558d9d
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_plane.h
@@ -0,0 +1,26 @@
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
14struct zx_layer_data {
15 void __iomem *layer;
16 void __iomem *csc;
17 void __iomem *hbsc;
18 void __iomem *rsz;
19};
20
21struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
22 struct zx_layer_data *data,
23 enum drm_plane_type type);
24void zx_plane_set_update(struct drm_plane *plane);
25
26#endif /* __ZX_PLANE_H__ */
diff --git a/drivers/gpu/drm/zte/zx_plane_regs.h b/drivers/gpu/drm/zte/zx_plane_regs.h
new file mode 100644
index 000000000000..3dde6716a558
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_plane_regs.h
@@ -0,0 +1,91 @@
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__ */
diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
new file mode 100644
index 000000000000..73fe15c17c32
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -0,0 +1,661 @@
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
34enum vou_chn_type {
35 VOU_CHN_MAIN,
36 VOU_CHN_AUX,
37};
38
39struct 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
47static 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
55static 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
63struct 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
71static 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
79static 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
87struct 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
100struct 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
115static 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
122void 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
149void 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
160static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
161{
162 zx_writel(zcrtc->chnreg + CHN_UPDATE, 1);
163}
164
165static 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
240static 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
260static 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
278static 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
284static 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
293static 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
358static 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
369int 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
390void 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
407static 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
442static 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
463static 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
504static 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
616disable_ppu_clk:
617 clk_disable_unprepare(vou->ppu_clk);
618disable_axi_clk:
619 clk_disable_unprepare(vou->axi_clk);
620 return ret;
621}
622
623static 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
632static const struct component_ops zx_crtc_component_ops = {
633 .bind = zx_crtc_bind,
634 .unbind = zx_crtc_unbind,
635};
636
637static int zx_crtc_probe(struct platform_device *pdev)
638{
639 return component_add(&pdev->dev, &zx_crtc_component_ops);
640}
641
642static int zx_crtc_remove(struct platform_device *pdev)
643{
644 component_del(&pdev->dev, &zx_crtc_component_ops);
645 return 0;
646}
647
648static const struct of_device_id zx_crtc_of_match[] = {
649 { .compatible = "zte,zx296718-dpc", },
650 { /* end */ },
651};
652MODULE_DEVICE_TABLE(of, zx_crtc_of_match);
653
654struct 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};
diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
new file mode 100644
index 000000000000..349e06cd86f4
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_vou.h
@@ -0,0 +1,46 @@
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 */
17enum 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
26enum 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
33struct 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
40void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc);
41void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc);
42
43int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
44void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
45
46#endif /* __ZX_VOU_H__ */
diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
new file mode 100644
index 000000000000..f44e7a4ae441
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_vou_regs.h
@@ -0,0 +1,157 @@
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__ */