brintos

brintos / linux-shallow public Read only

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