drm/nouveau: tidy connector/encoder creation a little
authorBen Skeggs <bskeggs@redhat.com>
Mon, 28 Jun 2010 04:35:50 +0000 (14:35 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 13 Jul 2010 00:13:09 +0000 (10:13 +1000)
Create connectors before encoders to avoid having to do another loop across
encoder list whenever we create a new connector.  This allows us to pass
the connector to the encoder creation functions, and avoid using a
create_resources() callback since we can now call it directly.

This can also potentially modify the connector ordering on nv50.  On cards
where the DCB connector and encoder tables are in the same order, things
will be unchanged.  However, there's some cards where the ordering between
the tables differ, and in one case, leads us to naming the connectors
"wrongly".

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
13 files changed:
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_encoder.h
drivers/gpu/drm/nouveau/nv04_dac.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_display.c
drivers/gpu/drm/nouveau/nv04_tv.c
drivers/gpu/drm/nouveau/nv17_tv.c
drivers/gpu/drm/nouveau/nv50_dac.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_sor.c

index adf4ec2d06c0cd7086ce327bb8a71c87fe1b9dd2..bd33a54f7deb75643e743a02623c687bf820f7cd 100644 (file)
@@ -81,6 +81,7 @@ struct dcb_connector_table_entry {
        enum dcb_connector_type type;
        uint8_t index2;
        uint8_t gpio_tag;
+       void *drm;
 };
 
 struct dcb_connector_table {
index 53700f8cd499f8baad9bb573b4282c8eabf4af5f..13f2e1ea2d796616ee2e28a9479ed6c66eb8b595 100644 (file)
@@ -729,66 +729,62 @@ nouveau_connector_funcs_lvds = {
        .force = nouveau_connector_force
 };
 
-int
-nouveau_connector_create(struct drm_device *dev,
-                        struct dcb_connector_table_entry *dcb)
+struct drm_connector *
+nouveau_connector_create(struct drm_device *dev, int index)
 {
        const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_connector *nv_connector = NULL;
+       struct dcb_connector_table_entry *dcb = NULL;
        struct drm_connector *connector;
-       struct drm_encoder *encoder;
        int type, ret = 0;
 
        NV_DEBUG_KMS(dev, "\n");
 
+       if (index >= dev_priv->vbios.dcb.connector.entries)
+               return ERR_PTR(-EINVAL);
+
+       dcb = &dev_priv->vbios.dcb.connector.entry[index];
+       if (dcb->drm)
+               return dcb->drm;
+
        switch (dcb->type) {
-       case DCB_CONNECTOR_NONE:
-               return 0;
        case DCB_CONNECTOR_VGA:
-               NV_INFO(dev, "Detected a VGA connector\n");
                type = DRM_MODE_CONNECTOR_VGA;
                break;
        case DCB_CONNECTOR_TV_0:
        case DCB_CONNECTOR_TV_1:
        case DCB_CONNECTOR_TV_3:
-               NV_INFO(dev, "Detected a TV connector\n");
                type = DRM_MODE_CONNECTOR_TV;
                break;
        case DCB_CONNECTOR_DVI_I:
-               NV_INFO(dev, "Detected a DVI-I connector\n");
                type = DRM_MODE_CONNECTOR_DVII;
                break;
        case DCB_CONNECTOR_DVI_D:
-               NV_INFO(dev, "Detected a DVI-D connector\n");
                type = DRM_MODE_CONNECTOR_DVID;
                break;
        case DCB_CONNECTOR_HDMI_0:
        case DCB_CONNECTOR_HDMI_1:
-               NV_INFO(dev, "Detected a HDMI connector\n");
                type = DRM_MODE_CONNECTOR_HDMIA;
                break;
        case DCB_CONNECTOR_LVDS:
-               NV_INFO(dev, "Detected a LVDS connector\n");
                type = DRM_MODE_CONNECTOR_LVDS;
                funcs = &nouveau_connector_funcs_lvds;
                break;
        case DCB_CONNECTOR_DP:
-               NV_INFO(dev, "Detected a DisplayPort connector\n");
                type = DRM_MODE_CONNECTOR_DisplayPort;
                break;
        case DCB_CONNECTOR_eDP:
-               NV_INFO(dev, "Detected an eDP connector\n");
                type = DRM_MODE_CONNECTOR_eDP;
                break;
        default:
                NV_ERROR(dev, "unknown connector type: 0x%02x!!\n", dcb->type);
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
        }
 
        nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
        if (!nv_connector)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
        nv_connector->dcb = dcb;
        connector = &nv_connector->base;
 
@@ -799,24 +795,6 @@ nouveau_connector_create(struct drm_device *dev,
        drm_connector_init(dev, connector, funcs, type);
        drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
 
-       /* attach encoders */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-
-               if (nv_encoder->dcb->connector != dcb->index)
-                       continue;
-
-               if (get_slave_funcs(nv_encoder))
-                       get_slave_funcs(nv_encoder)->create_resources(encoder, connector);
-
-               drm_mode_connector_attach_encoder(connector, encoder);
-       }
-
-       if (!connector->encoder_ids[0]) {
-               NV_WARN(dev, "  no encoders, ignoring\n");
-               goto fail;
-       }
-
        /* Check if we need dithering enabled */
        if (dcb->type == DCB_CONNECTOR_LVDS) {
                bool dummy, is_24bit = false;
@@ -877,11 +855,12 @@ nouveau_connector_create(struct drm_device *dev,
        }
 
        drm_sysfs_connector_add(connector);
-       return 0;
+       dcb->drm = connector;
+       return dcb->drm;
 
 fail:
        drm_connector_cleanup(connector);
        kfree(connector);
-       return ret;
+       return ERR_PTR(ret);
 
 }
index 4ef38abc2d9cfa85b2f569b22e01d4c3f596c753..1ce3d913867e2a6713275f5bf569311fa045db0f 100644 (file)
@@ -49,7 +49,7 @@ static inline struct nouveau_connector *nouveau_connector(
        return container_of(con, struct nouveau_connector, base);
 }
 
-int nouveau_connector_create(struct drm_device *,
-                            struct dcb_connector_table_entry *);
+struct drm_connector *
+nouveau_connector_create(struct drm_device *, int index);
 
 #endif /* __NOUVEAU_CONNECTOR_H__ */
index 20c54884dcb784162aaede75e06468ba13eeadd3..e3c8bd4f99c94ec200a9abae7fdeb4b110f0fe02 100644 (file)
@@ -1072,13 +1072,13 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd,
                                 unsigned long arg);
 
 /* nv04_dac.c */
-extern int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry);
+extern int nv04_dac_create(struct drm_connector *, struct dcb_entry *);
 extern uint32_t nv17_dac_sample_load(struct drm_encoder *encoder);
 extern int nv04_dac_output_offset(struct drm_encoder *encoder);
 extern void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable);
 
 /* nv04_dfp.c */
