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
