disp: msm: dp: use dp_msm_sim for dp-mst simulation

Revert changes in dp mst topology manager and use dp_msm_sim bridge
at aux layer to implement dp-mst simulation.

Change-Id: I863649f901ac918f65c9078e6a2f1b6931d19e3a
Signed-off-by: Xiaowen Wu <wxiaowen@codeaurora.org>
Signed-off-by: Karim Henain <khenain@codeaurora.org>
Signed-off-by: Sudarsan Ramesh <sudarame@codeaurora.org>
This commit is contained in:
Xiaowen Wu
2019-11-05 16:02:32 -05:00
committed by Sudarsan Ramesh
부모 52edf46bbd
커밋 467443d7e3
6개의 변경된 파일116개의 추가작업 그리고 546개의 파일을 삭제

파일 보기

@@ -27,6 +27,7 @@ struct dp_aux_private {
struct drm_dp_aux drm_aux;
struct dp_aux_bridge *aux_bridge;
struct dp_aux_bridge *sim_bridge;
bool bridge_in_transfer;
bool cmd_busy;
@@ -470,6 +471,12 @@ error:
return ret;
}
static inline bool dp_aux_is_sideband_msg(u32 address, size_t size)
{
return (address >= 0x1000 && address + size < 0x1800) ||
(address >= 0x2000 && address + size < 0x2200);
}
static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
struct drm_dp_aux_msg *msg)
{
@@ -491,7 +498,8 @@ static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
goto end;
}
if ((msg->address + msg->size) > SZ_4K) {
if ((msg->address + msg->size) > SZ_4K &&
!dp_aux_is_sideband_msg(msg->address, msg->size)) {
DP_DEBUG("invalid dpcd access: addr=0x%x, size=0x%lx\n",
msg->address, msg->size);
goto address_error;
@@ -521,9 +529,20 @@ static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
}
mutex_lock(aux->dp_aux.access_lock);
if (aux->read)
if (dp_aux_is_sideband_msg(msg->address, msg->size)) {
if (!aux->sim_bridge || !aux->sim_bridge->transfer) {
DP_ERR("no mst bridge available\n");
atomic_set(&aux->aborted, 1);
ret = -ETIMEDOUT;
goto end;
}
ret = aux->sim_bridge->transfer(aux->sim_bridge,
drm_aux, msg);
} else if (aux->read) {
memcpy(msg->buffer, aux->dpcd + msg->address,
msg->size);
}
mutex_unlock(aux->dp_aux.access_lock);
aux->aux_error_num = DP_AUX_ERR_NONE;
@@ -756,7 +775,7 @@ static void dp_aux_dpcd_updated(struct dp_aux *dp_aux)
}
static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en,
u8 *edid, u8 *dpcd)
u8 *edid, u8 *dpcd, struct dp_aux_bridge *sim_bridge)
{
struct dp_aux_private *aux;
@@ -771,6 +790,7 @@ static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en,
aux->edid = edid;
aux->dpcd = dpcd;
aux->sim_bridge = sim_bridge;
if (en) {
atomic_set(&aux->aborted, 0);

파일 보기

@@ -53,7 +53,8 @@ struct dp_aux {
void (*reconfig)(struct dp_aux *aux);
void (*abort)(struct dp_aux *aux, bool abort);
void (*dpcd_updated)(struct dp_aux *aux);
void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd);
void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd,
struct dp_aux_bridge *sim_bridge);
int (*aux_switch)(struct dp_aux *aux, bool enable, int orientation);
};

파일 보기