-extern int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry);
+extern int nv04_dfp_create(struct drm_connector *, struct dcb_entry *);
 extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent);
 extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent,
                               int head, bool dl);
@@ -1087,10 +1087,10 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode);
 
 /* nv04_tv.c */
 extern int nv04_tv_identify(struct drm_device *dev, int i2c_index);
-extern int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry);
+extern int nv04_tv_create(struct drm_connector *, struct dcb_entry *);
 
 /* nv17_tv.c */
-extern int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry);
+extern int nv17_tv_create(struct drm_connector *, struct dcb_entry *);
 
 /* nv04_display.c */
 extern int nv04_display_create(struct drm_device *);
index e1df8209cd0f58424c41fea37c4758801e1f4aad..e4442e28b568f839a04f363bdfe2d287a0bd825a 100644 (file)
@@ -71,8 +71,8 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
 
 struct nouveau_connector *
 nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
-int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry);
-int nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry);
+int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
+int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
 
 struct bit_displayport_encoder_table {
        uint32_t match;
index 1cb19e3acb554a998765c98a4aa31c708cd36caf..8066c56afa34522d48d3768f20080533315c0c02 100644 (file)
@@ -501,11 +501,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = {
        .destroy = nv04_dac_destroy,
 };
 
-int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry)
+int
+nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
 {
        const struct drm_encoder_helper_funcs *helper;
-       struct drm_encoder *encoder;
        struct nouveau_encoder *nv_encoder = NULL;
+       struct drm_device *dev = connector->dev;
+       struct drm_encoder *encoder;
 
        nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
        if (!nv_encoder)
@@ -527,5 +529,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry)
        encoder->possible_crtcs = entry->heads;
        encoder->possible_clones = 0;
 
