diff options
Diffstat (limited to 'drivers/gpu/drm/drm_dp_mst_topology.c')
-rw-r--r-- | drivers/gpu/drm/drm_dp_mst_topology.c | 68 |
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 | ||
840 | static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) | 840 | static 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 | ||
1012 | static void build_mst_prop_path(struct drm_dp_mst_port *port, | 1017 | static 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 | ||
1029 | static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, | 1035 | static 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 | ||
1801 | static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count) | 1811 | static 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 | */ |
2153 | enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) | 2179 | enum 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 | } |