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 "hw.h"
33#include "tvnv17.h"
34
35const char * const 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
52struct 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
257static 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
316static 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
357static 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
369static 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
381void 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
408void 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
441const 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
472void 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
527void 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
543void 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}
593