Loading drivers/gpu/drm/msm/dp/dp_display.c +122 −71 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ struct dp_display_private { struct dp_usbpd_cb usbpd_cb; struct dp_display_mode mode; struct dp_display dp_display; struct msm_drm_private *priv; struct workqueue_struct *wq; struct delayed_work hdcp_cb_work; Loading Loading @@ -299,7 +300,12 @@ static int dp_display_initialize_hdcp(struct dp_display_private *dp) pr_debug("HDCP 1.3 initialized\n"); dp->hdcp.hdcp2 = sde_dp_hdcp2p2_init(&hdcp_init_data); if (!IS_ERR_OR_NULL(dp->hdcp.hdcp2)) if (IS_ERR_OR_NULL(dp->hdcp.hdcp2)) { pr_err("Error initializing HDCP 2.x\n"); rc = -EINVAL; goto error; } pr_debug("HDCP 2.2 initialized\n"); dp->hdcp.feature_enabled = true; Loading @@ -316,7 +322,6 @@ static int dp_display_bind(struct device *dev, struct device *master, int rc = 0; struct dp_display_private *dp; struct drm_device *drm; struct msm_drm_private *priv; struct platform_device *pdev = to_platform_device(dev); if (!dev || !pdev || !master) { Loading @@ -336,25 +341,7 @@ static int dp_display_bind(struct device *dev, struct device *master, } dp->dp_display.drm_dev = drm; priv = drm->dev_private; rc = dp->aux->drm_aux_register(dp->aux); if (rc) { pr_err("DRM DP AUX register failed\n"); goto end; } rc = dp->power->power_client_init(dp->power, &priv->phandle); if (rc) { pr_err("Power client create failed\n"); goto end; } rc = dp_display_initialize_hdcp(dp); if (rc) { pr_err("HDCP initialization failed\n"); goto end; } dp->priv = drm->dev_private; end: return rc; } Loading Loading @@ -398,32 +385,25 @@ static bool dp_display_is_sink_count_zero(struct dp_display_private *dp) (dp->link->sink_count.count == 0); } static void dp_display_send_hpd_event(struct dp_display *dp_display) static void dp_display_send_hpd_event(struct dp_display_private *dp) { struct drm_device *dev = NULL; struct dp_display_private *dp; struct drm_connector *connector; char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE], bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE]; char *envp[5]; if (!dp_display) { pr_err("invalid input\n"); return; } connector = dp->dp_display.connector; dp = container_of(dp_display, struct dp_display_private, dp_display); if (!dp) { pr_err("invalid params\n"); if (!connector) { pr_err("connector not set\n"); return; } connector = dp->dp_display.connector; dev = dp_display->connector->dev; connector->status = connector->funcs->detect(connector, false); pr_debug("[%s] status updated to %s\n", connector->name, drm_get_connector_status_name(connector->status)); dev = dp->dp_display.connector->dev; snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name); snprintf(status, HPD_STRING_SIZE, "status=%s", drm_get_connector_status_name(connector->status)); Loading @@ -433,8 +413,7 @@ static void dp_display_send_hpd_event(struct dp_display *dp_display) snprintf(pattern, HPD_STRING_SIZE, "pattern=%d", dp->link->test_video.test_video_pattern); pr_debug("generating hotplug event [%s]:[%s] [%s] [%s]\n", name, status, bpp, pattern); pr_debug("[%s]:[%s] [%s] [%s]\n", name, status, bpp, pattern); envp[0] = name; envp[1] = status; envp[2] = bpp; Loading @@ -444,12 +423,48 @@ static void dp_display_send_hpd_event(struct dp_display *dp_display) envp); } static void dp_display_post_open(struct dp_display *dp_display) { struct drm_connector *connector; struct dp_display_private *dp; if (!dp_display) { pr_err("invalid input\n"); return; } dp = container_of(dp_display, struct dp_display_private, dp_display); if (IS_ERR_OR_NULL(dp)) { pr_err("invalid params\n"); return; } connector = dp->dp_display.connector; if (!connector) { pr_err("connector not set\n"); return; } /* if cable is already connected, send notification */ if (dp_display->is_connected) dp_display_send_hpd_event(dp); else dp_display->post_open = NULL; } static int dp_display_send_hpd_notification(struct dp_display_private *dp, bool hpd) { dp->dp_display.is_connected = hpd; /* in case, framework is not yet up, don't notify hpd */ if (dp->dp_display.post_open) return 0; reinit_completion(&dp->notification_comp); dp_display_send_hpd_event(&dp->dp_display); dp_display_send_hpd_event(dp); if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 5)) { pr_warn("%s timeout\n", hpd ? "connect" : "disconnect"); Loading @@ -475,6 +490,9 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->debug->psm_enabled = false; } if (!dp->dp_display.connector) return 0; rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector); if (rc) { if (rc == -ETIMEDOUT) { Loading Loading @@ -792,18 +810,6 @@ static int dp_init_sub_modules(struct dp_display_private *dp) .dev = dev, }; cb->configure = dp_display_usbpd_configure_cb; cb->disconnect = dp_display_usbpd_disconnect_cb; cb->attention = dp_display_usbpd_attention_cb; dp->usbpd = dp_usbpd_get(dev, cb); if (IS_ERR(dp->usbpd)) { rc = PTR_ERR(dp->usbpd); pr_err("failed to initialize usbpd, rc = %d\n", rc); dp->usbpd = NULL; goto error; } mutex_init(&dp->session_lock); dp->parser = dp_parser_get(dp->pdev); Loading @@ -811,7 +817,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) rc = PTR_ERR(dp->parser); pr_err("failed to initialize parser, rc = %d\n", rc); dp->parser = NULL; goto error_parser; goto error; } rc = dp->parser->parse(dp->parser); Loading @@ -836,6 +842,12 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_power; } rc = dp->power->power_client_init(dp->power, &dp->priv->phandle); if (rc) { pr_err("Power client create failed\n"); goto error_aux; } dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg); if (IS_ERR(dp->aux)) { rc = PTR_ERR(dp->aux); Loading @@ -844,6 +856,12 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_aux; } rc = dp->aux->drm_aux_register(dp->aux); if (rc) { pr_err("DRM DP AUX register failed\n"); goto error_link; } dp->link = dp_link_get(dev, dp->aux); if (IS_ERR(dp->link)) { rc = PTR_ERR(dp->link); Loading Loading @@ -887,6 +905,18 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_audio; } cb->configure = dp_display_usbpd_configure_cb; cb->disconnect = dp_display_usbpd_disconnect_cb; cb->attention = dp_display_usbpd_attention_cb; dp->usbpd = dp_usbpd_get(dev, cb); if (IS_ERR(dp->usbpd)) { rc = PTR_ERR(dp->usbpd); pr_err("failed to initialize usbpd, rc = %d\n", rc); dp->usbpd = NULL; goto error_usbpd; } dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd, dp->link, &dp->dp_display.connector); if (IS_ERR(dp->debug)) { Loading @@ -898,6 +928,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp) return rc; error_debug: dp_usbpd_put(dp->usbpd); error_usbpd: dp_audio_put(dp->audio); error_audio: dp_ctrl_put(dp->ctrl); Loading @@ -913,13 +945,40 @@ static int dp_init_sub_modules(struct dp_display_private *dp) dp_catalog_put(dp->catalog); error_catalog: dp_parser_put(dp->parser); error_parser: dp_usbpd_put(dp->usbpd); mutex_destroy(&dp->session_lock); error: mutex_destroy(&dp->session_lock); return rc; } static void dp_display_post_init(struct dp_display *dp_display) { int rc = 0; struct dp_display_private *dp; if (!dp_display) { pr_err("invalid input\n"); rc = -EINVAL; goto end; } dp = container_of(dp_display, struct dp_display_private, dp_display); if (IS_ERR_OR_NULL(dp)) { pr_err("invalid params\n"); rc = -EINVAL; goto end; } rc = dp_init_sub_modules(dp); if (rc) goto end; dp_display_initialize_hdcp(dp); dp_display->post_init = NULL; end: pr_debug("%s\n", rc ? "failed" : "success"); } static int dp_display_set_mode(struct dp_display *dp_display, struct dp_display_mode *mode) { Loading Loading @@ -1022,7 +1081,7 @@ static int dp_display_post_enable(struct dp_display *dp_display) } end: /* clear framework event notifier */ dp_display->send_hpd_event = NULL; dp_display->post_open = NULL; complete_all(&dp->notification_comp); mutex_unlock(&dp->session_lock); Loading Loading @@ -1147,7 +1206,7 @@ static int dp_display_validate_mode(struct dp_display *dp, u32 mode_pclk_khz) struct drm_dp_link *link_info; u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0; if (!dp || !mode_pclk_khz) { if (!dp || !mode_pclk_khz || !dp->connector) { pr_err("invalid params\n"); return -EINVAL; } Loading Loading @@ -1177,7 +1236,7 @@ static int dp_display_get_modes(struct dp_display *dp, struct dp_display_private *dp_display; int ret = 0; if (!dp) { if (!dp || !dp->connector) { pr_err("invalid params\n"); return 0; } Loading Loading @@ -1248,16 +1307,10 @@ static int dp_display_probe(struct platform_device *pdev) dp->pdev = pdev; dp->name = "drm_dp"; rc = dp_init_sub_modules(dp); if (rc) { rc = -EPROBE_DEFER; goto err_dev; } rc = dp_display_create_workqueue(dp); if (rc) { pr_err("Failed to create workqueue\n"); goto err_sub_mod; goto error; } platform_set_drvdata(pdev, dp); Loading @@ -1275,20 +1328,18 @@ static int dp_display_probe(struct platform_device *pdev) g_dp_display->unprepare = dp_display_unprepare; g_dp_display->request_irq = dp_request_irq; g_dp_display->get_debug = dp_get_debug; g_dp_display->send_hpd_event = dp_display_send_hpd_event; g_dp_display->post_open = dp_display_post_open; g_dp_display->post_init = dp_display_post_init; g_dp_display->pre_kickoff = dp_display_pre_kickoff; rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { pr_err("component add failed, rc=%d\n", rc); goto err_sub_mod; goto error; } return 0; err_sub_mod: dp_display_deinit_sub_modules(dp); err_dev: error: devm_kfree(&pdev->dev, dp); bail: return rc; Loading drivers/gpu/drm/msm/dp/dp_display.h +2 −1 Original line number Diff line number Diff line Loading @@ -42,9 +42,10 @@ struct dp_display { int (*unprepare)(struct dp_display *dp_display); int (*request_irq)(struct dp_display *dp_display); struct dp_debug *(*get_debug)(struct dp_display *dp_display); void (*send_hpd_event)(struct dp_display *dp_display); void (*post_open)(struct dp_display *dp_display); int (*pre_kickoff)(struct dp_display *dp_display, struct drm_msm_ext_hdr_metadata *hdr_meta); void (*post_init)(struct dp_display *dp_display); }; int dp_display_get_num_of_displays(void); Loading drivers/gpu/drm/msm/dp/dp_drm.c +10 −3 Original line number Diff line number Diff line Loading @@ -184,6 +184,9 @@ static void dp_bridge_disable(struct drm_bridge *drm_bridge) bridge = to_dp_bridge(drm_bridge); dp = bridge->display; if (dp && dp->connector) sde_connector_helper_bridge_disable(dp->connector); rc = dp->pre_disable(dp); if (rc) { pr_err("[%d] DP display pre disable failed, rc=%d\n", Loading Loading @@ -295,6 +298,10 @@ int dp_connector_post_init(struct drm_connector *connector, void *display) return -EINVAL; dp_display->connector = connector; if (dp_display->post_init) dp_display->post_init(dp_display); return 0; } Loading Loading @@ -376,7 +383,7 @@ enum drm_connector_status dp_connector_detect(struct drm_connector *conn, return status; } void dp_connector_send_hpd_event(void *display) void dp_connector_post_open(void *display) { struct dp_display *dp; Loading @@ -387,8 +394,8 @@ void dp_connector_send_hpd_event(void *display) dp = display; if (dp->send_hpd_event) dp->send_hpd_event(dp); if (dp->post_open) dp->post_open(dp); } int dp_connector_get_modes(struct drm_connector *connector, Loading drivers/gpu/drm/msm/dp/dp_drm.h +5 −1 Original line number Diff line number Diff line Loading @@ -95,7 +95,11 @@ int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode, int dp_connector_get_info(struct msm_display_info *info, void *display); void dp_connector_send_hpd_event(void *display); /** * dp_connector_post_open - handle the post open functionalites * @display: Pointer to private display structure */ void dp_connector_post_open(void *display); int dp_drm_bridge_init(void *display, struct drm_encoder *encoder); Loading drivers/gpu/drm/msm/dsi-staging/dsi_display.c +149 −36 Original line number Diff line number Diff line Loading @@ -790,6 +790,20 @@ static int dsi_display_debugfs_init(struct dsi_display *display) } } if (!debugfs_create_bool("ulps_enable", 0600, dir, &display->panel->ulps_enabled)) { pr_err("[%s] debugfs create ulps enable file failed\n", display->name); goto error_remove_dir; } if (!debugfs_create_bool("ulps_suspend_enable", 0600, dir, &display->panel->ulps_suspend_enabled)) { pr_err("[%s] debugfs create ulps-suspend enable file failed\n", display->name); goto error_remove_dir; } display->root = dir; return rc; error_remove_dir: Loading Loading @@ -826,12 +840,17 @@ static int dsi_display_is_ulps_req_valid(struct dsi_display *display, pr_debug("checking ulps req validity\n"); if (!dsi_panel_ulps_feature_enabled(display->panel)) if (!dsi_panel_ulps_feature_enabled(display->panel) && !display->panel->ulps_suspend_enabled) { pr_debug("%s: ULPS feature is not enabled\n", __func__); return false; } /* TODO: ULPS during suspend */ if (!dsi_panel_initialized(display->panel)) if (!dsi_panel_initialized(display->panel) && !display->panel->ulps_suspend_enabled) { pr_debug("%s: panel not yet initialized\n", __func__); return false; } if (enable && display->ulps_enabled) { pr_debug("ULPS already enabled\n"); Loading Loading @@ -2335,22 +2354,27 @@ int dsi_pre_clkoff_cb(void *priv, if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF)) { /* * If ULPS feature is enabled, enter ULPS first. * However, when blanking the panel, we should enter ULPS * only if ULPS during suspend feature is enabled. */ if (dsi_panel_initialized(display->panel) && dsi_panel_ulps_feature_enabled(display->panel)) { if (!dsi_panel_initialized(display->panel)) { if (display->panel->ulps_suspend_enabled) rc = dsi_display_set_ulps(display, true); if (rc) { } else if (dsi_panel_ulps_feature_enabled(display->panel)) { rc = dsi_display_set_ulps(display, true); } if (rc) pr_err("%s: failed enable ulps, rc = %d\n", __func__, rc); } } } if ((clk & DSI_CORE_CLK) && (new_state == DSI_CLK_OFF)) { /* * Enable DSI clamps only if entering idle power collapse. * Enable DSI clamps only if entering idle power collapse or * when ULPS during suspend is enabled.. */ if (dsi_panel_initialized(display->panel)) { if (dsi_panel_initialized(display->panel) || display->panel->ulps_suspend_enabled) { dsi_display_phy_idle_off(display); rc = dsi_display_set_clamp(display, true); if (rc) Loading Loading @@ -3954,7 +3978,7 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp) return rc; } int dsi_display_get_mode_count(struct dsi_display *display, static int dsi_display_get_mode_count_no_lock(struct dsi_display *display, u32 *count) { struct dsi_dfps_capabilities dfps_caps; Loading @@ -3966,15 +3990,13 @@ int dsi_display_get_mode_count(struct dsi_display *display, return -EINVAL; } mutex_lock(&display->display_lock); *count = display->panel->num_timing_nodes; rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps); if (rc) { pr_err("[%s] failed to get dfps caps from panel\n", display->name); goto done; return rc; } num_dfps_rates = !dfps_caps.dfps_support ? 1 : Loading @@ -3984,7 +4006,22 @@ int dsi_display_get_mode_count(struct dsi_display *display, /* Inflate num_of_modes by fps in dfps */ *count = display->panel->num_timing_nodes * num_dfps_rates; done: return 0; } int dsi_display_get_mode_count(struct dsi_display *display, u32 *count) { int rc; if (!display || !display->panel) { pr_err("invalid display:%d panel:%d\n", display != NULL, display ? display->panel != NULL : 0); return -EINVAL; } mutex_lock(&display->display_lock); rc = dsi_display_get_mode_count_no_lock(display, count); mutex_unlock(&display->display_lock); return 0; Loading @@ -3997,20 +4034,36 @@ void dsi_display_put_mode(struct dsi_display *display, } int dsi_display_get_modes(struct dsi_display *display, struct dsi_display_mode *modes) struct dsi_display_mode **out_modes) { struct dsi_dfps_capabilities dfps_caps; u32 num_dfps_rates, panel_mode_count; u32 num_dfps_rates, panel_mode_count, total_mode_count; u32 mode_idx, array_idx = 0; int i, rc = 0; int i, rc = -EINVAL; if (!display || !modes) { if (!display || !out_modes) { pr_err("Invalid params\n"); return -EINVAL; } *out_modes = NULL; mutex_lock(&display->display_lock); rc = dsi_display_get_mode_count_no_lock(display, &total_mode_count); if (rc) goto error; /* free any previously probed modes */ kfree(display->modes); display->modes = kcalloc(total_mode_count, sizeof(*display->modes), GFP_KERNEL); if (!display->modes) { rc = -ENOMEM; goto error; } rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps); if (rc) { pr_err("[%s] failed to get dfps caps from panel\n", Loading Loading @@ -4051,12 +4104,14 @@ int dsi_display_get_modes(struct dsi_display *display, } for (i = 0; i < num_dfps_rates; i++) { struct dsi_display_mode *sub_mode = &modes[array_idx]; struct dsi_display_mode *sub_mode = &display->modes[array_idx]; u32 curr_refresh_rate; if (!sub_mode) { pr_err("invalid mode data\n"); return -EFAULT; rc = -EFAULT; goto error; } memcpy(sub_mode, &panel_mode, sizeof(panel_mode)); Loading @@ -4080,8 +4135,54 @@ int dsi_display_get_modes(struct dsi_display *display, } } *out_modes = display->modes; rc = 0; error: if (rc) kfree(display->modes); mutex_unlock(&display->display_lock); return rc; } int dsi_display_find_mode(struct dsi_display *display, const struct dsi_display_mode *cmp, struct dsi_display_mode **out_mode) { u32 count, i; int rc; if (!display || !out_mode) return -EINVAL; *out_mode = NULL; rc = dsi_display_get_mode_count(display, &count); if (rc) return rc; mutex_lock(&display->display_lock); for (i = 0; i < count; i++) { struct dsi_display_mode *m = &display->modes[i]; if (cmp->timing.v_active == m->timing.v_active && cmp->timing.h_active == m->timing.h_active && cmp->timing.refresh_rate == m->timing.refresh_rate) { *out_mode = m; rc = 0; break; } } mutex_unlock(&display->display_lock); if (!*out_mode) { pr_err("[%s] failed to find mode for v_active %u h_active %u rate %u\n", display->name, cmp->timing.v_active, cmp->timing.h_active, cmp->timing.refresh_rate); rc = -ENOENT; } return rc; } Loading Loading @@ -4632,9 +4733,18 @@ int dsi_display_prepare(struct dsi_display *display) goto error_panel_post_unprep; } /* * If ULPS during suspend feature is enabled, then DSI PHY was * left on during suspend. In this case, we do not need to reset/init * PHY. This would have already been done when the CORE clocks are * turned on. However, if cont splash is disabled, the first time DSI * is powered on, phy init needs to be done unconditionally. */ if (!display->panel->ulps_suspend_enabled || !display->ulps_enabled) { rc = dsi_display_phy_sw_reset(display); if (rc) { pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc); pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc); goto error_ctrl_clk_off; } Loading @@ -4644,6 +4754,7 @@ int dsi_display_prepare(struct dsi_display *display) display->name, rc); goto error_ctrl_clk_off; } } rc = dsi_display_set_clk_src(display); if (rc) { Loading Loading @@ -5129,10 +5240,12 @@ int dsi_display_unprepare(struct dsi_display *display) pr_err("[%s] failed to deinit controller, rc=%d\n", display->name, rc); if (!display->panel->ulps_suspend_enabled) { rc = dsi_display_phy_disable(display); if (rc) pr_err("[%s] failed to disable DSI PHY, rc=%d\n", display->name, rc); } rc = dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_CORE_CLK, DSI_CLK_OFF); Loading Loading
drivers/gpu/drm/msm/dp/dp_display.c +122 −71 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ struct dp_display_private { struct dp_usbpd_cb usbpd_cb; struct dp_display_mode mode; struct dp_display dp_display; struct msm_drm_private *priv; struct workqueue_struct *wq; struct delayed_work hdcp_cb_work; Loading Loading @@ -299,7 +300,12 @@ static int dp_display_initialize_hdcp(struct dp_display_private *dp) pr_debug("HDCP 1.3 initialized\n"); dp->hdcp.hdcp2 = sde_dp_hdcp2p2_init(&hdcp_init_data); if (!IS_ERR_OR_NULL(dp->hdcp.hdcp2)) if (IS_ERR_OR_NULL(dp->hdcp.hdcp2)) { pr_err("Error initializing HDCP 2.x\n"); rc = -EINVAL; goto error; } pr_debug("HDCP 2.2 initialized\n"); dp->hdcp.feature_enabled = true; Loading @@ -316,7 +322,6 @@ static int dp_display_bind(struct device *dev, struct device *master, int rc = 0; struct dp_display_private *dp; struct drm_device *drm; struct msm_drm_private *priv; struct platform_device *pdev = to_platform_device(dev); if (!dev || !pdev || !master) { Loading @@ -336,25 +341,7 @@ static int dp_display_bind(struct device *dev, struct device *master, } dp->dp_display.drm_dev = drm; priv = drm->dev_private; rc = dp->aux->drm_aux_register(dp->aux); if (rc) { pr_err("DRM DP AUX register failed\n"); goto end; } rc = dp->power->power_client_init(dp->power, &priv->phandle); if (rc) { pr_err("Power client create failed\n"); goto end; } rc = dp_display_initialize_hdcp(dp); if (rc) { pr_err("HDCP initialization failed\n"); goto end; } dp->priv = drm->dev_private; end: return rc; } Loading Loading @@ -398,32 +385,25 @@ static bool dp_display_is_sink_count_zero(struct dp_display_private *dp) (dp->link->sink_count.count == 0); } static void dp_display_send_hpd_event(struct dp_display *dp_display) static void dp_display_send_hpd_event(struct dp_display_private *dp) { struct drm_device *dev = NULL; struct dp_display_private *dp; struct drm_connector *connector; char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE], bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE]; char *envp[5]; if (!dp_display) { pr_err("invalid input\n"); return; } connector = dp->dp_display.connector; dp = container_of(dp_display, struct dp_display_private, dp_display); if (!dp) { pr_err("invalid params\n"); if (!connector) { pr_err("connector not set\n"); return; } connector = dp->dp_display.connector; dev = dp_display->connector->dev; connector->status = connector->funcs->detect(connector, false); pr_debug("[%s] status updated to %s\n", connector->name, drm_get_connector_status_name(connector->status)); dev = dp->dp_display.connector->dev; snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name); snprintf(status, HPD_STRING_SIZE, "status=%s", drm_get_connector_status_name(connector->status)); Loading @@ -433,8 +413,7 @@ static void dp_display_send_hpd_event(struct dp_display *dp_display) snprintf(pattern, HPD_STRING_SIZE, "pattern=%d", dp->link->test_video.test_video_pattern); pr_debug("generating hotplug event [%s]:[%s] [%s] [%s]\n", name, status, bpp, pattern); pr_debug("[%s]:[%s] [%s] [%s]\n", name, status, bpp, pattern); envp[0] = name; envp[1] = status; envp[2] = bpp; Loading @@ -444,12 +423,48 @@ static void dp_display_send_hpd_event(struct dp_display *dp_display) envp); } static void dp_display_post_open(struct dp_display *dp_display) { struct drm_connector *connector; struct dp_display_private *dp; if (!dp_display) { pr_err("invalid input\n"); return; } dp = container_of(dp_display, struct dp_display_private, dp_display); if (IS_ERR_OR_NULL(dp)) { pr_err("invalid params\n"); return; } connector = dp->dp_display.connector; if (!connector) { pr_err("connector not set\n"); return; } /* if cable is already connected, send notification */ if (dp_display->is_connected) dp_display_send_hpd_event(dp); else dp_display->post_open = NULL; } static int dp_display_send_hpd_notification(struct dp_display_private *dp, bool hpd) { dp->dp_display.is_connected = hpd; /* in case, framework is not yet up, don't notify hpd */ if (dp->dp_display.post_open) return 0; reinit_completion(&dp->notification_comp); dp_display_send_hpd_event(&dp->dp_display); dp_display_send_hpd_event(dp); if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 5)) { pr_warn("%s timeout\n", hpd ? "connect" : "disconnect"); Loading @@ -475,6 +490,9 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->debug->psm_enabled = false; } if (!dp->dp_display.connector) return 0; rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector); if (rc) { if (rc == -ETIMEDOUT) { Loading Loading @@ -792,18 +810,6 @@ static int dp_init_sub_modules(struct dp_display_private *dp) .dev = dev, }; cb->configure = dp_display_usbpd_configure_cb; cb->disconnect = dp_display_usbpd_disconnect_cb; cb->attention = dp_display_usbpd_attention_cb; dp->usbpd = dp_usbpd_get(dev, cb); if (IS_ERR(dp->usbpd)) { rc = PTR_ERR(dp->usbpd); pr_err("failed to initialize usbpd, rc = %d\n", rc); dp->usbpd = NULL; goto error; } mutex_init(&dp->session_lock); dp->parser = dp_parser_get(dp->pdev); Loading @@ -811,7 +817,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) rc = PTR_ERR(dp->parser); pr_err("failed to initialize parser, rc = %d\n", rc); dp->parser = NULL; goto error_parser; goto error; } rc = dp->parser->parse(dp->parser); Loading @@ -836,6 +842,12 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_power; } rc = dp->power->power_client_init(dp->power, &dp->priv->phandle); if (rc) { pr_err("Power client create failed\n"); goto error_aux; } dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg); if (IS_ERR(dp->aux)) { rc = PTR_ERR(dp->aux); Loading @@ -844,6 +856,12 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_aux; } rc = dp->aux->drm_aux_register(dp->aux); if (rc) { pr_err("DRM DP AUX register failed\n"); goto error_link; } dp->link = dp_link_get(dev, dp->aux); if (IS_ERR(dp->link)) { rc = PTR_ERR(dp->link); Loading Loading @@ -887,6 +905,18 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_audio; } cb->configure = dp_display_usbpd_configure_cb; cb->disconnect = dp_display_usbpd_disconnect_cb; cb->attention = dp_display_usbpd_attention_cb; dp->usbpd = dp_usbpd_get(dev, cb); if (IS_ERR(dp->usbpd)) { rc = PTR_ERR(dp->usbpd); pr_err("failed to initialize usbpd, rc = %d\n", rc); dp->usbpd = NULL; goto error_usbpd; } dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd, dp->link, &dp->dp_display.connector); if (IS_ERR(dp->debug)) { Loading @@ -898,6 +928,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp) return rc; error_debug: dp_usbpd_put(dp->usbpd); error_usbpd: dp_audio_put(dp->audio); error_audio: dp_ctrl_put(dp->ctrl); Loading @@ -913,13 +945,40 @@ static int dp_init_sub_modules(struct dp_display_private *dp) dp_catalog_put(dp->catalog); error_catalog: dp_parser_put(dp->parser); error_parser: dp_usbpd_put(dp->usbpd); mutex_destroy(&dp->session_lock); error: mutex_destroy(&dp->session_lock); return rc; } static void dp_display_post_init(struct dp_display *dp_display) { int rc = 0; struct dp_display_private *dp; if (!dp_display) { pr_err("invalid input\n"); rc = -EINVAL; goto end; } dp = container_of(dp_display, struct dp_display_private, dp_display); if (IS_ERR_OR_NULL(dp)) { pr_err("invalid params\n"); rc = -EINVAL; goto end; } rc = dp_init_sub_modules(dp); if (rc) goto end; dp_display_initialize_hdcp(dp); dp_display->post_init = NULL; end: pr_debug("%s\n", rc ? "failed" : "success"); } static int dp_display_set_mode(struct dp_display *dp_display, struct dp_display_mode *mode) { Loading Loading @@ -1022,7 +1081,7 @@ static int dp_display_post_enable(struct dp_display *dp_display) } end: /* clear framework event notifier */ dp_display->send_hpd_event = NULL; dp_display->post_open = NULL; complete_all(&dp->notification_comp); mutex_unlock(&dp->session_lock); Loading Loading @@ -1147,7 +1206,7 @@ static int dp_display_validate_mode(struct dp_display *dp, u32 mode_pclk_khz) struct drm_dp_link *link_info; u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0; if (!dp || !mode_pclk_khz) { if (!dp || !mode_pclk_khz || !dp->connector) { pr_err("invalid params\n"); return -EINVAL; } Loading Loading @@ -1177,7 +1236,7 @@ static int dp_display_get_modes(struct dp_display *dp, struct dp_display_private *dp_display; int ret = 0; if (!dp) { if (!dp || !dp->connector) { pr_err("invalid params\n"); return 0; } Loading Loading @@ -1248,16 +1307,10 @@ static int dp_display_probe(struct platform_device *pdev) dp->pdev = pdev; dp->name = "drm_dp"; rc = dp_init_sub_modules(dp); if (rc) { rc = -EPROBE_DEFER; goto err_dev; } rc = dp_display_create_workqueue(dp); if (rc) { pr_err("Failed to create workqueue\n"); goto err_sub_mod; goto error; } platform_set_drvdata(pdev, dp); Loading @@ -1275,20 +1328,18 @@ static int dp_display_probe(struct platform_device *pdev) g_dp_display->unprepare = dp_display_unprepare; g_dp_display->request_irq = dp_request_irq; g_dp_display->get_debug = dp_get_debug; g_dp_display->send_hpd_event = dp_display_send_hpd_event; g_dp_display->post_open = dp_display_post_open; g_dp_display->post_init = dp_display_post_init; g_dp_display->pre_kickoff = dp_display_pre_kickoff; rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { pr_err("component add failed, rc=%d\n", rc); goto err_sub_mod; goto error; } return 0; err_sub_mod: dp_display_deinit_sub_modules(dp); err_dev: error: devm_kfree(&pdev->dev, dp); bail: return rc; Loading
drivers/gpu/drm/msm/dp/dp_display.h +2 −1 Original line number Diff line number Diff line Loading @@ -42,9 +42,10 @@ struct dp_display { int (*unprepare)(struct dp_display *dp_display); int (*request_irq)(struct dp_display *dp_display); struct dp_debug *(*get_debug)(struct dp_display *dp_display); void (*send_hpd_event)(struct dp_display *dp_display); void (*post_open)(struct dp_display *dp_display); int (*pre_kickoff)(struct dp_display *dp_display, struct drm_msm_ext_hdr_metadata *hdr_meta); void (*post_init)(struct dp_display *dp_display); }; int dp_display_get_num_of_displays(void); Loading
drivers/gpu/drm/msm/dp/dp_drm.c +10 −3 Original line number Diff line number Diff line Loading @@ -184,6 +184,9 @@ static void dp_bridge_disable(struct drm_bridge *drm_bridge) bridge = to_dp_bridge(drm_bridge); dp = bridge->display; if (dp && dp->connector) sde_connector_helper_bridge_disable(dp->connector); rc = dp->pre_disable(dp); if (rc) { pr_err("[%d] DP display pre disable failed, rc=%d\n", Loading Loading @@ -295,6 +298,10 @@ int dp_connector_post_init(struct drm_connector *connector, void *display) return -EINVAL; dp_display->connector = connector; if (dp_display->post_init) dp_display->post_init(dp_display); return 0; } Loading Loading @@ -376,7 +383,7 @@ enum drm_connector_status dp_connector_detect(struct drm_connector *conn, return status; } void dp_connector_send_hpd_event(void *display) void dp_connector_post_open(void *display) { struct dp_display *dp; Loading @@ -387,8 +394,8 @@ void dp_connector_send_hpd_event(void *display) dp = display; if (dp->send_hpd_event) dp->send_hpd_event(dp); if (dp->post_open) dp->post_open(dp); } int dp_connector_get_modes(struct drm_connector *connector, Loading
drivers/gpu/drm/msm/dp/dp_drm.h +5 −1 Original line number Diff line number Diff line Loading @@ -95,7 +95,11 @@ int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode, int dp_connector_get_info(struct msm_display_info *info, void *display); void dp_connector_send_hpd_event(void *display); /** * dp_connector_post_open - handle the post open functionalites * @display: Pointer to private display structure */ void dp_connector_post_open(void *display); int dp_drm_bridge_init(void *display, struct drm_encoder *encoder); Loading
drivers/gpu/drm/msm/dsi-staging/dsi_display.c +149 −36 Original line number Diff line number Diff line Loading @@ -790,6 +790,20 @@ static int dsi_display_debugfs_init(struct dsi_display *display) } } if (!debugfs_create_bool("ulps_enable", 0600, dir, &display->panel->ulps_enabled)) { pr_err("[%s] debugfs create ulps enable file failed\n", display->name); goto error_remove_dir; } if (!debugfs_create_bool("ulps_suspend_enable", 0600, dir, &display->panel->ulps_suspend_enabled)) { pr_err("[%s] debugfs create ulps-suspend enable file failed\n", display->name); goto error_remove_dir; } display->root = dir; return rc; error_remove_dir: Loading Loading @@ -826,12 +840,17 @@ static int dsi_display_is_ulps_req_valid(struct dsi_display *display, pr_debug("checking ulps req validity\n"); if (!dsi_panel_ulps_feature_enabled(display->panel)) if (!dsi_panel_ulps_feature_enabled(display->panel) && !display->panel->ulps_suspend_enabled) { pr_debug("%s: ULPS feature is not enabled\n", __func__); return false; } /* TODO: ULPS during suspend */ if (!dsi_panel_initialized(display->panel)) if (!dsi_panel_initialized(display->panel) && !display->panel->ulps_suspend_enabled) { pr_debug("%s: panel not yet initialized\n", __func__); return false; } if (enable && display->ulps_enabled) { pr_debug("ULPS already enabled\n"); Loading Loading @@ -2335,22 +2354,27 @@ int dsi_pre_clkoff_cb(void *priv, if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF)) { /* * If ULPS feature is enabled, enter ULPS first. * However, when blanking the panel, we should enter ULPS * only if ULPS during suspend feature is enabled. */ if (dsi_panel_initialized(display->panel) && dsi_panel_ulps_feature_enabled(display->panel)) { if (!dsi_panel_initialized(display->panel)) { if (display->panel->ulps_suspend_enabled) rc = dsi_display_set_ulps(display, true); if (rc) { } else if (dsi_panel_ulps_feature_enabled(display->panel)) { rc = dsi_display_set_ulps(display, true); } if (rc) pr_err("%s: failed enable ulps, rc = %d\n", __func__, rc); } } } if ((clk & DSI_CORE_CLK) && (new_state == DSI_CLK_OFF)) { /* * Enable DSI clamps only if entering idle power collapse. * Enable DSI clamps only if entering idle power collapse or * when ULPS during suspend is enabled.. */ if (dsi_panel_initialized(display->panel)) { if (dsi_panel_initialized(display->panel) || display->panel->ulps_suspend_enabled) { dsi_display_phy_idle_off(display); rc = dsi_display_set_clamp(display, true); if (rc) Loading Loading @@ -3954,7 +3978,7 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp) return rc; } int dsi_display_get_mode_count(struct dsi_display *display, static int dsi_display_get_mode_count_no_lock(struct dsi_display *display, u32 *count) { struct dsi_dfps_capabilities dfps_caps; Loading @@ -3966,15 +3990,13 @@ int dsi_display_get_mode_count(struct dsi_display *display, return -EINVAL; } mutex_lock(&display->display_lock); *count = display->panel->num_timing_nodes; rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps); if (rc) { pr_err("[%s] failed to get dfps caps from panel\n", display->name); goto done; return rc; } num_dfps_rates = !dfps_caps.dfps_support ? 1 : Loading @@ -3984,7 +4006,22 @@ int dsi_display_get_mode_count(struct dsi_display *display, /* Inflate num_of_modes by fps in dfps */ *count = display->panel->num_timing_nodes * num_dfps_rates; done: return 0; } int dsi_display_get_mode_count(struct dsi_display *display, u32 *count) { int rc; if (!display || !display->panel) { pr_err("invalid display:%d panel:%d\n", display != NULL, display ? display->panel != NULL : 0); return -EINVAL; } mutex_lock(&display->display_lock); rc = dsi_display_get_mode_count_no_lock(display, count); mutex_unlock(&display->display_lock); return 0; Loading @@ -3997,20 +4034,36 @@ void dsi_display_put_mode(struct dsi_display *display, } int dsi_display_get_modes(struct dsi_display *display, struct dsi_display_mode *modes) struct dsi_display_mode **out_modes) { struct dsi_dfps_capabilities dfps_caps; u32 num_dfps_rates, panel_mode_count; u32 num_dfps_rates, panel_mode_count, total_mode_count; u32 mode_idx, array_idx = 0; int i, rc = 0; int i, rc = -EINVAL; if (!display || !modes) { if (!display || !out_modes) { pr_err("Invalid params\n"); return -EINVAL; } *out_modes = NULL; mutex_lock(&display->display_lock); rc = dsi_display_get_mode_count_no_lock(display, &total_mode_count); if (rc) goto error; /* free any previously probed modes */ kfree(display->modes); display->modes = kcalloc(total_mode_count, sizeof(*display->modes), GFP_KERNEL); if (!display->modes) { rc = -ENOMEM; goto error; } rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps); if (rc) { pr_err("[%s] failed to get dfps caps from panel\n", Loading Loading @@ -4051,12 +4104,14 @@ int dsi_display_get_modes(struct dsi_display *display, } for (i = 0; i < num_dfps_rates; i++) { struct dsi_display_mode *sub_mode = &modes[array_idx]; struct dsi_display_mode *sub_mode = &display->modes[array_idx]; u32 curr_refresh_rate; if (!sub_mode) { pr_err("invalid mode data\n"); return -EFAULT; rc = -EFAULT; goto error; } memcpy(sub_mode, &panel_mode, sizeof(panel_mode)); Loading @@ -4080,8 +4135,54 @@ int dsi_display_get_modes(struct dsi_display *display, } } *out_modes = display->modes; rc = 0; error: if (rc) kfree(display->modes); mutex_unlock(&display->display_lock); return rc; } int dsi_display_find_mode(struct dsi_display *display, const struct dsi_display_mode *cmp, struct dsi_display_mode **out_mode) { u32 count, i; int rc; if (!display || !out_mode) return -EINVAL; *out_mode = NULL; rc = dsi_display_get_mode_count(display, &count); if (rc) return rc; mutex_lock(&display->display_lock); for (i = 0; i < count; i++) { struct dsi_display_mode *m = &display->modes[i]; if (cmp->timing.v_active == m->timing.v_active && cmp->timing.h_active == m->timing.h_active && cmp->timing.refresh_rate == m->timing.refresh_rate) { *out_mode = m; rc = 0; break; } } mutex_unlock(&display->display_lock); if (!*out_mode) { pr_err("[%s] failed to find mode for v_active %u h_active %u rate %u\n", display->name, cmp->timing.v_active, cmp->timing.h_active, cmp->timing.refresh_rate); rc = -ENOENT; } return rc; } Loading Loading @@ -4632,9 +4733,18 @@ int dsi_display_prepare(struct dsi_display *display) goto error_panel_post_unprep; } /* * If ULPS during suspend feature is enabled, then DSI PHY was * left on during suspend. In this case, we do not need to reset/init * PHY. This would have already been done when the CORE clocks are * turned on. However, if cont splash is disabled, the first time DSI * is powered on, phy init needs to be done unconditionally. */ if (!display->panel->ulps_suspend_enabled || !display->ulps_enabled) { rc = dsi_display_phy_sw_reset(display); if (rc) { pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc); pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc); goto error_ctrl_clk_off; } Loading @@ -4644,6 +4754,7 @@ int dsi_display_prepare(struct dsi_display *display) display->name, rc); goto error_ctrl_clk_off; } } rc = dsi_display_set_clk_src(display); if (rc) { Loading Loading @@ -5129,10 +5240,12 @@ int dsi_display_unprepare(struct dsi_display *display) pr_err("[%s] failed to deinit controller, rc=%d\n", display->name, rc); if (!display->panel->ulps_suspend_enabled) { rc = dsi_display_phy_disable(display); if (rc) pr_err("[%s] failed to disable DSI PHY, rc=%d\n", display->name, rc); } rc = dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_CORE_CLK, DSI_CLK_OFF); Loading