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