16ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs/*
26ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * Copyright (C) 2009 Francisco Jerez.
36ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * All Rights Reserved.
46ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
56ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * Permission is hereby granted, free of charge, to any person obtaining
66ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * a copy of this software and associated documentation files (the
76ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * "Software"), to deal in the Software without restriction, including
86ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * without limitation the rights to use, copy, modify, merge, publish,
96ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * distribute, sublicense, and/or sell copies of the Software, and to
106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * permit persons to whom the Software is furnished to do so, subject to
116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * the following conditions:
126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * The above copyright notice and this permission notice (including the
146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * next paragraph) shall be included in all copies or substantial
156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * portions of the Software.
166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs *
256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs */
266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "drmP.h"
286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "drm_crtc_helper.h"
296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_drv.h"
306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_encoder.h"
316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_connector.h"
326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_crtc.h"
33a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs#include "nouveau_gpio.h"
346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nouveau_hw.h"
356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs#include "nv17_tv.h"
366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
370829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerezstatic uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
380829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez{
390829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	struct drm_device *dev = encoder->dev;
400829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	struct drm_nouveau_private *dev_priv = dev->dev_private;
410829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	uint32_t testval, regoffset = nv04_dac_output_offset(encoder);
420829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end,
430829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c;
440829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	uint32_t sample = 0;
450829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	int head;
460829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
470829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez#define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20)
480829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	testval = RGB_TEST_DATA(0x82, 0xeb, 0x82);
4904a39c577f4114a3f098ee8ef0e20f7778b5ddadBen Skeggs	if (dev_priv->vbios.tvdactestval)
5004a39c577f4114a3f098ee8ef0e20f7778b5ddadBen Skeggs		testval = dev_priv->vbios.tvdactestval;
510829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
520829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	dacclk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);
530829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	head = (dacclk & 0x100) >> 8;
540829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
550829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	/* Save the previous state. */
56a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs	gpio1 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC1);
57a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs	gpio0 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC0);
580829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL);
590829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START);
600829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END);
610829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	fp_control = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL);
620829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	test_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
630829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	ctv_1c = NVReadRAMDAC(dev, head, 0x680c1c);
640829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	ctv_14 = NVReadRAMDAC(dev, head, 0x680c14);
650829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c);
660829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
670829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	/* Prepare the DAC for load detection.  */
68a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs	nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, true);
69a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs	nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, true);
700829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
710829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343);
720829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047);
730829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, 1183);
740829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL,
750829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		      NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS |
760829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		      NV_PRAMDAC_FP_TG_CONTROL_WIDTH_12 |
770829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		      NV_PRAMDAC_FP_TG_CONTROL_READ_PROG |
780829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		      NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS |
790829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		      NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS);
800829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
810829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, 0);
820829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
830829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset,
840829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		      (dacclk & ~0xff) | 0x22);
850829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	msleep(1);
860829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset,
870829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		      (dacclk & ~0xff) | 0x21);
880829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
890829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, 0x680c1c, 1 << 20);
900829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, 0x680c14, 4 << 16);
910829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
920829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	/* Sample pin 0x4 (usually S-video luma). */
930829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, 0x680c6c, testval >> 10 & 0x3ff);
940829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	msleep(20);
950829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	sample |= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset)
960829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		& 0x4 << 28;
970829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
980829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	/* Sample the remaining pins. */
990829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, 0x680c6c, testval & 0x3ff);
1000829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	msleep(20);
1010829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	sample |= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset)
1020829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez		& 0xa << 28;
1030829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
1040829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	/* Restore the previous state. */
1050829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, 0x680c1c, ctv_1c);
1060829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, 0x680c14, ctv_14);
1070829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, 0x680c6c, ctv_6c);
1080829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, dacclk);
1090829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, test_ctrl);
1100829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL, fp_control);
1110829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end);
1120829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start);
1130829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal);
114a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs	nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, gpio1);
115a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs	nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, gpio0);
1160829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
1170829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	return sample;
1180829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez}
1190829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez
1204664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerezstatic bool
1214664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerezget_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask)
1224664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez{
1234664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez	/* Zotac FX5200 */
124acae116ce16833859eb4eb929de571b9a800d685Francisco Jerez	if (nv_match_device(dev, 0x0322, 0x19da, 0x1035) ||
125acae116ce16833859eb4eb929de571b9a800d685Francisco Jerez	    nv_match_device(dev, 0x0322, 0x19da, 0x2035)) {
1264664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez		*pin_mask = 0xc;
1274664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez		return false;
1284664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez	}
1294664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez
13019bf5f7df918f86a1507389101b5eddcad983951Francisco Jerez	/* MSI nForce2 IGP */
131acae116ce16833859eb4eb929de571b9a800d685Francisco Jerez	if (nv_match_device(dev, 0x01f0, 0x1462, 0x5710)) {
13219bf5f7df918f86a1507389101b5eddcad983951Francisco Jerez		*pin_mask = 0xc;
13319bf5f7df918f86a1507389101b5eddcad983951Francisco Jerez		return false;
13419bf5f7df918f86a1507389101b5eddcad983951Francisco Jerez	}
13519bf5f7df918f86a1507389101b5eddcad983951Francisco Jerez
1364664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez	return true;
1374664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez}
1384664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez
13911d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerezstatic enum drm_connector_status
14011d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jereznv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
1416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
14211d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez	struct drm_device *dev = encoder->dev;
1430829168b474663d8b13f6105368dbbf4a1a03256Francisco Jerez	struct drm_nouveau_private *dev_priv = dev->dev_private;
14411d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez	struct drm_mode_config *conf = &dev->mode_config;
1456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
14611d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez	struct dcb_entry *dcb = tv_enc->base.dcb;
1474664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez	bool reliable = get_tv_detect_quirks(dev, &tv_enc->pin_mask);
1486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1498ccfe9e098d5975ef65d17de477f6b7dc0c446dbFrancisco Jerez	if (nv04_dac_in_use(encoder))
1508ccfe9e098d5975ef65d17de477f6b7dc0c446dbFrancisco Jerez		return connector_status_disconnected;
1518ccfe9e098d5975ef65d17de477f6b7dc0c446dbFrancisco Jerez
1524664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez	if (reliable) {
1534664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez		if (dev_priv->chipset == 0x42 ||
1544664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez		    dev_priv->chipset == 0x43)
1554664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez			tv_enc->pin_mask =
1564664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez				nv42_tv_sample_load(encoder) >> 28 & 0xe;
1574664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez		else
1584664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez			tv_enc->pin_mask =
1594664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez				nv17_dac_sample_load(encoder) >> 28 & 0xe;
1604664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez	}
1616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	switch (tv_enc->pin_mask) {
1636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	case 0x2:
1646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	case 0x4:
1656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Composite;
1666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		break;
1676ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	case 0xc:
1686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_SVIDEO;
1696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		break;
1706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	case 0xe:
17111d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez		if (dcb->tvconf.has_component_output)
1726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Component;
1736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		else
1746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_SCART;
1756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		break;
1766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	default:
1776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
1786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		break;
1796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
1806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_connector_property_set_value(connector,
18211d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez					 conf->tv_subconnector_property,
18311d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez					 tv_enc->subconnector);
1846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
1854664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez	if (!reliable) {
1864664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez		return connector_status_unknown;
1874664c67b5d054012562a74414ed3f8619912b3d1Francisco Jerez	} else if (tv_enc->subconnector) {
18811d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez		NV_INFO(dev, "Load detected on output %c\n",
18911d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez			'@' + ffs(dcb->or));
19011d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez		return connector_status_connected;
19111d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez	} else {
19211d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez		return connector_status_disconnected;
19311d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez	}
1946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
1956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
196f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerezstatic int nv17_tv_get_ld_modes(struct drm_encoder *encoder,
197f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez				struct drm_connector *connector)
1986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
1996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
200b1f559ecdc6026ef783ccadc62a61e7da906fcb4Chris Wilson	const struct drm_display_mode *tv_mode;
2016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	int n = 0;
2026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
203f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {
204b1f559ecdc6026ef783ccadc62a61e7da906fcb4Chris Wilson		struct drm_display_mode *mode;
205b1f559ecdc6026ef783ccadc62a61e7da906fcb4Chris Wilson
206f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		mode = drm_mode_duplicate(encoder->dev, tv_mode);
2076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
208f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		mode->clock = tv_norm->tv_enc_mode.vrefresh *
209f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez			mode->htotal / 1000 *
210f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez			mode->vtotal / 1000;
2116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
212f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
213f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez			mode->clock *= 2;
2146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
215f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&
216f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		    mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)
217f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez			mode->type |= DRM_MODE_TYPE_PREFERRED;
2186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
219f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		drm_mode_probed_add(connector, mode);
220f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		n++;
2216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
2226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
223f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	return n;
224f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez}
225f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez
226f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerezstatic int nv17_tv_get_hd_modes(struct drm_encoder *encoder,
227f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez				struct drm_connector *connector)
228f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez{
229f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
230f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	struct drm_display_mode *output_mode = &tv_norm->ctv_enc_mode.mode;
231f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	struct drm_display_mode *mode;
232f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	const struct {
233f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		int hdisplay;
234f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		int vdisplay;
235f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	} modes[] = {
236f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		{ 640, 400 },
237f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		{ 640, 480 },
238f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		{ 720, 480 },
239f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		{ 720, 576 },
240f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		{ 800, 600 },
241f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		{ 1024, 768 },
242f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		{ 1280, 720 },
243f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		{ 1280, 1024 },
244f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		{ 1920, 1080 }
245f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	};
246f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	int i, n = 0;
247f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez
2486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	for (i = 0; i < ARRAY_SIZE(modes); i++) {
2496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (modes[i].hdisplay > output_mode->hdisplay ||
2506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		    modes[i].vdisplay > output_mode->vdisplay)
2516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			continue;
2526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (modes[i].hdisplay == output_mode->hdisplay &&
2546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		    modes[i].vdisplay == output_mode->vdisplay) {
2556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			mode = drm_mode_duplicate(encoder->dev, output_mode);
2566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			mode->type |= DRM_MODE_TYPE_PREFERRED;
257f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez
2586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		} else {
2596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			mode = drm_cvt_mode(encoder->dev, modes[i].hdisplay,
260f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez					    modes[i].vdisplay, 60, false,
261f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez					    (output_mode->flags &
262f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez					     DRM_MODE_FLAG_INTERLACE), false);
2636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
2646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		/* CVT modes are sometimes unsuitable... */
2666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (output_mode->hdisplay <= 720
2676ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		    || output_mode->hdisplay >= 1920) {
2686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			mode->htotal = output_mode->htotal;
2696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			mode->hsync_start = (mode->hdisplay + (mode->htotal
2706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					     - mode->hdisplay) * 9 / 10) & ~7;
2716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			mode->hsync_end = mode->hsync_start + 8;
2726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
273f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez
2746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (output_mode->vdisplay >= 1024) {
2756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			mode->vtotal = output_mode->vtotal;
2766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			mode->vsync_start = output_mode->vsync_start;
2776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			mode->vsync_end = output_mode->vsync_end;
2786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
2796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
2806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		mode->type |= DRM_MODE_TYPE_DRIVER;
2816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		drm_mode_probed_add(connector, mode);
2826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		n++;
2836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
284f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez
2856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	return n;
2866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
2876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
288f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerezstatic int nv17_tv_get_modes(struct drm_encoder *encoder,
289f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez			     struct drm_connector *connector)
290f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez{
291f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
292f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez
293f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	if (tv_norm->kind == CTV_ENC_MODE)
294f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		return nv17_tv_get_hd_modes(encoder, connector);
295f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez	else
296f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez		return nv17_tv_get_ld_modes(encoder, connector);
297f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez}
298f243423759271026ddc3f8ab12a16cc7abfabc49Francisco Jerez
2996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int nv17_tv_mode_valid(struct drm_encoder *encoder,
3006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			      struct drm_display_mode *mode)
3016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
3026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
3036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (tv_norm->kind == CTV_ENC_MODE) {
3056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		struct drm_display_mode *output_mode =
3066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs						&tv_norm->ctv_enc_mode.mode;
3076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (mode->clock > 400000)
3096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return MODE_CLOCK_HIGH;
3106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (mode->hdisplay > output_mode->hdisplay ||
3126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		    mode->vdisplay > output_mode->vdisplay)
3136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return MODE_BAD;
3146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if ((mode->flags & DRM_MODE_FLAG_INTERLACE) !=
3166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		    (output_mode->flags & DRM_MODE_FLAG_INTERLACE))
3176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return MODE_NO_INTERLACE;
3186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
3206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return MODE_NO_DBLESCAN;
3216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else {
3236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		const int vsync_tolerance = 600;
3246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (mode->clock > 70000)
3266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return MODE_CLOCK_HIGH;
3276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (abs(drm_mode_vrefresh(mode) * 1000 -
3296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_norm->tv_enc_mode.vrefresh) > vsync_tolerance)
3306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return MODE_VSYNC;
3316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		/* The encoder takes care of the actual interlacing */
3336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
3346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return MODE_NO_INTERLACE;
3356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
3366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	return MODE_OK;
3386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
3396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
3416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			       struct drm_display_mode *mode,
3426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			       struct drm_display_mode *adjusted_mode)
3436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
3446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
3456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3468ccfe9e098d5975ef65d17de477f6b7dc0c446dbFrancisco Jerez	if (nv04_dac_in_use(encoder))
3478ccfe9e098d5975ef65d17de477f6b7dc0c446dbFrancisco Jerez		return false;
3488ccfe9e098d5975ef65d17de477f6b7dc0c446dbFrancisco Jerez
3496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (tv_norm->kind == CTV_ENC_MODE)
3506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock;
3516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	else
3526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		adjusted_mode->clock = 90000;
3536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	return true;
3556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
3566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)
3586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
3596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_device *dev = encoder->dev;
3606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;
3616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
3626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (nouveau_encoder(encoder)->last_dpms == mode)
3646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		return;
3656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	nouveau_encoder(encoder)->last_dpms = mode;
3666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
367ef2bb506687a5f1cc8ef2fef370bb168b2808106Maarten Maathuis	NV_INFO(dev, "Setting dpms mode %d on TV encoder (output %d)\n",
3686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 mode, nouveau_encoder(encoder)->dcb->index);
3696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	regs->ptv_200 &= ~1;
3716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (tv_norm->kind == CTV_ENC_MODE) {
3736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		nv04_dfp_update_fp_control(encoder, mode);
3746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else {
3766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		nv04_dfp_update_fp_control(encoder, DRM_MODE_DPMS_OFF);
3776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (mode == DRM_MODE_DPMS_ON)
3796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			regs->ptv_200 |= 1;
3806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
3816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	nv_load_ptv(dev, regs, 200);
3836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
384a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs	nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON);
385a0b25635515ef5049f93b032a1e37f18b16e0f6fBen Skeggs	nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON);
3866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
3886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
3896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
3906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void nv17_tv_prepare(struct drm_encoder *encoder)
3916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
3926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_device *dev = encoder->dev;
3936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
3946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_encoder_helper_funcs *helper = encoder->helper_private;
3956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
3966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	int head = nouveau_crtc(encoder->crtc)->index;
3976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	uint8_t *cr_lcd = &dev_priv->mode_reg.crtc_reg[head].CRTC[
3986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs							NV_CIO_CRE_LCD__INDEX];
3996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	uint32_t dacclk_off = NV_PRAMDAC_DACCLK +
4006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					nv04_dac_output_offset(encoder);
4016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	uint32_t dacclk;
4026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	helper->dpms(encoder, DRM_MODE_DPMS_OFF);
4046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	nv04_dfp_disable(dev, head);
4066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* Unbind any FP encoders from this head if we need the FP
4086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	 * stuff enabled. */
4096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (tv_norm->kind == CTV_ENC_MODE) {
4106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		struct drm_encoder *enc;
4116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
4136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			struct dcb_entry *dcb = nouveau_encoder(enc)->dcb;
4146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			if ((dcb->type == OUTPUT_TMDS ||
4166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			     dcb->type == OUTPUT_LVDS) &&
4176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			     !enc->crtc &&
4186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			     nv04_dfp_get_bound_head(dev, dcb) == head) {
4196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				nv04_dfp_bind_head(dev, dcb, head ^ 1,
42004a39c577f4114a3f098ee8ef0e20f7778b5ddadBen Skeggs						dev_priv->vbios.fp.dual_link);
4216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			}
4226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
4236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
4256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
426217275d03d7e1f3e62c7b0d9718df99456b7c356Francisco Jerez	if (tv_norm->kind == CTV_ENC_MODE)
427cd2fb2e9e0a6a3273d353b18e4bdd21cc0482724Francisco Jerez		*cr_lcd |= 0x1 | (head ? 0x0 : 0x8);
4286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* Set the DACCLK register */
4306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1;
4316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (dev_priv->card_type == NV_40)
4336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		dacclk |= 0x1a << 16;
4346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (tv_norm->kind == CTV_ENC_MODE) {
4366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		dacclk |=  0x20;
4376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (head)
4396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			dacclk |= 0x100;
4406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		else
4416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			dacclk &= ~0x100;
4426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else {
4446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		dacclk |= 0x10;
4456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
4476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	NVWriteRAMDAC(dev, 0, dacclk_off, dacclk);
4496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
4506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void nv17_tv_mode_set(struct drm_encoder *encoder,
4526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			     struct drm_display_mode *drm_mode,
4536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			     struct drm_display_mode *adjusted_mode)
4546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
4556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_device *dev = encoder->dev;
4566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
4576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	int head = nouveau_crtc(encoder->crtc)->index;
4586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv04_crtc_reg *regs = &dev_priv->mode_reg.crtc_reg[head];
4596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_state *tv_regs = &to_tv_enc(encoder)->state;
4606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
4616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	int i;
4626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	regs->CRTC[NV_CIO_CRE_53] = 0x40; /* FP_HTIMING */
4646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	regs->CRTC[NV_CIO_CRE_54] = 0; /* FP_VTIMING */
4656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	regs->ramdac_630 = 0x2; /* turn off green mode (tv test pattern?) */
4666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	regs->tv_setup = 1;
4676ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	regs->ramdac_8c0 = 0x0;
4686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (tv_norm->kind == TV_ENC_MODE) {
4706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_regs->ptv_200 = 0x13111100;
4716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (head)
4726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->ptv_200 |= 0x10;
4736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_regs->ptv_20c = 0x808010;
4756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_regs->ptv_304 = 0x2d00000;
4766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_regs->ptv_600 = 0x0;
4776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_regs->ptv_60c = 0x0;
4786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_regs->ptv_610 = 0x1e00000;
4796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (tv_norm->tv_enc_mode.vdisplay == 576) {
4816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->ptv_508 = 0x1200000;
4826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->ptv_614 = 0x33;
4836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		} else if (tv_norm->tv_enc_mode.vdisplay == 480) {
4856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->ptv_508 = 0xf00000;
4866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->ptv_614 = 0x13;
4876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
4886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
4896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (dev_priv->card_type >= NV_30) {
4906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->ptv_500 = 0xe8e0;
4916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->ptv_504 = 0x1710;
4926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->ptv_604 = 0x0;
4936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->ptv_608 = 0x0;
4946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		} else {
4956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			if (tv_norm->tv_enc_mode.vdisplay == 576) {
4966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				tv_regs->ptv_604 = 0x20;
4976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				tv_regs->ptv_608 = 0x10;
4986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				tv_regs->ptv_500 = 0x19710;
4996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				tv_regs->ptv_504 = 0x68f0;
5006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			} else if (tv_norm->tv_enc_mode.vdisplay == 480) {
5026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				tv_regs->ptv_604 = 0x10;
5036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				tv_regs->ptv_608 = 0x20;
5046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				tv_regs->ptv_500 = 0x4b90;
5056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				tv_regs->ptv_504 = 0x1b480;
5066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			}
5076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
5086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		for (i = 0; i < 0x40; i++)
5106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			tv_regs->tv_enc[i] = tv_norm->tv_enc_mode.tv_enc[i];
5116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else {
5136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		struct drm_display_mode *output_mode =
5146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs						&tv_norm->ctv_enc_mode.mode;
5156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		/* The registers in PRAMDAC+0xc00 control some timings and CSC
5176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * parameters for the CTV encoder (It's only used for "HD" TV
5186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * modes, I don't think I have enough working to guess what
5196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * they exactly mean...), it's probably connected at the
5206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * output of the FP encoder, but it also needs the analog
5216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * encoder in its OR enabled and routed to the head it's
5226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * using. It's enabled with the DACCLK register, bits [5:4].
5236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 */
5246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		for (i = 0; i < 38; i++)
5256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			regs->ctv_regs[i] = tv_norm->ctv_enc_mode.ctv_regs[i];
5266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_horiz_regs[FP_DISPLAY_END] = output_mode->hdisplay - 1;
5286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_horiz_regs[FP_TOTAL] = output_mode->htotal - 1;
5296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_horiz_regs[FP_SYNC_START] =
5306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs						output_mode->hsync_start - 1;
5316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_horiz_regs[FP_SYNC_END] = output_mode->hsync_end - 1;
5326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_horiz_regs[FP_CRTC] = output_mode->hdisplay +
5336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			max((output_mode->hdisplay-600)/40 - 1, 1);
5346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_vert_regs[FP_DISPLAY_END] = output_mode->vdisplay - 1;
5366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_vert_regs[FP_TOTAL] = output_mode->vtotal - 1;
5376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_vert_regs[FP_SYNC_START] =
5386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs						output_mode->vsync_start - 1;
5396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_vert_regs[FP_SYNC_END] = output_mode->vsync_end - 1;
5406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_vert_regs[FP_CRTC] = output_mode->vdisplay - 1;
5416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_control = NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS |
5436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			NV_PRAMDAC_FP_TG_CONTROL_READ_PROG |
5446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			NV_PRAMDAC_FP_TG_CONTROL_WIDTH_12;
5456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (output_mode->flags & DRM_MODE_FLAG_PVSYNC)
5476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			regs->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS;
5486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (output_mode->flags & DRM_MODE_FLAG_PHSYNC)
5496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			regs->fp_control |= NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS;
5506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_debug_0 = NV_PRAMDAC_FP_DEBUG_0_YWEIGHT_ROUND |
5526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			NV_PRAMDAC_FP_DEBUG_0_XWEIGHT_ROUND |
5536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			NV_PRAMDAC_FP_DEBUG_0_YINTERP_BILINEAR |
5546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			NV_PRAMDAC_FP_DEBUG_0_XINTERP_BILINEAR |
5556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			NV_RAMDAC_FP_DEBUG_0_TMDS_ENABLED |
5566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			NV_PRAMDAC_FP_DEBUG_0_YSCALE_ENABLE |
5576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			NV_PRAMDAC_FP_DEBUG_0_XSCALE_ENABLE;
5586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_debug_2 = 0;
5606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		regs->fp_margin_color = 0x801080;
5626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
5646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
5656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void nv17_tv_commit(struct drm_encoder *encoder)
5676ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
5686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_device *dev = encoder->dev;
5696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_nouveau_private *dev_priv = dev->dev_private;
5706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
5716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
5726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_encoder_helper_funcs *helper = encoder->helper_private;
5736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (get_tv_norm(encoder)->kind == TV_ENC_MODE) {
5756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		nv17_tv_update_rescaler(encoder);
5766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		nv17_tv_update_properties(encoder);
5776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else {
5786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		nv17_ctv_update_rescaler(encoder);
5796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
5806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	nv17_tv_state_load(dev, &to_tv_enc(encoder)->state);
5826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	/* This could use refinement for flatpanels, but it should work */
5846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (dev_priv->chipset < 0x44)
5856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL +
5866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					nv04_dac_output_offset(encoder),
5876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					0xf0000000);
5886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	else
5896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL +
5906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					nv04_dac_output_offset(encoder),
5916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					0x00100000);
5926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	helper->dpms(encoder, DRM_MODE_DPMS_ON);
5946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
5956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
5966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		drm_get_connector_name(
5976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			&nouveau_encoder_connector_get(nv_encoder)->base),
5986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
5996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
6006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void nv17_tv_save(struct drm_encoder *encoder)
6026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
6036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_device *dev = encoder->dev;
6046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
6056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	nouveau_encoder(encoder)->restore.output =
6076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					NVReadRAMDAC(dev, 0,
6086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					NV_PRAMDAC_DACCLK +
6096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					nv04_dac_output_offset(encoder));
6106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	nv17_tv_state_save(dev, &tv_enc->saved_state);
6126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->state.ptv_200 = tv_enc->saved_state.ptv_200;
6146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
6156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void nv17_tv_restore(struct drm_encoder *encoder)
6176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
6186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_device *dev = encoder->dev;
6196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK +
6216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				nv04_dac_output_offset(encoder),
6226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				nouveau_encoder(encoder)->restore.output);
6236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	nv17_tv_state_load(dev, &to_tv_enc(encoder)->saved_state);
625bf929efa56ac174bf6d4f54cd6fe811181a51ae5Francisco Jerez
626bf929efa56ac174bf6d4f54cd6fe811181a51ae5Francisco Jerez	nouveau_encoder(encoder)->last_dpms = NV_DPMS_CLEARED;
6276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
6286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int nv17_tv_create_resources(struct drm_encoder *encoder,
6306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				    struct drm_connector *connector)
6316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
6326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_device *dev = encoder->dev;
6336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_mode_config *conf = &dev->mode_config;
6346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
6356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
6366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	int num_tv_norms = dcb->tvconf.has_component_output ? NUM_TV_NORMS :
6376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs							NUM_LD_TV_NORMS;
6386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	int i;
6396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (nouveau_tv_norm) {
6416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		for (i = 0; i < num_tv_norms; i++) {
6426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			if (!strcmp(nv17_tv_norm_names[i], nouveau_tv_norm)) {
6436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				tv_enc->tv_norm = i;
6446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				break;
6456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			}
6466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
6476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (i == num_tv_norms)
6496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			NV_WARN(dev, "Invalid TV norm setting \"%s\"\n",
6506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				nouveau_tv_norm);
6516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
6526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_mode_create_tv_properties(dev, num_tv_norms, nv17_tv_norm_names);
6546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_connector_attach_property(connector,
6566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					conf->tv_select_subconnector_property,
6576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					tv_enc->select_subconnector);
6586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_connector_attach_property(connector,
6596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					conf->tv_subconnector_property,
6606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					tv_enc->subconnector);
6616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_connector_attach_property(connector,
6626ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					conf->tv_mode_property,
6636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					tv_enc->tv_norm);
6646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_connector_attach_property(connector,
6656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					conf->tv_flicker_reduction_property,
6666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					tv_enc->flicker);
6676ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_connector_attach_property(connector,
6686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					conf->tv_saturation_property,
6696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					tv_enc->saturation);
6706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_connector_attach_property(connector,
6716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					conf->tv_hue_property,
6726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					tv_enc->hue);
6736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_connector_attach_property(connector,
6746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					conf->tv_overscan_property,
6756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs					tv_enc->overscan);
6766ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	return 0;
6786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
6796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic int nv17_tv_set_property(struct drm_encoder *encoder,
6816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				struct drm_connector *connector,
6826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				struct drm_property *property,
6836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				uint64_t val)
6846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
6856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_mode_config *conf = &encoder->dev->mode_config;
6866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_crtc *crtc = encoder->crtc;
6876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
6886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
6896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	bool modes_changed = false;
6906ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
6916ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (property == conf->tv_overscan_property) {
6926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_enc->overscan = val;
6936ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (encoder->crtc) {
6946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			if (tv_norm->kind == CTV_ENC_MODE)
6956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				nv17_ctv_update_rescaler(encoder);
6966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			else
6976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				nv17_tv_update_rescaler(encoder);
6986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
6996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else if (property == conf->tv_saturation_property) {
7016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (tv_norm->kind != TV_ENC_MODE)
7026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return -EINVAL;
7036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_enc->saturation = val;
7056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		nv17_tv_update_properties(encoder);
7066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else if (property == conf->tv_hue_property) {
7086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (tv_norm->kind != TV_ENC_MODE)
7096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return -EINVAL;
7106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_enc->hue = val;
7126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		nv17_tv_update_properties(encoder);
7136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else if (property == conf->tv_flicker_reduction_property) {
7156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (tv_norm->kind != TV_ENC_MODE)
7166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return -EINVAL;
7176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_enc->flicker = val;
7196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (encoder->crtc)
7206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			nv17_tv_update_rescaler(encoder);
7216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7226ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else if (property == conf->tv_mode_property) {
7236ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (connector->dpms != DRM_MODE_DPMS_OFF)
7246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return -EINVAL;
7256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7266ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_enc->tv_norm = val;
7276ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7286ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		modes_changed = true;
7296ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7306ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else if (property == conf->tv_select_subconnector_property) {
7316ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (tv_norm->kind != TV_ENC_MODE)
7326ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			return -EINVAL;
7336ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7346ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		tv_enc->select_subconnector = val;
7356ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		nv17_tv_update_properties(encoder);
7366ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7376ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	} else {
7386ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		return -EINVAL;
7396ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
7406ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7416ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (modes_changed) {
7426ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		drm_helper_probe_single_connector_modes(connector, 0, 0);
7436ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7446ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		/* Disable the crtc to ensure a full modeset is
7456ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		 * performed whenever it's turned on again. */
7466ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		if (crtc) {
7476ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			struct drm_mode_set modeset = {
7486ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs				.crtc = crtc,
7496ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			};
7506ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7516ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs			crtc->funcs->set_config(&modeset);
7526ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		}
7536ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	}
7546ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7556ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	return 0;
7566ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
7576ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7586ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic void nv17_tv_destroy(struct drm_encoder *encoder)
7596ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
7606ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
7616ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
762ef2bb506687a5f1cc8ef2fef370bb168b2808106Maarten Maathuis	NV_DEBUG_KMS(encoder->dev, "\n");
7636ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7646ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_encoder_cleanup(encoder);
7656ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	kfree(tv_enc);
7666ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
7676ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7686ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic struct drm_encoder_helper_funcs nv17_tv_helper_funcs = {
7696ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.dpms = nv17_tv_dpms,
7706ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.save = nv17_tv_save,
7716ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.restore = nv17_tv_restore,
7726ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.mode_fixup = nv17_tv_mode_fixup,
7736ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.prepare = nv17_tv_prepare,
7746ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.commit = nv17_tv_commit,
7756ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.mode_set = nv17_tv_mode_set,
77611d6eb2af53395b25e1d6b8b79bb9a999c3e4c4dFrancisco Jerez	.detect = nv17_tv_detect,
7776ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs};
7786ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7796ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic struct drm_encoder_slave_funcs nv17_tv_slave_funcs = {
7806ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.get_modes = nv17_tv_get_modes,
7816ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.mode_valid = nv17_tv_mode_valid,
7826ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.create_resources = nv17_tv_create_resources,
7836ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.set_property = nv17_tv_set_property,
7846ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs};
7856ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7866ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggsstatic struct drm_encoder_funcs nv17_tv_funcs = {
7876ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	.destroy = nv17_tv_destroy,
7886ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs};
7896ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7908f1a60868f4594bc5576cca8952635f475e8bec6Ben Skeggsint
7918f1a60868f4594bc5576cca8952635f475e8bec6Ben Skeggsnv17_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
7926ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs{
7938f1a60868f4594bc5576cca8952635f475e8bec6Ben Skeggs	struct drm_device *dev = connector->dev;
7946ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct drm_encoder *encoder;
7956ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	struct nv17_tv_encoder *tv_enc = NULL;
7966ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
7976ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc = kzalloc(sizeof(*tv_enc), GFP_KERNEL);
7986ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	if (!tv_enc)
7996ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs		return -ENOMEM;
8006ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
8016ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->overscan = 50;
8026ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->flicker = 50;
8036ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->saturation = 50;
8046ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->hue = 0;
8056ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->tv_norm = TV_NORM_PAL;
8066ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
8076ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->select_subconnector = DRM_MODE_SUBCONNECTOR_Automatic;
8086ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->pin_mask = 0;
8096ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
8106ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	encoder = to_drm_encoder(&tv_enc->base);
8116ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
8126ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->base.dcb = entry;
8136ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	tv_enc->base.or = ffs(entry->or) - 1;
8146ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
8156ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_encoder_init(dev, encoder, &nv17_tv_funcs, DRM_MODE_ENCODER_TVDAC);
8166ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	drm_encoder_helper_add(encoder, &nv17_tv_helper_funcs);
8176ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	to_encoder_slave(encoder)->slave_funcs = &nv17_tv_slave_funcs;
8186ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
8196ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	encoder->possible_crtcs = entry->heads;
8206ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	encoder->possible_clones = 0;
8216ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs
8228f1a60868f4594bc5576cca8952635f475e8bec6Ben Skeggs	nv17_tv_create_resources(encoder, connector);
8238f1a60868f4594bc5576cca8952635f475e8bec6Ben Skeggs	drm_mode_connector_attach_encoder(connector, encoder);
8246ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs	return 0;
8256ee738610f41b59733f63718f0bdbcba7d3a3f12Ben Skeggs}
826