Loading arch/arm64/boot/dts/qcom/sm6150-sde.dtsi +3 −0 Original line number Diff line number Diff line Loading @@ -351,6 +351,9 @@ qcom,mdss-rot-danger-lut = <0x0 0x0>; qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; qcom,mdss-rot-qos-cpu-mask = <0xf>; qcom,mdss-rot-qos-cpu-dma-latency = <75>; qcom,mdss-default-ot-rd-limit = <32>; qcom,mdss-default-ot-wr-limit = <32>; Loading arch/arm64/configs/vendor/sm8150_defconfig +0 −1 Original line number Diff line number Diff line Loading @@ -413,7 +413,6 @@ CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y CONFIG_DRM_SDE_RSC=y CONFIG_FB_VIRTUAL=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y Loading drivers/gpu/drm/msm/dp/dp_debug.c +341 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ #include <linux/debugfs.h> #include <linux/slab.h> #include "dp_power.h" #include "dp_catalog.h" Loading @@ -35,6 +36,8 @@ struct dp_debug_private { u8 *dpcd; u32 dpcd_size; u32 mst_con_id; char exe_mode[SZ_32]; char reg_dump[SZ_32]; Loading Loading @@ -149,7 +152,7 @@ static ssize_t dp_debug_write_edid(struct file *file, goto bail; } if (edid_buf_index < debug->edid_size) if (debug->edid && (edid_buf_index < debug->edid_size)) debug->edid[edid_buf_index++] = d; buf_t += char_to_nib; Loading Loading @@ -344,6 +347,112 @@ static ssize_t dp_debug_write_edid_modes(struct file *file, return len; } 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; char buf[SZ_32]; 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; if (*ppos) goto end; len = min_t(size_t, count, SZ_32 - 1); if (copy_from_user(buf, user_buff, len)) goto end; 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; } } if (!in_list) pr_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: return len; } 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; char buf[SZ_32]; size_t len = 0; int con_id = 0; bool in_list = false; if (!debug) return -ENODEV; if (*ppos) goto end; /* Leave room for termination char */ len = min_t(size_t, count, SZ_32 - 1); if (copy_from_user(buf, user_buff, len)) goto clear; buf[len] = '\0'; if (kstrtoint(buf, 10, &con_id) != 0) goto clear; 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; break; } } mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); if (!in_list) pr_err("invalid connector id %u\n", con_id); goto end; clear: pr_debug("clearing mst_con_id\n"); debug->mst_con_id = 0; end: return len; } static ssize_t dp_debug_bw_code_write(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -713,6 +822,183 @@ static ssize_t dp_debug_read_edid_modes(struct file *file, return rc; } 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) { pr_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) { pr_err("connector %u not in mst list\n", debug->mst_con_id); rc = -EINVAL; goto error; } if (!connector) { pr_err("connector is NULL\n"); rc = -EINVAL; goto error; } if (*ppos) goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); if (!buf) { rc = -ENOMEM; goto error; } mutex_lock(&connector->dev->mode_config.mutex); list_for_each_entry(mode, &connector->modes, head) { ret = snprintf(buf + len, max_size, "%s %d %d %d %d %d 0x%x\n", mode->name, mode->vrefresh, mode->picture_aspect_ratio, mode->htotal, mode->vtotal, mode->clock, mode->flags); if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) break; } mutex_unlock(&connector->dev->mode_config.mutex); if (copy_to_user(user_buff, buf, len)) { kfree(buf); rc = -EFAULT; goto error; } *ppos += len; kfree(buf); return len; error: return rc; } static ssize_t dp_debug_read_mst_con_id(struct file *file, char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char *buf; u32 len = 0, ret = 0, max_size = SZ_4K; int rc = 0; if (!debug) { pr_err("invalid data\n"); rc = -ENODEV; goto error; } if (*ppos) goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); if (!buf) { rc = -ENOMEM; goto error; } ret = snprintf(buf, max_size, "%u\n", debug->mst_con_id); len += ret; if (copy_to_user(user_buff, buf, len)) { kfree(buf); rc = -EFAULT; goto error; } *ppos += len; kfree(buf); return len; error: return rc; } 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; char *buf; u32 len = 0, ret = 0, max_size = SZ_4K; int rc = 0; struct drm_connector *connector; if (!debug) { pr_err("invalid data\n"); rc = -ENODEV; goto error; } if (*ppos) goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); if (!buf) { rc = -ENOMEM; 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) continue; connector = mst_connector->conn; if (!connector) { pr_err("connector for id %d is NULL\n", mst_connector->con_id); continue; } ret = snprintf(buf + len, max_size, "conn name:%s, conn id:%d\n", connector->name, connector->base.id); if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) break; } mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); if (copy_to_user(user_buff, buf, len)) { kfree(buf); rc = -EFAULT; goto error; } *ppos += len; kfree(buf); return len; error: return rc; } static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -1209,6 +1495,23 @@ static const struct file_operations edid_modes_fops = { .write = dp_debug_write_edid_modes, }; static const struct file_operations edid_modes_mst_fops = { .open = simple_open, .read = dp_debug_read_edid_modes_mst, .write = dp_debug_write_edid_modes_mst, }; static const struct file_operations mst_conn_info_fops = { .open = simple_open, .read = dp_debug_read_mst_conn_info, }; static const struct file_operations mst_con_id_fops = { .open = simple_open, .read = dp_debug_read_mst_con_id, .write = dp_debug_write_mst_con_id, }; static const struct file_operations hpd_fops = { .open = simple_open, .write = dp_debug_write_hpd, Loading Loading @@ -1328,6 +1631,33 @@ static int dp_debug_init(struct dp_debug *dp_debug) goto error_remove_dir; } file = debugfs_create_file("edid_modes_mst", 0644, dir, debug, &edid_modes_mst_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs create edid_modes_mst failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("mst_con_id", 0644, dir, debug, &mst_con_id_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs create mst_con_id failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("mst_con_info", 0644, dir, debug, &mst_conn_info_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs create mst_conn_info failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("hpd", 0644, dir, debug, &hpd_fops); if (IS_ERR_OR_NULL(file)) { Loading Loading @@ -1537,6 +1867,16 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in) dp_debug->get_edid = dp_debug_get_edid; 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; return dp_debug; error: return ERR_PTR(rc); Loading drivers/gpu/drm/msm/dp/dp_debug.h +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "dp_link.h" #include "dp_usbpd.h" #include "dp_aux.h" #include "dp_display.h" /** * struct dp_debug Loading @@ -43,6 +44,7 @@ struct dp_debug { u32 max_pclk_khz; bool force_encryption; char hdcp_status[SZ_128]; struct dp_mst_connector dp_mst_connector_list; u8 *(*get_edid)(struct dp_debug *dp_debug); }; Loading drivers/gpu/drm/msm/dp/dp_display.c +101 −1 Original line number Diff line number Diff line Loading @@ -231,6 +231,10 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) u32 hdcp_auth_state; dp = container_of(dw, struct dp_display_private, hdcp_cb_work); if (!dp->power_on || atomic_read(&dp->aborted)) return; status = &dp->link->hdcp_status; if (status->hdcp_state == HDCP_STATE_INACTIVE) { Loading Loading @@ -294,8 +298,10 @@ static void dp_display_notify_hdcp_status_cb(void *ptr, dp->link->hdcp_status.hdcp_state = state; if (dp->is_connected) mutex_lock(&dp->session_lock); if (dp->power_on && !atomic_read(&dp->aborted)) queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4); mutex_unlock(&dp->session_lock); } static void dp_display_check_source_hdcp_caps(struct dp_display_private *dp) Loading Loading @@ -1648,6 +1654,9 @@ static enum drm_mode_status dp_display_validate_mode( struct dp_panel *dp_panel; struct dp_debug *debug; enum drm_mode_status mode_status = MODE_BAD; bool in_list = false; struct dp_mst_connector *mst_connector; int hdis, vdis, vref, ar, _hdis, _vdis, _vref, _ar; if (!dp_display || !mode || !panel) { pr_err("invalid params\n"); Loading Loading @@ -1691,6 +1700,58 @@ static enum drm_mode_status dp_display_validate_mode( goto end; } /* * 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); goto verify_default; } list_for_each_entry(mst_connector, &debug->dp_mst_connector_list.list, list) { if (mst_connector->con_id == dp_panel->connector->base.id) { in_list = true; if (!mst_connector->debug_en) { mode_status = MODE_OK; mutex_unlock( &debug->dp_mst_connector_list.lock); goto end; } hdis = mst_connector->hdisplay; vdis = mst_connector->vdisplay; vref = mst_connector->vrefresh; ar = mst_connector->aspect_ratio; _hdis = mode->hdisplay; _vdis = mode->vdisplay; _vref = mode->vrefresh; _ar = mode->picture_aspect_ratio; if (hdis == _hdis && vdis == _vdis && vref == _vref && ar == _ar) { mode_status = MODE_OK; mutex_unlock( &debug->dp_mst_connector_list.lock); goto end; } break; } } mutex_unlock(&debug->dp_mst_connector_list.lock); if (in_list) goto end; verify_default: if (debug->debug_en && (mode->hdisplay != debug->hdisplay || mode->vdisplay != debug->vdisplay || mode->vrefresh != debug->vrefresh || Loading Loading @@ -1888,6 +1949,7 @@ 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; if (!dp_display || !connector) { pr_err("invalid input\n"); Loading @@ -1896,8 +1958,11 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, dp = container_of(dp_display, struct dp_display_private, dp_display); mutex_lock(&dp->session_lock); if (!dp->mst.drm_registered) { pr_debug("drm mst not registered\n"); mutex_unlock(&dp->session_lock); return -EPERM; } Loading @@ -1912,6 +1977,7 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, if (IS_ERR(dp_panel)) { rc = PTR_ERR(dp_panel); pr_err("failed to initialize panel, rc = %d\n", rc); mutex_unlock(&dp->session_lock); return rc; } Loading @@ -1920,12 +1986,28 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, rc = PTR_ERR(dp_panel->audio); pr_err("[mst] failed to initialize audio, rc = %d\n", rc); dp_panel->audio = NULL; mutex_unlock(&dp->session_lock); return rc; } 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); mst_connector->debug_en = false; mst_connector->conn = connector; mst_connector->con_id = connector->base.id; 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); mutex_unlock(&dp->session_lock); return 0; } Loading @@ -1936,6 +2018,7 @@ 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) { pr_err("invalid input\n"); Loading @@ -1944,14 +2027,18 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display, dp = container_of(dp_display, struct dp_display_private, dp_display); mutex_lock(&dp->session_lock); if (!dp->mst.drm_registered) { pr_debug("drm mst not registered\n"); mutex_unlock(&dp->session_lock); return -EPERM; } sde_conn = to_sde_connector(connector); if (!sde_conn->drv_panel) { pr_err("invalid panel for connector:%d\n", connector->base.id); mutex_unlock(&dp->session_lock); return -EINVAL; } Loading @@ -1962,6 +2049,19 @@ 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->con_id == connector->base.id) { list_del(&con_to_remove->list); kfree(con_to_remove); } } mutex_unlock(&dp->debug->dp_mst_connector_list.lock); mutex_unlock(&dp->session_lock); return rc; } Loading Loading
arch/arm64/boot/dts/qcom/sm6150-sde.dtsi +3 −0 Original line number Diff line number Diff line Loading @@ -351,6 +351,9 @@ qcom,mdss-rot-danger-lut = <0x0 0x0>; qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; qcom,mdss-rot-qos-cpu-mask = <0xf>; qcom,mdss-rot-qos-cpu-dma-latency = <75>; qcom,mdss-default-ot-rd-limit = <32>; qcom,mdss-default-ot-wr-limit = <32>; Loading
arch/arm64/configs/vendor/sm8150_defconfig +0 −1 Original line number Diff line number Diff line Loading @@ -413,7 +413,6 @@ CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y CONFIG_DRM_SDE_RSC=y CONFIG_FB_VIRTUAL=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y Loading
drivers/gpu/drm/msm/dp/dp_debug.c +341 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ #include <linux/debugfs.h> #include <linux/slab.h> #include "dp_power.h" #include "dp_catalog.h" Loading @@ -35,6 +36,8 @@ struct dp_debug_private { u8 *dpcd; u32 dpcd_size; u32 mst_con_id; char exe_mode[SZ_32]; char reg_dump[SZ_32]; Loading Loading @@ -149,7 +152,7 @@ static ssize_t dp_debug_write_edid(struct file *file, goto bail; } if (edid_buf_index < debug->edid_size) if (debug->edid && (edid_buf_index < debug->edid_size)) debug->edid[edid_buf_index++] = d; buf_t += char_to_nib; Loading Loading @@ -344,6 +347,112 @@ static ssize_t dp_debug_write_edid_modes(struct file *file, return len; } 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; char buf[SZ_32]; 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; if (*ppos) goto end; len = min_t(size_t, count, SZ_32 - 1); if (copy_from_user(buf, user_buff, len)) goto end; 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; } } if (!in_list) pr_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: return len; } 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; char buf[SZ_32]; size_t len = 0; int con_id = 0; bool in_list = false; if (!debug) return -ENODEV; if (*ppos) goto end; /* Leave room for termination char */ len = min_t(size_t, count, SZ_32 - 1); if (copy_from_user(buf, user_buff, len)) goto clear; buf[len] = '\0'; if (kstrtoint(buf, 10, &con_id) != 0) goto clear; 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; break; } } mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); if (!in_list) pr_err("invalid connector id %u\n", con_id); goto end; clear: pr_debug("clearing mst_con_id\n"); debug->mst_con_id = 0; end: return len; } static ssize_t dp_debug_bw_code_write(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -713,6 +822,183 @@ static ssize_t dp_debug_read_edid_modes(struct file *file, return rc; } 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) { pr_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) { pr_err("connector %u not in mst list\n", debug->mst_con_id); rc = -EINVAL; goto error; } if (!connector) { pr_err("connector is NULL\n"); rc = -EINVAL; goto error; } if (*ppos) goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); if (!buf) { rc = -ENOMEM; goto error; } mutex_lock(&connector->dev->mode_config.mutex); list_for_each_entry(mode, &connector->modes, head) { ret = snprintf(buf + len, max_size, "%s %d %d %d %d %d 0x%x\n", mode->name, mode->vrefresh, mode->picture_aspect_ratio, mode->htotal, mode->vtotal, mode->clock, mode->flags); if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) break; } mutex_unlock(&connector->dev->mode_config.mutex); if (copy_to_user(user_buff, buf, len)) { kfree(buf); rc = -EFAULT; goto error; } *ppos += len; kfree(buf); return len; error: return rc; } static ssize_t dp_debug_read_mst_con_id(struct file *file, char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char *buf; u32 len = 0, ret = 0, max_size = SZ_4K; int rc = 0; if (!debug) { pr_err("invalid data\n"); rc = -ENODEV; goto error; } if (*ppos) goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); if (!buf) { rc = -ENOMEM; goto error; } ret = snprintf(buf, max_size, "%u\n", debug->mst_con_id); len += ret; if (copy_to_user(user_buff, buf, len)) { kfree(buf); rc = -EFAULT; goto error; } *ppos += len; kfree(buf); return len; error: return rc; } 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; char *buf; u32 len = 0, ret = 0, max_size = SZ_4K; int rc = 0; struct drm_connector *connector; if (!debug) { pr_err("invalid data\n"); rc = -ENODEV; goto error; } if (*ppos) goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); if (!buf) { rc = -ENOMEM; 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) continue; connector = mst_connector->conn; if (!connector) { pr_err("connector for id %d is NULL\n", mst_connector->con_id); continue; } ret = snprintf(buf + len, max_size, "conn name:%s, conn id:%d\n", connector->name, connector->base.id); if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) break; } mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); if (copy_to_user(user_buff, buf, len)) { kfree(buf); rc = -EFAULT; goto error; } *ppos += len; kfree(buf); return len; error: return rc; } static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -1209,6 +1495,23 @@ static const struct file_operations edid_modes_fops = { .write = dp_debug_write_edid_modes, }; static const struct file_operations edid_modes_mst_fops = { .open = simple_open, .read = dp_debug_read_edid_modes_mst, .write = dp_debug_write_edid_modes_mst, }; static const struct file_operations mst_conn_info_fops = { .open = simple_open, .read = dp_debug_read_mst_conn_info, }; static const struct file_operations mst_con_id_fops = { .open = simple_open, .read = dp_debug_read_mst_con_id, .write = dp_debug_write_mst_con_id, }; static const struct file_operations hpd_fops = { .open = simple_open, .write = dp_debug_write_hpd, Loading Loading @@ -1328,6 +1631,33 @@ static int dp_debug_init(struct dp_debug *dp_debug) goto error_remove_dir; } file = debugfs_create_file("edid_modes_mst", 0644, dir, debug, &edid_modes_mst_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs create edid_modes_mst failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("mst_con_id", 0644, dir, debug, &mst_con_id_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs create mst_con_id failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("mst_con_info", 0644, dir, debug, &mst_conn_info_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs create mst_conn_info failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("hpd", 0644, dir, debug, &hpd_fops); if (IS_ERR_OR_NULL(file)) { Loading Loading @@ -1537,6 +1867,16 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in) dp_debug->get_edid = dp_debug_get_edid; 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; return dp_debug; error: return ERR_PTR(rc); Loading
drivers/gpu/drm/msm/dp/dp_debug.h +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "dp_link.h" #include "dp_usbpd.h" #include "dp_aux.h" #include "dp_display.h" /** * struct dp_debug Loading @@ -43,6 +44,7 @@ struct dp_debug { u32 max_pclk_khz; bool force_encryption; char hdcp_status[SZ_128]; struct dp_mst_connector dp_mst_connector_list; u8 *(*get_edid)(struct dp_debug *dp_debug); }; Loading
drivers/gpu/drm/msm/dp/dp_display.c +101 −1 Original line number Diff line number Diff line Loading @@ -231,6 +231,10 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) u32 hdcp_auth_state; dp = container_of(dw, struct dp_display_private, hdcp_cb_work); if (!dp->power_on || atomic_read(&dp->aborted)) return; status = &dp->link->hdcp_status; if (status->hdcp_state == HDCP_STATE_INACTIVE) { Loading Loading @@ -294,8 +298,10 @@ static void dp_display_notify_hdcp_status_cb(void *ptr, dp->link->hdcp_status.hdcp_state = state; if (dp->is_connected) mutex_lock(&dp->session_lock); if (dp->power_on && !atomic_read(&dp->aborted)) queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4); mutex_unlock(&dp->session_lock); } static void dp_display_check_source_hdcp_caps(struct dp_display_private *dp) Loading Loading @@ -1648,6 +1654,9 @@ static enum drm_mode_status dp_display_validate_mode( struct dp_panel *dp_panel; struct dp_debug *debug; enum drm_mode_status mode_status = MODE_BAD; bool in_list = false; struct dp_mst_connector *mst_connector; int hdis, vdis, vref, ar, _hdis, _vdis, _vref, _ar; if (!dp_display || !mode || !panel) { pr_err("invalid params\n"); Loading Loading @@ -1691,6 +1700,58 @@ static enum drm_mode_status dp_display_validate_mode( goto end; } /* * 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); goto verify_default; } list_for_each_entry(mst_connector, &debug->dp_mst_connector_list.list, list) { if (mst_connector->con_id == dp_panel->connector->base.id) { in_list = true; if (!mst_connector->debug_en) { mode_status = MODE_OK; mutex_unlock( &debug->dp_mst_connector_list.lock); goto end; } hdis = mst_connector->hdisplay; vdis = mst_connector->vdisplay; vref = mst_connector->vrefresh; ar = mst_connector->aspect_ratio; _hdis = mode->hdisplay; _vdis = mode->vdisplay; _vref = mode->vrefresh; _ar = mode->picture_aspect_ratio; if (hdis == _hdis && vdis == _vdis && vref == _vref && ar == _ar) { mode_status = MODE_OK; mutex_unlock( &debug->dp_mst_connector_list.lock); goto end; } break; } } mutex_unlock(&debug->dp_mst_connector_list.lock); if (in_list) goto end; verify_default: if (debug->debug_en && (mode->hdisplay != debug->hdisplay || mode->vdisplay != debug->vdisplay || mode->vrefresh != debug->vrefresh || Loading Loading @@ -1888,6 +1949,7 @@ 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; if (!dp_display || !connector) { pr_err("invalid input\n"); Loading @@ -1896,8 +1958,11 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, dp = container_of(dp_display, struct dp_display_private, dp_display); mutex_lock(&dp->session_lock); if (!dp->mst.drm_registered) { pr_debug("drm mst not registered\n"); mutex_unlock(&dp->session_lock); return -EPERM; } Loading @@ -1912,6 +1977,7 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, if (IS_ERR(dp_panel)) { rc = PTR_ERR(dp_panel); pr_err("failed to initialize panel, rc = %d\n", rc); mutex_unlock(&dp->session_lock); return rc; } Loading @@ -1920,12 +1986,28 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, rc = PTR_ERR(dp_panel->audio); pr_err("[mst] failed to initialize audio, rc = %d\n", rc); dp_panel->audio = NULL; mutex_unlock(&dp->session_lock); return rc; } 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); mst_connector->debug_en = false; mst_connector->conn = connector; mst_connector->con_id = connector->base.id; 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); mutex_unlock(&dp->session_lock); return 0; } Loading @@ -1936,6 +2018,7 @@ 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) { pr_err("invalid input\n"); Loading @@ -1944,14 +2027,18 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display, dp = container_of(dp_display, struct dp_display_private, dp_display); mutex_lock(&dp->session_lock); if (!dp->mst.drm_registered) { pr_debug("drm mst not registered\n"); mutex_unlock(&dp->session_lock); return -EPERM; } sde_conn = to_sde_connector(connector); if (!sde_conn->drv_panel) { pr_err("invalid panel for connector:%d\n", connector->base.id); mutex_unlock(&dp->session_lock); return -EINVAL; } Loading @@ -1962,6 +2049,19 @@ 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->con_id == connector->base.id) { list_del(&con_to_remove->list); kfree(con_to_remove); } } mutex_unlock(&dp->debug->dp_mst_connector_list.lock); mutex_unlock(&dp->session_lock); return rc; } Loading