From: Dave Airlie <airlied@xxxxxxxxxx> Using the tiling info attempt to set a mode across two crtcs --- drivers/gpu/drm/drm_crtc.c | 100 +++++++++++++++++++++++++++++++++- drivers/gpu/drm/drm_displayid.c | 13 ++++- drivers/gpu/drm/drm_dp_mst_topology.c | 18 +++++- drivers/gpu/drm/drm_edid.c | 2 + drivers/gpu/drm/drm_probe_helper.c | 2 +- drivers/gpu/drm/i915/intel_modes.c | 1 + include/drm/drm_crtc.h | 8 +++ 7 files changed, 140 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 90e7730..99fa259 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2506,6 +2506,93 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, } EXPORT_SYMBOL(drm_crtc_check_viewport); +/* tiled variants */ +static int drm_mode_setcrtc_tiled(struct drm_mode_set *orig_set) +{ + struct drm_device *dev = orig_set->crtc->dev; + struct drm_mode_set set[2]; + struct drm_crtc *crtc2, *pick_crtc = NULL; + struct drm_connector *connector, *pick_conn[2]; + struct drm_display_mode *cur_mode, *pick_modes[2]; + int ret; + + /* first up we need to find another crtc to use */ + list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) { + if (crtc2 == orig_set->crtc) + continue; + if (crtc2->enabled) + continue; + pick_crtc = crtc2; + break; + } + + if (pick_crtc == NULL) { + DRM_DEBUG_KMS("unable to located second CRTC for tiling\n"); + return -EINVAL; + } + + pick_conn[0] = orig_set->connectors[0]; + pick_conn[1] = NULL; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (!connector->has_tile) + continue; + + if (connector == pick_conn[0]) + continue; + + if (connector->tile_group_id != pick_conn[0]->tile_group_id) + continue; + + pick_conn[1] = connector; + } + + DRM_DEBUG_KMS("picked connectors %x and %x from tgid %d\n", pick_conn[0]->base.id, + pick_conn[1]->base.id, pick_conn[0]->tile_group_id); + if (pick_conn[1] == NULL) { + DRM_DEBUG_KMS("unable to located second connector for tiling %d\n", pick_conn[0]->tile_group_id); + return -EINVAL; + } + + pick_modes[0] = pick_modes[1] = NULL; + list_for_each_entry(cur_mode, &pick_conn[0]->modes, head) { + DRM_DEBUG_KMS("trying %d %d\n", cur_mode->hdisplay, cur_mode->vdisplay); + if (cur_mode->hdisplay == pick_conn[1]->tile_h_size + 1 && + cur_mode->vdisplay == pick_conn[1]->tile_v_size + 1) { + pick_modes[0] = pick_modes[1] = cur_mode; + break; + } + } + if (pick_modes[0] == NULL) { + DRM_DEBUG_KMS("unable to locate second mode for tiling %d %d\n", pick_conn[1]->tile_h_size, pick_conn[1]->tile_v_size); + return -EINVAL; + } + + set[0].fb = set[1].fb = orig_set->fb; + + set[0].crtc = orig_set->crtc; + set[1].crtc = pick_crtc; + + set[0].connectors = &pick_conn[0]; + set[0].num_connectors = 1; + + set[1].connectors = &pick_conn[1]; + set[1].num_connectors = 1; + + set[0].x = orig_set->x; + set[0].y = orig_set->y; + 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); + + /* 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]); + + return ret; +} /** * drm_mode_setcrtc - set CRTC configuration * @dev: drm device for the ioctl @@ -2532,6 +2619,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, uint32_t __user *set_connectors_ptr; int ret; int i; + int num_tiles = 1; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -2640,6 +2728,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, connector->base.id, connector->name); + if (crtc_req->count_connectors == 1) { + if (connector->has_tile && connector->tile_is_single_monitor) { + if (mode->hdisplay > connector->tile_h_size || mode->vdisplay > connector->tile_v_size) + num_tiles = 2; + } + } connector_set[i] = connector; } } @@ -2651,7 +2745,11 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, set.connectors = connector_set; set.num_connectors = crtc_req->count_connectors; set.fb = fb; - ret = drm_mode_set_config_internal(&set); + + if (num_tiles > 1) { + ret = drm_mode_setcrtc_tiled(&set); + } else + ret = drm_mode_set_config_internal(&set); out: if (fb) diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index d434da1..63d57a6 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -53,7 +53,18 @@ int drm_parse_display_id(struct drm_connector *connector, tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4); tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4); - printk("tile cap %d\n", tile->tile_cap); + connector->has_tile = true; + if (tile->tile_cap & 0x80) + connector->tile_is_single_monitor = true; + + connector->num_h_tile = num_h_tile; + connector->num_v_tile = num_v_tile; + connector->tile_h_loc = tile_h_loc; + connector->tile_v_loc = tile_v_loc; + connector->tile_h_size = w; + connector->tile_v_size = h; + + printk("tile cap 0x%x\n", tile->tile_cap); printk("tile_size %d x %d\n", w, h); printk("topo num tiles %dx%d, location %dx%d\n", num_h_tile, num_v_tile, tile_h_loc, tile_v_loc); diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 5d2a08e..1f15d85 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -858,6 +858,8 @@ static void drm_dp_destroy_port(struct kref *kref) struct drm_dp_mst_topology_mgr *mgr = port->mgr; if (!port->input) { port->vcpi.num_slots = 0; + + kfree(port->cached_edid); if (port->connector) (*port->mgr->cbs->destroy_connector)(mgr, port->connector); drm_dp_port_teardown_pdt(port, port->pdt); @@ -1100,8 +1102,16 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, if (port->mstb) { port->mstb->conn_base_id = port->connector->base.id; } - if (port->port_num >= 8) + if (port->port_num >= 8) { port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); + if (port->cached_edid) { + drm_get_displayid(port->connector, + &port->aux.ddc, + port->cached_edid, + false); + } + + } } /* put reference to this port */ @@ -2210,10 +2220,16 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ if (!port) return NULL; + if (connector->has_tile && connector->tile_is_single_monitor) { + if (connector->tile_h_loc > 0 || connector->tile_v_loc > 0) { + goto out; + } + } if (port->cached_edid) edid = drm_edid_duplicate(port->cached_edid); else edid = drm_get_edid(connector, &port->aux.ddc); + out: drm_dp_put_port(port); return edid; } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3d805aa..94e8a57 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3881,6 +3881,8 @@ void drm_get_displayid(struct drm_connector *connector, bool secondary) { void *displayid = NULL; + + connector->has_tile = false; displayid = drm_find_displayid_extension(edid); if (!displayid) { return; diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index db7d250..3fa902a 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -139,7 +139,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect count = (*connector_funcs->get_modes)(connector); } - if (count == 0 && connector->status == connector_status_connected) + if (count == 0 && connector->status == connector_status_connected && !connector->has_tile) count = drm_add_modes_noedid(connector, 1024, 768); if (count == 0) goto prune; diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index 35a327e..52948c6 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -42,6 +42,7 @@ int intel_connector_update_modes(struct drm_connector *connector, int ret; drm_mode_connector_update_edid_property(connector, edid); + ret = drm_add_edid_modes(connector, edid); drm_edid_to_eld(connector, edid); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 1efc007..67c06bd 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -564,6 +564,14 @@ struct drm_connector { unsigned bad_edid_counter; struct dentry *debugfs_entry; + + /* DisplayID bits */ + bool has_tile; + bool tile_is_single_monitor; + uint32_t tile_group_id; + uint8_t num_h_tile, num_v_tile; + uint8_t tile_h_loc, tile_v_loc; + uint16_t tile_h_size, tile_v_size; }; /** -- 1.9.3 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel