aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_dp_mst_topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_dp_mst_topology.c')
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c68
1 files changed, 52 insertions, 16 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 070f913d2dba..9a5b68717ec8 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -839,6 +839,8 @@ static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb)
839 839
840static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) 840static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt)
841{ 841{
842 struct drm_dp_mst_branch *mstb;
843
842 switch (old_pdt) { 844 switch (old_pdt) {
843 case DP_PEER_DEVICE_DP_LEGACY_CONV: 845 case DP_PEER_DEVICE_DP_LEGACY_CONV:
844 case DP_PEER_DEVICE_SST_SINK: 846 case DP_PEER_DEVICE_SST_SINK:
@@ -846,8 +848,9 @@ static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt)
846 drm_dp_mst_unregister_i2c_bus(&port->aux); 848 drm_dp_mst_unregister_i2c_bus(&port->aux);
847 break; 849 break;
848 case DP_PEER_DEVICE_MST_BRANCHING: 850 case DP_PEER_DEVICE_MST_BRANCHING:
849 drm_dp_put_mst_branch_device(port->mstb); 851 mstb = port->mstb;
850 port->mstb = NULL; 852 port->mstb = NULL;
853 drm_dp_put_mst_branch_device(mstb);
851 break; 854 break;
852 } 855 }
853} 856}
@@ -858,6 +861,8 @@ static void drm_dp_destroy_port(struct kref *kref)
858 struct drm_dp_mst_topology_mgr *mgr = port->mgr; 861 struct drm_dp_mst_topology_mgr *mgr = port->mgr;
859 if (!port->input) { 862 if (!port->input) {
860 port->vcpi.num_slots = 0; 863 port->vcpi.num_slots = 0;
864
865 kfree(port->cached_edid);
861 if (port->connector) 866 if (port->connector)
862 (*port->mgr->cbs->destroy_connector)(mgr, port->connector); 867 (*port->mgr->cbs->destroy_connector)(mgr, port->connector);
863 drm_dp_port_teardown_pdt(port, port->pdt); 868 drm_dp_port_teardown_pdt(port, port->pdt);
@@ -1011,19 +1016,20 @@ static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb,
1011 1016
1012static void build_mst_prop_path(struct drm_dp_mst_port *port, 1017static void build_mst_prop_path(struct drm_dp_mst_port *port,
1013 struct drm_dp_mst_branch *mstb, 1018 struct drm_dp_mst_branch *mstb,
1014 char *proppath) 1019 char *proppath,
1020 size_t proppath_size)
1015{ 1021{
1016 int i; 1022 int i;
1017 char temp[8]; 1023 char temp[8];
1018 snprintf(proppath, 255, "mst:%d", mstb->mgr->conn_base_id); 1024 snprintf(proppath, proppath_size, "mst:%d", mstb->mgr->conn_base_id);
1019 for (i = 0; i < (mstb->lct - 1); i++) { 1025 for (i = 0; i < (mstb->lct - 1); i++) {
1020 int shift = (i % 2) ? 0 : 4; 1026 int shift = (i % 2) ? 0 : 4;
1021 int port_num = mstb->rad[i / 2] >> shift; 1027 int port_num = mstb->rad[i / 2] >> shift;
1022 snprintf(temp, 8, "-%d", port_num); 1028 snprintf(temp, sizeof(temp), "-%d", port_num);
1023 strncat(proppath, temp, 255); 1029 strlcat(proppath, temp, proppath_size);
1024 } 1030 }
1025 snprintf(temp, 8, "-%d", port->port_num); 1031 snprintf(temp, sizeof(temp), "-%d", port->port_num);
1026 strncat(proppath, temp, 255); 1032 strlcat(proppath, temp, proppath_size);
1027} 1033}
1028 1034
1029static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, 1035static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
@@ -1094,8 +1100,12 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
1094 1100
1095 if (created && !port->input) { 1101 if (created && !port->input) {
1096 char proppath[255]; 1102 char proppath[255];
1097 build_mst_prop_path(port, mstb, proppath); 1103 build_mst_prop_path(port, mstb, proppath, sizeof(proppath));
1098 port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath); 1104 port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath);
1105
1106 if (port->port_num >= 8) {
1107 port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
1108 }
1099 } 1109 }
1100 1110
1101 /* put reference to this port */ 1111 /* put reference to this port */
@@ -1798,17 +1808,27 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr,
1798 return 0; 1808 return 0;
1799} 1809}
1800 1810
1801static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count) 1811static bool drm_dp_get_vc_payload_bw(int dp_link_bw,
1812 int dp_link_count,
1813 int *out)
1802{ 1814{
1803 switch (dp_link_bw) { 1815 switch (dp_link_bw) {
1816 default:
1817 DRM_DEBUG_KMS("invalid link bandwidth in DPCD: %x (link count: %d)\n",
1818 dp_link_bw, dp_link_count);
1819 return false;
1820
1804 case DP_LINK_BW_1_62: 1821 case DP_LINK_BW_1_62:
1805 return 3 * dp_link_count; 1822 *out = 3 * dp_link_count;
1823 break;
1806 case DP_LINK_BW_2_7: 1824 case DP_LINK_BW_2_7:
1807 return 5 * dp_link_count; 1825 *out = 5 * dp_link_count;
1826 break;
1808 case DP_LINK_BW_5_4: 1827 case DP_LINK_BW_5_4:
1809 return 10 * dp_link_count; 1828 *out = 10 * dp_link_count;
1829 break;
1810 } 1830 }
1811 BUG(); 1831 return true;
1812} 1832}
1813 1833
1814/** 1834/**
@@ -1840,7 +1860,13 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
1840 goto out_unlock; 1860 goto out_unlock;
1841 } 1861 }
1842 1862
1843 mgr->pbn_div = drm_dp_get_vc_payload_bw(mgr->dpcd[1], mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK); 1863 if (!drm_dp_get_vc_payload_bw(mgr->dpcd[1],
1864 mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK,
1865 &mgr->pbn_div)) {
1866 ret = -EINVAL;
1867 goto out_unlock;
1868 }
1869
1844 mgr->total_pbn = 2560; 1870 mgr->total_pbn = 2560;
1845 mgr->total_slots = DIV_ROUND_UP(mgr->total_pbn, mgr->pbn_div); 1871 mgr->total_slots = DIV_ROUND_UP(mgr->total_pbn, mgr->pbn_div);
1846 mgr->avail_slots = mgr->total_slots; 1872 mgr->avail_slots = mgr->total_slots;
@@ -2150,7 +2176,8 @@ EXPORT_SYMBOL(drm_dp_mst_hpd_irq);
2150 * This returns the current connection state for a port. It validates the 2176 * This returns the current connection state for a port. It validates the
2151 * port pointer still exists so the caller doesn't require a reference 2177 * port pointer still exists so the caller doesn't require a reference
2152 */ 2178 */
2153enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) 2179enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector,
2180 struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
2154{ 2181{
2155 enum drm_connector_status status = connector_status_disconnected; 2182 enum drm_connector_status status = connector_status_disconnected;
2156 2183
@@ -2169,6 +2196,10 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr
2169 2196
2170 case DP_PEER_DEVICE_SST_SINK: 2197 case DP_PEER_DEVICE_SST_SINK:
2171 status = connector_status_connected; 2198 status = connector_status_connected;
2199 /* for logical ports - cache the EDID */
2200 if (port->port_num >= 8 && !port->cached_edid) {
2201 port->cached_edid = drm_get_edid(connector, &port->aux.ddc);
2202 }
2172 break; 2203 break;
2173 case DP_PEER_DEVICE_DP_LEGACY_CONV: 2204 case DP_PEER_DEVICE_DP_LEGACY_CONV:
2174 if (port->ldps) 2205 if (port->ldps)
@@ -2200,7 +2231,12 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
2200 if (!port) 2231 if (!port)
2201 return NULL; 2232 return NULL;
2202 2233
2203 edid = drm_get_edid(connector, &port->aux.ddc); 2234 if (port->cached_edid)
2235 edid = drm_edid_duplicate(port->cached_edid);
2236 else
2237 edid = drm_get_edid(connector, &port->aux.ddc);
2238
2239 drm_mode_connector_set_tile_property(connector);
2204 drm_dp_put_port(port); 2240 drm_dp_put_port(port);
2205 return edid; 2241 return edid;
2206} 2242}