Loading drivers/gpu/drm/msm/dp/dp_catalog.c +79 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ #include <linux/delay.h> #include <drm/drm_dp_helper.h> #include "dp_catalog.h" #include "dp_reg.h" Loading Loading @@ -747,6 +748,82 @@ static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl, } } static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl, u32 pattern) { struct dp_catalog_private *catalog; u32 value = 0x0; void __iomem *base = NULL; if (!ctrl) { pr_err("invalid input\n"); return; } dp_catalog_get_priv(ctrl); base = catalog->io->ctrl_io.base; dp_write(base + DP_STATE_CTRL, 0x0); switch (pattern) { case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: dp_write(base + DP_STATE_CTRL, 0x1); break; case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: value &= ~(1 << 16); dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); value |= 0xFC; dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); dp_write(base + DP_MAINLINK_LEVELS, 0x2); dp_write(base + DP_STATE_CTRL, 0x10); break; case DP_TEST_PHY_PATTERN_PRBS7: dp_write(base + DP_STATE_CTRL, 0x20); break; case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: dp_write(base + DP_STATE_CTRL, 0x40); /* 00111110000011111000001111100000 */ dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0); /* 00001111100000111110000011111000 */ dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8); /* 1111100000111110 */ dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E); break; case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN: value = BIT(16); dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); value |= 0xFC; dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); dp_write(base + DP_MAINLINK_LEVELS, 0x2); dp_write(base + DP_STATE_CTRL, 0x10); break; default: pr_debug("No valid test pattern requested: 0x%x\n", pattern); return; } /* Make sure the test pattern is programmed in the hardware */ wmb(); } static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl) { struct dp_catalog_private *catalog; void __iomem *base = NULL; if (!ctrl) { pr_err("invalid input\n"); return 0; } dp_catalog_get_priv(ctrl); base = catalog->io->ctrl_io.base; return dp_read(base + DP_MAINLINK_READY); } /* panel related catalog functions */ static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel) { Loading Loading @@ -988,6 +1065,8 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io) .get_interrupt = dp_catalog_ctrl_get_interrupt, .update_transfer_unit = dp_catalog_ctrl_update_transfer_unit, .read_hdcp_status = dp_catalog_ctrl_read_hdcp_status, .send_phy_pattern = dp_catalog_ctrl_send_phy_pattern, .read_phy_pattern = dp_catalog_ctrl_read_phy_pattern, }; struct dp_catalog_audio audio = { .init = dp_catalog_audio_init, Loading drivers/gpu/drm/msm/dp/dp_catalog.h +3 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,9 @@ struct dp_catalog_ctrl { void (*get_interrupt)(struct dp_catalog_ctrl *ctrl); void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl); u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl); void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern); u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl); }; enum dp_catalog_audio_sdp_type { Loading drivers/gpu/drm/msm/dp/dp_ctrl.c +138 −27 Original line number Diff line number Diff line Loading @@ -36,6 +36,11 @@ #define ST_SEND_VIDEO BIT(7) #define ST_PUSH_IDLE BIT(8) #define MR_LINK_TRAINING1 0x8 #define MR_LINK_SYMBOL_ERM 0x80 #define MR_LINK_PRBS7 0x100 #define MR_LINK_CUSTOM80 0x200 struct dp_vc_tu_mapping_table { u32 vic; u8 lanes; Loading Loading @@ -989,7 +994,7 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train) drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->link_info); if (ctrl->link->phy_pattern_requested(ctrl->link)) if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) goto end; if (!train) Loading Loading @@ -1135,18 +1140,14 @@ static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl) return false; } static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl, u32 sink_request) static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl) { int ret = 0; struct dp_ctrl_private *ctrl; if (!dp_ctrl) { ret = -EINVAL; goto end; } ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; do { if (ret == -EAGAIN) { Loading @@ -1159,8 +1160,6 @@ static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl, ctrl->catalog->phy_lane_cfg(ctrl->catalog, ctrl->orientation, ctrl->link->link_params.lane_count); if (sink_request & (DP_LINK_STATUS_UPDATED | DP_TEST_LINK_TRAINING)) { /* * Disable and re-enable the mainlink clock since the * link clock might have been adjusted as part of the Loading @@ -1171,7 +1170,6 @@ static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl, ret = dp_ctrl_enable_mainlink_clocks(ctrl); if (ret) continue; } dp_ctrl_configure_source_params(ctrl); Loading @@ -1185,10 +1183,111 @@ static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl, ret = dp_ctrl_setup_main_link(ctrl, true); } while (ret == -EAGAIN); end: return ret; } static void dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl) { int ret = 0; if (!ctrl->link->phy_params.phy_test_pattern_sel) { pr_debug("no test pattern selected by sink\n"); return; } pr_debug("start\n"); ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); /* * The global reset will need DP link ralated clocks to be * running. Add the global reset just before disabling the * link clocks and core clocks. */ ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); ctrl->dp_ctrl.off(&ctrl->dp_ctrl); ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl); if (ret) pr_err("failed to enable DP controller\n"); pr_debug("end\n"); } static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) { bool success = false; u32 pattern_sent = 0x0; u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel; pr_debug("request: %s\n", dp_link_get_phy_test_pattern(pattern_requested)); ctrl->catalog->update_vx_px(ctrl->catalog, ctrl->link->phy_params.v_level, ctrl->link->phy_params.p_level); ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested); ctrl->link->send_test_response(ctrl->link); pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog); switch (pattern_sent) { case MR_LINK_TRAINING1: if (pattern_requested == DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING) success = true; break; case MR_LINK_SYMBOL_ERM: if ((pattern_requested == DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT) || (pattern_requested == DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN)) success = true; break; case MR_LINK_PRBS7: if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7) success = true; break; case MR_LINK_CUSTOM80: if (pattern_requested == DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN) success = true; break; default: success = false; return; } pr_debug("%s: %s\n", success ? "success" : "failed", dp_link_get_phy_test_pattern(pattern_requested)); } static void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; u32 sink_request = 0x0; if (!dp_ctrl) { pr_err("invalid input\n"); return; } ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); sink_request = ctrl->link->sink_request; if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { pr_info("PHY_TEST_PATTERN request\n"); dp_ctrl_process_phy_test_request(ctrl); } if (sink_request & DP_LINK_STATUS_UPDATED) dp_ctrl_link_maintenance(ctrl); if (sink_request & DP_TEST_LINK_TRAINING) { ctrl->link->send_test_response(ctrl->link); dp_ctrl_link_maintenance(ctrl); } } static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; Loading @@ -1208,6 +1307,7 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl) struct dp_ctrl_private *ctrl; u32 rate = 0; u32 link_train_max_retries = 100; u32 const phy_cts_pixel_clk_khz = 148500; if (!dp_ctrl) { rc = -EINVAL; Loading @@ -1222,9 +1322,17 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl) ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true); ctrl->catalog->hpd_config(ctrl->catalog, true); ctrl->link->link_params.bw_code = drm_dp_link_rate_to_bw_code(rate); ctrl->link->link_params.lane_count = ctrl->panel->link_info.num_lanes; if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { pr_debug("using phy test link parameters\n"); if (!ctrl->panel->pinfo.pixel_clk_khz) ctrl->pixel_rate = phy_cts_pixel_clk_khz; } else { ctrl->link->link_params.bw_code = drm_dp_link_rate_to_bw_code(rate); ctrl->link->link_params.lane_count = ctrl->panel->link_info.num_lanes; ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; } pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n", ctrl->link->link_params.bw_code, Loading Loading @@ -1263,6 +1371,9 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl) dp_ctrl_enable_mainlink_clocks(ctrl); } if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) dp_ctrl_send_phy_test_pattern(ctrl); pr_debug("End-\n"); end: Loading Loading @@ -1337,12 +1448,12 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in) dp_ctrl->init = dp_ctrl_host_init; dp_ctrl->deinit = dp_ctrl_host_deinit; dp_ctrl->on = dp_ctrl_on; dp_ctrl->handle_sink_request = dp_ctrl_handle_sink_request; dp_ctrl->off = dp_ctrl_off; dp_ctrl->push_idle = dp_ctrl_push_idle; dp_ctrl->abort = dp_ctrl_abort; dp_ctrl->isr = dp_ctrl_isr; dp_ctrl->reset = dp_ctrl_reset; dp_ctrl->handle_sink_request = dp_ctrl_handle_sink_request; return dp_ctrl; error: Loading drivers/gpu/drm/msm/dp/dp_ctrl.h +1 −2 Original line number Diff line number Diff line Loading @@ -28,12 +28,11 @@ struct dp_ctrl { void (*deinit)(struct dp_ctrl *dp_ctrl); int (*on)(struct dp_ctrl *dp_ctrl); void (*off)(struct dp_ctrl *dp_ctrl); int (*handle_sink_request)(struct dp_ctrl *dp_ctrl, u32 sink_request); void (*reset)(struct dp_ctrl *dp_ctrl); void (*push_idle)(struct dp_ctrl *dp_ctrl); void (*abort)(struct dp_ctrl *dp_ctrl); void (*isr)(struct dp_ctrl *dp_ctrl); void (*handle_sink_request)(struct dp_ctrl *dp_ctrl); }; struct dp_ctrl_in { Loading drivers/gpu/drm/msm/dp/dp_display.c +5 −27 Original line number Diff line number Diff line Loading @@ -449,7 +449,7 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp, drm_helper_hpd_irq_event(dp->dp_display.connector->dev); if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) { pr_warn("timeout\n"); pr_warn("%s timeout\n", hpd ? "connect" : "disconnect"); return -EINVAL; } Loading Loading @@ -624,20 +624,6 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) return rc; } static void dp_display_link_maintenance(struct dp_display_private *dp) { if (dp->power_on) { pr_debug("Set DP ctrl to push idle for link maintenance\n"); dp->ctrl->push_idle(dp->ctrl); dp->ctrl->reset(dp->ctrl); } else { pr_err("DP not powered on, skip link maintenance\n"); return; } dp->ctrl->handle_sink_request(dp->ctrl, dp->link->sink_request); } static int dp_display_handle_hpd_irq(struct dp_display_private *dp) { if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) { Loading @@ -651,14 +637,7 @@ static int dp_display_handle_hpd_irq(struct dp_display_private *dp) return dp_display_process_hpd_high(dp); } if (dp->link->sink_request & DP_LINK_STATUS_UPDATED) dp_display_link_maintenance(dp); if (dp->link->sink_request & DP_TEST_LINK_TRAINING) { drm_dp_dpcd_write(dp->aux->drm_aux, DP_TEST_RESPONSE, &dp->link->test_response, 1); dp_display_link_maintenance(dp); } dp->ctrl->handle_sink_request(dp->ctrl); return 0; } Loading Loading @@ -689,13 +668,12 @@ static int dp_display_usbpd_attention_cb(struct device *dev) rc = dp->link->process_request(dp->link); /* check for any test request issued by sink */ if (!rc) { if (!rc) dp_display_handle_hpd_irq(dp); dp->hpd_irq_on = false; goto end; } dp->hpd_irq_on = false; } if (!dp->usbpd->hpd_high) { dp_display_process_hpd_low(dp); Loading Loading
drivers/gpu/drm/msm/dp/dp_catalog.c +79 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ #include <linux/delay.h> #include <drm/drm_dp_helper.h> #include "dp_catalog.h" #include "dp_reg.h" Loading Loading @@ -747,6 +748,82 @@ static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl, } } static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl, u32 pattern) { struct dp_catalog_private *catalog; u32 value = 0x0; void __iomem *base = NULL; if (!ctrl) { pr_err("invalid input\n"); return; } dp_catalog_get_priv(ctrl); base = catalog->io->ctrl_io.base; dp_write(base + DP_STATE_CTRL, 0x0); switch (pattern) { case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: dp_write(base + DP_STATE_CTRL, 0x1); break; case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: value &= ~(1 << 16); dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); value |= 0xFC; dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); dp_write(base + DP_MAINLINK_LEVELS, 0x2); dp_write(base + DP_STATE_CTRL, 0x10); break; case DP_TEST_PHY_PATTERN_PRBS7: dp_write(base + DP_STATE_CTRL, 0x20); break; case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: dp_write(base + DP_STATE_CTRL, 0x40); /* 00111110000011111000001111100000 */ dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0); /* 00001111100000111110000011111000 */ dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8); /* 1111100000111110 */ dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E); break; case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN: value = BIT(16); dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); value |= 0xFC; dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); dp_write(base + DP_MAINLINK_LEVELS, 0x2); dp_write(base + DP_STATE_CTRL, 0x10); break; default: pr_debug("No valid test pattern requested: 0x%x\n", pattern); return; } /* Make sure the test pattern is programmed in the hardware */ wmb(); } static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl) { struct dp_catalog_private *catalog; void __iomem *base = NULL; if (!ctrl) { pr_err("invalid input\n"); return 0; } dp_catalog_get_priv(ctrl); base = catalog->io->ctrl_io.base; return dp_read(base + DP_MAINLINK_READY); } /* panel related catalog functions */ static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel) { Loading Loading @@ -988,6 +1065,8 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io) .get_interrupt = dp_catalog_ctrl_get_interrupt, .update_transfer_unit = dp_catalog_ctrl_update_transfer_unit, .read_hdcp_status = dp_catalog_ctrl_read_hdcp_status, .send_phy_pattern = dp_catalog_ctrl_send_phy_pattern, .read_phy_pattern = dp_catalog_ctrl_read_phy_pattern, }; struct dp_catalog_audio audio = { .init = dp_catalog_audio_init, Loading
drivers/gpu/drm/msm/dp/dp_catalog.h +3 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,9 @@ struct dp_catalog_ctrl { void (*get_interrupt)(struct dp_catalog_ctrl *ctrl); void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl); u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl); void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern); u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl); }; enum dp_catalog_audio_sdp_type { Loading
drivers/gpu/drm/msm/dp/dp_ctrl.c +138 −27 Original line number Diff line number Diff line Loading @@ -36,6 +36,11 @@ #define ST_SEND_VIDEO BIT(7) #define ST_PUSH_IDLE BIT(8) #define MR_LINK_TRAINING1 0x8 #define MR_LINK_SYMBOL_ERM 0x80 #define MR_LINK_PRBS7 0x100 #define MR_LINK_CUSTOM80 0x200 struct dp_vc_tu_mapping_table { u32 vic; u8 lanes; Loading Loading @@ -989,7 +994,7 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train) drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->link_info); if (ctrl->link->phy_pattern_requested(ctrl->link)) if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) goto end; if (!train) Loading Loading @@ -1135,18 +1140,14 @@ static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl) return false; } static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl, u32 sink_request) static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl) { int ret = 0; struct dp_ctrl_private *ctrl; if (!dp_ctrl) { ret = -EINVAL; goto end; } ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; do { if (ret == -EAGAIN) { Loading @@ -1159,8 +1160,6 @@ static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl, ctrl->catalog->phy_lane_cfg(ctrl->catalog, ctrl->orientation, ctrl->link->link_params.lane_count); if (sink_request & (DP_LINK_STATUS_UPDATED | DP_TEST_LINK_TRAINING)) { /* * Disable and re-enable the mainlink clock since the * link clock might have been adjusted as part of the Loading @@ -1171,7 +1170,6 @@ static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl, ret = dp_ctrl_enable_mainlink_clocks(ctrl); if (ret) continue; } dp_ctrl_configure_source_params(ctrl); Loading @@ -1185,10 +1183,111 @@ static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl, ret = dp_ctrl_setup_main_link(ctrl, true); } while (ret == -EAGAIN); end: return ret; } static void dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl) { int ret = 0; if (!ctrl->link->phy_params.phy_test_pattern_sel) { pr_debug("no test pattern selected by sink\n"); return; } pr_debug("start\n"); ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); /* * The global reset will need DP link ralated clocks to be * running. Add the global reset just before disabling the * link clocks and core clocks. */ ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); ctrl->dp_ctrl.off(&ctrl->dp_ctrl); ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl); if (ret) pr_err("failed to enable DP controller\n"); pr_debug("end\n"); } static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) { bool success = false; u32 pattern_sent = 0x0; u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel; pr_debug("request: %s\n", dp_link_get_phy_test_pattern(pattern_requested)); ctrl->catalog->update_vx_px(ctrl->catalog, ctrl->link->phy_params.v_level, ctrl->link->phy_params.p_level); ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested); ctrl->link->send_test_response(ctrl->link); pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog); switch (pattern_sent) { case MR_LINK_TRAINING1: if (pattern_requested == DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING) success = true; break; case MR_LINK_SYMBOL_ERM: if ((pattern_requested == DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT) || (pattern_requested == DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN)) success = true; break; case MR_LINK_PRBS7: if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7) success = true; break; case MR_LINK_CUSTOM80: if (pattern_requested == DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN) success = true; break; default: success = false; return; } pr_debug("%s: %s\n", success ? "success" : "failed", dp_link_get_phy_test_pattern(pattern_requested)); } static void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; u32 sink_request = 0x0; if (!dp_ctrl) { pr_err("invalid input\n"); return; } ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); sink_request = ctrl->link->sink_request; if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { pr_info("PHY_TEST_PATTERN request\n"); dp_ctrl_process_phy_test_request(ctrl); } if (sink_request & DP_LINK_STATUS_UPDATED) dp_ctrl_link_maintenance(ctrl); if (sink_request & DP_TEST_LINK_TRAINING) { ctrl->link->send_test_response(ctrl->link); dp_ctrl_link_maintenance(ctrl); } } static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; Loading @@ -1208,6 +1307,7 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl) struct dp_ctrl_private *ctrl; u32 rate = 0; u32 link_train_max_retries = 100; u32 const phy_cts_pixel_clk_khz = 148500; if (!dp_ctrl) { rc = -EINVAL; Loading @@ -1222,9 +1322,17 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl) ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true); ctrl->catalog->hpd_config(ctrl->catalog, true); ctrl->link->link_params.bw_code = drm_dp_link_rate_to_bw_code(rate); ctrl->link->link_params.lane_count = ctrl->panel->link_info.num_lanes; if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { pr_debug("using phy test link parameters\n"); if (!ctrl->panel->pinfo.pixel_clk_khz) ctrl->pixel_rate = phy_cts_pixel_clk_khz; } else { ctrl->link->link_params.bw_code = drm_dp_link_rate_to_bw_code(rate); ctrl->link->link_params.lane_count = ctrl->panel->link_info.num_lanes; ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; } pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n", ctrl->link->link_params.bw_code, Loading Loading @@ -1263,6 +1371,9 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl) dp_ctrl_enable_mainlink_clocks(ctrl); } if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) dp_ctrl_send_phy_test_pattern(ctrl); pr_debug("End-\n"); end: Loading Loading @@ -1337,12 +1448,12 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in) dp_ctrl->init = dp_ctrl_host_init; dp_ctrl->deinit = dp_ctrl_host_deinit; dp_ctrl->on = dp_ctrl_on; dp_ctrl->handle_sink_request = dp_ctrl_handle_sink_request; dp_ctrl->off = dp_ctrl_off; dp_ctrl->push_idle = dp_ctrl_push_idle; dp_ctrl->abort = dp_ctrl_abort; dp_ctrl->isr = dp_ctrl_isr; dp_ctrl->reset = dp_ctrl_reset; dp_ctrl->handle_sink_request = dp_ctrl_handle_sink_request; return dp_ctrl; error: Loading
drivers/gpu/drm/msm/dp/dp_ctrl.h +1 −2 Original line number Diff line number Diff line Loading @@ -28,12 +28,11 @@ struct dp_ctrl { void (*deinit)(struct dp_ctrl *dp_ctrl); int (*on)(struct dp_ctrl *dp_ctrl); void (*off)(struct dp_ctrl *dp_ctrl); int (*handle_sink_request)(struct dp_ctrl *dp_ctrl, u32 sink_request); void (*reset)(struct dp_ctrl *dp_ctrl); void (*push_idle)(struct dp_ctrl *dp_ctrl); void (*abort)(struct dp_ctrl *dp_ctrl); void (*isr)(struct dp_ctrl *dp_ctrl); void (*handle_sink_request)(struct dp_ctrl *dp_ctrl); }; struct dp_ctrl_in { Loading
drivers/gpu/drm/msm/dp/dp_display.c +5 −27 Original line number Diff line number Diff line Loading @@ -449,7 +449,7 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp, drm_helper_hpd_irq_event(dp->dp_display.connector->dev); if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) { pr_warn("timeout\n"); pr_warn("%s timeout\n", hpd ? "connect" : "disconnect"); return -EINVAL; } Loading Loading @@ -624,20 +624,6 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) return rc; } static void dp_display_link_maintenance(struct dp_display_private *dp) { if (dp->power_on) { pr_debug("Set DP ctrl to push idle for link maintenance\n"); dp->ctrl->push_idle(dp->ctrl); dp->ctrl->reset(dp->ctrl); } else { pr_err("DP not powered on, skip link maintenance\n"); return; } dp->ctrl->handle_sink_request(dp->ctrl, dp->link->sink_request); } static int dp_display_handle_hpd_irq(struct dp_display_private *dp) { if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) { Loading @@ -651,14 +637,7 @@ static int dp_display_handle_hpd_irq(struct dp_display_private *dp) return dp_display_process_hpd_high(dp); } if (dp->link->sink_request & DP_LINK_STATUS_UPDATED) dp_display_link_maintenance(dp); if (dp->link->sink_request & DP_TEST_LINK_TRAINING) { drm_dp_dpcd_write(dp->aux->drm_aux, DP_TEST_RESPONSE, &dp->link->test_response, 1); dp_display_link_maintenance(dp); } dp->ctrl->handle_sink_request(dp->ctrl); return 0; } Loading Loading @@ -689,13 +668,12 @@ static int dp_display_usbpd_attention_cb(struct device *dev) rc = dp->link->process_request(dp->link); /* check for any test request issued by sink */ if (!rc) { if (!rc) dp_display_handle_hpd_irq(dp); dp->hpd_irq_on = false; goto end; } dp->hpd_irq_on = false; } if (!dp->usbpd->hpd_high) { dp_display_process_hpd_low(dp); Loading