blob: 6f727c85885739a56133d12054e806ab42647f99 [file] [log] [blame]
Archit Taneja08d83e4e2013-09-17 11:43:15 +05301
2/*
3 * Logic for the below structure :
4 * user enters the CEA or VESA timings by specifying the HDMI/DVI code.
5 * There is a correspondence between CEA/VESA timing and code, please
6 * refer to section 6.3 in HDMI 1.3 specification for timing code.
7 *
8 * In the below structure, cea_vesa_timings corresponds to all OMAP4
9 * supported CEA and VESA timing values.code_cea corresponds to the CEA
10 * code, It is used to get the timing from cea_vesa_timing array.Similarly
11 * with code_vesa. Code_index is used for back mapping, that is once EDID
12 * is read from the TV, EDID is parsed to find the timing values and then
13 * map it to corresponding CEA or VESA index.
14 */
15
16#include <linux/kernel.h>
17#include <linux/err.h>
18#include <video/omapdss.h>
19
20#include "hdmi.h"
21
22static const struct hdmi_config cea_timings[] = {
23 {
24 { 640, 480, 25200, 96, 16, 48, 2, 10, 33,
25 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
26 false, },
27 { 1, HDMI_HDMI },
28 },
29 {
30 { 720, 480, 27027, 62, 16, 60, 6, 9, 30,
31 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
32 false, },
33 { 2, HDMI_HDMI },
34 },
35 {
36 { 1280, 720, 74250, 40, 110, 220, 5, 5, 20,
37 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
38 false, },
39 { 4, HDMI_HDMI },
40 },
41 {
42 { 1920, 540, 74250, 44, 88, 148, 5, 2, 15,
43 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
44 true, },
45 { 5, HDMI_HDMI },
46 },
47 {
48 { 1440, 240, 27027, 124, 38, 114, 3, 4, 15,
49 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
50 true, },
51 { 6, HDMI_HDMI },
52 },
53 {
54 { 1920, 1080, 148500, 44, 88, 148, 5, 4, 36,
55 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
56 false, },
57 { 16, HDMI_HDMI },
58 },
59 {
60 { 720, 576, 27000, 64, 12, 68, 5, 5, 39,
61 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
62 false, },
63 { 17, HDMI_HDMI },
64 },
65 {
66 { 1280, 720, 74250, 40, 440, 220, 5, 5, 20,
67 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
68 false, },
69 { 19, HDMI_HDMI },
70 },
71 {
72 { 1920, 540, 74250, 44, 528, 148, 5, 2, 15,
73 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
74 true, },
75 { 20, HDMI_HDMI },
76 },
77 {
78 { 1440, 288, 27000, 126, 24, 138, 3, 2, 19,
79 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
80 true, },
81 { 21, HDMI_HDMI },
82 },
83 {
84 { 1440, 576, 54000, 128, 24, 136, 5, 5, 39,
85 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
86 false, },
87 { 29, HDMI_HDMI },
88 },
89 {
90 { 1920, 1080, 148500, 44, 528, 148, 5, 4, 36,
91 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
92 false, },
93 { 31, HDMI_HDMI },
94 },
95 {
96 { 1920, 1080, 74250, 44, 638, 148, 5, 4, 36,
97 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
98 false, },
99 { 32, HDMI_HDMI },
100 },
101 {
102 { 2880, 480, 108108, 248, 64, 240, 6, 9, 30,
103 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
104 false, },
105 { 35, HDMI_HDMI },
106 },
107 {
108 { 2880, 576, 108000, 256, 48, 272, 5, 5, 39,
109 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
110 false, },
111 { 37, HDMI_HDMI },
112 },
113};
114
115static const struct hdmi_config vesa_timings[] = {
116/* VESA From Here */
117 {
118 { 640, 480, 25175, 96, 16, 48, 2, 11, 31,
119 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
120 false, },
121 { 4, HDMI_DVI },
122 },
123 {
124 { 800, 600, 40000, 128, 40, 88, 4, 1, 23,
125 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
126 false, },
127 { 9, HDMI_DVI },
128 },
129 {
130 { 848, 480, 33750, 112, 16, 112, 8, 6, 23,
131 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
132 false, },
133 { 0xE, HDMI_DVI },
134 },
135 {
136 { 1280, 768, 79500, 128, 64, 192, 7, 3, 20,
137 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
138 false, },
139 { 0x17, HDMI_DVI },
140 },
141 {
142 { 1280, 800, 83500, 128, 72, 200, 6, 3, 22,
143 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
144 false, },
145 { 0x1C, HDMI_DVI },
146 },
147 {
148 { 1360, 768, 85500, 112, 64, 256, 6, 3, 18,
149 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
150 false, },
151 { 0x27, HDMI_DVI },
152 },
153 {
154 { 1280, 960, 108000, 112, 96, 312, 3, 1, 36,
155 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
156 false, },
157 { 0x20, HDMI_DVI },
158 },
159 {
160 { 1280, 1024, 108000, 112, 48, 248, 3, 1, 38,
161 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
162 false, },
163 { 0x23, HDMI_DVI },
164 },
165 {
166 { 1024, 768, 65000, 136, 24, 160, 6, 3, 29,
167 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
168 false, },
169 { 0x10, HDMI_DVI },
170 },
171 {
172 { 1400, 1050, 121750, 144, 88, 232, 4, 3, 32,
173 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
174 false, },
175 { 0x2A, HDMI_DVI },
176 },
177 {
178 { 1440, 900, 106500, 152, 80, 232, 6, 3, 25,
179 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
180 false, },
181 { 0x2F, HDMI_DVI },
182 },
183 {
184 { 1680, 1050, 146250, 176 , 104, 280, 6, 3, 30,
185 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
186 false, },
187 { 0x3A, HDMI_DVI },
188 },
189 {
190 { 1366, 768, 85500, 143, 70, 213, 3, 3, 24,
191 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
192 false, },
193 { 0x51, HDMI_DVI },
194 },
195 {
196 { 1920, 1080, 148500, 44, 148, 80, 5, 4, 36,
197 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
198 false, },
199 { 0x52, HDMI_DVI },
200 },
201 {
202 { 1280, 768, 68250, 32, 48, 80, 7, 3, 12,
203 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
204 false, },
205 { 0x16, HDMI_DVI },
206 },
207 {
208 { 1400, 1050, 101000, 32, 48, 80, 4, 3, 23,
209 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
210 false, },
211 { 0x29, HDMI_DVI },
212 },
213 {
214 { 1680, 1050, 119000, 32, 48, 80, 6, 3, 21,
215 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
216 false, },
217 { 0x39, HDMI_DVI },
218 },
219 {
220 { 1280, 800, 79500, 32, 48, 80, 6, 3, 14,
221 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
222 false, },
223 { 0x1B, HDMI_DVI },
224 },
225 {
226 { 1280, 720, 74250, 40, 110, 220, 5, 5, 20,
227 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
228 false, },
229 { 0x55, HDMI_DVI },
230 },
231 {
232 { 1920, 1200, 154000, 32, 48, 80, 6, 3, 26,
233 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
234 false, },
235 { 0x44, HDMI_DVI },
236 },
237};
238
239const struct hdmi_config *hdmi_default_timing(void)
240{
241 return &vesa_timings[0];
242}
243
244static const struct hdmi_config *hdmi_find_timing(int code,
245 const struct hdmi_config *timings_arr, int len)
246{
247 int i;
248
249 for (i = 0; i < len; i++) {
250 if (timings_arr[i].cm.code == code)
251 return &timings_arr[i];
252 }
253
254 return NULL;
255}
256
257const struct hdmi_config *hdmi_get_timings(int mode, int code)
258{
259 const struct hdmi_config *arr;
260 int len;
261
262 if (mode == HDMI_DVI) {
263 arr = vesa_timings;
264 len = ARRAY_SIZE(vesa_timings);
265 } else {
266 arr = cea_timings;
267 len = ARRAY_SIZE(cea_timings);
268 }
269
270 return hdmi_find_timing(code, arr, len);
271}
272
273static bool hdmi_timings_compare(struct omap_video_timings *timing1,
274 const struct omap_video_timings *timing2)
275{
276 int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync;
277
278 if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) ==
279 DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) &&
280 (timing2->x_res == timing1->x_res) &&
281 (timing2->y_res == timing1->y_res)) {
282
283 timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp;
284 timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp;
285 timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
286 timing1_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
287
288 DSSDBG("timing1_hsync = %d timing1_vsync = %d"\
289 "timing2_hsync = %d timing2_vsync = %d\n",
290 timing1_hsync, timing1_vsync,
291 timing2_hsync, timing2_vsync);
292
293 if ((timing1_hsync == timing2_hsync) &&
294 (timing1_vsync == timing2_vsync)) {
295 return true;
296 }
297 }
298 return false;
299}
300
301struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
302{
303 int i;
304 struct hdmi_cm cm = {-1};
305 DSSDBG("hdmi_get_code\n");
306
307 for (i = 0; i < ARRAY_SIZE(cea_timings); i++) {
308 if (hdmi_timings_compare(timing, &cea_timings[i].timings)) {
309 cm = cea_timings[i].cm;
310 goto end;
311 }
312 }
313 for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) {
314 if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) {
315 cm = vesa_timings[i].cm;
316 goto end;
317 }
318 }
319
320end:
321 return cm;
322}
323
324#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
325int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
326{
327 u32 deep_color;
328 bool deep_color_correct = false;
329
330 if (n == NULL || cts == NULL)
331 return -EINVAL;
332
333 /* TODO: When implemented, query deep color mode here. */
334 deep_color = 100;
335
336 /*
337 * When using deep color, the default N value (as in the HDMI
338 * specification) yields to an non-integer CTS. Hence, we
339 * modify it while keeping the restrictions described in
340 * section 7.2.1 of the HDMI 1.4a specification.
341 */
342 switch (sample_freq) {
343 case 32000:
344 case 48000:
345 case 96000:
346 case 192000:
347 if (deep_color == 125)
348 if (pclk == 27027 || pclk == 74250)
349 deep_color_correct = true;
350 if (deep_color == 150)
351 if (pclk == 27027)
352 deep_color_correct = true;
353 break;
354 case 44100:
355 case 88200:
356 case 176400:
357 if (deep_color == 125)
358 if (pclk == 27027)
359 deep_color_correct = true;
360 break;
361 default:
362 return -EINVAL;
363 }
364
365 if (deep_color_correct) {
366 switch (sample_freq) {
367 case 32000:
368 *n = 8192;
369 break;
370 case 44100:
371 *n = 12544;
372 break;
373 case 48000:
374 *n = 8192;
375 break;
376 case 88200:
377 *n = 25088;
378 break;
379 case 96000:
380 *n = 16384;
381 break;
382 case 176400:
383 *n = 50176;
384 break;
385 case 192000:
386 *n = 32768;
387 break;
388 default:
389 return -EINVAL;
390 }
391 } else {
392 switch (sample_freq) {
393 case 32000:
394 *n = 4096;
395 break;
396 case 44100:
397 *n = 6272;
398 break;
399 case 48000:
400 *n = 6144;
401 break;
402 case 88200:
403 *n = 12544;
404 break;
405 case 96000:
406 *n = 12288;
407 break;
408 case 176400:
409 *n = 25088;
410 break;
411 case 192000:
412 *n = 24576;
413 break;
414 default:
415 return -EINVAL;
416 }
417 }
418 /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
419 *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
420
421 return 0;
422}
423#endif