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