From: Dave Airlie <airlied@xxxxxxxxxx> So when userspace asks us to set a mode on a tiled crtc, split it up and find the actual modes and attempt to set them. Also disable crtcs when no longer in tiled group. Signed-off-by: Dave Airlie <airlied@xxxxxxxxxx> --- drivers/gpu/drm/drm_crtc.c | 51 ++++++++++++++++++++++++++++++++--- drivers/gpu/drm/drm_dp_mst_topology.c | 6 +++++ include/drm/drm_crtc.h | 8 ++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 99fa259..628f3af 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -764,6 +764,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, crtc->funcs = funcs; crtc->invert_dimensions = false; + INIT_LIST_HEAD(&crtc->tile_crtc_list); + crtc->tile_master = NULL; + drm_modeset_lock_all(dev); drm_modeset_lock_init(&crtc->mutex); /* dropped by _unlock_all(): */ @@ -2520,7 +2523,7 @@ static int drm_mode_setcrtc_tiled(struct drm_mode_set *orig_set) list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) { if (crtc2 == orig_set->crtc) continue; - if (crtc2->enabled) + if (crtc2->enabled && !crtc2->tile_master) continue; pick_crtc = crtc2; break; @@ -2583,14 +2586,26 @@ static int drm_mode_setcrtc_tiled(struct drm_mode_set *orig_set) set[1].x = orig_set->x + ((pick_conn[1]->tile_h_loc == 1) ? pick_conn[0]->tile_h_size + 1 : 0); set[1].y = orig_set->y + ((pick_conn[1]->tile_v_loc == 1) ? pick_conn[0]->tile_v_size + 1 : 0); + if (set[1].crtc->tile_master) { + list_del(&set[1].crtc->tile); + set[1].crtc->tile_master = NULL; + } + list_add_tail(&set[1].crtc->tile, &set[0].crtc->tile_crtc_list); + set[1].crtc->tile_master = set[0].crtc; /* find a mode to use on each head */ set[0].mode = pick_modes[0]; set[1].mode = pick_modes[1]; ret = drm_mode_set_config_internal(&set[0]); - ret = drm_mode_set_config_internal(&set[1]); + if (!ret) { + ret = drm_mode_set_config_internal(&set[1]); + } + if (ret) { + set[1].crtc->tile_master = NULL; + list_del(&set[1].crtc->tile); + } return ret; } /** @@ -2637,6 +2652,15 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, } DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); + if (crtc->tile_master) { + if (crtc_req->mode_valid) + ret = -EBUSY; + else + ret = 0; + DRM_DEBUG_KMS("[CRTC:%d] refused due to tile %d\n", crtc->base.id, ret); + goto out; + } + if (crtc_req->mode_valid) { /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ @@ -2748,9 +2772,25 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, if (num_tiles > 1) { ret = drm_mode_setcrtc_tiled(&set); - } else - ret = drm_mode_set_config_internal(&set); + } else { + if (!list_empty(&crtc->tile_crtc_list)) { + struct drm_crtc *tile_crtc, *t; + + list_for_each_entry_safe(tile_crtc, t, &crtc->tile_crtc_list, tile) { + struct drm_mode_set set2; + + tile_crtc->tile_master = NULL; + list_del(&tile_crtc->tile); + DRM_DEBUG_KMS("disabling crtc %p due to no longer needing tiling %p\n", tile_crtc, tile_crtc->primary); + memset(&set2, 0, sizeof(struct drm_mode_set)); + set2.crtc = tile_crtc; + set2.fb = NULL; + ret = drm_mode_set_config_internal(&set2); + } + } + ret = drm_mode_set_config_internal(&set); + } out: if (fb) drm_framebuffer_unreference(fb); @@ -4226,6 +4266,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, int ret = -EINVAL; struct drm_connector *connector = obj_to_connector(obj); + if (connector->has_tile && connector->tile_is_single_monitor && + (connector->tile_h_loc || connector->tile_v_loc)) + return 0; /* Do DPMS ourselves */ if (property == connector->dev->mode_config.dpms_property) { if (connector->funcs->dpms) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 08b7140..ca5eee6 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2190,6 +2190,12 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector if (port->port_num >= 8 && !port->cached_edid) { port->cached_edid = drm_get_edid(connector, &port->aux.ddc); } + + if (connector->has_tile && connector->tile_group_id == 0) + connector->tile_group_id = port->parent->conn_base_id; + if (connector->has_tile && (connector->tile_h_loc || connector->tile_v_loc)) + status = connector_status_disconnected; + break; case DP_PEER_DEVICE_DP_LEGACY_CONV: if (port->ldps) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 67c06bd..6041acd 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -375,6 +375,14 @@ struct drm_crtc { void *helper_private; struct drm_object_properties properties; + + /* crtcs this one is using for tiling */ + struct list_head tile_crtc_list; + + /* tile list entry */ + struct list_head tile; + + struct drm_crtc *tile_master; }; -- 1.9.3 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx