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

source code of linux/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c