brintos

brintos / linux-shallow public Read only

0
0
Text · 24.2 KiB · 3ecb101 Raw
833 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 <drm/drm_crtc_helper.h>28#include <drm/drm_modeset_helper_vtables.h>29#include <drm/drm_probe_helper.h>30#include "nouveau_drv.h"31#include "nouveau_reg.h"32#include "nouveau_encoder.h"33#include "nouveau_connector.h"34#include "nouveau_crtc.h"35#include "hw.h"36#include "tvnv17.h"37 38MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"39		 "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n"40		 "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n"41		 "\t\tDefault: PAL\n"42		 "\t\t*NOTE* Ignored for cards with external TV encoders.");43static char *nouveau_tv_norm;44module_param_named(tv_norm, nouveau_tv_norm, charp, 0400);45 46static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)47{48	struct drm_device *dev = encoder->dev;49	struct nouveau_drm *drm = nouveau_drm(dev);50	struct nvkm_gpio *gpio = nvxx_gpio(drm);51	uint32_t testval, regoffset = nv04_dac_output_offset(encoder);52	uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end,53		fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c;54	uint32_t sample = 0;55	int head;56 57#define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20)58	testval = RGB_TEST_DATA(0x82, 0xeb, 0x82);59	if (drm->vbios.tvdactestval)60		testval = drm->vbios.tvdactestval;61 62	dacclk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);63	head = (dacclk & 0x100) >> 8;64 65	/* Save the previous state. */66	gpio1 = nvkm_gpio_get(gpio, 0, DCB_GPIO_TVDAC1, 0xff);67	gpio0 = nvkm_gpio_get(gpio, 0, DCB_GPIO_TVDAC0, 0xff);68	fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL);69	fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START);70	fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END);71	fp_control = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL);72	test_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);73	ctv_1c = NVReadRAMDAC(dev, head, 0x680c1c);74	ctv_14 = NVReadRAMDAC(dev, head, 0x680c14);75	ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c);76 77	/* Prepare the DAC for load detection.  */78	nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, true);79	nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, true);80 81	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343);82	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047);83	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, 1183);84	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL,85		      NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS |86		      NV_PRAMDAC_FP_TG_CONTROL_WIDTH_12 |87		      NV_PRAMDAC_FP_TG_CONTROL_READ_PROG |88		      NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS |89		      NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS);90 91	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, 0);92 93	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset,94		      (dacclk & ~0xff) | 0x22);95	msleep(1);96	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset,97		      (dacclk & ~0xff) | 0x21);98 99	NVWriteRAMDAC(dev, head, 0x680c1c, 1 << 20);100	NVWriteRAMDAC(dev, head, 0x680c14, 4 << 16);101 102	/* Sample pin 0x4 (usually S-video luma). */103	NVWriteRAMDAC(dev, head, 0x680c6c, testval >> 10 & 0x3ff);104	msleep(20);105	sample |= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset)106		& 0x4 << 28;107 108	/* Sample the remaining pins. */109	NVWriteRAMDAC(dev, head, 0x680c6c, testval & 0x3ff);110	msleep(20);111	sample |= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset)112		& 0xa << 28;113 114	/* Restore the previous state. */115	NVWriteRAMDAC(dev, head, 0x680c1c, ctv_1c);116	NVWriteRAMDAC(dev, head, 0x680c14, ctv_14);117	NVWriteRAMDAC(dev, head, 0x680c6c, ctv_6c);118	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, dacclk);119	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, test_ctrl);120	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL, fp_control);121	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end);122	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start);123	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal);124	nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, gpio1);125	nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, gpio0);126 127	return sample;128}129 130static bool131get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask)132{133	struct nouveau_drm *drm = nouveau_drm(dev);134	struct nvkm_device *device = nvxx_device(drm);135 136	if (device->quirk && device->quirk->tv_pin_mask) {137		*pin_mask = device->quirk->tv_pin_mask;138		return false;139	}140 141	return true;142}143 144static enum drm_connector_status145nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)146{147	struct drm_device *dev = encoder->dev;148	struct nouveau_drm *drm = nouveau_drm(dev);149	struct drm_mode_config *conf = &dev->mode_config;150	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);151	struct dcb_output *dcb = tv_enc->base.dcb;152	bool reliable = get_tv_detect_quirks(dev, &tv_enc->pin_mask);153 154	if (nv04_dac_in_use(encoder))155		return connector_status_disconnected;156 157	if (reliable) {158		if (drm->client.device.info.chipset == 0x42 ||159		    drm->client.device.info.chipset == 0x43)160			tv_enc->pin_mask =161				nv42_tv_sample_load(encoder) >> 28 & 0xe;162		else163			tv_enc->pin_mask =164				nv17_dac_sample_load(encoder) >> 28 & 0xe;165	}166 167	switch (tv_enc->pin_mask) {168	case 0x2:169	case 0x4:170		tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Composite;171		break;172	case 0xc:173		tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO;174		break;175	case 0xe:176		if (dcb->tvconf.has_component_output)177			tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Component;178		else179			tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_SCART;180		break;181	default:182		tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;183		break;184	}185 186	drm_object_property_set_value(&connector->base,187					 conf->tv_subconnector_property,188					 tv_enc->subconnector);189 190	if (!reliable) {191		return connector_status_unknown;192	} else if (tv_enc->subconnector) {193		NV_INFO(drm, "Load detected on output %c\n",194			'@' + ffs(dcb->or));195		return connector_status_connected;196	} else {197		return connector_status_disconnected;198	}199}200 201static int nv17_tv_get_ld_modes(struct drm_encoder *encoder,202				struct drm_connector *connector)203{204	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);205	const struct drm_display_mode *tv_mode;206	int n = 0;207 208	for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {209		struct drm_display_mode *mode;210 211		mode = drm_mode_duplicate(encoder->dev, tv_mode);212		if (!mode)213			continue;214 215		mode->clock = tv_norm->tv_enc_mode.vrefresh *216			mode->htotal / 1000 *217			mode->vtotal / 1000;218 219		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)220			mode->clock *= 2;221 222		if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&223		    mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)224			mode->type |= DRM_MODE_TYPE_PREFERRED;225 226		drm_mode_probed_add(connector, mode);227		n++;228	}229 230	return n;231}232 233static int nv17_tv_get_hd_modes(struct drm_encoder *encoder,234				struct drm_connector *connector)235{236	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);237	struct drm_display_mode *output_mode = &tv_norm->ctv_enc_mode.mode;238	struct drm_display_mode *mode;239	const struct {240		int hdisplay;241		int vdisplay;242	} modes[] = {243		{ 640, 400 },244		{ 640, 480 },245		{ 720, 480 },246		{ 720, 576 },247		{ 800, 600 },248		{ 1024, 768 },249		{ 1280, 720 },250		{ 1280, 1024 },251		{ 1920, 1080 }252	};253	int i, n = 0;254 255	for (i = 0; i < ARRAY_SIZE(modes); i++) {256		if (modes[i].hdisplay > output_mode->hdisplay ||257		    modes[i].vdisplay > output_mode->vdisplay)258			continue;259 260		if (modes[i].hdisplay == output_mode->hdisplay &&261		    modes[i].vdisplay == output_mode->vdisplay) {262			mode = drm_mode_duplicate(encoder->dev, output_mode);263			if (!mode)264				continue;265			mode->type |= DRM_MODE_TYPE_PREFERRED;266 267		} else {268			mode = drm_cvt_mode(encoder->dev, modes[i].hdisplay,269					    modes[i].vdisplay, 60, false,270					    (output_mode->flags &271					     DRM_MODE_FLAG_INTERLACE), false);272			if (!mode)273				continue;274		}275 276		/* CVT modes are sometimes unsuitable... */277		if (output_mode->hdisplay <= 720278		    || output_mode->hdisplay >= 1920) {279			mode->htotal = output_mode->htotal;280			mode->hsync_start = (mode->hdisplay + (mode->htotal281					     - mode->hdisplay) * 9 / 10) & ~7;282			mode->hsync_end = mode->hsync_start + 8;283		}284 285		if (output_mode->vdisplay >= 1024) {286			mode->vtotal = output_mode->vtotal;287			mode->vsync_start = output_mode->vsync_start;288			mode->vsync_end = output_mode->vsync_end;289		}290 291		mode->type |= DRM_MODE_TYPE_DRIVER;292		drm_mode_probed_add(connector, mode);293		n++;294	}295 296	return n;297}298 299static int nv17_tv_get_modes(struct drm_encoder *encoder,300			     struct drm_connector *connector)301{302	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);303 304	if (tv_norm->kind == CTV_ENC_MODE)305		return nv17_tv_get_hd_modes(encoder, connector);306	else307		return nv17_tv_get_ld_modes(encoder, connector);308}309 310static int nv17_tv_mode_valid(struct drm_encoder *encoder,311			      struct drm_display_mode *mode)312{313	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);314 315	if (tv_norm->kind == CTV_ENC_MODE) {316		struct drm_display_mode *output_mode =317						&tv_norm->ctv_enc_mode.mode;318 319		if (mode->clock > 400000)320			return MODE_CLOCK_HIGH;321 322		if (mode->hdisplay > output_mode->hdisplay ||323		    mode->vdisplay > output_mode->vdisplay)324			return MODE_BAD;325 326		if ((mode->flags & DRM_MODE_FLAG_INTERLACE) !=327		    (output_mode->flags & DRM_MODE_FLAG_INTERLACE))328			return MODE_NO_INTERLACE;329 330		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)331			return MODE_NO_DBLESCAN;332 333	} else {334		const int vsync_tolerance = 600;335 336		if (mode->clock > 70000)337			return MODE_CLOCK_HIGH;338 339		if (abs(drm_mode_vrefresh(mode) * 1000 -340			tv_norm->tv_enc_mode.vrefresh) > vsync_tolerance)341			return MODE_VSYNC;342 343		/* The encoder takes care of the actual interlacing */344		if (mode->flags & DRM_MODE_FLAG_INTERLACE)345			return MODE_NO_INTERLACE;346	}347 348	return MODE_OK;349}350 351static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,352			       const struct drm_display_mode *mode,353			       struct drm_display_mode *adjusted_mode)354{355	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);356 357	if (nv04_dac_in_use(encoder))358		return false;359 360	if (tv_norm->kind == CTV_ENC_MODE)361		adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock;362	else363		adjusted_mode->clock = 90000;364 365	return true;366}367 368static void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)369{370	struct drm_device *dev = encoder->dev;371	struct nouveau_drm *drm = nouveau_drm(dev);372	struct nvkm_gpio *gpio = nvxx_gpio(drm);373	struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;374	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);375 376	if (nouveau_encoder(encoder)->last_dpms == mode)377		return;378	nouveau_encoder(encoder)->last_dpms = mode;379 380	NV_INFO(drm, "Setting dpms mode %d on TV encoder (output %d)\n",381		 mode, nouveau_encoder(encoder)->dcb->index);382 383	regs->ptv_200 &= ~1;384 385	if (tv_norm->kind == CTV_ENC_MODE) {386		nv04_dfp_update_fp_control(encoder, mode);387 388	} else {389		nv04_dfp_update_fp_control(encoder, DRM_MODE_DPMS_OFF);390 391		if (mode == DRM_MODE_DPMS_ON)392			regs->ptv_200 |= 1;393	}394 395	nv_load_ptv(dev, regs, 200);396 397	nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, mode == DRM_MODE_DPMS_ON);398	nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, mode == DRM_MODE_DPMS_ON);399 400	nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);401}402 403static void nv17_tv_prepare(struct drm_encoder *encoder)404{405	struct drm_device *dev = encoder->dev;406	struct nouveau_drm *drm = nouveau_drm(dev);407	const struct drm_encoder_helper_funcs *helper = encoder->helper_private;408	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);409	int head = nouveau_crtc(encoder->crtc)->index;410	uint8_t *cr_lcd = &nv04_display(dev)->mode_reg.crtc_reg[head].CRTC[411							NV_CIO_CRE_LCD__INDEX];412	uint32_t dacclk_off = NV_PRAMDAC_DACCLK +413					nv04_dac_output_offset(encoder);414	uint32_t dacclk;415 416	helper->dpms(encoder, DRM_MODE_DPMS_OFF);417 418	nv04_dfp_disable(dev, head);419 420	/* Unbind any FP encoders from this head if we need the FP421	 * stuff enabled. */422	if (tv_norm->kind == CTV_ENC_MODE) {423		struct drm_encoder *enc;424 425		list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {426			struct dcb_output *dcb = nouveau_encoder(enc)->dcb;427 428			if ((dcb->type == DCB_OUTPUT_TMDS ||429			     dcb->type == DCB_OUTPUT_LVDS) &&430			     !enc->crtc &&431			     nv04_dfp_get_bound_head(dev, dcb) == head) {432				nv04_dfp_bind_head(dev, dcb, head ^ 1,433						drm->vbios.fp.dual_link);434			}435		}436 437	}438 439	if (tv_norm->kind == CTV_ENC_MODE)440		*cr_lcd |= 0x1 | (head ? 0x0 : 0x8);441 442	/* Set the DACCLK register */443	dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1;444 445	if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE)446		dacclk |= 0x1a << 16;447 448	if (tv_norm->kind == CTV_ENC_MODE) {449		dacclk |=  0x20;450 451		if (head)452			dacclk |= 0x100;453		else454			dacclk &= ~0x100;455 456	} else {457		dacclk |= 0x10;458 459	}460 461	NVWriteRAMDAC(dev, 0, dacclk_off, dacclk);462}463 464static void nv17_tv_mode_set(struct drm_encoder *encoder,465			     struct drm_display_mode *drm_mode,466			     struct drm_display_mode *adjusted_mode)467{468	struct drm_device *dev = encoder->dev;469	struct nouveau_drm *drm = nouveau_drm(dev);470	int head = nouveau_crtc(encoder->crtc)->index;471	struct nv04_crtc_reg *regs = &nv04_display(dev)->mode_reg.crtc_reg[head];472	struct nv17_tv_state *tv_regs = &to_tv_enc(encoder)->state;473	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);474	int i;475 476	regs->CRTC[NV_CIO_CRE_53] = 0x40; /* FP_HTIMING */477	regs->CRTC[NV_CIO_CRE_54] = 0; /* FP_VTIMING */478	regs->ramdac_630 = 0x2; /* turn off green mode (tv test pattern?) */479	regs->tv_setup = 1;480	regs->ramdac_8c0 = 0x0;481 482	if (tv_norm->kind == TV_ENC_MODE) {483		tv_regs->ptv_200 = 0x13111100;484		if (head)485			tv_regs->ptv_200 |= 0x10;486 487		tv_regs->ptv_20c = 0x808010;488		tv_regs->ptv_304 = 0x2d00000;489		tv_regs->ptv_600 = 0x0;490		tv_regs->ptv_60c = 0x0;491		tv_regs->ptv_610 = 0x1e00000;492 493		if (tv_norm->tv_enc_mode.vdisplay == 576) {494			tv_regs->ptv_508 = 0x1200000;495			tv_regs->ptv_614 = 0x33;496 497		} else if (tv_norm->tv_enc_mode.vdisplay == 480) {498			tv_regs->ptv_508 = 0xf00000;499			tv_regs->ptv_614 = 0x13;500		}501 502		if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_RANKINE) {503			tv_regs->ptv_500 = 0xe8e0;504			tv_regs->ptv_504 = 0x1710;505			tv_regs->ptv_604 = 0x0;506			tv_regs->ptv_608 = 0x0;507		} else {508			if (tv_norm->tv_enc_mode.vdisplay == 576) {509				tv_regs->ptv_604 = 0x20;510				tv_regs->ptv_608 = 0x10;511				tv_regs->ptv_500 = 0x19710;512				tv_regs->ptv_504 = 0x68f0;513 514			} else if (tv_norm->tv_enc_mode.vdisplay == 480) {515				tv_regs->ptv_604 = 0x10;516				tv_regs->ptv_608 = 0x20;517				tv_regs->ptv_500 = 0x4b90;518				tv_regs->ptv_504 = 0x1b480;519			}520		}521 522		for (i = 0; i < 0x40; i++)523			tv_regs->tv_enc[i] = tv_norm->tv_enc_mode.tv_enc[i];524 525	} else {526		struct drm_display_mode *output_mode =527						&tv_norm->ctv_enc_mode.mode;528 529		/* The registers in PRAMDAC+0xc00 control some timings and CSC530		 * parameters for the CTV encoder (It's only used for "HD" TV531		 * modes, I don't think I have enough working to guess what532		 * they exactly mean...), it's probably connected at the533		 * output of the FP encoder, but it also needs the analog534		 * encoder in its OR enabled and routed to the head it's535		 * using. It's enabled with the DACCLK register, bits [5:4].536		 */537		for (i = 0; i < 38; i++)538			regs->ctv_regs[i] = tv_norm->ctv_enc_mode.ctv_regs[i];539 540		regs->fp_horiz_regs[FP_DISPLAY_END] = output_mode->hdisplay - 1;541		regs->fp_horiz_regs[FP_TOTAL] = output_mode->htotal - 1;542		regs->fp_horiz_regs[FP_SYNC_START] =543						output_mode->hsync_start - 1;544		regs->fp_horiz_regs[FP_SYNC_END] = output_mode->hsync_end - 1;545		regs->fp_horiz_regs[FP_CRTC] = output_mode->hdisplay +546			max((output_mode->hdisplay-600)/40 - 1, 1);547 548		regs->fp_vert_regs[FP_DISPLAY_END] = output_mode->vdisplay - 1;549		regs->fp_vert_regs[FP_TOTAL] = output_mode->vtotal - 1;550		regs->fp_vert_regs[FP_SYNC_START] =551						output_mode->vsync_start - 1;552		regs->fp_vert_regs[FP_SYNC_END] = output_mode->vsync_end - 1;553		regs->fp_vert_regs[FP_CRTC] = output_mode->vdisplay - 1;554 555		regs->fp_control = NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS |556			NV_PRAMDAC_FP_TG_CONTROL_READ_PROG |557			NV_PRAMDAC_FP_TG_CONTROL_WIDTH_12;558 559		if (output_mode->flags & DRM_MODE_FLAG_PVSYNC)560			regs->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS;561		if (output_mode->flags & DRM_MODE_FLAG_PHSYNC)562			regs->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS;563 564		regs->fp_debug_0 = NV_PRAMDAC_FP_DEBUG_0_YWEIGHT_ROUND |565			NV_PRAMDAC_FP_DEBUG_0_XWEIGHT_ROUND |566			NV_PRAMDAC_FP_DEBUG_0_YINTERP_BILINEAR |567			NV_PRAMDAC_FP_DEBUG_0_XINTERP_BILINEAR |568			NV_RAMDAC_FP_DEBUG_0_TMDS_ENABLED |569			NV_PRAMDAC_FP_DEBUG_0_YSCALE_ENABLE |570			NV_PRAMDAC_FP_DEBUG_0_XSCALE_ENABLE;571 572		regs->fp_debug_2 = 0;573 574		regs->fp_margin_color = 0x801080;575 576	}577}578 579static void nv17_tv_commit(struct drm_encoder *encoder)580{581	struct drm_device *dev = encoder->dev;582	struct nouveau_drm *drm = nouveau_drm(dev);583	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);584	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);585	const struct drm_encoder_helper_funcs *helper = encoder->helper_private;586 587	if (get_tv_norm(encoder)->kind == TV_ENC_MODE) {588		nv17_tv_update_rescaler(encoder);589		nv17_tv_update_properties(encoder);590	} else {591		nv17_ctv_update_rescaler(encoder);592	}593 594	nv17_tv_state_load(dev, &to_tv_enc(encoder)->state);595 596	/* This could use refinement for flatpanels, but it should work */597	if (drm->client.device.info.chipset < 0x44)598		NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL +599					nv04_dac_output_offset(encoder),600					0xf0000000);601	else602		NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL +603					nv04_dac_output_offset(encoder),604					0x00100000);605 606	helper->dpms(encoder, DRM_MODE_DPMS_ON);607 608	NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",609		nv04_encoder_get_connector(nv_encoder)->base.name,610		nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));611}612 613static void nv17_tv_save(struct drm_encoder *encoder)614{615	struct drm_device *dev = encoder->dev;616	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);617 618	nouveau_encoder(encoder)->restore.output =619					NVReadRAMDAC(dev, 0,620					NV_PRAMDAC_DACCLK +621					nv04_dac_output_offset(encoder));622 623	nv17_tv_state_save(dev, &tv_enc->saved_state);624 625	tv_enc->state.ptv_200 = tv_enc->saved_state.ptv_200;626}627 628static void nv17_tv_restore(struct drm_encoder *encoder)629{630	struct drm_device *dev = encoder->dev;631 632	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK +633				nv04_dac_output_offset(encoder),634				nouveau_encoder(encoder)->restore.output);635 636	nv17_tv_state_load(dev, &to_tv_enc(encoder)->saved_state);637 638	nouveau_encoder(encoder)->last_dpms = NV_DPMS_CLEARED;639}640 641static int nv17_tv_create_resources(struct drm_encoder *encoder,642				    struct drm_connector *connector)643{644	struct drm_device *dev = encoder->dev;645	struct nouveau_drm *drm = nouveau_drm(dev);646	struct drm_mode_config *conf = &dev->mode_config;647	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);648	struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;649	int num_tv_norms = dcb->tvconf.has_component_output ? NUM_TV_NORMS :650							NUM_LD_TV_NORMS;651	int i;652 653	if (nouveau_tv_norm) {654		i = match_string(nv17_tv_norm_names, num_tv_norms,655				 nouveau_tv_norm);656		if (i < 0)657			NV_WARN(drm, "Invalid TV norm setting \"%s\"\n",658				nouveau_tv_norm);659		else660			tv_enc->tv_norm = i;661	}662 663	drm_mode_create_tv_properties_legacy(dev, num_tv_norms, nv17_tv_norm_names);664 665	drm_object_attach_property(&connector->base,666					conf->tv_select_subconnector_property,667					tv_enc->select_subconnector);668	drm_object_attach_property(&connector->base,669					conf->tv_subconnector_property,670					tv_enc->subconnector);671	drm_object_attach_property(&connector->base,672					conf->legacy_tv_mode_property,673					tv_enc->tv_norm);674	drm_object_attach_property(&connector->base,675					conf->tv_flicker_reduction_property,676					tv_enc->flicker);677	drm_object_attach_property(&connector->base,678					conf->tv_saturation_property,679					tv_enc->saturation);680	drm_object_attach_property(&connector->base,681					conf->tv_hue_property,682					tv_enc->hue);683	drm_object_attach_property(&connector->base,684					conf->tv_overscan_property,685					tv_enc->overscan);686 687	return 0;688}689 690static int nv17_tv_set_property(struct drm_encoder *encoder,691				struct drm_connector *connector,692				struct drm_property *property,693				uint64_t val)694{695	struct drm_mode_config *conf = &encoder->dev->mode_config;696	struct drm_crtc *crtc = encoder->crtc;697	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);698	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);699	bool modes_changed = false;700 701	if (property == conf->tv_overscan_property) {702		tv_enc->overscan = val;703		if (encoder->crtc) {704			if (tv_norm->kind == CTV_ENC_MODE)705				nv17_ctv_update_rescaler(encoder);706			else707				nv17_tv_update_rescaler(encoder);708		}709 710	} else if (property == conf->tv_saturation_property) {711		if (tv_norm->kind != TV_ENC_MODE)712			return -EINVAL;713 714		tv_enc->saturation = val;715		nv17_tv_update_properties(encoder);716 717	} else if (property == conf->tv_hue_property) {718		if (tv_norm->kind != TV_ENC_MODE)719			return -EINVAL;720 721		tv_enc->hue = val;722		nv17_tv_update_properties(encoder);723 724	} else if (property == conf->tv_flicker_reduction_property) {725		if (tv_norm->kind != TV_ENC_MODE)726			return -EINVAL;727 728		tv_enc->flicker = val;729		if (encoder->crtc)730			nv17_tv_update_rescaler(encoder);731 732	} else if (property == conf->legacy_tv_mode_property) {733		if (connector->dpms != DRM_MODE_DPMS_OFF)734			return -EINVAL;735 736		tv_enc->tv_norm = val;737 738		modes_changed = true;739 740	} else if (property == conf->tv_select_subconnector_property) {741		if (tv_norm->kind != TV_ENC_MODE)742			return -EINVAL;743 744		tv_enc->select_subconnector = val;745		nv17_tv_update_properties(encoder);746 747	} else {748		return -EINVAL;749	}750 751	if (modes_changed) {752		drm_helper_probe_single_connector_modes(connector, 0, 0);753 754		/* Disable the crtc to ensure a full modeset is755		 * performed whenever it's turned on again. */756		if (crtc)757			drm_crtc_helper_set_mode(crtc, &crtc->mode,758						 crtc->x, crtc->y,759						 crtc->primary->fb);760	}761 762	return 0;763}764 765static void nv17_tv_destroy(struct drm_encoder *encoder)766{767	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);768 769	drm_encoder_cleanup(encoder);770	kfree(tv_enc);771}772 773static const struct drm_encoder_helper_funcs nv17_tv_helper_funcs = {774	.dpms = nv17_tv_dpms,775	.mode_fixup = nv17_tv_mode_fixup,776	.prepare = nv17_tv_prepare,777	.commit = nv17_tv_commit,778	.mode_set = nv17_tv_mode_set,779	.detect = nv17_tv_detect,780};781 782static const struct drm_encoder_slave_funcs nv17_tv_slave_funcs = {783	.get_modes = nv17_tv_get_modes,784	.mode_valid = nv17_tv_mode_valid,785	.create_resources = nv17_tv_create_resources,786	.set_property = nv17_tv_set_property,787};788 789static const struct drm_encoder_funcs nv17_tv_funcs = {790	.destroy = nv17_tv_destroy,791};792 793int794nv17_tv_create(struct drm_connector *connector, struct dcb_output *entry)795{796	struct drm_device *dev = connector->dev;797	struct drm_encoder *encoder;798	struct nv17_tv_encoder *tv_enc = NULL;799 800	tv_enc = kzalloc(sizeof(*tv_enc), GFP_KERNEL);801	if (!tv_enc)802		return -ENOMEM;803 804	tv_enc->overscan = 50;805	tv_enc->flicker = 50;806	tv_enc->saturation = 50;807	tv_enc->hue = 0;808	tv_enc->tv_norm = TV_NORM_PAL;809	tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;810	tv_enc->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic;811	tv_enc->pin_mask = 0;812 813	encoder = to_drm_encoder(&tv_enc->base);814 815	tv_enc->base.dcb = entry;816	tv_enc->base.or = ffs(entry->or) - 1;817 818	drm_encoder_init(dev, encoder, &nv17_tv_funcs, DRM_MODE_ENCODER_TVDAC,819			 NULL);820	drm_encoder_helper_add(encoder, &nv17_tv_helper_funcs);821	to_encoder_slave(encoder)->slave_funcs = &nv17_tv_slave_funcs;822 823	tv_enc->base.enc_save = nv17_tv_save;824	tv_enc->base.enc_restore = nv17_tv_restore;825 826	encoder->possible_crtcs = entry->heads;827	encoder->possible_clones = 0;828 829	nv17_tv_create_resources(encoder, connector);830	drm_connector_attach_encoder(connector, encoder);831	return 0;832}833