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 "nouveau_gpio.h" 36#include "nvreg.h" 37 38int nv04_dac_output_offset(struct drm_encoder *encoder) 39{ 40 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 41 int offset = 0; 42 43 if (dcb->or & (8 | OUTPUT_C)) 44 offset += 0x68; 45 if (dcb->or & (8 | OUTPUT_B)) 46 offset += 0x2000; 47 48 return offset; 49} 50 51/* 52 * arbitrary limit to number of sense oscillations tolerated in one sample 53 * period (observed to be at least 13 in "nvidia") 54 */ 55#define MAX_HBLANK_OSC 20 56 57/* 58 * arbitrary limit to number of conflicting sample pairs to tolerate at a 59 * voltage step (observed to be at least 5 in "nvidia") 60 */ 61#define MAX_SAMPLE_PAIRS 10 62 63static int sample_load_twice(struct drm_device *dev, bool sense[2]) 64{ 65 int i; 66 67 for (i = 0; i < 2; i++) { 68 bool sense_a, sense_b, sense_b_prime; 69 int j = 0; 70 71 /* 72 * wait for bit 0 clear -- out of hblank -- (say reg value 0x4), 73 * then wait for transition 0x4->0x5->0x4: enter hblank, leave 74 * hblank again 75 * use a 10ms timeout (guards against crtc being inactive, in 76 * which case blank state would never change) 77 */ 78 if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR, 79 0x00000001, 0x00000000)) 80 return -EBUSY; 81 if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR, 82 0x00000001, 0x00000001)) 83 return -EBUSY; 84 if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR, 85 0x00000001, 0x00000000)) 86 return -EBUSY; 87 88 udelay(100); 89 /* when level triggers, sense is _LO_ */ 90 sense_a = nv_rd08(dev, NV_PRMCIO_INP0) & 0x10; 91 92 /* take another reading until it agrees with sense_a... */ 93 do { 94 udelay(100); 95 sense_b = nv_rd08(dev, NV_PRMCIO_INP0) & 0x10; 96 if (sense_a != sense_b) { 97 sense_b_prime = 98 nv_rd08(dev, NV_PRMCIO_INP0) & 0x10; 99 if (sense_b == sense_b_prime) { 100 /* ... unless two consecutive subsequent 101 * samples agree; sense_a is replaced */ 102 sense_a = sense_b; 103 /* force mis-match so we loop */ 104 sense_b = !sense_a; 105 } 106 } 107 } while ((sense_a != sense_b) && ++j < MAX_HBLANK_OSC); 108 109 if (j == MAX_HBLANK_OSC) 110 /* with so much oscillation, default to sense:LO */ 111 sense[i] = false; 112 else 113 sense[i] = sense_a; 114 } 115 116 return 0; 117} 118 119static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder, 120 struct drm_connector *connector) 121{ 122 struct drm_device *dev = encoder->dev; 123 uint8_t saved_seq1, saved_pi, saved_rpc1, saved_cr_mode; 124 uint8_t saved_palette0[3], saved_palette_mask; 125 uint32_t saved_rtest_ctrl, saved_rgen_ctrl; 126 int i; 127 uint8_t blue; 128 bool sense = true; 129 130 /* 131 * for this detection to work, there needs to be a mode set up on the 132 * CRTC. this is presumed to be the case 133 */ 134 135 if (nv_two_heads(dev)) 136 /* only implemented for head A for now */ 137 NVSetOwner(dev, 0); 138 139 saved_cr_mode = NVReadVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX); 140 NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode | 0x80); 141 142 saved_seq1 = NVReadVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX); 143 NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1 & ~0x20); 144 145 saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL); 146 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL, 147 saved_rtest_ctrl & ~NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF); 148 149 msleep(10); 150 151 saved_pi = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX); 152 NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, 153 saved_pi & ~(0x80 | MASK(NV_CIO_CRE_PIXEL_FORMAT))); 154 saved_rpc1 = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX); 155 NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1 & ~0xc0); 156 157 nv_wr08(dev, NV_PRMDIO_READ_MODE_ADDRESS, 0x0); 158 for (i = 0; i < 3; i++) 159 saved_palette0[i] = nv_rd08(dev, NV_PRMDIO_PALETTE_DATA); 160 saved_palette_mask = nv_rd08(dev, NV_PRMDIO_PIXEL_MASK); 161 nv_wr08(dev, NV_PRMDIO_PIXEL_MASK, 0); 162 163 saved_rgen_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL); 164 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL, 165 (saved_rgen_ctrl & ~(NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS | 166 NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM)) | 167 NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON); 168 169 blue = 8; /* start of test range */ 170 171 do { 172 bool sense_pair[2]; 173 174 nv_wr08(dev, NV_PRMDIO_WRITE_MODE_ADDRESS, 0); 175 nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, 0); 176 nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, 0); 177 /* testing blue won't find monochrome monitors. I don't care */ 178 nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, blue); 179 180 i = 0; 181 /* take sample pairs until both samples in the pair agree */ 182 do { 183 if (sample_load_twice(dev, sense_pair)) 184 goto out; 185 } while ((sense_pair[0] != sense_pair[1]) && 186 ++i < MAX_SAMPLE_PAIRS); 187 188 if (i == MAX_SAMPLE_PAIRS) 189 /* too much oscillation defaults to LO */ 190 sense = false; 191 else 192 sense = sense_pair[0]; 193 194 /* 195 * if sense goes LO before blue ramps to 0x18, monitor is not connected. 196 * ergo, if blue gets to 0x18, monitor must be connected 197 */ 198 } while (++blue < 0x18 && sense); 199 200out: 201 nv_wr08(dev, NV_PRMDIO_PIXEL_MASK, saved_palette_mask); 202 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL, saved_rgen_ctrl); 203 nv_wr08(dev, NV_PRMDIO_WRITE_MODE_ADDRESS, 0); 204 for (i = 0; i < 3; i++) 205 nv_wr08(dev, NV_PRMDIO_PALETTE_DATA, saved_palette0[i]); 206 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL, saved_rtest_ctrl); 207 NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, saved_pi); 208 NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1); 209 NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1); 210 NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode); 211 212 if (blue == 0x18) { 213 NV_INFO(dev, "Load detected on head A\n"); 214 return connector_status_connected; 215 } 216 217 return connector_status_disconnected; 218} 219 220uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) 221{ 222 struct drm_device *dev = encoder->dev; 223 struct drm_nouveau_private *dev_priv = dev->dev_private; 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 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC1); 256 saved_gpio0 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC0); 257 258 nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); 259 nouveau_gpio_func_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 /* do it again just in case it's a residual current */ 295 sample &= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); 296 297 temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL); 298 NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL, 299 temp & ~NV_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED); 300 NVWriteRAMDAC(dev, head, NV_PRAMDAC_TESTPOINT_DATA, 0); 301 302 /* bios does something more complex for restoring, but I think this is good enough */ 303 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, saved_routput); 304 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, saved_rtest_ctrl); 305 if (regoffset == 0x68) 306 nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); 307 nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); 308 309 nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, saved_gpio1); 310 nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, saved_gpio0); 311 312 return sample; 313} 314 315static enum drm_connector_status 316nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) 317{ 318 struct drm_device *dev = encoder->dev; 319 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 320 321 if (nv04_dac_in_use(encoder)) 322 return connector_status_disconnected; 323 324 if (nv17_dac_sample_load(encoder) & 325 NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { 326 NV_INFO(dev, "Load detected on output %c\n", 327 '@' + ffs(dcb->or)); 328 return connector_status_connected; 329 } else { 330 return connector_status_disconnected; 331 } 332} 333 334static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, 335 struct drm_display_mode *mode, 336 struct drm_display_mode *adjusted_mode) 337{ 338 if (nv04_dac_in_use(encoder)) 339 return false; 340 341 return true; 342} 343 344static void nv04_dac_prepare(struct drm_encoder *encoder) 345{ 346 struct drm_encoder_helper_funcs *helper = encoder->helper_private; 347 struct drm_device *dev = encoder->dev; 348 int head = nouveau_crtc(encoder->crtc)->index; 349 350 helper->dpms(encoder, DRM_MODE_DPMS_OFF); 351 352 nv04_dfp_disable(dev, head); 353} 354 355static void nv04_dac_mode_set(struct drm_encoder *encoder, 356 struct drm_display_mode *mode, 357 struct drm_display_mode *adjusted_mode) 358{ 359 struct drm_device *dev = encoder->dev; 360 struct drm_nouveau_private *dev_priv = dev->dev_private; 361 int head = nouveau_crtc(encoder->crtc)->index; 362 363 if (nv_gf4_disp_arch(dev)) { 364 struct drm_encoder *rebind; 365 uint32_t dac_offset = nv04_dac_output_offset(encoder); 366 uint32_t otherdac; 367 368 /* bit 16-19 are bits that are set on some G70 cards, 369 * but don't seem to have much effect */ 370 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset, 371 head << 8 | NV_PRAMDAC_DACCLK_SEL_DACCLK); 372 /* force any other vga encoders to bind to the other crtc */ 373 list_for_each_entry(rebind, &dev->mode_config.encoder_list, head) { 374 if (rebind == encoder 375 || nouveau_encoder(rebind)->dcb->type != OUTPUT_ANALOG) 376 continue; 377 378 dac_offset = nv04_dac_output_offset(rebind); 379 otherdac = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset); 380 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset, 381 (otherdac & ~0x0100) | (head ^ 1) << 8); 382 } 383 } 384 385 /* This could use refinement for flatpanels, but it should work this way */ 386 if (dev_priv->chipset < 0x44) 387 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0xf0000000); 388 else 389 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); 390} 391 392static void nv04_dac_commit(struct drm_encoder *encoder) 393{ 394 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 395 struct drm_device *dev = encoder->dev; 396 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); 397 struct drm_encoder_helper_funcs *helper = encoder->helper_private; 398 399 helper->dpms(encoder, DRM_MODE_DPMS_ON); 400 401 NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", 402 drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), 403 nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); 404} 405 406void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) 407{ 408 struct drm_device *dev = encoder->dev; 409 struct drm_nouveau_private *dev_priv = dev->dev_private; 410 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 411 412 if (nv_gf4_disp_arch(dev)) { 413 uint32_t *dac_users = &dev_priv->dac_users[ffs(dcb->or) - 1]; 414 int dacclk_off = NV_PRAMDAC_DACCLK + nv04_dac_output_offset(encoder); 415 uint32_t dacclk = NVReadRAMDAC(dev, 0, dacclk_off); 416 417 if (enable) { 418 *dac_users |= 1 << dcb->index; 419 NVWriteRAMDAC(dev, 0, dacclk_off, dacclk | NV_PRAMDAC_DACCLK_SEL_DACCLK); 420 421 } else { 422 *dac_users &= ~(1 << dcb->index); 423 if (!*dac_users) 424 NVWriteRAMDAC(dev, 0, dacclk_off, 425 dacclk & ~NV_PRAMDAC_DACCLK_SEL_DACCLK); 426 } 427 } 428} 429 430/* Check if the DAC corresponding to 'encoder' is being used by 431 * someone else. */ 432bool nv04_dac_in_use(struct drm_encoder *encoder) 433{ 434 struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; 435 struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; 436 437 return nv_gf4_disp_arch(encoder->dev) && 438 (dev_priv->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index)); 439} 440 441static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) 442{ 443 struct drm_device *dev = encoder->dev; 444 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 445 446 if (nv_encoder->last_dpms == mode) 447 return; 448 nv_encoder->last_dpms = mode; 449 450 NV_INFO(dev, "Setting dpms mode %d on vga encoder (output %d)\n", 451 mode, nv_encoder->dcb->index); 452 453 nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); 454} 455 456static void nv04_dac_save(struct drm_encoder *encoder) 457{ 458 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 459 struct drm_device *dev = encoder->dev; 460 461 if (nv_gf4_disp_arch(dev)) 462 nv_encoder->restore.output = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + 463 nv04_dac_output_offset(encoder)); 464} 465 466static void nv04_dac_restore(struct drm_encoder *encoder) 467{ 468 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 469 struct drm_device *dev = encoder->dev; 470 471 if (nv_gf4_disp_arch(dev)) 472 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + nv04_dac_output_offset(encoder), 473 nv_encoder->restore.output); 474 475 nv_encoder->last_dpms = NV_DPMS_CLEARED; 476} 477 478static void nv04_dac_destroy(struct drm_encoder *encoder) 479{ 480 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 481 482 NV_DEBUG_KMS(encoder->dev, "\n"); 483 484 drm_encoder_cleanup(encoder); 485 kfree(nv_encoder); 486} 487 488static const struct drm_encoder_helper_funcs nv04_dac_helper_funcs = { 489 .dpms = nv04_dac_dpms, 490 .save = nv04_dac_save, 491 .restore = nv04_dac_restore, 492 .mode_fixup = nv04_dac_mode_fixup, 493 .prepare = nv04_dac_prepare, 494 .commit = nv04_dac_commit, 495 .mode_set = nv04_dac_mode_set, 496 .detect = nv04_dac_detect 497}; 498 499static const struct drm_encoder_helper_funcs nv17_dac_helper_funcs = { 500 .dpms = nv04_dac_dpms, 501 .save = nv04_dac_save, 502 .restore = nv04_dac_restore, 503 .mode_fixup = nv04_dac_mode_fixup, 504 .prepare = nv04_dac_prepare, 505 .commit = nv04_dac_commit, 506 .mode_set = nv04_dac_mode_set, 507 .detect = nv17_dac_detect 508}; 509 510static const struct drm_encoder_funcs nv04_dac_funcs = { 511 .destroy = nv04_dac_destroy, 512}; 513 514int 515nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry) 516{ 517 const struct drm_encoder_helper_funcs *helper; 518 struct nouveau_encoder *nv_encoder = NULL; 519 struct drm_device *dev = connector->dev; 520 struct drm_encoder *encoder; 521 522 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); 523 if (!nv_encoder) 524 return -ENOMEM; 525 526 encoder = to_drm_encoder(nv_encoder); 527 528 nv_encoder->dcb = entry; 529 nv_encoder->or = ffs(entry->or) - 1; 530 531 if (nv_gf4_disp_arch(dev)) 532 helper = &nv17_dac_helper_funcs; 533 else 534 helper = &nv04_dac_helper_funcs; 535 536 drm_encoder_init(dev, encoder, &nv04_dac_funcs, DRM_MODE_ENCODER_DAC); 537 drm_encoder_helper_add(encoder, helper); 538 539 encoder->possible_crtcs = entry->heads; 540 encoder->possible_clones = 0; 541 542 drm_mode_connector_attach_encoder(connector, encoder); 543 return 0; 544} 545