@@ -15,6 +15,7 @@
#include "dp_display.h"
#include "dp_pll.h"
#include "dp_hpd.h"
#include "dp_mst_sim_helper.h"
#define DEBUG_NAME "drm_dp"
@@ -45,8 +46,73 @@ struct dp_debug_private {
struct dp_pll *pll;
struct dp_display *display;
struct mutex lock;
struct dp_aux_bridge *sim_bridge;
};
static int dp_debug_sim_hpd_cb(void *arg, bool hpd, bool hpd_irq)
{
struct dp_debug_private *debug = arg;
if (hpd_irq)
return debug->hpd->simulate_attention(debug->hpd, 0);
else
return debug->hpd->simulate_connect(debug->hpd, hpd);
}
static int dp_debug_configure_mst_bridge(struct dp_debug_private *debug)
{
struct device_node *bridge_node;
struct dp_mst_sim_port *ports;
int i, ret;
static const struct dp_mst_sim_port output_port = {
false, false, true, 3, false, 0x12,
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
0, 0, 2520, 2520, NULL, 0
};
if (!debug->sim_bridge) {
bridge_node = of_parse_phandle(debug->dev->of_node,
"qcom,dp-aux-bridge-sim", 0);
if (!bridge_node)
return 0;
debug->sim_bridge = of_dp_aux_find_bridge(bridge_node);
}
if (!debug->sim_bridge)
return -EINVAL;
if (debug->sim_bridge->register_hpd) {
ret = debug->sim_bridge->register_hpd(debug->sim_bridge,
dp_debug_sim_hpd_cb, debug);
if (ret)
return ret;
}
if (!debug->dp_debug.mst_port_cnt || !debug->sim_bridge->mst_ctx)
return 0;
ports = kcalloc(debug->dp_debug.mst_port_cnt,
sizeof(*ports), GFP_KERNEL);
if (!ports)
return -ENOMEM;
for (i = 0; i < debug->dp_debug.mst_port_cnt; i++) {
memcpy(&ports[i], &output_port, sizeof(*ports));
ports[i].peer_guid[0] = i;
ports[i].edid = debug->edid;
ports[i].edid_size = debug->edid_size;
}
ret = dp_mst_sim_update(debug->sim_bridge->mst_ctx,
debug->dp_debug.mst_port_cnt, ports);
kfree(ports);
return ret;
}
static int dp_debug_get_edid_buf(struct dp_debug_private *debug)
{
int rc = 0;
@@ -133,7 +199,8 @@ static ssize_t dp_debug_write_edid(struct file *file,
debug->aux->set_sim_mode(debug->aux,
debug->dp_debug.sim_mode,
debug->edid, debug->dpcd);
debug->edid, debug->dpcd,
debug->sim_bridge);
}
}
@@ -167,6 +234,9 @@ bail:
*/
DP_INFO("[%s]\n", edid ? "SET" : "CLEAR");
if (dp_debug_configure_mst_bridge(debug))
DP_ERR("failed to config mst bridge\n");
mutex_unlock(&debug->lock);
return rc;
}
@@ -830,10 +900,13 @@ static ssize_t dp_debug_mst_sideband_mode_write(struct file *file,
return -EINVAL;
}
debug->parser->has_mst_sideband = mst_sideband_mode ? true : false;
debug->dp_debug.mst_port_cnt = mst_port_cnt;
DP_DEBUG("mst_sideband_mode: %d port_cnt:%d\n",
mst_sideband_mode, mst_port_cnt);
if (dp_debug_configure_mst_bridge(debug))
DP_ERR("failed to config mst bridge\n");
return count;
}
@@ -1636,9 +1709,13 @@ static void dp_debug_set_sim_mode(struct dp_debug_private *debug, bool sim)
return;
}
if (dp_debug_configure_mst_bridge(debug))
DP_ERR("failed to config mst bridge\n");
debug->dp_debug.mst_hpd_sim = true;
debug->dp_debug.sim_mode = true;
debug->aux->set_sim_mode(debug->aux, true,
debug->edid, debug->dpcd);
debug->edid, debug->dpcd, debug->sim_bridge);
debug->ctrl->set_sim_mode(debug->ctrl, true);
} else {
if (debug->hotplug) {
@@ -1649,9 +1726,10 @@ static void dp_debug_set_sim_mode(struct dp_debug_private *debug, bool sim)
debug->aux->abort(debug->aux, true);
debug->ctrl->abort(debug->ctrl, true);
debug->aux->set_sim_mode(debug->aux, false, NULL, NULL);
debug->aux->set_sim_mode(debug->aux, false, NULL, NULL, NULL);
debug->ctrl->set_sim_mode(debug->ctrl, false);
debug->dp_debug.sim_mode = false;
debug->dp_debug.mst_hpd_sim = false;
debug->panel->set_edid(debug->panel, 0, 0);
if (debug->edid) {

파일 보기

@@ -992,19 +992,11 @@ static void dp_display_mst_init(struct dp_display_private *dp)
static void dp_display_set_mst_mgr_state(struct dp_display_private *dp,
bool state)
{
struct dp_mst_hpd_info info = {0};
if (!dp->mst.mst_active)
return;
info.mst_protocol = dp->parser->has_mst_sideband;
if (state) {
info.mst_port_cnt = dp->debug->mst_port_cnt;
info.edid = dp->debug->get_edid(dp->debug);
}
if (dp->mst.cbs.set_mgr_state)
dp->mst.cbs.set_mgr_state(&dp->dp_display, state, &info);
dp->mst.cbs.set_mgr_state(&dp->dp_display, state);
DP_MST_DEBUG("mst_mgr_state: %d\n", state);
}
@@ -1585,19 +1577,8 @@ static int dp_display_stream_enable(struct dp_display_private *dp,
static void dp_display_mst_attention(struct dp_display_private *dp)
{
struct dp_mst_hpd_info hpd_irq = {0};
if (dp->mst.mst_active && dp->mst.cbs.hpd_irq) {
hpd_irq.mst_hpd_sim = dp->debug->mst_hpd_sim;
hpd_irq.mst_sim_add_con = dp->debug->mst_sim_add_con;
hpd_irq.mst_sim_remove_con = dp->debug->mst_sim_remove_con;
hpd_irq.mst_sim_remove_con_id = dp->debug->mst_sim_remove_con_id;
hpd_irq.edid = dp->debug->get_edid(dp->debug);
dp->mst.cbs.hpd_irq(&dp->dp_display, &hpd_irq);
dp->debug->mst_hpd_sim = false;
dp->debug->mst_sim_add_con = false;
dp->debug->mst_sim_remove_con = false;
}
if (dp->mst.mst_active && dp->mst.cbs.hpd_irq)
dp->mst.cbs.hpd_irq(&dp->dp_display);
DP_MST_DEBUG("mst_attention_work. mst_active:%d\n", dp->mst.mst_active);
}

파일 보기

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _DP_DISPLAY_H_
@@ -18,23 +18,12 @@ enum dp_drv_state {
PM_SUSPEND,
};
struct dp_mst_hpd_info {
bool mst_protocol;
bool mst_hpd_sim;
u32 mst_port_cnt;
u8 *edid;
bool mst_sim_add_con;
bool mst_sim_remove_con;
int mst_sim_remove_con_id;
};
struct dp_mst_drm_cbs {
void (*hpd)(void *display, bool hpd_status);
void (*hpd_irq)(void *display, struct dp_mst_hpd_info *info);
void (*hpd_irq)(void *display);
void (*set_drv_state)(void *dp_display,
enum dp_drv_state mst_state);
int (*set_mgr_state)(void *dp_display, bool state,
struct dp_mst_hpd_info *info);
int (*set_mgr_state)(void *dp_display, bool state);
};
struct dp_mst_drm_install_info {

파일 보기

@@ -86,34 +86,12 @@ struct dp_drm_mst_fw_helper_ops {
struct drm_dp_mst_port *port);
};
struct dp_mst_sim_port_data {
bool input_port;
u8 peer_device_type;
u8 port_number;
bool mcs;
bool ddps;
bool legacy_device_plug_status;
u8 dpcd_revision;
u8 peer_guid[16];
u8 num_sdp_streams;
u8 num_sdp_stream_sinks;
};
struct dp_mst_sim_port_edid {
u8 port_number;
u8 edid[SZ_256];
bool valid;
};
struct dp_mst_sim_mode {
bool mst_state;
struct edid *edid;
struct dp_mst_sim_port_edid port_edids[DP_MST_SIM_MAX_PORTS];
struct work_struct probe_work;
const struct drm_dp_mst_topology_cbs *cbs;
u32 port_cnt;
};
struct dp_mst_bridge {
struct drm_bridge base;
struct drm_private_obj obj;
@@ -153,7 +131,6 @@ struct dp_mst_private {
struct dp_mst_bridge mst_bridge[MAX_DP_MST_DRM_BRIDGES];
struct dp_display *dp_display;
const struct dp_drm_mst_fw_helper_ops *mst_fw_cbs;
struct dp_mst_sim_mode simulator;
struct mutex mst_lock;
struct mutex edid_lock;
enum dp_drv_state state;
@@ -176,22 +153,6 @@ struct dp_mst_encoder_info_cache {
struct dp_mst_private dp_mst;
struct dp_mst_encoder_info_cache dp_mst_enc_cache;
static void dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
{
struct dp_mst_private *mst = container_of(mgr, struct dp_mst_private,
mst_mgr);
struct drm_device *dev = mst->dp_display->drm_dev;
char event_string[] = "HOTPLUG=1";
char *envp[2];
envp[0] = event_string;
envp[1] = NULL;
kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
DP_MST_INFO("mst hot plug event\n");
}
static struct drm_private_state *dp_mst_duplicate_bridge_state(
struct drm_private_obj *obj)
{
@@ -231,408 +192,6 @@ static struct dp_mst_bridge_state *dp_mst_get_bridge_atomic_state(
drm_atomic_get_private_obj_state(state, &bridge->obj));
}
static void dp_mst_sim_destroy_port(struct kref *ref)
{
struct drm_dp_mst_port *port = container_of(ref,
struct drm_dp_mst_port, topology_kref);
struct drm_dp_mst_topology_mgr *mgr = port->mgr;
if (port->cached_edid)
kfree(port->cached_edid);
if (port->connector) {
mutex_lock(&mgr->delayed_destroy_lock);
list_add(&port->next, &mgr->destroy_port_list);
mutex_unlock(&mgr->delayed_destroy_lock);
schedule_work(&mgr->delayed_destroy_work);
return;
}
drm_dp_mst_put_port_malloc(port);
}
static void dp_mst_sim_topology_get_port(struct drm_dp_mst_port *port)
{
WARN_ON(kref_read(&port->topology_kref) == 0);
kref_get(&port->topology_kref);
DP_MST_DEBUG("get port %p topology(%d)\n", port,
kref_read(&port->topology_kref));
}
static void dp_mst_sim_topology_put_port(struct drm_dp_mst_port *port)
{
DP_MST_DEBUG("put port %p topology(%d)\n", port,
kref_read(&port->topology_kref) - 1);
kref_put(&port->topology_kref, dp_mst_sim_destroy_port);
}
/*
* DRM DP MST Framework simulator OPs
*
* If simulation mode is enabled, on HPD connect, mst mode is enabled on the
* topology manager and 2 simulated ports are created using
* dp_mst_sim_add_port. These 2 ports are added to the MST branch device.
* Each node in the DP MST topology has 2 reference objects one for memory
* allocation and the other for its use on the topology tree. When the last
* topology reference is released on a port, the port gets destroyed and when
* the last malloc reference is released, then the port memory is freed.
* Each port also gets a reference on its parent branch object to make sure
* that the branch is not destroyed prematurely.
*/
static void dp_mst_sim_add_port(struct dp_mst_private *mst,
struct dp_mst_sim_port_data *port_msg)
{
struct drm_dp_mst_branch *mstb;
struct drm_dp_mst_port *port;
mstb = mst->mst_mgr.mst_primary;
if (!mstb) {
DP_ERR("Unable to add port. mst branch device was destroyed\n");
return;
}
port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!port)
return;
kref_init(&port->topology_kref);
kref_init(&port->malloc_kref);
port->parent = mstb;
port->port_num = port_msg->port_number;
port->mgr = mstb->mgr;
port->aux.name = dp_mst.caps.drm_aux->name;
port->aux.dev = mst->dp_display->drm_dev->dev;
/*
* Make sure the memory allocation for our parent branch stays
* around until our own memory allocation is released
*/
kref_get(&mstb->malloc_kref);
port->pdt = port_msg->peer_device_type;
port->input = port_msg->input_port;
port->mcs = port_msg->mcs;
port->ddps = port_msg->ddps;
port->ldps = port_msg->legacy_device_plug_status;
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;
mutex_lock(&mstb->mgr->lock);
dp_mst_sim_topology_get_port(port);
list_add(&port->next, &mstb->ports);
mutex_unlock(&mstb->mgr->lock);
/* use fixed pbn for simulator ports */
port->full_pbn = 2520;
if (!port->input) {
port->connector = (*mstb->mgr->cbs->add_connector)
(mstb->mgr, port, NULL);
if (!port->connector) {
/* remove it from the port list */
mutex_lock(&mstb->mgr->lock);
list_del(&port->next);
mutex_unlock(&mstb->mgr->lock);
dp_mst_sim_topology_put_port(port);
goto put_port;
}
drm_connector_register(port->connector);
}
put_port:
dp_mst_sim_topology_put_port(port);
}
static void dp_mst_sim_remove_port(struct dp_mst_private *mst,
struct drm_dp_mst_port *port)
{
struct drm_dp_mst_branch *mstb;
int i;
mstb = mst->mst_mgr.mst_primary;
if (!mstb) {
DP_ERR("Unable to remove port. mst branch device is null\n");
return;
}
mutex_lock(&mstb->mgr->lock);
list_del(&port->next);
mutex_unlock(&mstb->mgr->lock);
dp_mst_sim_topology_put_port(port);
for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) {
if (mst->simulator.port_edids[i].port_number ==
port->port_num) {
mst->simulator.port_edids[i].valid = false;
}
}
}
static void dp_mst_sim_link_probe_work(struct work_struct *work)
{
struct dp_mst_sim_mode *sim;
struct dp_mst_private *mst;
struct dp_mst_sim_port_data port_data;
u8 cnt, i;
DP_MST_DEBUG("enter\n");
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY);
sim = container_of(work, struct dp_mst_sim_mode, probe_work);
mst = container_of(sim, struct dp_mst_private, simulator);
port_data.input_port = false;
port_data.peer_device_type = DP_PEER_DEVICE_SST_SINK;
port_data.mcs = false;
port_data.ddps = true;
port_data.legacy_device_plug_status = false;
port_data.dpcd_revision = 0;
port_data.num_sdp_streams = 0;
port_data.num_sdp_stream_sinks = 0;
for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++)
sim->port_edids[i].valid = false;
for (cnt = 0; cnt < sim->port_cnt; cnt++) {
port_data.port_number = cnt;
for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) {
if (sim->port_edids[i].valid) continue;
sim->port_edids[i].port_number = port_data.port_number;
memcpy(sim->port_edids[i].edid, sim->edid, SZ_256);
sim->port_edids[i].valid = true;
break;
}
dp_mst_sim_add_port(mst, &port_data);
}
dp_mst_hotplug(&mst->mst_mgr);
DP_MST_DEBUG("completed\n");
}
static int dp_mst_sim_no_action(struct drm_dp_mst_topology_mgr *mgr)
{
return 0;
}
static int dp_mst_sim_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
{
int i, j;
int cur_slots = 1;
struct drm_dp_payload req_payload;
struct drm_dp_mst_port *port;
mutex_lock(&mgr->payload_lock);
for (i = 0; i < mgr->max_payloads; i++) {
req_payload.start_slot = cur_slots;
if (mgr->proposed_vcpis[i]) {
port = container_of(mgr->proposed_vcpis[i],
struct drm_dp_mst_port, vcpi);
req_payload.num_slots =
mgr->proposed_vcpis[i]->num_slots;
req_payload.vcpi = mgr->proposed_vcpis[i]->vcpi;
} else {
port = NULL;
req_payload.num_slots = 0;
}
if (mgr->payloads[i].start_slot != req_payload.start_slot)
mgr->payloads[i].start_slot = req_payload.start_slot;
if (mgr->payloads[i].num_slots != req_payload.num_slots) {
if (req_payload.num_slots) {
req_payload.payload_state = DP_PAYLOAD_LOCAL;
mgr->payloads[i].num_slots =
req_payload.num_slots;
mgr->payloads[i].vcpi = req_payload.vcpi;
} else if (mgr->payloads[i].num_slots) {
mgr->payloads[i].num_slots = 0;
mgr->payloads[i].payload_state =
DP_PAYLOAD_DELETE_LOCAL;
req_payload.payload_state =
mgr->payloads[i].payload_state;
mgr->payloads[i].start_slot = 0;
} else
req_payload.payload_state =
mgr->payloads[i].payload_state;
mgr->payloads[i].payload_state =
req_payload.payload_state;
}
cur_slots += req_payload.num_slots;
}
for (i = 0; i < mgr->max_payloads; i++) {
if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) {
DP_DEBUG("removing payload %d\n", i);
for (j = i; j < mgr->max_payloads - 1; j++) {
memcpy(&mgr->payloads[j],
&mgr->payloads[j + 1],
sizeof(struct drm_dp_payload));
mgr->proposed_vcpis[j] =
mgr->proposed_vcpis[j + 1];
if (mgr->proposed_vcpis[j] &&
mgr->proposed_vcpis[j]->num_slots) {
set_bit(j + 1, &mgr->payload_mask);
} else {
clear_bit(j + 1, &mgr->payload_mask);
}
}
memset(&mgr->payloads[mgr->max_payloads - 1], 0,
sizeof(struct drm_dp_payload));
mgr->proposed_vcpis[mgr->max_payloads - 1] = NULL;
clear_bit(mgr->max_payloads, &mgr->payload_mask);
}
}
mutex_unlock(&mgr->payload_lock);
return 0;
}
static int dp_mst_sim_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr)
{
struct drm_dp_mst_port *port;
int i;
mutex_lock(&mgr->payload_lock);
for (i = 0; i < mgr->max_payloads; i++) {
if (!mgr->proposed_vcpis[i])
continue;
port = container_of(mgr->proposed_vcpis[i],
struct drm_dp_mst_port, vcpi);
DP_DEBUG("payload %d %d\n", i, mgr->payloads[i].payload_state);
if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL)
mgr->payloads[i].payload_state = DP_PAYLOAD_REMOTE;
else if (mgr->payloads[i].payload_state ==
DP_PAYLOAD_DELETE_LOCAL)
mgr->payloads[i].payload_state = 0;
}
mutex_unlock(&mgr->payload_lock);
return 0;
}
static struct edid *dp_mst_sim_get_edid(struct drm_connector *connector,
struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port)
{
struct dp_mst_private *mst = container_of(mgr,
struct dp_mst_private, mst_mgr);
int i;
for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) {
if (mst->simulator.port_edids[i].valid &&
mst->simulator.port_edids[i].port_number ==
port->port_num) {
return drm_edid_duplicate((struct edid *)
(mst->simulator.port_edids[i].edid));
}
}
DRM_ERROR("edid not found for connector %d\n", connector->base.id);
return NULL;
}
static int dp_mst_sim_topology_mgr_set_mst(
struct drm_dp_mst_topology_mgr *mgr,
bool mst_state)
{
int rc;
struct dp_mst_private *mst = container_of(mgr,
struct dp_mst_private, mst_mgr);
DP_MST_DEBUG("enter: mst_state %d\n", mst_state);
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, mst_state);
rc = drm_dp_mst_topology_mgr_set_mst(mgr, mst_state);
if (rc < 0) {
DRM_ERROR("unable to set mst topology mgr, rc: %d\n", rc);
return rc;
}
if (mst_state)
queue_work(system_long_wq, &mst->simulator.probe_work);
mst->simulator.mst_state = mst_state;
return 0;
}
static void dp_mst_sim_handle_hpd_irq(void *dp_display,
struct dp_mst_hpd_info *info)
{
struct dp_display *dp;
struct dp_mst_private *mst;
struct drm_dp_mst_port *port;
struct dp_mst_sim_port_data port_data;
struct drm_dp_mst_branch *mstb;
int i;
bool in_list, port_available;
dp = dp_display;
mst = dp->dp_mst_prv_info;
if (info->mst_sim_add_con) {
port_available = false;
for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) {
if (mst->simulator.port_edids[i].valid) continue;
port_data.port_number = i;
mst->simulator.port_edids[i].port_number = i;
memcpy(mst->simulator.port_edids[i].edid, info->edid,
SZ_256);
mst->simulator.port_edids[i].valid = true;
port_available = true;
break;
}
if (!port_available) {
DRM_ERROR("add port failed, limit (%d) reached\n",
DP_MST_SIM_MAX_PORTS);
return;
}
port_data.input_port = false;
port_data.peer_device_type = DP_PEER_DEVICE_SST_SINK;
port_data.mcs = false;
port_data.ddps = true;
port_data.legacy_device_plug_status = false;
port_data.dpcd_revision = 0;
port_data.num_sdp_streams = 0;
port_data.num_sdp_stream_sinks = 0;
dp_mst_sim_add_port(mst, &port_data);
} else if (info->mst_sim_remove_con) {
mstb = mst->mst_mgr.mst_primary;
in_list = false;
mutex_lock(&mst->mst_mgr.lock);
list_for_each_entry(port,
&mstb->ports, next) {
if (port->connector && port->connector->base.id ==
info->mst_sim_remove_con_id) {
in_list = true;
break;
}
}
mutex_unlock(&mst->mst_mgr.lock);
if (!in_list) {
DRM_ERROR("invalid connector id %d\n",
info->mst_sim_remove_con_id);
return;
} else {
dp_mst_sim_remove_port(mst, port);
}
dp_mst_sim_topology_put_port(port);
}
}
static int dp_mst_detect_port(
struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
@@ -719,23 +278,6 @@ static const struct dp_drm_mst_fw_helper_ops drm_dp_mst_fw_helper_ops = {
.deallocate_vcpi = drm_dp_mst_deallocate_vcpi,
};
static const struct dp_drm_mst_fw_helper_ops drm_dp_sim_mst_fw_helper_ops = {
.calc_pbn_mode = dp_mst_calc_pbn_mode,
.find_vcpi_slots = drm_dp_find_vcpi_slots,
.atomic_find_vcpi_slots = drm_dp_atomic_find_vcpi_slots,
.allocate_vcpi = drm_dp_mst_allocate_vcpi,
.update_payload_part1 = dp_mst_sim_update_payload_part1,
.check_act_status = dp_mst_sim_no_action,
.update_payload_part2 = dp_mst_sim_update_payload_part2,
.detect_port_ctx = dp_mst_detect_port,
.get_edid = dp_mst_sim_get_edid,
.topology_mgr_set_mst = dp_mst_sim_topology_mgr_set_mst,
.get_vcpi_info = _dp_mst_get_vcpi_info,
.atomic_release_vcpi_slots = drm_dp_atomic_release_vcpi_slots,
.reset_vcpi_slots = drm_dp_mst_reset_vcpi_slots,
.deallocate_vcpi = drm_dp_mst_deallocate_vcpi,
};
/* DP MST Bridge OPs */
static int dp_mst_bridge_attach(struct drm_bridge *dp_bridge,
@@ -1008,9 +550,6 @@ static void _dp_mst_bridge_pre_disable_part2(struct dp_mst_bridge *dp_bridge)
port->vcpi.vcpi = dp_bridge->vcpi;
mst->mst_fw_cbs->deallocate_vcpi(&mst->mst_mgr, port);
if (mst->simulator.mst_state)
dp_mst_sim_remove_port(mst, port);
dp_bridge->vcpi = 0;
dp_bridge->pbn = 0;
@@ -2159,8 +1698,7 @@ static void dp_mst_hpd_event_notify(struct dp_mst_private *mst, bool hpd_status)
/* DP Driver Callback OPs */
static int dp_mst_display_set_mgr_state(void *dp_display, bool state,
struct dp_mst_hpd_info *info)
static int dp_mst_display_set_mgr_state(void *dp_display, bool state)
{
int rc;
struct dp_display *dp = dp_display;
@@ -2176,15 +1714,7 @@ static int dp_mst_display_set_mgr_state(void *dp_display, bool state,
if (state)
mst->mst_session_state = state;
if (info && !info->mst_protocol) {
if (state) {
mst->simulator.edid = (struct edid *)info->edid;
mst->simulator.port_cnt = info->mst_port_cnt;
}
mst->mst_fw_cbs = &drm_dp_sim_mst_fw_helper_ops;
} else {
mst->mst_fw_cbs = &drm_dp_mst_fw_helper_ops;
}
mst->mst_fw_cbs = &drm_dp_mst_fw_helper_ops;
rc = mst->mst_fw_cbs->topology_mgr_set_mst(&mst->mst_mgr, state);
if (rc < 0) {
@@ -2215,8 +1745,7 @@ static void dp_mst_display_hpd(void *dp_display, bool hpd_status)
dp_mst_hpd_event_notify(mst, hpd_status);
}
static void dp_mst_display_hpd_irq(void *dp_display,
struct dp_mst_hpd_info *info)
static void dp_mst_display_hpd_irq(void *dp_display)
{
int rc;
struct dp_display *dp = dp_display;
@@ -2228,26 +1757,6 @@ static void dp_mst_display_hpd_irq(void *dp_display,
struct drm_connector *conn;
struct sde_connector *c_conn;
if (info->mst_hpd_sim) {
if (mst->simulator.mst_state && (info->mst_sim_add_con ||
info->mst_sim_remove_con)) {
dp_mst_sim_handle_hpd_irq(dp_display, info);
/*
* When removing a connector, hpd_irq -> sim_destroy ->
* destroy_connector_work will be executed in a thread.
* This thread will perform the dp_mst_hotplug at the
* appropriate time. Do not perform hotplug here
* because it may be too early.
*/
if (info->mst_sim_remove_con)
return;
}
dp_mst_hotplug(&mst->mst_mgr);
return;
}
if (!mst->mst_session_state) {
DP_ERR("mst_hpd_irq received before mst session start\n");
return;
@@ -2324,12 +1833,6 @@ static const struct drm_dp_mst_topology_cbs dp_mst_fixed_drm_cbs = {
.add_connector = dp_mst_add_fixed_connector,
};
static void dp_mst_sim_init(struct dp_mst_private *mst)
{
INIT_WORK(&mst->simulator.probe_work, dp_mst_sim_link_probe_work);
mst->simulator.cbs = &dp_mst_drm_cbs;
}
int dp_mst_init(struct dp_display *dp_display)
{
struct drm_device *dev;
@@ -2378,8 +1881,6 @@ int dp_mst_init(struct dp_display *dp_display)
goto error;
}
dp_mst_sim_init(&dp_mst);
dp_mst.mst_initialized = true;
/* create drm_bridges for cached mst encoders and clear cache */