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