disp: msm: dp: optimize sim function handling in dp_debug

Remove edid/dpcd simulation function from dp_debug and calls to
sim bridge instead to simplify dp_debug module. Also add mst edid
support and mst hpd simulation from aux level.

Move selected mode from dp_debug module to dp_panel module to
simplify mst handling and decouple dp_debug from main dp driver.

Remove custom edid/dpcd mode from dp_panel and dp_aux module.
Remove mst connector list handling from dp_display module.

Change-Id: Ife1d2deb0e353f0a9695b7b90e5bf3459e1c81f7
Signed-off-by: Xiaowen Wu <wxiaowen@codeaurora.org>
Signed-off-by: Karim Henain <khenain@codeaurora.org>
Signed-off-by: Sudarsan Ramesh <sudarame@codeaurora.org>
此提交包含在:
Xiaowen Wu
2020-07-16 10:47:50 -04:00
提交者 Sudarsan Ramesh
父節點 24d245556e
當前提交 67ce55687b
共有 10 個檔案被更改,包括 328 行新增821 行删除

查看文件

@@ -5,6 +5,8 @@
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_probe_helper.h>
#include "dp_power.h"
#include "dp_catalog.h"
@@ -15,20 +17,20 @@
#include "dp_display.h"
#include "dp_pll.h"
#include "dp_hpd.h"
#include "dp_mst_sim_helper.h"
#include "dp_mst_sim.h"
#define DEBUG_NAME "drm_dp"
struct dp_debug_private {
struct dentry *root;
u8 *edid;
u32 edid_size;
u8 *dpcd;
u32 dpcd_offset;
u32 dpcd_size;
u32 mst_con_id;
u32 mst_edid_idx;
bool hotplug;
u32 sim_mode;
char exe_mode[SZ_32];
char reg_dump[SZ_32];
@@ -59,92 +61,60 @@ static int dp_debug_sim_hpd_cb(void *arg, bool hpd, bool hpd_irq)
return debug->hpd->simulate_connect(debug->hpd, hpd);
}
static int dp_debug_configure_mst_bridge(struct dp_debug_private *debug)
static int dp_debug_attach_sim_bridge(struct dp_debug_private *debug)
{
struct device_node *bridge_node;
struct dp_mst_sim_port *ports;
int i, ret;
int 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)
if (debug->sim_bridge)
return 0;
ports = kcalloc(debug->dp_debug.mst_port_cnt,
sizeof(*ports), GFP_KERNEL);
if (!ports)
return -ENOMEM;
ret = dp_sim_create_bridge(debug->dev, &debug->sim_bridge);
if (ret)
return ret;
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;
}
dp_sim_update_port_num(debug->sim_bridge, 1);
ret = dp_mst_sim_update(debug->sim_bridge->mst_ctx,
debug->dp_debug.mst_port_cnt, ports);
if (debug->sim_bridge->register_hpd)
debug->sim_bridge->register_hpd(debug->sim_bridge,
dp_debug_sim_hpd_cb, debug);
kfree(ports);
return ret;
return 0;
}
static int dp_debug_get_edid_buf(struct dp_debug_private *debug)
static void dp_debug_enable_sim_mode(struct dp_debug_private *debug,
u32 mode_mask)
{
int rc = 0;
/* return if mode is already enabled */
if ((debug->sim_mode & mode_mask) == mode_mask)
return;
if (!debug->edid) {
debug->edid = devm_kzalloc(debug->dev, SZ_256, GFP_KERNEL);
if (!debug->edid) {
rc = -ENOMEM;
goto end;
}
/* create bridge if not yet */
if (dp_debug_attach_sim_bridge(debug))
return;
debug->edid_size = SZ_256;
}
end:
return rc;
/* switch to bridge mode */
if (!debug->sim_mode)
debug->aux->set_sim_mode(debug->aux, debug->sim_bridge);
/* update sim mode */
debug->sim_mode |= mode_mask;
dp_sim_set_sim_mode(debug->sim_bridge, debug->sim_mode);
}
static int dp_debug_get_dpcd_buf(struct dp_debug_private *debug)
static void dp_debug_disable_sim_mode(struct dp_debug_private *debug,
u32 mode_mask)
{
int rc = 0;
/* return if mode is already disabled */
if (!(debug->sim_mode & mode_mask))
return;
if (!debug->dpcd) {
debug->dpcd = devm_kzalloc(debug->dev, SZ_4K, GFP_KERNEL);
if (!debug->dpcd) {
rc = -ENOMEM;
goto end;
}
/* update sim mode */
debug->sim_mode &= ~mode_mask;
dp_sim_set_sim_mode(debug->sim_bridge, debug->sim_mode);
debug->dpcd_size = SZ_4K;
}
end:
return rc;
/* switch to normal mode */
if (!debug->sim_mode)
debug->aux->set_sim_mode(debug->aux, NULL);
}
static ssize_t dp_debug_write_edid(struct file *file,
@@ -178,33 +148,13 @@ static ssize_t dp_debug_write_edid(struct file *file,
edid_size = size / char_to_nib;
buf_t = buf;
size = edid_size;
if (dp_debug_get_edid_buf(debug))
edid = kzalloc(size, GFP_KERNEL);
if (!edid)
goto bail;
if (edid_size != debug->edid_size) {
DP_DEBUG("realloc debug edid\n");
if (debug->edid) {
devm_kfree(debug->dev, debug->edid);
debug->edid = devm_kzalloc(debug->dev,
edid_size, GFP_KERNEL);
if (!debug->edid) {
rc = -ENOMEM;
goto bail;
}
debug->edid_size = edid_size;
debug->aux->set_sim_mode(debug->aux,
debug->dp_debug.sim_mode,
debug->edid, debug->dpcd,
debug->sim_bridge);
}
}
while (edid_size--) {
while (size--) {
char t[3];
int d;
@@ -216,26 +166,16 @@ static ssize_t dp_debug_write_edid(struct file *file,
goto bail;
}
if (debug->edid && (edid_buf_index < debug->edid_size))
debug->edid[edid_buf_index++] = d;
edid[edid_buf_index++] = d;
buf_t += char_to_nib;
}
edid = debug->edid;
dp_debug_enable_sim_mode(debug, DP_SIM_MODE_EDID);
dp_sim_update_port_edid(debug->sim_bridge, debug->mst_edid_idx,
edid, edid_size);
bail:
kfree(buf);
debug->panel->set_edid(debug->panel, edid, debug->edid_size);
/*
* print edid status as this code is executed
* only while running in debug mode which is manually
* triggered by a tester or a script.
*/
DP_INFO("[%s]\n", edid ? "SET" : "CLEAR");
if (dp_debug_configure_mst_bridge(debug))
DP_ERR("failed to config mst bridge\n");
kfree(edid);
mutex_unlock(&debug->lock);
return rc;
@@ -252,7 +192,6 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
ssize_t rc = count;
char offset_ch[5];
u32 offset, data_len;
const u32 dp_receiver_cap_size = 16;
if (!debug)
return -ENODEV;
@@ -284,15 +223,6 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
goto bail;
}
if (dp_debug_get_dpcd_buf(debug))
goto bail;
if (offset == 0xFFFF) {
DP_ERR("clearing dpcd\n");
memset(debug->dpcd, 0, debug->dpcd_size);
goto bail;
}
size -= 4;
if (size == 0)
goto bail;
@@ -301,7 +231,11 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
data_len = dpcd_size;
buf_t = buf + 4;
dpcd_buf_index = offset;
dpcd = kzalloc(dpcd_size, GFP_KERNEL);
if (ZERO_OR_NULL_PTR(dpcd)) {
rc = -ENOMEM;
goto bail;
}
while (dpcd_size--) {
char t[3];
@@ -315,33 +249,33 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
goto bail;
}
if (dpcd_buf_index < debug->dpcd_size)
debug->dpcd[dpcd_buf_index++] = d;
dpcd[dpcd_buf_index++] = d;
buf_t += char_to_nib;
}
dpcd = debug->dpcd;
/*
* if link training status registers are reprogramed,
* read link training status from simulator, otherwise
* read link training status from real aux channel.
*/
if (offset <= DP_LANE0_1_STATUS &&
offset + dpcd_buf_index > DP_LANE0_1_STATUS)
dp_debug_enable_sim_mode(debug,
DP_SIM_MODE_DPCD_READ | DP_SIM_MODE_LINK_TRAIN);
else
dp_debug_enable_sim_mode(debug, DP_SIM_MODE_DPCD_READ);
dp_sim_write_dpcd_reg(debug->sim_bridge,
dpcd, dpcd_buf_index, offset);
debug->dpcd_offset = offset;
debug->dpcd_size = dpcd_buf_index;
bail:
kfree(buf);
if (!dpcd || (size / char_to_nib) >= dp_receiver_cap_size ||
offset == 0xffff) {
debug->panel->set_dpcd(debug->panel, dpcd);
/*
* print dpcd status as this code is executed
* only while running in debug mode which is manually
* triggered by a tester or a script.
*/
if (!dpcd || (offset == 0xffff))
DP_INFO("[%s]\n", "CLEAR");
else
DP_INFO("[%s]\n", "SET");
}
kfree(dpcd);
mutex_unlock(&debug->lock);
debug->aux->dpcd_updated(debug->aux);
return rc;
}
@@ -353,44 +287,42 @@ static ssize_t dp_debug_read_dpcd(struct file *file,
int const buf_size = SZ_4K;
u32 offset = 0;
u32 len = 0;
bool notify = false;
u8 *dpcd;
if (!debug || !debug->aux || !debug->dpcd)
if (!debug || !debug->aux)
return -ENODEV;
mutex_lock(&debug->lock);
if (*ppos)
goto end;
return 0;
buf = kzalloc(buf_size, GFP_KERNEL);
if (!buf)
goto end;
return -ENOMEM;
len += snprintf(buf, buf_size, "0x%x", debug->aux->reg);
mutex_lock(&debug->lock);
dpcd = kzalloc(buf_size, GFP_KERNEL);
if (!dpcd)
goto bail;
if (!debug->aux->read) {
while (1) {
if (debug->aux->reg + offset >= buf_size ||
offset >= debug->aux->size)
break;
dp_sim_read_dpcd_reg(debug->sim_bridge, dpcd,
debug->dpcd_size, debug->dpcd_offset);
len += snprintf(buf + len, buf_size - len, "0x%x",
debug->dpcd[debug->aux->reg + offset++]);
}
len += snprintf(buf, buf_size, "0x%x", debug->dpcd_offset);
notify = true;
while (offset < debug->dpcd_size) {
len += snprintf(buf + len, buf_size - len, "0x%x",
dpcd[debug->dpcd_offset + offset++]);
}
kfree(dpcd);
len = min_t(size_t, count, len);
if (!copy_to_user(user_buff, buf, len))
*ppos += len;
kfree(buf);
end:
bail:
mutex_unlock(&debug->lock);
if (notify)
debug->aux->dpcd_updated(debug->aux);
kfree(buf);
return len;
}
@@ -441,6 +373,7 @@ static ssize_t dp_debug_write_edid_modes(struct file *file,
const char __user *user_buff, size_t count, loff_t *ppos)
{
struct dp_debug_private *debug = file->private_data;
struct dp_panel *panel;
char buf[SZ_32];
size_t len = 0;
int hdisplay = 0, vdisplay = 0, vrefresh = 0, aspect_ratio;
@@ -451,6 +384,8 @@ static ssize_t dp_debug_write_edid_modes(struct file *file,
if (*ppos)
goto end;
panel = debug->panel;
/* Leave room for termination char */
len = min_t(size_t, count, SZ_32 - 1);
if (copy_from_user(buf, user_buff, len))
@@ -465,15 +400,15 @@ static ssize_t dp_debug_write_edid_modes(struct file *file,
if (!hdisplay || !vdisplay || !vrefresh)
goto clear;
debug->dp_debug.debug_en = true;
debug->dp_debug.hdisplay = hdisplay;
debug->dp_debug.vdisplay = vdisplay;
debug->dp_debug.vrefresh = vrefresh;
debug->dp_debug.aspect_ratio = aspect_ratio;
panel->mode_override = true;
panel->hdisplay = hdisplay;
panel->vdisplay = vdisplay;
panel->vrefresh = vrefresh;
panel->aspect_ratio = aspect_ratio;
goto end;
clear:
DP_DEBUG("clearing debug modes\n");
debug->dp_debug.debug_en = false;
panel->mode_override = false;
end:
return len;
}
@@ -482,18 +417,21 @@ static ssize_t dp_debug_write_edid_modes_mst(struct file *file,
const char __user *user_buff, size_t count, loff_t *ppos)
{
struct dp_debug_private *debug = file->private_data;
struct dp_mst_connector *mst_connector;
struct drm_connector *connector;
struct sde_connector *sde_conn;
struct dp_panel *panel = NULL;
char buf[SZ_512];
char *read_buf;
size_t len = 0;
int hdisplay = 0, vdisplay = 0, vrefresh = 0, aspect_ratio = 0;
int con_id = 0, offset = 0, debug_en = 0;
bool in_list = false;
if (!debug)
return -ENODEV;
mutex_lock(&debug->lock);
if (*ppos)
goto end;
@@ -504,33 +442,32 @@ static ssize_t dp_debug_write_edid_modes_mst(struct file *file,
buf[len] = '\0';
read_buf = buf;
mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
while (sscanf(read_buf, "%d %d %d %d %d %d%n", &debug_en, &con_id,
&hdisplay, &vdisplay, &vrefresh, &aspect_ratio,
&offset) == 6) {
list_for_each_entry(mst_connector,
&debug->dp_debug.dp_mst_connector_list.list,
list) {
if (mst_connector->con_id == con_id) {
in_list = true;
mst_connector->debug_en = (bool) debug_en;
mst_connector->hdisplay = hdisplay;
mst_connector->vdisplay = vdisplay;
mst_connector->vrefresh = vrefresh;
mst_connector->aspect_ratio = aspect_ratio;
DP_INFO("Setting %dx%dp%d on conn %d\n",
hdisplay, vdisplay, vrefresh, con_id);
connector = drm_connector_lookup((*debug->connector)->dev,
NULL, con_id);
if (connector) {
sde_conn = to_sde_connector(connector);
panel = sde_conn->drv_panel;
if (panel && sde_conn->mst_port) {
panel->mode_override = debug_en;
panel->hdisplay = hdisplay;
panel->vdisplay = vdisplay;
panel->vrefresh = vrefresh;
panel->aspect_ratio = aspect_ratio;
} else {
DP_ERR("connector id %d is not mst\n", con_id);
}
drm_connector_put(connector);
} else {
DP_ERR("invalid connector id %d\n", con_id);
}
if (!in_list)
DP_DEBUG("dp connector id %d is invalid\n", con_id);
in_list = false;
read_buf += offset;
}
mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);
end:
mutex_unlock(&debug->lock);
return len;
}
@@ -538,17 +475,19 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file,
const char __user *user_buff, size_t count, loff_t *ppos)
{
struct dp_debug_private *debug = file->private_data;
struct dp_mst_connector *mst_connector;
struct drm_connector *connector;
struct sde_connector *sde_conn;
struct drm_dp_mst_port *mst_port;
struct dp_panel *dp_panel;
char buf[SZ_32];
size_t len = 0;
int con_id = 0, status;
bool in_list = false;
const int dp_en = BIT(3), hpd_high = BIT(7), hpd_irq = BIT(8);
int vdo = dp_en | hpd_high | hpd_irq;
if (!debug)
return -ENODEV;
mutex_lock(&debug->lock);
if (*ppos)
goto end;
@@ -559,50 +498,49 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file,
buf[len] = '\0';
if (sscanf(buf, "%d %d", &con_id, &status) != 2) {
len = 0;
if (sscanf(buf, "%d %d", &con_id, &status) != 2)
goto end;
}
if (!con_id)
goto clear;
/* Verify that the connector id is for a valid mst connector. */
mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
list_for_each_entry(mst_connector,
&debug->dp_debug.dp_mst_connector_list.list, list) {
if (mst_connector->con_id == con_id) {
in_list = true;
debug->mst_con_id = con_id;
mst_connector->state = status;
break;
}
}
mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);
if (!in_list && status != connector_status_connected) {
connector = drm_connector_lookup((*debug->connector)->dev,
NULL, con_id);
if (!connector) {
DP_ERR("invalid connector id %u\n", con_id);
goto end;
}
if (status == connector_status_unknown)
goto end;
sde_conn = to_sde_connector(connector);
debug->dp_debug.mst_hpd_sim = true;
if (status == connector_status_connected) {
DP_INFO("plug mst connector\n", con_id, status);
debug->dp_debug.mst_sim_add_con = true;
} else {
DP_INFO("unplug mst connector %d\n", con_id, status);
if (!sde_conn->drv_panel || !sde_conn->mst_port) {
DP_ERR("invalid connector state %d\n", con_id);
goto out;
}
debug->hpd->simulate_attention(debug->hpd, vdo);
debug->mst_con_id = con_id;
if (status == connector_status_unknown)
goto out;
mst_port = sde_conn->mst_port;
dp_panel = sde_conn->drv_panel;
if (debug->dp_debug.sim_mode) {
dp_sim_update_port_status(debug->sim_bridge,
mst_port->port_num, status);
} else {
dp_panel->mst_hide = (status == connector_status_disconnected);
drm_kms_helper_hotplug_event(connector->dev);
}
out:
drm_connector_put(connector);
goto end;
clear:
DP_DEBUG("clearing mst_con_id\n");
debug->mst_con_id = 0;
end:
mutex_unlock(&debug->lock);
return len;
}
@@ -626,7 +564,6 @@ static ssize_t dp_debug_write_mst_con_add(struct file *file,
if (copy_from_user(buf, user_buff, len))
goto end;
debug->dp_debug.mst_hpd_sim = true;
debug->dp_debug.mst_sim_add_con = true;
debug->hpd->simulate_attention(debug->hpd, vdo);
end:
@@ -637,7 +574,8 @@ static ssize_t dp_debug_write_mst_con_remove(struct file *file,
const char __user *user_buff, size_t count, loff_t *ppos)
{
struct dp_debug_private *debug = file->private_data;
struct dp_mst_connector *mst_connector;
struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
char buf[SZ_32];
size_t len = 0;
int con_id = 0;
@@ -666,23 +604,20 @@ static ssize_t dp_debug_write_mst_con_remove(struct file *file,
if (!con_id)
goto end;
/* Verify that the connector id is for a valid mst connector. */
mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
list_for_each_entry(mst_connector,
&debug->dp_debug.dp_mst_connector_list.list, list) {
if (mst_connector->con_id == con_id) {
drm_connector_list_iter_begin((*debug->connector)->dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->base.id == con_id) {
in_list = true;
break;
}
}
mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);
drm_connector_list_iter_end(&conn_iter);
if (!in_list) {
DRM_ERROR("invalid connector id %u\n", con_id);
goto end;
}
debug->dp_debug.mst_hpd_sim = true;
debug->dp_debug.mst_sim_remove_con = true;
debug->dp_debug.mst_sim_remove_con_id = con_id;
debug->hpd->simulate_attention(debug->hpd, vdo);
@@ -882,6 +817,8 @@ static ssize_t dp_debug_mst_sideband_mode_write(struct file *file,
if (!debug)
return -ENODEV;
mutex_lock(&debug->lock);
/* Leave room for termination char */
len = min_t(size_t, count, SZ_8 - 1);
if (copy_from_user(buf, user_buff, len))
@@ -891,22 +828,29 @@ static ssize_t dp_debug_mst_sideband_mode_write(struct file *file,
if (sscanf(buf, "%d %u", &mst_sideband_mode, &mst_port_cnt) != 2) {
DP_ERR("invalid input\n");
return -EINVAL;
goto bail;
}
if (mst_port_cnt > DP_MST_SIM_MAX_PORTS) {
DP_ERR("port cnt:%d exceeding max:%d\n", mst_port_cnt,
DP_MST_SIM_MAX_PORTS);
return -EINVAL;
}
if (!mst_port_cnt)
mst_port_cnt = 1;
debug->mst_edid_idx = 0;
if (mst_sideband_mode)
dp_debug_disable_sim_mode(debug, DP_SIM_MODE_MST);
else
dp_debug_enable_sim_mode(debug, DP_SIM_MODE_MST);
dp_sim_update_port_num(debug->sim_bridge, mst_port_cnt);
buf[0] = !mst_sideband_mode;
dp_sim_write_dpcd_reg(debug->sim_bridge, buf, 1, DP_MSTM_CAP);
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");
bail:
mutex_unlock(&debug->lock);
return count;
}
@@ -1129,50 +1073,29 @@ static ssize_t dp_debug_read_edid_modes_mst(struct file *file,
char __user *user_buff, size_t count, loff_t *ppos)
{
struct dp_debug_private *debug = file->private_data;
struct dp_mst_connector *mst_connector;
char *buf;
u32 len = 0, ret = 0, max_size = SZ_4K;
int rc = 0;
struct drm_connector *connector;
struct drm_display_mode *mode;
bool in_list = false;
if (!debug) {
DP_ERR("invalid data\n");
rc = -ENODEV;
goto error;
}
mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
list_for_each_entry(mst_connector,
&debug->dp_debug.dp_mst_connector_list.list, list) {
if (mst_connector->con_id == debug->mst_con_id) {
connector = mst_connector->conn;
in_list = true;
}
}
mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);
if (!in_list) {
DP_ERR("connector %u not in mst list\n", debug->mst_con_id);
rc = -EINVAL;
goto error;
}
if (!connector) {
DP_ERR("connector is NULL\n");
rc = -EINVAL;
goto error;
return -ENODEV;
}
if (*ppos)
goto error;
return 0;
connector = drm_connector_lookup((*debug->connector)->dev,
NULL, debug->mst_con_id);
if (!connector) {
DP_ERR("connector %u not in mst list\n", debug->mst_con_id);
return 0;
}
buf = kzalloc(SZ_4K, GFP_KERNEL);
if (!buf) {
rc = -ENOMEM;
goto error;
}
if (!buf)
goto clean;
mutex_lock(&connector->dev->mode_config.mutex);
list_for_each_entry(mode, &connector->modes, head) {
@@ -1188,17 +1111,15 @@ static ssize_t dp_debug_read_edid_modes_mst(struct file *file,
len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len)) {
kfree(buf);
rc = -EFAULT;
goto error;
len = -EFAULT;
goto clean;
}
*ppos += len;
clean:
kfree(buf);
drm_connector_put(connector);
return len;
error:
return rc;
}
static ssize_t dp_debug_read_mst_con_id(struct file *file,
@@ -1246,11 +1167,13 @@ static ssize_t dp_debug_read_mst_conn_info(struct file *file,
char __user *user_buff, size_t count, loff_t *ppos)
{
struct dp_debug_private *debug = file->private_data;
struct dp_mst_connector *mst_connector;
struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
struct sde_connector *sde_conn;
struct dp_display *display;
char *buf;
u32 len = 0, ret = 0, max_size = SZ_4K;
int rc = 0;
struct drm_connector *connector;
if (!debug) {
DP_ERR("invalid data\n");
@@ -1267,21 +1190,13 @@ static ssize_t dp_debug_read_mst_conn_info(struct file *file,
goto error;
}
mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
list_for_each_entry(mst_connector,
&debug->dp_debug.dp_mst_connector_list.list, list) {
/* Do not print info for head node */
if (mst_connector->con_id == -1)
drm_connector_list_iter_begin((*debug->connector)->dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
sde_conn = to_sde_connector(connector);
display = sde_conn->display;
if (!sde_conn->mst_port ||
display->base_connector != (*debug->connector))
continue;
connector = mst_connector->conn;
if (!connector) {
DP_ERR("connector for id %d is NULL\n",
mst_connector->con_id);
continue;
}
ret = scnprintf(buf + len, max_size,
"conn name:%s, conn id:%d state:%d\n",
connector->name, connector->base.id,
@@ -1289,7 +1204,7 @@ static ssize_t dp_debug_read_mst_conn_info(struct file *file,
if (dp_debug_check_buffer_overflow(ret, &max_size, &len))
break;
}
mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);
drm_connector_list_iter_end(&conn_iter);
len = min_t(size_t, count, len);
if (copy_to_user(user_buff, buf, len)) {
@@ -1643,7 +1558,7 @@ static ssize_t dp_debug_read_hdr_mst(struct file *file,
struct dp_debug_private *debug = file->private_data;
char *buf = NULL;
u32 len = 0, max_size = SZ_4K;
struct dp_mst_connector *mst_connector;
struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
bool in_list = false;
@@ -1652,15 +1567,14 @@ static ssize_t dp_debug_read_hdr_mst(struct file *file,
return -ENODEV;
}
mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
list_for_each_entry(mst_connector,
&debug->dp_debug.dp_mst_connector_list.list, list) {
if (mst_connector->con_id == debug->mst_con_id) {
connector = mst_connector->conn;
drm_connector_list_iter_begin((*debug->connector)->dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->base.id == debug->mst_con_id) {
in_list = true;
break;
}
}
mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);
drm_connector_list_iter_end(&conn_iter);
if (!in_list) {
DP_ERR("connector %u not in mst list\n", debug->mst_con_id);
@@ -1699,24 +1613,15 @@ static ssize_t dp_debug_read_hdr_mst(struct file *file,
static void dp_debug_set_sim_mode(struct dp_debug_private *debug, bool sim)
{
struct drm_connector_list_iter conn_iter;
struct drm_connector *connector;
struct sde_connector *sde_conn;
struct dp_display *display;
struct dp_panel *panel;
if (sim) {
if (dp_debug_get_edid_buf(debug))
return;
if (dp_debug_get_dpcd_buf(debug)) {
devm_kfree(debug->dev, debug->edid);
debug->edid = NULL;
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->sim_bridge);
debug->ctrl->set_sim_mode(debug->ctrl, true);
dp_debug_enable_sim_mode(debug, DP_SIM_MODE_ALL);
} else {
if (debug->hotplug) {
DP_WARN("sim mode off before hotplug disconnect\n");
@@ -1726,23 +1631,24 @@ 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, 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) {
devm_kfree(debug->dev, debug->edid);
debug->edid = NULL;
}
debug->mst_edid_idx = 0;
dp_debug_disable_sim_mode(debug, DP_SIM_MODE_ALL);
}
debug->panel->set_dpcd(debug->panel, 0);
if (debug->dpcd) {
devm_kfree(debug->dev, debug->dpcd);
debug->dpcd = NULL;
/* clear override settings in panel */
drm_connector_list_iter_begin((*debug->connector)->dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
sde_conn = to_sde_connector(connector);
display = sde_conn->display;
if (display->base_connector == (*debug->connector)) {
panel = sde_conn->drv_panel;
panel->mode_override = false;
panel->mst_hide = false;
}
}
drm_connector_list_iter_end(&conn_iter);
/*
* print simulation status as this code is executed
@@ -2067,6 +1973,8 @@ static int dp_debug_init_mst(struct dp_debug_private *debug, struct dentry *dir)
return rc;
}
debugfs_create_u32("mst_edid_idx", 0644, dir, &debug->mst_edid_idx);
return rc;
}
@@ -2485,18 +2393,6 @@ error:
return rc;
}
u8 *dp_debug_get_edid(struct dp_debug *dp_debug)
{
struct dp_debug_private *debug;
if (!dp_debug)
return NULL;
debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
return debug->edid;
}
static void dp_debug_abort(struct dp_debug *dp_debug)
{
struct dp_debug_private *debug;
@@ -2544,7 +2440,6 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in)
goto error;
}
debug->dp_debug.debug_en = false;
debug->hpd = in->hpd;
debug->link = in->link;
debug->panel = in->panel;
@@ -2558,9 +2453,6 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in)
debug->display = in->display;
dp_debug = &debug->dp_debug;
dp_debug->vdisplay = 0;
dp_debug->hdisplay = 0;
dp_debug->vrefresh = 0;
mutex_init(&debug->lock);
@@ -2571,21 +2463,9 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in)
}
debug->aux->access_lock = &debug->lock;
dp_debug->get_edid = dp_debug_get_edid;
dp_debug->abort = dp_debug_abort;
dp_debug->set_mst_con = dp_debug_set_mst_con;
INIT_LIST_HEAD(&dp_debug->dp_mst_connector_list.list);
/*
* Do not associate the head of the list with any connector in order to
* maintain backwards compatibility with the SST use case.
*/
dp_debug->dp_mst_connector_list.con_id = -1;
dp_debug->dp_mst_connector_list.conn = NULL;
dp_debug->dp_mst_connector_list.debug_en = false;
mutex_init(&dp_debug->dp_mst_connector_list.lock);
dp_debug->max_pclk_khz = debug->parser->max_pclk_khz;
return dp_debug;
@@ -2604,6 +2484,9 @@ static int dp_debug_deinit(struct dp_debug *dp_debug)
debugfs_remove_recursive(debug->root);
if (debug->sim_bridge)
dp_sim_destroy_bridge(debug->sim_bridge);
return 0;
}
@@ -2618,14 +2501,7 @@ void dp_debug_put(struct dp_debug *dp_debug)
dp_debug_deinit(dp_debug);
mutex_destroy(&dp_debug->dp_mst_connector_list.lock);
mutex_destroy(&debug->lock);
if (debug->edid)
devm_kfree(debug->dev, debug->edid);
if (debug->dpcd)
devm_kfree(debug->dev, debug->dpcd);
devm_kfree(debug->dev, debug);
}