diff options
author | Dave Airlie <airlied@redhat.com> | 2016-02-18 22:10:18 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-02-18 22:10:18 -0500 |
commit | d2eaa59000c7717e68a75cf2c106f056d2bc30b4 (patch) | |
tree | 9e33b1fbb1f83a93727bf4aba77fe39f6a9b16f3 | |
parent | 9864fd76f35294fdc222507ef07a3dde7b28458d (diff) | |
parent | a2b5f9b9f308f66140a14150b8b9162ce9ca043b (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.txt | 50 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/inno_hdmi.c | 938 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/inno_hdmi.h | 362 |
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 @@ | |||
1 | Rockchip specific extensions to the Innosilicon HDMI | ||
2 | ================================ | ||
3 | |||
4 | Required 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 | |||
19 | Example: | ||
20 | hdmi: 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 | |||
39 | config 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 | ||
9 | obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o | 9 | obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o |
10 | obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o | 10 | obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o |
11 | obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o | ||
11 | 12 | ||
12 | obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_vop_reg.o | 13 | obj-$(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 | |||
39 | struct 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 | |||
48 | struct 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 | |||
58 | struct 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 | |||
78 | enum { | ||
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 | |||
87 | static 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 | |||
157 | static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset) | ||
158 | { | ||
159 | return readl_relaxed(hdmi->regs + (offset) * 0x04); | ||
160 | } | ||
161 | |||
162 | static inline void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val) | ||
163 | { | ||
164 | writel_relaxed(val, hdmi->regs + (offset) * 0x04); | ||
165 | } | ||
166 | |||
167 | static 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 | |||
176 | static 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 | |||
190 | static 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 | |||
198 | static 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 | |||
231 | static 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 | |||
249 | static 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 | |||
278 | static 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 | |||
291 | static 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 | |||
309 | static 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 | |||
386 | static 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 | |||
438 | static 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 | |||
487 | static 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 | |||
499 | static 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 | |||
509 | static 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 | |||
516 | static 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 | |||
523 | static 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 | |||
530 | static struct drm_encoder_funcs inno_hdmi_encoder_funcs = { | ||
531 | .destroy = drm_encoder_cleanup, | ||
532 | }; | ||
533 | |||
534 | static enum drm_connector_status | ||
535 | inno_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 | |||
543 | static 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 | |||
564 | static enum drm_mode_status | ||
565 | inno_hdmi_connector_mode_valid(struct drm_connector *connector, | ||
566 | struct drm_display_mode *mode) | ||
567 | { | ||
568 | return MODE_OK; | ||
569 | } | ||
570 | |||
571 | static struct drm_encoder * | ||
572 | inno_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 | |||
579 | static int | ||
580 | inno_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 | |||
586 | static void inno_hdmi_connector_destroy(struct drm_connector *connector) | ||
587 | { | ||
588 | drm_connector_unregister(connector); | ||
589 | drm_connector_cleanup(connector); | ||
590 | } | ||
591 | |||
592 | static 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 | |||
602 | static 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 | |||
608 | static 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 | |||
640 | static 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 | |||
657 | static 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 | |||
675 | static 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 | |||
684 | static 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 | |||
700 | static 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 | |||
730 | static 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 | |||
767 | static u32 inno_hdmi_i2c_func(struct i2c_adapter *adapter) | ||
768 | { | ||
769 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
770 | } | ||
771 | |||
772 | static const struct i2c_algorithm inno_hdmi_algorithm = { | ||
773 | .master_xfer = inno_hdmi_i2c_xfer, | ||
774 | .functionality = inno_hdmi_i2c_func, | ||
775 | }; | ||
776 | |||
777 | static 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 | |||
813 | static 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 | |||
887 | static 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 | |||
899 | static const struct component_ops inno_hdmi_ops = { | ||
900 | .bind = inno_hdmi_bind, | ||
901 | .unbind = inno_hdmi_unbind, | ||
902 | }; | ||
903 | |||
904 | static int inno_hdmi_probe(struct platform_device *pdev) | ||
905 | { | ||
906 | return component_add(&pdev->dev, &inno_hdmi_ops); | ||
907 | } | ||
908 | |||
909 | static int inno_hdmi_remove(struct platform_device *pdev) | ||
910 | { | ||
911 | component_del(&pdev->dev, &inno_hdmi_ops); | ||
912 | |||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static const struct of_device_id inno_hdmi_dt_ids[] = { | ||
917 | { .compatible = "rockchip,rk3036-inno-hdmi", | ||
918 | }, | ||
919 | {}, | ||
920 | }; | ||
921 | MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); | ||
922 | |||
923 | static 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 | |||
932 | module_platform_driver(inno_hdmi_driver); | ||
933 | |||
934 | MODULE_AUTHOR("Zheng Yang <zhengyang@rock-chips.com>"); | ||
935 | MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); | ||
936 | MODULE_DESCRIPTION("Rockchip Specific INNO-HDMI Driver"); | ||
937 | MODULE_LICENSE("GPL v2"); | ||
938 | MODULE_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 | |||
21 | enum 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 | ||
59 | enum { | ||
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) | ||
72 | enum { | ||
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) | ||
84 | enum { | ||
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 | ||
137 | enum { | ||
138 | CTS_SOURCE_INTERNAL = 0, | ||
139 | CTS_SOURCE_EXTERNAL = 1, | ||
140 | }; | ||
141 | #define v_CTS_SOURCE(n) (n << 7) | ||
142 | |||
143 | enum { | ||
144 | DOWNSAMPLE_DISABLE = 0, | ||
145 | DOWNSAMPLE_1_2 = 1, | ||
146 | DOWNSAMPLE_1_4 = 2, | ||
147 | }; | ||
148 | #define v_DOWN_SAMPLE(n) (n << 5) | ||
149 | |||
150 | enum { | ||
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) | ||
157 | enum { | ||
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 | ||
166 | enum { | ||
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 | ||
177 | enum { | ||
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) | ||
184 | enum { | ||
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 | ||
238 | enum { | ||
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 | ||
246 | enum { | ||
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__ */ | ||