diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv04_dac.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_dac.c | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c index 1cb19e3acb55..ea3627041ecf 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c | |||
@@ -220,6 +220,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) | |||
220 | { | 220 | { |
221 | struct drm_device *dev = encoder->dev; | 221 | struct drm_device *dev = encoder->dev; |
222 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 222 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
223 | struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; | ||
223 | struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; | 224 | struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; |
224 | uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); | 225 | uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); |
225 | uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, | 226 | uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, |
@@ -251,22 +252,21 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) | |||
251 | nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf); | 252 | nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf); |
252 | } | 253 | } |
253 | 254 | ||
254 | saved_gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1); | 255 | saved_gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1); |
255 | saved_gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0); | 256 | saved_gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0); |
256 | 257 | ||
257 | nv17_gpio_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); | 258 | gpio->set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); |
258 | nv17_gpio_set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV); | 259 | gpio->set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV); |
259 | 260 | ||
260 | msleep(4); | 261 | msleep(4); |
261 | 262 | ||
262 | saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); | 263 | saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); |
263 | head = (saved_routput & 0x100) >> 8; | 264 | head = (saved_routput & 0x100) >> 8; |
264 | #if 0 | 265 | |
265 | /* if there's a spare crtc, using it will minimise flicker for the case | 266 | /* if there's a spare crtc, using it will minimise flicker */ |
266 | * where the in-use crtc is in use by an off-chip tmds encoder */ | 267 | if (!(NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX) & 0xC0)) |
267 | if (xf86_config->crtc[head]->enabled && !xf86_config->crtc[head ^ 1]->enabled) | ||
268 | head ^= 1; | 268 | head ^= 1; |
269 | #endif | 269 | |
270 | /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */ | 270 | /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */ |
271 | routput = (saved_routput & 0xfffffece) | head << 8; | 271 | routput = (saved_routput & 0xfffffece) | head << 8; |
272 | 272 | ||
@@ -304,8 +304,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) | |||
304 | nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); | 304 | nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); |
305 | nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); | 305 | nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); |
306 | 306 | ||
307 | nv17_gpio_set(dev, DCB_GPIO_TVDAC1, saved_gpio1); | 307 | gpio->set(dev, DCB_GPIO_TVDAC1, saved_gpio1); |
308 | nv17_gpio_set(dev, DCB_GPIO_TVDAC0, saved_gpio0); | 308 | gpio->set(dev, DCB_GPIO_TVDAC0, saved_gpio0); |
309 | 309 | ||
310 | return sample; | 310 | return sample; |
311 | } | 311 | } |
@@ -315,9 +315,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) | |||
315 | { | 315 | { |
316 | struct drm_device *dev = encoder->dev; | 316 | struct drm_device *dev = encoder->dev; |
317 | struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; | 317 | struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; |
318 | uint32_t sample = nv17_dac_sample_load(encoder); | ||
319 | 318 | ||
320 | if (sample & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { | 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) { | ||
321 | NV_INFO(dev, "Load detected on output %c\n", | 324 | NV_INFO(dev, "Load detected on output %c\n", |
322 | '@' + ffs(dcb->or)); | 325 | '@' + ffs(dcb->or)); |
323 | return connector_status_connected; | 326 | return connector_status_connected; |
@@ -330,6 +333,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, | |||
330 | struct drm_display_mode *mode, | 333 | struct drm_display_mode *mode, |
331 | struct drm_display_mode *adjusted_mode) | 334 | struct drm_display_mode *adjusted_mode) |
332 | { | 335 | { |
336 | if (nv04_dac_in_use(encoder)) | ||
337 | return false; | ||
338 | |||
333 | return true; | 339 | return true; |
334 | } | 340 | } |
335 | 341 | ||
@@ -428,6 +434,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) | |||
428 | } | 434 | } |
429 | } | 435 | } |
430 | 436 | ||
437 | /* Check if the DAC corresponding to 'encoder' is being used by | ||
438 | * someone else. */ | ||
439 | bool 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 | |||
431 | static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) | 448 | static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) |
432 | { | 449 | { |
433 | struct drm_device *dev = encoder->dev; | 450 | struct drm_device *dev = encoder->dev; |
@@ -501,11 +518,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = { | |||
501 | .destroy = nv04_dac_destroy, | 518 | .destroy = nv04_dac_destroy, |
502 | }; | 519 | }; |
503 | 520 | ||
504 | int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) | 521 | int |
522 | nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry) | ||
505 | { | 523 | { |
506 | const struct drm_encoder_helper_funcs *helper; | 524 | const struct drm_encoder_helper_funcs *helper; |
507 | struct drm_encoder *encoder; | ||
508 | struct nouveau_encoder *nv_encoder = NULL; | 525 | struct nouveau_encoder *nv_encoder = NULL; |
526 | struct drm_device *dev = connector->dev; | ||
527 | struct drm_encoder *encoder; | ||
509 | 528 | ||
510 | nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); | 529 | nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); |
511 | if (!nv_encoder) | 530 | if (!nv_encoder) |
@@ -527,5 +546,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) | |||
527 | encoder->possible_crtcs = entry->heads; | 546 | encoder->possible_crtcs = entry->heads; |
528 | encoder->possible_clones = 0; | 547 | encoder->possible_clones = 0; |
529 | 548 | ||
549 | drm_mode_connector_attach_encoder(connector, encoder); | ||
530 | return 0; | 550 | return 0; |
531 | } | 551 | } |