Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 6319 → Rev 6320

/drivers/video/drm/drm_dp_mst_topology.c
806,6 → 806,18
return mstb;
}
 
static void drm_dp_free_mst_port(struct kref *kref);
 
static void drm_dp_free_mst_branch_device(struct kref *kref)
{
struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
if (mstb->port_parent) {
if (list_empty(&mstb->port_parent->next))
kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port);
}
kfree(mstb);
}
 
static void drm_dp_destroy_mst_branch_device(struct kref *kref)
{
struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
813,6 → 825,15
bool wake_tx = false;
 
/*
* init kref again to be used by ports to remove mst branch when it is
* not needed anymore
*/
kref_init(kref);
 
if (mstb->port_parent && list_empty(&mstb->port_parent->next))
kref_get(&mstb->port_parent->kref);
 
/*
* destroy all ports - don't need lock
* as there are no more references to the mst branch
* device at this point.
838,7 → 859,7
 
// if (wake_tx)
// wake_up(&mstb->mgr->tx_waitq);
kfree(mstb);
kref_put(kref, drm_dp_free_mst_branch_device);
}
 
static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb)
886,6 → 907,7
* from an EDID retrieval */
 
mutex_lock(&mgr->destroy_connector_lock);
kref_get(&port->parent->kref);
list_add(&port->next, &mgr->destroy_connector_list);
mutex_unlock(&mgr->destroy_connector_lock);
// schedule_work(&mgr->destroy_connector_work);
981,17 → 1003,17
static u8 drm_dp_calculate_rad(struct drm_dp_mst_port *port,
u8 *rad)
{
int lct = port->parent->lct;
int parent_lct = port->parent->lct;
int shift = 4;
int idx = lct / 2;
if (lct > 1) {
memcpy(rad, port->parent->rad, idx);
shift = (lct % 2) ? 4 : 0;
int idx = (parent_lct - 1) / 2;
if (parent_lct > 1) {
memcpy(rad, port->parent->rad, idx + 1);
shift = (parent_lct % 2) ? 4 : 0;
} else
rad[0] = 0;
 
rad[idx] |= port->port_num << shift;
return lct + 1;
return parent_lct + 1;
}
 
/*
1021,18 → 1043,27
return send_link;
}
 
static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb,
struct drm_dp_mst_port *port)
static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
{
int ret;
if (port->dpcd_rev >= 0x12) {
port->guid_valid = drm_dp_validate_guid(mstb->mgr, port->guid);
if (!port->guid_valid) {
ret = drm_dp_send_dpcd_write(mstb->mgr,
port,
 
memcpy(mstb->guid, guid, 16);
 
if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) {
if (mstb->port_parent) {
ret = drm_dp_send_dpcd_write(
mstb->mgr,
mstb->port_parent,
DP_GUID,
16, port->guid);
port->guid_valid = true;
16,
mstb->guid);
} else {
 
ret = drm_dp_dpcd_write(
mstb->mgr->aux,
DP_GUID,
mstb->guid,
16);
}
}
}
1047,7 → 1078,7
snprintf(proppath, proppath_size, "mst:%d", mstb->mgr->conn_base_id);
for (i = 0; i < (mstb->lct - 1); i++) {
int shift = (i % 2) ? 0 : 4;
int port_num = mstb->rad[i / 2] >> shift;
int port_num = (mstb->rad[i / 2] >> shift) & 0xf;
snprintf(temp, sizeof(temp), "-%d", port_num);
strlcat(proppath, temp, proppath_size);
}
1089,7 → 1120,6
port->dpcd_rev = port_msg->dpcd_revision;
port->num_sdp_streams = port_msg->num_sdp_streams;
port->num_sdp_stream_sinks = port_msg->num_sdp_stream_sinks;
memcpy(port->guid, port_msg->peer_guid, 16);
 
/* manage mstb port lists with mgr lock - take a reference
for this list */
1102,11 → 1132,9
 
if (old_ddps != port->ddps) {
if (port->ddps) {
drm_dp_check_port_guid(mstb, port);
if (!port->input)
drm_dp_send_enum_path_resources(mstb->mgr, mstb, port);
} else {
port->guid_valid = false;
port->available_pbn = 0;
}
}
1165,10 → 1193,8
 
if (old_ddps != port->ddps) {
if (port->ddps) {
drm_dp_check_port_guid(mstb, port);
dowork = true;
} else {
port->guid_valid = false;
port->available_pbn = 0;
}
}
1198,7 → 1224,7
 
for (i = 0; i < lct - 1; i++) {
int shift = (i % 2) ? 0 : 4;
int port_num = rad[i / 2] >> shift;
int port_num = (rad[i / 2] >> shift) & 0xf;
 
list_for_each_entry(port, &mstb->ports, next) {
if (port->port_num == port_num) {
1218,6 → 1244,48
return mstb;
}
 
static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
struct drm_dp_mst_branch *mstb,
uint8_t *guid)
{
struct drm_dp_mst_branch *found_mstb;
struct drm_dp_mst_port *port;
 
if (memcmp(mstb->guid, guid, 16) == 0)
return mstb;
 
 
list_for_each_entry(port, &mstb->ports, next) {
if (!port->mstb)
continue;
 
found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);
 
if (found_mstb)
return found_mstb;
}
 
return NULL;
}
 
static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid(
struct drm_dp_mst_topology_mgr *mgr,
uint8_t *guid)
{
struct drm_dp_mst_branch *mstb;
 
/* find the port by iterating down */
mutex_lock(&mgr->lock);
 
mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid);
 
if (mstb)
kref_get(&mstb->kref);
 
mutex_unlock(&mgr->lock);
return mstb;
}
 
static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_branch *mstb)
{
1328,6 → 1396,7
struct drm_dp_sideband_msg_tx *txmsg)
{
struct drm_dp_mst_branch *mstb = txmsg->dst;
u8 req_type;
 
/* both msg slots are full */
if (txmsg->seqno == -1) {
1344,6 → 1413,12
txmsg->seqno = 1;
mstb->tx_slots[txmsg->seqno] = txmsg;
}
 
req_type = txmsg->msg[0] & 0x7f;
if (req_type == DP_CONNECTION_STATUS_NOTIFY ||
req_type == DP_RESOURCE_STATUS_NOTIFY)
hdr->broadcast = 1;
else
hdr->broadcast = 0;
hdr->path_msg = txmsg->path_msg;
hdr->lct = mstb->lct;
1446,26 → 1521,18
}
 
