Loading msm/dp/dp_debug.c +112 −0 Original line number Diff line number Diff line Loading @@ -511,6 +511,90 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, return len; } static ssize_t dp_debug_write_mst_con_add(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[SZ_32]; size_t len = 0; 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; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_32 - 1); 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: return len; } 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; char buf[SZ_32]; size_t len = 0; int con_id = 0; 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; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_32 - 1); if (copy_from_user(buf, user_buff, len)) goto end; buf[len] = '\0'; if (sscanf(buf, "%d", &con_id) != 1) { len = 0; goto end; } 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) { in_list = true; break; } } mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); 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); 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 @@ -1699,6 +1783,16 @@ static const struct file_operations mst_con_id_fops = { .write = dp_debug_write_mst_con_id, }; static const struct file_operations mst_con_add_fops = { .open = simple_open, .write = dp_debug_write_mst_con_add, }; static const struct file_operations mst_con_remove_fops = { .open = simple_open, .write = dp_debug_write_mst_con_remove, }; static const struct file_operations hpd_fops = { .open = simple_open, .write = dp_debug_write_hpd, Loading Loading @@ -1855,6 +1949,24 @@ static int dp_debug_init(struct dp_debug *dp_debug) goto error_remove_dir; } file = debugfs_create_file("mst_con_add", 0644, dir, debug, &mst_con_add_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); DRM_ERROR("[%s] debugfs create mst_con_add failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("mst_con_remove", 0644, dir, debug, &mst_con_remove_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); DRM_ERROR("[%s] debugfs create mst_con_remove 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 msm/dp/dp_debug.h +14 −0 Original line number Diff line number Diff line Loading @@ -16,13 +16,24 @@ /** * 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 * @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 */ struct dp_debug { bool debug_en; Loading @@ -40,6 +51,9 @@ struct dp_debug { 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; u8 *(*get_edid)(struct dp_debug *dp_debug); Loading msm/dp/dp_display.c +6 −0 Original line number Diff line number Diff line Loading @@ -1026,8 +1026,14 @@ static void dp_display_mst_attention(struct dp_display_private *dp) if (dp->mst.mst_active && dp->mst.cbs.hpd_irq) { hpd_irq.mst_hpd_sim = dp->debug->mst_hpd_sim; hpd_irq.mst_sim_add_con = dp->debug->mst_sim_add_con; hpd_irq.mst_sim_remove_con = dp->debug->mst_sim_remove_con; hpd_irq.mst_sim_remove_con_id = dp->debug->mst_sim_remove_con_id; hpd_irq.edid = dp->debug->get_edid(dp->debug); dp->mst.cbs.hpd_irq(&dp->dp_display, &hpd_irq); dp->debug->mst_hpd_sim = false; dp->debug->mst_sim_add_con = false; dp->debug->mst_sim_remove_con = false; } DP_MST_DEBUG("mst_attention_work. mst_active:%d\n", dp->mst.mst_active); Loading msm/dp/dp_display.h +4 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ #include "dp_panel.h" #define DP_MST_SIM_MAX_PORTS 2 #define DP_MST_SIM_MAX_PORTS 8 enum dp_drv_state { PM_DEFAULT, Loading @@ -24,6 +24,9 @@ struct dp_mst_hpd_info { bool mst_hpd_sim; u32 mst_port_cnt; u8 *edid; bool mst_sim_add_con; bool mst_sim_remove_con; int mst_sim_remove_con_id; }; struct dp_mst_drm_cbs { Loading msm/dp/dp_mst_drm.c +139 −3 Original line number Diff line number Diff line Loading @@ -94,9 +94,16 @@ struct dp_mst_sim_port_data { u8 num_sdp_stream_sinks; }; struct dp_mst_sim_port_edid { u8 port_number; u8 edid[SZ_256]; bool valid; }; struct dp_mst_sim_mode { bool mst_state; struct edid *edid; struct dp_mst_sim_port_edid port_edids[DP_MST_SIM_MAX_PORTS]; struct work_struct probe_work; const struct drm_dp_mst_topology_cbs *cbs; u32 port_cnt; Loading Loading @@ -156,8 +163,22 @@ static void dp_mst_sim_destroy_port(struct kref *ref) { struct drm_dp_mst_port *port = container_of(ref, struct drm_dp_mst_port, kref); struct drm_dp_mst_topology_mgr *mgr = port->mgr; if (port->cached_edid) kfree(port->cached_edid); if (port->connector) { mutex_lock(&mgr->destroy_connector_lock); kref_get(&port->parent->kref); list_add(&port->next, &mgr->destroy_connector_list); mutex_unlock(&mgr->destroy_connector_lock); schedule_work(&mgr->destroy_connector_work); return; } else { kfree(port); } } /* DRM DP MST Framework simulator OPs */ static void dp_mst_sim_add_port(struct dp_mst_private *mst, Loading Loading @@ -218,7 +239,7 @@ static void dp_mst_sim_link_probe_work(struct work_struct *work) struct dp_mst_sim_mode *sim; struct dp_mst_private *mst; struct dp_mst_sim_port_data port_data; u8 cnt; u8 cnt, i; DP_MST_DEBUG("enter\n"); sim = container_of(work, struct dp_mst_sim_mode, probe_work); Loading @@ -233,8 +254,21 @@ static void dp_mst_sim_link_probe_work(struct work_struct *work) port_data.num_sdp_streams = 0; port_data.num_sdp_stream_sinks = 0; for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) sim->port_edids[i].valid = false; for (cnt = 0; cnt < sim->port_cnt; cnt++) { port_data.port_number = cnt; for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { if (sim->port_edids[i].valid) continue; sim->port_edids[i].port_number = port_data.port_number; memcpy(sim->port_edids[i].edid, sim->edid, SZ_256); sim->port_edids[i].valid = true; break; } dp_mst_sim_add_port(mst, &port_data); } Loading Loading @@ -351,8 +385,19 @@ static struct edid *dp_mst_sim_get_edid(struct drm_connector *connector, { struct dp_mst_private *mst = container_of(mgr, struct dp_mst_private, mst_mgr); int i; return drm_edid_duplicate(mst->simulator.edid); for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { if (mst->simulator.port_edids[i].valid && mst->simulator.port_edids[i].port_number == port->port_num) { return drm_edid_duplicate((struct edid *) (mst->simulator.port_edids[i].edid)); } } DRM_ERROR("edid not found for connector %d\n", connector->base.id); return NULL; } static int dp_mst_sim_topology_mgr_set_mst( Loading @@ -370,6 +415,83 @@ static int dp_mst_sim_topology_mgr_set_mst( return 0; } static void dp_mst_sim_handle_hpd_irq(void *dp_display, struct dp_mst_hpd_info *info) { struct dp_display *dp; struct dp_mst_private *mst; struct drm_dp_mst_port *port; struct dp_mst_sim_port_data port_data; struct drm_dp_mst_branch *mstb; int i; bool in_list, port_available; dp = dp_display; mst = dp->dp_mst_prv_info; if (info->mst_sim_add_con) { port_available = false; for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { if (mst->simulator.port_edids[i].valid) continue; port_data.port_number = i; mst->simulator.port_edids[i].port_number = i; memcpy(mst->simulator.port_edids[i].edid, info->edid, SZ_256); mst->simulator.port_edids[i].valid = true; port_available = true; break; } if (!port_available) { DRM_ERROR("add port failed, limit (%d) reached\n", DP_MST_SIM_MAX_PORTS); return; } port_data.input_port = false; port_data.peer_device_type = DP_PEER_DEVICE_SST_SINK; port_data.mcs = false; port_data.ddps = true; port_data.legacy_device_plug_status = false; port_data.dpcd_revision = 0; port_data.num_sdp_streams = 0; port_data.num_sdp_stream_sinks = 0; dp_mst_sim_add_port(mst, &port_data); } else if (info->mst_sim_remove_con) { mstb = mst->mst_mgr.mst_primary; in_list = false; mutex_lock(&mst->mst_mgr.lock); list_for_each_entry(port, &mstb->ports, next) { if (port->connector && port->connector->base.id == info->mst_sim_remove_con_id) { in_list = true; list_del(&port->next); break; } } mutex_unlock(&mst->mst_mgr.lock); if (!in_list) { DRM_ERROR("invalid connector id %d\n", info->mst_sim_remove_con_id); return; } for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { if (mst->simulator.port_edids[i].port_number == port->port_num) { mst->simulator.port_edids[i].valid = false; } } kref_put(&port->kref, dp_mst_sim_destroy_port); } } static void _dp_mst_get_vcpi_info( struct drm_dp_mst_topology_mgr *mgr, int vcpi, int *start_slot, int *num_slots) Loading Loading @@ -1857,6 +1979,20 @@ static void dp_mst_display_hpd_irq(void *dp_display, bool handled; if (info->mst_hpd_sim) { if (info->mst_sim_add_con || info->mst_sim_remove_con) { dp_mst_sim_handle_hpd_irq(dp_display, info); /* * When removing a connector, hpd_irq -> sim_destroy -> * destroy_connector_work will be executed in a thread. * This thread will perform the dp_mst_hotplug at the * appropriate time. Do not perform hotplug here * because it may be too early. */ if (info->mst_sim_remove_con) return; } dp_mst_hotplug(&mst->mst_mgr); return; } Loading Loading
msm/dp/dp_debug.c +112 −0 Original line number Diff line number Diff line Loading @@ -511,6 +511,90 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, return len; } static ssize_t dp_debug_write_mst_con_add(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[SZ_32]; size_t len = 0; 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; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_32 - 1); 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: return len; } 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; char buf[SZ_32]; size_t len = 0; int con_id = 0; 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; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_32 - 1); if (copy_from_user(buf, user_buff, len)) goto end; buf[len] = '\0'; if (sscanf(buf, "%d", &con_id) != 1) { len = 0; goto end; } 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) { in_list = true; break; } } mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); 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); 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 @@ -1699,6 +1783,16 @@ static const struct file_operations mst_con_id_fops = { .write = dp_debug_write_mst_con_id, }; static const struct file_operations mst_con_add_fops = { .open = simple_open, .write = dp_debug_write_mst_con_add, }; static const struct file_operations mst_con_remove_fops = { .open = simple_open, .write = dp_debug_write_mst_con_remove, }; static const struct file_operations hpd_fops = { .open = simple_open, .write = dp_debug_write_hpd, Loading Loading @@ -1855,6 +1949,24 @@ static int dp_debug_init(struct dp_debug *dp_debug) goto error_remove_dir; } file = debugfs_create_file("mst_con_add", 0644, dir, debug, &mst_con_add_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); DRM_ERROR("[%s] debugfs create mst_con_add failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("mst_con_remove", 0644, dir, debug, &mst_con_remove_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); DRM_ERROR("[%s] debugfs create mst_con_remove 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
msm/dp/dp_debug.h +14 −0 Original line number Diff line number Diff line Loading @@ -16,13 +16,24 @@ /** * 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 * @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 */ struct dp_debug { bool debug_en; Loading @@ -40,6 +51,9 @@ struct dp_debug { 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; u8 *(*get_edid)(struct dp_debug *dp_debug); Loading
msm/dp/dp_display.c +6 −0 Original line number Diff line number Diff line Loading @@ -1026,8 +1026,14 @@ static void dp_display_mst_attention(struct dp_display_private *dp) if (dp->mst.mst_active && dp->mst.cbs.hpd_irq) { hpd_irq.mst_hpd_sim = dp->debug->mst_hpd_sim; hpd_irq.mst_sim_add_con = dp->debug->mst_sim_add_con; hpd_irq.mst_sim_remove_con = dp->debug->mst_sim_remove_con; hpd_irq.mst_sim_remove_con_id = dp->debug->mst_sim_remove_con_id; hpd_irq.edid = dp->debug->get_edid(dp->debug); dp->mst.cbs.hpd_irq(&dp->dp_display, &hpd_irq); dp->debug->mst_hpd_sim = false; dp->debug->mst_sim_add_con = false; dp->debug->mst_sim_remove_con = false; } DP_MST_DEBUG("mst_attention_work. mst_active:%d\n", dp->mst.mst_active); Loading
msm/dp/dp_display.h +4 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ #include "dp_panel.h" #define DP_MST_SIM_MAX_PORTS 2 #define DP_MST_SIM_MAX_PORTS 8 enum dp_drv_state { PM_DEFAULT, Loading @@ -24,6 +24,9 @@ struct dp_mst_hpd_info { bool mst_hpd_sim; u32 mst_port_cnt; u8 *edid; bool mst_sim_add_con; bool mst_sim_remove_con; int mst_sim_remove_con_id; }; struct dp_mst_drm_cbs { Loading
msm/dp/dp_mst_drm.c +139 −3 Original line number Diff line number Diff line Loading @@ -94,9 +94,16 @@ struct dp_mst_sim_port_data { u8 num_sdp_stream_sinks; }; struct dp_mst_sim_port_edid { u8 port_number; u8 edid[SZ_256]; bool valid; }; struct dp_mst_sim_mode { bool mst_state; struct edid *edid; struct dp_mst_sim_port_edid port_edids[DP_MST_SIM_MAX_PORTS]; struct work_struct probe_work; const struct drm_dp_mst_topology_cbs *cbs; u32 port_cnt; Loading Loading @@ -156,8 +163,22 @@ static void dp_mst_sim_destroy_port(struct kref *ref) { struct drm_dp_mst_port *port = container_of(ref, struct drm_dp_mst_port, kref); struct drm_dp_mst_topology_mgr *mgr = port->mgr; if (port->cached_edid) kfree(port->cached_edid); if (port->connector) { mutex_lock(&mgr->destroy_connector_lock); kref_get(&port->parent->kref); list_add(&port->next, &mgr->destroy_connector_list); mutex_unlock(&mgr->destroy_connector_lock); schedule_work(&mgr->destroy_connector_work); return; } else { kfree(port); } } /* DRM DP MST Framework simulator OPs */ static void dp_mst_sim_add_port(struct dp_mst_private *mst, Loading Loading @@ -218,7 +239,7 @@ static void dp_mst_sim_link_probe_work(struct work_struct *work) struct dp_mst_sim_mode *sim; struct dp_mst_private *mst; struct dp_mst_sim_port_data port_data; u8 cnt; u8 cnt, i; DP_MST_DEBUG("enter\n"); sim = container_of(work, struct dp_mst_sim_mode, probe_work); Loading @@ -233,8 +254,21 @@ static void dp_mst_sim_link_probe_work(struct work_struct *work) port_data.num_sdp_streams = 0; port_data.num_sdp_stream_sinks = 0; for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) sim->port_edids[i].valid = false; for (cnt = 0; cnt < sim->port_cnt; cnt++) { port_data.port_number = cnt; for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { if (sim->port_edids[i].valid) continue; sim->port_edids[i].port_number = port_data.port_number; memcpy(sim->port_edids[i].edid, sim->edid, SZ_256); sim->port_edids[i].valid = true; break; } dp_mst_sim_add_port(mst, &port_data); } Loading Loading @@ -351,8 +385,19 @@ static struct edid *dp_mst_sim_get_edid(struct drm_connector *connector, { struct dp_mst_private *mst = container_of(mgr, struct dp_mst_private, mst_mgr); int i; return drm_edid_duplicate(mst->simulator.edid); for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { if (mst->simulator.port_edids[i].valid && mst->simulator.port_edids[i].port_number == port->port_num) { return drm_edid_duplicate((struct edid *) (mst->simulator.port_edids[i].edid)); } } DRM_ERROR("edid not found for connector %d\n", connector->base.id); return NULL; } static int dp_mst_sim_topology_mgr_set_mst( Loading @@ -370,6 +415,83 @@ static int dp_mst_sim_topology_mgr_set_mst( return 0; } static void dp_mst_sim_handle_hpd_irq(void *dp_display, struct dp_mst_hpd_info *info) { struct dp_display *dp; struct dp_mst_private *mst; struct drm_dp_mst_port *port; struct dp_mst_sim_port_data port_data; struct drm_dp_mst_branch *mstb; int i; bool in_list, port_available; dp = dp_display; mst = dp->dp_mst_prv_info; if (info->mst_sim_add_con) { port_available = false; for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { if (mst->simulator.port_edids[i].valid) continue; port_data.port_number = i; mst->simulator.port_edids[i].port_number = i; memcpy(mst->simulator.port_edids[i].edid, info->edid, SZ_256); mst->simulator.port_edids[i].valid = true; port_available = true; break; } if (!port_available) { DRM_ERROR("add port failed, limit (%d) reached\n", DP_MST_SIM_MAX_PORTS); return; } port_data.input_port = false; port_data.peer_device_type = DP_PEER_DEVICE_SST_SINK; port_data.mcs = false; port_data.ddps = true; port_data.legacy_device_plug_status = false; port_data.dpcd_revision = 0; port_data.num_sdp_streams = 0; port_data.num_sdp_stream_sinks = 0; dp_mst_sim_add_port(mst, &port_data); } else if (info->mst_sim_remove_con) { mstb = mst->mst_mgr.mst_primary; in_list = false; mutex_lock(&mst->mst_mgr.lock); list_for_each_entry(port, &mstb->ports, next) { if (port->connector && port->connector->base.id == info->mst_sim_remove_con_id) { in_list = true; list_del(&port->next); break; } } mutex_unlock(&mst->mst_mgr.lock); if (!in_list) { DRM_ERROR("invalid connector id %d\n", info->mst_sim_remove_con_id); return; } for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { if (mst->simulator.port_edids[i].port_number == port->port_num) { mst->simulator.port_edids[i].valid = false; } } kref_put(&port->kref, dp_mst_sim_destroy_port); } } static void _dp_mst_get_vcpi_info( struct drm_dp_mst_topology_mgr *mgr, int vcpi, int *start_slot, int *num_slots) Loading Loading @@ -1857,6 +1979,20 @@ static void dp_mst_display_hpd_irq(void *dp_display, bool handled; if (info->mst_hpd_sim) { if (info->mst_sim_add_con || info->mst_sim_remove_con) { dp_mst_sim_handle_hpd_irq(dp_display, info); /* * When removing a connector, hpd_irq -> sim_destroy -> * destroy_connector_work will be executed in a thread. * This thread will perform the dp_mst_hotplug at the * appropriate time. Do not perform hotplug here * because it may be too early. */ if (info->mst_sim_remove_con) return; } dp_mst_hotplug(&mst->mst_mgr); return; } Loading