Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nv17_tv_modes.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009 Francisco Jerez.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26 
27 #include <drm/drmP.h>
28 #include <drm/drm_crtc_helper.h>
29 #include "nouveau_drm.h"
30 #include "nouveau_encoder.h"
31 #include "nouveau_crtc.h"
32 #include "nouveau_hw.h"
33 #include "nv17_tv.h"
34 
36  [TV_NORM_PAL] = "PAL",
37  [TV_NORM_PAL_M] = "PAL-M",
38  [TV_NORM_PAL_N] = "PAL-N",
39  [TV_NORM_PAL_NC] = "PAL-Nc",
40  [TV_NORM_NTSC_M] = "NTSC-M",
41  [TV_NORM_NTSC_J] = "NTSC-J",
42  [TV_NORM_HD480I] = "hd480i",
43  [TV_NORM_HD480P] = "hd480p",
44  [TV_NORM_HD576I] = "hd576i",
45  [TV_NORM_HD576P] = "hd576p",
46  [TV_NORM_HD720P] = "hd720p",
47  [TV_NORM_HD1080I] = "hd1080i"
48 };
49 
50 /* TV standard specific parameters */
51 
53  [TV_NORM_PAL] = { TV_ENC_MODE, {
54  .tv_enc_mode = { 720, 576, 50000, {
55  0x2a, 0x9, 0x8a, 0xcb, 0x0, 0x0, 0xb, 0x18,
56  0x7e, 0x40, 0x8a, 0x35, 0x27, 0x0, 0x34, 0x3,
57  0x3e, 0x3, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
58  0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x3,
59  0xd3, 0x4, 0xd4, 0x1, 0x2, 0x0, 0xa, 0x5,
60  0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
61  0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
62  0xbd, 0x15, 0x5, 0x15, 0x3e, 0x3, 0x0, 0x0
63  } } } },
64 
65  [TV_NORM_PAL_M] = { TV_ENC_MODE, {
66  .tv_enc_mode = { 720, 480, 59940, {
67  0x21, 0xe6, 0xef, 0xe3, 0x0, 0x0, 0xb, 0x18,
68  0x7e, 0x44, 0x76, 0x32, 0x25, 0x0, 0x3c, 0x0,
69  0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
70  0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
71  0xc5, 0x4, 0xc5, 0x1, 0x2, 0x0, 0xa, 0x5,
72  0x0, 0x18, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
73  0x0, 0xb4, 0x0, 0x15, 0x40, 0x10, 0x0, 0x9c,
74  0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
75  } } } },
76 
77  [TV_NORM_PAL_N] = { TV_ENC_MODE, {
78  .tv_enc_mode = { 720, 576, 50000, {
79  0x2a, 0x9, 0x8a, 0xcb, 0x0, 0x0, 0xb, 0x18,
80  0x7e, 0x40, 0x8a, 0x32, 0x25, 0x0, 0x3c, 0x0,
81  0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
82  0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
83  0xc5, 0x4, 0xc5, 0x1, 0x2, 0x0, 0xa, 0x5,
84  0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
85  0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
86  0xbd, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
87  } } } },
88 
90  .tv_enc_mode = { 720, 576, 50000, {
91  0x21, 0xf6, 0x94, 0x46, 0x0, 0x0, 0xb, 0x18,
92  0x7e, 0x44, 0x8a, 0x35, 0x27, 0x0, 0x34, 0x3,
93  0x3e, 0x3, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
94  0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x3,
95  0xd3, 0x4, 0xd4, 0x1, 0x2, 0x0, 0xa, 0x5,
96  0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
97  0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
98  0xbd, 0x15, 0x5, 0x15, 0x3e, 0x3, 0x0, 0x0
99  } } } },
100 
101  [TV_NORM_NTSC_M] = { TV_ENC_MODE, {
102  .tv_enc_mode = { 720, 480, 59940, {
103  0x21, 0xf0, 0x7c, 0x1f, 0x0, 0x0, 0xb, 0x18,
104  0x7e, 0x44, 0x76, 0x48, 0x0, 0x0, 0x3c, 0x0,
105  0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
106  0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
107  0xc5, 0x4, 0xc5, 0x1, 0x2, 0x0, 0xa, 0x5,
108  0x0, 0x16, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
109  0x0, 0xb4, 0x0, 0x15, 0x4, 0x10, 0x0, 0x9c,
110  0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
111  } } } },
112 
113  [TV_NORM_NTSC_J] = { TV_ENC_MODE, {
114  .tv_enc_mode = { 720, 480, 59940, {
115  0x21, 0xf0, 0x7c, 0x1f, 0x0, 0x0, 0xb, 0x18,
116  0x7e, 0x44, 0x76, 0x48, 0x0, 0x0, 0x32, 0x0,
117  0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
118  0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
119  0xcf, 0x4, 0xcf, 0x1, 0x2, 0x0, 0xa, 0x5,
120  0x0, 0x16, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
121  0x0, 0xb4, 0x0, 0x15, 0x4, 0x10, 0x0, 0xa4,
122  0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
123  } } } },
124 
125  [TV_NORM_HD480I] = { TV_ENC_MODE, {
126  .tv_enc_mode = { 720, 480, 59940, {
127  0x21, 0xf0, 0x7c, 0x1f, 0x0, 0x0, 0xb, 0x18,
128  0x7e, 0x44, 0x76, 0x48, 0x0, 0x0, 0x32, 0x0,
129  0x3c, 0x0, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x83,
130  0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x1,
131  0xcf, 0x4, 0xcf, 0x1, 0x2, 0x0, 0xa, 0x5,
132  0x0, 0x16, 0xff, 0x3, 0x20, 0xf, 0x78, 0x0,
133  0x0, 0xb4, 0x0, 0x15, 0x4, 0x10, 0x0, 0xa4,
134  0xc8, 0x15, 0x5, 0x15, 0x3c, 0x0, 0x0, 0x0
135  } } } },
136 
137  [TV_NORM_HD576I] = { TV_ENC_MODE, {
138  .tv_enc_mode = { 720, 576, 50000, {
139  0x2a, 0x9, 0x8a, 0xcb, 0x0, 0x0, 0xb, 0x18,
140  0x7e, 0x40, 0x8a, 0x35, 0x27, 0x0, 0x34, 0x3,
141  0x3e, 0x3, 0x17, 0x21, 0x1b, 0x1b, 0x24, 0x9c,
142  0x1, 0x0, 0xf, 0xf, 0x60, 0x5, 0xd3, 0x3,
143  0xd3, 0x4, 0xd4, 0x1, 0x2, 0x0, 0xa, 0x5,
144  0x0, 0x1a, 0xff, 0x3, 0x18, 0xf, 0x78, 0x0,
145  0x0, 0xb4, 0x0, 0x15, 0x49, 0x10, 0x0, 0x9b,
146  0xbd, 0x15, 0x5, 0x15, 0x3e, 0x3, 0x0, 0x0
147  } } } },
148 
149 
151  .ctv_enc_mode = {
152  .mode = { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000,
153  720, 735, 743, 858, 0, 480, 490, 494, 525, 0,
155  .ctv_regs = { 0x3540000, 0x0, 0x0, 0x314,
156  0x354003a, 0x40000, 0x6f0344, 0x18100000,
157  0x10160004, 0x10060005, 0x1006000c, 0x10060020,
158  0x10060021, 0x140e0022, 0x10060202, 0x1802020a,
159  0x1810020b, 0x10000fff, 0x10000fff, 0x10000fff,
160  0x10000fff, 0x10000fff, 0x10000fff, 0x70,
161  0x3ff0000, 0x57, 0x2e001e, 0x258012c,
162  0xa0aa04ec, 0x30, 0x80960019, 0x12c0300,
163  0x2019, 0x600, 0x32060019, 0x0, 0x0, 0x400
164  } } } },
165 
167  .ctv_enc_mode = {
168  .mode = { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000,
169  720, 730, 738, 864, 0, 576, 581, 585, 625, 0,
171  .ctv_regs = { 0x3540000, 0x0, 0x0, 0x314,
172  0x354003a, 0x40000, 0x6f0344, 0x18100000,
173  0x10060001, 0x10060009, 0x10060026, 0x10060027,
174  0x140e0028, 0x10060268, 0x1810026d, 0x10000fff,
175  0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff,
176  0x10000fff, 0x10000fff, 0x10000fff, 0x69,
177  0x3ff0000, 0x57, 0x2e001e, 0x258012c,
178  0xa0aa04ec, 0x30, 0x80960019, 0x12c0300,
179  0x2019, 0x600, 0x32060019, 0x0, 0x0, 0x400
180  } } } },
181 
183  .ctv_enc_mode = {
184  .mode = { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250,
185  1280, 1349, 1357, 1650, 0, 720, 725, 730, 750, 0,
187  .ctv_regs = { 0x1260394, 0x0, 0x0, 0x622,
188  0x66b0021, 0x6004a, 0x1210626, 0x8170000,
189  0x70004, 0x70016, 0x70017, 0x40f0018,
190  0x702e8, 0x81702ed, 0xfff, 0xfff,
191  0xfff, 0xfff, 0xfff, 0xfff,
192  0xfff, 0xfff, 0xfff, 0x0,
193  0x2e40001, 0x58, 0x2e001e, 0x258012c,
194  0xa0aa04ec, 0x30, 0x810c0039, 0x12c0300,
195  0xc0002039, 0x600, 0x32060039, 0x0, 0x0, 0x0
196  } } } },
197 
199  .ctv_enc_mode = {
200  .mode = { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250,
201  1920, 1961, 2049, 2200, 0, 1080, 1084, 1088, 1125, 0,
204  .ctv_regs = { 0xac0420, 0x44c0478, 0x4a4, 0x4fc0868,
205  0x8940028, 0x60054, 0xe80870, 0xbf70000,
206  0xbc70004, 0x70005, 0x70012, 0x70013,
207  0x40f0014, 0x70230, 0xbf70232, 0xbf70233,
208  0x1c70237, 0x70238, 0x70244, 0x70245,
209  0x40f0246, 0x70462, 0x1f70464, 0x0,
210  0x2e40001, 0x58, 0x2e001e, 0x258012c,
211  0xa0aa04ec, 0x30, 0x815f004c, 0x12c0300,
212  0xc000204c, 0x600, 0x3206004c, 0x0, 0x0, 0x0
213  } } } }
214 };
215 
216 /*
217  * The following is some guesswork on how the TV encoder flicker
218  * filter/rescaler works:
219  *
220  * It seems to use some sort of resampling filter, it is controlled
221  * through the registers at NV_PTV_HFILTER and NV_PTV_VFILTER, they
222  * control the horizontal and vertical stage respectively, there is
223  * also NV_PTV_HFILTER2 the blob fills identically to NV_PTV_HFILTER,
224  * but they seem to do nothing. A rough guess might be that they could
225  * be used to independently control the filtering of each interlaced
226  * field, but I don't know how they are enabled. The whole filtering
227  * process seems to be disabled with bits 26:27 of PTV_200, but we
228  * aren't doing that.
229  *
230  * The layout of both register sets is the same:
231  *
232  * A: [BASE+0x18]...[BASE+0x0] [BASE+0x58]..[BASE+0x40]
233  * B: [BASE+0x34]...[BASE+0x1c] [BASE+0x74]..[BASE+0x5c]
234  *
235  * Each coefficient is stored in bits [31],[15:9] in two's complement
236  * format. They seem to be some kind of weights used in a low-pass
237  * filter. Both A and B coefficients are applied to the 14 nearest
238  * samples on each side (Listed from nearest to furthermost. They
239  * roughly cover 2 framebuffer pixels on each side). They are
240  * probably multiplied with some more hardwired weights before being
241  * used: B-coefficients are applied the same on both sides,
242  * A-coefficients are inverted before being applied to the opposite
243  * side.
244  *
245  * After all the hassle, I got the following formula by empirical
246  * means...
247  */
248 
249 #define calc_overscan(o) interpolate(0x100, 0xe1, 0xc1, o)
250 
251 #define id1 (1LL << 8)
252 #define id2 (1LL << 16)
253 #define id3 (1LL << 24)
254 #define id4 (1LL << 32)
255 #define id5 (1LL << 48)
256 
257 static struct filter_params{
258  int64_t k1;
259  int64_t ki;
260  int64_t ki2;
261  int64_t ki3;
262  int64_t kr;
263  int64_t kir;
264  int64_t ki2r;
265  int64_t ki3r;
266  int64_t kf;
267  int64_t kif;
268  int64_t ki2f;
269  int64_t ki3f;
270  int64_t krf;
271  int64_t kirf;
272  int64_t ki2rf;
273  int64_t ki3rf;
274 } fparams[2][4] = {
275  /* Horizontal filter parameters */
276  {
277  {64.311690 * id5, -39.516924 * id5, 6.586143 * id5, 0.000002 * id5,
278  0.051285 * id4, 26.168746 * id4, -4.361449 * id4, -0.000001 * id4,
279  9.308169 * id3, 78.180965 * id3, -13.030158 * id3, -0.000001 * id3,
280  -8.801540 * id1, -46.572890 * id1, 7.762145 * id1, -0.000000 * id1},
281  {-44.565569 * id5, -68.081246 * id5, 39.812074 * id5, -4.009316 * id5,
282  29.832207 * id4, 50.047322 * id4, -25.380017 * id4, 2.546422 * id4,
283  104.605622 * id3, 141.908641 * id3, -74.322319 * id3, 7.484316 * id3,
284  -37.081621 * id1, -90.397510 * id1, 42.784229 * id1, -4.289952 * id1},
285  {-56.793244 * id5, 31.153584 * id5, -5.192247 * id5, -0.000003 * id5,
286  33.541131 * id4, -34.149302 * id4, 5.691537 * id4, 0.000002 * id4,
287  87.196610 * id3, -88.995169 * id3, 14.832456 * id3, 0.000012 * id3,
288  17.288138 * id1, 71.864786 * id1, -11.977408 * id1, -0.000009 * id1},
289  {51.787796 * id5, 21.211771 * id5, -18.993730 * id5, 1.853310 * id5,
290  -41.470726 * id4, -17.775823 * id4, 13.057821 * id4, -1.15823 * id4,
291  -154.235673 * id3, -44.878641 * id3, 40.656077 * id3, -3.695595 * id3,
292  112.201065 * id1, 39.992155 * id1, -25.155714 * id1, 2.113984 * id1},
293  },
294 
295  /* Vertical filter parameters */
296  {
297  {67.601979 * id5, 0.428319 * id5, -0.071318 * id5, -0.000012 * id5,
298  -3.402339 * id4, 0.000209 * id4, -0.000092 * id4, 0.000010 * id4,
299  -9.180996 * id3, 6.111270 * id3, -1.024457 * id3, 0.001043 * id3,
300  6.060315 * id1, -0.017425 * id1, 0.007830 * id1, -0.000869 * id1},
301  {6.755647 * id5, 5.841348 * id5, 1.469734 * id5, -0.149656 * id5,
302  8.293120 * id4, -1.192888 * id4, -0.947652 * id4, 0.094507 * id4,
303  37.526655 * id3, 10.257875 * id3, -10.823275 * id3, 1.081497 * id3,
304  -2.361928 * id1, -2.059432 * id1, 1.840671 * id1, -0.168100 * id1},
305  {-14.780391 * id5, -16.042148 * id5, 2.673692 * id5, -0.000000 * id5,
306  39.541978 * id4, 5.680053 * id4, -0.946676 * id4, 0.000000 * id4,
307  152.994486 * id3, 12.625439 * id3, -2.119579 * id3, 0.002708 * id3,
308  -38.125089 * id1, -0.855880 * id1, 0.155359 * id1, -0.002245 * id1},
309  {-27.476193 * id5, -1.454976 * id5, 1.286557 * id5, 0.025346 * id5,
310  20.687300 * id4, 3.014003 * id4, -0.557786 * id4, -0.01311 * id4,
311  60.008737 * id3, -0.738273 * id3, 5.408217 * id3, -0.796798 * id3,
312  -17.296835 * id1, 4.438577 * id1, -2.809420 * id1, 0.385491 * id1},
313  }
314 };
315 
316 static void tv_setup_filter(struct drm_encoder *encoder)
317 {
318  struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
319  struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
320  struct drm_display_mode *mode = &encoder->crtc->mode;
321  uint32_t (*filters[])[4][7] = {&tv_enc->state.hfilter,
322  &tv_enc->state.vfilter};
323  int i, j, k;
324  int32_t overscan = calc_overscan(tv_enc->overscan);
325  int64_t flicker = (tv_enc->flicker - 50) * (id3 / 100);
326  uint64_t rs[] = {mode->hdisplay * id3,
327  mode->vdisplay * id3};
328 
329  do_div(rs[0], overscan * tv_norm->tv_enc_mode.hdisplay);
330  do_div(rs[1], overscan * tv_norm->tv_enc_mode.vdisplay);
331 
332  for (k = 0; k < 2; k++) {
333  rs[k] = max((int64_t)rs[k], id2);
334 
335  for (j = 0; j < 4; j++) {
336  struct filter_params *p = &fparams[k][j];
337 
338  for (i = 0; i < 7; i++) {
339  int64_t c = (p->k1 + p->ki*i + p->ki2*i*i +
340  p->ki3*i*i*i)
341  + (p->kr + p->kir*i + p->ki2r*i*i +
342  p->ki3r*i*i*i) * rs[k]
343  + (p->kf + p->kif*i + p->ki2f*i*i +
344  p->ki3f*i*i*i) * flicker
345  + (p->krf + p->kirf*i + p->ki2rf*i*i +
346  p->ki3rf*i*i*i) * flicker * rs[k];
347 
348  (*filters[k])[j][i] = (c + id5/2) >> 39
349  & (0x1 << 31 | 0x7f << 9);
350  }
351  }
352  }
353 }
354 
355 /* Hardware state saving/restoring */
356 
357 static void tv_save_filter(struct drm_device *dev, uint32_t base,
358  uint32_t regs[4][7])
359 {
360  int i, j;
361  uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
362 
363  for (i = 0; i < 4; i++) {
364  for (j = 0; j < 7; j++)
365  regs[i][j] = nv_read_ptv(dev, offsets[i]+4*j);
366  }
367 }
368 
369 static void tv_load_filter(struct drm_device *dev, uint32_t base,
370  uint32_t regs[4][7])
371 {
372  int i, j;
373  uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
374 
375  for (i = 0; i < 4; i++) {
376  for (j = 0; j < 7; j++)
377  nv_write_ptv(dev, offsets[i]+4*j, regs[i][j]);
378  }
379 }
380 
382 {
383  int i;
384 
385  for (i = 0; i < 0x40; i++)
386  state->tv_enc[i] = nv_read_tv_enc(dev, i);
387 
388  tv_save_filter(dev, NV_PTV_HFILTER, state->hfilter);
389  tv_save_filter(dev, NV_PTV_HFILTER2, state->hfilter2);
390  tv_save_filter(dev, NV_PTV_VFILTER, state->vfilter);
391 
392  nv_save_ptv(dev, state, 200);
393  nv_save_ptv(dev, state, 204);
394  nv_save_ptv(dev, state, 208);
395  nv_save_ptv(dev, state, 20c);
396  nv_save_ptv(dev, state, 304);
397  nv_save_ptv(dev, state, 500);
398  nv_save_ptv(dev, state, 504);
399  nv_save_ptv(dev, state, 508);
400  nv_save_ptv(dev, state, 600);
401  nv_save_ptv(dev, state, 604);
402  nv_save_ptv(dev, state, 608);
403  nv_save_ptv(dev, state, 60c);
404  nv_save_ptv(dev, state, 610);
405  nv_save_ptv(dev, state, 614);
406 }
407 
409 {
410  int i;
411 
412  for (i = 0; i < 0x40; i++)
413  nv_write_tv_enc(dev, i, state->tv_enc[i]);
414 
415  tv_load_filter(dev, NV_PTV_HFILTER, state->hfilter);
416  tv_load_filter(dev, NV_PTV_HFILTER2, state->hfilter2);
417  tv_load_filter(dev, NV_PTV_VFILTER, state->vfilter);
418 
419  nv_load_ptv(dev, state, 200);
420  nv_load_ptv(dev, state, 204);
421  nv_load_ptv(dev, state, 208);
422  nv_load_ptv(dev, state, 20c);
423  nv_load_ptv(dev, state, 304);
424  nv_load_ptv(dev, state, 500);
425  nv_load_ptv(dev, state, 504);
426  nv_load_ptv(dev, state, 508);
427  nv_load_ptv(dev, state, 600);
428  nv_load_ptv(dev, state, 604);
429  nv_load_ptv(dev, state, 608);
430  nv_load_ptv(dev, state, 60c);
431  nv_load_ptv(dev, state, 610);
432  nv_load_ptv(dev, state, 614);
433 
434  /* This is required for some settings to kick in. */
435  nv_write_tv_enc(dev, 0x3e, 1);
436  nv_write_tv_enc(dev, 0x3e, 0);
437 }
438 
439 /* Timings similar to the ones the blob sets */
440 
441 const struct drm_display_mode nv17_tv_modes[] = {
442  { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 0,
443  320, 344, 392, 560, 0, 200, 200, 202, 220, 0,
446  { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 0,
447  320, 344, 392, 560, 0, 240, 240, 246, 263, 0,
450  { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 0,
451  400, 432, 496, 640, 0, 300, 300, 303, 314, 0,
454  { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 0,
455  640, 672, 768, 880, 0, 480, 480, 492, 525, 0,
457  { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 0,
458  720, 752, 872, 960, 0, 480, 480, 493, 525, 0,
460  { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 0,
461  720, 776, 856, 960, 0, 576, 576, 588, 597, 0,
463  { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 0,
464  800, 840, 920, 1040, 0, 600, 600, 604, 618, 0,
466  { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 0,
467  1024, 1064, 1200, 1344, 0, 768, 768, 777, 806, 0,
469  {}
470 };
471 
473 {
474  struct drm_device *dev = encoder->dev;
475  struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
476  struct nv17_tv_state *regs = &tv_enc->state;
477  struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
478  int subconnector = tv_enc->select_subconnector ?
479  tv_enc->select_subconnector :
480  tv_enc->subconnector;
481 
482  switch (subconnector) {
484  {
485  regs->ptv_204 = 0x2;
486 
487  /* The composite connector may be found on either pin. */
488  if (tv_enc->pin_mask & 0x4)
489  regs->ptv_204 |= 0x010000;
490  else if (tv_enc->pin_mask & 0x2)
491  regs->ptv_204 |= 0x100000;
492  else
493  regs->ptv_204 |= 0x110000;
494 
495  regs->tv_enc[0x7] = 0x10;
496  break;
497  }
499  regs->ptv_204 = 0x11012;
500  regs->tv_enc[0x7] = 0x18;
501  break;
502 
504  regs->ptv_204 = 0x111333;
505  regs->tv_enc[0x7] = 0x14;
506  break;
507 
509  regs->ptv_204 = 0x111012;
510  regs->tv_enc[0x7] = 0x18;
511  break;
512  }
513 
514  regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20],
515  255, tv_enc->saturation);
516  regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22],
517  255, tv_enc->saturation);
518  regs->tv_enc[0x25] = tv_enc->hue * 255 / 100;
519 
520  nv_load_ptv(dev, regs, 204);
521  nv_load_tv_enc(dev, regs, 7);
522  nv_load_tv_enc(dev, regs, 20);
523  nv_load_tv_enc(dev, regs, 22);
524  nv_load_tv_enc(dev, regs, 25);
525 }
526 
528 {
529  struct drm_device *dev = encoder->dev;
530  struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
531  struct nv17_tv_state *regs = &tv_enc->state;
532 
533  regs->ptv_208 = 0x40 | (calc_overscan(tv_enc->overscan) << 8);
534 
535  tv_setup_filter(encoder);
536 
537  nv_load_ptv(dev, regs, 208);
538  tv_load_filter(dev, NV_PTV_HFILTER, regs->hfilter);
539  tv_load_filter(dev, NV_PTV_HFILTER2, regs->hfilter2);
540  tv_load_filter(dev, NV_PTV_VFILTER, regs->vfilter);
541 }
542 
544 {
545  struct drm_device *dev = encoder->dev;
546  struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
547  int head = nouveau_crtc(encoder->crtc)->index;
548  struct nv04_crtc_reg *regs = &nv04_display(dev)->mode_reg.crtc_reg[head];
549  struct drm_display_mode *crtc_mode = &encoder->crtc->mode;
550  struct drm_display_mode *output_mode =
551  &get_tv_norm(encoder)->ctv_enc_mode.mode;
552  int overscan, hmargin, vmargin, hratio, vratio;
553 
554  /* The rescaler doesn't do the right thing for interlaced modes. */
555  if (output_mode->flags & DRM_MODE_FLAG_INTERLACE)
556  overscan = 100;
557  else
558  overscan = tv_enc->overscan;
559 
560  hmargin = (output_mode->hdisplay - crtc_mode->hdisplay) / 2;
561  vmargin = (output_mode->vdisplay - crtc_mode->vdisplay) / 2;
562 
563  hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20),
564  hmargin, overscan);
565  vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20),
566  vmargin, overscan);
567 
568  hratio = crtc_mode->hdisplay * 0x800 /
569  (output_mode->hdisplay - 2*hmargin);
570  vratio = crtc_mode->vdisplay * 0x800 /
571  (output_mode->vdisplay - 2*vmargin) & ~3;
572 
573  regs->fp_horiz_regs[FP_VALID_START] = hmargin;
574  regs->fp_horiz_regs[FP_VALID_END] = output_mode->hdisplay - hmargin - 1;
575  regs->fp_vert_regs[FP_VALID_START] = vmargin;
576  regs->fp_vert_regs[FP_VALID_END] = output_mode->vdisplay - vmargin - 1;
577 
582 
583  NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HVALID_START,
585  NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HVALID_END,
586  regs->fp_horiz_regs[FP_VALID_END]);
587  NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_VVALID_START,
589  NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_VVALID_END,
590  regs->fp_vert_regs[FP_VALID_END]);
591  NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_DEBUG_1, regs->fp_debug_1);
592 }