blob: 9f2f0feb7b7593db13663e2d1ed39e3ca9ceddc5 [file] [log] [blame]
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001/*
2 * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
10 * for SLISHDMI13T and SLIPHDMIT IP cores
11 *
12 * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
13 */
14
15#include <linux/irq.h>
16#include <linux/delay.h>
17#include <linux/err.h>
18#include <linux/clk.h>
Sachin Kamat5a819ed2014-01-28 10:33:16 +053019#include <linux/hdmi.h>
Fabio Estevam9aaf8802013-11-29 08:46:32 -020020#include <linux/of_device.h>
21
Andy Yan3d1b35a2014-12-05 14:25:05 +080022#include <drm/drm_of.h>
Fabio Estevam9aaf8802013-11-29 08:46:32 -020023#include <drm/drmP.h>
24#include <drm/drm_crtc_helper.h>
25#include <drm/drm_edid.h>
26#include <drm/drm_encoder_slave.h>
27
Fabio Estevam9aaf8802013-11-29 08:46:32 -020028#include "imx-hdmi.h"
Fabio Estevam9aaf8802013-11-29 08:46:32 -020029
30#define HDMI_EDID_LEN 512
31
32#define RGB 0
33#define YCBCR444 1
34#define YCBCR422_16BITS 2
35#define YCBCR422_8BITS 3
36#define XVYCC444 4
37
38enum hdmi_datamap {
39 RGB444_8B = 0x01,
40 RGB444_10B = 0x03,
41 RGB444_12B = 0x05,
42 RGB444_16B = 0x07,
43 YCbCr444_8B = 0x09,
44 YCbCr444_10B = 0x0B,
45 YCbCr444_12B = 0x0D,
46 YCbCr444_16B = 0x0F,
47 YCbCr422_8B = 0x16,
48 YCbCr422_10B = 0x14,
49 YCbCr422_12B = 0x12,
50};
51
Fabio Estevam9aaf8802013-11-29 08:46:32 -020052static const u16 csc_coeff_default[3][4] = {
53 { 0x2000, 0x0000, 0x0000, 0x0000 },
54 { 0x0000, 0x2000, 0x0000, 0x0000 },
55 { 0x0000, 0x0000, 0x2000, 0x0000 }
56};
57
58static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
59 { 0x2000, 0x6926, 0x74fd, 0x010e },
60 { 0x2000, 0x2cdd, 0x0000, 0x7e9a },
61 { 0x2000, 0x0000, 0x38b4, 0x7e3b }
62};
63
64static const u16 csc_coeff_rgb_out_eitu709[3][4] = {
65 { 0x2000, 0x7106, 0x7a02, 0x00a7 },
66 { 0x2000, 0x3264, 0x0000, 0x7e6d },
67 { 0x2000, 0x0000, 0x3b61, 0x7e25 }
68};
69
70static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
71 { 0x2591, 0x1322, 0x074b, 0x0000 },
72 { 0x6535, 0x2000, 0x7acc, 0x0200 },
73 { 0x6acd, 0x7534, 0x2000, 0x0200 }
74};
75
76static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
77 { 0x2dc5, 0x0d9b, 0x049e, 0x0000 },
78 { 0x62f0, 0x2000, 0x7d11, 0x0200 },
79 { 0x6756, 0x78ab, 0x2000, 0x0200 }
80};
81
82struct hdmi_vmode {
83 bool mdvi;
84 bool mhsyncpolarity;
85 bool mvsyncpolarity;
86 bool minterlaced;
87 bool mdataenablepolarity;
88
89 unsigned int mpixelclock;
90 unsigned int mpixelrepetitioninput;
91 unsigned int mpixelrepetitionoutput;
92};
93
94struct hdmi_data_info {
95 unsigned int enc_in_format;
96 unsigned int enc_out_format;
97 unsigned int enc_color_depth;
98 unsigned int colorimetry;
99 unsigned int pix_repet_factor;
100 unsigned int hdcp_enable;
101 struct hdmi_vmode video_mode;
102};
103
104struct imx_hdmi {
105 struct drm_connector connector;
Andy Yan3d1b35a2014-12-05 14:25:05 +0800106 struct drm_encoder *encoder;
107 struct drm_bridge *bridge;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200108
109 enum imx_hdmi_devtype dev_type;
110 struct device *dev;
111 struct clk *isfr_clk;
112 struct clk *iahb_clk;
113
114 struct hdmi_data_info hdmi_data;
Andy Yan3d1b35a2014-12-05 14:25:05 +0800115 const struct imx_hdmi_plat_data *plat_data;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200116 int vic;
117
118 u8 edid[HDMI_EDID_LEN];
119 bool cable_plugin;
120
121 bool phy_enabled;
122 struct drm_display_mode previous_mode;
123
124 struct regmap *regmap;
125 struct i2c_adapter *ddc;
126 void __iomem *regs;
127
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200128 unsigned int sample_rate;
129 int ratio;
130};
131
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200132static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
133{
134 writeb(val, hdmi->regs + offset);
135}
136
137static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
138{
139 return readb(hdmi->regs + offset);
140}
141
Russell King812bc612013-11-04 12:42:02 +0000142static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
143{
144 u8 val = hdmi_readb(hdmi, reg) & ~mask;
Fabio Estevamb44ab1b2014-04-28 08:01:07 -0300145
Russell King812bc612013-11-04 12:42:02 +0000146 val |= data & mask;
147 hdmi_writeb(hdmi, val, reg);
148}
149
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200150static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
Andy Yanb5878332014-12-05 14:23:52 +0800151 u8 shift, u8 mask)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200152{
Russell King812bc612013-11-04 12:42:02 +0000153 hdmi_modb(hdmi, data << shift, mask, reg);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200154}
155
156static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
157 unsigned int value)
158{
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200159 hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
160 hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
161 hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
162
163 /* nshift factor = 0 */
Russell King812bc612013-11-04 12:42:02 +0000164 hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200165}
166
167static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
168{
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200169 /* Must be set/cleared first */
Russell King812bc612013-11-04 12:42:02 +0000170 hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200171
172 hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
173 hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
174 hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
175 HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
176}
177
178static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
179 unsigned int ratio)
180{
181 unsigned int n = (128 * freq) / 1000;
182
183 switch (freq) {
184 case 32000:
185 if (pixel_clk == 25170000)
186 n = (ratio == 150) ? 9152 : 4576;
187 else if (pixel_clk == 27020000)
188 n = (ratio == 150) ? 8192 : 4096;
189 else if (pixel_clk == 74170000 || pixel_clk == 148350000)
190 n = 11648;
191 else
192 n = 4096;
193 break;
194
195 case 44100:
196 if (pixel_clk == 25170000)
197 n = 7007;
198 else if (pixel_clk == 74170000)
199 n = 17836;
200 else if (pixel_clk == 148350000)
201 n = (ratio == 150) ? 17836 : 8918;
202 else
203 n = 6272;
204 break;
205
206 case 48000:
207 if (pixel_clk == 25170000)
208 n = (ratio == 150) ? 9152 : 6864;
209 else if (pixel_clk == 27020000)
210 n = (ratio == 150) ? 8192 : 6144;
211 else if (pixel_clk == 74170000)
212 n = 11648;
213 else if (pixel_clk == 148350000)
214 n = (ratio == 150) ? 11648 : 5824;
215 else
216 n = 6144;
217 break;
218
219 case 88200:
220 n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
221 break;
222
223 case 96000:
224 n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
225 break;
226
227 case 176400:
228 n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
229 break;
230
231 case 192000:
232 n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
233 break;
234
235 default:
236 break;
237 }
238
239 return n;
240}
241
242static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
243 unsigned int ratio)
244{
245 unsigned int cts = 0;
246
247 pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq,
248 pixel_clk, ratio);
249
250 switch (freq) {
251 case 32000:
252 if (pixel_clk == 297000000) {
253 cts = 222750;
254 break;
255 }
256 case 48000:
257 case 96000:
258 case 192000:
259 switch (pixel_clk) {
260 case 25200000:
261 case 27000000:
262 case 54000000:
263 case 74250000:
264 case 148500000:
265 cts = pixel_clk / 1000;
266 break;
267 case 297000000:
268 cts = 247500;
269 break;
270 /*
271 * All other TMDS clocks are not supported by
272 * DWC_hdmi_tx. The TMDS clocks divided or
273 * multiplied by 1,001 coefficients are not
274 * supported.
275 */
276 default:
277 break;
278 }
279 break;
280 case 44100:
281 case 88200:
282 case 176400:
283 switch (pixel_clk) {
284 case 25200000:
285 cts = 28000;
286 break;
287 case 27000000:
288 cts = 30000;
289 break;
290 case 54000000:
291 cts = 60000;
292 break;
293 case 74250000:
294 cts = 82500;
295 break;
296 case 148500000:
297 cts = 165000;
298 break;
299 case 297000000:
300 cts = 247500;
301 break;
302 default:
303 break;
304 }
305 break;
306 default:
307 break;
308 }
309 if (ratio == 100)
310 return cts;
Catalina Mocanu7557b6e2014-09-24 14:27:36 -0700311 return (cts * ratio) / 100;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200312}
313
Russell King40678382013-11-07 15:35:06 +0000314static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
Andy Yanb5878332014-12-05 14:23:52 +0800315 unsigned long pixel_clk)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200316{
317 unsigned int clk_n, clk_cts;
318
Russell King40678382013-11-07 15:35:06 +0000319 clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200320 hdmi->ratio);
Russell King40678382013-11-07 15:35:06 +0000321 clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200322 hdmi->ratio);
323
324 if (!clk_cts) {
325 dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
Andy Yanb5878332014-12-05 14:23:52 +0800326 __func__, pixel_clk);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200327 return;
328 }
329
330 dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n",
331 __func__, hdmi->sample_rate, hdmi->ratio,
Russell King40678382013-11-07 15:35:06 +0000332 pixel_clk, clk_n, clk_cts);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200333
334 hdmi_set_clock_regenerator_n(hdmi, clk_n);
335 hdmi_regenerate_cts(hdmi, clk_cts);
336}
337
338static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
339{
Russell King40678382013-11-07 15:35:06 +0000340 hdmi_set_clk_regenerator(hdmi, 74250000);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200341}
342
343static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
344{
Russell King40678382013-11-07 15:35:06 +0000345 hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200346}
347
348/*
349 * this submodule is responsible for the video data synchronization.
350 * for example, for RGB 4:4:4 input, the data map is defined as
351 * pin{47~40} <==> R[7:0]
352 * pin{31~24} <==> G[7:0]
353 * pin{15~8} <==> B[7:0]
354 */
355static void hdmi_video_sample(struct imx_hdmi *hdmi)
356{
357 int color_format = 0;
358 u8 val;
359
360 if (hdmi->hdmi_data.enc_in_format == RGB) {
361 if (hdmi->hdmi_data.enc_color_depth == 8)
362 color_format = 0x01;
363 else if (hdmi->hdmi_data.enc_color_depth == 10)
364 color_format = 0x03;
365 else if (hdmi->hdmi_data.enc_color_depth == 12)
366 color_format = 0x05;
367 else if (hdmi->hdmi_data.enc_color_depth == 16)
368 color_format = 0x07;
369 else
370 return;
371 } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
372 if (hdmi->hdmi_data.enc_color_depth == 8)
373 color_format = 0x09;
374 else if (hdmi->hdmi_data.enc_color_depth == 10)
375 color_format = 0x0B;
376 else if (hdmi->hdmi_data.enc_color_depth == 12)
377 color_format = 0x0D;
378 else if (hdmi->hdmi_data.enc_color_depth == 16)
379 color_format = 0x0F;
380 else
381 return;
382 } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
383 if (hdmi->hdmi_data.enc_color_depth == 8)
384 color_format = 0x16;
385 else if (hdmi->hdmi_data.enc_color_depth == 10)
386 color_format = 0x14;
387 else if (hdmi->hdmi_data.enc_color_depth == 12)
388 color_format = 0x12;
389 else
390 return;
391 }
392
393 val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
394 ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
395 HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
396 hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
397
398 /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
399 val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
400 HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
401 HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
402 hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
403 hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
404 hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
405 hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
406 hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
407 hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
408 hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
409}
410
411static int is_color_space_conversion(struct imx_hdmi *hdmi)
412{
Fabio Estevamba92b222014-02-06 10:12:03 -0200413 return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200414}
415
416static int is_color_space_decimation(struct imx_hdmi *hdmi)
417{
Fabio Estevamba92b222014-02-06 10:12:03 -0200418 if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
419 return 0;
420 if (hdmi->hdmi_data.enc_in_format == RGB ||
421 hdmi->hdmi_data.enc_in_format == YCBCR444)
422 return 1;
423 return 0;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200424}
425
426static int is_color_space_interpolation(struct imx_hdmi *hdmi)
427{
Fabio Estevamba92b222014-02-06 10:12:03 -0200428 if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
429 return 0;
430 if (hdmi->hdmi_data.enc_out_format == RGB ||
431 hdmi->hdmi_data.enc_out_format == YCBCR444)
432 return 1;
433 return 0;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200434}
435
436static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
437{
438 const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
Russell Kingc082f9d2013-11-04 12:10:40 +0000439 unsigned i;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200440 u32 csc_scale = 1;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200441
442 if (is_color_space_conversion(hdmi)) {
443 if (hdmi->hdmi_data.enc_out_format == RGB) {
Gulsah Kose256a38b2014-03-09 20:11:07 +0200444 if (hdmi->hdmi_data.colorimetry ==
445 HDMI_COLORIMETRY_ITU_601)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200446 csc_coeff = &csc_coeff_rgb_out_eitu601;
447 else
448 csc_coeff = &csc_coeff_rgb_out_eitu709;
449 } else if (hdmi->hdmi_data.enc_in_format == RGB) {
Gulsah Kose256a38b2014-03-09 20:11:07 +0200450 if (hdmi->hdmi_data.colorimetry ==
451 HDMI_COLORIMETRY_ITU_601)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200452 csc_coeff = &csc_coeff_rgb_in_eitu601;
453 else
454 csc_coeff = &csc_coeff_rgb_in_eitu709;
455 csc_scale = 0;
456 }
457 }
458
Russell Kingc082f9d2013-11-04 12:10:40 +0000459 /* The CSC registers are sequential, alternating MSB then LSB */
460 for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
461 u16 coeff_a = (*csc_coeff)[0][i];
462 u16 coeff_b = (*csc_coeff)[1][i];
463 u16 coeff_c = (*csc_coeff)[2][i];
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200464
Andy Yanb5878332014-12-05 14:23:52 +0800465 hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
Russell Kingc082f9d2013-11-04 12:10:40 +0000466 hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
467 hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
468 hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
Andy Yanb5878332014-12-05 14:23:52 +0800469 hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
Russell Kingc082f9d2013-11-04 12:10:40 +0000470 hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
471 }
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200472
Russell King812bc612013-11-04 12:42:02 +0000473 hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
474 HDMI_CSC_SCALE);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200475}
476
477static void hdmi_video_csc(struct imx_hdmi *hdmi)
478{
479 int color_depth = 0;
480 int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
481 int decimation = 0;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200482
483 /* YCC422 interpolation to 444 mode */
484 if (is_color_space_interpolation(hdmi))
485 interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
486 else if (is_color_space_decimation(hdmi))
487 decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
488
489 if (hdmi->hdmi_data.enc_color_depth == 8)
490 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
491 else if (hdmi->hdmi_data.enc_color_depth == 10)
492 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
493 else if (hdmi->hdmi_data.enc_color_depth == 12)
494 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
495 else if (hdmi->hdmi_data.enc_color_depth == 16)
496 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
497 else
498 return;
499
500 /* Configure the CSC registers */
501 hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
Russell King812bc612013-11-04 12:42:02 +0000502 hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
503 HDMI_CSC_SCALE);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200504
505 imx_hdmi_update_csc_coeffs(hdmi);
506}
507
508/*
509 * HDMI video packetizer is used to packetize the data.
510 * for example, if input is YCC422 mode or repeater is used,
511 * data should be repacked this module can be bypassed.
512 */
513static void hdmi_video_packetize(struct imx_hdmi *hdmi)
514{
515 unsigned int color_depth = 0;
516 unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
517 unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
518 struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
Russell Kingbebdf662013-11-04 12:55:30 +0000519 u8 val, vp_conf;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200520
Andy Yanb5878332014-12-05 14:23:52 +0800521 if (hdmi_data->enc_out_format == RGB ||
522 hdmi_data->enc_out_format == YCBCR444) {
523 if (!hdmi_data->enc_color_depth) {
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200524 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
Andy Yanb5878332014-12-05 14:23:52 +0800525 } else if (hdmi_data->enc_color_depth == 8) {
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200526 color_depth = 4;
527 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
Andy Yanb5878332014-12-05 14:23:52 +0800528 } else if (hdmi_data->enc_color_depth == 10) {
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200529 color_depth = 5;
Andy Yanb5878332014-12-05 14:23:52 +0800530 } else if (hdmi_data->enc_color_depth == 12) {
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200531 color_depth = 6;
Andy Yanb5878332014-12-05 14:23:52 +0800532 } else if (hdmi_data->enc_color_depth == 16) {
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200533 color_depth = 7;
Andy Yanb5878332014-12-05 14:23:52 +0800534 } else {
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200535 return;
Andy Yanb5878332014-12-05 14:23:52 +0800536 }
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200537 } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
538 if (!hdmi_data->enc_color_depth ||
539 hdmi_data->enc_color_depth == 8)
540 remap_size = HDMI_VP_REMAP_YCC422_16bit;
541 else if (hdmi_data->enc_color_depth == 10)
542 remap_size = HDMI_VP_REMAP_YCC422_20bit;
543 else if (hdmi_data->enc_color_depth == 12)
544 remap_size = HDMI_VP_REMAP_YCC422_24bit;
545 else
546 return;
547 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
Andy Yanb5878332014-12-05 14:23:52 +0800548 } else {
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200549 return;
Andy Yanb5878332014-12-05 14:23:52 +0800550 }
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200551
552 /* set the packetizer registers */
553 val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
554 HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
555 ((hdmi_data->pix_repet_factor <<
556 HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
557 HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
558 hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
559
Russell King812bc612013-11-04 12:42:02 +0000560 hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
561 HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200562
563 /* Data from pixel repeater block */
564 if (hdmi_data->pix_repet_factor > 1) {
Russell Kingbebdf662013-11-04 12:55:30 +0000565 vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
566 HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200567 } else { /* data from packetizer block */
Russell Kingbebdf662013-11-04 12:55:30 +0000568 vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
569 HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200570 }
571
Russell Kingbebdf662013-11-04 12:55:30 +0000572 hdmi_modb(hdmi, vp_conf,
573 HDMI_VP_CONF_PR_EN_MASK |
574 HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
575
Russell King812bc612013-11-04 12:42:02 +0000576 hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
577 HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200578
579 hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
580
581 if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
Russell Kingbebdf662013-11-04 12:55:30 +0000582 vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
583 HDMI_VP_CONF_PP_EN_ENABLE |
584 HDMI_VP_CONF_YCC422_EN_DISABLE;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200585 } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
Russell Kingbebdf662013-11-04 12:55:30 +0000586 vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
587 HDMI_VP_CONF_PP_EN_DISABLE |
588 HDMI_VP_CONF_YCC422_EN_ENABLE;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200589 } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
Russell Kingbebdf662013-11-04 12:55:30 +0000590 vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
591 HDMI_VP_CONF_PP_EN_DISABLE |
592 HDMI_VP_CONF_YCC422_EN_DISABLE;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200593 } else {
594 return;
595 }
596
Russell Kingbebdf662013-11-04 12:55:30 +0000597 hdmi_modb(hdmi, vp_conf,
598 HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
599 HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200600
Russell King812bc612013-11-04 12:42:02 +0000601 hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
602 HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
603 HDMI_VP_STUFF_PP_STUFFING_MASK |
604 HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200605
Russell King812bc612013-11-04 12:42:02 +0000606 hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
607 HDMI_VP_CONF);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200608}
609
610static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
Andy Yanb5878332014-12-05 14:23:52 +0800611 unsigned char bit)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200612{
Russell King812bc612013-11-04 12:42:02 +0000613 hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
614 HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200615}
616
617static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
Andy Yanb5878332014-12-05 14:23:52 +0800618 unsigned char bit)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200619{
Russell King812bc612013-11-04 12:42:02 +0000620 hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
621 HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200622}
623
624static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
Andy Yanb5878332014-12-05 14:23:52 +0800625 unsigned char bit)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200626{
Russell King812bc612013-11-04 12:42:02 +0000627 hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
628 HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200629}
630
631static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
Andy Yanb5878332014-12-05 14:23:52 +0800632 unsigned char bit)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200633{
634 hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
635}
636
637static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
Andy Yanb5878332014-12-05 14:23:52 +0800638 unsigned char bit)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200639{
640 hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
641}
642
643static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
644{
Emil Renner Berthing0e6bcf32014-03-30 00:21:21 +0100645 while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200646 if (msec-- == 0)
647 return false;
Emil Renner Berthing0e6bcf32014-03-30 00:21:21 +0100648 udelay(1000);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200649 }
650 return true;
651}
652
653static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
Andy Yanb5878332014-12-05 14:23:52 +0800654 unsigned char addr)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200655{
656 hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
657 hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
658 hdmi_writeb(hdmi, (unsigned char)(data >> 8),
Andy Yanb5878332014-12-05 14:23:52 +0800659 HDMI_PHY_I2CM_DATAO_1_ADDR);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200660 hdmi_writeb(hdmi, (unsigned char)(data >> 0),
Andy Yanb5878332014-12-05 14:23:52 +0800661 HDMI_PHY_I2CM_DATAO_0_ADDR);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200662 hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
Andy Yanb5878332014-12-05 14:23:52 +0800663 HDMI_PHY_I2CM_OPERATION_ADDR);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200664 hdmi_phy_wait_i2c_done(hdmi, 1000);
665}
666
667static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
Andy Yanb5878332014-12-05 14:23:52 +0800668 unsigned char addr)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200669{
670 __hdmi_phy_i2c_write(hdmi, data, addr);
671 return 0;
672}
673
674static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
675{
676 hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
677 HDMI_PHY_CONF0_PDZ_OFFSET,
678 HDMI_PHY_CONF0_PDZ_MASK);
679}
680
681static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
682{
683 hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
684 HDMI_PHY_CONF0_ENTMDS_OFFSET,
685 HDMI_PHY_CONF0_ENTMDS_MASK);
686}
687
688static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
689{
690 hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
691 HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
692 HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
693}
694
695static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
696{
697 hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
698 HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
699 HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
700}
701
702static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
703{
704 hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
705 HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
706 HDMI_PHY_CONF0_SELDATAENPOL_MASK);
707}
708
709static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
710{
711 hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
712 HDMI_PHY_CONF0_SELDIPIF_OFFSET,
713 HDMI_PHY_CONF0_SELDIPIF_MASK);
714}
715
Russell King3e46f152013-11-04 11:24:00 +0000716enum {
717 RES_8,
718 RES_10,
719 RES_12,
720 RES_MAX,
721};
722
723struct mpll_config {
724 unsigned long mpixelclock;
725 struct {
726 u16 cpce;
727 u16 gmp;
728 } res[RES_MAX];
729};
730
731static const struct mpll_config mpll_config[] = {
732 {
733 45250000, {
734 { 0x01e0, 0x0000 },
735 { 0x21e1, 0x0000 },
736 { 0x41e2, 0x0000 }
737 },
738 }, {
739 92500000, {
740 { 0x0140, 0x0005 },
741 { 0x2141, 0x0005 },
742 { 0x4142, 0x0005 },
743 },
744 }, {
745 148500000, {
746 { 0x00a0, 0x000a },
747 { 0x20a1, 0x000a },
748 { 0x40a2, 0x000a },
749 },
750 }, {
751 ~0UL, {
752 { 0x00a0, 0x000a },
753 { 0x2001, 0x000f },
754 { 0x4002, 0x000f },
755 },
756 }
757};
758
759struct curr_ctrl {
760 unsigned long mpixelclock;
761 u16 curr[RES_MAX];
762};
763
764static const struct curr_ctrl curr_ctrl[] = {
765 /* pixelclk bpp8 bpp10 bpp12 */
766 {
767 54000000, { 0x091c, 0x091c, 0x06dc },
768 }, {
769 58400000, { 0x091c, 0x06dc, 0x06dc },
770 }, {
771 72000000, { 0x06dc, 0x06dc, 0x091c },
772 }, {
773 74250000, { 0x06dc, 0x0b5c, 0x091c },
774 }, {
775 118800000, { 0x091c, 0x091c, 0x06dc },
776 }, {
777 216000000, { 0x06dc, 0x0b5c, 0x091c },
778 }
779};
780
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200781static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
782 unsigned char res, int cscon)
783{
Russell King3e46f152013-11-04 11:24:00 +0000784 unsigned res_idx, i;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200785 u8 val, msec;
786
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200787 if (prep)
788 return -EINVAL;
Russell King3e46f152013-11-04 11:24:00 +0000789
790 switch (res) {
791 case 0: /* color resolution 0 is 8 bit colour depth */
792 case 8:
793 res_idx = RES_8;
794 break;
795 case 10:
796 res_idx = RES_10;
797 break;
798 case 12:
799 res_idx = RES_12;
800 break;
801 default:
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200802 return -EINVAL;
Russell King3e46f152013-11-04 11:24:00 +0000803 }
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200804
805 /* Enable csc path */
806 if (cscon)
807 val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
808 else
809 val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
810
811 hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
812
813 /* gen2 tx power off */
814 imx_hdmi_phy_gen2_txpwron(hdmi, 0);
815
816 /* gen2 pddq */
817 imx_hdmi_phy_gen2_pddq(hdmi, 1);
818
819 /* PHY reset */
820 hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
821 hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
822
823 hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
824
825 hdmi_phy_test_clear(hdmi, 1);
826 hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
Andy Yanb5878332014-12-05 14:23:52 +0800827 HDMI_PHY_I2CM_SLAVE_ADDR);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200828 hdmi_phy_test_clear(hdmi, 0);
829
Russell King3e46f152013-11-04 11:24:00 +0000830 /* PLL/MPLL Cfg - always match on final entry */
831 for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
832 if (hdmi->hdmi_data.video_mode.mpixelclock <=
833 mpll_config[i].mpixelclock)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200834 break;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200835
Russell King3e46f152013-11-04 11:24:00 +0000836 hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
837 hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
838
839 for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
840 if (hdmi->hdmi_data.video_mode.mpixelclock <=
841 curr_ctrl[i].mpixelclock)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200842 break;
Russell King3e46f152013-11-04 11:24:00 +0000843
844 if (i >= ARRAY_SIZE(curr_ctrl)) {
Andy Yanb5878332014-12-05 14:23:52 +0800845 dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
846 hdmi->hdmi_data.video_mode.mpixelclock);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200847 return -EINVAL;
848 }
849
Russell King3e46f152013-11-04 11:24:00 +0000850 /* CURRCTRL */
851 hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
852
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200853 hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
854 hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
855 /* RESISTANCE TERM 133Ohm Cfg */
856 hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
857 /* PREEMP Cgf 0.00 */
858 hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
859 /* TX/CK LVL 10 */
860 hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
861 /* REMOVE CLK TERM */
862 hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
863
864 imx_hdmi_phy_enable_power(hdmi, 1);
865
866 /* toggle TMDS enable */
867 imx_hdmi_phy_enable_tmds(hdmi, 0);
868 imx_hdmi_phy_enable_tmds(hdmi, 1);
869
870 /* gen2 tx power on */
871 imx_hdmi_phy_gen2_txpwron(hdmi, 1);
872 imx_hdmi_phy_gen2_pddq(hdmi, 0);
873
874 /*Wait for PHY PLL lock */
875 msec = 5;
876 do {
877 val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
878 if (!val)
879 break;
880
881 if (msec == 0) {
882 dev_err(hdmi->dev, "PHY PLL not locked\n");
883 return -ETIMEDOUT;
884 }
885
886 udelay(1000);
887 msec--;
888 } while (1);
889
890 return 0;
891}
892
893static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
894{
895 int i, ret;
896 bool cscon = false;
897
898 /*check csc whether needed activated in HDMI mode */
899 cscon = (is_color_space_conversion(hdmi) &&
900 !hdmi->hdmi_data.video_mode.mdvi);
901
902 /* HDMI Phy spec says to do the phy initialization sequence twice */
903 for (i = 0; i < 2; i++) {
904 imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
905 imx_hdmi_phy_sel_interface_control(hdmi, 0);
906 imx_hdmi_phy_enable_tmds(hdmi, 0);
907 imx_hdmi_phy_enable_power(hdmi, 0);
908
909 /* Enable CSC */
910 ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
911 if (ret)
912 return ret;
913 }
914
915 hdmi->phy_enabled = true;
916 return 0;
917}
918
919static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
920{
Russell King812bc612013-11-04 12:42:02 +0000921 u8 de;
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200922
923 if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
924 de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
925 else
926 de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
927
928 /* disable rx detect */
Russell King812bc612013-11-04 12:42:02 +0000929 hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
930 HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200931
Russell King812bc612013-11-04 12:42:02 +0000932 hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200933
Russell King812bc612013-11-04 12:42:02 +0000934 hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
935 HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200936}
937
938static void hdmi_config_AVI(struct imx_hdmi *hdmi)
939{
940 u8 val, pix_fmt, under_scan;
941 u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
942 bool aspect_16_9;
943
944 aspect_16_9 = false; /* FIXME */
945
946 /* AVI Data Byte 1 */
947 if (hdmi->hdmi_data.enc_out_format == YCBCR444)
948 pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
949 else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
950 pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
951 else
952 pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
953
954 under_scan = HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
955
956 /*
957 * Active format identification data is present in the AVI InfoFrame.
958 * Under scan info, no bar data
959 */
960 val = pix_fmt | under_scan |
961 HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
962 HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
963
964 hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
965
966 /* AVI Data Byte 2 -Set the Aspect Ratio */
967 if (aspect_16_9) {
968 act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
969 coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
970 } else {
971 act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
972 coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
973 }
974
975 /* Set up colorimetry */
976 if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
977 colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
Sachin Kamat5a819ed2014-01-28 10:33:16 +0530978 if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200979 ext_colorimetry =
980 HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
Sachin Kamat5a819ed2014-01-28 10:33:16 +0530981 else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200982 ext_colorimetry =
983 HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
984 } else if (hdmi->hdmi_data.enc_out_format != RGB) {
Sachin Kamat5a819ed2014-01-28 10:33:16 +0530985 if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200986 colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
Sachin Kamat5a819ed2014-01-28 10:33:16 +0530987 else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
Fabio Estevam9aaf8802013-11-29 08:46:32 -0200988 colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
989 ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
990 } else { /* Carries no data */
991 colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
992 ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
993 }
994
995 val = colorimetry | coded_ratio | act_ratio;
996 hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
997
998 /* AVI Data Byte 3 */
999 val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
1000 HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
1001 HDMI_FC_AVICONF2_SCALING_NONE;
1002 hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
1003
1004 /* AVI Data Byte 4 */
1005 hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
1006
1007 /* AVI Data Byte 5- set up input and output pixel repetition */
1008 val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
1009 HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
1010 HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
1011 ((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
1012 HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
1013 HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
1014 hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
1015
1016 /* IT Content and quantization range = don't care */
1017 val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
1018 HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
1019 hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
1020
1021 /* AVI Data Bytes 6-13 */
1022 hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
1023 hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
1024 hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
1025 hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
1026 hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
1027 hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
1028 hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
1029 hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
1030}
1031
1032static void hdmi_av_composer(struct imx_hdmi *hdmi,
1033 const struct drm_display_mode *mode)
1034{
1035 u8 inv_val;
1036 struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
1037 int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
1038
1039 vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
1040 vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
1041 vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
1042 vmode->mpixelclock = mode->clock * 1000;
1043
1044 dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
1045
1046 /* Set up HDMI_FC_INVIDCONF */
1047 inv_val = (hdmi->hdmi_data.hdcp_enable ?
1048 HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
1049 HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
1050
1051 inv_val |= (vmode->mvsyncpolarity ?
1052 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
1053 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
1054
1055 inv_val |= (vmode->mhsyncpolarity ?
1056 HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
1057 HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
1058
1059 inv_val |= (vmode->mdataenablepolarity ?
1060 HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
1061 HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
1062
1063 if (hdmi->vic == 39)
1064 inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
1065 else
1066 inv_val |= (vmode->minterlaced ?
1067 HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
1068 HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
1069
1070 inv_val |= (vmode->minterlaced ?
1071 HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
1072 HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
1073
1074 inv_val |= (vmode->mdvi ?
1075 HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
1076 HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
1077
1078 hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
1079
1080 /* Set up horizontal active pixel width */
1081 hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
1082 hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
1083
1084 /* Set up vertical active lines */
1085 hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
1086 hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
1087
1088 /* Set up horizontal blanking pixel region width */
1089 hblank = mode->htotal - mode->hdisplay;
1090 hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
1091 hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
1092
1093 /* Set up vertical blanking pixel region width */
1094 vblank = mode->vtotal - mode->vdisplay;
1095 hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
1096
1097 /* Set up HSYNC active edge delay width (in pixel clks) */
1098 h_de_hs = mode->hsync_start - mode->hdisplay;
1099 hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
1100 hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
1101
1102 /* Set up VSYNC active edge delay (in lines) */
1103 v_de_vs = mode->vsync_start - mode->vdisplay;
1104 hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
1105
1106 /* Set up HSYNC active pulse width (in pixel clks) */
1107 hsync_len = mode->hsync_end - mode->hsync_start;
1108 hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
1109 hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
1110
1111 /* Set up VSYNC active edge delay (in lines) */
1112 vsync_len = mode->vsync_end - mode->vsync_start;
1113 hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
1114}
1115
1116static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
1117{
1118 if (!hdmi->phy_enabled)
1119 return;
1120
1121 imx_hdmi_phy_enable_tmds(hdmi, 0);
1122 imx_hdmi_phy_enable_power(hdmi, 0);
1123
1124 hdmi->phy_enabled = false;
1125}
1126
1127/* HDMI Initialization Step B.4 */
1128static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
1129{
1130 u8 clkdis;
1131
1132 /* control period minimum duration */
1133 hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
1134 hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
1135 hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
1136
1137 /* Set to fill TMDS data channels */
1138 hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
1139 hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
1140 hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
1141
1142 /* Enable pixel clock and tmds data path */
1143 clkdis = 0x7F;
1144 clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
1145 hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
1146
1147 clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
1148 hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
1149
1150 /* Enable csc path */
1151 if (is_color_space_conversion(hdmi)) {
1152 clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
1153 hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
1154 }
1155}
1156
1157static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
1158{
Russell King812bc612013-11-04 12:42:02 +00001159 hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001160}
1161
1162/* Workaround to clear the overflow condition */
1163static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
1164{
1165 int count;
1166 u8 val;
1167
1168 /* TMDS software reset */
1169 hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
1170
1171 val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
1172 if (hdmi->dev_type == IMX6DL_HDMI) {
1173 hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
1174 return;
1175 }
1176
1177 for (count = 0; count < 4; count++)
1178 hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
1179}
1180
1181static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
1182{
1183 hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
1184 hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
1185}
1186
1187static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
1188{
1189 hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
1190 HDMI_IH_MUTE_FC_STAT2);
1191}
1192
1193static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
1194{
1195 int ret;
1196
1197 hdmi_disable_overflow_interrupts(hdmi);
1198
1199 hdmi->vic = drm_match_cea_mode(mode);
1200
1201 if (!hdmi->vic) {
1202 dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
1203 hdmi->hdmi_data.video_mode.mdvi = true;
1204 } else {
1205 dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
1206 hdmi->hdmi_data.video_mode.mdvi = false;
1207 }
1208
1209 if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
Andy Yanb5878332014-12-05 14:23:52 +08001210 (hdmi->vic == 21) || (hdmi->vic == 22) ||
1211 (hdmi->vic == 2) || (hdmi->vic == 3) ||
1212 (hdmi->vic == 17) || (hdmi->vic == 18))
Sachin Kamat5a819ed2014-01-28 10:33:16 +05301213 hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001214 else
Sachin Kamat5a819ed2014-01-28 10:33:16 +05301215 hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001216
1217 if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
Andy Yanb5878332014-12-05 14:23:52 +08001218 (hdmi->vic == 12) || (hdmi->vic == 13) ||
1219 (hdmi->vic == 14) || (hdmi->vic == 15) ||
1220 (hdmi->vic == 25) || (hdmi->vic == 26) ||
1221 (hdmi->vic == 27) || (hdmi->vic == 28) ||
1222 (hdmi->vic == 29) || (hdmi->vic == 30) ||
1223 (hdmi->vic == 35) || (hdmi->vic == 36) ||
1224 (hdmi->vic == 37) || (hdmi->vic == 38))
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001225 hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
1226 else
1227 hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
1228
1229 hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
1230
1231 /* TODO: Get input format from IPU (via FB driver interface) */
1232 hdmi->hdmi_data.enc_in_format = RGB;
1233
1234 hdmi->hdmi_data.enc_out_format = RGB;
1235
1236 hdmi->hdmi_data.enc_color_depth = 8;
1237 hdmi->hdmi_data.pix_repet_factor = 0;
1238 hdmi->hdmi_data.hdcp_enable = 0;
1239 hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
1240
1241 /* HDMI Initialization Step B.1 */
1242 hdmi_av_composer(hdmi, mode);
1243
1244 /* HDMI Initializateion Step B.2 */
1245 ret = imx_hdmi_phy_init(hdmi);
1246 if (ret)
1247 return ret;
1248
1249 /* HDMI Initialization Step B.3 */
1250 imx_hdmi_enable_video_path(hdmi);
1251
1252 /* not for DVI mode */
Andy Yanb5878332014-12-05 14:23:52 +08001253 if (hdmi->hdmi_data.video_mode.mdvi) {
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001254 dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
Andy Yanb5878332014-12-05 14:23:52 +08001255 } else {
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001256 dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
1257
1258 /* HDMI Initialization Step E - Configure audio */
1259 hdmi_clk_regenerator_update_pixel_clock(hdmi);
1260 hdmi_enable_audio_clk(hdmi);
1261
1262 /* HDMI Initialization Step F - Configure AVI InfoFrame */
1263 hdmi_config_AVI(hdmi);
1264 }
1265
1266 hdmi_video_packetize(hdmi);
1267 hdmi_video_csc(hdmi);
1268 hdmi_video_sample(hdmi);
1269 hdmi_tx_hdcp_config(hdmi);
1270
1271 imx_hdmi_clear_overflow(hdmi);
1272 if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
1273 hdmi_enable_overflow_interrupts(hdmi);
1274
1275 return 0;
1276}
1277
1278/* Wait until we are registered to enable interrupts */
1279static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
1280{
1281 hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
1282 HDMI_PHY_I2CM_INT_ADDR);
1283
1284 hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
1285 HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
1286 HDMI_PHY_I2CM_CTLINT_ADDR);
1287
1288 /* enable cable hot plug irq */
1289 hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
1290
1291 /* Clear Hotplug interrupts */
1292 hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
1293
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001294 return 0;
1295}
1296
1297static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
1298{
1299 u8 ih_mute;
1300
1301 /*
1302 * Boot up defaults are:
1303 * HDMI_IH_MUTE = 0x03 (disabled)
1304 * HDMI_IH_MUTE_* = 0x00 (enabled)
1305 *
1306 * Disable top level interrupt bits in HDMI block
1307 */
1308 ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
1309 HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
1310 HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
1311
1312 hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
1313
1314 /* by default mask all interrupts */
1315 hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
1316 hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
1317 hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
1318 hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
1319 hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
1320 hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
1321 hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
1322 hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
1323 hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
1324 hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
1325 hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
1326 hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
1327 hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
1328 hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
1329 hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
1330
1331 /* Disable interrupts in the IH_MUTE_* registers */
1332 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
1333 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
1334 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
1335 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
1336 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
1337 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
1338 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
1339 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
1340 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
1341 hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
1342
1343 /* Enable top level interrupt bits in HDMI block */
1344 ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
1345 HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
1346 hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
1347}
1348
1349static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
1350{
1351 imx_hdmi_setup(hdmi, &hdmi->previous_mode);
1352}
1353
1354static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
1355{
1356 imx_hdmi_phy_disable(hdmi);
1357}
1358
Andy Yan3d1b35a2014-12-05 14:25:05 +08001359static void imx_hdmi_bridge_mode_set(struct drm_bridge *bridge,
1360 struct drm_display_mode *mode,
1361 struct drm_display_mode *adjusted_mode)
1362{
1363 struct imx_hdmi *hdmi = bridge->driver_private;
1364
1365 imx_hdmi_setup(hdmi, mode);
1366
1367 /* Store the display mode for plugin/DKMS poweron events */
1368 memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
1369}
1370
1371static bool imx_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
1372 const struct drm_display_mode *mode,
1373 struct drm_display_mode *adjusted_mode)
1374{
1375 return true;
1376}
1377
1378static void imx_hdmi_bridge_disable(struct drm_bridge *bridge)
1379{
1380 struct imx_hdmi *hdmi = bridge->driver_private;
1381
1382 imx_hdmi_poweroff(hdmi);
1383}
1384
1385static void imx_hdmi_bridge_enable(struct drm_bridge *bridge)
1386{
1387 struct imx_hdmi *hdmi = bridge->driver_private;
1388
1389 imx_hdmi_poweron(hdmi);
1390}
1391
1392static void imx_hdmi_bridge_destroy(struct drm_bridge *bridge)
1393{
1394 drm_bridge_cleanup(bridge);
1395 kfree(bridge);
1396}
1397
1398static void imx_hdmi_bridge_nop(struct drm_bridge *bridge)
1399{
1400 /* do nothing */
1401}
1402
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001403static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
1404 *connector, bool force)
1405{
Russell Kingd94905e2013-11-03 22:23:24 +00001406 struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
1407 connector);
Russell King98dbead2014-04-18 10:46:45 +01001408
1409 return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
1410 connector_status_connected : connector_status_disconnected;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001411}
1412
1413static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
1414{
1415 struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
1416 connector);
1417 struct edid *edid;
1418 int ret;
1419
1420 if (!hdmi->ddc)
1421 return 0;
1422
1423 edid = drm_get_edid(connector, hdmi->ddc);
1424 if (edid) {
1425 dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
1426 edid->width_cm, edid->height_cm);
1427
1428 drm_mode_connector_update_edid_property(connector, edid);
1429 ret = drm_add_edid_modes(connector, edid);
1430 kfree(edid);
1431 } else {
1432 dev_dbg(hdmi->dev, "failed to get edid\n");
1433 }
1434
1435 return 0;
1436}
1437
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001438static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
1439 *connector)
1440{
1441 struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
1442 connector);
1443
Andy Yan3d1b35a2014-12-05 14:25:05 +08001444 return hdmi->encoder;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001445}
1446
Andy Yan3d1b35a2014-12-05 14:25:05 +08001447static void imx_hdmi_connector_destroy(struct drm_connector *connector)
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001448{
Andy Yan3d1b35a2014-12-05 14:25:05 +08001449 drm_connector_unregister(connector);
1450 drm_connector_cleanup(connector);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001451}
1452
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001453static struct drm_connector_funcs imx_hdmi_connector_funcs = {
1454 .dpms = drm_helper_connector_dpms,
1455 .fill_modes = drm_helper_probe_single_connector_modes,
1456 .detect = imx_hdmi_connector_detect,
Andy Yan3d1b35a2014-12-05 14:25:05 +08001457 .destroy = imx_hdmi_connector_destroy,
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001458};
1459
1460static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
1461 .get_modes = imx_hdmi_connector_get_modes,
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001462 .best_encoder = imx_hdmi_connector_best_encoder,
1463};
1464
Andy Yan3d1b35a2014-12-05 14:25:05 +08001465struct drm_bridge_funcs imx_hdmi_bridge_funcs = {
1466 .enable = imx_hdmi_bridge_enable,
1467 .disable = imx_hdmi_bridge_disable,
1468 .pre_enable = imx_hdmi_bridge_nop,
1469 .post_disable = imx_hdmi_bridge_nop,
1470 .mode_set = imx_hdmi_bridge_mode_set,
1471 .mode_fixup = imx_hdmi_bridge_mode_fixup,
1472 .destroy = imx_hdmi_bridge_destroy,
1473};
1474
Russell Kingd94905e2013-11-03 22:23:24 +00001475static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
1476{
1477 struct imx_hdmi *hdmi = dev_id;
1478 u8 intr_stat;
1479
1480 intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
1481 if (intr_stat)
1482 hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
1483
1484 return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
1485}
1486
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001487static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
1488{
1489 struct imx_hdmi *hdmi = dev_id;
1490 u8 intr_stat;
1491 u8 phy_int_pol;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001492
1493 intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
1494
1495 phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
1496
1497 if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
1498 if (phy_int_pol & HDMI_PHY_HPD) {
1499 dev_dbg(hdmi->dev, "EVENT=plugin\n");
1500
Russell King812bc612013-11-04 12:42:02 +00001501 hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001502
1503 imx_hdmi_poweron(hdmi);
1504 } else {
1505 dev_dbg(hdmi->dev, "EVENT=plugout\n");
1506
Gulsah Kose256a38b2014-03-09 20:11:07 +02001507 hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
Andy Yanb5878332014-12-05 14:23:52 +08001508 HDMI_PHY_POL0);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001509
1510 imx_hdmi_poweroff(hdmi);
1511 }
Russell Kingd94905e2013-11-03 22:23:24 +00001512 drm_helper_hpd_irq_event(hdmi->connector.dev);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001513 }
1514
1515 hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
Russell Kingd94905e2013-11-03 22:23:24 +00001516 hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001517
1518 return IRQ_HANDLED;
1519}
1520
Russell King1b3f7672013-11-03 13:30:48 +00001521static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001522{
Andy Yan3d1b35a2014-12-05 14:25:05 +08001523 struct drm_encoder *encoder = hdmi->encoder;
1524 struct drm_bridge *bridge;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001525 int ret;
1526
Andy Yan3d1b35a2014-12-05 14:25:05 +08001527 bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
1528 if (!bridge) {
1529 DRM_ERROR("Failed to allocate drm bridge\n");
1530 return -ENOMEM;
1531 }
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001532
Andy Yan3d1b35a2014-12-05 14:25:05 +08001533 hdmi->bridge = bridge;
1534 bridge->driver_private = hdmi;
1535
1536 ret = drm_bridge_init(drm, bridge, &imx_hdmi_bridge_funcs);
1537 if (ret) {
1538 DRM_ERROR("Failed to initialize bridge with drm\n");
1539 return -EINVAL;
1540 }
1541
1542 encoder->bridge = bridge;
Russell Kingd94905e2013-11-03 22:23:24 +00001543 hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001544
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001545 drm_connector_helper_add(&hdmi->connector,
Andy Yanb5878332014-12-05 14:23:52 +08001546 &imx_hdmi_connector_helper_funcs);
Russell King1b3f7672013-11-03 13:30:48 +00001547 drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
1548 DRM_MODE_CONNECTOR_HDMIA);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001549
Andy Yan3d1b35a2014-12-05 14:25:05 +08001550 hdmi->connector.encoder = encoder;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001551
Andy Yan3d1b35a2014-12-05 14:25:05 +08001552 drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001553
1554 return 0;
1555}
1556
Andy Yan3d1b35a2014-12-05 14:25:05 +08001557int imx_hdmi_bind(struct device *dev, struct device *master,
1558 void *data, struct drm_encoder *encoder,
1559 struct resource *iores, int irq,
1560 const struct dw_hdmi_plat_data *plat_data)
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001561{
Russell King1b3f7672013-11-03 13:30:48 +00001562 struct drm_device *drm = data;
Russell King17b50012013-11-03 11:23:34 +00001563 struct device_node *np = dev->of_node;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001564 struct device_node *ddc_node;
1565 struct imx_hdmi *hdmi;
Andy Yan3d1b35a2014-12-05 14:25:05 +08001566 int ret;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001567
Russell King17b50012013-11-03 11:23:34 +00001568 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001569 if (!hdmi)
1570 return -ENOMEM;
1571
Andy Yan3d1b35a2014-12-05 14:25:05 +08001572 hdmi->plat_data = plat_data;
Russell King17b50012013-11-03 11:23:34 +00001573 hdmi->dev = dev;
Andy Yan3d1b35a2014-12-05 14:25:05 +08001574 hdmi->dev_type = plat_data->dev_type;
Russell King40678382013-11-07 15:35:06 +00001575 hdmi->sample_rate = 48000;
1576 hdmi->ratio = 100;
Andy Yan3d1b35a2014-12-05 14:25:05 +08001577 hdmi->encoder = encoder;
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001578
Philipp Zabelb5d45902014-03-05 10:20:56 +01001579 ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001580 if (ddc_node) {
1581 hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001582 of_node_put(ddc_node);
Andy Yanc2c38482014-12-05 14:24:28 +08001583 if (!hdmi->ddc) {
1584 dev_dbg(hdmi->dev, "failed to read ddc node\n");
1585 return -EPROBE_DEFER;
1586 }
1587
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001588 } else {
1589 dev_dbg(hdmi->dev, "no ddc property found\n");
1590 }
1591
Russell Kingd94905e2013-11-03 22:23:24 +00001592 ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
1593 imx_hdmi_irq, IRQF_SHARED,
1594 dev_name(dev), hdmi);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001595 if (ret)
1596 return ret;
1597
Russell King17b50012013-11-03 11:23:34 +00001598 hdmi->regs = devm_ioremap_resource(dev, iores);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001599 if (IS_ERR(hdmi->regs))
1600 return PTR_ERR(hdmi->regs);
1601
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001602 hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
1603 if (IS_ERR(hdmi->isfr_clk)) {
1604 ret = PTR_ERR(hdmi->isfr_clk);
Andy Yanb5878332014-12-05 14:23:52 +08001605 dev_err(hdmi->dev, "Unable to get HDMI isfr clk: %d\n", ret);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001606 return ret;
1607 }
1608
1609 ret = clk_prepare_enable(hdmi->isfr_clk);
1610 if (ret) {
Andy Yanb5878332014-12-05 14:23:52 +08001611 dev_err(hdmi->dev, "Cannot enable HDMI isfr clock: %d\n", ret);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001612 return ret;
1613 }
1614
1615 hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
1616 if (IS_ERR(hdmi->iahb_clk)) {
1617 ret = PTR_ERR(hdmi->iahb_clk);
Andy Yanb5878332014-12-05 14:23:52 +08001618 dev_err(hdmi->dev, "Unable to get HDMI iahb clk: %d\n", ret);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001619 goto err_isfr;
1620 }
1621
1622 ret = clk_prepare_enable(hdmi->iahb_clk);
1623 if (ret) {
Andy Yanb5878332014-12-05 14:23:52 +08001624 dev_err(hdmi->dev, "Cannot enable HDMI iahb clock: %d\n", ret);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001625 goto err_isfr;
1626 }
1627
1628 /* Product and revision IDs */
Russell King17b50012013-11-03 11:23:34 +00001629 dev_info(dev,
Andy Yanb5878332014-12-05 14:23:52 +08001630 "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
1631 hdmi_readb(hdmi, HDMI_DESIGN_ID),
1632 hdmi_readb(hdmi, HDMI_REVISION_ID),
1633 hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
1634 hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001635
1636 initialize_hdmi_ih_mutes(hdmi);
1637
1638 /*
1639 * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
1640 * N and cts values before enabling phy
1641 */
1642 hdmi_init_clk_regenerator(hdmi);
1643
1644 /*
1645 * Configure registers related to HDMI interrupt
1646 * generation before registering IRQ.
1647 */
1648 hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
1649
1650 /* Clear Hotplug interrupts */
1651 hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
1652
1653 ret = imx_hdmi_fb_registered(hdmi);
1654 if (ret)
1655 goto err_iahb;
1656
Russell King1b3f7672013-11-03 13:30:48 +00001657 ret = imx_hdmi_register(drm, hdmi);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001658 if (ret)
1659 goto err_iahb;
1660
Russell Kingd94905e2013-11-03 22:23:24 +00001661 /* Unmute interrupts */
1662 hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001663
Russell King17b50012013-11-03 11:23:34 +00001664 dev_set_drvdata(dev, hdmi);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001665
1666 return 0;
1667
1668err_iahb:
1669 clk_disable_unprepare(hdmi->iahb_clk);
1670err_isfr:
1671 clk_disable_unprepare(hdmi->isfr_clk);
1672
1673 return ret;
1674}
Andy Yan3d1b35a2014-12-05 14:25:05 +08001675EXPORT_SYMBOL_GPL(imx_hdmi_bind);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001676
Andy Yan3d1b35a2014-12-05 14:25:05 +08001677void imx_hdmi_unbind(struct device *dev, struct device *master, void *data)
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001678{
Russell King17b50012013-11-03 11:23:34 +00001679 struct imx_hdmi *hdmi = dev_get_drvdata(dev);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001680
Russell Kingd94905e2013-11-03 22:23:24 +00001681 /* Disable all interrupts */
1682 hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
1683
Russell King1b3f7672013-11-03 13:30:48 +00001684 hdmi->connector.funcs->destroy(&hdmi->connector);
Andy Yan3d1b35a2014-12-05 14:25:05 +08001685 hdmi->encoder->funcs->destroy(hdmi->encoder);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001686
1687 clk_disable_unprepare(hdmi->iahb_clk);
1688 clk_disable_unprepare(hdmi->isfr_clk);
1689 i2c_put_adapter(hdmi->ddc);
Russell King17b50012013-11-03 11:23:34 +00001690}
Andy Yan3d1b35a2014-12-05 14:25:05 +08001691EXPORT_SYMBOL_GPL(imx_hdmi_unbind);
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001692
1693MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
Andy Yan3d1b35a2014-12-05 14:25:05 +08001694MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
1695MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
Fabio Estevam9aaf8802013-11-29 08:46:32 -02001696MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
1697MODULE_LICENSE("GPL");
1698MODULE_ALIAS("platform:imx-hdmi");