/* called holding qlock */
static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr)
static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_sideband_msg_tx *txmsg)
{
struct drm_dp_sideband_msg_tx *txmsg;
int ret;
 
/* construct a chunk from the first msg in the tx_msg queue */
if (list_empty(&mgr->tx_msg_upq)) {
mgr->tx_up_in_progress = false;
return;
}
ret = process_single_tx_qlock(mgr, txmsg, true);
 
txmsg = list_first_entry(&mgr->tx_msg_upq, struct drm_dp_sideband_msg_tx, next);
ret = process_single_tx_qlock(mgr, txmsg, true);
if (ret == 1) {
/* up txmsgs aren't put in slots - so free after we send it */
list_del(&txmsg->next);
kfree(txmsg);
} else if (ret)
if (ret != 1)
DRM_DEBUG_KMS("failed to send msg in q %d\n", ret);
mgr->tx_up_in_progress = true;
 
txmsg->dst->tx_slots[txmsg->seqno] = NULL;
}
 
static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr,
1515,6 → 1582,9
txmsg->reply.u.link_addr.ports[i].num_sdp_streams,
txmsg->reply.u.link_addr.ports[i].num_sdp_stream_sinks);
}
 
drm_dp_check_mstb_guid(mstb, txmsg->reply.u.link_addr.guid);
 
for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) {
drm_dp_add_port(mstb, mgr->dev, &txmsg->reply.u.link_addr.ports[i]);
}
1562,6 → 1632,37
return 0;
}
 
static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb)
{
if (!mstb->port_parent)
return NULL;
 
if (mstb->port_parent->mstb != mstb)
return mstb->port_parent;
 
return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent);
}
 
static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_branch *mstb,
int *port_num)
{
struct drm_dp_mst_branch *rmstb = NULL;
struct drm_dp_mst_port *found_port;
mutex_lock(&mgr->lock);
if (mgr->mst_primary) {
found_port = drm_dp_get_last_connected_port_to_mstb(mstb);
 
if (found_port) {
rmstb = found_port->parent;
kref_get(&rmstb->kref);
*port_num = found_port->port_num;
}
}
mutex_unlock(&mgr->lock);
return rmstb;
}
 
static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port,
int id,
1569,11 → 1670,16
{
struct drm_dp_sideband_msg_tx *txmsg;
struct drm_dp_mst_branch *mstb;
int len, ret;
int len, ret, port_num;
 
port_num = port->port_num;
mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
if (!mstb) {
mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num);
 
if (!mstb)
return -EINVAL;
}
 
txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
if (!txmsg) {
1582,7 → 1688,7
}
 
txmsg->dst = mstb;
len = build_allocate_payload(txmsg, port->port_num,
len = build_allocate_payload(txmsg, port_num,
id,
pbn);
 
1852,11 → 1958,12
drm_dp_encode_up_ack_reply(txmsg, req_type);
 
mutex_lock(&mgr->qlock);
list_add_tail(&txmsg->next, &mgr->tx_msg_upq);
if (!mgr->tx_up_in_progress) {
process_single_up_tx_qlock(mgr);
}
 
process_single_up_tx_qlock(mgr, txmsg);
 
mutex_unlock(&mgr->qlock);
 
kfree(txmsg);
return 0;
}
 
1935,13 → 2042,6
mgr->mst_primary = mstb;
kref_get(&mgr->mst_primary->kref);
 
