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