diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/video/omap2/dss/hdmi.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/video/omap2/dss/hdmi.c')
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 1763 |
1 files changed, 1763 insertions, 0 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c new file mode 100644 index 000000000000..b0555f4f0a78 --- /dev/null +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -0,0 +1,1763 @@ | |||
1 | /* | ||
2 | * hdmi.c | ||
3 | * | ||
4 | * HDMI interface DSS driver setting for TI's OMAP4 family of processor. | ||
5 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
6 | * Authors: Yong Zhi | ||
7 | * Mythri pk <mythripk@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #define DSS_SUBSYS_NAME "HDMI" | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/err.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/mutex.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/string.h> | ||
32 | #include <video/omapdss.h> | ||
33 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
34 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
35 | #include <sound/soc.h> | ||
36 | #include <sound/pcm_params.h> | ||
37 | #endif | ||
38 | |||
39 | #include "dss.h" | ||
40 | #include "hdmi.h" | ||
41 | #include "dss_features.h" | ||
42 | |||
43 | static struct { | ||
44 | struct mutex lock; | ||
45 | struct omap_display_platform_data *pdata; | ||
46 | struct platform_device *pdev; | ||
47 | void __iomem *base_wp; /* HDMI wrapper */ | ||
48 | int code; | ||
49 | int mode; | ||
50 | u8 edid[HDMI_EDID_MAX_LENGTH]; | ||
51 | u8 edid_set; | ||
52 | bool custom_set; | ||
53 | struct hdmi_config cfg; | ||
54 | } hdmi; | ||
55 | |||
56 | /* | ||
57 | * Logic for the below structure : | ||
58 | * user enters the CEA or VESA timings by specifying the HDMI/DVI code. | ||
59 | * There is a correspondence between CEA/VESA timing and code, please | ||
60 | * refer to section 6.3 in HDMI 1.3 specification for timing code. | ||
61 | * | ||
62 | * In the below structure, cea_vesa_timings corresponds to all OMAP4 | ||
63 | * supported CEA and VESA timing values.code_cea corresponds to the CEA | ||
64 | * code, It is used to get the timing from cea_vesa_timing array.Similarly | ||
65 | * with code_vesa. Code_index is used for back mapping, that is once EDID | ||
66 | * is read from the TV, EDID is parsed to find the timing values and then | ||
67 | * map it to corresponding CEA or VESA index. | ||
68 | */ | ||
69 | |||
70 | static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = { | ||
71 | { {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0}, | ||
72 | { {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1}, | ||
73 | { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}, | ||
74 | { {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0}, | ||
75 | { {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0}, | ||
76 | { {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0}, | ||
77 | { {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0}, | ||
78 | { {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1}, | ||
79 | { {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1}, | ||
80 | { {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1}, | ||
81 | { {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0}, | ||
82 | { {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0}, | ||
83 | { {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1}, | ||
84 | { {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0}, | ||
85 | { {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1}, | ||
86 | /* VESA From Here */ | ||
87 | { {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0}, | ||
88 | { {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1}, | ||
89 | { {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1}, | ||
90 | { {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0}, | ||
91 | { {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0}, | ||
92 | { {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1}, | ||
93 | { {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1}, | ||
94 | { {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1}, | ||
95 | { {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0}, | ||
96 | { {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0}, | ||
97 | { {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0}, | ||
98 | { {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0}, | ||
99 | { {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1}, | ||
100 | { {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1}, | ||
101 | { {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1}, | ||
102 | { {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1}, | ||
103 | { {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1}, | ||
104 | { {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1}, | ||
105 | { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1} | ||
106 | }; | ||
107 | |||
108 | /* | ||
109 | * This is a static mapping array which maps the timing values | ||
110 | * with corresponding CEA / VESA code | ||
111 | */ | ||
112 | static const int code_index[OMAP_HDMI_TIMINGS_NB] = { | ||
113 | 1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32, | ||
114 | /* <--15 CEA 17--> vesa*/ | ||
115 | 4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A, | ||
116 | 0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B | ||
117 | }; | ||
118 | |||
119 | /* | ||
120 | * This is reverse static mapping which maps the CEA / VESA code | ||
121 | * to the corresponding timing values | ||
122 | */ | ||
123 | static const int code_cea[39] = { | ||
124 | -1, 0, 3, 3, 2, 8, 5, 5, -1, -1, | ||
125 | -1, -1, -1, -1, -1, -1, 9, 10, 10, 1, | ||
126 | 7, 6, 6, -1, -1, -1, -1, -1, -1, 11, | ||
127 | 11, 12, 14, -1, -1, 13, 13, 4, 4 | ||
128 | }; | ||
129 | |||
130 | static const int code_vesa[85] = { | ||
131 | -1, -1, -1, -1, 15, -1, -1, -1, -1, 16, | ||
132 | -1, -1, -1, -1, 17, -1, 23, -1, -1, -1, | ||
133 | -1, -1, 29, 18, -1, -1, -1, 32, 19, -1, | ||
134 | -1, -1, 21, -1, -1, 22, -1, -1, -1, 20, | ||
135 | -1, 30, 24, -1, -1, -1, -1, 25, -1, -1, | ||
136 | -1, -1, -1, -1, -1, -1, -1, 31, 26, -1, | ||
137 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||
138 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||
139 | -1, 27, 28, -1, 33}; | ||
140 | |||
141 | static const u8 edid_header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0}; | ||
142 | |||
143 | static inline void hdmi_write_reg(const struct hdmi_reg idx, u32 val) | ||
144 | { | ||
145 | __raw_writel(val, hdmi.base_wp + idx.idx); | ||
146 | } | ||
147 | |||
148 | static inline u32 hdmi_read_reg(const struct hdmi_reg idx) | ||
149 | { | ||
150 | return __raw_readl(hdmi.base_wp + idx.idx); | ||
151 | } | ||
152 | |||
153 | static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx, | ||
154 | int b2, int b1, u32 val) | ||
155 | { | ||
156 | u32 t = 0; | ||
157 | while (val != REG_GET(idx, b2, b1)) { | ||
158 | udelay(1); | ||
159 | if (t++ > 10000) | ||
160 | return !val; | ||
161 | } | ||
162 | return val; | ||
163 | } | ||
164 | |||
165 | int hdmi_init_display(struct omap_dss_device *dssdev) | ||
166 | { | ||
167 | DSSDBG("init_display\n"); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int hdmi_pll_init(enum hdmi_clk_refsel refsel, int dcofreq, | ||
173 | struct hdmi_pll_info *fmt, u16 sd) | ||
174 | { | ||
175 | u32 r; | ||
176 | |||
177 | /* PLL start always use manual mode */ | ||
178 | REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 0, 0); | ||
179 | |||
180 | r = hdmi_read_reg(PLLCTRL_CFG1); | ||
181 | r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */ | ||
182 | r = FLD_MOD(r, fmt->regn, 8, 1); /* CFG1_PLL_REGN */ | ||
183 | |||
184 | hdmi_write_reg(PLLCTRL_CFG1, r); | ||
185 | |||
186 | r = hdmi_read_reg(PLLCTRL_CFG2); | ||
187 | |||
188 | r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */ | ||
189 | r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */ | ||
190 | r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */ | ||
191 | |||
192 | if (dcofreq) { | ||
193 | /* divider programming for frequency beyond 1000Mhz */ | ||
194 | REG_FLD_MOD(PLLCTRL_CFG3, sd, 17, 10); | ||
195 | r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ | ||
196 | } else { | ||
197 | r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ | ||
198 | } | ||
199 | |||
200 | hdmi_write_reg(PLLCTRL_CFG2, r); | ||
201 | |||
202 | r = hdmi_read_reg(PLLCTRL_CFG4); | ||
203 | r = FLD_MOD(r, fmt->regm2, 24, 18); | ||
204 | r = FLD_MOD(r, fmt->regmf, 17, 0); | ||
205 | |||
206 | hdmi_write_reg(PLLCTRL_CFG4, r); | ||
207 | |||
208 | /* go now */ | ||
209 | REG_FLD_MOD(PLLCTRL_PLL_GO, 0x1, 0, 0); | ||
210 | |||
211 | /* wait for bit change */ | ||
212 | if (hdmi_wait_for_bit_change(PLLCTRL_PLL_GO, 0, 0, 1) != 1) { | ||
213 | DSSERR("PLL GO bit not set\n"); | ||
214 | return -ETIMEDOUT; | ||
215 | } | ||
216 | |||
217 | /* Wait till the lock bit is set in PLL status */ | ||
218 | if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { | ||
219 | DSSWARN("cannot lock PLL\n"); | ||
220 | DSSWARN("CFG1 0x%x\n", | ||
221 | hdmi_read_reg(PLLCTRL_CFG1)); | ||
222 | DSSWARN("CFG2 0x%x\n", | ||
223 | hdmi_read_reg(PLLCTRL_CFG2)); | ||
224 | DSSWARN("CFG4 0x%x\n", | ||
225 | hdmi_read_reg(PLLCTRL_CFG4)); | ||
226 | return -ETIMEDOUT; | ||
227 | } | ||
228 | |||
229 | DSSDBG("PLL locked!\n"); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | /* PHY_PWR_CMD */ | ||
235 | static int hdmi_set_phy_pwr(enum hdmi_phy_pwr val) | ||
236 | { | ||
237 | /* Command for power control of HDMI PHY */ | ||
238 | REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 7, 6); | ||
239 | |||
240 | /* Status of the power control of HDMI PHY */ | ||
241 | if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 5, 4, val) != val) { | ||
242 | DSSERR("Failed to set PHY power mode to %d\n", val); | ||
243 | return -ETIMEDOUT; | ||
244 | } | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* PLL_PWR_CMD */ | ||
250 | static int hdmi_set_pll_pwr(enum hdmi_pll_pwr val) | ||
251 | { | ||
252 | /* Command for power control of HDMI PLL */ | ||
253 | REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 3, 2); | ||
254 | |||
255 | /* wait till PHY_PWR_STATUS is set */ | ||
256 | if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 1, 0, val) != val) { | ||
257 | DSSERR("Failed to set PHY_PWR_STATUS\n"); | ||
258 | return -ETIMEDOUT; | ||
259 | } | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int hdmi_pll_reset(void) | ||
265 | { | ||
266 | /* SYSRESET controlled by power FSM */ | ||
267 | REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 3, 3); | ||
268 | |||
269 | /* READ 0x0 reset is in progress */ | ||
270 | if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) { | ||
271 | DSSERR("Failed to sysreset PLL\n"); | ||
272 | return -ETIMEDOUT; | ||
273 | } | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int hdmi_phy_init(void) | ||
279 | { | ||
280 | u16 r = 0; | ||
281 | |||
282 | r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_LDOON); | ||
283 | if (r) | ||
284 | return r; | ||
285 | |||
286 | r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON); | ||
287 | if (r) | ||
288 | return r; | ||
289 | |||
290 | /* | ||
291 | * Read address 0 in order to get the SCP reset done completed | ||
292 | * Dummy access performed to make sure reset is done | ||
293 | */ | ||
294 | hdmi_read_reg(HDMI_TXPHY_TX_CTRL); | ||
295 | |||
296 | /* | ||
297 | * Write to phy address 0 to configure the clock | ||
298 | * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field | ||
299 | */ | ||
300 | REG_FLD_MOD(HDMI_TXPHY_TX_CTRL, 0x1, 31, 30); | ||
301 | |||
302 | /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ | ||
303 | hdmi_write_reg(HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); | ||
304 | |||
305 | /* Setup max LDO voltage */ | ||
306 | REG_FLD_MOD(HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); | ||
307 | |||
308 | /* Write to phy address 3 to change the polarity control */ | ||
309 | REG_FLD_MOD(HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int hdmi_wait_softreset(void) | ||
315 | { | ||
316 | /* reset W1 */ | ||
317 | REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0); | ||
318 | |||
319 | /* wait till SOFTRESET == 0 */ | ||
320 | if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) { | ||
321 | DSSERR("sysconfig reset failed\n"); | ||
322 | return -ETIMEDOUT; | ||
323 | } | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int hdmi_pll_program(struct hdmi_pll_info *fmt) | ||
329 | { | ||
330 | u16 r = 0; | ||
331 | enum hdmi_clk_refsel refsel; | ||
332 | |||
333 | /* wait for wrapper reset */ | ||
334 | r = hdmi_wait_softreset(); | ||
335 | if (r) | ||
336 | return r; | ||
337 | |||
338 | r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); | ||
339 | if (r) | ||
340 | return r; | ||
341 | |||
342 | r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_BOTHON_ALLCLKS); | ||
343 | if (r) | ||
344 | return r; | ||
345 | |||
346 | r = hdmi_pll_reset(); | ||
347 | if (r) | ||
348 | return r; | ||
349 | |||
350 | refsel = HDMI_REFSEL_SYSCLK; | ||
351 | |||
352 | r = hdmi_pll_init(refsel, fmt->dcofreq, fmt, fmt->regsd); | ||
353 | if (r) | ||
354 | return r; | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static void hdmi_phy_off(void) | ||
360 | { | ||
361 | hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF); | ||
362 | } | ||
363 | |||
364 | static int hdmi_core_ddc_edid(u8 *pedid, int ext) | ||
365 | { | ||
366 | u32 i, j; | ||
367 | char checksum = 0; | ||
368 | u32 offset = 0; | ||
369 | |||
370 | /* Turn on CLK for DDC */ | ||
371 | REG_FLD_MOD(HDMI_CORE_AV_DPD, 0x7, 2, 0); | ||
372 | |||
373 | /* | ||
374 | * SW HACK : Without the Delay DDC(i2c bus) reads 0 values / | ||
375 | * right shifted values( The behavior is not consistent and seen only | ||
376 | * with some TV's) | ||
377 | */ | ||
378 | usleep_range(800, 1000); | ||
379 | |||
380 | if (!ext) { | ||
381 | /* Clk SCL Devices */ | ||
382 | REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0xA, 3, 0); | ||
383 | |||
384 | /* HDMI_CORE_DDC_STATUS_IN_PROG */ | ||
385 | if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS, | ||
386 | 4, 4, 0) != 0) { | ||
387 | DSSERR("Failed to program DDC\n"); | ||
388 | return -ETIMEDOUT; | ||
389 | } | ||
390 | |||
391 | /* Clear FIFO */ | ||
392 | REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x9, 3, 0); | ||
393 | |||
394 | /* HDMI_CORE_DDC_STATUS_IN_PROG */ | ||
395 | if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS, | ||
396 | 4, 4, 0) != 0) { | ||
397 | DSSERR("Failed to program DDC\n"); | ||
398 | return -ETIMEDOUT; | ||
399 | } | ||
400 | |||
401 | } else { | ||
402 | if (ext % 2 != 0) | ||
403 | offset = 0x80; | ||
404 | } | ||
405 | |||
406 | /* Load Segment Address Register */ | ||
407 | REG_FLD_MOD(HDMI_CORE_DDC_SEGM, ext/2, 7, 0); | ||
408 | |||
409 | /* Load Slave Address Register */ | ||
410 | REG_FLD_MOD(HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1); | ||
411 | |||
412 | /* Load Offset Address Register */ | ||
413 | REG_FLD_MOD(HDMI_CORE_DDC_OFFSET, offset, 7, 0); | ||
414 | |||
415 | /* Load Byte Count */ | ||
416 | REG_FLD_MOD(HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); | ||
417 | REG_FLD_MOD(HDMI_CORE_DDC_COUNT2, 0x0, 1, 0); | ||
418 | |||
419 | /* Set DDC_CMD */ | ||
420 | if (ext) | ||
421 | REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x4, 3, 0); | ||
422 | else | ||
423 | REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x2, 3, 0); | ||
424 | |||
425 | /* HDMI_CORE_DDC_STATUS_BUS_LOW */ | ||
426 | if (REG_GET(HDMI_CORE_DDC_STATUS, 6, 6) == 1) { | ||
427 | DSSWARN("I2C Bus Low?\n"); | ||
428 | return -EIO; | ||
429 | } | ||
430 | /* HDMI_CORE_DDC_STATUS_NO_ACK */ | ||
431 | if (REG_GET(HDMI_CORE_DDC_STATUS, 5, 5) == 1) { | ||
432 | DSSWARN("I2C No Ack\n"); | ||
433 | return -EIO; | ||
434 | } | ||
435 | |||
436 | i = ext * 128; | ||
437 | j = 0; | ||
438 | while (((REG_GET(HDMI_CORE_DDC_STATUS, 4, 4) == 1) || | ||
439 | (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0)) && | ||
440 | j < 128) { | ||
441 | |||
442 | if (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0) { | ||
443 | /* FIFO not empty */ | ||
444 | pedid[i++] = REG_GET(HDMI_CORE_DDC_DATA, 7, 0); | ||
445 | j++; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | for (j = 0; j < 128; j++) | ||
450 | checksum += pedid[j]; | ||
451 | |||
452 | if (checksum != 0) { | ||
453 | DSSERR("E-EDID checksum failed!!\n"); | ||
454 | return -EIO; | ||
455 | } | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static int read_edid(u8 *pedid, u16 max_length) | ||
461 | { | ||
462 | int r = 0, n = 0, i = 0; | ||
463 | int max_ext_blocks = (max_length / 128) - 1; | ||
464 | |||
465 | r = hdmi_core_ddc_edid(pedid, 0); | ||
466 | if (r) { | ||
467 | return r; | ||
468 | } else { | ||
469 | n = pedid[0x7e]; | ||
470 | |||
471 | /* | ||
472 | * README: need to comply with max_length set by the caller. | ||
473 | * Better implementation should be to allocate necessary | ||
474 | * memory to store EDID according to nb_block field found | ||
475 | * in first block | ||
476 | */ | ||
477 | if (n > max_ext_blocks) | ||
478 | n = max_ext_blocks; | ||
479 | |||
480 | for (i = 1; i <= n; i++) { | ||
481 | r = hdmi_core_ddc_edid(pedid, i); | ||
482 | if (r) | ||
483 | return r; | ||
484 | } | ||
485 | } | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int get_timings_index(void) | ||
490 | { | ||
491 | int code; | ||
492 | |||
493 | if (hdmi.mode == 0) | ||
494 | code = code_vesa[hdmi.code]; | ||
495 | else | ||
496 | code = code_cea[hdmi.code]; | ||
497 | |||
498 | if (code == -1) { | ||
499 | /* HDMI code 4 corresponds to 640 * 480 VGA */ | ||
500 | hdmi.code = 4; | ||
501 | /* DVI mode 1 corresponds to HDMI 0 to DVI */ | ||
502 | hdmi.mode = HDMI_DVI; | ||
503 | |||
504 | code = code_vesa[hdmi.code]; | ||
505 | } | ||
506 | return code; | ||
507 | } | ||
508 | |||
509 | static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) | ||
510 | { | ||
511 | int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0; | ||
512 | int timing_vsync = 0, timing_hsync = 0; | ||
513 | struct omap_video_timings temp; | ||
514 | struct hdmi_cm cm = {-1}; | ||
515 | DSSDBG("hdmi_get_code\n"); | ||
516 | |||
517 | for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) { | ||
518 | temp = cea_vesa_timings[i].timings; | ||
519 | if ((temp.pixel_clock == timing->pixel_clock) && | ||
520 | (temp.x_res == timing->x_res) && | ||
521 | (temp.y_res == timing->y_res)) { | ||
522 | |||
523 | temp_hsync = temp.hfp + temp.hsw + temp.hbp; | ||
524 | timing_hsync = timing->hfp + timing->hsw + timing->hbp; | ||
525 | temp_vsync = temp.vfp + temp.vsw + temp.vbp; | ||
526 | timing_vsync = timing->vfp + timing->vsw + timing->vbp; | ||
527 | |||
528 | DSSDBG("temp_hsync = %d , temp_vsync = %d" | ||
529 | "timing_hsync = %d, timing_vsync = %d\n", | ||
530 | temp_hsync, temp_hsync, | ||
531 | timing_hsync, timing_vsync); | ||
532 | |||
533 | if ((temp_hsync == timing_hsync) && | ||
534 | (temp_vsync == timing_vsync)) { | ||
535 | code = i; | ||
536 | cm.code = code_index[i]; | ||
537 | if (code < 14) | ||
538 | cm.mode = HDMI_HDMI; | ||
539 | else | ||
540 | cm.mode = HDMI_DVI; | ||
541 | DSSDBG("Hdmi_code = %d mode = %d\n", | ||
542 | cm.code, cm.mode); | ||
543 | break; | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | |||
548 | return cm; | ||
549 | } | ||
550 | |||
551 | static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid , | ||
552 | struct omap_video_timings *timings) | ||
553 | { | ||
554 | /* X and Y resolution */ | ||
555 | timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) | | ||
556 | edid[current_descriptor_addrs + 2]); | ||
557 | timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) | | ||
558 | edid[current_descriptor_addrs + 5]); | ||
559 | |||
560 | timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) | | ||
561 | edid[current_descriptor_addrs]); | ||
562 | |||
563 | timings->pixel_clock = 10 * timings->pixel_clock; | ||
564 | |||
565 | /* HORIZONTAL FRONT PORCH */ | ||
566 | timings->hfp = edid[current_descriptor_addrs + 8] | | ||
567 | ((edid[current_descriptor_addrs + 11] & 0xc0) << 2); | ||
568 | /* HORIZONTAL SYNC WIDTH */ | ||
569 | timings->hsw = edid[current_descriptor_addrs + 9] | | ||
570 | ((edid[current_descriptor_addrs + 11] & 0x30) << 4); | ||
571 | /* HORIZONTAL BACK PORCH */ | ||
572 | timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8) | | ||
573 | edid[current_descriptor_addrs + 3]) - | ||
574 | (timings->hfp + timings->hsw); | ||
575 | /* VERTICAL FRONT PORCH */ | ||
576 | timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4) | | ||
577 | ((edid[current_descriptor_addrs + 11] & 0x0f) << 2); | ||
578 | /* VERTICAL SYNC WIDTH */ | ||
579 | timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F) | | ||
580 | ((edid[current_descriptor_addrs + 11] & 0x03) << 4); | ||
581 | /* VERTICAL BACK PORCH */ | ||
582 | timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8) | | ||
583 | edid[current_descriptor_addrs + 6]) - | ||
584 | (timings->vfp + timings->vsw); | ||
585 | |||
586 | } | ||
587 | |||
588 | /* Description : This function gets the resolution information from EDID */ | ||
589 | static void get_edid_timing_data(u8 *edid) | ||
590 | { | ||
591 | u8 count; | ||
592 | u16 current_descriptor_addrs; | ||
593 | struct hdmi_cm cm; | ||
594 | struct omap_video_timings edid_timings; | ||
595 | |||
596 | /* search block 0, there are 4 DTDs arranged in priority order */ | ||
597 | for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) { | ||
598 | current_descriptor_addrs = | ||
599 | EDID_DESCRIPTOR_BLOCK0_ADDRESS + | ||
600 | count * EDID_TIMING_DESCRIPTOR_SIZE; | ||
601 | get_horz_vert_timing_info(current_descriptor_addrs, | ||
602 | edid, &edid_timings); | ||
603 | cm = hdmi_get_code(&edid_timings); | ||
604 | DSSDBG("Block0[%d] value matches code = %d , mode = %d\n", | ||
605 | count, cm.code, cm.mode); | ||
606 | if (cm.code == -1) { | ||
607 | continue; | ||
608 | } else { | ||
609 | hdmi.code = cm.code; | ||
610 | hdmi.mode = cm.mode; | ||
611 | DSSDBG("code = %d , mode = %d\n", | ||
612 | hdmi.code, hdmi.mode); | ||
613 | return; | ||
614 | } | ||
615 | } | ||
616 | if (edid[0x7e] != 0x00) { | ||
617 | for (count = 0; count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR; | ||
618 | count++) { | ||
619 | current_descriptor_addrs = | ||
620 | EDID_DESCRIPTOR_BLOCK1_ADDRESS + | ||
621 | count * EDID_TIMING_DESCRIPTOR_SIZE; | ||
622 | get_horz_vert_timing_info(current_descriptor_addrs, | ||
623 | edid, &edid_timings); | ||
624 | cm = hdmi_get_code(&edid_timings); | ||
625 | DSSDBG("Block1[%d] value matches code = %d, mode = %d", | ||
626 | count, cm.code, cm.mode); | ||
627 | if (cm.code == -1) { | ||
628 | continue; | ||
629 | } else { | ||
630 | hdmi.code = cm.code; | ||
631 | hdmi.mode = cm.mode; | ||
632 | DSSDBG("code = %d , mode = %d\n", | ||
633 | hdmi.code, hdmi.mode); | ||
634 | return; | ||
635 | } | ||
636 | } | ||
637 | } | ||
638 | |||
639 | DSSINFO("no valid timing found , falling back to VGA\n"); | ||
640 | hdmi.code = 4; /* setting default value of 640 480 VGA */ | ||
641 | hdmi.mode = HDMI_DVI; | ||
642 | } | ||
643 | |||
644 | static void hdmi_read_edid(struct omap_video_timings *dp) | ||
645 | { | ||
646 | int ret = 0, code; | ||
647 | |||
648 | memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH); | ||
649 | |||
650 | if (!hdmi.edid_set) | ||
651 | ret = read_edid(hdmi.edid, HDMI_EDID_MAX_LENGTH); | ||
652 | |||
653 | if (!ret) { | ||
654 | if (!memcmp(hdmi.edid, edid_header, sizeof(edid_header))) { | ||
655 | /* search for timings of default resolution */ | ||
656 | get_edid_timing_data(hdmi.edid); | ||
657 | hdmi.edid_set = true; | ||
658 | } | ||
659 | } else { | ||
660 | DSSWARN("failed to read E-EDID\n"); | ||
661 | } | ||
662 | |||
663 | if (!hdmi.edid_set) { | ||
664 | DSSINFO("fallback to VGA\n"); | ||
665 | hdmi.code = 4; /* setting default value of 640 480 VGA */ | ||
666 | hdmi.mode = HDMI_DVI; | ||
667 | } | ||
668 | |||
669 | code = get_timings_index(); | ||
670 | |||
671 | *dp = cea_vesa_timings[code].timings; | ||
672 | } | ||
673 | |||
674 | static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, | ||
675 | struct hdmi_core_infoframe_avi *avi_cfg, | ||
676 | struct hdmi_core_packet_enable_repeat *repeat_cfg) | ||
677 | { | ||
678 | DSSDBG("Enter hdmi_core_init\n"); | ||
679 | |||
680 | /* video core */ | ||
681 | video_cfg->ip_bus_width = HDMI_INPUT_8BIT; | ||
682 | video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT; | ||
683 | video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE; | ||
684 | video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE; | ||
685 | video_cfg->hdmi_dvi = HDMI_DVI; | ||
686 | video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK; | ||
687 | |||
688 | /* info frame */ | ||
689 | avi_cfg->db1_format = 0; | ||
690 | avi_cfg->db1_active_info = 0; | ||
691 | avi_cfg->db1_bar_info_dv = 0; | ||
692 | avi_cfg->db1_scan_info = 0; | ||
693 | avi_cfg->db2_colorimetry = 0; | ||
694 | avi_cfg->db2_aspect_ratio = 0; | ||
695 | avi_cfg->db2_active_fmt_ar = 0; | ||
696 | avi_cfg->db3_itc = 0; | ||
697 | avi_cfg->db3_ec = 0; | ||
698 | avi_cfg->db3_q_range = 0; | ||
699 | avi_cfg->db3_nup_scaling = 0; | ||
700 | avi_cfg->db4_videocode = 0; | ||
701 | avi_cfg->db5_pixel_repeat = 0; | ||
702 | avi_cfg->db6_7_line_eoftop = 0 ; | ||
703 | avi_cfg->db8_9_line_sofbottom = 0; | ||
704 | avi_cfg->db10_11_pixel_eofleft = 0; | ||
705 | avi_cfg->db12_13_pixel_sofright = 0; | ||
706 | |||
707 | /* packet enable and repeat */ | ||
708 | repeat_cfg->audio_pkt = 0; | ||
709 | repeat_cfg->audio_pkt_repeat = 0; | ||
710 | repeat_cfg->avi_infoframe = 0; | ||
711 | repeat_cfg->avi_infoframe_repeat = 0; | ||
712 | repeat_cfg->gen_cntrl_pkt = 0; | ||
713 | repeat_cfg->gen_cntrl_pkt_repeat = 0; | ||
714 | repeat_cfg->generic_pkt = 0; | ||
715 | repeat_cfg->generic_pkt_repeat = 0; | ||
716 | } | ||
717 | |||
718 | static void hdmi_core_powerdown_disable(void) | ||
719 | { | ||
720 | DSSDBG("Enter hdmi_core_powerdown_disable\n"); | ||
721 | REG_FLD_MOD(HDMI_CORE_CTRL1, 0x0, 0, 0); | ||
722 | } | ||
723 | |||
724 | static void hdmi_core_swreset_release(void) | ||
725 | { | ||
726 | DSSDBG("Enter hdmi_core_swreset_release\n"); | ||
727 | REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x0, 0, 0); | ||
728 | } | ||
729 | |||
730 | static void hdmi_core_swreset_assert(void) | ||
731 | { | ||
732 | DSSDBG("Enter hdmi_core_swreset_assert\n"); | ||
733 | REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x1, 0, 0); | ||
734 | } | ||
735 | |||
736 | /* DSS_HDMI_CORE_VIDEO_CONFIG */ | ||
737 | static void hdmi_core_video_config(struct hdmi_core_video_config *cfg) | ||
738 | { | ||
739 | u32 r = 0; | ||
740 | |||
741 | /* sys_ctrl1 default configuration not tunable */ | ||
742 | r = hdmi_read_reg(HDMI_CORE_CTRL1); | ||
743 | r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5); | ||
744 | r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4); | ||
745 | r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2); | ||
746 | r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1); | ||
747 | hdmi_write_reg(HDMI_CORE_CTRL1, r); | ||
748 | |||
749 | REG_FLD_MOD(HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6); | ||
750 | |||
751 | /* Vid_Mode */ | ||
752 | r = hdmi_read_reg(HDMI_CORE_SYS_VID_MODE); | ||
753 | |||
754 | /* dither truncation configuration */ | ||
755 | if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) { | ||
756 | r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6); | ||
757 | r = FLD_MOD(r, 1, 5, 5); | ||
758 | } else { | ||
759 | r = FLD_MOD(r, cfg->op_dither_truc, 7, 6); | ||
760 | r = FLD_MOD(r, 0, 5, 5); | ||
761 | } | ||
762 | hdmi_write_reg(HDMI_CORE_SYS_VID_MODE, r); | ||
763 | |||
764 | /* HDMI_Ctrl */ | ||
765 | r = hdmi_read_reg(HDMI_CORE_AV_HDMI_CTRL); | ||
766 | r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6); | ||
767 | r = FLD_MOD(r, cfg->pkt_mode, 5, 3); | ||
768 | r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0); | ||
769 | hdmi_write_reg(HDMI_CORE_AV_HDMI_CTRL, r); | ||
770 | |||
771 | /* TMDS_CTRL */ | ||
772 | REG_FLD_MOD(HDMI_CORE_SYS_TMDS_CTRL, | ||
773 | cfg->tclk_sel_clkmult, 6, 5); | ||
774 | } | ||
775 | |||
776 | static void hdmi_core_aux_infoframe_avi_config( | ||
777 | struct hdmi_core_infoframe_avi info_avi) | ||
778 | { | ||
779 | u32 val; | ||
780 | char sum = 0, checksum = 0; | ||
781 | |||
782 | sum += 0x82 + 0x002 + 0x00D; | ||
783 | hdmi_write_reg(HDMI_CORE_AV_AVI_TYPE, 0x082); | ||
784 | hdmi_write_reg(HDMI_CORE_AV_AVI_VERS, 0x002); | ||
785 | hdmi_write_reg(HDMI_CORE_AV_AVI_LEN, 0x00D); | ||
786 | |||
787 | val = (info_avi.db1_format << 5) | | ||
788 | (info_avi.db1_active_info << 4) | | ||
789 | (info_avi.db1_bar_info_dv << 2) | | ||
790 | (info_avi.db1_scan_info); | ||
791 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(0), val); | ||
792 | sum += val; | ||
793 | |||
794 | val = (info_avi.db2_colorimetry << 6) | | ||
795 | (info_avi.db2_aspect_ratio << 4) | | ||
796 | (info_avi.db2_active_fmt_ar); | ||
797 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(1), val); | ||
798 | sum += val; | ||
799 | |||
800 | val = (info_avi.db3_itc << 7) | | ||
801 | (info_avi.db3_ec << 4) | | ||
802 | (info_avi.db3_q_range << 2) | | ||
803 | (info_avi.db3_nup_scaling); | ||
804 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(2), val); | ||
805 | sum += val; | ||
806 | |||
807 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(3), info_avi.db4_videocode); | ||
808 | sum += info_avi.db4_videocode; | ||
809 | |||
810 | val = info_avi.db5_pixel_repeat; | ||
811 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(4), val); | ||
812 | sum += val; | ||
813 | |||
814 | val = info_avi.db6_7_line_eoftop & 0x00FF; | ||
815 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(5), val); | ||
816 | sum += val; | ||
817 | |||
818 | val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF); | ||
819 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(6), val); | ||
820 | sum += val; | ||
821 | |||
822 | val = info_avi.db8_9_line_sofbottom & 0x00FF; | ||
823 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(7), val); | ||
824 | sum += val; | ||
825 | |||
826 | val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF); | ||
827 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(8), val); | ||
828 | sum += val; | ||
829 | |||
830 | val = info_avi.db10_11_pixel_eofleft & 0x00FF; | ||
831 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(9), val); | ||
832 | sum += val; | ||
833 | |||
834 | val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF); | ||
835 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(10), val); | ||
836 | sum += val; | ||
837 | |||
838 | val = info_avi.db12_13_pixel_sofright & 0x00FF; | ||
839 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(11), val); | ||
840 | sum += val; | ||
841 | |||
842 | val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF); | ||
843 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(12), val); | ||
844 | sum += val; | ||
845 | |||
846 | checksum = 0x100 - sum; | ||
847 | hdmi_write_reg(HDMI_CORE_AV_AVI_CHSUM, checksum); | ||
848 | } | ||
849 | |||
850 | static void hdmi_core_av_packet_config( | ||
851 | struct hdmi_core_packet_enable_repeat repeat_cfg) | ||
852 | { | ||
853 | /* enable/repeat the infoframe */ | ||
854 | hdmi_write_reg(HDMI_CORE_AV_PB_CTRL1, | ||
855 | (repeat_cfg.audio_pkt << 5) | | ||
856 | (repeat_cfg.audio_pkt_repeat << 4) | | ||
857 | (repeat_cfg.avi_infoframe << 1) | | ||
858 | (repeat_cfg.avi_infoframe_repeat)); | ||
859 | |||
860 | /* enable/repeat the packet */ | ||
861 | hdmi_write_reg(HDMI_CORE_AV_PB_CTRL2, | ||
862 | (repeat_cfg.gen_cntrl_pkt << 3) | | ||
863 | (repeat_cfg.gen_cntrl_pkt_repeat << 2) | | ||
864 | (repeat_cfg.generic_pkt << 1) | | ||
865 | (repeat_cfg.generic_pkt_repeat)); | ||
866 | } | ||
867 | |||
868 | static void hdmi_wp_init(struct omap_video_timings *timings, | ||
869 | struct hdmi_video_format *video_fmt, | ||
870 | struct hdmi_video_interface *video_int) | ||
871 | { | ||
872 | DSSDBG("Enter hdmi_wp_init\n"); | ||
873 | |||
874 | timings->hbp = 0; | ||
875 | timings->hfp = 0; | ||
876 | timings->hsw = 0; | ||
877 | timings->vbp = 0; | ||
878 | timings->vfp = 0; | ||
879 | timings->vsw = 0; | ||
880 | |||
881 | video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444; | ||
882 | video_fmt->y_res = 0; | ||
883 | video_fmt->x_res = 0; | ||
884 | |||
885 | video_int->vsp = 0; | ||
886 | video_int->hsp = 0; | ||
887 | |||
888 | video_int->interlacing = 0; | ||
889 | video_int->tm = 0; /* HDMI_TIMING_SLAVE */ | ||
890 | |||
891 | } | ||
892 | |||
893 | static void hdmi_wp_video_start(bool start) | ||
894 | { | ||
895 | REG_FLD_MOD(HDMI_WP_VIDEO_CFG, start, 31, 31); | ||
896 | } | ||
897 | |||
898 | static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, | ||
899 | struct omap_video_timings *timings, struct hdmi_config *param) | ||
900 | { | ||
901 | DSSDBG("Enter hdmi_wp_video_init_format\n"); | ||
902 | |||
903 | video_fmt->y_res = param->timings.timings.y_res; | ||
904 | video_fmt->x_res = param->timings.timings.x_res; | ||
905 | |||
906 | timings->hbp = param->timings.timings.hbp; | ||
907 | timings->hfp = param->timings.timings.hfp; | ||
908 | timings->hsw = param->timings.timings.hsw; | ||
909 | timings->vbp = param->timings.timings.vbp; | ||
910 | timings->vfp = param->timings.timings.vfp; | ||
911 | timings->vsw = param->timings.timings.vsw; | ||
912 | } | ||
913 | |||
914 | static void hdmi_wp_video_config_format( | ||
915 | struct hdmi_video_format *video_fmt) | ||
916 | { | ||
917 | u32 l = 0; | ||
918 | |||
919 | REG_FLD_MOD(HDMI_WP_VIDEO_CFG, video_fmt->packing_mode, 10, 8); | ||
920 | |||
921 | l |= FLD_VAL(video_fmt->y_res, 31, 16); | ||
922 | l |= FLD_VAL(video_fmt->x_res, 15, 0); | ||
923 | hdmi_write_reg(HDMI_WP_VIDEO_SIZE, l); | ||
924 | } | ||
925 | |||
926 | static void hdmi_wp_video_config_interface( | ||
927 | struct hdmi_video_interface *video_int) | ||
928 | { | ||
929 | u32 r; | ||
930 | DSSDBG("Enter hdmi_wp_video_config_interface\n"); | ||
931 | |||
932 | r = hdmi_read_reg(HDMI_WP_VIDEO_CFG); | ||
933 | r = FLD_MOD(r, video_int->vsp, 7, 7); | ||
934 | r = FLD_MOD(r, video_int->hsp, 6, 6); | ||
935 | r = FLD_MOD(r, video_int->interlacing, 3, 3); | ||
936 | r = FLD_MOD(r, video_int->tm, 1, 0); | ||
937 | hdmi_write_reg(HDMI_WP_VIDEO_CFG, r); | ||
938 | } | ||
939 | |||
940 | static void hdmi_wp_video_config_timing( | ||
941 | struct omap_video_timings *timings) | ||
942 | { | ||
943 | u32 timing_h = 0; | ||
944 | u32 timing_v = 0; | ||
945 | |||
946 | DSSDBG("Enter hdmi_wp_video_config_timing\n"); | ||
947 | |||
948 | timing_h |= FLD_VAL(timings->hbp, 31, 20); | ||
949 | timing_h |= FLD_VAL(timings->hfp, 19, 8); | ||
950 | timing_h |= FLD_VAL(timings->hsw, 7, 0); | ||
951 | hdmi_write_reg(HDMI_WP_VIDEO_TIMING_H, timing_h); | ||
952 | |||
953 | timing_v |= FLD_VAL(timings->vbp, 31, 20); | ||
954 | timing_v |= FLD_VAL(timings->vfp, 19, 8); | ||
955 | timing_v |= FLD_VAL(timings->vsw, 7, 0); | ||
956 | hdmi_write_reg(HDMI_WP_VIDEO_TIMING_V, timing_v); | ||
957 | } | ||
958 | |||
959 | static void hdmi_basic_configure(struct hdmi_config *cfg) | ||
960 | { | ||
961 | /* HDMI */ | ||
962 | struct omap_video_timings video_timing; | ||
963 | struct hdmi_video_format video_format; | ||
964 | struct hdmi_video_interface video_interface; | ||
965 | /* HDMI core */ | ||
966 | struct hdmi_core_infoframe_avi avi_cfg; | ||
967 | struct hdmi_core_video_config v_core_cfg; | ||
968 | struct hdmi_core_packet_enable_repeat repeat_cfg; | ||
969 | |||
970 | hdmi_wp_init(&video_timing, &video_format, | ||
971 | &video_interface); | ||
972 | |||
973 | hdmi_core_init(&v_core_cfg, | ||
974 | &avi_cfg, | ||
975 | &repeat_cfg); | ||
976 | |||
977 | hdmi_wp_video_init_format(&video_format, | ||
978 | &video_timing, cfg); | ||
979 | |||
980 | hdmi_wp_video_config_timing(&video_timing); | ||
981 | |||
982 | /* video config */ | ||
983 | video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422; | ||
984 | |||
985 | hdmi_wp_video_config_format(&video_format); | ||
986 | |||
987 | video_interface.vsp = cfg->timings.vsync_pol; | ||
988 | video_interface.hsp = cfg->timings.hsync_pol; | ||
989 | video_interface.interlacing = cfg->interlace; | ||
990 | video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */ | ||
991 | |||
992 | hdmi_wp_video_config_interface(&video_interface); | ||
993 | |||
994 | /* | ||
995 | * configure core video part | ||
996 | * set software reset in the core | ||
997 | */ | ||
998 | hdmi_core_swreset_assert(); | ||
999 | |||
1000 | /* power down off */ | ||
1001 | hdmi_core_powerdown_disable(); | ||
1002 | |||
1003 | v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL; | ||
1004 | v_core_cfg.hdmi_dvi = cfg->cm.mode; | ||
1005 | |||
1006 | hdmi_core_video_config(&v_core_cfg); | ||
1007 | |||
1008 | /* release software reset in the core */ | ||
1009 | hdmi_core_swreset_release(); | ||
1010 | |||
1011 | /* | ||
1012 | * configure packet | ||
1013 | * info frame video see doc CEA861-D page 65 | ||
1014 | */ | ||
1015 | avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB; | ||
1016 | avi_cfg.db1_active_info = | ||
1017 | HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF; | ||
1018 | avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO; | ||
1019 | avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0; | ||
1020 | avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO; | ||
1021 | avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO; | ||
1022 | avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME; | ||
1023 | avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO; | ||
1024 | avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601; | ||
1025 | avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT; | ||
1026 | avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO; | ||
1027 | avi_cfg.db4_videocode = cfg->cm.code; | ||
1028 | avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO; | ||
1029 | avi_cfg.db6_7_line_eoftop = 0; | ||
1030 | avi_cfg.db8_9_line_sofbottom = 0; | ||
1031 | avi_cfg.db10_11_pixel_eofleft = 0; | ||
1032 | avi_cfg.db12_13_pixel_sofright = 0; | ||
1033 | |||
1034 | hdmi_core_aux_infoframe_avi_config(avi_cfg); | ||
1035 | |||
1036 | /* enable/repeat the infoframe */ | ||
1037 | repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; | ||
1038 | repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON; | ||
1039 | /* wakeup */ | ||
1040 | repeat_cfg.audio_pkt = HDMI_PACKETENABLE; | ||
1041 | repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON; | ||
1042 | hdmi_core_av_packet_config(repeat_cfg); | ||
1043 | } | ||
1044 | |||
1045 | static void update_hdmi_timings(struct hdmi_config *cfg, | ||
1046 | struct omap_video_timings *timings, int code) | ||
1047 | { | ||
1048 | cfg->timings.timings.x_res = timings->x_res; | ||
1049 | cfg->timings.timings.y_res = timings->y_res; | ||
1050 | cfg->timings.timings.hbp = timings->hbp; | ||
1051 | cfg->timings.timings.hfp = timings->hfp; | ||
1052 | cfg->timings.timings.hsw = timings->hsw; | ||
1053 | cfg->timings.timings.vbp = timings->vbp; | ||
1054 | cfg->timings.timings.vfp = timings->vfp; | ||
1055 | cfg->timings.timings.vsw = timings->vsw; | ||
1056 | cfg->timings.timings.pixel_clock = timings->pixel_clock; | ||
1057 | cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol; | ||
1058 | cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol; | ||
1059 | } | ||
1060 | |||
1061 | static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | ||
1062 | struct hdmi_pll_info *pi) | ||
1063 | { | ||
1064 | unsigned long clkin, refclk; | ||
1065 | u32 mf; | ||
1066 | |||
1067 | clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000; | ||
1068 | /* | ||
1069 | * Input clock is predivided by N + 1 | ||
1070 | * out put of which is reference clk | ||
1071 | */ | ||
1072 | pi->regn = dssdev->clocks.hdmi.regn; | ||
1073 | refclk = clkin / (pi->regn + 1); | ||
1074 | |||
1075 | /* | ||
1076 | * multiplier is pixel_clk/ref_clk | ||
1077 | * Multiplying by 100 to avoid fractional part removal | ||
1078 | */ | ||
1079 | pi->regm = (phy * 100 / (refclk)) / 100; | ||
1080 | pi->regm2 = dssdev->clocks.hdmi.regm2; | ||
1081 | |||
1082 | /* | ||
1083 | * fractional multiplier is remainder of the difference between | ||
1084 | * multiplier and actual phy(required pixel clock thus should be | ||
1085 | * multiplied by 2^18(262144) divided by the reference clock | ||
1086 | */ | ||
1087 | mf = (phy - pi->regm * refclk) * 262144; | ||
1088 | pi->regmf = mf / (refclk); | ||
1089 | |||
1090 | /* | ||
1091 | * Dcofreq should be set to 1 if required pixel clock | ||
1092 | * is greater than 1000MHz | ||
1093 | */ | ||
1094 | pi->dcofreq = phy > 1000 * 100; | ||
1095 | pi->regsd = ((pi->regm * clkin / 10) / ((pi->regn + 1) * 250) + 5) / 10; | ||
1096 | |||
1097 | DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf); | ||
1098 | DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); | ||
1099 | } | ||
1100 | |||
1101 | static void hdmi_enable_clocks(int enable) | ||
1102 | { | ||
1103 | if (enable) | ||
1104 | dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | | ||
1105 | DSS_CLK_SYSCK | DSS_CLK_VIDFCK); | ||
1106 | else | ||
1107 | dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | | ||
1108 | DSS_CLK_SYSCK | DSS_CLK_VIDFCK); | ||
1109 | } | ||
1110 | |||
1111 | static int hdmi_power_on(struct omap_dss_device *dssdev) | ||
1112 | { | ||
1113 | int r, code = 0; | ||
1114 | struct hdmi_pll_info pll_data; | ||
1115 | struct omap_video_timings *p; | ||
1116 | unsigned long phy; | ||
1117 | |||
1118 | hdmi_enable_clocks(1); | ||
1119 | |||
1120 | dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); | ||
1121 | |||
1122 | p = &dssdev->panel.timings; | ||
1123 | |||
1124 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", | ||
1125 | dssdev->panel.timings.x_res, | ||
1126 | dssdev->panel.timings.y_res); | ||
1127 | |||
1128 | if (!hdmi.custom_set) { | ||
1129 | DSSDBG("Read EDID as no EDID is not set on poweron\n"); | ||
1130 | hdmi_read_edid(p); | ||
1131 | } | ||
1132 | code = get_timings_index(); | ||
1133 | dssdev->panel.timings = cea_vesa_timings[code].timings; | ||
1134 | update_hdmi_timings(&hdmi.cfg, p, code); | ||
1135 | |||
1136 | phy = p->pixel_clock; | ||
1137 | |||
1138 | hdmi_compute_pll(dssdev, phy, &pll_data); | ||
1139 | |||
1140 | hdmi_wp_video_start(0); | ||
1141 | |||
1142 | /* config the PLL and PHY first */ | ||
1143 | r = hdmi_pll_program(&pll_data); | ||
1144 | if (r) { | ||
1145 | DSSDBG("Failed to lock PLL\n"); | ||
1146 | goto err; | ||
1147 | } | ||
1148 | |||
1149 | r = hdmi_phy_init(); | ||
1150 | if (r) { | ||
1151 | DSSDBG("Failed to start PHY\n"); | ||
1152 | goto err; | ||
1153 | } | ||
1154 | |||
1155 | hdmi.cfg.cm.mode = hdmi.mode; | ||
1156 | hdmi.cfg.cm.code = hdmi.code; | ||
1157 | hdmi_basic_configure(&hdmi.cfg); | ||
1158 | |||
1159 | /* Make selection of HDMI in DSS */ | ||
1160 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); | ||
1161 | |||
1162 | /* Select the dispc clock source as PRCM clock, to ensure that it is not | ||
1163 | * DSI PLL source as the clock selected by DSI PLL might not be | ||
1164 | * sufficient for the resolution selected / that can be changed | ||
1165 | * dynamically by user. This can be moved to single location , say | ||
1166 | * Boardfile. | ||
1167 | */ | ||
1168 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); | ||
1169 | |||
1170 | /* bypass TV gamma table */ | ||
1171 | dispc_enable_gamma_table(0); | ||
1172 | |||
1173 | /* tv size */ | ||
1174 | dispc_set_digit_size(dssdev->panel.timings.x_res, | ||
1175 | dssdev->panel.timings.y_res); | ||
1176 | |||
1177 | dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 1); | ||
1178 | |||
1179 | hdmi_wp_video_start(1); | ||
1180 | |||
1181 | return 0; | ||
1182 | err: | ||
1183 | hdmi_enable_clocks(0); | ||
1184 | return -EIO; | ||
1185 | } | ||
1186 | |||
1187 | static void hdmi_power_off(struct omap_dss_device *dssdev) | ||
1188 | { | ||
1189 | dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); | ||
1190 | |||
1191 | hdmi_wp_video_start(0); | ||
1192 | hdmi_phy_off(); | ||
1193 | hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); | ||
1194 | hdmi_enable_clocks(0); | ||
1195 | |||
1196 | hdmi.edid_set = 0; | ||
1197 | } | ||
1198 | |||
1199 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | ||
1200 | struct omap_video_timings *timings) | ||
1201 | { | ||
1202 | struct hdmi_cm cm; | ||
1203 | |||
1204 | cm = hdmi_get_code(timings); | ||
1205 | if (cm.code == -1) { | ||
1206 | DSSERR("Invalid timing entered\n"); | ||
1207 | return -EINVAL; | ||
1208 | } | ||
1209 | |||
1210 | return 0; | ||
1211 | |||
1212 | } | ||
1213 | |||
1214 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) | ||
1215 | { | ||
1216 | struct hdmi_cm cm; | ||
1217 | |||
1218 | hdmi.custom_set = 1; | ||
1219 | cm = hdmi_get_code(&dssdev->panel.timings); | ||
1220 | hdmi.code = cm.code; | ||
1221 | hdmi.mode = cm.mode; | ||
1222 | omapdss_hdmi_display_enable(dssdev); | ||
1223 | hdmi.custom_set = 0; | ||
1224 | } | ||
1225 | |||
1226 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) | ||
1227 | { | ||
1228 | int r = 0; | ||
1229 | |||
1230 | DSSDBG("ENTER hdmi_display_enable\n"); | ||
1231 | |||
1232 | mutex_lock(&hdmi.lock); | ||
1233 | |||
1234 | r = omap_dss_start_device(dssdev); | ||
1235 | if (r) { | ||
1236 | DSSERR("failed to start device\n"); | ||
1237 | goto err0; | ||
1238 | } | ||
1239 | |||
1240 | if (dssdev->platform_enable) { | ||
1241 | r = dssdev->platform_enable(dssdev); | ||
1242 | if (r) { | ||
1243 | DSSERR("failed to enable GPIO's\n"); | ||
1244 | goto err1; | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | r = hdmi_power_on(dssdev); | ||
1249 | if (r) { | ||
1250 | DSSERR("failed to power on device\n"); | ||
1251 | goto err2; | ||
1252 | } | ||
1253 | |||
1254 | mutex_unlock(&hdmi.lock); | ||
1255 | return 0; | ||
1256 | |||
1257 | err2: | ||
1258 | if (dssdev->platform_disable) | ||
1259 | dssdev->platform_disable(dssdev); | ||
1260 | err1: | ||
1261 | omap_dss_stop_device(dssdev); | ||
1262 | err0: | ||
1263 | mutex_unlock(&hdmi.lock); | ||
1264 | return r; | ||
1265 | } | ||
1266 | |||
1267 | void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | ||
1268 | { | ||
1269 | DSSDBG("Enter hdmi_display_disable\n"); | ||
1270 | |||
1271 | mutex_lock(&hdmi.lock); | ||
1272 | |||
1273 | hdmi_power_off(dssdev); | ||
1274 | |||
1275 | if (dssdev->platform_disable) | ||
1276 | dssdev->platform_disable(dssdev); | ||
1277 | |||
1278 | omap_dss_stop_device(dssdev); | ||
1279 | |||
1280 | mutex_unlock(&hdmi.lock); | ||
1281 | } | ||
1282 | |||
1283 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
1284 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1285 | static void hdmi_wp_audio_config_format( | ||
1286 | struct hdmi_audio_format *aud_fmt) | ||
1287 | { | ||
1288 | u32 r; | ||
1289 | |||
1290 | DSSDBG("Enter hdmi_wp_audio_config_format\n"); | ||
1291 | |||
1292 | r = hdmi_read_reg(HDMI_WP_AUDIO_CFG); | ||
1293 | r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24); | ||
1294 | r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16); | ||
1295 | r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5); | ||
1296 | r = FLD_MOD(r, aud_fmt->type, 4, 4); | ||
1297 | r = FLD_MOD(r, aud_fmt->justification, 3, 3); | ||
1298 | r = FLD_MOD(r, aud_fmt->sample_order, 2, 2); | ||
1299 | r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1); | ||
1300 | r = FLD_MOD(r, aud_fmt->sample_size, 0, 0); | ||
1301 | hdmi_write_reg(HDMI_WP_AUDIO_CFG, r); | ||
1302 | } | ||
1303 | |||
1304 | static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma) | ||
1305 | { | ||
1306 | u32 r; | ||
1307 | |||
1308 | DSSDBG("Enter hdmi_wp_audio_config_dma\n"); | ||
1309 | |||
1310 | r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2); | ||
1311 | r = FLD_MOD(r, aud_dma->transfer_size, 15, 8); | ||
1312 | r = FLD_MOD(r, aud_dma->block_size, 7, 0); | ||
1313 | hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r); | ||
1314 | |||
1315 | r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL); | ||
1316 | r = FLD_MOD(r, aud_dma->mode, 9, 9); | ||
1317 | r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0); | ||
1318 | hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r); | ||
1319 | } | ||
1320 | |||
1321 | static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg) | ||
1322 | { | ||
1323 | u32 r; | ||
1324 | |||
1325 | /* audio clock recovery parameters */ | ||
1326 | r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL); | ||
1327 | r = FLD_MOD(r, cfg->use_mclk, 2, 2); | ||
1328 | r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1); | ||
1329 | r = FLD_MOD(r, cfg->cts_mode, 0, 0); | ||
1330 | hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r); | ||
1331 | |||
1332 | REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0); | ||
1333 | REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0); | ||
1334 | REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0); | ||
1335 | |||
1336 | if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) { | ||
1337 | REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0); | ||
1338 | REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0); | ||
1339 | REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0); | ||
1340 | } else { | ||
1341 | /* | ||
1342 | * HDMI IP uses this configuration to divide the MCLK to | ||
1343 | * update CTS value. | ||
1344 | */ | ||
1345 | REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0); | ||
1346 | |||
1347 | /* Configure clock for audio packets */ | ||
1348 | REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1, | ||
1349 | cfg->aud_par_busclk, 7, 0); | ||
1350 | REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2, | ||
1351 | (cfg->aud_par_busclk >> 8), 7, 0); | ||
1352 | REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3, | ||
1353 | (cfg->aud_par_busclk >> 16), 7, 0); | ||
1354 | } | ||
1355 | |||
1356 | /* Override of SPDIF sample frequency with value in I2S_CHST4 */ | ||
1357 | REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1); | ||
1358 | |||
1359 | /* I2S parameters */ | ||
1360 | REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0); | ||
1361 | |||
1362 | r = hdmi_read_reg(HDMI_CORE_AV_I2S_IN_CTRL); | ||
1363 | r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7); | ||
1364 | r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); | ||
1365 | r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5); | ||
1366 | r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); | ||
1367 | r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3); | ||
1368 | r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2); | ||
1369 | r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); | ||
1370 | r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); | ||
1371 | hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r); | ||
1372 | |||
1373 | r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5); | ||
1374 | r = FLD_MOD(r, cfg->freq_sample, 7, 4); | ||
1375 | r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1); | ||
1376 | r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0); | ||
1377 | hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r); | ||
1378 | |||
1379 | REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0); | ||
1380 | |||
1381 | /* Audio channels and mode parameters */ | ||
1382 | REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1); | ||
1383 | r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE); | ||
1384 | r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4); | ||
1385 | r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3); | ||
1386 | r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2); | ||
1387 | r = FLD_MOD(r, cfg->en_spdif, 1, 1); | ||
1388 | hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r); | ||
1389 | } | ||
1390 | |||
1391 | static void hdmi_core_audio_infoframe_config( | ||
1392 | struct hdmi_core_infoframe_audio *info_aud) | ||
1393 | { | ||
1394 | u8 val; | ||
1395 | u8 sum = 0, checksum = 0; | ||
1396 | |||
1397 | /* | ||
1398 | * Set audio info frame type, version and length as | ||
1399 | * described in HDMI 1.4a Section 8.2.2 specification. | ||
1400 | * Checksum calculation is defined in Section 5.3.5. | ||
1401 | */ | ||
1402 | hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84); | ||
1403 | hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01); | ||
1404 | hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a); | ||
1405 | sum += 0x84 + 0x001 + 0x00a; | ||
1406 | |||
1407 | val = (info_aud->db1_coding_type << 4) | ||
1408 | | (info_aud->db1_channel_count - 1); | ||
1409 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val); | ||
1410 | sum += val; | ||
1411 | |||
1412 | val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size; | ||
1413 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val); | ||
1414 | sum += val; | ||
1415 | |||
1416 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00); | ||
1417 | |||
1418 | val = info_aud->db4_channel_alloc; | ||
1419 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val); | ||
1420 | sum += val; | ||
1421 | |||
1422 | val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3); | ||
1423 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val); | ||
1424 | sum += val; | ||
1425 | |||
1426 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00); | ||
1427 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00); | ||
1428 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00); | ||
1429 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00); | ||
1430 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00); | ||
1431 | |||
1432 | checksum = 0x100 - sum; | ||
1433 | hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum); | ||
1434 | |||
1435 | /* | ||
1436 | * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing | ||
1437 | * is available. | ||
1438 | */ | ||
1439 | } | ||
1440 | |||
1441 | static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts) | ||
1442 | { | ||
1443 | u32 r; | ||
1444 | u32 deep_color = 0; | ||
1445 | u32 pclk = hdmi.cfg.timings.timings.pixel_clock; | ||
1446 | |||
1447 | if (n == NULL || cts == NULL) | ||
1448 | return -EINVAL; | ||
1449 | /* | ||
1450 | * Obtain current deep color configuration. This needed | ||
1451 | * to calculate the TMDS clock based on the pixel clock. | ||
1452 | */ | ||
1453 | r = REG_GET(HDMI_WP_VIDEO_CFG, 1, 0); | ||
1454 | switch (r) { | ||
1455 | case 1: /* No deep color selected */ | ||
1456 | deep_color = 100; | ||
1457 | break; | ||
1458 | case 2: /* 10-bit deep color selected */ | ||
1459 | deep_color = 125; | ||
1460 | break; | ||
1461 | case 3: /* 12-bit deep color selected */ | ||
1462 | deep_color = 150; | ||
1463 | break; | ||
1464 | default: | ||
1465 | return -EINVAL; | ||
1466 | } | ||
1467 | |||
1468 | switch (sample_freq) { | ||
1469 | case 32000: | ||
1470 | if ((deep_color == 125) && ((pclk == 54054) | ||
1471 | || (pclk == 74250))) | ||
1472 | *n = 8192; | ||
1473 | else | ||
1474 | *n = 4096; | ||
1475 | break; | ||
1476 | case 44100: | ||
1477 | *n = 6272; | ||
1478 | break; | ||
1479 | case 48000: | ||
1480 | if ((deep_color == 125) && ((pclk == 54054) | ||
1481 | || (pclk == 74250))) | ||
1482 | *n = 8192; | ||
1483 | else | ||
1484 | *n = 6144; | ||
1485 | break; | ||
1486 | default: | ||
1487 | *n = 0; | ||
1488 | return -EINVAL; | ||
1489 | } | ||
1490 | |||
1491 | /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ | ||
1492 | *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); | ||
1493 | |||
1494 | return 0; | ||
1495 | } | ||
1496 | |||
1497 | static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, | ||
1498 | struct snd_pcm_hw_params *params, | ||
1499 | struct snd_soc_dai *dai) | ||
1500 | { | ||
1501 | struct hdmi_audio_format audio_format; | ||
1502 | struct hdmi_audio_dma audio_dma; | ||
1503 | struct hdmi_core_audio_config core_cfg; | ||
1504 | struct hdmi_core_infoframe_audio aud_if_cfg; | ||
1505 | int err, n, cts; | ||
1506 | enum hdmi_core_audio_sample_freq sample_freq; | ||
1507 | |||
1508 | switch (params_format(params)) { | ||
1509 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1510 | core_cfg.i2s_cfg.word_max_length = | ||
1511 | HDMI_AUDIO_I2S_MAX_WORD_20BITS; | ||
1512 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS; | ||
1513 | core_cfg.i2s_cfg.in_length_bits = | ||
1514 | HDMI_AUDIO_I2S_INPUT_LENGTH_16; | ||
1515 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1516 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; | ||
1517 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; | ||
1518 | audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1519 | audio_dma.transfer_size = 0x10; | ||
1520 | break; | ||
1521 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1522 | core_cfg.i2s_cfg.word_max_length = | ||
1523 | HDMI_AUDIO_I2S_MAX_WORD_24BITS; | ||
1524 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS; | ||
1525 | core_cfg.i2s_cfg.in_length_bits = | ||
1526 | HDMI_AUDIO_I2S_INPUT_LENGTH_24; | ||
1527 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; | ||
1528 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; | ||
1529 | audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1530 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1531 | audio_dma.transfer_size = 0x20; | ||
1532 | break; | ||
1533 | default: | ||
1534 | return -EINVAL; | ||
1535 | } | ||
1536 | |||
1537 | switch (params_rate(params)) { | ||
1538 | case 32000: | ||
1539 | sample_freq = HDMI_AUDIO_FS_32000; | ||
1540 | break; | ||
1541 | case 44100: | ||
1542 | sample_freq = HDMI_AUDIO_FS_44100; | ||
1543 | break; | ||
1544 | case 48000: | ||
1545 | sample_freq = HDMI_AUDIO_FS_48000; | ||
1546 | break; | ||
1547 | default: | ||
1548 | return -EINVAL; | ||
1549 | } | ||
1550 | |||
1551 | err = hdmi_config_audio_acr(params_rate(params), &n, &cts); | ||
1552 | if (err < 0) | ||
1553 | return err; | ||
1554 | |||
1555 | /* Audio wrapper config */ | ||
1556 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; | ||
1557 | audio_format.active_chnnls_msk = 0x03; | ||
1558 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | ||
1559 | audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; | ||
1560 | /* Disable start/stop signals of IEC 60958 blocks */ | ||
1561 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF; | ||
1562 | |||
1563 | audio_dma.block_size = 0xC0; | ||
1564 | audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; | ||
1565 | audio_dma.fifo_threshold = 0x20; /* in number of samples */ | ||
1566 | |||
1567 | hdmi_wp_audio_config_dma(&audio_dma); | ||
1568 | hdmi_wp_audio_config_format(&audio_format); | ||
1569 | |||
1570 | /* | ||
1571 | * I2S config | ||
1572 | */ | ||
1573 | core_cfg.i2s_cfg.en_high_bitrate_aud = false; | ||
1574 | /* Only used with high bitrate audio */ | ||
1575 | core_cfg.i2s_cfg.cbit_order = false; | ||
1576 | /* Serial data and word select should change on sck rising edge */ | ||
1577 | core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; | ||
1578 | core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; | ||
1579 | /* Set I2S word select polarity */ | ||
1580 | core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT; | ||
1581 | core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; | ||
1582 | /* Set serial data to word select shift. See Phillips spec. */ | ||
1583 | core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; | ||
1584 | /* Enable one of the four available serial data channels */ | ||
1585 | core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN; | ||
1586 | |||
1587 | /* Core audio config */ | ||
1588 | core_cfg.freq_sample = sample_freq; | ||
1589 | core_cfg.n = n; | ||
1590 | core_cfg.cts = cts; | ||
1591 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { | ||
1592 | core_cfg.aud_par_busclk = 0; | ||
1593 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW; | ||
1594 | core_cfg.use_mclk = false; | ||
1595 | } else { | ||
1596 | core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8); | ||
1597 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW; | ||
1598 | core_cfg.use_mclk = true; | ||
1599 | core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; | ||
1600 | } | ||
1601 | core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; | ||
1602 | core_cfg.en_spdif = false; | ||
1603 | /* Use sample frequency from channel status word */ | ||
1604 | core_cfg.fs_override = true; | ||
1605 | /* Enable ACR packets */ | ||
1606 | core_cfg.en_acr_pkt = true; | ||
1607 | /* Disable direct streaming digital audio */ | ||
1608 | core_cfg.en_dsd_audio = false; | ||
1609 | /* Use parallel audio interface */ | ||
1610 | core_cfg.en_parallel_aud_input = true; | ||
1611 | |||
1612 | hdmi_core_audio_config(&core_cfg); | ||
1613 | |||
1614 | /* | ||
1615 | * Configure packet | ||
1616 | * info frame audio see doc CEA861-D page 74 | ||
1617 | */ | ||
1618 | aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM; | ||
1619 | aud_if_cfg.db1_channel_count = 2; | ||
1620 | aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM; | ||
1621 | aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM; | ||
1622 | aud_if_cfg.db4_channel_alloc = 0x00; | ||
1623 | aud_if_cfg.db5_downmix_inh = false; | ||
1624 | aud_if_cfg.db5_lsv = 0; | ||
1625 | |||
1626 | hdmi_core_audio_infoframe_config(&aud_if_cfg); | ||
1627 | return 0; | ||
1628 | } | ||
1629 | |||
1630 | static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, | ||
1631 | struct snd_soc_dai *dai) | ||
1632 | { | ||
1633 | int err = 0; | ||
1634 | switch (cmd) { | ||
1635 | case SNDRV_PCM_TRIGGER_START: | ||
1636 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1637 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1638 | REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0); | ||
1639 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31); | ||
1640 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30); | ||
1641 | break; | ||
1642 | |||
1643 | case SNDRV_PCM_TRIGGER_STOP: | ||
1644 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1645 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1646 | REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0); | ||
1647 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30); | ||
1648 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31); | ||
1649 | break; | ||
1650 | default: | ||
1651 | err = -EINVAL; | ||
1652 | } | ||
1653 | return err; | ||
1654 | } | ||
1655 | |||
1656 | static int hdmi_audio_startup(struct snd_pcm_substream *substream, | ||
1657 | struct snd_soc_dai *dai) | ||
1658 | { | ||
1659 | if (!hdmi.mode) { | ||
1660 | pr_err("Current video settings do not support audio.\n"); | ||
1661 | return -EIO; | ||
1662 | } | ||
1663 | return 0; | ||
1664 | } | ||
1665 | |||
1666 | static struct snd_soc_codec_driver hdmi_audio_codec_drv = { | ||
1667 | }; | ||
1668 | |||
1669 | static struct snd_soc_dai_ops hdmi_audio_codec_ops = { | ||
1670 | .hw_params = hdmi_audio_hw_params, | ||
1671 | .trigger = hdmi_audio_trigger, | ||
1672 | .startup = hdmi_audio_startup, | ||
1673 | }; | ||
1674 | |||
1675 | static struct snd_soc_dai_driver hdmi_codec_dai_drv = { | ||
1676 | .name = "hdmi-audio-codec", | ||
1677 | .playback = { | ||
1678 | .channels_min = 2, | ||
1679 | .channels_max = 2, | ||
1680 | .rates = SNDRV_PCM_RATE_32000 | | ||
1681 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | ||
1682 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
1683 | SNDRV_PCM_FMTBIT_S24_LE, | ||
1684 | }, | ||
1685 | .ops = &hdmi_audio_codec_ops, | ||
1686 | }; | ||
1687 | #endif | ||
1688 | |||
1689 | /* HDMI HW IP initialisation */ | ||
1690 | static int omapdss_hdmihw_probe(struct platform_device *pdev) | ||
1691 | { | ||
1692 | struct resource *hdmi_mem; | ||
1693 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
1694 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1695 | int ret; | ||
1696 | #endif | ||
1697 | |||
1698 | hdmi.pdata = pdev->dev.platform_data; | ||
1699 | hdmi.pdev = pdev; | ||
1700 | |||
1701 | mutex_init(&hdmi.lock); | ||
1702 | |||
1703 | hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); | ||
1704 | if (!hdmi_mem) { | ||
1705 | DSSERR("can't get IORESOURCE_MEM HDMI\n"); | ||
1706 | return -EINVAL; | ||
1707 | } | ||
1708 | |||
1709 | /* Base address taken from platform */ | ||
1710 | hdmi.base_wp = ioremap(hdmi_mem->start, resource_size(hdmi_mem)); | ||
1711 | if (!hdmi.base_wp) { | ||
1712 | DSSERR("can't ioremap WP\n"); | ||
1713 | return -ENOMEM; | ||
1714 | } | ||
1715 | |||
1716 | hdmi_panel_init(); | ||
1717 | |||
1718 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
1719 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1720 | |||
1721 | /* Register ASoC codec DAI */ | ||
1722 | ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, | ||
1723 | &hdmi_codec_dai_drv, 1); | ||
1724 | if (ret) { | ||
1725 | DSSERR("can't register ASoC HDMI audio codec\n"); | ||
1726 | return ret; | ||
1727 | } | ||
1728 | #endif | ||
1729 | return 0; | ||
1730 | } | ||
1731 | |||
1732 | static int omapdss_hdmihw_remove(struct platform_device *pdev) | ||
1733 | { | ||
1734 | hdmi_panel_exit(); | ||
1735 | |||
1736 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
1737 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1738 | snd_soc_unregister_codec(&pdev->dev); | ||
1739 | #endif | ||
1740 | |||
1741 | iounmap(hdmi.base_wp); | ||
1742 | |||
1743 | return 0; | ||
1744 | } | ||
1745 | |||
1746 | static struct platform_driver omapdss_hdmihw_driver = { | ||
1747 | .probe = omapdss_hdmihw_probe, | ||
1748 | .remove = omapdss_hdmihw_remove, | ||
1749 | .driver = { | ||
1750 | .name = "omapdss_hdmi", | ||
1751 | .owner = THIS_MODULE, | ||
1752 | }, | ||
1753 | }; | ||
1754 | |||
1755 | int hdmi_init_platform_driver(void) | ||
1756 | { | ||
1757 | return platform_driver_register(&omapdss_hdmihw_driver); | ||
1758 | } | ||
1759 | |||
1760 | void hdmi_uninit_platform_driver(void) | ||
1761 | { | ||
1762 | return platform_driver_unregister(&omapdss_hdmihw_driver); | ||
1763 | } | ||