{
struct drm_dp_payload reset_pay;
reset_pay.start_slot = 0;
reset_pay.num_slots = 0x3f;
drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
}
 
ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC);
if (ret < 0) {
1948,20 → 2048,13
goto out_unlock;
}
 
 
/* sort out guid */
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, mgr->guid, 16);
if (ret != 16) {
DRM_DEBUG_KMS("failed to read DP GUID %d\n", ret);
goto out_unlock;
{
struct drm_dp_payload reset_pay;
reset_pay.start_slot = 0;
reset_pay.num_slots = 0x3f;
drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
}
 
mgr->guid_valid = drm_dp_validate_guid(mgr, mgr->guid);
if (!mgr->guid_valid) {
ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, mgr->guid, 16);
mgr->guid_valid = true;
}
 
// queue_work(system_long_wq, &mgr->work);
 
ret = 0;
2151,8 → 2244,10
 
if (mgr->up_req_recv.have_eomt) {
struct drm_dp_sideband_msg_req_body msg;
struct drm_dp_mst_branch *mstb;
struct drm_dp_mst_branch *mstb = NULL;
bool seqno;
 
if (!mgr->up_req_recv.initial_hdr.broadcast) {
mstb = drm_dp_get_mst_branch_device(mgr,
mgr->up_req_recv.initial_hdr.lct,
mgr->up_req_recv.initial_hdr.rad);
2161,18 → 2256,39
memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
return 0;
}
}
 
seqno = mgr->up_req_recv.initial_hdr.seqno;
drm_dp_sideband_parse_req(&mgr->up_req_recv, &msg);
 
if (msg.req_type == DP_CONNECTION_STATUS_NOTIFY) {
drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false);
drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);
 
if (!mstb)
mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.conn_stat.guid);
 
if (!mstb) {
DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
return 0;
}
 
drm_dp_update_port(mstb, &msg.u.conn_stat);
 
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);
(*mgr->cbs->hotplug)(mgr);
 
} else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) {
drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false);
drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false);
if (!mstb)
mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.resource_stat.guid);
 
if (!mstb) {
DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct);
memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
return 0;
}
 
DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", msg.u.resource_stat.port_number, msg.u.resource_stat.available_pbn);
}
 
2352,6 → 2468,7
DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn);
if (pbn == port->vcpi.pbn) {
*slots = port->vcpi.num_slots;
drm_dp_put_port(port);
return true;
}
}
2511,32 → 2628,31
*/
int drm_dp_calc_pbn_mode(int clock, int bpp)
{
fixed20_12 pix_bw;
fixed20_12 fbpp;
fixed20_12 result;
fixed20_12 margin, tmp;
u32 res;
u64 kbps;
s64 peak_kbps;
u32 numerator;
u32 denominator;
 
pix_bw.full = dfixed_const(clock);
fbpp.full = dfixed_const(bpp);
tmp.full = dfixed_const(8);
fbpp.full = dfixed_div(fbpp, tmp);
kbps = clock * bpp;
 
result.full = dfixed_mul(pix_bw, fbpp);
margin.full = dfixed_const(54);
tmp.full = dfixed_const(64);
margin.full = dfixed_div(margin, tmp);
result.full = dfixed_div(result, margin);
/*
* margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006
* The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on
* common multiplier to render an integer PBN for all link rate/lane
* counts combinations
* calculate
* peak_kbps *= (1006/1000)
* peak_kbps *= (64/54)
* peak_kbps *= 8 convert to bytes
*/
 
margin.full = dfixed_const(1006);
tmp.full = dfixed_const(1000);
margin.full = dfixed_div(margin, tmp);
result.full = dfixed_mul(result, margin);
numerator = 64 * 1006;
denominator = 54 * 8 * 1000 * 1000;
 
result.full = dfixed_div(result, tmp);
result.full = dfixed_ceil(result);
res = dfixed_trunc(result);
return res;
kbps *= numerator;
peak_kbps = drm_fixp_from_fraction(kbps, denominator);
 
return drm_fixp2int_ceil(peak_kbps);
}
EXPORT_SYMBOL(drm_dp_calc_pbn_mode);
 
2544,11 → 2660,23
{
int ret;
ret = drm_dp_calc_pbn_mode(154000, 30);
if (ret != 689)
if (ret != 689) {
DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
154000, 30, 689, ret);
return -EINVAL;
}
ret = drm_dp_calc_pbn_mode(234000, 30);
if (ret != 1047)
if (ret != 1047) {
DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
234000, 30, 1047, ret);
return -EINVAL;
}
ret = drm_dp_calc_pbn_mode(297000, 24);
if (ret != 1063) {
DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
297000, 24, 1063, ret);
return -EINVAL;
}
return 0;
}
 
2627,6 → 2755,12
mutex_unlock(&mgr->qlock);
}
 
static void drm_dp_free_mst_port(struct kref *kref)
{
struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref);
kref_put(&port->parent->kref, drm_dp_free_mst_branch_device);
kfree(port);
}
/**
* drm_dp_mst_topology_mgr_init - initialise a topology manager
* @mgr: manager struct to initialise
2647,7 → 2781,6
mutex_init(&mgr->qlock);
mutex_init(&mgr->payload_lock);
mutex_init(&mgr->destroy_connector_lock);
INIT_LIST_HEAD(&mgr->tx_msg_upq);
INIT_LIST_HEAD(&mgr->tx_msg_downq);
INIT_LIST_HEAD(&mgr->destroy_connector_list);
INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work);