1 | /* |
2 | * Copyright © 2006-2008 Intel Corporation |
3 | * Jesse Barnes <jesse.barnes@intel.com> |
4 | * |
5 | * Permission is hereby granted, free of charge, to any person obtaining a |
6 | * copy of this software and associated documentation files (the "Software"), |
7 | * to deal in the Software without restriction, including without limitation |
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
9 | * and/or sell copies of the Software, and to permit persons to whom the |
10 | * Software is furnished to do so, subject to the following conditions: |
11 | * |
12 | * The above copyright notice and this permission notice (including the next |
13 | * paragraph) shall be included in all copies or substantial portions of the |
14 | * Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
22 | * DEALINGS IN THE SOFTWARE. |
23 | * |
24 | * Authors: |
25 | * Eric Anholt <eric@anholt.net> |
26 | * |
27 | */ |
28 | |
29 | /** @file |
30 | * Integrated TV-out support for the 915GM and 945GM. |
31 | */ |
32 | |
33 | #include <linux/math64.h> |
34 | #include <drm/drmP.h> |
35 | #include <drm/drm_crtc.h> |
36 | #include <drm/drm_edid.h> |
37 | #include "intel_drv.h" |
38 | #include <drm/i915_drm.h> |
39 | #include "i915_drv.h" |
40 | |
41 | enum tv_margin { |
42 | TV_MARGIN_LEFT, TV_MARGIN_TOP, |
43 | TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM |
44 | }; |
45 | |
46 | /** Private structure for the integrated TV support */ |
47 | struct intel_tv { |
48 | struct intel_encoder base; |
49 | |
50 | int type; |
51 | const char *tv_format; |
52 | int margin[4]; |
53 | u32 save_TV_H_CTL_1; |
54 | u32 save_TV_H_CTL_2; |
55 | u32 save_TV_H_CTL_3; |
56 | u32 save_TV_V_CTL_1; |
57 | u32 save_TV_V_CTL_2; |
58 | u32 save_TV_V_CTL_3; |
59 | u32 save_TV_V_CTL_4; |
60 | u32 save_TV_V_CTL_5; |
61 | u32 save_TV_V_CTL_6; |
62 | u32 save_TV_V_CTL_7; |
63 | u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3; |
64 | |
65 | u32 save_TV_CSC_Y; |
66 | u32 save_TV_CSC_Y2; |
67 | u32 save_TV_CSC_U; |
68 | u32 save_TV_CSC_U2; |
69 | u32 save_TV_CSC_V; |
70 | u32 save_TV_CSC_V2; |
71 | u32 save_TV_CLR_KNOBS; |
72 | u32 save_TV_CLR_LEVEL; |
73 | u32 save_TV_WIN_POS; |
74 | u32 save_TV_WIN_SIZE; |
75 | u32 save_TV_FILTER_CTL_1; |
76 | u32 save_TV_FILTER_CTL_2; |
77 | u32 save_TV_FILTER_CTL_3; |
78 | |
79 | u32 save_TV_H_LUMA[60]; |
80 | u32 save_TV_H_CHROMA[60]; |
81 | u32 save_TV_V_LUMA[43]; |
82 | u32 save_TV_V_CHROMA[43]; |
83 | |
84 | u32 save_TV_DAC; |
85 | u32 save_TV_CTL; |
86 | }; |
87 | |
88 | struct video_levels { |
89 | int blank, black, burst; |
90 | }; |
91 | |
92 | struct color_conversion { |
93 | u16 ry, gy, by, ay; |
94 | u16 ru, gu, bu, au; |
95 | u16 rv, gv, bv, av; |
96 | }; |
97 | |
98 | static const u32 filter_table[] = { |
99 | 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, |
100 | 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, |
101 | 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, |
102 | 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, |
103 | 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, |
104 | 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, |
105 | 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, |
106 | 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, |
107 | 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, |
108 | 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, |
109 | 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, |
110 | 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, |
111 | 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, |
112 | 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, |
113 | 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, |
114 | 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, |
115 | 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, |
116 | 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, |
117 | 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, |
118 | 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, |
119 | 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, |
120 | 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, |
121 | 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, |
122 | 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, |
123 | 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, |
124 | 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, |
125 | 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, |
126 | 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, |
127 | 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, |
128 | 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, |
129 | 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0, |
130 | 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, |
131 | 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, |
132 | 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, |
133 | 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, |
134 | 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, |
135 | 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, |
136 | 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, |
137 | 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, |
138 | 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, |
139 | 0x28003100, 0x28002F00, 0x00003100, 0x36403000, |
140 | 0x2D002CC0, 0x30003640, 0x2D0036C0, |
141 | 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, |
142 | 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, |
143 | 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, |
144 | 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, |
145 | 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, |
146 | 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, |
147 | 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, |
148 | 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, |
149 | 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, |
150 | 0x28003100, 0x28002F00, 0x00003100, |
151 | }; |
152 | |
153 | /* |
154 | * Color conversion values have 3 separate fixed point formats: |
155 | * |
156 | * 10 bit fields (ay, au) |
157 | * 1.9 fixed point (b.bbbbbbbbb) |
158 | * 11 bit fields (ry, by, ru, gu, gv) |
159 | * exp.mantissa (ee.mmmmmmmmm) |
160 | * ee = 00 = 10^-1 (0.mmmmmmmmm) |
161 | * ee = 01 = 10^-2 (0.0mmmmmmmmm) |
162 | * ee = 10 = 10^-3 (0.00mmmmmmmmm) |
163 | * ee = 11 = 10^-4 (0.000mmmmmmmmm) |
164 | * 12 bit fields (gy, rv, bu) |
165 | * exp.mantissa (eee.mmmmmmmmm) |
166 | * eee = 000 = 10^-1 (0.mmmmmmmmm) |
167 | * eee = 001 = 10^-2 (0.0mmmmmmmmm) |
168 | * eee = 010 = 10^-3 (0.00mmmmmmmmm) |
169 | * eee = 011 = 10^-4 (0.000mmmmmmmmm) |
170 | * eee = 100 = reserved |
171 | * eee = 101 = reserved |
172 | * eee = 110 = reserved |
173 | * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation) |
174 | * |
175 | * Saturation and contrast are 8 bits, with their own representation: |
176 | * 8 bit field (saturation, contrast) |
177 | * exp.mantissa (ee.mmmmmm) |
178 | * ee = 00 = 10^-1 (0.mmmmmm) |
179 | * ee = 01 = 10^0 (m.mmmmm) |
180 | * ee = 10 = 10^1 (mm.mmmm) |
181 | * ee = 11 = 10^2 (mmm.mmm) |
182 | * |
183 | * Simple conversion function: |
184 | * |
185 | * static u32 |
186 | * float_to_csc_11(float f) |
187 | * { |
188 | * u32 exp; |
189 | * u32 mant; |
190 | * u32 ret; |
191 | * |
192 | * if (f < 0) |
193 | * f = -f; |
194 | * |
195 | * if (f >= 1) { |
196 | * exp = 0x7; |
197 | * mant = 1 << 8; |
198 | * } else { |
199 | * for (exp = 0; exp < 3 && f < 0.5; exp++) |
200 | * f *= 2.0; |
201 | * mant = (f * (1 << 9) + 0.5); |
202 | * if (mant >= (1 << 9)) |
203 | * mant = (1 << 9) - 1; |
204 | * } |
205 | * ret = (exp << 9) | mant; |
206 | * return ret; |
207 | * } |
208 | */ |
209 | |
210 | /* |
211 | * Behold, magic numbers! If we plant them they might grow a big |
212 | * s-video cable to the sky... or something. |
213 | * |
214 | * Pre-converted to appropriate hex value. |
215 | */ |
216 | |
217 | /* |
218 | * PAL & NTSC values for composite & s-video connections |
219 | */ |
220 | static const struct color_conversion ntsc_m_csc_composite = { |
221 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, |
222 | .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200, |
223 | .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200, |
224 | }; |
225 | |
226 | static const struct video_levels ntsc_m_levels_composite = { |
227 | .blank = 225, .black = 267, .burst = 113, |
228 | }; |
229 | |
230 | static const struct color_conversion ntsc_m_csc_svideo = { |
231 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133, |
232 | .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200, |
233 | .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200, |
234 | }; |
235 | |
236 | static const struct video_levels ntsc_m_levels_svideo = { |
237 | .blank = 266, .black = 316, .burst = 133, |
238 | }; |
239 | |
240 | static const struct color_conversion ntsc_j_csc_composite = { |
241 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119, |
242 | .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200, |
243 | .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200, |
244 | }; |
245 | |
246 | static const struct video_levels ntsc_j_levels_composite = { |
247 | .blank = 225, .black = 225, .burst = 113, |
248 | }; |
249 | |
250 | static const struct color_conversion ntsc_j_csc_svideo = { |
251 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c, |
252 | .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200, |
253 | .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200, |
254 | }; |
255 | |
256 | static const struct video_levels ntsc_j_levels_svideo = { |
257 | .blank = 266, .black = 266, .burst = 133, |
258 | }; |
259 | |
260 | static const struct color_conversion pal_csc_composite = { |
261 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113, |
262 | .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200, |
263 | .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200, |
264 | }; |
265 | |
266 | static const struct video_levels pal_levels_composite = { |
267 | .blank = 237, .black = 237, .burst = 118, |
268 | }; |
269 | |
270 | static const struct color_conversion pal_csc_svideo = { |
271 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145, |
272 | .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200, |
273 | .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200, |
274 | }; |
275 | |
276 | static const struct video_levels pal_levels_svideo = { |
277 | .blank = 280, .black = 280, .burst = 139, |
278 | }; |
279 | |
280 | static const struct color_conversion pal_m_csc_composite = { |
281 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, |
282 | .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200, |
283 | .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200, |
284 | }; |
285 | |
286 | static const struct video_levels pal_m_levels_composite = { |
287 | .blank = 225, .black = 267, .burst = 113, |
288 | }; |
289 | |
290 | static const struct color_conversion pal_m_csc_svideo = { |
291 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133, |
292 | .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200, |
293 | .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200, |
294 | }; |
295 | |
296 | static const struct video_levels pal_m_levels_svideo = { |
297 | .blank = 266, .black = 316, .burst = 133, |
298 | }; |
299 | |
300 | static const struct color_conversion pal_n_csc_composite = { |
301 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, |
302 | .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200, |
303 | .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200, |
304 | }; |
305 | |
306 | static const struct video_levels pal_n_levels_composite = { |
307 | .blank = 225, .black = 267, .burst = 118, |
308 | }; |
309 | |
310 | static const struct color_conversion pal_n_csc_svideo = { |
311 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133, |
312 | .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200, |
313 | .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200, |
314 | }; |
315 | |
316 | static const struct video_levels pal_n_levels_svideo = { |
317 | .blank = 266, .black = 316, .burst = 139, |
318 | }; |
319 | |
320 | /* |
321 | * Component connections |
322 | */ |
323 | static const struct color_conversion sdtv_csc_yprpb = { |
324 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145, |
325 | .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200, |
326 | .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200, |
327 | }; |
328 | |
329 | #ifndef __NetBSD__ /* XXX unused? */ |
330 | static const struct color_conversion sdtv_csc_rgb = { |
331 | .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, |
332 | .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, |
333 | .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, |
334 | }; |
335 | #endif |
336 | |
337 | static const struct color_conversion hdtv_csc_yprpb = { |
338 | .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145, |
339 | .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200, |
340 | .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200, |
341 | }; |
342 | |
343 | #ifndef __NetBSD__ /* XXX unused? */ |
344 | static const struct color_conversion hdtv_csc_rgb = { |
345 | .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, |
346 | .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, |
347 | .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, |
348 | }; |
349 | #endif |
350 | |
351 | static const struct video_levels component_levels = { |
352 | .blank = 279, .black = 279, .burst = 0, |
353 | }; |
354 | |
355 | |
356 | struct tv_mode { |
357 | const char *name; |
358 | int clock; |
359 | int refresh; /* in millihertz (for precision) */ |
360 | u32 oversample; |
361 | int hsync_end, hblank_start, hblank_end, htotal; |
362 | bool progressive, trilevel_sync, component_only; |
363 | int vsync_start_f1, vsync_start_f2, vsync_len; |
364 | bool veq_ena; |
365 | int veq_start_f1, veq_start_f2, veq_len; |
366 | int vi_end_f1, vi_end_f2, nbr_end; |
367 | bool burst_ena; |
368 | int hburst_start, hburst_len; |
369 | int vburst_start_f1, vburst_end_f1; |
370 | int vburst_start_f2, vburst_end_f2; |
371 | int vburst_start_f3, vburst_end_f3; |
372 | int vburst_start_f4, vburst_end_f4; |
373 | /* |
374 | * subcarrier programming |
375 | */ |
376 | int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc; |
377 | u32 sc_reset; |
378 | bool pal_burst; |
379 | /* |
380 | * blank/black levels |
381 | */ |
382 | const struct video_levels *composite_levels, *svideo_levels; |
383 | const struct color_conversion *composite_color, *svideo_color; |
384 | const u32 *filter_table; |
385 | int max_srcw; |
386 | }; |
387 | |
388 | |
389 | /* |
390 | * Sub carrier DDA |
391 | * |
392 | * I think this works as follows: |
393 | * |
394 | * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096 |
395 | * |
396 | * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value |
397 | * |
398 | * So, |
399 | * dda1_ideal = subcarrier/pixel * 4096 |
400 | * dda1_inc = floor (dda1_ideal) |
401 | * dda2 = dda1_ideal - dda1_inc |
402 | * |
403 | * then pick a ratio for dda2 that gives the closest approximation. If |
404 | * you can't get close enough, you can play with dda3 as well. This |
405 | * seems likely to happen when dda2 is small as the jumps would be larger |
406 | * |
407 | * To invert this, |
408 | * |
409 | * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size) |
410 | * |
411 | * The constants below were all computed using a 107.520MHz clock |
412 | */ |
413 | |
414 | /** |
415 | * Register programming values for TV modes. |
416 | * |
417 | * These values account for -1s required. |
418 | */ |
419 | |
420 | static const struct tv_mode tv_modes[] = { |
421 | { |
422 | .name = "NTSC-M" , |
423 | .clock = 108000, |
424 | .refresh = 59940, |
425 | .oversample = TV_OVERSAMPLE_8X, |
426 | .component_only = 0, |
427 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ |
428 | |
429 | .hsync_end = 64, .hblank_end = 124, |
430 | .hblank_start = 836, .htotal = 857, |
431 | |
432 | .progressive = false, .trilevel_sync = false, |
433 | |
434 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, |
435 | .vsync_len = 6, |
436 | |
437 | .veq_ena = true, .veq_start_f1 = 0, |
438 | .veq_start_f2 = 1, .veq_len = 18, |
439 | |
440 | .vi_end_f1 = 20, .vi_end_f2 = 21, |
441 | .nbr_end = 240, |
442 | |
443 | .burst_ena = true, |
444 | .hburst_start = 72, .hburst_len = 34, |
445 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, |
446 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, |
447 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, |
448 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, |
449 | |
450 | /* desired 3.5800000 actual 3.5800000 clock 107.52 */ |
451 | .dda1_inc = 135, |
452 | .dda2_inc = 20800, .dda2_size = 27456, |
453 | .dda3_inc = 0, .dda3_size = 0, |
454 | .sc_reset = TV_SC_RESET_EVERY_4, |
455 | .pal_burst = false, |
456 | |
457 | .composite_levels = &ntsc_m_levels_composite, |
458 | .composite_color = &ntsc_m_csc_composite, |
459 | .svideo_levels = &ntsc_m_levels_svideo, |
460 | .svideo_color = &ntsc_m_csc_svideo, |
461 | |
462 | .filter_table = filter_table, |
463 | }, |
464 | { |
465 | .name = "NTSC-443" , |
466 | .clock = 108000, |
467 | .refresh = 59940, |
468 | .oversample = TV_OVERSAMPLE_8X, |
469 | .component_only = 0, |
470 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */ |
471 | .hsync_end = 64, .hblank_end = 124, |
472 | .hblank_start = 836, .htotal = 857, |
473 | |
474 | .progressive = false, .trilevel_sync = false, |
475 | |
476 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, |
477 | .vsync_len = 6, |
478 | |
479 | .veq_ena = true, .veq_start_f1 = 0, |
480 | .veq_start_f2 = 1, .veq_len = 18, |
481 | |
482 | .vi_end_f1 = 20, .vi_end_f2 = 21, |
483 | .nbr_end = 240, |
484 | |
485 | .burst_ena = true, |
486 | .hburst_start = 72, .hburst_len = 34, |
487 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, |
488 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, |
489 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, |
490 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, |
491 | |
492 | /* desired 4.4336180 actual 4.4336180 clock 107.52 */ |
493 | .dda1_inc = 168, |
494 | .dda2_inc = 4093, .dda2_size = 27456, |
495 | .dda3_inc = 310, .dda3_size = 525, |
496 | .sc_reset = TV_SC_RESET_NEVER, |
497 | .pal_burst = false, |
498 | |
499 | .composite_levels = &ntsc_m_levels_composite, |
500 | .composite_color = &ntsc_m_csc_composite, |
501 | .svideo_levels = &ntsc_m_levels_svideo, |
502 | .svideo_color = &ntsc_m_csc_svideo, |
503 | |
504 | .filter_table = filter_table, |
505 | }, |
506 | { |
507 | .name = "NTSC-J" , |
508 | .clock = 108000, |
509 | .refresh = 59940, |
510 | .oversample = TV_OVERSAMPLE_8X, |
511 | .component_only = 0, |
512 | |
513 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ |
514 | .hsync_end = 64, .hblank_end = 124, |
515 | .hblank_start = 836, .htotal = 857, |
516 | |
517 | .progressive = false, .trilevel_sync = false, |
518 | |
519 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, |
520 | .vsync_len = 6, |
521 | |
522 | .veq_ena = true, .veq_start_f1 = 0, |
523 | .veq_start_f2 = 1, .veq_len = 18, |
524 | |
525 | .vi_end_f1 = 20, .vi_end_f2 = 21, |
526 | .nbr_end = 240, |
527 | |
528 | .burst_ena = true, |
529 | .hburst_start = 72, .hburst_len = 34, |
530 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, |
531 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, |
532 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, |
533 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, |
534 | |
535 | /* desired 3.5800000 actual 3.5800000 clock 107.52 */ |
536 | .dda1_inc = 135, |
537 | .dda2_inc = 20800, .dda2_size = 27456, |
538 | .dda3_inc = 0, .dda3_size = 0, |
539 | .sc_reset = TV_SC_RESET_EVERY_4, |
540 | .pal_burst = false, |
541 | |
542 | .composite_levels = &ntsc_j_levels_composite, |
543 | .composite_color = &ntsc_j_csc_composite, |
544 | .svideo_levels = &ntsc_j_levels_svideo, |
545 | .svideo_color = &ntsc_j_csc_svideo, |
546 | |
547 | .filter_table = filter_table, |
548 | }, |
549 | { |
550 | .name = "PAL-M" , |
551 | .clock = 108000, |
552 | .refresh = 59940, |
553 | .oversample = TV_OVERSAMPLE_8X, |
554 | .component_only = 0, |
555 | |
556 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ |
557 | .hsync_end = 64, .hblank_end = 124, |
558 | .hblank_start = 836, .htotal = 857, |
559 | |
560 | .progressive = false, .trilevel_sync = false, |
561 | |
562 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, |
563 | .vsync_len = 6, |
564 | |
565 | .veq_ena = true, .veq_start_f1 = 0, |
566 | .veq_start_f2 = 1, .veq_len = 18, |
567 | |
568 | .vi_end_f1 = 20, .vi_end_f2 = 21, |
569 | .nbr_end = 240, |
570 | |
571 | .burst_ena = true, |
572 | .hburst_start = 72, .hburst_len = 34, |
573 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, |
574 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, |
575 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, |
576 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, |
577 | |
578 | /* desired 3.5800000 actual 3.5800000 clock 107.52 */ |
579 | .dda1_inc = 135, |
580 | .dda2_inc = 16704, .dda2_size = 27456, |
581 | .dda3_inc = 0, .dda3_size = 0, |
582 | .sc_reset = TV_SC_RESET_EVERY_8, |
583 | .pal_burst = true, |
584 | |
585 | .composite_levels = &pal_m_levels_composite, |
586 | .composite_color = &pal_m_csc_composite, |
587 | .svideo_levels = &pal_m_levels_svideo, |
588 | .svideo_color = &pal_m_csc_svideo, |
589 | |
590 | .filter_table = filter_table, |
591 | }, |
592 | { |
593 | /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ |
594 | .name = "PAL-N" , |
595 | .clock = 108000, |
596 | .refresh = 50000, |
597 | .oversample = TV_OVERSAMPLE_8X, |
598 | .component_only = 0, |
599 | |
600 | .hsync_end = 64, .hblank_end = 128, |
601 | .hblank_start = 844, .htotal = 863, |
602 | |
603 | .progressive = false, .trilevel_sync = false, |
604 | |
605 | |
606 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, |
607 | .vsync_len = 6, |
608 | |
609 | .veq_ena = true, .veq_start_f1 = 0, |
610 | .veq_start_f2 = 1, .veq_len = 18, |
611 | |
612 | .vi_end_f1 = 24, .vi_end_f2 = 25, |
613 | .nbr_end = 286, |
614 | |
615 | .burst_ena = true, |
616 | .hburst_start = 73, .hburst_len = 34, |
617 | .vburst_start_f1 = 8, .vburst_end_f1 = 285, |
618 | .vburst_start_f2 = 8, .vburst_end_f2 = 286, |
619 | .vburst_start_f3 = 9, .vburst_end_f3 = 286, |
620 | .vburst_start_f4 = 9, .vburst_end_f4 = 285, |
621 | |
622 | |
623 | /* desired 4.4336180 actual 4.4336180 clock 107.52 */ |
624 | .dda1_inc = 135, |
625 | .dda2_inc = 23578, .dda2_size = 27648, |
626 | .dda3_inc = 134, .dda3_size = 625, |
627 | .sc_reset = TV_SC_RESET_EVERY_8, |
628 | .pal_burst = true, |
629 | |
630 | .composite_levels = &pal_n_levels_composite, |
631 | .composite_color = &pal_n_csc_composite, |
632 | .svideo_levels = &pal_n_levels_svideo, |
633 | .svideo_color = &pal_n_csc_svideo, |
634 | |
635 | .filter_table = filter_table, |
636 | }, |
637 | { |
638 | /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ |
639 | .name = "PAL" , |
640 | .clock = 108000, |
641 | .refresh = 50000, |
642 | .oversample = TV_OVERSAMPLE_8X, |
643 | .component_only = 0, |
644 | |
645 | .hsync_end = 64, .hblank_end = 142, |
646 | .hblank_start = 844, .htotal = 863, |
647 | |
648 | .progressive = false, .trilevel_sync = false, |
649 | |
650 | .vsync_start_f1 = 5, .vsync_start_f2 = 6, |
651 | .vsync_len = 5, |
652 | |
653 | .veq_ena = true, .veq_start_f1 = 0, |
654 | .veq_start_f2 = 1, .veq_len = 15, |
655 | |
656 | .vi_end_f1 = 24, .vi_end_f2 = 25, |
657 | .nbr_end = 286, |
658 | |
659 | .burst_ena = true, |
660 | .hburst_start = 73, .hburst_len = 32, |
661 | .vburst_start_f1 = 8, .vburst_end_f1 = 285, |
662 | .vburst_start_f2 = 8, .vburst_end_f2 = 286, |
663 | .vburst_start_f3 = 9, .vburst_end_f3 = 286, |
664 | .vburst_start_f4 = 9, .vburst_end_f4 = 285, |
665 | |
666 | /* desired 4.4336180 actual 4.4336180 clock 107.52 */ |
667 | .dda1_inc = 168, |
668 | .dda2_inc = 4122, .dda2_size = 27648, |
669 | .dda3_inc = 67, .dda3_size = 625, |
670 | .sc_reset = TV_SC_RESET_EVERY_8, |
671 | .pal_burst = true, |
672 | |
673 | .composite_levels = &pal_levels_composite, |
674 | .composite_color = &pal_csc_composite, |
675 | .svideo_levels = &pal_levels_svideo, |
676 | .svideo_color = &pal_csc_svideo, |
677 | |
678 | .filter_table = filter_table, |
679 | }, |
680 | { |
681 | .name = "480p" , |
682 | .clock = 107520, |
683 | .refresh = 59940, |
684 | .oversample = TV_OVERSAMPLE_4X, |
685 | .component_only = 1, |
686 | |
687 | .hsync_end = 64, .hblank_end = 122, |
688 | .hblank_start = 842, .htotal = 857, |
689 | |
690 | .progressive = true, .trilevel_sync = false, |
691 | |
692 | .vsync_start_f1 = 12, .vsync_start_f2 = 12, |
693 | .vsync_len = 12, |
694 | |
695 | .veq_ena = false, |
696 | |
697 | .vi_end_f1 = 44, .vi_end_f2 = 44, |
698 | .nbr_end = 479, |
699 | |
700 | .burst_ena = false, |
701 | |
702 | .filter_table = filter_table, |
703 | }, |
704 | { |
705 | .name = "576p" , |
706 | .clock = 107520, |
707 | .refresh = 50000, |
708 | .oversample = TV_OVERSAMPLE_4X, |
709 | .component_only = 1, |
710 | |
711 | .hsync_end = 64, .hblank_end = 139, |
712 | .hblank_start = 859, .htotal = 863, |
713 | |
714 | .progressive = true, .trilevel_sync = false, |
715 | |
716 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, |
717 | .vsync_len = 10, |
718 | |
719 | .veq_ena = false, |
720 | |
721 | .vi_end_f1 = 48, .vi_end_f2 = 48, |
722 | .nbr_end = 575, |
723 | |
724 | .burst_ena = false, |
725 | |
726 | .filter_table = filter_table, |
727 | }, |
728 | { |
729 | .name = "720p@60Hz" , |
730 | .clock = 148800, |
731 | .refresh = 60000, |
732 | .oversample = TV_OVERSAMPLE_2X, |
733 | .component_only = 1, |
734 | |
735 | .hsync_end = 80, .hblank_end = 300, |
736 | .hblank_start = 1580, .htotal = 1649, |
737 | |
738 | .progressive = true, .trilevel_sync = true, |
739 | |
740 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, |
741 | .vsync_len = 10, |
742 | |
743 | .veq_ena = false, |
744 | |
745 | .vi_end_f1 = 29, .vi_end_f2 = 29, |
746 | .nbr_end = 719, |
747 | |
748 | .burst_ena = false, |
749 | |
750 | .filter_table = filter_table, |
751 | }, |
752 | { |
753 | .name = "720p@50Hz" , |
754 | .clock = 148800, |
755 | .refresh = 50000, |
756 | .oversample = TV_OVERSAMPLE_2X, |
757 | .component_only = 1, |
758 | |
759 | .hsync_end = 80, .hblank_end = 300, |
760 | .hblank_start = 1580, .htotal = 1979, |
761 | |
762 | .progressive = true, .trilevel_sync = true, |
763 | |
764 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, |
765 | .vsync_len = 10, |
766 | |
767 | .veq_ena = false, |
768 | |
769 | .vi_end_f1 = 29, .vi_end_f2 = 29, |
770 | .nbr_end = 719, |
771 | |
772 | .burst_ena = false, |
773 | |
774 | .filter_table = filter_table, |
775 | .max_srcw = 800 |
776 | }, |
777 | { |
778 | .name = "1080i@50Hz" , |
779 | .clock = 148800, |
780 | .refresh = 50000, |
781 | .oversample = TV_OVERSAMPLE_2X, |
782 | .component_only = 1, |
783 | |
784 | .hsync_end = 88, .hblank_end = 235, |
785 | .hblank_start = 2155, .htotal = 2639, |
786 | |
787 | .progressive = false, .trilevel_sync = true, |
788 | |
789 | .vsync_start_f1 = 4, .vsync_start_f2 = 5, |
790 | .vsync_len = 10, |
791 | |
792 | .veq_ena = true, .veq_start_f1 = 4, |
793 | .veq_start_f2 = 4, .veq_len = 10, |
794 | |
795 | |
796 | .vi_end_f1 = 21, .vi_end_f2 = 22, |
797 | .nbr_end = 539, |
798 | |
799 | .burst_ena = false, |
800 | |
801 | .filter_table = filter_table, |
802 | }, |
803 | { |
804 | .name = "1080i@60Hz" , |
805 | .clock = 148800, |
806 | .refresh = 60000, |
807 | .oversample = TV_OVERSAMPLE_2X, |
808 | .component_only = 1, |
809 | |
810 | .hsync_end = 88, .hblank_end = 235, |
811 | .hblank_start = 2155, .htotal = 2199, |
812 | |
813 | .progressive = false, .trilevel_sync = true, |
814 | |
815 | .vsync_start_f1 = 4, .vsync_start_f2 = 5, |
816 | .vsync_len = 10, |
817 | |
818 | .veq_ena = true, .veq_start_f1 = 4, |
819 | .veq_start_f2 = 4, .veq_len = 10, |
820 | |
821 | |
822 | .vi_end_f1 = 21, .vi_end_f2 = 22, |
823 | .nbr_end = 539, |
824 | |
825 | .burst_ena = false, |
826 | |
827 | .filter_table = filter_table, |
828 | }, |
829 | }; |
830 | |
831 | static struct intel_tv *enc_to_tv(struct intel_encoder *encoder) |
832 | { |
833 | return container_of(encoder, struct intel_tv, base); |
834 | } |
835 | |
836 | static struct intel_tv *intel_attached_tv(struct drm_connector *connector) |
837 | { |
838 | return enc_to_tv(intel_attached_encoder(connector)); |
839 | } |
840 | |
841 | static bool |
842 | intel_tv_get_hw_state(struct intel_encoder *encoder, enum i915_pipe *pipe) |
843 | { |
844 | struct drm_device *dev = encoder->base.dev; |
845 | struct drm_i915_private *dev_priv = dev->dev_private; |
846 | u32 tmp = I915_READ(TV_CTL); |
847 | |
848 | if (!(tmp & TV_ENC_ENABLE)) |
849 | return false; |
850 | |
851 | *pipe = PORT_TO_PIPE(tmp); |
852 | |
853 | return true; |
854 | } |
855 | |
856 | static void |
857 | intel_enable_tv(struct intel_encoder *encoder) |
858 | { |
859 | struct drm_device *dev = encoder->base.dev; |
860 | struct drm_i915_private *dev_priv = dev->dev_private; |
861 | |
862 | I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE); |
863 | } |
864 | |
865 | static void |
866 | intel_disable_tv(struct intel_encoder *encoder) |
867 | { |
868 | struct drm_device *dev = encoder->base.dev; |
869 | struct drm_i915_private *dev_priv = dev->dev_private; |
870 | |
871 | I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE); |
872 | } |
873 | |
874 | static const struct tv_mode * |
875 | intel_tv_mode_lookup(const char *tv_format) |
876 | { |
877 | int i; |
878 | |
879 | for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { |
880 | const struct tv_mode *tv_mode = &tv_modes[i]; |
881 | |
882 | if (!strcmp(tv_format, tv_mode->name)) |
883 | return tv_mode; |
884 | } |
885 | return NULL; |
886 | } |
887 | |
888 | static const struct tv_mode * |
889 | intel_tv_mode_find(struct intel_tv *intel_tv) |
890 | { |
891 | return intel_tv_mode_lookup(intel_tv->tv_format); |
892 | } |
893 | |
894 | static enum drm_mode_status |
895 | intel_tv_mode_valid(struct drm_connector *connector, |
896 | struct drm_display_mode *mode) |
897 | { |
898 | struct intel_tv *intel_tv = intel_attached_tv(connector); |
899 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); |
900 | |
901 | /* Ensure TV refresh is close to desired refresh */ |
902 | if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000) |
903 | < 1000) |
904 | return MODE_OK; |
905 | |
906 | return MODE_CLOCK_RANGE; |
907 | } |
908 | |
909 | |
910 | static void |
911 | intel_tv_get_config(struct intel_encoder *encoder, |
912 | struct intel_crtc_config *pipe_config) |
913 | { |
914 | pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock; |
915 | } |
916 | |
917 | static bool |
918 | intel_tv_compute_config(struct intel_encoder *encoder, |
919 | struct intel_crtc_config *pipe_config) |
920 | { |
921 | struct intel_tv *intel_tv = enc_to_tv(encoder); |
922 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); |
923 | |
924 | if (!tv_mode) |
925 | return false; |
926 | |
927 | pipe_config->adjusted_mode.crtc_clock = tv_mode->clock; |
928 | DRM_DEBUG_KMS("forcing bpc to 8 for TV\n" ); |
929 | pipe_config->pipe_bpp = 8*3; |
930 | |
931 | /* TV has it's own notion of sync and other mode flags, so clear them. */ |
932 | pipe_config->adjusted_mode.flags = 0; |
933 | |
934 | /* |
935 | * FIXME: We don't check whether the input mode is actually what we want |
936 | * or whether userspace is doing something stupid. |
937 | */ |
938 | |
939 | return true; |
940 | } |
941 | |
942 | static void intel_tv_mode_set(struct intel_encoder *encoder) |
943 | { |
944 | struct drm_device *dev = encoder->base.dev; |
945 | struct drm_i915_private *dev_priv = dev->dev_private; |
946 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); |
947 | struct intel_tv *intel_tv = enc_to_tv(encoder); |
948 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); |
949 | u32 tv_ctl; |
950 | u32 hctl1, hctl2, hctl3; |
951 | u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; |
952 | u32 scctl1, scctl2, scctl3; |
953 | int i, j; |
954 | const struct video_levels *video_levels; |
955 | const struct color_conversion *color_conversion; |
956 | bool burst_ena; |
957 | int pipe = intel_crtc->pipe; |
958 | |
959 | if (!tv_mode) |
960 | return; /* can't happen (mode_prepare prevents this) */ |
961 | |
962 | tv_ctl = I915_READ(TV_CTL); |
963 | tv_ctl &= TV_CTL_SAVE; |
964 | |
965 | switch (intel_tv->type) { |
966 | default: |
967 | case DRM_MODE_CONNECTOR_Unknown: |
968 | case DRM_MODE_CONNECTOR_Composite: |
969 | tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; |
970 | video_levels = tv_mode->composite_levels; |
971 | color_conversion = tv_mode->composite_color; |
972 | burst_ena = tv_mode->burst_ena; |
973 | break; |
974 | case DRM_MODE_CONNECTOR_Component: |
975 | tv_ctl |= TV_ENC_OUTPUT_COMPONENT; |
976 | video_levels = &component_levels; |
977 | if (tv_mode->burst_ena) |
978 | color_conversion = &sdtv_csc_yprpb; |
979 | else |
980 | color_conversion = &hdtv_csc_yprpb; |
981 | burst_ena = false; |
982 | break; |
983 | case DRM_MODE_CONNECTOR_SVIDEO: |
984 | tv_ctl |= TV_ENC_OUTPUT_SVIDEO; |
985 | video_levels = tv_mode->svideo_levels; |
986 | color_conversion = tv_mode->svideo_color; |
987 | burst_ena = tv_mode->burst_ena; |
988 | break; |
989 | } |
990 | hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | |
991 | (tv_mode->htotal << TV_HTOTAL_SHIFT); |
992 | |
993 | hctl2 = (tv_mode->hburst_start << 16) | |
994 | (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT); |
995 | |
996 | if (burst_ena) |
997 | hctl2 |= TV_BURST_ENA; |
998 | |
999 | hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) | |
1000 | (tv_mode->hblank_end << TV_HBLANK_END_SHIFT); |
1001 | |
1002 | vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) | |
1003 | (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) | |
1004 | (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT); |
1005 | |
1006 | vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) | |
1007 | (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) | |
1008 | (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT); |
1009 | |
1010 | vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) | |
1011 | (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) | |
1012 | (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT); |
1013 | |
1014 | if (tv_mode->veq_ena) |
1015 | vctl3 |= TV_EQUAL_ENA; |
1016 | |
1017 | vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) | |
1018 | (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT); |
1019 | |
1020 | vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) | |
1021 | (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT); |
1022 | |
1023 | vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) | |
1024 | (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT); |
1025 | |
1026 | vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) | |
1027 | (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT); |
1028 | |
1029 | if (intel_crtc->pipe == 1) |
1030 | tv_ctl |= TV_ENC_PIPEB_SELECT; |
1031 | tv_ctl |= tv_mode->oversample; |
1032 | |
1033 | if (tv_mode->progressive) |
1034 | tv_ctl |= TV_PROGRESSIVE; |
1035 | if (tv_mode->trilevel_sync) |
1036 | tv_ctl |= TV_TRILEVEL_SYNC; |
1037 | if (tv_mode->pal_burst) |
1038 | tv_ctl |= TV_PAL_BURST; |
1039 | |
1040 | scctl1 = 0; |
1041 | if (tv_mode->dda1_inc) |
1042 | scctl1 |= TV_SC_DDA1_EN; |
1043 | if (tv_mode->dda2_inc) |
1044 | scctl1 |= TV_SC_DDA2_EN; |
1045 | if (tv_mode->dda3_inc) |
1046 | scctl1 |= TV_SC_DDA3_EN; |
1047 | scctl1 |= tv_mode->sc_reset; |
1048 | if (video_levels) |
1049 | scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; |
1050 | scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT; |
1051 | |
1052 | scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT | |
1053 | tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT; |
1054 | |
1055 | scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT | |
1056 | tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT; |
1057 | |
1058 | /* Enable two fixes for the chips that need them. */ |
1059 | if (dev->pdev->device < 0x2772) |
1060 | tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX; |
1061 | |
1062 | I915_WRITE(TV_H_CTL_1, hctl1); |
1063 | I915_WRITE(TV_H_CTL_2, hctl2); |
1064 | I915_WRITE(TV_H_CTL_3, hctl3); |
1065 | I915_WRITE(TV_V_CTL_1, vctl1); |
1066 | I915_WRITE(TV_V_CTL_2, vctl2); |
1067 | I915_WRITE(TV_V_CTL_3, vctl3); |
1068 | I915_WRITE(TV_V_CTL_4, vctl4); |
1069 | I915_WRITE(TV_V_CTL_5, vctl5); |
1070 | I915_WRITE(TV_V_CTL_6, vctl6); |
1071 | I915_WRITE(TV_V_CTL_7, vctl7); |
1072 | I915_WRITE(TV_SC_CTL_1, scctl1); |
1073 | I915_WRITE(TV_SC_CTL_2, scctl2); |
1074 | I915_WRITE(TV_SC_CTL_3, scctl3); |
1075 | |
1076 | if (color_conversion) { |
1077 | I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | |
1078 | color_conversion->gy); |
1079 | I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) | |
1080 | color_conversion->ay); |
1081 | I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | |
1082 | color_conversion->gu); |
1083 | I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | |
1084 | color_conversion->au); |
1085 | I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | |
1086 | color_conversion->gv); |
1087 | I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | |
1088 | color_conversion->av); |
1089 | } |
1090 | |
1091 | if (INTEL_INFO(dev)->gen >= 4) |
1092 | I915_WRITE(TV_CLR_KNOBS, 0x00404000); |
1093 | else |
1094 | I915_WRITE(TV_CLR_KNOBS, 0x00606000); |
1095 | |
1096 | if (video_levels) |
1097 | I915_WRITE(TV_CLR_LEVEL, |
1098 | ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | |
1099 | (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); |
1100 | { |
1101 | int pipeconf_reg = PIPECONF(pipe); |
1102 | int dspcntr_reg = DSPCNTR(intel_crtc->plane); |
1103 | int pipeconf = I915_READ(pipeconf_reg); |
1104 | int dspcntr = I915_READ(dspcntr_reg); |
1105 | int xpos = 0x0, ypos = 0x0; |
1106 | unsigned int xsize, ysize; |
1107 | /* Pipe must be off here */ |
1108 | I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); |
1109 | intel_flush_primary_plane(dev_priv, intel_crtc->plane); |
1110 | |
1111 | /* Wait for vblank for the disable to take effect */ |
1112 | if (IS_GEN2(dev)) |
1113 | intel_wait_for_vblank(dev, intel_crtc->pipe); |
1114 | |
1115 | I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE); |
1116 | /* Wait for vblank for the disable to take effect. */ |
1117 | intel_wait_for_pipe_off(dev, intel_crtc->pipe); |
1118 | |
1119 | /* Filter ctl must be set before TV_WIN_SIZE */ |
1120 | I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); |
1121 | xsize = tv_mode->hblank_start - tv_mode->hblank_end; |
1122 | if (tv_mode->progressive) |
1123 | ysize = tv_mode->nbr_end + 1; |
1124 | else |
1125 | ysize = 2*tv_mode->nbr_end + 1; |
1126 | |
1127 | xpos += intel_tv->margin[TV_MARGIN_LEFT]; |
1128 | ypos += intel_tv->margin[TV_MARGIN_TOP]; |
1129 | xsize -= (intel_tv->margin[TV_MARGIN_LEFT] + |
1130 | intel_tv->margin[TV_MARGIN_RIGHT]); |
1131 | ysize -= (intel_tv->margin[TV_MARGIN_TOP] + |
1132 | intel_tv->margin[TV_MARGIN_BOTTOM]); |
1133 | I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); |
1134 | I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); |
1135 | |
1136 | I915_WRITE(pipeconf_reg, pipeconf); |
1137 | I915_WRITE(dspcntr_reg, dspcntr); |
1138 | intel_flush_primary_plane(dev_priv, intel_crtc->plane); |
1139 | } |
1140 | |
1141 | j = 0; |
1142 | for (i = 0; i < 60; i++) |
1143 | I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); |
1144 | for (i = 0; i < 60; i++) |
1145 | I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); |
1146 | for (i = 0; i < 43; i++) |
1147 | I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); |
1148 | for (i = 0; i < 43; i++) |
1149 | I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); |
1150 | I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE); |
1151 | I915_WRITE(TV_CTL, tv_ctl); |
1152 | } |
1153 | |
1154 | static const struct drm_display_mode reported_modes[] = { |
1155 | { |
1156 | .name = "NTSC 480i" , |
1157 | .clock = 107520, |
1158 | .hdisplay = 1280, |
1159 | .hsync_start = 1368, |
1160 | .hsync_end = 1496, |
1161 | .htotal = 1712, |
1162 | |
1163 | .vdisplay = 1024, |
1164 | .vsync_start = 1027, |
1165 | .vsync_end = 1034, |
1166 | .vtotal = 1104, |
1167 | .type = DRM_MODE_TYPE_DRIVER, |
1168 | }, |
1169 | }; |
1170 | |
1171 | /** |
1172 | * Detects TV presence by checking for load. |
1173 | * |
1174 | * Requires that the current pipe's DPLL is active. |
1175 | |
1176 | * \return true if TV is connected. |
1177 | * \return false if TV is disconnected. |
1178 | */ |
1179 | static int |
1180 | intel_tv_detect_type(struct intel_tv *intel_tv, |
1181 | struct drm_connector *connector) |
1182 | { |
1183 | struct drm_encoder *encoder = &intel_tv->base.base; |
1184 | struct drm_crtc *crtc = encoder->crtc; |
1185 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
1186 | struct drm_device *dev = encoder->dev; |
1187 | struct drm_i915_private *dev_priv = dev->dev_private; |
1188 | unsigned long irqflags; |
1189 | u32 tv_ctl, save_tv_ctl; |
1190 | u32 tv_dac, save_tv_dac; |
1191 | int type; |
1192 | |
1193 | /* Disable TV interrupts around load detect or we'll recurse */ |
1194 | if (connector->polled & DRM_CONNECTOR_POLL_HPD) { |
1195 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
1196 | i915_disable_pipestat(dev_priv, 0, |
1197 | PIPE_HOTPLUG_INTERRUPT_STATUS | |
1198 | PIPE_HOTPLUG_TV_INTERRUPT_STATUS); |
1199 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
1200 | } |
1201 | |
1202 | save_tv_dac = tv_dac = I915_READ(TV_DAC); |
1203 | save_tv_ctl = tv_ctl = I915_READ(TV_CTL); |
1204 | |
1205 | /* Poll for TV detection */ |
1206 | tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK); |
1207 | tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; |
1208 | if (intel_crtc->pipe == 1) |
1209 | tv_ctl |= TV_ENC_PIPEB_SELECT; |
1210 | else |
1211 | tv_ctl &= ~TV_ENC_PIPEB_SELECT; |
1212 | |
1213 | tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK); |
1214 | tv_dac |= (TVDAC_STATE_CHG_EN | |
1215 | TVDAC_A_SENSE_CTL | |
1216 | TVDAC_B_SENSE_CTL | |
1217 | TVDAC_C_SENSE_CTL | |
1218 | DAC_CTL_OVERRIDE | |
1219 | DAC_A_0_7_V | |
1220 | DAC_B_0_7_V | |
1221 | DAC_C_0_7_V); |
1222 | |
1223 | |
1224 | /* |
1225 | * The TV sense state should be cleared to zero on cantiga platform. Otherwise |
1226 | * the TV is misdetected. This is hardware requirement. |
1227 | */ |
1228 | if (IS_GM45(dev)) |
1229 | tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL | |
1230 | TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL); |
1231 | |
1232 | I915_WRITE(TV_CTL, tv_ctl); |
1233 | I915_WRITE(TV_DAC, tv_dac); |
1234 | POSTING_READ(TV_DAC); |
1235 | |
1236 | intel_wait_for_vblank(intel_tv->base.base.dev, |
1237 | to_intel_crtc(intel_tv->base.base.crtc)->pipe); |
1238 | |
1239 | type = -1; |
1240 | tv_dac = I915_READ(TV_DAC); |
1241 | DRM_DEBUG_KMS("TV detected: %x, %x\n" , tv_ctl, tv_dac); |
1242 | /* |
1243 | * A B C |
1244 | * 0 1 1 Composite |
1245 | * 1 0 X svideo |
1246 | * 0 0 0 Component |
1247 | */ |
1248 | if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { |
1249 | DRM_DEBUG_KMS("Detected Composite TV connection\n" ); |
1250 | type = DRM_MODE_CONNECTOR_Composite; |
1251 | } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { |
1252 | DRM_DEBUG_KMS("Detected S-Video TV connection\n" ); |
1253 | type = DRM_MODE_CONNECTOR_SVIDEO; |
1254 | } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { |
1255 | DRM_DEBUG_KMS("Detected Component TV connection\n" ); |
1256 | type = DRM_MODE_CONNECTOR_Component; |
1257 | } else { |
1258 | DRM_DEBUG_KMS("Unrecognised TV connection\n" ); |
1259 | type = -1; |
1260 | } |
1261 | |
1262 | I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); |
1263 | I915_WRITE(TV_CTL, save_tv_ctl); |
1264 | POSTING_READ(TV_CTL); |
1265 | |
1266 | /* For unknown reasons the hw barfs if we don't do this vblank wait. */ |
1267 | intel_wait_for_vblank(intel_tv->base.base.dev, |
1268 | to_intel_crtc(intel_tv->base.base.crtc)->pipe); |
1269 | |
1270 | /* Restore interrupt config */ |
1271 | if (connector->polled & DRM_CONNECTOR_POLL_HPD) { |
1272 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
1273 | i915_enable_pipestat(dev_priv, 0, |
1274 | PIPE_HOTPLUG_INTERRUPT_STATUS | |
1275 | PIPE_HOTPLUG_TV_INTERRUPT_STATUS); |
1276 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
1277 | } |
1278 | |
1279 | return type; |
1280 | } |
1281 | |
1282 | /* |
1283 | * Here we set accurate tv format according to connector type |
1284 | * i.e Component TV should not be assigned by NTSC or PAL |
1285 | */ |
1286 | static void intel_tv_find_better_format(struct drm_connector *connector) |
1287 | { |
1288 | struct intel_tv *intel_tv = intel_attached_tv(connector); |
1289 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); |
1290 | int i; |
1291 | |
1292 | if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) == |
1293 | tv_mode->component_only) |
1294 | return; |
1295 | |
1296 | |
1297 | for (i = 0; i < sizeof(tv_modes) / sizeof(*tv_modes); i++) { |
1298 | tv_mode = tv_modes + i; |
1299 | |
1300 | if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) == |
1301 | tv_mode->component_only) |
1302 | break; |
1303 | } |
1304 | |
1305 | intel_tv->tv_format = tv_mode->name; |
1306 | drm_object_property_set_value(&connector->base, |
1307 | connector->dev->mode_config.tv_mode_property, i); |
1308 | } |
1309 | |
1310 | /** |
1311 | * Detect the TV connection. |
1312 | * |
1313 | * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure |
1314 | * we have a pipe programmed in order to probe the TV. |
1315 | */ |
1316 | static enum drm_connector_status |
1317 | intel_tv_detect(struct drm_connector *connector, bool force) |
1318 | { |
1319 | struct drm_display_mode mode; |
1320 | struct intel_tv *intel_tv = intel_attached_tv(connector); |
1321 | int type; |
1322 | |
1323 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n" , |
1324 | connector->base.id, drm_get_connector_name(connector), |
1325 | force); |
1326 | |
1327 | mode = reported_modes[0]; |
1328 | |
1329 | if (force) { |
1330 | struct intel_load_detect_pipe tmp; |
1331 | |
1332 | if (intel_get_load_detect_pipe(connector, &mode, &tmp)) { |
1333 | type = intel_tv_detect_type(intel_tv, connector); |
1334 | intel_release_load_detect_pipe(connector, &tmp); |
1335 | } else |
1336 | return connector_status_unknown; |
1337 | } else |
1338 | return connector->status; |
1339 | |
1340 | if (type < 0) |
1341 | return connector_status_disconnected; |
1342 | |
1343 | intel_tv->type = type; |
1344 | intel_tv_find_better_format(connector); |
1345 | |
1346 | return connector_status_connected; |
1347 | } |
1348 | |
1349 | static const struct input_res { |
1350 | const char *name; |
1351 | int w, h; |
1352 | } input_res_table[] = { |
1353 | {"640x480" , 640, 480}, |
1354 | {"800x600" , 800, 600}, |
1355 | {"1024x768" , 1024, 768}, |
1356 | {"1280x1024" , 1280, 1024}, |
1357 | {"848x480" , 848, 480}, |
1358 | {"1280x720" , 1280, 720}, |
1359 | {"1920x1080" , 1920, 1080}, |
1360 | }; |
1361 | |
1362 | /* |
1363 | * Chose preferred mode according to line number of TV format |
1364 | */ |
1365 | static void |
1366 | intel_tv_chose_preferred_modes(struct drm_connector *connector, |
1367 | struct drm_display_mode *mode_ptr) |
1368 | { |
1369 | struct intel_tv *intel_tv = intel_attached_tv(connector); |
1370 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); |
1371 | |
1372 | if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480) |
1373 | mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; |
1374 | else if (tv_mode->nbr_end > 480) { |
1375 | if (tv_mode->progressive == true && tv_mode->nbr_end < 720) { |
1376 | if (mode_ptr->vdisplay == 720) |
1377 | mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; |
1378 | } else if (mode_ptr->vdisplay == 1080) |
1379 | mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; |
1380 | } |
1381 | } |
1382 | |
1383 | /** |
1384 | * Stub get_modes function. |
1385 | * |
1386 | * This should probably return a set of fixed modes, unless we can figure out |
1387 | * how to probe modes off of TV connections. |
1388 | */ |
1389 | |
1390 | static int |
1391 | intel_tv_get_modes(struct drm_connector *connector) |
1392 | { |
1393 | struct drm_display_mode *mode_ptr; |
1394 | struct intel_tv *intel_tv = intel_attached_tv(connector); |
1395 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); |
1396 | int j, count = 0; |
1397 | u64 tmp; |
1398 | |
1399 | for (j = 0; j < ARRAY_SIZE(input_res_table); |
1400 | j++) { |
1401 | const struct input_res *input = &input_res_table[j]; |
1402 | unsigned int hactive_s = input->w; |
1403 | unsigned int vactive_s = input->h; |
1404 | |
1405 | if (tv_mode->max_srcw && input->w > tv_mode->max_srcw) |
1406 | continue; |
1407 | |
1408 | if (input->w > 1024 && (!tv_mode->progressive |
1409 | && !tv_mode->component_only)) |
1410 | continue; |
1411 | |
1412 | mode_ptr = drm_mode_create(connector->dev); |
1413 | if (!mode_ptr) |
1414 | continue; |
1415 | strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN); |
1416 | |
1417 | mode_ptr->hdisplay = hactive_s; |
1418 | mode_ptr->hsync_start = hactive_s + 1; |
1419 | mode_ptr->hsync_end = hactive_s + 64; |
1420 | if (mode_ptr->hsync_end <= mode_ptr->hsync_start) |
1421 | mode_ptr->hsync_end = mode_ptr->hsync_start + 1; |
1422 | mode_ptr->htotal = hactive_s + 96; |
1423 | |
1424 | mode_ptr->vdisplay = vactive_s; |
1425 | mode_ptr->vsync_start = vactive_s + 1; |
1426 | mode_ptr->vsync_end = vactive_s + 32; |
1427 | if (mode_ptr->vsync_end <= mode_ptr->vsync_start) |
1428 | mode_ptr->vsync_end = mode_ptr->vsync_start + 1; |
1429 | mode_ptr->vtotal = vactive_s + 33; |
1430 | |
1431 | tmp = (u64) tv_mode->refresh * mode_ptr->vtotal; |
1432 | tmp *= mode_ptr->htotal; |
1433 | tmp = div_u64(tmp, 1000000); |
1434 | mode_ptr->clock = (int) tmp; |
1435 | |
1436 | mode_ptr->type = DRM_MODE_TYPE_DRIVER; |
1437 | intel_tv_chose_preferred_modes(connector, mode_ptr); |
1438 | drm_mode_probed_add(connector, mode_ptr); |
1439 | count++; |
1440 | } |
1441 | |
1442 | return count; |
1443 | } |
1444 | |
1445 | static void |
1446 | intel_tv_destroy(struct drm_connector *connector) |
1447 | { |
1448 | drm_connector_cleanup(connector); |
1449 | kfree(connector); |
1450 | } |
1451 | |
1452 | |
1453 | static int |
1454 | intel_tv_set_property(struct drm_connector *connector, struct drm_property *property, |
1455 | uint64_t val) |
1456 | { |
1457 | struct drm_device *dev = connector->dev; |
1458 | struct intel_tv *intel_tv = intel_attached_tv(connector); |
1459 | struct drm_crtc *crtc = intel_tv->base.base.crtc; |
1460 | int ret = 0; |
1461 | bool changed = false; |
1462 | |
1463 | ret = drm_object_property_set_value(&connector->base, property, val); |
1464 | if (ret < 0) |
1465 | goto out; |
1466 | |
1467 | if (property == dev->mode_config.tv_left_margin_property && |
1468 | intel_tv->margin[TV_MARGIN_LEFT] != val) { |
1469 | intel_tv->margin[TV_MARGIN_LEFT] = val; |
1470 | changed = true; |
1471 | } else if (property == dev->mode_config.tv_right_margin_property && |
1472 | intel_tv->margin[TV_MARGIN_RIGHT] != val) { |
1473 | intel_tv->margin[TV_MARGIN_RIGHT] = val; |
1474 | changed = true; |
1475 | } else if (property == dev->mode_config.tv_top_margin_property && |
1476 | intel_tv->margin[TV_MARGIN_TOP] != val) { |
1477 | intel_tv->margin[TV_MARGIN_TOP] = val; |
1478 | changed = true; |
1479 | } else if (property == dev->mode_config.tv_bottom_margin_property && |
1480 | intel_tv->margin[TV_MARGIN_BOTTOM] != val) { |
1481 | intel_tv->margin[TV_MARGIN_BOTTOM] = val; |
1482 | changed = true; |
1483 | } else if (property == dev->mode_config.tv_mode_property) { |
1484 | if (val >= ARRAY_SIZE(tv_modes)) { |
1485 | ret = -EINVAL; |
1486 | goto out; |
1487 | } |
1488 | if (!strcmp(intel_tv->tv_format, tv_modes[val].name)) |
1489 | goto out; |
1490 | |
1491 | intel_tv->tv_format = tv_modes[val].name; |
1492 | changed = true; |
1493 | } else { |
1494 | ret = -EINVAL; |
1495 | goto out; |
1496 | } |
1497 | |
1498 | if (changed && crtc) |
1499 | intel_crtc_restore_mode(crtc); |
1500 | out: |
1501 | return ret; |
1502 | } |
1503 | |
1504 | static const struct drm_connector_funcs intel_tv_connector_funcs = { |
1505 | .dpms = intel_connector_dpms, |
1506 | .detect = intel_tv_detect, |
1507 | .destroy = intel_tv_destroy, |
1508 | .set_property = intel_tv_set_property, |
1509 | .fill_modes = drm_helper_probe_single_connector_modes, |
1510 | }; |
1511 | |
1512 | static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { |
1513 | .mode_valid = intel_tv_mode_valid, |
1514 | .get_modes = intel_tv_get_modes, |
1515 | .best_encoder = intel_best_encoder, |
1516 | }; |
1517 | |
1518 | static const struct drm_encoder_funcs intel_tv_enc_funcs = { |
1519 | .destroy = intel_encoder_destroy, |
1520 | }; |
1521 | |
1522 | /* |
1523 | * Enumerate the child dev array parsed from VBT to check whether |
1524 | * the integrated TV is present. |
1525 | * If it is present, return 1. |
1526 | * If it is not present, return false. |
1527 | * If no child dev is parsed from VBT, it assumes that the TV is present. |
1528 | */ |
1529 | static int tv_is_present_in_vbt(struct drm_device *dev) |
1530 | { |
1531 | struct drm_i915_private *dev_priv = dev->dev_private; |
1532 | union child_device_config *p_child; |
1533 | int i, ret; |
1534 | |
1535 | if (!dev_priv->vbt.child_dev_num) |
1536 | return 1; |
1537 | |
1538 | ret = 0; |
1539 | for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { |
1540 | p_child = dev_priv->vbt.child_dev + i; |
1541 | /* |
1542 | * If the device type is not TV, continue. |
1543 | */ |
1544 | switch (p_child->old.device_type) { |
1545 | case DEVICE_TYPE_INT_TV: |
1546 | case DEVICE_TYPE_TV: |
1547 | case DEVICE_TYPE_TV_SVIDEO_COMPOSITE: |
1548 | break; |
1549 | default: |
1550 | continue; |
1551 | } |
1552 | /* Only when the addin_offset is non-zero, it is regarded |
1553 | * as present. |
1554 | */ |
1555 | if (p_child->old.addin_offset) { |
1556 | ret = 1; |
1557 | break; |
1558 | } |
1559 | } |
1560 | return ret; |
1561 | } |
1562 | |
1563 | void |
1564 | intel_tv_init(struct drm_device *dev) |
1565 | { |
1566 | struct drm_i915_private *dev_priv = dev->dev_private; |
1567 | struct drm_connector *connector; |
1568 | struct intel_tv *intel_tv; |
1569 | struct intel_encoder *intel_encoder; |
1570 | struct intel_connector *intel_connector; |
1571 | u32 tv_dac_on, tv_dac_off, save_tv_dac; |
1572 | const char *tv_format_names[ARRAY_SIZE(tv_modes)]; |
1573 | int i, initial_mode = 0; |
1574 | |
1575 | if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) |
1576 | return; |
1577 | |
1578 | if (!tv_is_present_in_vbt(dev)) { |
1579 | DRM_DEBUG_KMS("Integrated TV is not present.\n" ); |
1580 | return; |
1581 | } |
1582 | /* Even if we have an encoder we may not have a connector */ |
1583 | if (!dev_priv->vbt.int_tv_support) |
1584 | return; |
1585 | |
1586 | /* |
1587 | * Sanity check the TV output by checking to see if the |
1588 | * DAC register holds a value |
1589 | */ |
1590 | save_tv_dac = I915_READ(TV_DAC); |
1591 | |
1592 | I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN); |
1593 | tv_dac_on = I915_READ(TV_DAC); |
1594 | |
1595 | I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); |
1596 | tv_dac_off = I915_READ(TV_DAC); |
1597 | |
1598 | I915_WRITE(TV_DAC, save_tv_dac); |
1599 | |
1600 | /* |
1601 | * If the register does not hold the state change enable |
1602 | * bit, (either as a 0 or a 1), assume it doesn't really |
1603 | * exist |
1604 | */ |
1605 | if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 || |
1606 | (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) |
1607 | return; |
1608 | |
1609 | intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL); |
1610 | if (!intel_tv) { |
1611 | return; |
1612 | } |
1613 | |
1614 | intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL); |
1615 | if (!intel_connector) { |
1616 | kfree(intel_tv); |
1617 | return; |
1618 | } |
1619 | |
1620 | intel_encoder = &intel_tv->base; |
1621 | connector = &intel_connector->base; |
1622 | |
1623 | /* The documentation, for the older chipsets at least, recommend |
1624 | * using a polling method rather than hotplug detection for TVs. |
1625 | * This is because in order to perform the hotplug detection, the PLLs |
1626 | * for the TV must be kept alive increasing power drain and starving |
1627 | * bandwidth from other encoders. Notably for instance, it causes |
1628 | * pipe underruns on Crestline when this encoder is supposedly idle. |
1629 | * |
1630 | * More recent chipsets favour HDMI rather than integrated S-Video. |
1631 | */ |
1632 | intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
1633 | |
1634 | drm_connector_init(dev, connector, &intel_tv_connector_funcs, |
1635 | DRM_MODE_CONNECTOR_SVIDEO); |
1636 | |
1637 | drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs, |
1638 | DRM_MODE_ENCODER_TVDAC); |
1639 | |
1640 | intel_encoder->compute_config = intel_tv_compute_config; |
1641 | intel_encoder->get_config = intel_tv_get_config; |
1642 | intel_encoder->mode_set = intel_tv_mode_set; |
1643 | intel_encoder->enable = intel_enable_tv; |
1644 | intel_encoder->disable = intel_disable_tv; |
1645 | intel_encoder->get_hw_state = intel_tv_get_hw_state; |
1646 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
1647 | intel_connector->unregister = intel_connector_unregister; |
1648 | |
1649 | intel_connector_attach_encoder(intel_connector, intel_encoder); |
1650 | intel_encoder->type = INTEL_OUTPUT_TVOUT; |
1651 | intel_encoder->crtc_mask = (1 << 0) | (1 << 1); |
1652 | intel_encoder->cloneable = 0; |
1653 | intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1)); |
1654 | intel_tv->type = DRM_MODE_CONNECTOR_Unknown; |
1655 | |
1656 | /* BIOS margin values */ |
1657 | intel_tv->margin[TV_MARGIN_LEFT] = 54; |
1658 | intel_tv->margin[TV_MARGIN_TOP] = 36; |
1659 | intel_tv->margin[TV_MARGIN_RIGHT] = 46; |
1660 | intel_tv->margin[TV_MARGIN_BOTTOM] = 37; |
1661 | |
1662 | intel_tv->tv_format = tv_modes[initial_mode].name; |
1663 | |
1664 | drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); |
1665 | connector->interlace_allowed = false; |
1666 | connector->doublescan_allowed = false; |
1667 | |
1668 | /* Create TV properties then attach current values */ |
1669 | for (i = 0; i < ARRAY_SIZE(tv_modes); i++) |
1670 | tv_format_names[i] = (const char *)tv_modes[i].name; |
1671 | drm_mode_create_tv_properties(dev, |
1672 | ARRAY_SIZE(tv_modes), |
1673 | tv_format_names); |
1674 | |
1675 | drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property, |
1676 | initial_mode); |
1677 | drm_object_attach_property(&connector->base, |
1678 | dev->mode_config.tv_left_margin_property, |
1679 | intel_tv->margin[TV_MARGIN_LEFT]); |
1680 | drm_object_attach_property(&connector->base, |
1681 | dev->mode_config.tv_top_margin_property, |
1682 | intel_tv->margin[TV_MARGIN_TOP]); |
1683 | drm_object_attach_property(&connector->base, |
1684 | dev->mode_config.tv_right_margin_property, |
1685 | intel_tv->margin[TV_MARGIN_RIGHT]); |
1686 | drm_object_attach_property(&connector->base, |
1687 | dev->mode_config.tv_bottom_margin_property, |
1688 | intel_tv->margin[TV_MARGIN_BOTTOM]); |
1689 | drm_sysfs_connector_add(connector); |
1690 | } |
1691 | |