+ 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 *);