1/* 2 * Copyright 2003 NVIDIA, Corporation 3 * Copyright 2006 Dave Airlie 4 * Copyright 2007 Maarten Maathuis 5 * Copyright 2007-2009 Stuart Bennett 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the next 15 * paragraph) shall be included in all copies or substantial portions of the 16 * Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 * DEALINGS IN THE SOFTWARE. 25 */ 26 27#include "drmP.h" 28#include "drm_crtc_helper.h" 29 30#include "nouveau_drv.h" 31#include "nouveau_encoder.h" 32#include "nouveau_connector.h" 33#include "nouveau_crtc.h" 34#include "nouveau_hw.h" 35#include "nvreg.h" 36 37int nv04_dac_output_offset(struct drm_encoder *encoder) 38{ 39 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 40 int offset = 0; 41 42 if (dcb->or & (8 | OUTPUT_C)) 43 offset += 0x68; 44 if (dcb->or & (8 | OUTPUT_B)) 45 offset += 0x2000; 46 47 return offset; 48} 49 50/* 51 * arbitrary limit to number of sense oscillations tolerated in one sample 52 * period (observed to be at least 13 in "nvidia") 53 */ 54#define MAX_HBLANK_OSC 20 55 56/* 57 * arbitrary limit to number of conflicting sample pairs to tolerate at a 58 * voltage step (observed to be at least 5 in "nvidia") 59 */ 60#define MAX_SAMPLE_PAIRS 10 61 62static int sample_load_twice(struct drm_device *dev, bool sense[2]) 63{ 64 int i; 65 66 for (i = 0; i < 2; i++) { 67 bool sense_a, sense_b, sense_b_prime; 68 int j = 0; 69 70 /* 71 * wait for bit 0 clear -- out of hblank -- (say reg value 0x4), 72 * then wait for transition 0x4->0x5->0x4: enter hblank, leave 73 * hblank again 74 * use a 10ms timeout (guards against crtc being inactive, in 75 * which case blank state would never change) 76 */ 77 if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR, 78 0x00000001, 0x00000000)) 79 return -EBUSY; 80 if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR, 81 0x00000001, 0x00000001)) 82 return -EBUSY; 83 if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR, 84 0x00000001, 0x00000000)) 85 return -EBUSY; 86 87 udelay(100); 88 /* when level triggers, sense is _LO_ */ 89 sense_a = nv_rd08(dev, NV_PRMCIO_INP0) & 0x10; 90 91 /* take another reading until it agrees with sense_a... */ 92 do { 93 udelay(100); 94 sense_b = nv_rd08(dev, NV_PRMCIO_INP0) & 0x10; 95 if (sense_a != sense_b) { 96 sense_b_prime = 97 nv_rd08(dev, NV_PRMCIO_INP0) & 0x10; 98 if (sense_b == sense_b_prime) { 99 /* ... unless two consecutive subsequent 100 * samples agree; sense_a is replaced */ 101 sense_a = sense_b; 102 /* force mis-match so we loop */ 103 sense_b = !sense_a; 104 } 105 } 106 } while ((sense_a != sense_b) && ++j < MAX_HBLANK_OSC); 107 108 if (j == MAX_HBLANK_OSC) 109 /* with so much oscillation, default to sense:LO */ 110 sense[i] = false; 111 else 112 sense[i] = sense_a; 113 } 114 115 return 0; 116} 117 118static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder, 119 struct drm_connector *connector) 120{ 121 struct drm_device *dev = encoder->dev; 122 uint8_t saved_seq1, saved_pi, saved_rpc1, saved_cr_mode; 123 uint8_t saved_palette0[3], saved_palette_mask; 124 uint32_t saved_rtest_ctrl, saved_rgen_ctrl; 125 int i; 126 uint8_t blue; 127 bool sense = true; 128 129 /* 130 * for this detection to work, there needs to be a mode set up on the 131 * CRTC. this is presumed to be the case 132 */ 133 134 if (nv_two_heads(dev)) 135 /* only implemented for head A for now */ 136 NVSetOwner(dev, 0); 137 138 saved_cr_mode = NVReadVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX); 139 NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode | 0x80); 140 141 saved_seq1 = NVReadVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX); 142 NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1 & ~0x20); 143 144 saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL); 145 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL, 146 saved_rtest_ctrl & ~NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF); 147 148 msleep(10); 149 150 saved_pi = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX); 151 NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, 152 saved_pi & ~(0x80 | MASK(NV_CIO_CRE_PIXEL_FORMAT))); 153 saved_rpc1 = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX); 154 NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1 & ~0xc0); 155 156 nv_wr08(dev, NV_PRMDIO_READ_MODE_ADDRESS, 0x0); 157 for (i = 0; i < 3; i++) 158 saved_palette0[i] = nv_rd08(dev, NV_PRMDIO_PALETTE_DATA); 159 saved_palette_mask = nv_rd08(dev, NV_PRMDIO_PIXEL_MASK); 160 nv_wr08(dev, NV_PRMDIO_PIXEL_MASK, 0); 161 162 saved_rgen_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL); 163 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL, 164 (saved_rgen_ctrl & ~(NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS | 165 NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM)) | 166 NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON); 167 168 blue = 8; /* start of test range */ 169 170 do { 171 bool sense_pair[2]; 172 173 nv_wr08(dev, NV_PRMDIO_WRITE_MODE_ADDRESS, 0); 174 nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, 0); 175 nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, 0); 176 /* testing blue won't find monochrome monitors. I don't care */ 177 nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, blue); 178 179 i = 0; 180 /* take sample pairs until both samples in the pair agree */ 181 do { 182 if (sample_load_twice(dev, sense_pair)) 183 goto out; 184 } while ((sense_pair[0] != sense_pair[1]) && 185 ++i < MAX_SAMPLE_PAIRS); 186 187 if (i == MAX_SAMPLE_PAIRS) 188 /* too much oscillation defaults to LO */ 189 sense = false; 190 else 191 sense = sense_pair[0]; 192 193 /* 194 * if sense goes LO before blue ramps to 0x18, monitor is not connected. 195 * ergo, if blue gets to 0x18, monitor must be connected 196 */ 197 } while (++blue < 0x18 && sense); 198 199out: 200 nv_wr08(dev, NV_PRMDIO_PIXEL_MASK, saved_palette_mask); 201 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL, saved_rgen_ctrl); 202 nv_wr08(dev, NV_PRMDIO_WRITE_MODE_ADDRESS, 0); 203 for (i = 0; i < 3; i++) 204 nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, saved_palette0[i]); 205 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL, saved_rtest_ctrl); 206 NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, saved_pi); 207 NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1); 208 NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1); 209 NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode); 210 211 if (blue == 0x18) { 212 NV_INFO(dev, "Load detected on head A\n"); 213 return connector_status_connected; 214 } 215 216 return connector_status_disconnected; 217} 218 219uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) 220{ 221 struct drm_device *dev = encoder->dev; 222 struct drm_nouveau_private *dev_priv = dev->dev_private; 223 struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; 224 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 225 uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); 226 uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, 227 saved_rtest_ctrl, saved_gpio0, saved_gpio1, temp, routput; 228 int head; 229 230#define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20) 231 if (dcb->type == OUTPUT_TV) { 232 testval = RGB_TEST_DATA(0xa0, 0xa0, 0xa0); 233 234 if (dev_priv->vbios.tvdactestval) 235 testval = dev_priv->vbios.tvdactestval; 236 } else { 237 testval = RGB_TEST_DATA(0x140, 0x140, 0x140); /* 0x94050140 */ 238 239 if (dev_priv->vbios.dactestval) 240 testval = dev_priv->vbios.dactestval; 241 } 242 243 saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); 244 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, 245 saved_rtest_ctrl & ~NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF); 246 247 saved_powerctrl_2 = nvReadMC(dev, NV_PBUS_POWERCTRL_2); 248 249 nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2 & 0xd7ffffff); 250 if (regoffset == 0x68) { 251 saved_powerctrl_4 = nvReadMC(dev, NV_PBUS_POWERCTRL_4); 252 nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf); 253 } 254 255 saved_gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1); 256 saved_gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0); 257 258 gpio->set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); 259 gpio->set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV); 260 261 msleep(4); 262 263 saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); 264 head = (saved_routput & 0x100) >> 8; 265 266 /* if there's a spare crtc, using it will minimise flicker */ 267 if (!(NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX) & 0xC0)) 268 head ^= 1; 269 270 /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */ 271 routput = (saved_routput & 0xfffffece) | head << 8; 272 273 if (dev_priv->card_type >= NV_40) { 274 if (dcb->type == OUTPUT_TV) 275 routput |= 0x1a << 16; 276 else 277 routput &= ~(0x1a << 16); 278 } 279 280 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, routput); 281 msleep(1); 282 283 temp = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); 284 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, temp | 1); 285 286 NVWriteRAMDAC(dev, head, NV_PRAMDAC_TESTPOINT_DATA, 287 NV_PRAMDAC_TESTPOINT_DATA_NOTBLANK | testval); 288 temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL); 289 NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL, 290 temp | NV_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED); 291 msleep(5); 292 293 sample = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); 294 295 temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL); 296 NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL, 297 temp & ~NV_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED); 298 NVWriteRAMDAC(dev, head, NV_PRAMDAC_TESTPOINT_DATA, 0); 299 300 /* bios does something more complex for restoring, but I think this is good enough */ 301 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, saved_routput); 302 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, saved_rtest_ctrl); 303 if (regoffset == 0x68) 304 nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); 305 nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); 306 307 gpio->set(dev, DCB_GPIO_TVDAC1, saved_gpio1); 308 gpio->set(dev, DCB_GPIO_TVDAC0, saved_gpio0); 309 310 return sample; 311} 312 313static enum drm_connector_status 314nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) 315{ 316 struct drm_device *dev = encoder->dev; 317 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 318 319 if (nv04_dac_in_use(encoder)) 320 return connector_status_disconnected; 321 322 if (nv17_dac_sample_load(encoder) & 323 NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { 324 NV_INFO(dev, "Load detected on output %c\n", 325 '@' + ffs(dcb->or)); 326 return connector_status_connected; 327 } else { 328 return connector_status_disconnected; 329 } 330} 331 332static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, 333 struct drm_display_mode *mode, 334 struct drm_display_mode *adjusted_mode) 335{ 336 if (nv04_dac_in_use(encoder)) 337 return false; 338 339 return true; 340} 341 342static void nv04_dac_prepare(struct drm_encoder *encoder) 343{ 344 struct drm_encoder_helper_funcs *helper = encoder->helper_private; 345 struct drm_device *dev = encoder->dev; 346 struct drm_nouveau_private *dev_priv = dev->dev_private; 347 int head = nouveau_crtc(encoder->crtc)->index; 348 struct nv04_crtc_reg *crtcstate = dev_priv->mode_reg.crtc_reg; 349 350 helper->dpms(encoder, DRM_MODE_DPMS_OFF); 351 352 nv04_dfp_disable(dev, head); 353 354 /* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f) 355 * at LCD__INDEX which we don't alter 356 */ 357 if (!(crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] & 0x44)) 358 crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] = 0; 359} 360 361 362static void nv04_dac_mode_set(struct drm_encoder *encoder, 363 struct drm_display_mode *mode, 364 struct drm_display_mode *adjusted_mode) 365{ 366 struct drm_device *dev = encoder->dev; 367 struct drm_nouveau_private *dev_priv = dev->dev_private; 368 int head = nouveau_crtc(encoder->crtc)->index; 369 370 if (nv_gf4_disp_arch(dev)) { 371 struct drm_encoder *rebind; 372 uint32_t dac_offset = nv04_dac_output_offset(encoder); 373 uint32_t otherdac; 374 375 /* bit 16-19 are bits that are set on some G70 cards, 376 * but don't seem to have much effect */ 377 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset, 378 head << 8 | NV_PRAMDAC_DACCLK_SEL_DACCLK); 379 /* force any other vga encoders to bind to the other crtc */ 380 list_for_each_entry(rebind, &dev->mode_config.encoder_list, head) { 381 if (rebind == encoder 382 || nouveau_encoder(rebind)->dcb->type != OUTPUT_ANALOG) 383 continue; 384 385 dac_offset = nv04_dac_output_offset(rebind); 386 otherdac = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset); 387 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset, 388 (otherdac & ~0x0100) | (head ^ 1) << 8); 389 } 390 } 391 392 /* This could use refinement for flatpanels, but it should work this way */ 393 if (dev_priv->chipset < 0x44) 394 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0xf0000000); 395 else 396 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); 397} 398 399static void nv04_dac_commit(struct drm_encoder *encoder) 400{ 401 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 402 struct drm_device *dev = encoder->dev; 403 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); 404 struct drm_encoder_helper_funcs *helper = encoder->helper_private; 405 406 helper->dpms(encoder, DRM_MODE_DPMS_ON); 407 408 NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", 409 drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), 410 nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); 411} 412 413void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) 414{ 415 struct drm_device *dev = encoder->dev; 416 struct drm_nouveau_private *dev_priv = dev->dev_private; 417 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 418 419 if (nv_gf4_disp_arch(dev)) { 420 uint32_t *dac_users = &dev_priv->dac_users[ffs(dcb->or) - 1]; 421 int dacclk_off = NV_PRAMDAC_DACCLK + nv04_dac_output_offset(encoder); 422 uint32_t dacclk = NVReadRAMDAC(dev, 0, dacclk_off); 423 424 if (enable) { 425 *dac_users |= 1 << dcb->index; 426 NVWriteRAMDAC(dev, 0, dacclk_off, dacclk | NV_PRAMDAC_DACCLK_SEL_DACCLK); 427 428 } else { 429 *dac_users &= ~(1 << dcb->index); 430 if (!*dac_users) 431 NVWriteRAMDAC(dev, 0, dacclk_off, 432 dacclk & ~NV_PRAMDAC_DACCLK_SEL_DACCLK); 433 } 434 } 435} 436 437/* Check if the DAC corresponding to 'encoder' is being used by 438 * someone else. */ 439bool nv04_dac_in_use(struct drm_encoder *encoder) 440{ 441 struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; 442 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 443 444 return nv_gf4_disp_arch(encoder->dev) && 445 (dev_priv->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index)); 446} 447 448static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) 449{ 450 struct drm_device *dev = encoder->dev; 451 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 452 453 if (nv_encoder->last_dpms == mode) 454 return; 455 nv_encoder->last_dpms = mode; 456 457 NV_INFO(dev, "Setting dpms mode %d on vga encoder (output %d)\n", 458 mode, nv_encoder->dcb->index); 459 460 nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); 461} 462 463static void nv04_dac_save(struct drm_encoder *encoder) 464{ 465 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 466 struct drm_device *dev = encoder->dev; 467 468 if (nv_gf4_disp_arch(dev)) 469 nv_encoder->restore.output = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + 470 nv04_dac_output_offset(encoder)); 471} 472 473static void nv04_dac_restore(struct drm_encoder *encoder) 474{ 475 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 476 struct drm_device *dev = encoder->dev; 477 478 if (nv_gf4_disp_arch(dev)) 479 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + nv04_dac_output_offset(encoder), 480 nv_encoder->restore.output); 481 482 nv_encoder->last_dpms = NV_DPMS_CLEARED; 483} 484 485static void nv04_dac_destroy(struct drm_encoder *encoder) 486{ 487 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 488 489 NV_DEBUG_KMS(encoder->dev, "\n"); 490 491 drm_encoder_cleanup(encoder); 492 kfree(nv_encoder); 493} 494 495static const struct drm_encoder_helper_funcs nv04_dac_helper_funcs = { 496 .dpms = nv04_dac_dpms, 497 .save = nv04_dac_save, 498 .restore = nv04_dac_restore, 499 .mode_fixup = nv04_dac_mode_fixup, 500 .prepare = nv04_dac_prepare, 501 .commit = nv04_dac_commit, 502 .mode_set = nv04_dac_mode_set, 503 .detect = nv04_dac_detect 504}; 505 506static const struct drm_encoder_helper_funcs nv17_dac_helper_funcs = { 507 .dpms = nv04_dac_dpms, 508 .save = nv04_dac_save, 509 .restore = nv04_dac_restore, 510 .mode_fixup = nv04_dac_mode_fixup, 511 .prepare = nv04_dac_prepare, 512 .commit = nv04_dac_commit, 513 .mode_set = nv04_dac_mode_set, 514 .detect = nv17_dac_detect 515}; 516 517static const struct drm_encoder_funcs nv04_dac_funcs = { 518 .destroy = nv04_dac_destroy, 519}; 520 521int 522nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry) 523{ 524 const struct drm_encoder_helper_funcs *helper; 525 struct nouveau_encoder *nv_encoder = NULL; 526 struct drm_device *dev = connector->dev; 527 struct drm_encoder *encoder; 528 529 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); 530 if (!nv_encoder) 531 return -ENOMEM; 532 533 encoder = to_drm_encoder(nv_encoder); 534 535 nv_encoder->dcb = entry; 536 nv_encoder->or = ffs(entry->or) - 1; 537 538 if (nv_gf4_disp_arch(dev)) 539 helper = &nv17_dac_helper_funcs; 540 else 541 helper = &nv04_dac_helper_funcs; 542 543 drm_encoder_init(dev, encoder, &nv04_dac_funcs, DRM_MODE_ENCODER_DAC); 544 drm_encoder_helper_add(encoder, helper); 545 546 encoder->possible_crtcs = entry->heads; 547 encoder->possible_clones = 0; 548 549 drm_mode_connector_attach_encoder(connector, encoder); 550 return 0; 551} 552