diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpu/drm/drm_dp_mst_topology.c | 279 |
1 files changed, 182 insertions, 97 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 6ed90a2437e5..8ae13de272c4 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c | |||
| @@ -803,6 +803,18 @@ static struct drm_dp_mst_branch *drm_dp_add_mst_branch_device(u8 lct, u8 *rad) | |||
| 803 | return mstb; | 803 | return mstb; |
| 804 | } | 804 | } |
| 805 | 805 | ||
| 806 | static void drm_dp_free_mst_port(struct kref *kref); | ||
| 807 | |||
| 808 | static void drm_dp_free_mst_branch_device(struct kref *kref) | ||
| 809 | { | ||
| 810 | struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); | ||
| 811 | if (mstb->port_parent) { | ||
| 812 | if (list_empty(&mstb->port_parent->next)) | ||
| 813 | kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port); | ||
| 814 | } | ||
| 815 | kfree(mstb); | ||
| 816 | } | ||
| 817 | |||
| 806 | static void drm_dp_destroy_mst_branch_device(struct kref *kref) | 818 | static void drm_dp_destroy_mst_branch_device(struct kref *kref) |
| 807 | { | 819 | { |
| 808 | struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); | 820 | struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); |
| @@ -810,6 +822,15 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) | |||
| 810 | bool wake_tx = false; | 822 | bool wake_tx = false; |
| 811 | 823 | ||
| 812 | /* | 824 | /* |
| 825 | * init kref again to be used by ports to remove mst branch when it is | ||
| 826 | * not needed anymore | ||
| 827 | */ | ||
| 828 | kref_init(kref); | ||
| 829 | |||
| 830 | if (mstb->port_parent && list_empty(&mstb->port_parent->next)) | ||
| 831 | kref_get(&mstb->port_parent->kref); | ||
| 832 | |||
| 833 | /* | ||
| 813 | * destroy all ports - don't need lock | 834 | * destroy all ports - don't need lock |
| 814 | * as there are no more references to the mst branch | 835 | * as there are no more references to the mst branch |
| 815 | * device at this point. | 836 | * device at this point. |
| @@ -835,7 +856,8 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) | |||
| 835 | 856 | ||
| 836 | if (wake_tx) | 857 | if (wake_tx) |
| 837 | wake_up(&mstb->mgr->tx_waitq); | 858 | wake_up(&mstb->mgr->tx_waitq); |
| 838 | kfree(mstb); | 859 | |
| 860 | kref_put(kref, drm_dp_free_mst_branch_device); | ||
| 839 | } | 861 | } |
| 840 | 862 | ||
| 841 | static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) | 863 | static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) |
| @@ -883,6 +905,7 @@ static void drm_dp_destroy_port(struct kref *kref) | |||
| 883 | * from an EDID retrieval */ | 905 | * from an EDID retrieval */ |
| 884 | 906 | ||
| 885 | mutex_lock(&mgr->destroy_connector_lock); | 907 | mutex_lock(&mgr->destroy_connector_lock); |
| 908 | kref_get(&port->parent->kref); | ||
| 886 | list_add(&port->next, &mgr->destroy_connector_list); | 909 | list_add(&port->next, &mgr->destroy_connector_list); |
| 887 | mutex_unlock(&mgr->destroy_connector_lock); | 910 | mutex_unlock(&mgr->destroy_connector_lock); |
| 888 | schedule_work(&mgr->destroy_connector_work); | 911 | schedule_work(&mgr->destroy_connector_work); |
| @@ -1018,18 +1041,27 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port) | |||
| 1018 | return send_link; | 1041 | return send_link; |
| 1019 | } | 1042 | } |
| 1020 | 1043 | ||
| 1021 | static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb, | 1044 | static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid) |
| 1022 | struct drm_dp_mst_port *port) | ||
| 1023 | { | 1045 | { |
| 1024 | int ret; | 1046 | int ret; |
| 1025 | if (port->dpcd_rev >= 0x12) { | 1047 | |
| 1026 | port->guid_valid = drm_dp_validate_guid(mstb->mgr, port->guid); | 1048 | memcpy(mstb->guid, guid, 16); |
| 1027 | if (!port->guid_valid) { | 1049 | |
| 1028 | ret = drm_dp_send_dpcd_write(mstb->mgr, | 1050 | if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) { |
| 1029 | port, | 1051 | if (mstb->port_parent) { |
| 1030 | DP_GUID, | 1052 | ret = drm_dp_send_dpcd_write( |
| 1031 | 16, port->guid); | 1053 | mstb->mgr, |
| 1032 | port->guid_valid = true; | 1054 | mstb->port_parent, |
| 1055 | DP_GUID, | ||
| 1056 | 16, | ||
| 1057 | mstb->guid); | ||
| 1058 | } else { | ||
| 1059 | |||
| 1060 | ret = drm_dp_dpcd_write( | ||
| 1061 | mstb->mgr->aux, | ||
| 1062 | DP_GUID, | ||
| 1063 | mstb->guid, | ||
| 1064 | 16); | ||
| 1033 | } | 1065 | } |
| 1034 | } | 1066 | } |
| 1035 | } | 1067 | } |
| @@ -1086,7 +1118,6 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, | |||
| 1086 | port->dpcd_rev = port_msg->dpcd_revision; | 1118 | port->dpcd_rev = port_msg->dpcd_revision; |
| 1087 | port->num_sdp_streams = port_msg->num_sdp_streams; | 1119 | port->num_sdp_streams = port_msg->num_sdp_streams; |
| 1088 | port->num_sdp_stream_sinks = port_msg->num_sdp_stream_sinks; | 1120 | port->num_sdp_stream_sinks = port_msg->num_sdp_stream_sinks; |
| 1089 | memcpy(port->guid, port_msg->peer_guid, 16); | ||
| 1090 | 1121 | ||
| 1091 | /* manage mstb port lists with mgr lock - take a reference | 1122 | /* manage mstb port lists with mgr lock - take a reference |
| 1092 | for this list */ | 1123 | for this list */ |
| @@ -1099,11 +1130,9 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, | |||
| 1099 | 1130 | ||
| 1100 | if (old_ddps != port->ddps) { | 1131 | if (old_ddps != port->ddps) { |
| 1101 | if (port->ddps) { | 1132 | if (port->ddps) { |
| 1102 | drm_dp_check_port_guid(mstb, port); | ||
| 1103 | if (!port->input) | 1133 | if (!port->input) |
| 1104 | drm_dp_send_enum_path_resources(mstb->mgr, mstb, port); | 1134 | drm_dp_send_enum_path_resources(mstb->mgr, mstb, port); |
| 1105 | } else { | 1135 | } else { |
| 1106 | port->guid_valid = false; | ||
| 1107 | port->available_pbn = 0; | 1136 | port->available_pbn = 0; |
| 1108 | } | 1137 | } |
| 1109 | } | 1138 | } |
| @@ -1130,13 +1159,11 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, | |||
| 1130 | drm_dp_put_port(port); | 1159 | drm_dp_put_port(port); |
| 1131 | goto out; | 1160 | goto out; |
| 1132 | } | 1161 | } |
| 1133 | if (port->port_num >= DP_MST_LOGICAL_PORT_0) { | 1162 | |
| 1134 | port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); | 1163 | drm_mode_connector_set_tile_property(port->connector); |
| 1135 | drm_mode_connector_set_tile_property(port->connector); | 1164 | |
| 1136 | } | ||
| 1137 | (*mstb->mgr->cbs->register_connector)(port->connector); | 1165 | (*mstb->mgr->cbs->register_connector)(port->connector); |
| 1138 | } | 1166 | } |
| 1139 | |||
| 1140 | out: | 1167 | out: |
| 1141 | /* put reference to this port */ | 1168 | /* put reference to this port */ |
| 1142 | drm_dp_put_port(port); | 1169 | drm_dp_put_port(port); |
| @@ -1161,11 +1188,9 @@ static void drm_dp_update_port(struct drm_dp_mst_branch *mstb, | |||
| 1161 | port->ddps = conn_stat->displayport_device_plug_status; | 1188 | port->ddps = conn_stat->displayport_device_plug_status; |
| 1162 | 1189 | ||
| 1163 | if (old_ddps != port->ddps) { | 1190 | if (old_ddps != port->ddps) { |
| 1191 | dowork = true; | ||
| 1164 | if (port->ddps) { | 1192 | if (port->ddps) { |
| 1165 | drm_dp_check_port_guid(mstb, port); | ||
| 1166 | dowork = true; | ||
| 1167 | } else { | 1193 | } else { |
| 1168 | port->guid_valid = false; | ||
| 1169 | port->available_pbn = 0; | 1194 | port->available_pbn = 0; |
| 1170 | } | 1195 | } |
| 1171 | } | 1196 | } |
| @@ -1222,13 +1247,14 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper( | |||
| 1222 | struct drm_dp_mst_branch *found_mstb; | 1247 | struct drm_dp_mst_branch *found_mstb; |
| 1223 | struct drm_dp_mst_port *port; | 1248 | struct drm_dp_mst_port *port; |
| 1224 | 1249 | ||
| 1250 | if (memcmp(mstb->guid, guid, 16) == 0) | ||
| 1251 | return mstb; | ||
| 1252 | |||
| 1253 | |||
| 1225 | list_for_each_entry(port, &mstb->ports, next) { | 1254 | list_for_each_entry(port, &mstb->ports, next) { |
| 1226 | if (!port->mstb) | 1255 | if (!port->mstb) |
| 1227 | continue; | 1256 | continue; |
| 1228 | 1257 | ||
| 1229 | if (port->guid_valid && memcmp(port->guid, guid, 16) == 0) | ||
| 1230 | return port->mstb; | ||
| 1231 | |||
| 1232 | found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid); | 1258 | found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid); |
| 1233 | 1259 | ||
| 1234 | if (found_mstb) | 1260 | if (found_mstb) |
| @@ -1247,10 +1273,7 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid( | |||
| 1247 | /* find the port by iterating down */ | 1273 | /* find the port by iterating down */ |
| 1248 | mutex_lock(&mgr->lock); | 1274 | mutex_lock(&mgr->lock); |
| 1249 | 1275 | ||
| 1250 | if (mgr->guid_valid && memcmp(mgr->guid, guid, 16) == 0) | 1276 | mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid); |
| 1251 | mstb = mgr->mst_primary; | ||
| 1252 | else | ||
| 1253 | mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid); | ||
| 1254 | 1277 | ||
| 1255 | if (mstb) | 1278 | if (mstb) |
| 1256 | kref_get(&mstb->kref); | 1279 | kref_get(&mstb->kref); |
| @@ -1271,8 +1294,13 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m | |||
| 1271 | if (port->input) | 1294 | if (port->input) |
| 1272 | continue; | 1295 | continue; |
| 1273 | 1296 | ||
| 1274 | if (!port->ddps) | 1297 | if (!port->ddps) { |
| 1298 | if (port->cached_edid) { | ||
| 1299 | kfree(port->cached_edid); | ||
| 1300 | port->cached_edid = NULL; | ||
| 1301 | } | ||
| 1275 | continue; | 1302 | continue; |
| 1303 | } | ||
| 1276 | 1304 | ||
| 1277 | if (!port->available_pbn) | 1305 | if (!port->available_pbn) |
| 1278 | drm_dp_send_enum_path_resources(mgr, mstb, port); | 1306 | drm_dp_send_enum_path_resources(mgr, mstb, port); |
| @@ -1283,6 +1311,12 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m | |||
| 1283 | drm_dp_check_and_send_link_address(mgr, mstb_child); | 1311 | drm_dp_check_and_send_link_address(mgr, mstb_child); |
| 1284 | drm_dp_put_mst_branch_device(mstb_child); | 1312 | drm_dp_put_mst_branch_device(mstb_child); |
| 1285 | } | 1313 | } |
| 1314 | } else if (port->pdt == DP_PEER_DEVICE_SST_SINK || | ||
| 1315 | port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV) { | ||
| 1316 | if (!port->cached_edid) { | ||
| 1317 | port->cached_edid = | ||
| 1318 | drm_get_edid(port->connector, &port->aux.ddc); | ||
| 1319 | } | ||
| 1286 | } | 1320 | } |
| 1287 | } | 1321 | } |
| 1288 | } | 1322 | } |
| @@ -1302,6 +1336,8 @@ static void drm_dp_mst_link_probe_work(struct work_struct *work) | |||
| 1302 | drm_dp_check_and_send_link_address(mgr, mstb); | 1336 | drm_dp_check_and_send_link_address(mgr, mstb); |
| 1303 | drm_dp_put_mst_branch_device(mstb); | 1337 | drm_dp_put_mst_branch_device(mstb); |
| 1304 | } | 1338 | } |
| 1339 | |||
| 1340 | (*mgr->cbs->hotplug)(mgr); | ||
| 1305 | } | 1341 | } |
| 1306 | 1342 | ||
| 1307 | static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, | 1343 | static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, |
| @@ -1555,10 +1591,12 @@ static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, | |||
| 1555 | txmsg->reply.u.link_addr.ports[i].num_sdp_streams, | 1591 | txmsg->reply.u.link_addr.ports[i].num_sdp_streams, |
| 1556 | txmsg->reply.u.link_addr.ports[i].num_sdp_stream_sinks); | 1592 | txmsg->reply.u.link_addr.ports[i].num_sdp_stream_sinks); |
| 1557 | } | 1593 | } |
| 1594 | |||
| 1595 | drm_dp_check_mstb_guid(mstb, txmsg->reply.u.link_addr.guid); | ||
| 1596 | |||
| 1558 | for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) { | 1597 | for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) { |
| 1559 | drm_dp_add_port(mstb, mgr->dev, &txmsg->reply.u.link_addr.ports[i]); | 1598 | drm_dp_add_port(mstb, mgr->dev, &txmsg->reply.u.link_addr.ports[i]); |
| 1560 | } | 1599 | } |
| 1561 | (*mgr->cbs->hotplug)(mgr); | ||
| 1562 | } | 1600 | } |
| 1563 | } else { | 1601 | } else { |
| 1564 | mstb->link_address_sent = false; | 1602 | mstb->link_address_sent = false; |
| @@ -1602,6 +1640,37 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, | |||
| 1602 | return 0; | 1640 | return 0; |
| 1603 | } | 1641 | } |
| 1604 | 1642 | ||
| 1643 | static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb) | ||
| 1644 | { | ||
| 1645 | if (!mstb->port_parent) | ||
| 1646 | return NULL; | ||
| 1647 | |||
| 1648 | if (mstb->port_parent->mstb != mstb) | ||
| 1649 | return mstb->port_parent; | ||
| 1650 | |||
| 1651 | return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent); | ||
| 1652 | } | ||
| 1653 | |||
| 1654 | static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr, | ||
| 1655 | struct drm_dp_mst_branch *mstb, | ||
| 1656 | int *port_num) | ||
| 1657 | { | ||
| 1658 | struct drm_dp_mst_branch *rmstb = NULL; | ||
| 1659 | struct drm_dp_mst_port *found_port; | ||
| 1660 | mutex_lock(&mgr->lock); | ||
| 1661 | if (mgr->mst_primary) { | ||
| 1662 | found_port = drm_dp_get_last_connected_port_to_mstb(mstb); | ||
| 1663 | |||
| 1664 | if (found_port) { | ||
| 1665 | rmstb = found_port->parent; | ||
| 1666 | kref_get(&rmstb->kref); | ||
| 1667 | *port_num = found_port->port_num; | ||
| 1668 | } | ||
| 1669 | } | ||
| 1670 | mutex_unlock(&mgr->lock); | ||
| 1671 | return rmstb; | ||
| 1672 | } | ||
| 1673 | |||
| 1605 | static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, | 1674 | static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, |
| 1606 | struct drm_dp_mst_port *port, | 1675 | struct drm_dp_mst_port *port, |
| 1607 | int id, | 1676 | int id, |
| @@ -1609,13 +1678,18 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, | |||
| 1609 | { | 1678 | { |
| 1610 | struct drm_dp_sideband_msg_tx *txmsg; | 1679 | struct drm_dp_sideband_msg_tx *txmsg; |
| 1611 | struct drm_dp_mst_branch *mstb; | 1680 | struct drm_dp_mst_branch *mstb; |
| 1612 | int len, ret; | 1681 | int len, ret, port_num; |
| 1613 | u8 sinks[DRM_DP_MAX_SDP_STREAMS]; | 1682 | u8 sinks[DRM_DP_MAX_SDP_STREAMS]; |
| 1614 | int i; | 1683 | int i; |
| 1615 | 1684 | ||
| 1685 | port_num = port->port_num; | ||
| 1616 | mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); | 1686 | mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); |
| 1617 | if (!mstb) | 1687 | if (!mstb) { |
| 1618 | return -EINVAL; | 1688 | mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num); |
| 1689 | |||
| 1690 | if (!mstb) | ||
| 1691 | return -EINVAL; | ||
| 1692 | } | ||
| 1619 | 1693 | ||
| 1620 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); | 1694 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); |
| 1621 | if (!txmsg) { | 1695 | if (!txmsg) { |
| @@ -1627,7 +1701,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, | |||
| 1627 | sinks[i] = i; | 1701 | sinks[i] = i; |
| 1628 | 1702 | ||
| 1629 | txmsg->dst = mstb; | 1703 | txmsg->dst = mstb; |
| 1630 | len = build_allocate_payload(txmsg, port->port_num, | 1704 | len = build_allocate_payload(txmsg, port_num, |
| 1631 | id, | 1705 | id, |
| 1632 | pbn, port->num_sdp_streams, sinks); | 1706 | pbn, port->num_sdp_streams, sinks); |
| 1633 | 1707 | ||
| @@ -1983,31 +2057,17 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms | |||
| 1983 | mgr->mst_primary = mstb; | 2057 | mgr->mst_primary = mstb; |
| 1984 | kref_get(&mgr->mst_primary->kref); | 2058 | kref_get(&mgr->mst_primary->kref); |
| 1985 | 2059 | ||
| 1986 | { | ||
| 1987 | struct drm_dp_payload reset_pay; | ||
| 1988 | reset_pay.start_slot = 0; | ||
| 1989 | reset_pay.num_slots = 0x3f; | ||
| 1990 | drm_dp_dpcd_write_payload(mgr, 0, &reset_pay); | ||
| 1991 | } | ||
| 1992 | |||
| 1993 | ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, | 2060 | ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, |
| 1994 | DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); | 2061 | DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); |
| 1995 | if (ret < 0) { | 2062 | if (ret < 0) { |
| 1996 | goto out_unlock; | 2063 | goto out_unlock; |
| 1997 | } | 2064 | } |
| 1998 | 2065 | ||
| 1999 | 2066 | { | |
| 2000 | /* sort out guid */ | 2067 | struct drm_dp_payload reset_pay; |
| 2001 | ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, mgr->guid, 16); | 2068 | reset_pay.start_slot = 0; |
| 2002 | if (ret != 16) { | 2069 | reset_pay.num_slots = 0x3f; |
| 2003 | DRM_DEBUG_KMS("failed to read DP GUID %d\n", ret); | 2070 | drm_dp_dpcd_write_payload(mgr, 0, &reset_pay); |
| 2004 | goto out_unlock; | ||
| 2005 | } | ||
| 2006 | |||
| 2007 | mgr->guid_valid = drm_dp_validate_guid(mgr, mgr->guid); | ||
| 2008 | if (!mgr->guid_valid) { | ||
| 2009 | ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, mgr->guid, 16); | ||
| 2010 | mgr->guid_valid = true; | ||
| 2011 | } | 2071 | } |
| 2012 | 2072 | ||
| 2013 | queue_work(system_long_wq, &mgr->work); | 2073 | queue_work(system_long_wq, &mgr->work); |
| @@ -2231,9 +2291,8 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) | |||
| 2231 | } | 2291 | } |
| 2232 | 2292 | ||
| 2233 | drm_dp_update_port(mstb, &msg.u.conn_stat); | 2293 | drm_dp_update_port(mstb, &msg.u.conn_stat); |
| 2234 | DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type); | ||
| 2235 | (*mgr->cbs->hotplug)(mgr); | ||
| 2236 | 2294 | ||
| 2295 | DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type); | ||
| 2237 | } else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) { | 2296 | } else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) { |
| 2238 | drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false); | 2297 | drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false); |
| 2239 | if (!mstb) | 2298 | if (!mstb) |
| @@ -2320,10 +2379,6 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector | |||
| 2320 | 2379 | ||
| 2321 | case DP_PEER_DEVICE_SST_SINK: | 2380 | case DP_PEER_DEVICE_SST_SINK: |
| 2322 | status = connector_status_connected; | 2381 | status = connector_status_connected; |
| 2323 | /* for logical ports - cache the EDID */ | ||
| 2324 | if (port->port_num >= 8 && !port->cached_edid) { | ||
| 2325 | port->cached_edid = drm_get_edid(connector, &port->aux.ddc); | ||
| 2326 | } | ||
| 2327 | break; | 2382 | break; |
| 2328 | case DP_PEER_DEVICE_DP_LEGACY_CONV: | 2383 | case DP_PEER_DEVICE_DP_LEGACY_CONV: |
| 2329 | if (port->ldps) | 2384 | if (port->ldps) |
| @@ -2378,10 +2433,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ | |||
| 2378 | 2433 | ||
| 2379 | if (port->cached_edid) | 2434 | if (port->cached_edid) |
| 2380 | edid = drm_edid_duplicate(port->cached_edid); | 2435 | edid = drm_edid_duplicate(port->cached_edid); |
| 2381 | else { | 2436 | |
| 2382 | edid = drm_get_edid(connector, &port->aux.ddc); | ||
| 2383 | drm_mode_connector_set_tile_property(connector); | ||
| 2384 | } | ||
| 2385 | port->has_audio = drm_detect_monitor_audio(edid); | 2437 | port->has_audio = drm_detect_monitor_audio(edid); |
| 2386 | drm_dp_put_port(port); | 2438 | drm_dp_put_port(port); |
| 2387 | return edid; | 2439 | return edid; |
| @@ -2446,6 +2498,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp | |||
| 2446 | DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn); | 2498 | DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn); |
| 2447 | if (pbn == port->vcpi.pbn) { | 2499 | if (pbn == port->vcpi.pbn) { |
| 2448 | *slots = port->vcpi.num_slots; | 2500 | *slots = port->vcpi.num_slots; |
| 2501 | drm_dp_put_port(port); | ||
| 2449 | return true; | 2502 | return true; |
| 2450 | } | 2503 | } |
| 2451 | } | 2504 | } |
| @@ -2605,32 +2658,31 @@ EXPORT_SYMBOL(drm_dp_check_act_status); | |||
| 2605 | */ | 2658 | */ |
| 2606 | int drm_dp_calc_pbn_mode(int clock, int bpp) | 2659 | int drm_dp_calc_pbn_mode(int clock, int bpp) |
| 2607 | { | 2660 | { |
| 2608 | fixed20_12 pix_bw; | 2661 | u64 kbps; |
| 2609 | fixed20_12 fbpp; | 2662 | s64 peak_kbps; |
| 2610 | fixed20_12 result; | 2663 | u32 numerator; |
| 2611 | fixed20_12 margin, tmp; | 2664 | u32 denominator; |
| 2612 | u32 res; | 2665 | |
| 2613 | 2666 | kbps = clock * bpp; | |
| 2614 | pix_bw.full = dfixed_const(clock); | 2667 | |
| 2615 | fbpp.full = dfixed_const(bpp); | 2668 | /* |
| 2616 | tmp.full = dfixed_const(8); | 2669 | * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 |
| 2617 | fbpp.full = dfixed_div(fbpp, tmp); | 2670 | * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on |
| 2618 | 2671 | * common multiplier to render an integer PBN for all link rate/lane | |
| 2619 | result.full = dfixed_mul(pix_bw, fbpp); | 2672 | * counts combinations |
| 2620 | margin.full = dfixed_const(54); | 2673 | * calculate |
| 2621 | tmp.full = dfixed_const(64); | 2674 | * peak_kbps *= (1006/1000) |
| 2622 | margin.full = dfixed_div(margin, tmp); | 2675 | * peak_kbps *= (64/54) |
| 2623 | result.full = dfixed_div(result, margin); | 2676 | * peak_kbps *= 8 convert to bytes |
| 2624 | 2677 | */ | |
| 2625 | margin.full = dfixed_const(1006); | 2678 | |
| 2626 | tmp.full = dfixed_const(1000); | 2679 | numerator = 64 * 1006; |
| 2627 | margin.full = dfixed_div(margin, tmp); | 2680 | denominator = 54 * 8 * 1000 * 1000; |
| 2628 | result.full = dfixed_mul(result, margin); | 2681 | |
| 2629 | 2682 | kbps *= numerator; | |
| 2630 | result.full = dfixed_div(result, tmp); | 2683 | peak_kbps = drm_fixp_from_fraction(kbps, denominator); |
| 2631 | result.full = dfixed_ceil(result); | 2684 | |
| 2632 | res = dfixed_trunc(result); | 2685 | return drm_fixp2int_ceil(peak_kbps); |
| 2633 | return res; | ||
| 2634 | } | 2686 | } |
| 2635 | EXPORT_SYMBOL(drm_dp_calc_pbn_mode); | 2687 | EXPORT_SYMBOL(drm_dp_calc_pbn_mode); |
| 2636 | 2688 | ||
| @@ -2638,11 +2690,23 @@ static int test_calc_pbn_mode(void) | |||
| 2638 | { | 2690 | { |
| 2639 | int ret; | 2691 | int ret; |
| 2640 | ret = drm_dp_calc_pbn_mode(154000, 30); | 2692 | ret = drm_dp_calc_pbn_mode(154000, 30); |
| 2641 | if (ret != 689) | 2693 | if (ret != 689) { |
| 2694 | DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n", | ||
| 2695 | 154000, 30, 689, ret); | ||
| 2642 | return -EINVAL; | 2696 | return -EINVAL; |
| 2697 | } | ||
| 2643 | ret = drm_dp_calc_pbn_mode(234000, 30); | 2698 | ret = drm_dp_calc_pbn_mode(234000, 30); |
| 2644 | if (ret != 1047) | 2699 | if (ret != 1047) { |
| 2700 | DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n", | ||
| 2701 | 234000, 30, 1047, ret); | ||
| 2645 | return -EINVAL; | 2702 | return -EINVAL; |
| 2703 | } | ||
| 2704 | ret = drm_dp_calc_pbn_mode(297000, 24); | ||
| 2705 | if (ret != 1063) { | ||
| 2706 | DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n", | ||
| 2707 | 297000, 24, 1063, ret); | ||
| 2708 | return -EINVAL; | ||
| 2709 | } | ||
| 2646 | return 0; | 2710 | return 0; |
| 2647 | } | 2711 | } |
| 2648 | 2712 | ||
| @@ -2783,6 +2847,13 @@ static void drm_dp_tx_work(struct work_struct *work) | |||
| 2783 | mutex_unlock(&mgr->qlock); | 2847 | mutex_unlock(&mgr->qlock); |
| 2784 | } | 2848 | } |
| 2785 | 2849 | ||
| 2850 | static void drm_dp_free_mst_port(struct kref *kref) | ||
| 2851 | { | ||
| 2852 | struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); | ||
| 2853 | kref_put(&port->parent->kref, drm_dp_free_mst_branch_device); | ||
| 2854 | kfree(port); | ||
| 2855 | } | ||
| 2856 | |||
| 2786 | static void drm_dp_destroy_connector_work(struct work_struct *work) | 2857 | static void drm_dp_destroy_connector_work(struct work_struct *work) |
| 2787 | { | 2858 | { |
| 2788 | struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); | 2859 | struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); |
| @@ -2803,13 +2874,22 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) | |||
| 2803 | list_del(&port->next); | 2874 | list_del(&port->next); |
| 2804 | mutex_unlock(&mgr->destroy_connector_lock); | 2875 | mutex_unlock(&mgr->destroy_connector_lock); |
| 2805 | 2876 | ||
| 2877 | kref_init(&port->kref); | ||
| 2878 | INIT_LIST_HEAD(&port->next); | ||
| 2879 | |||
| 2806 | mgr->cbs->destroy_connector(mgr, port->connector); | 2880 | mgr->cbs->destroy_connector(mgr, port->connector); |
| 2807 | 2881 | ||
| 2808 | drm_dp_port_teardown_pdt(port, port->pdt); | 2882 | drm_dp_port_teardown_pdt(port, port->pdt); |
| 2809 | 2883 | ||
| 2810 | if (!port->input && port->vcpi.vcpi > 0) | 2884 | if (!port->input && port->vcpi.vcpi > 0) { |
| 2811 | drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); | 2885 | if (mgr->mst_state) { |
| 2812 | kfree(port); | 2886 | drm_dp_mst_reset_vcpi_slots(mgr, port); |
| 2887 | drm_dp_update_payload_part1(mgr); | ||
| 2888 | drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); | ||
| 2889 | } | ||
| 2890 | } | ||
| 2891 | |||
| 2892 | kref_put(&port->kref, drm_dp_free_mst_port); | ||
| 2813 | send_hotplug = true; | 2893 | send_hotplug = true; |
| 2814 | } | 2894 | } |
| 2815 | if (send_hotplug) | 2895 | if (send_hotplug) |
| @@ -2847,6 +2927,9 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, | |||
| 2847 | mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes; | 2927 | mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes; |
| 2848 | mgr->max_payloads = max_payloads; | 2928 | mgr->max_payloads = max_payloads; |
| 2849 | mgr->conn_base_id = conn_base_id; | 2929 | mgr->conn_base_id = conn_base_id; |
| 2930 | if (max_payloads + 1 > sizeof(mgr->payload_mask) * 8 || | ||
| 2931 | max_payloads + 1 > sizeof(mgr->vcpi_mask) * 8) | ||
| 2932 | return -EINVAL; | ||
| 2850 | mgr->payloads = kcalloc(max_payloads, sizeof(struct drm_dp_payload), GFP_KERNEL); | 2933 | mgr->payloads = kcalloc(max_payloads, sizeof(struct drm_dp_payload), GFP_KERNEL); |
| 2851 | if (!mgr->payloads) | 2934 | if (!mgr->payloads) |
| 2852 | return -ENOMEM; | 2935 | return -ENOMEM; |
| @@ -2854,7 +2937,9 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, | |||
| 2854 | if (!mgr->proposed_vcpis) | 2937 | if (!mgr->proposed_vcpis) |
| 2855 | return -ENOMEM; | 2938 | return -ENOMEM; |
| 2856 | set_bit(0, &mgr->payload_mask); | 2939 | set_bit(0, &mgr->payload_mask); |
| 2857 | test_calc_pbn_mode(); | 2940 | if (test_calc_pbn_mode() < 0) |
| 2941 | DRM_ERROR("MST PBN self-test failed\n"); | ||
| 2942 | |||
| 2858 | return 0; | 2943 | return 0; |
| 2859 | } | 2944 | } |
| 2860 | EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init); | 2945 | EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init); |
