diff --git a/msm/dp/dp_aux.c b/msm/dp/dp_aux.c index 56853ae4c3..e75e10e7a4 100644 --- a/msm/dp/dp_aux.c +++ b/msm/dp/dp_aux.c @@ -29,6 +29,7 @@ struct dp_aux_private { struct dp_aux_bridge *aux_bridge; struct dp_aux_bridge *sim_bridge; bool bridge_in_transfer; + bool sim_in_transfer; bool cmd_busy; bool native; @@ -43,9 +44,6 @@ struct dp_aux_private { u32 retry_cnt; atomic_t aborted; - - u8 *dpcd; - u8 *edid; }; #ifdef CONFIG_DYNAMIC_DEBUG @@ -477,114 +475,6 @@ static inline bool dp_aux_is_sideband_msg(u32 address, size_t size) (address >= 0x2000 && address + size < 0x2200); } -static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux, - struct drm_dp_aux_msg *msg) -{ - u32 timeout; - ssize_t ret; - struct dp_aux_private *aux = container_of(drm_aux, - struct dp_aux_private, drm_aux); - - mutex_lock(&aux->mutex); - - ret = dp_aux_transfer_ready(aux, msg, false); - if (ret) - goto end; - - aux->aux_error_num = DP_AUX_ERR_NONE; - - if (!aux->dpcd || !aux->edid) { - DP_ERR("invalid aux/dpcd structure\n"); - goto end; - } - - 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; - } - - if (aux->native) { - mutex_lock(aux->dp_aux.access_lock); - aux->dp_aux.reg = msg->address; - aux->dp_aux.read = aux->read; - aux->dp_aux.size = msg->size; - - if (!aux->read) - memcpy(aux->dpcd + msg->address, - msg->buffer, msg->size); - - reinit_completion(&aux->comp); - mutex_unlock(aux->dp_aux.access_lock); - - timeout = wait_for_completion_timeout(&aux->comp, HZ * 2); - if (!timeout) { - DP_ERR("%s timeout: 0x%x\n", - aux->read ? "read" : "write", - msg->address); - atomic_set(&aux->aborted, 1); - ret = -ETIMEDOUT; - goto end; - } - - mutex_lock(aux->dp_aux.access_lock); - 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; - } else { - if (aux->read && msg->address == 0x50) { - memcpy(msg->buffer, - aux->edid + aux->offset - 16, - msg->size); - } - } - - if (aux->aux_error_num == DP_AUX_ERR_NONE) { - dp_aux_hex_dump(drm_aux, msg); - - if (!aux->read) - memset(msg->buffer, 0, msg->size); - - msg->reply = aux->native ? - DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; - } else { - /* Reply defer to retry */ - msg->reply = aux->native ? - DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER; - } - - ret = msg->size; - goto end; - -address_error: - memset(msg->buffer, 0, msg->size); - ret = msg->size; -end: - if (ret == -ETIMEDOUT) - aux->dp_aux.state |= DP_STATE_AUX_TIMEOUT; - aux->dp_aux.reg = 0xFFFF; - aux->dp_aux.read = true; - aux->dp_aux.size = 0; - - mutex_unlock(&aux->mutex); - return ret; -} - /* * This function does the real job to process an AUX transaction. * It will call aux_reset() function to reset the AUX channel, @@ -664,6 +554,28 @@ static ssize_t dp_aux_bridge_transfer(struct drm_dp_aux *drm_aux, return size; } +static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux, + struct drm_dp_aux_msg *msg) +{ + struct dp_aux_private *aux = container_of(drm_aux, + struct dp_aux_private, drm_aux); + ssize_t size; + + if (aux->sim_in_transfer) { + if (aux->aux_bridge && aux->aux_bridge->transfer) + size = dp_aux_bridge_transfer(drm_aux, msg); + else + size = dp_aux_transfer(drm_aux, msg); + } else { + aux->sim_in_transfer = true; + size = aux->sim_bridge->transfer(aux->sim_bridge, + drm_aux, msg); + aux->sim_in_transfer = false; + } + + return size; +} + static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg *aux_cfg) { int i = 0; @@ -758,24 +670,8 @@ static void dp_aux_deregister(struct dp_aux *dp_aux) drm_dp_aux_unregister(&aux->drm_aux); } -static void dp_aux_dpcd_updated(struct dp_aux *dp_aux) -{ - struct dp_aux_private *aux; - - if (!dp_aux) { - DP_ERR("invalid input\n"); - return; - } - - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); - - /* make sure wait has started */ - usleep_range(20, 30); - complete(&aux->comp); -} - -static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en, - u8 *edid, u8 *dpcd, struct dp_aux_bridge *sim_bridge) +static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, + struct dp_aux_bridge *sim_bridge) { struct dp_aux_private *aux; @@ -788,11 +684,9 @@ static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en, mutex_lock(&aux->mutex); - aux->edid = edid; - aux->dpcd = dpcd; aux->sim_bridge = sim_bridge; - if (en) { + if (sim_bridge) { atomic_set(&aux->aborted, 0); aux->drm_aux.transfer = dp_aux_transfer_debug; } else if (aux->aux_bridge && aux->aux_bridge->transfer) { @@ -884,7 +778,6 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, aux->aux_bridge = aux_bridge; dp_aux = &aux->dp_aux; aux->retry_cnt = 0; - aux->dp_aux.reg = 0xFFFF; dp_aux->isr = dp_aux_isr; dp_aux->init = dp_aux_init; @@ -893,7 +786,6 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, dp_aux->drm_aux_deregister = dp_aux_deregister; dp_aux->reconfig = dp_aux_reconfig; dp_aux->abort = dp_aux_abort_transaction; - dp_aux->dpcd_updated = dp_aux_dpcd_updated; dp_aux->set_sim_mode = dp_aux_set_sim_mode; dp_aux->aux_switch = dp_aux_configure_aux_switch; diff --git a/msm/dp/dp_aux.h b/msm/dp/dp_aux.h index d297d02e2c..28f62c5ba4 100644 --- a/msm/dp/dp_aux.h +++ b/msm/dp/dp_aux.h @@ -36,8 +36,6 @@ enum dp_aux_error { }; struct dp_aux { - u32 reg; - u32 size; u32 state; bool read; @@ -52,8 +50,7 @@ struct dp_aux { void (*deinit)(struct dp_aux *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, struct dp_aux_bridge *sim_bridge); int (*aux_switch)(struct dp_aux *aux, bool enable, int orientation); }; diff --git a/msm/dp/dp_debug.c b/msm/dp/dp_debug.c index 5e6dd1b38f..44134ee315 100644 --- a/msm/dp/dp_debug.c +++ b/msm/dp/dp_debug.c @@ -5,6 +5,8 @@ #include #include +#include +#include #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); } diff --git a/msm/dp/dp_debug.h b/msm/dp/dp_debug.h index 4a1cdf7dc3..5f7311828b 100644 --- a/msm/dp/dp_debug.h +++ b/msm/dp/dp_debug.h @@ -48,57 +48,39 @@ /** * struct dp_debug - * @debug_en: specifies whether debug mode enabled * @sim_mode: specifies whether sim mode enabled * @psm_enabled: specifies whether psm enabled * @hdcp_disabled: specifies if hdcp is disabled * @hdcp_wait_sink_sync: used to wait for sink synchronization before HDCP auth - * @aspect_ratio: used to filter out aspect_ratio value - * @vdisplay: used to filter out vdisplay value - * @hdisplay: used to filter out hdisplay value - * @vrefresh: used to filter out vrefresh value * @tpg_state: specifies whether tpg feature is enabled * @max_pclk_khz: max pclk supported * @force_encryption: enable/disable forced encryption for HDCP 2.2 * @skip_uevent: skip hotplug uevent to the user space * @hdcp_status: string holding hdcp status information - * @dp_mst_connector_list: list containing all dp mst connectors - * @mst_hpd_sim: specifies whether simulated hpd enabled * @mst_sim_add_con: specifies whether new sim connector is to be added * @mst_sim_remove_con: specifies whether sim connector is to be removed * @mst_sim_remove_con_id: specifies id of sim connector to be removed - * @mst_port_cnt: number of mst ports to be added during hpd * @connect_notification_delay_ms: time (in ms) to wait for any attention * messages before sending the connect notification uevent * @disconnect_delay_ms: time (in ms) to wait before turning off the mainlink * in response to HPD low of cable disconnect event */ struct dp_debug { - bool debug_en; bool sim_mode; bool psm_enabled; bool hdcp_disabled; bool hdcp_wait_sink_sync; - int aspect_ratio; - int vdisplay; - int hdisplay; - int vrefresh; bool tpg_state; u32 max_pclk_khz; bool force_encryption; bool skip_uevent; char hdcp_status[SZ_128]; - struct dp_mst_connector dp_mst_connector_list; - bool mst_hpd_sim; bool mst_sim_add_con; bool mst_sim_remove_con; int mst_sim_remove_con_id; - u32 mst_port_cnt; unsigned long connect_notification_delay_ms; u32 disconnect_delay_ms; - struct dp_mst_connector mst_connector_cache; - u8 *(*get_edid)(struct dp_debug *dp_debug); void (*abort)(struct dp_debug *dp_debug); void (*set_mst_con)(struct dp_debug *dp_debug, int con_id); }; diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 9d99670b35..224d0054af 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -1599,7 +1599,7 @@ static void dp_display_attention_work(struct work_struct *work) goto exit; } - if (dp->debug->mst_hpd_sim || !dp_display_state_is(DP_STATE_READY)) { + if (!dp_display_state_is(DP_STATE_READY)) { mutex_unlock(&dp->session_lock); goto mst_attention; } @@ -1740,8 +1740,7 @@ static int dp_display_usbpd_attention_cb(struct device *dev) return 0; } - if ((dp->hpd->hpd_irq && dp_display_state_is(DP_STATE_READY)) || - dp->debug->mst_hpd_sim) { + if (dp->hpd->hpd_irq && dp_display_state_is(DP_STATE_READY)) { queue_work(dp->wq, &dp->attention_work); complete_all(&dp->attention_comp); } else if (dp->process_hpd_connect || @@ -2796,72 +2795,6 @@ static int dp_display_validate_topology(struct dp_display_private *dp, return 0; } -static void dp_display_validate_mst_connectors(struct dp_debug *debug, - struct dp_panel *dp_panel, struct drm_display_mode *mode, - enum drm_mode_status *mode_status, bool *use_default) -{ - struct dp_mst_connector *mst_connector; - int hdis, vdis, vref, ar, _hdis, _vdis, _vref, _ar; - bool in_list = false; - - /* - * If the connector exists in the mst connector list and if debug is - * enabled for that connector, use the mst connector settings from the - * list for validation. Otherwise, use non-mst default settings. - */ - mutex_lock(&debug->dp_mst_connector_list.lock); - - if (list_empty(&debug->dp_mst_connector_list.list)) { - mutex_unlock(&debug->dp_mst_connector_list.lock); - *use_default = true; - return; - } - - list_for_each_entry(mst_connector, &debug->dp_mst_connector_list.list, - list) { - if (mst_connector->con_id != dp_panel->connector->base.id) - continue; - - in_list = true; - - if (!mst_connector->debug_en) { - mutex_unlock(&debug->dp_mst_connector_list.lock); - *use_default = false; - *mode_status = MODE_OK; - return; - } - - hdis = mst_connector->hdisplay; - vdis = mst_connector->vdisplay; - vref = mst_connector->vrefresh; - ar = mst_connector->aspect_ratio; - - _hdis = mode->hdisplay; - _vdis = mode->vdisplay; - _vref = drm_mode_vrefresh(mode); - _ar = mode->picture_aspect_ratio; - - if (hdis == _hdis && vdis == _vdis && vref == _vref && - ar == _ar) { - mutex_unlock(&debug->dp_mst_connector_list.lock); - *use_default = false; - *mode_status = MODE_OK; - return; - } - - break; - } - - mutex_unlock(&debug->dp_mst_connector_list.lock); - - if (in_list) { - *use_default = false; - return; - } - - *use_default = true; -} - static enum drm_mode_status dp_display_validate_mode( struct dp_display *dp_display, void *panel, struct drm_display_mode *mode, @@ -2873,7 +2806,6 @@ static enum drm_mode_status dp_display_validate_mode( enum drm_mode_status mode_status = MODE_BAD; struct dp_display_mode dp_mode; int rc = 0; - bool use_default = true; if (!dp_display || !mode || !panel || !avail_res || !avail_res->max_mixer_width) { @@ -2919,17 +2851,6 @@ static enum drm_mode_status dp_display_validate_mode( if (rc) goto end; - dp_display_validate_mst_connectors(debug, dp_panel, mode, &mode_status, - &use_default); - if (!use_default) - goto end; - - if (debug->debug_en && (mode->hdisplay != debug->hdisplay || - mode->vdisplay != debug->vdisplay || - drm_mode_vrefresh(mode) != debug->vrefresh || - mode->picture_aspect_ratio != debug->aspect_ratio)) - goto end; - mode_status = MODE_OK; end: mutex_unlock(&dp->session_lock); @@ -3281,8 +3202,6 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, struct dp_panel_in panel_in; struct dp_panel *dp_panel; struct dp_display_private *dp; - struct dp_mst_connector *mst_connector; - struct dp_mst_connector *cached_connector; if (!dp_display || !connector) { DP_ERR("invalid input\n"); @@ -3326,38 +3245,6 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, DP_MST_DEBUG("dp mst connector installed. conn:%d\n", connector->base.id); - mutex_lock(&dp->debug->dp_mst_connector_list.lock); - - mst_connector = kmalloc(sizeof(struct dp_mst_connector), - GFP_KERNEL); - if (!mst_connector) { - mutex_unlock(&dp->debug->dp_mst_connector_list.lock); - rc = -ENOMEM; - goto end; - } - - cached_connector = &dp->debug->mst_connector_cache; - if (cached_connector->debug_en) { - mst_connector->debug_en = true; - mst_connector->hdisplay = cached_connector->hdisplay; - mst_connector->vdisplay = cached_connector->vdisplay; - mst_connector->vrefresh = cached_connector->vrefresh; - mst_connector->aspect_ratio = cached_connector->aspect_ratio; - memset(cached_connector, 0, sizeof(*cached_connector)); - dp->debug->set_mst_con(dp->debug, connector->base.id); - } else { - mst_connector->debug_en = false; - } - - mst_connector->conn = connector; - mst_connector->con_id = connector->base.id; - mst_connector->state = connector_status_unknown; - INIT_LIST_HEAD(&mst_connector->list); - - list_add(&mst_connector->list, - &dp->debug->dp_mst_connector_list.list); - - mutex_unlock(&dp->debug->dp_mst_connector_list.lock); end: mutex_unlock(&dp->session_lock); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, rc); @@ -3372,7 +3259,6 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display, struct sde_connector *sde_conn; struct dp_panel *dp_panel; struct dp_display_private *dp; - struct dp_mst_connector *con_to_remove, *temp_con; if (!dp_display || !connector) { DP_ERR("invalid input\n"); @@ -3404,64 +3290,12 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display, DP_MST_DEBUG("dp mst connector uninstalled. conn:%d\n", connector->base.id); - mutex_lock(&dp->debug->dp_mst_connector_list.lock); - - list_for_each_entry_safe(con_to_remove, temp_con, - &dp->debug->dp_mst_connector_list.list, list) { - if (con_to_remove->conn == connector) { - /* - * cache any debug info if enabled that can be applied - * on new connectors. - */ - if (con_to_remove->debug_en) - memcpy(&dp->debug->mst_connector_cache, - con_to_remove, - sizeof(*con_to_remove)); - - list_del(&con_to_remove->list); - kfree(con_to_remove); - } - } - - mutex_unlock(&dp->debug->dp_mst_connector_list.lock); mutex_unlock(&dp->session_lock); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); return rc; } -static int dp_display_mst_get_connector_info(struct dp_display *dp_display, - struct drm_connector *connector, - struct dp_mst_connector *mst_conn) -{ - struct dp_display_private *dp; - struct dp_mst_connector *conn, *temp_conn; - - if (!connector || !mst_conn) { - DP_ERR("invalid input\n"); - return -EINVAL; - } - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - mutex_lock(&dp->session_lock); - if (!dp->mst.drm_registered) { - DP_DEBUG("drm mst not registered\n"); - mutex_unlock(&dp->session_lock); - return -EPERM; - } - - mutex_lock(&dp->debug->dp_mst_connector_list.lock); - list_for_each_entry_safe(conn, temp_conn, - &dp->debug->dp_mst_connector_list.list, list) { - if (conn->con_id == connector->base.id) - memcpy(mst_conn, conn, sizeof(*mst_conn)); - } - mutex_unlock(&dp->debug->dp_mst_connector_list.lock); - mutex_unlock(&dp->session_lock); - return 0; -} - static int dp_display_mst_connector_update_edid(struct dp_display *dp_display, struct drm_connector *connector, struct edid *edid) @@ -3710,8 +3544,6 @@ static int dp_display_probe(struct platform_device *pdev) g_dp_display->set_stream_info = dp_display_set_stream_info; g_dp_display->update_pps = dp_display_update_pps; g_dp_display->convert_to_dp_mode = dp_display_convert_to_dp_mode; - g_dp_display->mst_get_connector_info = - dp_display_mst_get_connector_info; g_dp_display->mst_get_fixed_topology_port = dp_display_mst_get_fixed_topology_port; g_dp_display->wakeup_phy_layer = diff --git a/msm/dp/dp_display.h b/msm/dp/dp_display.h index 078a38fe05..916ce78d69 100644 --- a/msm/dp/dp_display.h +++ b/msm/dp/dp_display.h @@ -11,7 +11,6 @@ #include "dp_panel.h" -#define DP_MST_SIM_MAX_PORTS 8 enum dp_drv_state { PM_DEFAULT, @@ -38,19 +37,6 @@ struct dp_mst_caps { struct drm_dp_aux *drm_aux; }; -struct dp_mst_connector { - bool debug_en; - int con_id; - int hdisplay; - int vdisplay; - int vrefresh; - int aspect_ratio; - struct drm_connector *conn; - struct mutex lock; - struct list_head list; - enum drm_connector_status state; -}; - struct dp_display { struct drm_device *drm_dev; struct dp_bridge *bridge; @@ -100,9 +86,6 @@ struct dp_display { struct edid *edid); int (*mst_connector_update_link_info)(struct dp_display *dp_display, struct drm_connector *connector); - int (*mst_get_connector_info)(struct dp_display *dp_display, - struct drm_connector *connector, - struct dp_mst_connector *mst_conn); int (*mst_get_fixed_topology_port)(struct dp_display *dp_display, u32 strm_id, u32 *port_num); int (*get_mst_caps)(struct dp_display *dp_display, diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index 29fdfb91fb..e6ec6b0a2b 100644 --- a/msm/dp/dp_drm.c +++ b/msm/dp/dp_drm.c @@ -654,10 +654,11 @@ enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode, void *display, const struct msm_resource_caps_info *avail_res) { - int rc = 0; + int rc = 0, vrefresh; struct dp_display *dp_disp; struct sde_connector *sde_conn; struct msm_resource_caps_info avail_dp_res; + struct dp_panel *dp_panel; if (!mode || !display || !connector) { DP_ERR("invalid params\n"); @@ -671,6 +672,9 @@ enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, } dp_disp = display; + dp_panel = sde_conn->drv_panel; + + vrefresh = drm_mode_vrefresh(mode); rc = dp_disp->get_available_dp_resources(dp_disp, avail_res, &avail_dp_res); @@ -679,6 +683,12 @@ enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, return MODE_ERROR; } + if (dp_panel->mode_override && (mode->hdisplay != dp_panel->hdisplay || + mode->vdisplay != dp_panel->vdisplay || + vrefresh != dp_panel->vrefresh || + mode->picture_aspect_ratio != dp_panel->aspect_ratio)) + return MODE_BAD; + return dp_disp->validate_mode(dp_disp, sde_conn->drv_panel, mode, &avail_dp_res); } diff --git a/msm/dp/dp_mst_drm.c b/msm/dp/dp_mst_drm.c index c01851569f..e74ce9f847 100644 --- a/msm/dp/dp_mst_drm.c +++ b/msm/dp/dp_mst_drm.c @@ -896,25 +896,27 @@ dp_mst_connector_detect(struct drm_connector *connector, bool force, struct sde_connector *c_conn = to_sde_connector(connector); struct dp_display *dp_display = c_conn->display; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; - enum drm_connector_status status; - struct dp_mst_connector mst_conn; + struct dp_panel *dp_panel; struct drm_modeset_acquire_ctx ctx; + enum drm_connector_status status; DP_MST_DEBUG("enter:\n"); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY); + if (!c_conn->drv_panel || !c_conn->mst_port) { + DP_DEBUG("conn %d is invalid\n"); + return connector_status_disconnected; + } + + dp_panel = c_conn->drv_panel; + + if (dp_panel->mst_hide) + return connector_status_disconnected; + drm_modeset_acquire_init(&ctx, 0); status = mst->mst_fw_cbs->detect_port_ctx(connector, - &ctx, &mst->mst_mgr, - c_conn->mst_port); - - memset(&mst_conn, 0, sizeof(mst_conn)); - dp_display->mst_get_connector_info(dp_display, connector, &mst_conn); - if (mst_conn.conn == connector && - mst_conn.state != connector_status_unknown) { - status = mst_conn.state; - } + &ctx, &mst->mst_mgr, c_conn->mst_port); DP_MST_INFO("conn:%d status:%d\n", connector->base.id, status); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, connector->base.id, status); @@ -989,10 +991,11 @@ enum drm_mode_status dp_mst_connector_mode_valid( struct sde_connector *c_conn; struct drm_dp_mst_port *mst_port; struct dp_display_mode dp_mode; + struct dp_panel *dp_panel; uint16_t full_pbn, required_pbn; int available_slots, required_slots; struct dp_mst_bridge_state *dp_bridge_state; - int i, slots_in_use = 0, active_enc_cnt = 0; + int i, vrefresh, slots_in_use = 0, active_enc_cnt = 0; const u32 tot_slots = 63; if (!connector || !mode || !display) { @@ -1003,6 +1006,18 @@ enum drm_mode_status dp_mst_connector_mode_valid( mst = dp_display->dp_mst_prv_info; c_conn = to_sde_connector(connector); mst_port = c_conn->mst_port; + dp_panel = c_conn->drv_panel; + + if (!dp_panel || !mst_port) + return MODE_ERROR; + + vrefresh = drm_mode_vrefresh(mode); + + if (dp_panel->mode_override && (mode->hdisplay != dp_panel->hdisplay || + mode->vdisplay != dp_panel->vdisplay || + vrefresh != dp_panel->vrefresh || + mode->picture_aspect_ratio != dp_panel->aspect_ratio)) + return MODE_BAD; /* dp bridge state is protected by drm_mode_config.connection_mutex */ for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { @@ -1036,7 +1051,7 @@ enum drm_mode_status dp_mst_connector_mode_valid( return MODE_BAD; } - return dp_connector_mode_valid(connector, mode, display, avail_res); + return dp_display->validate_mode(dp_display, dp_panel, mode, avail_res); } int dp_mst_connector_get_info(struct drm_connector *connector, diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index c4ce5788ae..1097a26825 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -69,8 +69,6 @@ struct dp_panel_private { struct dp_link *link; struct dp_parser *parser; struct dp_catalog_panel *catalog; - bool custom_edid; - bool custom_dpcd; bool panel_on; bool vsc_supported; bool vscext_supported; @@ -1489,11 +1487,6 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func) panel->vscext_supported = false; panel->vscext_chaining_supported = false; - if (panel->custom_dpcd) { - DP_DEBUG("skip dpcd read in debug mode\n"); - goto skip_dpcd_read; - } - rlen = drm_dp_dpcd_read(drm_aux, DP_TRAINING_AUX_RD_INTERVAL, &temp, 1); if (rlen != 1) { DP_ERR("error reading DP_TRAINING_AUX_RD_INTERVAL\n"); @@ -1527,26 +1520,22 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func) if (rlen != 1) { DP_DEBUG("failed to read DPRX_FEATURE_ENUMERATION_LIST\n"); rx_feature = 0; + } else { + panel->vsc_supported = !!(rx_feature & + VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED); + panel->vscext_supported = !!(rx_feature & + VSC_EXT_VESA_SDP_SUPPORTED); + panel->vscext_chaining_supported = !!(rx_feature & + VSC_EXT_VESA_SDP_CHAINING_SUPPORTED); + + DP_DEBUG("vsc=%d, vscext=%d, vscext_chaining=%d\n", + panel->vsc_supported, panel->vscext_supported, + panel->vscext_chaining_supported); } -skip_dpcd_read: - if (panel->custom_dpcd) - rx_feature = dp_panel->dpcd[DP_RECEIVER_CAP_SIZE + 1]; - - panel->vsc_supported = !!(rx_feature & - VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED); - panel->vscext_supported = !!(rx_feature & VSC_EXT_VESA_SDP_SUPPORTED); - panel->vscext_chaining_supported = !!(rx_feature & - VSC_EXT_VESA_SDP_CHAINING_SUPPORTED); - - DP_DEBUG("vsc=%d, vscext=%d, vscext_chaining=%d\n", - panel->vsc_supported, panel->vscext_supported, - panel->vscext_chaining_supported); - link_info->revision = dpcd[DP_DPCD_REV]; panel->major = (link_info->revision >> 4) & 0x0f; panel->minor = link_info->revision & 0x0f; - /* override link params updated in dp_panel_init_panel_info */ link_info->rate = min_t(unsigned long, panel->parser->max_lclk_khz, drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE])); @@ -1617,74 +1606,6 @@ static int dp_panel_set_default_link_params(struct dp_panel *dp_panel) return 0; } -static bool dp_panel_validate_edid(struct edid *edid, size_t edid_size) -{ - if (!edid || (edid_size < EDID_LENGTH)) - return false; - - if (EDID_LENGTH * (edid->extensions + 1) > edid_size) { - DP_ERR("edid size does not match allocated.\n"); - return false; - } - - if (!drm_edid_is_valid(edid)) { - DP_ERR("invalid edid.\n"); - return false; - } - return true; -} - -static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid, - size_t edid_size) -{ - struct dp_panel_private *panel; - - if (!dp_panel) { - DP_ERR("invalid input\n"); - return -EINVAL; - } - - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - - if (edid && dp_panel_validate_edid((struct edid *)edid, edid_size)) { - dp_panel->edid_ctrl->edid = (struct edid *)edid; - panel->custom_edid = true; - } else { - panel->custom_edid = false; - dp_panel->edid_ctrl->edid = NULL; - } - - DP_DEBUG("%d\n", panel->custom_edid); - return 0; -} - -static int dp_panel_set_dpcd(struct dp_panel *dp_panel, u8 *dpcd) -{ - struct dp_panel_private *panel; - u8 *dp_dpcd; - - if (!dp_panel) { - DP_ERR("invalid input\n"); - return -EINVAL; - } - - dp_dpcd = dp_panel->dpcd; - - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - - if (dpcd) { - memcpy(dp_dpcd, dpcd, DP_RECEIVER_CAP_SIZE + - DP_RECEIVER_EXT_CAP_SIZE + 1); - panel->custom_dpcd = true; - } else { - panel->custom_dpcd = false; - } - - DP_DEBUG("%d\n", panel->custom_dpcd); - - return 0; -} - static int dp_panel_read_edid(struct dp_panel *dp_panel, struct drm_connector *connector) { @@ -1699,11 +1620,6 @@ static int dp_panel_read_edid(struct dp_panel *dp_panel, panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - if (panel->custom_edid) { - DP_DEBUG("skip edid read in debug mode\n"); - goto end; - } - sde_get_edid(connector, &panel->aux->drm_aux->ddc, (void **)&dp_panel->edid_ctrl); if (!dp_panel->edid_ctrl->edid) { @@ -2347,7 +2263,7 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags) shdr_if_sdp = &panel->catalog->shdr_if_sdp; vsc_colorimetry = &panel->catalog->vsc_colorimetry; - if (!panel->custom_edid && dp_panel->edid_ctrl->edid) + if (dp_panel->edid_ctrl->edid) sde_free_edid((void **)&dp_panel->edid_ctrl); dp_panel_set_stream_info(dp_panel, DP_STREAM_MAX, 0, 0, 0, 0); @@ -3083,8 +2999,6 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) dp_panel->get_mode_bpp = dp_panel_get_mode_bpp; dp_panel->get_modes = dp_panel_get_modes; dp_panel->handle_sink_request = dp_panel_handle_sink_request; - dp_panel->set_edid = dp_panel_set_edid; - dp_panel->set_dpcd = dp_panel_set_dpcd; dp_panel->tpg_config = dp_panel_tpg_config; dp_panel->spd_config = dp_panel_spd_config; dp_panel->setup_hdr = dp_panel_setup_hdr; diff --git a/msm/dp/dp_panel.h b/msm/dp/dp_panel.h index 595b6bdf28..336df80c84 100644 --- a/msm/dp/dp_panel.h +++ b/msm/dp/dp_panel.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #ifndef _DP_PANEL_H_ @@ -151,6 +151,14 @@ struct dp_panel { bool dsc_continuous_pps; bool mst_state; + /* override debug option */ + bool mst_hide; + bool mode_override; + int hdisplay; + int vdisplay; + int vrefresh; + int aspect_ratio; + s64 fec_overhead_fp; int (*init)(struct dp_panel *dp_panel); @@ -163,8 +171,6 @@ struct dp_panel { int (*get_modes)(struct dp_panel *dp_panel, struct drm_connector *connector, struct dp_display_mode *mode); void (*handle_sink_request)(struct dp_panel *dp_panel); - int (*set_edid)(struct dp_panel *dp_panel, u8 *edid, size_t edid_size); - int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd); int (*setup_hdr)(struct dp_panel *dp_panel, struct drm_msm_ext_hdr_metadata *hdr_meta, bool dhdr_update, u64 core_clk_rate, bool flush);