The nouveau connector reset implementation creates a custom state
subclass, but only initializes a pristine state and sets
driver-specific defaults without resetting any hardware. This is
equivalent to what atomic_create_state expects. Convert to it.

This is significantly harder than the other drivers though, since
pre-nv50 display doesn't support atomic modesetting. Instead, its
connectors keep their property state embedded in struct
nouveau_connector, and drm_connector.state is left NULL.

Thus, only the atomic path needs to be converted, with the embedded
state initialized at connector creation time for pre-nv50.  Those
connectors are also given connector funcs without atomic_create_state:
the DRM core would otherwise install the embedded state into
drm_connector.state and eventually pass it to atomic_destroy_state,
which frees it.

Signed-off-by: Maxime Ripard <[email protected]>

---
Cc: Danilo Krummrich <[email protected]>
Cc: Lyude Paul <[email protected]>
Cc: [email protected]
---
 drivers/gpu/drm/nouveau/dispnv50/disp.c     |  25 ++++--
 drivers/gpu/drm/nouveau/nouveau_connector.c | 129 +++++++++++++++++++++-------
 drivers/gpu/drm/nouveau/nouveau_connector.h |   3 +-
 3 files changed, 119 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c 
b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index e91130f93db6..98a5188f6523 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -1249,7 +1249,7 @@ nv50_mstc_destroy(struct drm_connector *connector)
 static const struct drm_connector_funcs
 nv50_mstc = {
-       .reset = nouveau_conn_reset,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = nv50_mstc_destroy,
+       .atomic_create_state = nouveau_conn_atomic_create_state,
        .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
        .atomic_destroy_state = nouveau_conn_atomic_destroy_state,
@@ -1263,4 +1263,5 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct 
drm_dp_mst_port *port,
 {
        struct drm_device *dev = mstm->outp->base.base.dev;
+       struct drm_connector_state *conn_state;
        struct drm_crtc *crtc;
        struct nv50_mstc *mstc;
@@ -1274,13 +1275,16 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct 
drm_dp_mst_port *port,
        ret = drm_connector_dynamic_init(dev, &mstc->connector, &nv50_mstc,
                                         DRM_MODE_CONNECTOR_DisplayPort, NULL);
-       if (ret) {
-               kfree(*pmstc);
-               *pmstc = NULL;
-               return ret;
-       }
+       if (ret)
+               goto err_free;
 
        drm_connector_helper_add(&mstc->connector, &nv50_mstc_help);
 
-       mstc->connector.funcs->reset(&mstc->connector);
+       conn_state = 
mstc->connector.funcs->atomic_create_state(&mstc->connector);
+       if (IS_ERR(conn_state)) {
+               ret = PTR_ERR(conn_state);
+               goto err_cleanup;
+       }
+       mstc->connector.state = conn_state;
+
        nouveau_conn_attach_properties(&mstc->connector);
 
@@ -1298,4 +1302,11 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct 
drm_dp_mst_port *port,
        drm_dp_mst_get_port_malloc(port);
        return 0;
+
+err_cleanup:
+       drm_connector_cleanup(&mstc->connector);
+err_free:
+       kfree(*pmstc);
+       *pmstc = NULL;
+       return ret;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c 
b/drivers/gpu/drm/nouveau/nouveau_connector.c
index cc3caf8de64b..e472c23c2981 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -243,23 +243,8 @@ nouveau_conn_atomic_duplicate_state(struct drm_connector 
*connector)
 }
 
-void
-nouveau_conn_reset(struct drm_connector *connector)
+static void
+nouveau_conn_atom_init(struct drm_connector *connector,
+                      struct nouveau_conn_atom *asyc)
 {
-       struct nouveau_connector *nv_connector = nouveau_connector(connector);
-       struct nouveau_conn_atom *asyc;
-
-       if (drm_drv_uses_atomic_modeset(connector->dev)) {
-               if (WARN_ON(!(asyc = kzalloc_obj(*asyc))))
-                       return;
-
-               if (connector->state)
-                       nouveau_conn_atomic_destroy_state(connector,
-                                                         connector->state);
-
-               __drm_atomic_helper_connector_reset(connector, &asyc->state);
-       } else {
-               asyc = &nv_connector->properties_state;
-       }
-
        asyc->dither.mode = DITHERING_MODE_AUTO;
        asyc->dither.depth = DITHERING_DEPTH_AUTO;
@@ -281,4 +266,19 @@ nouveau_conn_reset(struct drm_connector *connector)
 }
 
+struct drm_connector_state *
+nouveau_conn_atomic_create_state(struct drm_connector *connector)
+{
+       struct nouveau_conn_atom *asyc;
+
+       asyc = kzalloc_obj(*asyc);
+       if (WARN_ON(!asyc))
+               return ERR_PTR(-ENOMEM);
+
+       __drm_atomic_helper_connector_state_init(&asyc->state, connector);
+       nouveau_conn_atom_init(connector, asyc);
+
+       return &asyc->state;
+}
+
 void
 nouveau_conn_attach_properties(struct drm_connector *connector)
@@ -1231,5 +1231,47 @@ static const struct drm_connector_funcs
 nouveau_connector_funcs = {
        .dpms = drm_helper_connector_dpms,
-       .reset = nouveau_conn_reset,
+       .detect = nouveau_connector_detect,
+       .force = nouveau_connector_force,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = nouveau_connector_set_property,
+       .destroy = nouveau_connector_destroy,
+       .atomic_create_state = nouveau_conn_atomic_create_state,
+       .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
+       .atomic_destroy_state = nouveau_conn_atomic_destroy_state,
+       .atomic_set_property = nouveau_conn_atomic_set_property,
+       .atomic_get_property = nouveau_conn_atomic_get_property,
+       .late_register = nouveau_connector_late_register,
+       .early_unregister = nouveau_connector_early_unregister,
+};
+
+static const struct drm_connector_funcs
+nouveau_connector_funcs_lvds = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = nouveau_connector_detect_lvds,
+       .force = nouveau_connector_force,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = nouveau_connector_set_property,
+       .destroy = nouveau_connector_destroy,
+       .atomic_create_state = nouveau_conn_atomic_create_state,
+       .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state,
+       .atomic_destroy_state = nouveau_conn_atomic_destroy_state,
+       .atomic_set_property = nouveau_conn_atomic_set_property,
+       .atomic_get_property = nouveau_conn_atomic_get_property,
+       .late_register = nouveau_connector_late_register,
+       .early_unregister = nouveau_connector_early_unregister,
+};
+
+/*
+ * Pre-nv50 doesn't support atomic modesetting: the connector property state
+ * lives in the embedded struct nouveau_connector.properties_state and
+ * drm_connector.state is left alone, as expected from a legacy driver.
+ *
+ * Those connectors must not expose atomic_create_state: the DRM core would
+ * then install the embedded state into drm_connector.state and eventually
+ * pass it to atomic_destroy_state, which frees it.
+ */
+static const struct drm_connector_funcs
+nouveau_connector_funcs_legacy = {
+       .dpms = drm_helper_connector_dpms,
        .detect = nouveau_connector_detect,
        .force = nouveau_connector_force,
@@ -1246,7 +1288,6 @@ nouveau_connector_funcs = {
 
 static const struct drm_connector_funcs
-nouveau_connector_funcs_lvds = {
+nouveau_connector_funcs_lvds_legacy = {
        .dpms = drm_helper_connector_dpms,
-       .reset = nouveau_conn_reset,
        .detect = nouveau_connector_detect_lvds,
        .force = nouveau_connector_force,
@@ -1362,5 +1403,7 @@ nouveau_connector_create(struct drm_device *dev, int 
index)
        struct nouveau_display *disp = nouveau_display(dev);
        struct nouveau_connector *nv_connector = NULL;
+       struct drm_connector_state *conn_state;
        struct drm_connector *connector;
+       const struct drm_connector_funcs *funcs;
        struct drm_connector_list_iter conn_iter;
        int type, ret = 0;
@@ -1459,8 +1502,17 @@ nouveau_connector_create(struct drm_device *dev, int 
index)
 
        type = drm_conntype_from_dcb(nv_connector->type);
-       if (type == DRM_MODE_CONNECTOR_LVDS)
-               drm_connector_init(dev, connector, 
&nouveau_connector_funcs_lvds, type);
-       else
-               drm_connector_init(dev, connector, &nouveau_connector_funcs, 
type);
+       if (type == DRM_MODE_CONNECTOR_LVDS) {
+               if (drm_drv_uses_atomic_modeset(dev))
+                       funcs = &nouveau_connector_funcs_lvds;
+               else
+                       funcs = &nouveau_connector_funcs_lvds_legacy;
+       } else {
+               if (drm_drv_uses_atomic_modeset(dev))
+                       funcs = &nouveau_connector_funcs;
+               else
+                       funcs = &nouveau_connector_funcs_legacy;
+       }
+
+       drm_connector_init(dev, connector, funcs, type);
 
        switch (type) {
@@ -1514,13 +1566,26 @@ nouveau_connector_create(struct drm_device *dev, int 
index)
                                                   nouveau_connector_irq, 
NVIF_CONN_EVENT_V0_IRQ,
                                                   &nv_connector->irq);
-                       if (ret) {
-                               nvif_event_dtor(&nv_connector->hpd);
-                               nvif_conn_dtor(&nv_connector->conn);
+                       if (ret)
                                goto drm_conn_err;
-                       }
                }
        }
 
-       connector->funcs->reset(connector);
+       if (drm_drv_uses_atomic_modeset(dev)) {
+               conn_state = connector->funcs->atomic_create_state(connector);
+               if (IS_ERR(conn_state)) {
+                       ret = PTR_ERR(conn_state);
+                       goto drm_conn_err;
+               }
+               connector->state = conn_state;
+       } else {
+               /* Pre-nv50 keeps its property state embedded in struct
+                * nouveau_connector: drm_connector.state must remain NULL,
+                * the DRM core expects legacy drivers to use
+                * drm_connector.encoder.
+                */
+               nouveau_conn_atom_init(connector,
+                                      &nv_connector->properties_state);
+       }
+
        nouveau_conn_attach_properties(connector);
 
@@ -1567,4 +1632,8 @@ nouveau_connector_create(struct drm_device *dev, int 
index)
 
 drm_conn_err:
+       nvif_event_dtor(&nv_connector->irq);
+       nvif_event_dtor(&nv_connector->hpd);
+       cancel_work_sync(&nv_connector->irq_work);
+       nvif_conn_dtor(&nv_connector->conn);
        drm_connector_cleanup(connector);
        kfree(nv_connector);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h 
b/drivers/gpu/drm/nouveau/nouveau_connector.h
index eb292d2ba4bc..02f843648eb8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -217,5 +217,6 @@ extern int nouveau_hdmimhz;
 
 void nouveau_conn_attach_properties(struct drm_connector *);
-void nouveau_conn_reset(struct drm_connector *);
+struct drm_connector_state *
+nouveau_conn_atomic_create_state(struct drm_connector *);
 struct drm_connector_state *
 nouveau_conn_atomic_duplicate_state(struct drm_connector *);

-- 
2.55.0

Reply via email to