+       drm_mode_connector_attach_encoder(connector, encoder);
        return 0;
 }
index 41634d4752fe08f6309d81c0b81ff0b7a65cc64f..3559d8972c74c359373d75691bbb7e70a28359db 100644 (file)
@@ -584,11 +584,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = {
        .destroy = nv04_dfp_destroy,
 };
 
-int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry)
+int
+nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry)
 {
        const struct drm_encoder_helper_funcs *helper;
-       struct drm_encoder *encoder;
        struct nouveau_encoder *nv_encoder = NULL;
+       struct drm_encoder *encoder;
        int type;
 
        switch (entry->type) {
@@ -613,11 +614,12 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry)
        nv_encoder->dcb = entry;
        nv_encoder->or = ffs(entry->or) - 1;
 
-       drm_encoder_init(dev, encoder, &nv04_dfp_funcs, type);
+       drm_encoder_init(connector->dev, encoder, &nv04_dfp_funcs, type);
        drm_encoder_helper_add(encoder, helper);
 
        encoder->possible_crtcs = entry->heads;
        encoder->possible_clones = 0;
 
+       drm_mode_connector_attach_encoder(connector, encoder);
        return 0;
 }
index c7898b4f6dfbe0e1fb440452368d22077a0b083d..b35b7ed0833b036ac2edc07be4b2a4a0eb0bf8f7 100644 (file)
@@ -94,6 +94,7 @@ 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;
@@ -132,19 +133,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,8 +160,14 @@ 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);
index c4e3404337d4708e7b60c57e538908455f2ac235..84b5954a8efbb78d78ab499f0ab9b26e4a7110c9 100644 (file)
@@ -223,10 +223,12 @@ static void nv04_tv_destroy(struct drm_encoder *encoder)
        kfree(nv_encoder);
 }
 
-int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
+int
+nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
 {
        struct nouveau_encoder *nv_encoder;
        struct drm_encoder *encoder;
+       struct drm_device *dev = connector->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct i2c_adapter *adap;
        struct drm_encoder_funcs *funcs = NULL;
@@ -266,7 +268,7 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
 
        was_locked = NVLockVgaCrtcs(dev, false);
 
-       ret = drm_i2c_encoder_init(encoder->dev, to_encoder_slave(encoder), adap,
+       ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), adap,
                                   &nv04_tv_encoder_info[type].board_info);
 
        NVLockVgaCrtcs(dev, was_locked);
@@ -294,7 +296,9 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
 
        /* Set the slave encoder configuration */
        sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params);
+       sfuncs->create_resources(encoder, connector);
 
+       drm_mode_connector_attach_encoder(connector, encoder);
        return 0;
 
 fail:
index 74c880374fb92a5593583b4d077bac002ec76c3c..44437ff46394d54dda7e76428740a33aaf4ff93d 100644 (file)
@@ -744,8 +744,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = {
        .destroy = nv17_tv_destroy,
 };
 
-int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
+int
+nv17_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
 {
+       struct drm_device *dev = connector->dev;
        struct drm_encoder *encoder;
        struct nv17_tv_encoder *tv_enc = NULL;
 
@@ -774,5 +776,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
        encoder->possible_crtcs = entry->heads;
        encoder->possible_clones = 0;
 
+       nv17_tv_create_resources(encoder, connector);
+       drm_mode_connector_attach_encoder(connector, encoder);
        return 0;
 }
