]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/nouveau/nv17_tv_modes.c
Merge branch 'drm-nouveau-fixes' of git://anongit.freedesktop.org/git/nouveau/linux...
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / nv17_tv_modes.c
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
35 char *nv17_tv_norm_names[NUM_TV_NORMS] = {
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
52 struct nv17_tv_norm_params nv17_tv_norms[NUM_TV_NORMS] = {
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
89         [TV_NORM_PAL_NC] = { TV_ENC_MODE, {
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
150         [TV_NORM_HD480P] = { CTV_ENC_MODE, {
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,
154                                                    DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
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
166         [TV_NORM_HD576P] = { CTV_ENC_MODE, {
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,
170                                                    DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
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
182         [TV_NORM_HD720P] = { CTV_ENC_MODE, {
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,
186                                                    DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
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
198         [TV_NORM_HD1080I] = { CTV_ENC_MODE, {
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,
202                                                    DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC
203                                                    | DRM_MODE_FLAG_INTERLACE) },
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
381 void nv17_tv_state_save(struct drm_device *dev, struct nv17_tv_state *state)
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
408 void nv17_tv_state_load(struct drm_device *dev, struct nv17_tv_state *state)
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,
444                    DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC
445                    | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) },
446         { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 0,
447                    320, 344, 392, 560, 0, 240, 240, 246, 263, 0,
448                    DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC
449                    | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) },
450         { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 0,
451                    400, 432, 496, 640, 0, 300, 300, 303, 314, 0,
452                    DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC
453                    | DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_CLKDIV2) },
454         { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 0,
455                    640, 672, 768, 880, 0, 480, 480, 492, 525, 0,
456                    DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
457         { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 0,
458                    720, 752, 872, 960, 0, 480, 480, 493, 525, 0,
459                    DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
460         { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 0,
461                    720, 776, 856, 960, 0, 576, 576, 588, 597, 0,
462                    DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
463         { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 0,
464                    800, 840, 920, 1040, 0, 600, 600, 604, 618, 0,
465                    DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
466         { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 0,
467                    1024, 1064, 1200, 1344, 0, 768, 768, 777, 806, 0,
468                    DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
469         {}
470 };
471
472 void nv17_tv_update_properties(struct drm_encoder *encoder)
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) {
483         case DRM_MODE_SUBCONNECTOR_Composite:
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         }
498         case DRM_MODE_SUBCONNECTOR_SVIDEO:
499                 regs->ptv_204 = 0x11012;
500                 regs->tv_enc[0x7] = 0x18;
501                 break;
502
503         case DRM_MODE_SUBCONNECTOR_Component:
504                 regs->ptv_204 = 0x111333;
505                 regs->tv_enc[0x7] = 0x14;
506                 break;
507
508         case DRM_MODE_SUBCONNECTOR_SCART:
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
527 void nv17_tv_update_rescaler(struct drm_encoder *encoder)
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
543 void nv17_ctv_update_rescaler(struct drm_encoder *encoder)
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
578         regs->fp_debug_1 = NV_PRAMDAC_FP_DEBUG_1_YSCALE_TESTMODE_ENABLE |
579                 XLATE(vratio, 0, NV_PRAMDAC_FP_DEBUG_1_YSCALE_VALUE) |
580                 NV_PRAMDAC_FP_DEBUG_1_XSCALE_TESTMODE_ENABLE |
581                 XLATE(hratio, 0, NV_PRAMDAC_FP_DEBUG_1_XSCALE_VALUE);
582
583         NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HVALID_START,
584                       regs->fp_horiz_regs[FP_VALID_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,
588                       regs->fp_vert_regs[FP_VALID_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 }