Loading drivers/gpu/drm/drm_dp_mst_topology.c +82 −3 Original line number Diff line number Diff line Loading @@ -294,6 +294,12 @@ static void drm_dp_encode_sideband_req(struct drm_dp_sideband_msg_req_body *req, memcpy(&buf[idx], req->u.i2c_write.bytes, req->u.i2c_write.num_bytes); idx += req->u.i2c_write.num_bytes; break; case DP_POWER_DOWN_PHY: case DP_POWER_UP_PHY: buf[idx] = (req->u.port_num.port_number & 0xf) << 4; idx++; break; } raw->cur_len = idx; } Loading Loading @@ -538,6 +544,21 @@ static bool drm_dp_sideband_parse_query_payload_ack(struct drm_dp_sideband_msg_r return false; } static bool drm_dp_sideband_parse_power_updown_phy_ack(struct drm_dp_sideband_msg_rx *raw, struct drm_dp_sideband_msg_reply_body *repmsg) { int idx = 1; repmsg->u.port_number.port_number = (raw->msg[idx] >> 4) & 0xf; idx++; if (idx > raw->curlen) { DRM_DEBUG_KMS("power up/down phy parse length fail %d %d\n", idx, raw->curlen); return false; } return true; } static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, struct drm_dp_sideband_msg_reply_body *msg) { Loading Loading @@ -567,6 +588,9 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, return drm_dp_sideband_parse_enum_path_resources_ack(raw, msg); case DP_ALLOCATE_PAYLOAD: return drm_dp_sideband_parse_allocate_payload_ack(raw, msg); case DP_POWER_DOWN_PHY: case DP_POWER_UP_PHY: return drm_dp_sideband_parse_power_updown_phy_ack(raw, msg); default: DRM_ERROR("Got unknown reply 0x%02x\n", msg->req_type); return false; Loading Loading @@ -693,6 +717,22 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n return 0; } static int build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg, int port_num, bool power_up) { struct drm_dp_sideband_msg_req_body req; if (power_up) req.req_type = DP_POWER_UP_PHY; else req.req_type = DP_POWER_DOWN_PHY; req.u.port_num.port_number = port_num; drm_dp_encode_sideband_req(&req, msg); msg->path_msg = true; return 0; } static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_vcpi *vcpi) { Loading Loading @@ -1042,10 +1082,12 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port) lct = drm_dp_calculate_rad(port, rad); port->mstb = drm_dp_add_mst_branch_device(lct, rad); if (port->mstb) { port->mstb->mgr = port->mgr; port->mstb->port_parent = port; send_link = true; } break; } return send_link; Loading Loading @@ -1724,6 +1766,40 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, return ret; } int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, bool power_up) { struct drm_dp_sideband_msg_tx *txmsg; int len, ret; port = drm_dp_get_validated_port_ref(mgr, port); if (!port) return -EINVAL; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); if (!txmsg) { drm_dp_put_port(port); return -ENOMEM; } txmsg->dst = port->parent; len = build_power_updown_phy(txmsg, port->port_num, power_up); drm_dp_queue_down_tx(mgr, txmsg); ret = drm_dp_mst_wait_tx_reply(port->parent, txmsg); if (ret > 0) { if (txmsg->reply.reply_type == 1) ret = -EINVAL; else ret = 0; } kfree(txmsg); drm_dp_put_port(port); return ret; } EXPORT_SYMBOL(drm_dp_send_power_updown_phy); static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr, int id, struct drm_dp_payload *payload) Loading Loading @@ -2013,6 +2089,9 @@ static bool drm_dp_get_vc_payload_bw(int dp_link_bw, case DP_LINK_BW_5_4: *out = 10 * dp_link_count; break; case DP_LINK_BW_8_1: *out = 15 * dp_link_count; break; } return true; } Loading drivers/gpu/drm/msm/dp/dp_catalog_v420.c +34 −4 Original line number Diff line number Diff line Loading @@ -27,9 +27,9 @@ #define MAX_PRE_EMP_LEVELS 4 static u8 const vm_pre_emphasis[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { {0x00, 0x0B, 0x14, 0xFF}, /* pe0, 0 db */ {0x00, 0x0B, 0x12, 0xFF}, /* pe1, 3.5 db */ {0x00, 0x0B, 0xFF, 0xFF}, /* pe2, 6.0 db */ {0x00, 0x0E, 0x16, 0xFF}, /* pe0, 0 db */ {0x00, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */ {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */ {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ }; Loading @@ -37,7 +37,7 @@ static u8 const vm_pre_emphasis[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { static u8 const vm_voltage_swing[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { {0x07, 0x0F, 0x16, 0xFF}, /* sw0, 0.4v */ {0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6 v */ {0x19, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ {0x1A, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ }; Loading Loading @@ -102,6 +102,34 @@ static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux, 0x1F); } static void dp_catalog_aux_clear_hw_interrupts_v420(struct dp_catalog_aux *aux) { struct dp_catalog_private_v420 *catalog; struct dp_io_data *io_data; u32 data = 0; if (!aux) { pr_err("invalid input\n"); return; } catalog = dp_catalog_get_priv_v420(aux); io_data = catalog->io->dp_phy; data = dp_read(catalog->exe_mode, io_data, DP_PHY_AUX_INTERRUPT_STATUS_V420); dp_write(catalog->exe_mode, io_data, DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x1f); wmb(); /* make sure 0x1f is written before next write */ dp_write(catalog->exe_mode, io_data, DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x9f); wmb(); /* make sure 0x9f is written before next write */ dp_write(catalog->exe_mode, io_data, DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0); wmb(); /* make sure register is cleared */ } static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel, u32 rate, u32 stream_rate_khz, bool fixed_nvid) Loading Loading @@ -312,6 +340,8 @@ int dp_catalog_get_v420(struct device *dev, struct dp_catalog *catalog, catalog->priv.set_exe_mode = dp_catalog_set_exe_mode_v420; catalog->aux.setup = dp_catalog_aux_setup_v420; catalog->aux.clear_hw_interrupts = dp_catalog_aux_clear_hw_interrupts_v420; catalog->panel.config_msa = dp_catalog_panel_config_msa_v420; catalog->ctrl.phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg_v420; catalog->ctrl.update_vx_px = dp_catalog_ctrl_update_vx_px_v420; Loading drivers/gpu/drm/msm/dp/dp_debug.c +51 −16 Original line number Diff line number Diff line Loading @@ -451,8 +451,10 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, struct dp_mst_connector *mst_connector; char buf[SZ_32]; size_t len = 0; int con_id = 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; Loading @@ -467,8 +469,10 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, buf[len] = '\0'; if (kstrtoint(buf, 10, &con_id) != 0) goto clear; if (sscanf(buf, "%d %d", &con_id, &status) != 2) { len = 0; goto end; } if (!con_id) goto clear; Loading @@ -480,6 +484,7 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, if (mst_connector->con_id == con_id) { in_list = true; debug->mst_con_id = con_id; mst_connector->state = status; break; } } Loading @@ -487,6 +492,10 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, if (!in_list) pr_err("invalid connector id %u\n", con_id); else if (status != connector_status_unknown) { debug->dp_debug.mst_hpd_sim = true; debug->hpd->simulate_attention(debug->hpd, vdo); } goto end; clear: Loading Loading @@ -530,6 +539,21 @@ static ssize_t dp_debug_bw_code_write(struct file *file, return len; } static ssize_t dp_debug_mst_mode_read(struct file *file, char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[64]; ssize_t len; len = scnprintf(buf, sizeof(buf), "mst_mode = %d, mst_state = %d\n", debug->parser->has_mst, debug->panel->mst_state); return simple_read_from_buffer(user_buff, count, ppos, buf, len); } static ssize_t dp_debug_mst_mode_write(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -631,28 +655,35 @@ static ssize_t dp_debug_mst_sideband_mode_write(struct file *file, struct dp_debug_private *debug = file->private_data; char buf[SZ_8]; size_t len = 0; u32 mst_sideband_mode = 0; int mst_sideband_mode = 0; u32 mst_port_cnt = 0; if (!debug) return -ENODEV; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_8 - 1); if (copy_from_user(buf, user_buff, len)) return 0; return -EFAULT; buf[len] = '\0'; if (kstrtoint(buf, 10, &mst_sideband_mode) != 0) return 0; if (sscanf(buf, "%d %u", &mst_sideband_mode, &mst_port_cnt) != 2) { pr_err("invalid input\n"); return -EINVAL; } debug->parser->has_mst_sideband = mst_sideband_mode ? true : false; pr_debug("mst_enable: %d\n", mst_sideband_mode); if (mst_port_cnt > DP_MST_SIM_MAX_PORTS) { pr_err("port cnt:%d exceeding max:%d\n", mst_port_cnt, DP_MST_SIM_MAX_PORTS); return -EINVAL; } return len; debug->parser->has_mst_sideband = mst_sideband_mode ? true : false; debug->dp_debug.mst_port_cnt = mst_port_cnt; pr_debug("mst_sideband_mode: %d port_cnt:%d\n", mst_sideband_mode, mst_port_cnt); return count; } static ssize_t dp_debug_widebus_mode_write(struct file *file, Loading Loading @@ -1049,9 +1080,10 @@ static ssize_t dp_debug_read_mst_conn_info(struct file *file, continue; } ret = snprintf(buf + len, max_size, "conn name:%s, conn id:%d\n", connector->name, connector->base.id); ret = scnprintf(buf + len, max_size, "conn name:%s, conn id:%d state:%d\n", connector->name, connector->base.id, connector->status); if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) break; } Loading Loading @@ -1659,6 +1691,7 @@ static const struct file_operations dump_fops = { static const struct file_operations mst_mode_fops = { .open = simple_open, .write = dp_debug_mst_mode_write, .read = dp_debug_mst_mode_read, }; static const struct file_operations mst_sideband_mode_fops = { Loading Loading @@ -1988,6 +2021,8 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in) dp_debug->dp_mst_connector_list.conn = NULL; dp_debug->dp_mst_connector_list.debug_en = false; dp_debug->max_pclk_khz = debug->parser->max_pclk_khz; 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 @@ -45,6 +45,8 @@ struct dp_debug { bool force_encryption; char hdcp_status[SZ_128]; struct dp_mst_connector dp_mst_connector_list; bool mst_hpd_sim; u32 mst_port_cnt; u8 *(*get_edid)(struct dp_debug *dp_debug); void (*abort)(struct dp_debug *dp_debug); Loading drivers/gpu/drm/msm/dp/dp_display.c +90 −22 Original line number Diff line number Diff line Loading @@ -572,10 +572,17 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) return 0; } static void dp_display_update_mst_state(struct dp_display_private *dp, bool state) { dp->mst.mst_active = state; dp->panel->mst_state = state; } static void dp_display_process_mst_hpd_high(struct dp_display_private *dp) { bool is_mst_receiver; struct dp_mst_hdp_info info; struct dp_mst_hpd_info info; if (dp->parser->has_mst && dp->mst.drm_registered) { DP_MST_DEBUG("mst_hpd_high work\n"); Loading @@ -583,9 +590,14 @@ static void dp_display_process_mst_hpd_high(struct dp_display_private *dp) is_mst_receiver = dp->panel->read_mst_cap(dp->panel); if (is_mst_receiver && !dp->mst.mst_active) { dp->mst.mst_active = true; /* clear sink mst state */ drm_dp_dpcd_writeb(dp->aux->drm_aux, DP_MSTM_CTRL, 0); dp_display_update_mst_state(dp, true); info.mst_protocol = dp->parser->has_mst_sideband; info.mst_port_cnt = dp->debug->mst_port_cnt; info.edid = dp->debug->get_edid(dp->debug); if (dp->mst.cbs.hpd) Loading @@ -604,9 +616,6 @@ static void dp_display_host_init(struct dp_display_private *dp) if (dp->core_initialized) return; if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) dp->aux->aux_switch(dp->aux, true, dp->hpd->orientation); if (dp->hpd->orientation == ORIENTATION_CC2) flip = true; Loading @@ -632,9 +641,6 @@ static void dp_display_host_deinit(struct dp_display_private *dp) return; } if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); dp->aux->deinit(dp->aux); dp->ctrl->deinit(dp->ctrl); dp->power->deinit(dp->power); Loading @@ -652,7 +658,8 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->is_connected = true; dp->dp_display.max_pclk_khz = dp->parser->max_pclk_khz; dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, dp->debug->max_pclk_khz); dp_display_host_init(dp); Loading Loading @@ -693,7 +700,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) static void dp_display_process_mst_hpd_low(struct dp_display_private *dp) { struct dp_mst_hdp_info info = {0}; struct dp_mst_hpd_info info = {0}; if (dp->mst.mst_active) { DP_MST_DEBUG("mst_hpd_low work\n"); Loading @@ -702,8 +709,7 @@ static void dp_display_process_mst_hpd_low(struct dp_display_private *dp) info.mst_protocol = dp->parser->has_mst_sideband; dp->mst.cbs.hpd(&dp->dp_display, false, &info); } dp->mst.mst_active = false; dp_display_update_mst_state(dp, false); } DP_MST_DEBUG("mst_hpd_low. mst_active:%d\n", dp->mst.mst_active); Loading Loading @@ -765,6 +771,12 @@ static int dp_display_usbpd_configure_cb(struct device *dev) goto end; } if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) { rc = dp->aux->aux_switch(dp->aux, true, dp->hpd->orientation); if (rc) goto end; } dp_display_host_init(dp); /* check for hpd high and framework ready */ Loading Loading @@ -820,7 +832,7 @@ static void dp_display_clean(struct dp_display_private *dp) dp_display_stream_pre_disable(dp, dp_panel); dp_display_stream_disable(dp, dp_panel); dp_panel->deinit(dp_panel); dp_panel->deinit(dp_panel, 0); } dp->power_on = false; Loading Loading @@ -900,6 +912,9 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) dp_display_disconnect_sync(dp); dp->dp_display.post_open = NULL; if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); end: return rc; } Loading @@ -926,8 +941,13 @@ static int dp_display_stream_enable(struct dp_display_private *dp, static void dp_display_mst_attention(struct dp_display_private *dp) { if (dp->mst.mst_active && dp->mst.cbs.hpd_irq) dp->mst.cbs.hpd_irq(&dp->dp_display); struct dp_mst_hpd_info hpd_irq = {0}; if (dp->mst.mst_active && dp->mst.cbs.hpd_irq) { hpd_irq.mst_hpd_sim = dp->debug->mst_hpd_sim; dp->mst.cbs.hpd_irq(&dp->dp_display, &hpd_irq); dp->debug->mst_hpd_sim = false; } DP_MST_DEBUG("mst_attention_work. mst_active:%d\n", dp->mst.mst_active); } Loading @@ -937,6 +957,9 @@ static void dp_display_attention_work(struct work_struct *work) struct dp_display_private *dp = container_of(work, struct dp_display_private, attention_work); if (dp->debug->mst_hpd_sim) goto mst_attention; if (dp->link->process_request(dp->link)) goto cp_irq; Loading Loading @@ -1002,7 +1025,8 @@ static int dp_display_usbpd_attention_cb(struct device *dev) if (!dp->hpd->hpd_high) dp_display_disconnect_sync(dp); else if (dp->hpd->hpd_irq && dp->core_initialized) else if ((dp->hpd->hpd_irq && dp->core_initialized) || dp->debug->mst_hpd_sim) queue_work(dp->wq, &dp->attention_work); else if (!dp->power_on) queue_delayed_work(dp->wq, &dp->connect_work, 0); Loading Loading @@ -1572,11 +1596,7 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel) } dp_display_stream_disable(dp, dp_panel); /* log this as it results from user action of cable dis-connection */ pr_info("[OK]\n"); end: dp_panel->deinit(dp_panel); mutex_unlock(&dp->session_lock); return 0; } Loading Loading @@ -1629,6 +1649,8 @@ static struct dp_debug *dp_get_debug(struct dp_display *dp_display) static int dp_display_unprepare(struct dp_display *dp_display, void *panel) { struct dp_display_private *dp; struct dp_panel *dp_panel = panel; u32 flags = 0; if (!dp_display || !panel) { pr_err("invalid input\n"); Loading @@ -1639,10 +1661,19 @@ static int dp_display_unprepare(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); /* * Check if the power off sequence was triggered * by a source initialated action like framework * reboot or suspend-resume but not from normal * hot plug. */ if (dp_display_is_ready(dp)) flags |= DP_PANEL_SRC_INITIATED_POWER_DOWN; if (dp->active_stream_cnt) goto end; if (dp_display_is_ready(dp)) { if (flags & DP_PANEL_SRC_INITIATED_POWER_DOWN) { dp->link->psm_config(dp->link, &dp->panel->link_info, true); dp->debug->psm_enabled = true; Loading @@ -1663,8 +1694,10 @@ static int dp_display_unprepare(struct dp_display *dp_display, void *panel) complete_all(&dp->notification_comp); pr_debug("[OK]\n"); /* log this as it results from user action of cable dis-connection */ pr_info("[OK]\n"); end: dp_panel->deinit(dp_panel, flags); mutex_unlock(&dp->session_lock); return 0; Loading Loading @@ -2034,6 +2067,7 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, 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, Loading Loading @@ -2099,6 +2133,38 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display, 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) { pr_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) { pr_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) Loading Loading @@ -2221,6 +2287,8 @@ static int dp_display_probe(struct platform_device *pdev) g_dp_display->get_mst_caps = dp_display_get_mst_caps; g_dp_display->set_stream_info = dp_display_set_stream_info; 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; rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { Loading Loading
drivers/gpu/drm/drm_dp_mst_topology.c +82 −3 Original line number Diff line number Diff line Loading @@ -294,6 +294,12 @@ static void drm_dp_encode_sideband_req(struct drm_dp_sideband_msg_req_body *req, memcpy(&buf[idx], req->u.i2c_write.bytes, req->u.i2c_write.num_bytes); idx += req->u.i2c_write.num_bytes; break; case DP_POWER_DOWN_PHY: case DP_POWER_UP_PHY: buf[idx] = (req->u.port_num.port_number & 0xf) << 4; idx++; break; } raw->cur_len = idx; } Loading Loading @@ -538,6 +544,21 @@ static bool drm_dp_sideband_parse_query_payload_ack(struct drm_dp_sideband_msg_r return false; } static bool drm_dp_sideband_parse_power_updown_phy_ack(struct drm_dp_sideband_msg_rx *raw, struct drm_dp_sideband_msg_reply_body *repmsg) { int idx = 1; repmsg->u.port_number.port_number = (raw->msg[idx] >> 4) & 0xf; idx++; if (idx > raw->curlen) { DRM_DEBUG_KMS("power up/down phy parse length fail %d %d\n", idx, raw->curlen); return false; } return true; } static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, struct drm_dp_sideband_msg_reply_body *msg) { Loading Loading @@ -567,6 +588,9 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, return drm_dp_sideband_parse_enum_path_resources_ack(raw, msg); case DP_ALLOCATE_PAYLOAD: return drm_dp_sideband_parse_allocate_payload_ack(raw, msg); case DP_POWER_DOWN_PHY: case DP_POWER_UP_PHY: return drm_dp_sideband_parse_power_updown_phy_ack(raw, msg); default: DRM_ERROR("Got unknown reply 0x%02x\n", msg->req_type); return false; Loading Loading @@ -693,6 +717,22 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n return 0; } static int build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg, int port_num, bool power_up) { struct drm_dp_sideband_msg_req_body req; if (power_up) req.req_type = DP_POWER_UP_PHY; else req.req_type = DP_POWER_DOWN_PHY; req.u.port_num.port_number = port_num; drm_dp_encode_sideband_req(&req, msg); msg->path_msg = true; return 0; } static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_vcpi *vcpi) { Loading Loading @@ -1042,10 +1082,12 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port) lct = drm_dp_calculate_rad(port, rad); port->mstb = drm_dp_add_mst_branch_device(lct, rad); if (port->mstb) { port->mstb->mgr = port->mgr; port->mstb->port_parent = port; send_link = true; } break; } return send_link; Loading Loading @@ -1724,6 +1766,40 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, return ret; } int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, bool power_up) { struct drm_dp_sideband_msg_tx *txmsg; int len, ret; port = drm_dp_get_validated_port_ref(mgr, port); if (!port) return -EINVAL; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); if (!txmsg) { drm_dp_put_port(port); return -ENOMEM; } txmsg->dst = port->parent; len = build_power_updown_phy(txmsg, port->port_num, power_up); drm_dp_queue_down_tx(mgr, txmsg); ret = drm_dp_mst_wait_tx_reply(port->parent, txmsg); if (ret > 0) { if (txmsg->reply.reply_type == 1) ret = -EINVAL; else ret = 0; } kfree(txmsg); drm_dp_put_port(port); return ret; } EXPORT_SYMBOL(drm_dp_send_power_updown_phy); static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr, int id, struct drm_dp_payload *payload) Loading Loading @@ -2013,6 +2089,9 @@ static bool drm_dp_get_vc_payload_bw(int dp_link_bw, case DP_LINK_BW_5_4: *out = 10 * dp_link_count; break; case DP_LINK_BW_8_1: *out = 15 * dp_link_count; break; } return true; } Loading
drivers/gpu/drm/msm/dp/dp_catalog_v420.c +34 −4 Original line number Diff line number Diff line Loading @@ -27,9 +27,9 @@ #define MAX_PRE_EMP_LEVELS 4 static u8 const vm_pre_emphasis[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { {0x00, 0x0B, 0x14, 0xFF}, /* pe0, 0 db */ {0x00, 0x0B, 0x12, 0xFF}, /* pe1, 3.5 db */ {0x00, 0x0B, 0xFF, 0xFF}, /* pe2, 6.0 db */ {0x00, 0x0E, 0x16, 0xFF}, /* pe0, 0 db */ {0x00, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */ {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */ {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ }; Loading @@ -37,7 +37,7 @@ static u8 const vm_pre_emphasis[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { static u8 const vm_voltage_swing[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { {0x07, 0x0F, 0x16, 0xFF}, /* sw0, 0.4v */ {0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6 v */ {0x19, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ {0x1A, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ }; Loading Loading @@ -102,6 +102,34 @@ static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux, 0x1F); } static void dp_catalog_aux_clear_hw_interrupts_v420(struct dp_catalog_aux *aux) { struct dp_catalog_private_v420 *catalog; struct dp_io_data *io_data; u32 data = 0; if (!aux) { pr_err("invalid input\n"); return; } catalog = dp_catalog_get_priv_v420(aux); io_data = catalog->io->dp_phy; data = dp_read(catalog->exe_mode, io_data, DP_PHY_AUX_INTERRUPT_STATUS_V420); dp_write(catalog->exe_mode, io_data, DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x1f); wmb(); /* make sure 0x1f is written before next write */ dp_write(catalog->exe_mode, io_data, DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x9f); wmb(); /* make sure 0x9f is written before next write */ dp_write(catalog->exe_mode, io_data, DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0); wmb(); /* make sure register is cleared */ } static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel, u32 rate, u32 stream_rate_khz, bool fixed_nvid) Loading Loading @@ -312,6 +340,8 @@ int dp_catalog_get_v420(struct device *dev, struct dp_catalog *catalog, catalog->priv.set_exe_mode = dp_catalog_set_exe_mode_v420; catalog->aux.setup = dp_catalog_aux_setup_v420; catalog->aux.clear_hw_interrupts = dp_catalog_aux_clear_hw_interrupts_v420; catalog->panel.config_msa = dp_catalog_panel_config_msa_v420; catalog->ctrl.phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg_v420; catalog->ctrl.update_vx_px = dp_catalog_ctrl_update_vx_px_v420; Loading
drivers/gpu/drm/msm/dp/dp_debug.c +51 −16 Original line number Diff line number Diff line Loading @@ -451,8 +451,10 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, struct dp_mst_connector *mst_connector; char buf[SZ_32]; size_t len = 0; int con_id = 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; Loading @@ -467,8 +469,10 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, buf[len] = '\0'; if (kstrtoint(buf, 10, &con_id) != 0) goto clear; if (sscanf(buf, "%d %d", &con_id, &status) != 2) { len = 0; goto end; } if (!con_id) goto clear; Loading @@ -480,6 +484,7 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, if (mst_connector->con_id == con_id) { in_list = true; debug->mst_con_id = con_id; mst_connector->state = status; break; } } Loading @@ -487,6 +492,10 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file, if (!in_list) pr_err("invalid connector id %u\n", con_id); else if (status != connector_status_unknown) { debug->dp_debug.mst_hpd_sim = true; debug->hpd->simulate_attention(debug->hpd, vdo); } goto end; clear: Loading Loading @@ -530,6 +539,21 @@ static ssize_t dp_debug_bw_code_write(struct file *file, return len; } static ssize_t dp_debug_mst_mode_read(struct file *file, char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[64]; ssize_t len; len = scnprintf(buf, sizeof(buf), "mst_mode = %d, mst_state = %d\n", debug->parser->has_mst, debug->panel->mst_state); return simple_read_from_buffer(user_buff, count, ppos, buf, len); } static ssize_t dp_debug_mst_mode_write(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -631,28 +655,35 @@ static ssize_t dp_debug_mst_sideband_mode_write(struct file *file, struct dp_debug_private *debug = file->private_data; char buf[SZ_8]; size_t len = 0; u32 mst_sideband_mode = 0; int mst_sideband_mode = 0; u32 mst_port_cnt = 0; if (!debug) return -ENODEV; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_8 - 1); if (copy_from_user(buf, user_buff, len)) return 0; return -EFAULT; buf[len] = '\0'; if (kstrtoint(buf, 10, &mst_sideband_mode) != 0) return 0; if (sscanf(buf, "%d %u", &mst_sideband_mode, &mst_port_cnt) != 2) { pr_err("invalid input\n"); return -EINVAL; } debug->parser->has_mst_sideband = mst_sideband_mode ? true : false; pr_debug("mst_enable: %d\n", mst_sideband_mode); if (mst_port_cnt > DP_MST_SIM_MAX_PORTS) { pr_err("port cnt:%d exceeding max:%d\n", mst_port_cnt, DP_MST_SIM_MAX_PORTS); return -EINVAL; } return len; debug->parser->has_mst_sideband = mst_sideband_mode ? true : false; debug->dp_debug.mst_port_cnt = mst_port_cnt; pr_debug("mst_sideband_mode: %d port_cnt:%d\n", mst_sideband_mode, mst_port_cnt); return count; } static ssize_t dp_debug_widebus_mode_write(struct file *file, Loading Loading @@ -1049,9 +1080,10 @@ static ssize_t dp_debug_read_mst_conn_info(struct file *file, continue; } ret = snprintf(buf + len, max_size, "conn name:%s, conn id:%d\n", connector->name, connector->base.id); ret = scnprintf(buf + len, max_size, "conn name:%s, conn id:%d state:%d\n", connector->name, connector->base.id, connector->status); if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) break; } Loading Loading @@ -1659,6 +1691,7 @@ static const struct file_operations dump_fops = { static const struct file_operations mst_mode_fops = { .open = simple_open, .write = dp_debug_mst_mode_write, .read = dp_debug_mst_mode_read, }; static const struct file_operations mst_sideband_mode_fops = { Loading Loading @@ -1988,6 +2021,8 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in) dp_debug->dp_mst_connector_list.conn = NULL; dp_debug->dp_mst_connector_list.debug_en = false; dp_debug->max_pclk_khz = debug->parser->max_pclk_khz; 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 @@ -45,6 +45,8 @@ struct dp_debug { bool force_encryption; char hdcp_status[SZ_128]; struct dp_mst_connector dp_mst_connector_list; bool mst_hpd_sim; u32 mst_port_cnt; u8 *(*get_edid)(struct dp_debug *dp_debug); void (*abort)(struct dp_debug *dp_debug); Loading
drivers/gpu/drm/msm/dp/dp_display.c +90 −22 Original line number Diff line number Diff line Loading @@ -572,10 +572,17 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) return 0; } static void dp_display_update_mst_state(struct dp_display_private *dp, bool state) { dp->mst.mst_active = state; dp->panel->mst_state = state; } static void dp_display_process_mst_hpd_high(struct dp_display_private *dp) { bool is_mst_receiver; struct dp_mst_hdp_info info; struct dp_mst_hpd_info info; if (dp->parser->has_mst && dp->mst.drm_registered) { DP_MST_DEBUG("mst_hpd_high work\n"); Loading @@ -583,9 +590,14 @@ static void dp_display_process_mst_hpd_high(struct dp_display_private *dp) is_mst_receiver = dp->panel->read_mst_cap(dp->panel); if (is_mst_receiver && !dp->mst.mst_active) { dp->mst.mst_active = true; /* clear sink mst state */ drm_dp_dpcd_writeb(dp->aux->drm_aux, DP_MSTM_CTRL, 0); dp_display_update_mst_state(dp, true); info.mst_protocol = dp->parser->has_mst_sideband; info.mst_port_cnt = dp->debug->mst_port_cnt; info.edid = dp->debug->get_edid(dp->debug); if (dp->mst.cbs.hpd) Loading @@ -604,9 +616,6 @@ static void dp_display_host_init(struct dp_display_private *dp) if (dp->core_initialized) return; if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) dp->aux->aux_switch(dp->aux, true, dp->hpd->orientation); if (dp->hpd->orientation == ORIENTATION_CC2) flip = true; Loading @@ -632,9 +641,6 @@ static void dp_display_host_deinit(struct dp_display_private *dp) return; } if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); dp->aux->deinit(dp->aux); dp->ctrl->deinit(dp->ctrl); dp->power->deinit(dp->power); Loading @@ -652,7 +658,8 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->is_connected = true; dp->dp_display.max_pclk_khz = dp->parser->max_pclk_khz; dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, dp->debug->max_pclk_khz); dp_display_host_init(dp); Loading Loading @@ -693,7 +700,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) static void dp_display_process_mst_hpd_low(struct dp_display_private *dp) { struct dp_mst_hdp_info info = {0}; struct dp_mst_hpd_info info = {0}; if (dp->mst.mst_active) { DP_MST_DEBUG("mst_hpd_low work\n"); Loading @@ -702,8 +709,7 @@ static void dp_display_process_mst_hpd_low(struct dp_display_private *dp) info.mst_protocol = dp->parser->has_mst_sideband; dp->mst.cbs.hpd(&dp->dp_display, false, &info); } dp->mst.mst_active = false; dp_display_update_mst_state(dp, false); } DP_MST_DEBUG("mst_hpd_low. mst_active:%d\n", dp->mst.mst_active); Loading Loading @@ -765,6 +771,12 @@ static int dp_display_usbpd_configure_cb(struct device *dev) goto end; } if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) { rc = dp->aux->aux_switch(dp->aux, true, dp->hpd->orientation); if (rc) goto end; } dp_display_host_init(dp); /* check for hpd high and framework ready */ Loading Loading @@ -820,7 +832,7 @@ static void dp_display_clean(struct dp_display_private *dp) dp_display_stream_pre_disable(dp, dp_panel); dp_display_stream_disable(dp, dp_panel); dp_panel->deinit(dp_panel); dp_panel->deinit(dp_panel, 0); } dp->power_on = false; Loading Loading @@ -900,6 +912,9 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) dp_display_disconnect_sync(dp); dp->dp_display.post_open = NULL; if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); end: return rc; } Loading @@ -926,8 +941,13 @@ static int dp_display_stream_enable(struct dp_display_private *dp, static void dp_display_mst_attention(struct dp_display_private *dp) { if (dp->mst.mst_active && dp->mst.cbs.hpd_irq) dp->mst.cbs.hpd_irq(&dp->dp_display); struct dp_mst_hpd_info hpd_irq = {0}; if (dp->mst.mst_active && dp->mst.cbs.hpd_irq) { hpd_irq.mst_hpd_sim = dp->debug->mst_hpd_sim; dp->mst.cbs.hpd_irq(&dp->dp_display, &hpd_irq); dp->debug->mst_hpd_sim = false; } DP_MST_DEBUG("mst_attention_work. mst_active:%d\n", dp->mst.mst_active); } Loading @@ -937,6 +957,9 @@ static void dp_display_attention_work(struct work_struct *work) struct dp_display_private *dp = container_of(work, struct dp_display_private, attention_work); if (dp->debug->mst_hpd_sim) goto mst_attention; if (dp->link->process_request(dp->link)) goto cp_irq; Loading Loading @@ -1002,7 +1025,8 @@ static int dp_display_usbpd_attention_cb(struct device *dev) if (!dp->hpd->hpd_high) dp_display_disconnect_sync(dp); else if (dp->hpd->hpd_irq && dp->core_initialized) else if ((dp->hpd->hpd_irq && dp->core_initialized) || dp->debug->mst_hpd_sim) queue_work(dp->wq, &dp->attention_work); else if (!dp->power_on) queue_delayed_work(dp->wq, &dp->connect_work, 0); Loading Loading @@ -1572,11 +1596,7 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel) } dp_display_stream_disable(dp, dp_panel); /* log this as it results from user action of cable dis-connection */ pr_info("[OK]\n"); end: dp_panel->deinit(dp_panel); mutex_unlock(&dp->session_lock); return 0; } Loading Loading @@ -1629,6 +1649,8 @@ static struct dp_debug *dp_get_debug(struct dp_display *dp_display) static int dp_display_unprepare(struct dp_display *dp_display, void *panel) { struct dp_display_private *dp; struct dp_panel *dp_panel = panel; u32 flags = 0; if (!dp_display || !panel) { pr_err("invalid input\n"); Loading @@ -1639,10 +1661,19 @@ static int dp_display_unprepare(struct dp_display *dp_display, void *panel) mutex_lock(&dp->session_lock); /* * Check if the power off sequence was triggered * by a source initialated action like framework * reboot or suspend-resume but not from normal * hot plug. */ if (dp_display_is_ready(dp)) flags |= DP_PANEL_SRC_INITIATED_POWER_DOWN; if (dp->active_stream_cnt) goto end; if (dp_display_is_ready(dp)) { if (flags & DP_PANEL_SRC_INITIATED_POWER_DOWN) { dp->link->psm_config(dp->link, &dp->panel->link_info, true); dp->debug->psm_enabled = true; Loading @@ -1663,8 +1694,10 @@ static int dp_display_unprepare(struct dp_display *dp_display, void *panel) complete_all(&dp->notification_comp); pr_debug("[OK]\n"); /* log this as it results from user action of cable dis-connection */ pr_info("[OK]\n"); end: dp_panel->deinit(dp_panel, flags); mutex_unlock(&dp->session_lock); return 0; Loading Loading @@ -2034,6 +2067,7 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, 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, Loading Loading @@ -2099,6 +2133,38 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display, 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) { pr_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) { pr_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) Loading Loading @@ -2221,6 +2287,8 @@ static int dp_display_probe(struct platform_device *pdev) g_dp_display->get_mst_caps = dp_display_get_mst_caps; g_dp_display->set_stream_info = dp_display_set_stream_info; 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; rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { Loading