index 1fd9537beff60c404ebded245764edb3e1845802..e114f818751d3e9c42f59cd02444f0831bd89e47 100644 (file)
@@ -275,14 +275,11 @@ static const struct drm_encoder_funcs nv50_dac_encoder_funcs = {
 };
 
 int
-nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
+nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
 {
        struct nouveau_encoder *nv_encoder;
        struct drm_encoder *encoder;
 
-       NV_DEBUG_KMS(dev, "\n");
-       NV_INFO(dev, "Detected a DAC output\n");
-
        nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
        if (!nv_encoder)
                return -ENOMEM;
@@ -293,12 +290,14 @@ nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
 
        nv_encoder->disconnect = nv50_dac_disconnect;
 
-       drm_encoder_init(dev, encoder, &nv50_dac_encoder_funcs,
+       drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
                         DRM_MODE_ENCODER_DAC);
        drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
 
        encoder->possible_crtcs = entry->heads;
        encoder->possible_clones = 0;
+
+       drm_mode_connector_attach_encoder(connector, encoder);
        return 0;
 }
 
index 515edde2c59fa387d50eebb9d53017d90c5cd5f4..e031904ef7a78407115dec45110d9d74637718de 100644 (file)
@@ -465,6 +465,7 @@ int nv50_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;
        int ret, i;
 
        NV_DEBUG_KMS(dev, "\n");
@@ -507,14 +508,18 @@ int nv50_display_create(struct drm_device *dev)
                        continue;
                }
 
+               connector = nouveau_connector_create(dev, entry->connector);
+               if (IS_ERR(connector))
+                       continue;
+
                switch (entry->type) {
                case OUTPUT_TMDS:
                case OUTPUT_LVDS:
                case OUTPUT_DP:
-                       nv50_sor_create(dev, entry);
+                       nv50_sor_create(connector, entry);
                        break;
                case OUTPUT_ANALOG:
-                       nv50_dac_create(dev, entry);
+                       nv50_dac_create(connector, entry);
                        break;
                default:
                        NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
@@ -522,11 +527,13 @@ int nv50_display_create(struct drm_device *dev)
                }
        }
 
-       for (i = 0 ; i < dcb->connector.entries; i++) {
-               if (i != 0 && dcb->connector.entry[i].index2 ==
-                             dcb->connector.entry[i - 1].index2)
-                       continue;
-               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);
+               }
        }
 
        ret = nv50_display_init(dev);
index 812778db76ac185b5943a8257ae401ff82f27202..4832bba7c43a1c0e5a67d153a9514e43384966d9 100644 (file)
@@ -272,32 +272,22 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = {
 };
 
 int
-nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
+nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
 {
        struct nouveau_encoder *nv_encoder = NULL;
+       struct drm_device *dev = connector->dev;
        struct drm_encoder *encoder;
-       bool dum;
        int type;
 
        NV_DEBUG_KMS(dev, "\n");
 
        switch (entry->type) {
        case OUTPUT_TMDS:
-               NV_INFO(dev, "Detected a TMDS output\n");
+       case OUTPUT_DP:
                type = DRM_MODE_ENCODER_TMDS;
                break;
        case OUTPUT_LVDS:
-               NV_INFO(dev, "Detected a LVDS output\n");
                type = DRM_MODE_ENCODER_LVDS;
-
-               if (nouveau_bios_parse_lvds_table(dev, 0, &dum, &dum)) {
-                       NV_ERROR(dev, "Failed parsing LVDS table\n");
-                       return -EINVAL;
-               }
-               break;
-       case OUTPUT_DP:
-               NV_INFO(dev, "Detected a DP output\n");
-               type = DRM_MODE_ENCODER_TMDS;
                break;
        default:
                return -EINVAL;
@@ -342,5 +332,6 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
                        nv_encoder->dp.mc_unknown = 5;
        }
 
+       drm_mode_connector_attach_encoder(connector, encoder);
        return 0;
 }