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