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