diff options
author | Dave Airlie <airlied@redhat.com> | 2016-02-05 00:24:17 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-02-05 00:24:17 -0500 |
commit | 6739b3d7bc18a5373efd863b11831e8f515fffe1 (patch) | |
tree | b08d818569141778000f5e93a47c5ed966751608 | |
parent | c745884b30f96348f83ce59caf6798d8085daa77 (diff) | |
parent | 91a25e463130c8e19bdb42f2d827836c7937992e (diff) |
Merge branch 'drm-fixes-mst' of git://people.freedesktop.org/~airlied/linux into drm-fixes
displayport multistream fixes from AMD.
* 'drm-fixes-mst' of git://people.freedesktop.org/~airlied/linux:
drm/dp/mst: deallocate payload on port destruction
drm/dp/mst: Reverse order of MST enable and clearing VC payload table.
drm/dp/mst: move GUID storage from mgr, port to only mst branch
drm/dp/mst: change MST detection scheme
drm/dp/mst: Calculate MST PBN with 31.32 fixed point
drm: Add drm_fixp_from_fraction and drm_fixp2int_ceil
drm/mst: Add range check for max_payloads during init
drm/mst: Don't ignore the MST PBN self-test result
drm: fix missing reference counting decrease
-rw-r--r-- | drivers/gpu/drm/drm_dp_mst_topology.c | 279 | ||||
-rw-r--r-- | include/drm/drm_dp_mst_helper.h | 25 | ||||
-rw-r--r-- | include/drm/drm_fixed.h | 53 |
3 files changed, 243 insertions, 114 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); |
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 24ab1787b771..fdb47051d549 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h | |||
@@ -44,8 +44,6 @@ struct drm_dp_vcpi { | |||
44 | /** | 44 | /** |
45 | * struct drm_dp_mst_port - MST port | 45 | * struct drm_dp_mst_port - MST port |
46 | * @kref: reference count for this port. | 46 | * @kref: reference count for this port. |
47 | * @guid_valid: for DP 1.2 devices if we have validated the GUID. | ||
48 | * @guid: guid for DP 1.2 device on this port. | ||
49 | * @port_num: port number | 47 | * @port_num: port number |
50 | * @input: if this port is an input port. | 48 | * @input: if this port is an input port. |
51 | * @mcs: message capability status - DP 1.2 spec. | 49 | * @mcs: message capability status - DP 1.2 spec. |
@@ -70,10 +68,6 @@ struct drm_dp_vcpi { | |||
70 | struct drm_dp_mst_port { | 68 | struct drm_dp_mst_port { |
71 | struct kref kref; | 69 | struct kref kref; |
72 | 70 | ||
73 | /* if dpcd 1.2 device is on this port - its GUID info */ | ||
74 | bool guid_valid; | ||
75 | u8 guid[16]; | ||
76 | |||
77 | u8 port_num; | 71 | u8 port_num; |
78 | bool input; | 72 | bool input; |
79 | bool mcs; | 73 | bool mcs; |
@@ -110,10 +104,12 @@ struct drm_dp_mst_port { | |||
110 | * @tx_slots: transmission slots for this device. | 104 | * @tx_slots: transmission slots for this device. |
111 | * @last_seqno: last sequence number used to talk to this. | 105 | * @last_seqno: last sequence number used to talk to this. |
112 | * @link_address_sent: if a link address message has been sent to this device yet. | 106 | * @link_address_sent: if a link address message has been sent to this device yet. |
107 | * @guid: guid for DP 1.2 branch device. port under this branch can be | ||
108 | * identified by port #. | ||
113 | * | 109 | * |
114 | * This structure represents an MST branch device, there is one | 110 | * This structure represents an MST branch device, there is one |
115 | * primary branch device at the root, along with any others connected | 111 | * primary branch device at the root, along with any other branches connected |
116 | * to downstream ports | 112 | * to downstream port of parent branches. |
117 | */ | 113 | */ |
118 | struct drm_dp_mst_branch { | 114 | struct drm_dp_mst_branch { |
119 | struct kref kref; | 115 | struct kref kref; |
@@ -132,6 +128,9 @@ struct drm_dp_mst_branch { | |||
132 | struct drm_dp_sideband_msg_tx *tx_slots[2]; | 128 | struct drm_dp_sideband_msg_tx *tx_slots[2]; |
133 | int last_seqno; | 129 | int last_seqno; |
134 | bool link_address_sent; | 130 | bool link_address_sent; |
131 | |||
132 | /* global unique identifier to identify branch devices */ | ||
133 | u8 guid[16]; | ||
135 | }; | 134 | }; |
136 | 135 | ||
137 | 136 | ||
@@ -406,11 +405,9 @@ struct drm_dp_payload { | |||
406 | * @conn_base_id: DRM connector ID this mgr is connected to. | 405 | * @conn_base_id: DRM connector ID this mgr is connected to. |
407 | * @down_rep_recv: msg receiver state for down replies. | 406 | * @down_rep_recv: msg receiver state for down replies. |
408 | * @up_req_recv: msg receiver state for up requests. | 407 | * @up_req_recv: msg receiver state for up requests. |
409 | * @lock: protects mst state, primary, guid, dpcd. | 408 | * @lock: protects mst state, primary, dpcd. |
410 | * @mst_state: if this manager is enabled for an MST capable port. | 409 | * @mst_state: if this manager is enabled for an MST capable port. |
411 | * @mst_primary: pointer to the primary branch device. | 410 | * @mst_primary: pointer to the primary branch device. |
412 | * @guid_valid: GUID valid for the primary branch device. | ||
413 | * @guid: GUID for primary port. | ||
414 | * @dpcd: cache of DPCD for primary port. | 411 | * @dpcd: cache of DPCD for primary port. |
415 | * @pbn_div: PBN to slots divisor. | 412 | * @pbn_div: PBN to slots divisor. |
416 | * | 413 | * |
@@ -432,13 +429,11 @@ struct drm_dp_mst_topology_mgr { | |||
432 | struct drm_dp_sideband_msg_rx up_req_recv; | 429 | struct drm_dp_sideband_msg_rx up_req_recv; |
433 | 430 | ||
434 | /* pointer to info about the initial MST device */ | 431 | /* pointer to info about the initial MST device */ |
435 | struct mutex lock; /* protects mst_state + primary + guid + dpcd */ | 432 | struct mutex lock; /* protects mst_state + primary + dpcd */ |
436 | 433 | ||
437 | bool mst_state; | 434 | bool mst_state; |
438 | struct drm_dp_mst_branch *mst_primary; | 435 | struct drm_dp_mst_branch *mst_primary; |
439 | /* primary MST device GUID */ | 436 | |
440 | bool guid_valid; | ||
441 | u8 guid[16]; | ||
442 | u8 dpcd[DP_RECEIVER_CAP_SIZE]; | 437 | u8 dpcd[DP_RECEIVER_CAP_SIZE]; |
443 | u8 sink_count; | 438 | u8 sink_count; |
444 | int pbn_div; | 439 | int pbn_div; |
diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h index d639049a613d..553210c02ee0 100644 --- a/include/drm/drm_fixed.h +++ b/include/drm/drm_fixed.h | |||
@@ -73,18 +73,28 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B) | |||
73 | #define DRM_FIXED_ONE (1ULL << DRM_FIXED_POINT) | 73 | #define DRM_FIXED_ONE (1ULL << DRM_FIXED_POINT) |
74 | #define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1) | 74 | #define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1) |
75 | #define DRM_FIXED_DIGITS_MASK (~DRM_FIXED_DECIMAL_MASK) | 75 | #define DRM_FIXED_DIGITS_MASK (~DRM_FIXED_DECIMAL_MASK) |
76 | #define DRM_FIXED_EPSILON 1LL | ||
77 | #define DRM_FIXED_ALMOST_ONE (DRM_FIXED_ONE - DRM_FIXED_EPSILON) | ||
76 | 78 | ||
77 | static inline s64 drm_int2fixp(int a) | 79 | static inline s64 drm_int2fixp(int a) |
78 | { | 80 | { |
79 | return ((s64)a) << DRM_FIXED_POINT; | 81 | return ((s64)a) << DRM_FIXED_POINT; |
80 | } | 82 | } |
81 | 83 | ||
82 | static inline int drm_fixp2int(int64_t a) | 84 | static inline int drm_fixp2int(s64 a) |
83 | { | 85 | { |
84 | return ((s64)a) >> DRM_FIXED_POINT; | 86 | return ((s64)a) >> DRM_FIXED_POINT; |
85 | } | 87 | } |
86 | 88 | ||
87 | static inline unsigned drm_fixp_msbset(int64_t a) | 89 | static inline int drm_fixp2int_ceil(s64 a) |
90 | { | ||
91 | if (a > 0) | ||
92 | return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE); | ||
93 | else | ||
94 | return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE); | ||
95 | } | ||
96 | |||
97 | static inline unsigned drm_fixp_msbset(s64 a) | ||
88 | { | 98 | { |
89 | unsigned shift, sign = (a >> 63) & 1; | 99 | unsigned shift, sign = (a >> 63) & 1; |
90 | 100 | ||
@@ -136,6 +146,45 @@ static inline s64 drm_fixp_div(s64 a, s64 b) | |||
136 | return result; | 146 | return result; |
137 | } | 147 | } |
138 | 148 | ||
149 | static inline s64 drm_fixp_from_fraction(s64 a, s64 b) | ||
150 | { | ||
151 | s64 res; | ||
152 | bool a_neg = a < 0; | ||
153 | bool b_neg = b < 0; | ||
154 | u64 a_abs = a_neg ? -a : a; | ||
155 | u64 b_abs = b_neg ? -b : b; | ||
156 | u64 rem; | ||
157 | |||
158 | /* determine integer part */ | ||
159 | u64 res_abs = div64_u64_rem(a_abs, b_abs, &rem); | ||
160 | |||
161 | /* determine fractional part */ | ||
162 | { | ||
163 | u32 i = DRM_FIXED_POINT; | ||
164 | |||
165 | do { | ||
166 | rem <<= 1; | ||
167 | res_abs <<= 1; | ||
168 | if (rem >= b_abs) { | ||
169 | res_abs |= 1; | ||
170 | rem -= b_abs; | ||
171 | } | ||
172 | } while (--i != 0); | ||
173 | } | ||
174 | |||
175 | /* round up LSB */ | ||
176 | { | ||
177 | u64 summand = (rem << 1) >= b_abs; | ||
178 | |||
179 | res_abs += summand; | ||
180 | } | ||
181 | |||
182 | res = (s64) res_abs; | ||
183 | if (a_neg ^ b_neg) | ||
184 | res = -res; | ||
185 | return res; | ||
186 | } | ||
187 | |||
139 | static inline s64 drm_fixp_exp(s64 x) | 188 | static inline s64 drm_fixp_exp(s64 x) |
140 | { | 189 | { |
141 | s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000); | 190 | s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000); |