summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nv04_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv04_display.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv04_display.c90
1 files changed, 53 insertions, 37 deletions
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index c7898b4f6dfb..9e28cf772e3c 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -32,8 +32,6 @@
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
-#define MULTIPLE_ENCODERS(e) (e & (e - 1))
-
static void
nv04_display_store_initial_head_owner(struct drm_device *dev)
{
@@ -41,7 +39,7 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
if (dev_priv->chipset != 0x11) {
dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44);
- goto ownerknown;
+ return;
}
/* reading CR44 is broken on nv11, so we attempt to infer it */
@@ -52,8 +50,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
bool tvA = false;
bool tvB = false;
- NVLockVgaCrtcs(dev, false);
-
slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) &
0x80;
if (slaved_on_B)
@@ -66,8 +62,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) &
MASK(NV_CIO_CRE_LCD_LCD_SELECT));
- NVLockVgaCrtcs(dev, true);
-
if (slaved_on_A && !tvA)
dev_priv->crtc_owner = 0x0;
else if (slaved_on_B && !tvB)
@@ -79,14 +73,40 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
else
dev_priv->crtc_owner = 0x0;
}
+}
+
+int
+nv04_display_early_init(struct drm_device *dev)
+{
+ /* Make the I2C buses accessible. */
+ if (!nv_gf4_disp_arch(dev)) {
+ uint32_t pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
+
+ if (!(pmc_enable & 1))
+ nv_wr32(dev, NV03_PMC_ENABLE, pmc_enable | 1);
+ }
-ownerknown:
- NV_INFO(dev, "Initial CRTC_OWNER is %d\n", dev_priv->crtc_owner);
+ /* Unlock the VGA CRTCs. */
+ NVLockVgaCrtcs(dev, false);
+
+ /* Make sure the CRTCs aren't in slaved mode. */
+ if (nv_two_heads(dev)) {
+ nv04_display_store_initial_head_owner(dev);
+ NVSetOwner(dev, 0);
+ }
+
+ return 0;
+}
+
+void
+nv04_display_late_takedown(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (nv_two_heads(dev))
+ NVSetOwner(dev, dev_priv->crtc_owner);
- /* we need to ensure the heads are not tied henceforth, or reading any
- * 8 bit reg on head B will fail
- * setting a single arbitrary head solves that */
- NVSetOwner(dev, 0);
+ NVLockVgaCrtcs(dev, true);
}
int
@@ -94,14 +114,13 @@ nv04_display_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_table *dcb = &dev_priv->vbios.dcb;
+ struct drm_connector *connector, *ct;
struct drm_encoder *encoder;
struct drm_crtc *crtc;
int i, ret;
NV_DEBUG_KMS(dev, "\n");
- if (nv_two_heads(dev))
- nv04_display_store_initial_head_owner(dev);
nouveau_hw_save_vga_fonts(dev, 1);
drm_mode_config_init(dev);
@@ -132,19 +151,23 @@ nv04_display_create(struct drm_device *dev)
for (i = 0; i < dcb->entries; i++) {
struct dcb_entry *dcbent = &dcb->entry[i];
+ connector = nouveau_connector_create(dev, dcbent->connector);
+ if (IS_ERR(connector))
+ continue;
+
switch (dcbent->type) {
case OUTPUT_ANALOG:
- ret = nv04_dac_create(dev, dcbent);
+ ret = nv04_dac_create(connector, dcbent);
break;
case OUTPUT_LVDS:
case OUTPUT_TMDS:
- ret = nv04_dfp_create(dev, dcbent);
+ ret = nv04_dfp_create(connector, dcbent);
break;
case OUTPUT_TV:
if (dcbent->location == DCB_LOC_ON_CHIP)
- ret = nv17_tv_create(dev, dcbent);
+ ret = nv17_tv_create(connector, dcbent);
else
- ret = nv04_tv_create(dev, dcbent);
+ ret = nv04_tv_create(connector, dcbent);
break;
default:
NV_WARN(dev, "DCB type %d not known\n", dcbent->type);
@@ -155,12 +178,16 @@ nv04_display_create(struct drm_device *dev)
continue;
}
- for (i = 0; i < dcb->connector.entries; i++)
- nouveau_connector_create(dev, &dcb->connector.entry[i]);
+ list_for_each_entry_safe(connector, ct,
+ &dev->mode_config.connector_list, head) {
+ if (!connector->encoder_ids[0]) {
+ NV_WARN(dev, "%s has no encoders, removing\n",
+ drm_get_connector_name(connector));
+ connector->funcs->destroy(connector);
+ }
+ }
/* Save previous state */
- NVLockVgaCrtcs(dev, false);
-
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
crtc->funcs->save(crtc);
@@ -191,8 +218,6 @@ nv04_display_destroy(struct drm_device *dev)
}
/* Restore state */
- NVLockVgaCrtcs(dev, false);
-
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct drm_encoder_helper_funcs *func = encoder->helper_private;
@@ -207,15 +232,12 @@ nv04_display_destroy(struct drm_device *dev)
nouveau_hw_save_vga_fonts(dev, 0);
}
-void
-nv04_display_restore(struct drm_device *dev)
+int
+nv04_display_init(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_encoder *encoder;
struct drm_crtc *crtc;
- NVLockVgaCrtcs(dev, false);
-
/* meh.. modeset apparently doesn't setup all the regs and depends
* on pre-existing state, for now load the state of the card *before*
* nouveau was loaded, and then do a modeset.
@@ -233,12 +255,6 @@ nv04_display_restore(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
crtc->funcs->restore(crtc);
- if (nv_two_heads(dev)) {
- NV_INFO(dev, "Restoring CRTC_OWNER to %d.\n",
- dev_priv->crtc_owner);
- NVSetOwner(dev, dev_priv->crtc_owner);
- }
-
- NVLockVgaCrtcs(dev, true);
+ return 0;
}