aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-02-18 22:10:18 -0500
committerDave Airlie <airlied@redhat.com>2016-02-18 22:10:18 -0500
commitd2eaa59000c7717e68a75cf2c106f056d2bc30b4 (patch)
tree9e33b1fbb1f83a93727bf4aba77fe39f6a9b16f3
parent9864fd76f35294fdc222507ef07a3dde7b28458d (diff)
parenta2b5f9b9f308f66140a14150b8b9162ce9ca043b (diff)
Merge branch 'drm-rockchip-next-2016-02-18' of https://github.com/markyzq/kernel-drm-rockchip into drm-next
add Innosilicon HDMI support. * 'drm-rockchip-next-2016-02-18' of https://github.com/markyzq/kernel-drm-rockchip: dt-bindings: add document for Innosilicon HDMI on Rockchip platform drm/rockchip: hdmi: add Innosilicon HDMI support
-rw-r--r--Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt50
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig8
-rw-r--r--drivers/gpu/drm/rockchip/Makefile1
-rw-r--r--drivers/gpu/drm/rockchip/inno_hdmi.c938
-rw-r--r--drivers/gpu/drm/rockchip/inno_hdmi.h362
5 files changed, 1359 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt
new file mode 100644
index 000000000000..8096a29f9776
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt
@@ -0,0 +1,50 @@
1Rockchip specific extensions to the Innosilicon HDMI
2================================
3
4Required properties:
5- compatible:
6 "rockchip,rk3036-inno-hdmi";
7- reg:
8 Physical base address and length of the controller's registers.
9- clocks, clock-names:
10 Phandle to hdmi controller clock, name should be "pclk"
11- interrupts:
12 HDMI interrupt number
13- ports:
14 Contain one port node with endpoint definitions as defined in
15 Documentation/devicetree/bindings/graph.txt.
16- pinctrl-0, pinctrl-name:
17 Switch the iomux of HPD/CEC pins to HDMI function.
18
19Example:
20hdmi: hdmi@20034000 {
21 compatible = "rockchip,rk3036-inno-hdmi";
22 reg = <0x20034000 0x4000>;
23 interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
24 clocks = <&cru PCLK_HDMI>;
25 clock-names = "pclk";
26 pinctrl-names = "default";
27 pinctrl-0 = <&hdmi_ctl>;
28 status = "disabled";
29
30 hdmi_in: port {
31 #address-cells = <1>;
32 #size-cells = <0>;
33 hdmi_in_lcdc: endpoint@0 {
34 reg = <0>;
35 remote-endpoint = <&lcdc_out_hdmi>;
36 };
37 };
38};
39
40&pinctrl {
41 hdmi {
42 hdmi_ctl: hdmi-ctl {
43 rockchip,pins = <1 8 RK_FUNC_1 &pcfg_pull_none>,
44 <1 9 RK_FUNC_1 &pcfg_pull_none>,
45 <1 10 RK_FUNC_1 &pcfg_pull_none>,
46 <1 11 RK_FUNC_1 &pcfg_pull_none>;
47 };
48 };
49
50};
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 85739859dffc..76b3362c5e59 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -35,3 +35,11 @@ config ROCKCHIP_DW_MIPI_DSI
35 for the Synopsys DesignWare HDMI driver. If you want to 35 for the Synopsys DesignWare HDMI driver. If you want to
36 enable MIPI DSI on RK3288 based SoC, you should selet this 36 enable MIPI DSI on RK3288 based SoC, you should selet this
37 option. 37 option.
38
39config ROCKCHIP_INNO_HDMI
40 tristate "Rockchip specific extensions for Innosilicon HDMI"
41 depends on DRM_ROCKCHIP
42 help
43 This selects support for Rockchip SoC specific extensions
44 for the Innosilicon HDMI driver. If you want to enable
45 HDMI on RK3036 based SoC, you should select this option.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index f6a809afceec..df8fbef17791 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -8,5 +8,6 @@ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
8 8
9obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o 9obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
10obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o 10obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
11obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
11 12
12obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_vop_reg.o 13obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_vop_reg.o
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
new file mode 100644
index 000000000000..10d62fff22f1
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -0,0 +1,938 @@
1/*
2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3 * Zheng Yang <zhengyang@rock-chips.com>
4 * Yakir Yang <ykk@rock-chips.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/irq.h>
17#include <linux/clk.h>
18#include <linux/delay.h>
19#include <linux/err.h>
20#include <linux/hdmi.h>
21#include <linux/mfd/syscon.h>
22#include <linux/module.h>
23#include <linux/mutex.h>
24#include <linux/of_device.h>
25
26#include <drm/drm_of.h>
27#include <drm/drmP.h>
28#include <drm/drm_atomic_helper.h>
29#include <drm/drm_crtc_helper.h>
30#include <drm/drm_edid.h>
31
32#include "rockchip_drm_drv.h"
33#include "rockchip_drm_vop.h"
34
35#include "inno_hdmi.h"
36
37#define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x)
38
39struct hdmi_data_info {
40 int vic;
41 bool sink_is_hdmi;
42 bool sink_has_audio;
43 unsigned int enc_in_format;
44 unsigned int enc_out_format;
45 unsigned int colorimetry;
46};
47
48struct inno_hdmi_i2c {
49 struct i2c_adapter adap;
50
51 u8 ddc_addr;
52 u8 segment_addr;
53
54 struct mutex lock;
55 struct completion cmp;
56};
57
58struct inno_hdmi {
59 struct device *dev;
60 struct drm_device *drm_dev;
61
62 int irq;
63 struct clk *pclk;
64 void __iomem *regs;
65
66 struct drm_connector connector;
67 struct drm_encoder encoder;
68
69 struct inno_hdmi_i2c *i2c;
70 struct i2c_adapter *ddc;
71
72 unsigned int tmds_rate;
73
74 struct hdmi_data_info hdmi_data;
75 struct drm_display_mode previous_mode;
76};
77
78enum {
79 CSC_ITU601_16_235_TO_RGB_0_255_8BIT,
80 CSC_ITU601_0_255_TO_RGB_0_255_8BIT,
81 CSC_ITU709_16_235_TO_RGB_0_255_8BIT,
82 CSC_RGB_0_255_TO_ITU601_16_235_8BIT,
83 CSC_RGB_0_255_TO_ITU709_16_235_8BIT,
84 CSC_RGB_0_255_TO_RGB_16_235_8BIT,
85};
86
87static const char coeff_csc[][24] = {
88 /*
89 * YUV2RGB:601 SD mode(Y[16:235], UV[16:240], RGB[0:255]):
90 * R = 1.164*Y + 1.596*V - 204
91 * G = 1.164*Y - 0.391*U - 0.813*V + 154
92 * B = 1.164*Y + 2.018*U - 258
93 */
94 {
95 0x04, 0xa7, 0x00, 0x00, 0x06, 0x62, 0x02, 0xcc,
96 0x04, 0xa7, 0x11, 0x90, 0x13, 0x40, 0x00, 0x9a,
97 0x04, 0xa7, 0x08, 0x12, 0x00, 0x00, 0x03, 0x02
98 },
99 /*
100 * YUV2RGB:601 SD mode(YUV[0:255],RGB[0:255]):
101 * R = Y + 1.402*V - 248
102 * G = Y - 0.344*U - 0.714*V + 135
103 * B = Y + 1.772*U - 227
104 */
105 {
106 0x04, 0x00, 0x00, 0x00, 0x05, 0x9b, 0x02, 0xf8,
107 0x04, 0x00, 0x11, 0x60, 0x12, 0xdb, 0x00, 0x87,
108 0x04, 0x00, 0x07, 0x16, 0x00, 0x00, 0x02, 0xe3
109 },
110 /*
111 * YUV2RGB:709 HD mode(Y[16:235],UV[16:240],RGB[0:255]):
112 * R = 1.164*Y + 1.793*V - 248
113 * G = 1.164*Y - 0.213*U - 0.534*V + 77
114 * B = 1.164*Y + 2.115*U - 289
115 */
116 {
117 0x04, 0xa7, 0x00, 0x00, 0x07, 0x2c, 0x02, 0xf8,
118 0x04, 0xa7, 0x10, 0xda, 0x12, 0x22, 0x00, 0x4d,
119 0x04, 0xa7, 0x08, 0x74, 0x00, 0x00, 0x03, 0x21
120 },
121
122 /*
123 * RGB2YUV:601 SD mode:
124 * Cb = -0.291G - 0.148R + 0.439B + 128
125 * Y = 0.504G + 0.257R + 0.098B + 16
126 * Cr = -0.368G + 0.439R - 0.071B + 128
127 */
128 {
129 0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
130 0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
131 0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
132 },
133 /*
134 * RGB2YUV:709 HD mode:
135 * Cb = - 0.338G - 0.101R + 0.439B + 128
136 * Y = 0.614G + 0.183R + 0.062B + 16
137 * Cr = - 0.399G + 0.439R - 0.040B + 128
138 */
139 {
140 0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
141 0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
142 0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
143 },
144 /*
145 * RGB[0:255]2RGB[16:235]:
146 * R' = R x (235-16)/255 + 16;
147 * G' = G x (235-16)/255 + 16;
148 * B' = B x (235-16)/255 + 16;
149 */
150 {
151 0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
152 0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
153 0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10
154 },
155};
156
157static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset)
158{
159 return readl_relaxed(hdmi->regs + (offset) * 0x04);
160}
161
162static inline void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val)
163{
164 writel_relaxed(val, hdmi->regs + (offset) * 0x04);
165}
166
167static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset,
168 u32 msk, u32 val)
169{
170 u8 temp = hdmi_readb(hdmi, offset) & ~msk;
171
172 temp |= val & msk;
173 hdmi_writeb(hdmi, offset, temp);
174}
175
176static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi)
177{
178 int ddc_bus_freq;
179
180 ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE;
181
182 hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
183 hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
184
185 /* Clear the EDID interrupt flag and mute the interrupt */
186 hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
187 hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
188}
189
190static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable)
191{
192 if (enable)
193 hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_ON);
194 else
195 hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF);
196}
197
198static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode)
199{
200 switch (mode) {
201 case NORMAL:
202 inno_hdmi_sys_power(hdmi, false);
203
204 hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f);
205 hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb);
206
207 hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
208 hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
209 hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
210 hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f);
211 hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00);
212 hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01);
213
214 inno_hdmi_sys_power(hdmi, true);
215 break;
216
217 case LOWER_PWR:
218 inno_hdmi_sys_power(hdmi, false);
219 hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00);
220 hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00);
221 hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00);
222 hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
223
224 break;
225
226 default:
227 dev_err(hdmi->dev, "Unknown power mode %d\n", mode);
228 }
229}
230
231static void inno_hdmi_reset(struct inno_hdmi *hdmi)
232{
233 u32 val;
234 u32 msk;
235
236 hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL);
237 udelay(100);
238
239 hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG);
240 udelay(100);
241
242 msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
243 val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
244 hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
245
246 inno_hdmi_set_pwr_mode(hdmi, NORMAL);
247}
248
249static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc,
250 union hdmi_infoframe *frame, u32 frame_index,
251 u32 mask, u32 disable, u32 enable)
252{
253 if (mask)
254 hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, disable);
255
256 hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index);
257
258 if (setup_rc >= 0) {
259 u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
260 ssize_t rc, i;
261
262 rc = hdmi_infoframe_pack(frame, packed_frame,
263 sizeof(packed_frame));
264 if (rc < 0)
265 return rc;
266
267 for (i = 0; i < rc; i++)
268 hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i,
269 packed_frame[i]);
270
271 if (mask)
272 hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, enable);
273 }
274
275 return setup_rc;
276}
277
278static int inno_hdmi_config_video_vsi(struct inno_hdmi *hdmi,
279 struct drm_display_mode *mode)
280{
281 union hdmi_infoframe frame;
282 int rc;
283
284 rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
285 mode);
286
287 return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_VSI,
288 m_PACKET_VSI_EN, v_PACKET_VSI_EN(0), v_PACKET_VSI_EN(1));
289}
290
291static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi,
292 struct drm_display_mode *mode)
293{
294 union hdmi_infoframe frame;
295 int rc;
296
297 rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
298
299 if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444)
300 frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
301 else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422)
302 frame.avi.colorspace = HDMI_COLORSPACE_YUV422;
303 else
304 frame.avi.colorspace = HDMI_COLORSPACE_RGB;
305
306 return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0);
307}
308
309static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
310{
311 struct hdmi_data_info *data = &hdmi->hdmi_data;
312 int c0_c2_change = 0;
313 int csc_enable = 0;
314 int csc_mode = 0;
315 int auto_csc = 0;
316 int value;
317 int i;
318
319 /* Input video mode is SDR RGB24bit, data enable signal from external */
320 hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL |
321 v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444));
322
323 /* Input color hardcode to RGB, and output color hardcode to RGB888 */
324 value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) |
325 v_VIDEO_OUTPUT_COLOR(0) |
326 v_VIDEO_INPUT_CSP(0);
327 hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value);
328
329 if (data->enc_in_format == data->enc_out_format) {
330 if ((data->enc_in_format == HDMI_COLORSPACE_RGB) ||
331 (data->enc_in_format >= HDMI_COLORSPACE_YUV444)) {
332 value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
333 hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
334
335 hdmi_modb(hdmi, HDMI_VIDEO_CONTRL,
336 m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP,
337 v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) |
338 v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
339 return 0;
340 }
341 }
342
343 if (data->colorimetry == HDMI_COLORIMETRY_ITU_601) {
344 if ((data->enc_in_format == HDMI_COLORSPACE_RGB) &&
345 (data->enc_out_format == HDMI_COLORSPACE_YUV444)) {
346 csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
347 auto_csc = AUTO_CSC_DISABLE;
348 c0_c2_change = C0_C2_CHANGE_DISABLE;
349 csc_enable = v_CSC_ENABLE;
350 } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) &&
351 (data->enc_out_format == HDMI_COLORSPACE_RGB)) {
352 csc_mode = CSC_ITU601_16_235_TO_RGB_0_255_8BIT;
353 auto_csc = AUTO_CSC_ENABLE;
354 c0_c2_change = C0_C2_CHANGE_DISABLE;
355 csc_enable = v_CSC_DISABLE;
356 }
357 } else {
358 if ((data->enc_in_format == HDMI_COLORSPACE_RGB) &&
359 (data->enc_out_format == HDMI_COLORSPACE_YUV444)) {
360 csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
361 auto_csc = AUTO_CSC_DISABLE;
362 c0_c2_change = C0_C2_CHANGE_DISABLE;
363 csc_enable = v_CSC_ENABLE;
364 } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) &&
365 (data->enc_out_format == HDMI_COLORSPACE_RGB)) {
366 csc_mode = CSC_ITU709_16_235_TO_RGB_0_255_8BIT;
367 auto_csc = AUTO_CSC_ENABLE;
368 c0_c2_change = C0_C2_CHANGE_DISABLE;
369 csc_enable = v_CSC_DISABLE;
370 }
371 }
372
373 for (i = 0; i < 24; i++)
374 hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i,
375 coeff_csc[csc_mode][i]);
376
377 value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1);
378 hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
379 hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC |
380 m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) |
381 v_VIDEO_C0_C2_SWAP(c0_c2_change));
382
383 return 0;
384}
385
386static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
387 struct drm_display_mode *mode)
388{
389 int value;
390
391 /* Set detail external video timing polarity and interlace mode */
392 value = v_EXTERANL_VIDEO(1);
393 value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
394 v_HSYNC_POLARITY(1) : v_HSYNC_POLARITY(0);
395 value |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
396 v_VSYNC_POLARITY(1) : v_VSYNC_POLARITY(0);
397 value |= mode->flags & DRM_MODE_FLAG_INTERLACE ?
398 v_INETLACE(1) : v_INETLACE(0);
399 hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value);
400
401 /* Set detail external video timing */
402 value = mode->htotal;
403 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_L, value & 0xFF);
404 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);
405
406 value = mode->htotal - mode->hdisplay;
407 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF);
408 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
409
410 value = mode->hsync_start - mode->hdisplay;
411 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF);
412 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
413
414 value = mode->hsync_end - mode->hsync_start;
415 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_L, value & 0xFF);
416 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF);
417
418 value = mode->vtotal;
419 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_L, value & 0xFF);
420 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);
421
422 value = mode->vtotal - mode->vdisplay;
423 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF);
424
425 value = mode->vsync_start - mode->vdisplay;
426 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF);
427
428 value = mode->vsync_end - mode->vsync_start;
429 hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDURATION, value & 0xFF);
430
431 hdmi_writeb(hdmi, HDMI_PHY_PRE_DIV_RATIO, 0x1e);
432 hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_LOW, 0x2c);
433 hdmi_writeb(hdmi, HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH, 0x01);
434
435 return 0;
436}
437
438static int inno_hdmi_setup(struct inno_hdmi *hdmi,
439 struct drm_display_mode *mode)
440{
441 hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
442
443 hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB;
444 hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB;
445
446 if ((hdmi->hdmi_data.vic == 6) || (hdmi->hdmi_data.vic == 7) ||
447 (hdmi->hdmi_data.vic == 21) || (hdmi->hdmi_data.vic == 22) ||
448 (hdmi->hdmi_data.vic == 2) || (hdmi->hdmi_data.vic == 3) ||
449 (hdmi->hdmi_data.vic == 17) || (hdmi->hdmi_data.vic == 18))
450 hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
451 else
452 hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
453
454 /* Mute video and audio output */
455 hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
456 v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
457
458 /* Set HDMI Mode */
459 hdmi_writeb(hdmi, HDMI_HDCP_CTRL,
460 v_HDMI_DVI(hdmi->hdmi_data.sink_is_hdmi));
461
462 inno_hdmi_config_video_timing(hdmi, mode);
463
464 inno_hdmi_config_video_csc(hdmi);
465
466 if (hdmi->hdmi_data.sink_is_hdmi) {
467 inno_hdmi_config_video_avi(hdmi, mode);
468 inno_hdmi_config_video_vsi(hdmi, mode);
469 }
470
471 /*
472 * When IP controller have configured to an accurate video
473 * timing, then the TMDS clock source would be switched to
474 * DCLK_LCDC, so we need to init the TMDS rate to mode pixel
475 * clock rate, and reconfigure the DDC clock.
476 */
477 hdmi->tmds_rate = mode->clock * 1000;
478 inno_hdmi_i2c_init(hdmi);
479
480 /* Unmute video and audio output */
481 hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
482 v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
483
484 return 0;
485}
486
487static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder,
488 struct drm_display_mode *mode,
489 struct drm_display_mode *adj_mode)
490{
491 struct inno_hdmi *hdmi = to_inno_hdmi(encoder);
492
493 inno_hdmi_setup(hdmi, adj_mode);
494
495 /* Store the display mode for plugin/DPMS poweron events */
496 memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode));
497}
498
499static void inno_hdmi_encoder_enable(struct drm_encoder *encoder)
500{
501 struct inno_hdmi *hdmi = to_inno_hdmi(encoder);
502
503 rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
504 ROCKCHIP_OUT_MODE_P888);
505
506 inno_hdmi_set_pwr_mode(hdmi, NORMAL);
507}
508
509static void inno_hdmi_encoder_disable(struct drm_encoder *encoder)
510{
511 struct inno_hdmi *hdmi = to_inno_hdmi(encoder);
512
513 inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR);
514}
515
516static bool inno_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
517 const struct drm_display_mode *mode,
518 struct drm_display_mode *adj_mode)
519{
520 return true;
521}
522
523static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = {
524 .enable = inno_hdmi_encoder_enable,
525 .disable = inno_hdmi_encoder_disable,
526 .mode_fixup = inno_hdmi_encoder_mode_fixup,
527 .mode_set = inno_hdmi_encoder_mode_set,
528};
529
530static struct drm_encoder_funcs inno_hdmi_encoder_funcs = {
531 .destroy = drm_encoder_cleanup,
532};
533
534static enum drm_connector_status
535inno_hdmi_connector_detect(struct drm_connector *connector, bool force)
536{
537 struct inno_hdmi *hdmi = to_inno_hdmi(connector);
538
539 return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ?
540 connector_status_connected : connector_status_disconnected;
541}
542
543static int inno_hdmi_connector_get_modes(struct drm_connector *connector)
544{
545 struct inno_hdmi *hdmi = to_inno_hdmi(connector);
546 struct edid *edid;
547 int ret = 0;
548
549 if (!hdmi->ddc)
550 return 0;
551
552 edid = drm_get_edid(connector, hdmi->ddc);
553 if (edid) {
554 hdmi->hdmi_data.sink_is_hdmi = drm_detect_hdmi_monitor(edid);
555 hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid);
556 drm_mode_connector_update_edid_property(connector, edid);
557 ret = drm_add_edid_modes(connector, edid);
558 kfree(edid);
559 }
560
561 return ret;
562}
563
564static enum drm_mode_status
565inno_hdmi_connector_mode_valid(struct drm_connector *connector,
566 struct drm_display_mode *mode)
567{
568 return MODE_OK;
569}
570
571static struct drm_encoder *
572inno_hdmi_connector_best_encoder(struct drm_connector *connector)
573{
574 struct inno_hdmi *hdmi = to_inno_hdmi(connector);
575
576 return &hdmi->encoder;
577}
578
579static int
580inno_hdmi_probe_single_connector_modes(struct drm_connector *connector,
581 uint32_t maxX, uint32_t maxY)
582{
583 return drm_helper_probe_single_connector_modes(connector, 1920, 1080);
584}
585
586static void inno_hdmi_connector_destroy(struct drm_connector *connector)
587{
588 drm_connector_unregister(connector);
589 drm_connector_cleanup(connector);
590}
591
592static struct drm_connector_funcs inno_hdmi_connector_funcs = {
593 .dpms = drm_atomic_helper_connector_dpms,
594 .fill_modes = inno_hdmi_probe_single_connector_modes,
595 .detect = inno_hdmi_connector_detect,
596 .destroy = inno_hdmi_connector_destroy,
597 .reset = drm_atomic_helper_connector_reset,
598 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
599 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
600};
601
602static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = {
603 .get_modes = inno_hdmi_connector_get_modes,
604 .mode_valid = inno_hdmi_connector_mode_valid,
605 .best_encoder = inno_hdmi_connector_best_encoder,
606};
607
608static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi)
609{
610 struct drm_encoder *encoder = &hdmi->encoder;
611 struct device *dev = hdmi->dev;
612
613 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
614
615 /*
616 * If we failed to find the CRTC(s) which this encoder is
617 * supposed to be connected to, it's because the CRTC has
618 * not been registered yet. Defer probing, and hope that
619 * the required CRTC is added later.
620 */
621 if (encoder->possible_crtcs == 0)
622 return -EPROBE_DEFER;
623
624 drm_encoder_helper_add(encoder, &inno_hdmi_encoder_helper_funcs);
625 drm_encoder_init(drm, encoder, &inno_hdmi_encoder_funcs,
626 DRM_MODE_ENCODER_TMDS, NULL);
627
628 hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
629
630 drm_connector_helper_add(&hdmi->connector,
631 &inno_hdmi_connector_helper_funcs);
632 drm_connector_init(drm, &hdmi->connector, &inno_hdmi_connector_funcs,
633 DRM_MODE_CONNECTOR_HDMIA);
634
635 drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
636
637 return 0;
638}
639
640static irqreturn_t inno_hdmi_i2c_irq(struct inno_hdmi *hdmi)
641{
642 struct inno_hdmi_i2c *i2c = hdmi->i2c;
643 u8 stat;
644
645 stat = hdmi_readb(hdmi, HDMI_INTERRUPT_STATUS1);
646 if (!(stat & m_INT_EDID_READY))
647 return IRQ_NONE;
648
649 /* Clear HDMI EDID interrupt flag */
650 hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
651
652 complete(&i2c->cmp);
653
654 return IRQ_HANDLED;
655}
656
657static irqreturn_t inno_hdmi_hardirq(int irq, void *dev_id)
658{
659 struct inno_hdmi *hdmi = dev_id;
660 irqreturn_t ret = IRQ_NONE;
661 u8 interrupt;
662
663 if (hdmi->i2c)
664 ret = inno_hdmi_i2c_irq(hdmi);
665
666 interrupt = hdmi_readb(hdmi, HDMI_STATUS);
667 if (interrupt & m_INT_HOTPLUG) {
668 hdmi_modb(hdmi, HDMI_STATUS, m_INT_HOTPLUG, m_INT_HOTPLUG);
669 ret = IRQ_WAKE_THREAD;
670 }
671
672 return ret;
673}
674
675static irqreturn_t inno_hdmi_irq(int irq, void *dev_id)
676{
677 struct inno_hdmi *hdmi = dev_id;
678
679 drm_helper_hpd_irq_event(hdmi->connector.dev);
680
681 return IRQ_HANDLED;
682}
683
684static int inno_hdmi_i2c_read(struct inno_hdmi *hdmi, struct i2c_msg *msgs)
685{
686 int length = msgs->len;
687 u8 *buf = msgs->buf;
688 int ret;
689
690 ret = wait_for_completion_timeout(&hdmi->i2c->cmp, HZ / 10);
691 if (!ret)
692 return -EAGAIN;
693
694 while (length--)
695 *buf++ = hdmi_readb(hdmi, HDMI_EDID_FIFO_ADDR);
696
697 return 0;
698}
699
700static int inno_hdmi_i2c_write(struct inno_hdmi *hdmi, struct i2c_msg *msgs)
701{
702 /*
703 * The DDC module only support read EDID message, so
704 * we assume that each word write to this i2c adapter
705 * should be the offset of EDID word address.
706 */
707 if ((msgs->len != 1) ||
708 ((msgs->addr != DDC_ADDR) && (msgs->addr != DDC_SEGMENT_ADDR)))
709 return -EINVAL;
710
711 reinit_completion(&hdmi->i2c->cmp);
712
713 if (msgs->addr == DDC_SEGMENT_ADDR)
714 hdmi->i2c->segment_addr = msgs->buf[0];
715 if (msgs->addr == DDC_ADDR)
716 hdmi->i2c->ddc_addr = msgs->buf[0];
717
718 /* Set edid fifo first addr */
719 hdmi_writeb(hdmi, HDMI_EDID_FIFO_OFFSET, 0x00);
720
721 /* Set edid word address 0x00/0x80 */
722 hdmi_writeb(hdmi, HDMI_EDID_WORD_ADDR, hdmi->i2c->ddc_addr);
723
724 /* Set edid segment pointer */
725 hdmi_writeb(hdmi, HDMI_EDID_SEGMENT_POINTER, hdmi->i2c->segment_addr);
726
727 return 0;
728}
729
730static int inno_hdmi_i2c_xfer(struct i2c_adapter *adap,
731 struct i2c_msg *msgs, int num)
732{
733 struct inno_hdmi *hdmi = i2c_get_adapdata(adap);
734 struct inno_hdmi_i2c *i2c = hdmi->i2c;
735 int i, ret = 0;
736
737 mutex_lock(&i2c->lock);
738
739 /* Clear the EDID interrupt flag and unmute the interrupt */
740 hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, m_INT_EDID_READY);
741 hdmi_writeb(hdmi, HDMI_INTERRUPT_STATUS1, m_INT_EDID_READY);
742
743 for (i = 0; i < num; i++) {
744 dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n",
745 i + 1, num, msgs[i].len, msgs[i].flags);
746
747 if (msgs[i].flags & I2C_M_RD)
748 ret = inno_hdmi_i2c_read(hdmi, &msgs[i]);
749 else
750 ret = inno_hdmi_i2c_write(hdmi, &msgs[i]);
751
752 if (ret < 0)
753 break;
754 }
755
756 if (!ret)
757 ret = num;
758
759 /* Mute HDMI EDID interrupt */
760 hdmi_writeb(hdmi, HDMI_INTERRUPT_MASK1, 0);
761
762 mutex_unlock(&i2c->lock);
763
764 return ret;
765}
766
767static u32 inno_hdmi_i2c_func(struct i2c_adapter *adapter)
768{
769 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
770}
771
772static const struct i2c_algorithm inno_hdmi_algorithm = {
773 .master_xfer = inno_hdmi_i2c_xfer,
774 .functionality = inno_hdmi_i2c_func,
775};
776
777static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi)
778{
779 struct i2c_adapter *adap;
780 struct inno_hdmi_i2c *i2c;
781 int ret;
782
783 i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL);
784 if (!i2c)
785 return ERR_PTR(-ENOMEM);
786
787 mutex_init(&i2c->lock);
788 init_completion(&i2c->cmp);
789
790 adap = &i2c->adap;
791 adap->class = I2C_CLASS_DDC;
792 adap->owner = THIS_MODULE;
793 adap->dev.parent = hdmi->dev;
794 adap->dev.of_node = hdmi->dev->of_node;
795 adap->algo = &inno_hdmi_algorithm;
796 strlcpy(adap->name, "Inno HDMI", sizeof(adap->name));
797 i2c_set_adapdata(adap, hdmi);
798
799 ret = i2c_add_adapter(adap);
800 if (ret) {
801 dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);
802 devm_kfree(hdmi->dev, i2c);
803 return ERR_PTR(ret);
804 }
805
806 hdmi->i2c = i2c;
807
808 dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name);
809
810 return adap;
811}
812
813static int inno_hdmi_bind(struct device *dev, struct device *master,
814 void *data)
815{
816 struct platform_device *pdev = to_platform_device(dev);
817 struct drm_device *drm = data;
818 struct inno_hdmi *hdmi;
819 struct resource *iores;
820 int irq;
821 int ret;
822
823 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
824 if (!hdmi)
825 return -ENOMEM;
826
827 hdmi->dev = dev;
828 hdmi->drm_dev = drm;
829
830 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
831 if (!iores)
832 return -ENXIO;
833
834 hdmi->regs = devm_ioremap_resource(dev, iores);
835 if (IS_ERR(hdmi->regs))
836 return PTR_ERR(hdmi->regs);
837
838 hdmi->pclk = devm_clk_get(hdmi->dev, "pclk");
839 if (IS_ERR(hdmi->pclk)) {
840 dev_err(hdmi->dev, "Unable to get HDMI pclk clk\n");
841 return PTR_ERR(hdmi->pclk);
842 }
843
844 ret = clk_prepare_enable(hdmi->pclk);
845 if (ret) {
846 dev_err(hdmi->dev, "Cannot enable HDMI pclk clock: %d\n", ret);
847 return ret;
848 }
849
850 irq = platform_get_irq(pdev, 0);
851 if (irq < 0)
852 return irq;
853
854 inno_hdmi_reset(hdmi);
855
856 hdmi->ddc = inno_hdmi_i2c_adapter(hdmi);
857 if (IS_ERR(hdmi->ddc)) {
858 hdmi->ddc = NULL;
859 return PTR_ERR(hdmi->ddc);
860 }
861
862 /*
863 * When IP controller haven't configured to an accurate video
864 * timing, then the TMDS clock source would be switched to
865 * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate,
866 * and reconfigure the DDC clock.
867 */
868 hdmi->tmds_rate = clk_get_rate(hdmi->pclk);
869 inno_hdmi_i2c_init(hdmi);
870
871 ret = inno_hdmi_register(drm, hdmi);
872 if (ret)
873 return ret;
874
875 dev_set_drvdata(dev, hdmi);
876
877 /* Unmute hotplug interrupt */
878 hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
879
880 ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq,
881 inno_hdmi_irq, IRQF_SHARED,
882 dev_name(dev), hdmi);
883
884 return ret;
885}
886
887static void inno_hdmi_unbind(struct device *dev, struct device *master,
888 void *data)
889{
890 struct inno_hdmi *hdmi = dev_get_drvdata(dev);
891
892 hdmi->connector.funcs->destroy(&hdmi->connector);
893 hdmi->encoder.funcs->destroy(&hdmi->encoder);
894
895 clk_disable_unprepare(hdmi->pclk);
896 i2c_put_adapter(hdmi->ddc);
897}
898
899static const struct component_ops inno_hdmi_ops = {
900 .bind = inno_hdmi_bind,
901 .unbind = inno_hdmi_unbind,
902};
903
904static int inno_hdmi_probe(struct platform_device *pdev)
905{
906 return component_add(&pdev->dev, &inno_hdmi_ops);
907}
908
909static int inno_hdmi_remove(struct platform_device *pdev)
910{
911 component_del(&pdev->dev, &inno_hdmi_ops);
912
913 return 0;
914}
915
916static const struct of_device_id inno_hdmi_dt_ids[] = {
917 { .compatible = "rockchip,rk3036-inno-hdmi",
918 },
919 {},
920};
921MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids);
922
923static struct platform_driver inno_hdmi_driver = {
924 .probe = inno_hdmi_probe,
925 .remove = inno_hdmi_remove,
926 .driver = {
927 .name = "innohdmi-rockchip",
928 .of_match_table = inno_hdmi_dt_ids,
929 },
930};
931
932module_platform_driver(inno_hdmi_driver);
933
934MODULE_AUTHOR("Zheng Yang <zhengyang@rock-chips.com>");
935MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
936MODULE_DESCRIPTION("Rockchip Specific INNO-HDMI Driver");
937MODULE_LICENSE("GPL v2");
938MODULE_ALIAS("platform:innohdmi-rockchip");
diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi.h
new file mode 100644
index 000000000000..aa7c415f8cc1
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.h
@@ -0,0 +1,362 @@
1/*
2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3 * Zheng Yang <zhengyang@rock-chips.com>
4 * Yakir Yang <ykk@rock-chips.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#ifndef __INNO_HDMI_H__
17#define __INNO_HDMI_H__
18
19#define DDC_SEGMENT_ADDR 0x30
20
21enum PWR_MODE {
22 NORMAL,
23 LOWER_PWR,
24};
25
26#define HDMI_SCL_RATE (100*1000)
27#define DDC_BUS_FREQ_L 0x4b
28#define DDC_BUS_FREQ_H 0x4c
29
30#define HDMI_SYS_CTRL 0x00
31#define m_RST_ANALOG (1 << 6)
32#define v_RST_ANALOG (0 << 6)
33#define v_NOT_RST_ANALOG (1 << 6)
34#define m_RST_DIGITAL (1 << 5)
35#define v_RST_DIGITAL (0 << 5)
36#define v_NOT_RST_DIGITAL (1 << 5)
37#define m_REG_CLK_INV (1 << 4)
38#define v_REG_CLK_NOT_INV (0 << 4)
39#define v_REG_CLK_INV (1 << 4)
40#define m_VCLK_INV (1 << 3)
41#define v_VCLK_NOT_INV (0 << 3)
42#define v_VCLK_INV (1 << 3)
43#define m_REG_CLK_SOURCE (1 << 2)
44#define v_REG_CLK_SOURCE_TMDS (0 << 2)
45#define v_REG_CLK_SOURCE_SYS (1 << 2)
46#define m_POWER (1 << 1)
47#define v_PWR_ON (0 << 1)
48#define v_PWR_OFF (1 << 1)
49#define m_INT_POL (1 << 0)
50#define v_INT_POL_HIGH 1
51#define v_INT_POL_LOW 0
52
53#define HDMI_VIDEO_CONTRL1 0x01
54#define m_VIDEO_INPUT_FORMAT (7 << 1)
55#define m_DE_SOURCE (1 << 0)
56#define v_VIDEO_INPUT_FORMAT(n) (n << 1)
57#define v_DE_EXTERNAL 1
58#define v_DE_INTERNAL 0
59enum {
60 VIDEO_INPUT_SDR_RGB444 = 0,
61 VIDEO_INPUT_DDR_RGB444 = 5,
62 VIDEO_INPUT_DDR_YCBCR422 = 6
63};
64
65#define HDMI_VIDEO_CONTRL2 0x02
66#define m_VIDEO_OUTPUT_COLOR (3 << 6)
67#define m_VIDEO_INPUT_BITS (3 << 4)
68#define m_VIDEO_INPUT_CSP (1 << 0)
69#define v_VIDEO_OUTPUT_COLOR(n) (((n) & 0x3) << 6)
70#define v_VIDEO_INPUT_BITS(n) (n << 4)
71#define v_VIDEO_INPUT_CSP(n) (n << 0)
72enum {
73 VIDEO_INPUT_12BITS = 0,
74 VIDEO_INPUT_10BITS = 1,
75 VIDEO_INPUT_REVERT = 2,
76 VIDEO_INPUT_8BITS = 3,
77};
78
79#define HDMI_VIDEO_CONTRL 0x03
80#define m_VIDEO_AUTO_CSC (1 << 7)
81#define v_VIDEO_AUTO_CSC(n) (n << 7)
82#define m_VIDEO_C0_C2_SWAP (1 << 0)
83#define v_VIDEO_C0_C2_SWAP(n) (n << 0)
84enum {
85 C0_C2_CHANGE_ENABLE = 0,
86 C0_C2_CHANGE_DISABLE = 1,
87 AUTO_CSC_DISABLE = 0,
88 AUTO_CSC_ENABLE = 1,
89};
90
91#define HDMI_VIDEO_CONTRL3 0x04
92#define m_COLOR_DEPTH_NOT_INDICATED (1 << 4)
93#define m_SOF (1 << 3)
94#define m_COLOR_RANGE (1 << 2)
95#define m_CSC (1 << 0)
96#define v_COLOR_DEPTH_NOT_INDICATED(n) ((n) << 4)
97#define v_SOF_ENABLE (0 << 3)
98#define v_SOF_DISABLE (1 << 3)
99#define v_COLOR_RANGE_FULL (1 << 2)
100#define v_COLOR_RANGE_LIMITED (0 << 2)
101#define v_CSC_ENABLE 1
102#define v_CSC_DISABLE 0
103
104#define HDMI_AV_MUTE 0x05
105#define m_AVMUTE_CLEAR (1 << 7)
106#define m_AVMUTE_ENABLE (1 << 6)
107#define m_AUDIO_MUTE (1 << 1)
108#define m_VIDEO_BLACK (1 << 0)
109#define v_AVMUTE_CLEAR(n) (n << 7)
110#define v_AVMUTE_ENABLE(n) (n << 6)
111#define v_AUDIO_MUTE(n) (n << 1)
112#define v_VIDEO_MUTE(n) (n << 0)
113
114#define HDMI_VIDEO_TIMING_CTL 0x08
115#define v_HSYNC_POLARITY(n) (n << 3)
116#define v_VSYNC_POLARITY(n) (n << 2)
117#define v_INETLACE(n) (n << 1)
118#define v_EXTERANL_VIDEO(n) (n << 0)
119
120#define HDMI_VIDEO_EXT_HTOTAL_L 0x09
121#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a
122#define HDMI_VIDEO_EXT_HBLANK_L 0x0b
123#define HDMI_VIDEO_EXT_HBLANK_H 0x0c
124#define HDMI_VIDEO_EXT_HDELAY_L 0x0d
125#define HDMI_VIDEO_EXT_HDELAY_H 0x0e
126#define HDMI_VIDEO_EXT_HDURATION_L 0x0f
127#define HDMI_VIDEO_EXT_HDURATION_H 0x10
128#define HDMI_VIDEO_EXT_VTOTAL_L 0x11
129#define HDMI_VIDEO_EXT_VTOTAL_H 0x12
130#define HDMI_VIDEO_EXT_VBLANK 0x13
131#define HDMI_VIDEO_EXT_VDELAY 0x14
132#define HDMI_VIDEO_EXT_VDURATION 0x15
133
134#define HDMI_VIDEO_CSC_COEF 0x18
135
136#define HDMI_AUDIO_CTRL1 0x35
137enum {
138 CTS_SOURCE_INTERNAL = 0,
139 CTS_SOURCE_EXTERNAL = 1,
140};
141#define v_CTS_SOURCE(n) (n << 7)
142
143enum {
144 DOWNSAMPLE_DISABLE = 0,
145 DOWNSAMPLE_1_2 = 1,
146 DOWNSAMPLE_1_4 = 2,
147};
148#define v_DOWN_SAMPLE(n) (n << 5)
149
150enum {
151 AUDIO_SOURCE_IIS = 0,
152 AUDIO_SOURCE_SPDIF = 1,
153};
154#define v_AUDIO_SOURCE(n) (n << 3)
155
156#define v_MCLK_ENABLE(n) (n << 2)
157enum {
158 MCLK_128FS = 0,
159 MCLK_256FS = 1,
160 MCLK_384FS = 2,
161 MCLK_512FS = 3,
162};
163#define v_MCLK_RATIO(n) (n)
164
165#define AUDIO_SAMPLE_RATE 0x37
166enum {
167 AUDIO_32K = 0x3,
168 AUDIO_441K = 0x0,
169 AUDIO_48K = 0x2,
170 AUDIO_882K = 0x8,
171 AUDIO_96K = 0xa,
172 AUDIO_1764K = 0xc,
173 AUDIO_192K = 0xe,
174};
175
176#define AUDIO_I2S_MODE 0x38
177enum {
178 I2S_CHANNEL_1_2 = 1,
179 I2S_CHANNEL_3_4 = 3,
180 I2S_CHANNEL_5_6 = 7,
181 I2S_CHANNEL_7_8 = 0xf
182};
183#define v_I2S_CHANNEL(n) ((n) << 2)
184enum {
185 I2S_STANDARD = 0,
186 I2S_LEFT_JUSTIFIED = 1,
187 I2S_RIGHT_JUSTIFIED = 2,
188};
189#define v_I2S_MODE(n) (n)
190
191#define AUDIO_I2S_MAP 0x39
192#define AUDIO_I2S_SWAPS_SPDIF 0x3a
193#define v_SPIDF_FREQ(n) (n)
194
195#define N_32K 0x1000
196#define N_441K 0x1880
197#define N_882K 0x3100
198#define N_1764K 0x6200
199#define N_48K 0x1800
200#define N_96K 0x3000
201#define N_192K 0x6000
202
203#define HDMI_AUDIO_CHANNEL_STATUS 0x3e
204#define m_AUDIO_STATUS_NLPCM (1 << 7)
205#define m_AUDIO_STATUS_USE (1 << 6)
206#define m_AUDIO_STATUS_COPYRIGHT (1 << 5)
207#define m_AUDIO_STATUS_ADDITION (3 << 2)
208#define m_AUDIO_STATUS_CLK_ACCURACY (2 << 0)
209#define v_AUDIO_STATUS_NLPCM(n) ((n & 1) << 7)
210#define AUDIO_N_H 0x3f
211#define AUDIO_N_M 0x40
212#define AUDIO_N_L 0x41
213
214#define HDMI_AUDIO_CTS_H 0x45
215#define HDMI_AUDIO_CTS_M 0x46
216#define HDMI_AUDIO_CTS_L 0x47
217
218#define HDMI_DDC_CLK_L 0x4b
219#define HDMI_DDC_CLK_H 0x4c
220
221#define HDMI_EDID_SEGMENT_POINTER 0x4d
222#define HDMI_EDID_WORD_ADDR 0x4e
223#define HDMI_EDID_FIFO_OFFSET 0x4f
224#define HDMI_EDID_FIFO_ADDR 0x50
225
226#define HDMI_PACKET_SEND_MANUAL 0x9c
227#define HDMI_PACKET_SEND_AUTO 0x9d
228#define m_PACKET_GCP_EN (1 << 7)
229#define m_PACKET_MSI_EN (1 << 6)
230#define m_PACKET_SDI_EN (1 << 5)
231#define m_PACKET_VSI_EN (1 << 4)
232#define v_PACKET_GCP_EN(n) ((n & 1) << 7)
233#define v_PACKET_MSI_EN(n) ((n & 1) << 6)
234#define v_PACKET_SDI_EN(n) ((n & 1) << 5)
235#define v_PACKET_VSI_EN(n) ((n & 1) << 4)
236
237#define HDMI_CONTROL_PACKET_BUF_INDEX 0x9f
238enum {
239 INFOFRAME_VSI = 0x05,
240 INFOFRAME_AVI = 0x06,
241 INFOFRAME_AAI = 0x08,
242};
243
244#define HDMI_CONTROL_PACKET_ADDR 0xa0
245#define HDMI_MAXIMUM_INFO_FRAME_SIZE 0x11
246enum {
247 AVI_COLOR_MODE_RGB = 0,
248 AVI_COLOR_MODE_YCBCR422 = 1,
249 AVI_COLOR_MODE_YCBCR444 = 2,
250 AVI_COLORIMETRY_NO_DATA = 0,
251
252 AVI_COLORIMETRY_SMPTE_170M = 1,
253 AVI_COLORIMETRY_ITU709 = 2,
254 AVI_COLORIMETRY_EXTENDED = 3,
255
256 AVI_CODED_FRAME_ASPECT_NO_DATA = 0,
257 AVI_CODED_FRAME_ASPECT_4_3 = 1,
258 AVI_CODED_FRAME_ASPECT_16_9 = 2,
259
260 ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08,
261 ACTIVE_ASPECT_RATE_4_3 = 0x09,
262 ACTIVE_ASPECT_RATE_16_9 = 0x0A,
263 ACTIVE_ASPECT_RATE_14_9 = 0x0B,
264};
265
266#define HDMI_HDCP_CTRL 0x52
267#define m_HDMI_DVI (1 << 1)
268#define v_HDMI_DVI(n) (n << 1)
269
270#define HDMI_INTERRUPT_MASK1 0xc0
271#define HDMI_INTERRUPT_STATUS1 0xc1
272#define m_INT_ACTIVE_VSYNC (1 << 5)
273#define m_INT_EDID_READY (1 << 2)
274
275#define HDMI_INTERRUPT_MASK2 0xc2
276#define HDMI_INTERRUPT_STATUS2 0xc3
277#define m_INT_HDCP_ERR (1 << 7)
278#define m_INT_BKSV_FLAG (1 << 6)
279#define m_INT_HDCP_OK (1 << 4)
280
281#define HDMI_STATUS 0xc8
282#define m_HOTPLUG (1 << 7)
283#define m_MASK_INT_HOTPLUG (1 << 5)
284#define m_INT_HOTPLUG (1 << 1)
285#define v_MASK_INT_HOTPLUG(n) ((n & 0x1) << 5)
286
287#define HDMI_COLORBAR 0xc9
288
289#define HDMI_PHY_SYNC 0xce
290#define HDMI_PHY_SYS_CTL 0xe0
291#define m_TMDS_CLK_SOURCE (1 << 5)
292#define v_TMDS_FROM_PLL (0 << 5)
293#define v_TMDS_FROM_GEN (1 << 5)
294#define m_PHASE_CLK (1 << 4)
295#define v_DEFAULT_PHASE (0 << 4)
296#define v_SYNC_PHASE (1 << 4)
297#define m_TMDS_CURRENT_PWR (1 << 3)
298#define v_TURN_ON_CURRENT (0 << 3)
299#define v_CAT_OFF_CURRENT (1 << 3)
300#define m_BANDGAP_PWR (1 << 2)
301#define v_BANDGAP_PWR_UP (0 << 2)
302#define v_BANDGAP_PWR_DOWN (1 << 2)
303#define m_PLL_PWR (1 << 1)
304#define v_PLL_PWR_UP (0 << 1)
305#define v_PLL_PWR_DOWN (1 << 1)
306#define m_TMDS_CHG_PWR (1 << 0)
307#define v_TMDS_CHG_PWR_UP (0 << 0)
308#define v_TMDS_CHG_PWR_DOWN (1 << 0)
309
310#define HDMI_PHY_CHG_PWR 0xe1
311#define v_CLK_CHG_PWR(n) ((n & 1) << 3)
312#define v_DATA_CHG_PWR(n) ((n & 7) << 0)
313
314#define HDMI_PHY_DRIVER 0xe2
315#define v_CLK_MAIN_DRIVER(n) (n << 4)
316#define v_DATA_MAIN_DRIVER(n) (n << 0)
317
318#define HDMI_PHY_PRE_EMPHASIS 0xe3
319#define v_PRE_EMPHASIS(n) ((n & 7) << 4)
320#define v_CLK_PRE_DRIVER(n) ((n & 3) << 2)
321#define v_DATA_PRE_DRIVER(n) ((n & 3) << 0)
322
323#define HDMI_PHY_FEEDBACK_DIV_RATIO_LOW 0xe7
324#define v_FEEDBACK_DIV_LOW(n) (n & 0xff)
325#define HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH 0xe8
326#define v_FEEDBACK_DIV_HIGH(n) (n & 1)
327
328#define HDMI_PHY_PRE_DIV_RATIO 0xed
329#define v_PRE_DIV_RATIO(n) (n & 0x1f)
330
331#define HDMI_CEC_CTRL 0xd0
332#define m_ADJUST_FOR_HISENSE (1 << 6)
333#define m_REJECT_RX_BROADCAST (1 << 5)
334#define m_BUSFREETIME_ENABLE (1 << 2)
335#define m_REJECT_RX (1 << 1)
336#define m_START_TX (1 << 0)
337
338#define HDMI_CEC_DATA 0xd1
339#define HDMI_CEC_TX_OFFSET 0xd2
340#define HDMI_CEC_RX_OFFSET 0xd3
341#define HDMI_CEC_CLK_H 0xd4
342#define HDMI_CEC_CLK_L 0xd5
343#define HDMI_CEC_TX_LENGTH 0xd6
344#define HDMI_CEC_RX_LENGTH 0xd7
345#define HDMI_CEC_TX_INT_MASK 0xd8
346#define m_TX_DONE (1 << 3)
347#define m_TX_NOACK (1 << 2)
348#define m_TX_BROADCAST_REJ (1 << 1)
349#define m_TX_BUSNOTFREE (1 << 0)
350
351#define HDMI_CEC_RX_INT_MASK 0xd9
352#define m_RX_LA_ERR (1 << 4)
353#define m_RX_GLITCH (1 << 3)
354#define m_RX_DONE (1 << 0)
355
356#define HDMI_CEC_TX_INT 0xda
357#define HDMI_CEC_RX_INT 0xdb
358#define HDMI_CEC_BUSFREETIME_L 0xdc
359#define HDMI_CEC_BUSFREETIME_H 0xdd
360#define HDMI_CEC_LOGICADDR 0xde
361
362#endif /* __INNO_HDMI_H__ */