Loading drivers/gpu/drm/msm/dp/dp_display.c +123 −72 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 @@ -300,7 +301,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 @@ -317,7 +323,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 @@ -337,25 +342,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 @@ -399,32 +386,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 @@ -434,8 +414,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 @@ -445,12 +424,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 @@ -476,6 +491,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 @@ -793,18 +811,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 @@ -812,7 +818,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 @@ -837,6 +843,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 @@ -845,6 +857,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 @@ -888,6 +906,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 @@ -899,6 +929,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 @@ -914,13 +946,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 @@ -1023,7 +1082,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 @@ -1148,7 +1207,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 @@ -1178,7 +1237,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 @@ -1206,7 +1265,7 @@ static int dp_display_pre_kickoff(struct dp_display *dp_display, dp = container_of(dp_display, struct dp_display_private, dp_display); if (hdr->hdr_supported) if (hdr->hdr_supported && dp->panel->hdr_supported(dp->panel)) rc = dp->panel->setup_hdr(dp->panel, hdr); return rc; Loading Loading @@ -1249,16 +1308,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 @@ -1276,20 +1329,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 +7 −3 Original line number Diff line number Diff line Loading @@ -295,6 +295,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 +380,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 +391,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/dp/dp_panel.c +56 −5 Original line number Diff line number Diff line Loading @@ -19,6 +19,11 @@ #define DP_PANEL_DEFAULT_BPP 24 #define DP_MAX_DS_PORT_COUNT 1 #define DPRX_FEATURE_ENUMERATION_LIST 0x2210 #define VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED BIT(3) #define VSC_EXT_VESA_SDP_SUPPORTED BIT(4) #define VSC_EXT_VESA_SDP_CHAINING_SUPPORTED BIT(5) enum dp_panel_hdr_pixel_encoding { RGB, YCbCr444, Loading Loading @@ -65,9 +70,14 @@ struct dp_panel_private { bool custom_edid; bool custom_dpcd; bool panel_on; bool vsc_supported; bool vscext_supported; bool vscext_chaining_supported; enum dp_panel_hdr_state hdr_state; u8 spd_vendor_name[8]; u8 spd_product_description[16]; u8 major; u8 minor; }; static const struct dp_panel_info fail_safe = { Loading Loading @@ -99,7 +109,7 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) int rlen, rc = 0; struct dp_panel_private *panel; struct drm_dp_link *link_info; u8 *dpcd, major = 0, minor = 0; u8 *dpcd, rx_feature; u32 dfp_count = 0; unsigned long caps = DP_LINK_CAP_ENHANCED_FRAMING; Loading Loading @@ -131,11 +141,33 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false); } rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DPRX_FEATURE_ENUMERATION_LIST, &rx_feature, 1); if (rlen != 1) { pr_debug("failed to read DPRX_FEATURE_ENUMERATION_LIST\n"); panel->vsc_supported = false; panel->vscext_supported = false; panel->vscext_chaining_supported = false; } else { panel->vsc_supported = !!(rx_feature & VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED); panel->vscext_supported = !!(rx_feature & VSC_EXT_VESA_SDP_SUPPORTED); panel->vscext_chaining_supported = !!(rx_feature & VSC_EXT_VESA_SDP_CHAINING_SUPPORTED); } pr_debug("vsc=%d, vscext=%d, vscext_chaining=%d\n", panel->vsc_supported, panel->vscext_supported, panel->vscext_chaining_supported); link_info->revision = dp_panel->dpcd[DP_DPCD_REV]; major = (link_info->revision >> 4) & 0x0f; minor = link_info->revision & 0x0f; pr_debug("version: %d.%d\n", major, minor); panel->major = (link_info->revision >> 4) & 0x0f; panel->minor = link_info->revision & 0x0f; pr_debug("version: %d.%d\n", panel->major, panel->minor); link_info->rate = drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]); Loading Loading @@ -655,6 +687,21 @@ static u32 dp_panel_get_min_req_link_rate(struct dp_panel *dp_panel) return min_link_rate_khz; } static bool dp_panel_hdr_supported(struct dp_panel *dp_panel) { struct dp_panel_private *panel; if (!dp_panel) { pr_err("invalid input\n"); return false; } panel = container_of(dp_panel, struct dp_panel_private, dp_panel); return panel->major >= 1 && panel->vsc_supported && (panel->minor >= 4 || panel->vscext_supported); } static bool dp_panel_is_validate_hdr_state(struct dp_panel_private *panel, struct drm_msm_ext_hdr_metadata *hdr_meta) { Loading Loading @@ -731,7 +778,10 @@ static int dp_panel_setup_hdr(struct dp_panel *dp_panel, hdr->version = 0x01; hdr->length = 0x1A; if (panel->hdr_state) memcpy(&hdr->hdr_meta, hdr_meta, sizeof(hdr->hdr_meta)); else memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta)); panel->catalog->config_hdr(panel->catalog, panel->hdr_state); end: Loading Loading @@ -806,6 +856,7 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) dp_panel->tpg_config = dp_panel_tpg_config; dp_panel->spd_config = dp_panel_spd_config; dp_panel->setup_hdr = dp_panel_setup_hdr; dp_panel->hdr_supported = dp_panel_hdr_supported; dp_panel_edid_register(panel); Loading Loading
drivers/gpu/drm/msm/dp/dp_display.c +123 −72 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 @@ -300,7 +301,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 @@ -317,7 +323,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 @@ -337,25 +342,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 @@ -399,32 +386,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 @@ -434,8 +414,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 @@ -445,12 +424,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 @@ -476,6 +491,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 @@ -793,18 +811,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 @@ -812,7 +818,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 @@ -837,6 +843,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 @@ -845,6 +857,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 @@ -888,6 +906,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 @@ -899,6 +929,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 @@ -914,13 +946,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 @@ -1023,7 +1082,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 @@ -1148,7 +1207,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 @@ -1178,7 +1237,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 @@ -1206,7 +1265,7 @@ static int dp_display_pre_kickoff(struct dp_display *dp_display, dp = container_of(dp_display, struct dp_display_private, dp_display); if (hdr->hdr_supported) if (hdr->hdr_supported && dp->panel->hdr_supported(dp->panel)) rc = dp->panel->setup_hdr(dp->panel, hdr); return rc; Loading Loading @@ -1249,16 +1308,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 @@ -1276,20 +1329,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 +7 −3 Original line number Diff line number Diff line Loading @@ -295,6 +295,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 +380,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 +391,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/dp/dp_panel.c +56 −5 Original line number Diff line number Diff line Loading @@ -19,6 +19,11 @@ #define DP_PANEL_DEFAULT_BPP 24 #define DP_MAX_DS_PORT_COUNT 1 #define DPRX_FEATURE_ENUMERATION_LIST 0x2210 #define VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED BIT(3) #define VSC_EXT_VESA_SDP_SUPPORTED BIT(4) #define VSC_EXT_VESA_SDP_CHAINING_SUPPORTED BIT(5) enum dp_panel_hdr_pixel_encoding { RGB, YCbCr444, Loading Loading @@ -65,9 +70,14 @@ struct dp_panel_private { bool custom_edid; bool custom_dpcd; bool panel_on; bool vsc_supported; bool vscext_supported; bool vscext_chaining_supported; enum dp_panel_hdr_state hdr_state; u8 spd_vendor_name[8]; u8 spd_product_description[16]; u8 major; u8 minor; }; static const struct dp_panel_info fail_safe = { Loading Loading @@ -99,7 +109,7 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) int rlen, rc = 0; struct dp_panel_private *panel; struct drm_dp_link *link_info; u8 *dpcd, major = 0, minor = 0; u8 *dpcd, rx_feature; u32 dfp_count = 0; unsigned long caps = DP_LINK_CAP_ENHANCED_FRAMING; Loading Loading @@ -131,11 +141,33 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false); } rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DPRX_FEATURE_ENUMERATION_LIST, &rx_feature, 1); if (rlen != 1) { pr_debug("failed to read DPRX_FEATURE_ENUMERATION_LIST\n"); panel->vsc_supported = false; panel->vscext_supported = false; panel->vscext_chaining_supported = false; } else { panel->vsc_supported = !!(rx_feature & VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED); panel->vscext_supported = !!(rx_feature & VSC_EXT_VESA_SDP_SUPPORTED); panel->vscext_chaining_supported = !!(rx_feature & VSC_EXT_VESA_SDP_CHAINING_SUPPORTED); } pr_debug("vsc=%d, vscext=%d, vscext_chaining=%d\n", panel->vsc_supported, panel->vscext_supported, panel->vscext_chaining_supported); link_info->revision = dp_panel->dpcd[DP_DPCD_REV]; major = (link_info->revision >> 4) & 0x0f; minor = link_info->revision & 0x0f; pr_debug("version: %d.%d\n", major, minor); panel->major = (link_info->revision >> 4) & 0x0f; panel->minor = link_info->revision & 0x0f; pr_debug("version: %d.%d\n", panel->major, panel->minor); link_info->rate = drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]); Loading Loading @@ -655,6 +687,21 @@ static u32 dp_panel_get_min_req_link_rate(struct dp_panel *dp_panel) return min_link_rate_khz; } static bool dp_panel_hdr_supported(struct dp_panel *dp_panel) { struct dp_panel_private *panel; if (!dp_panel) { pr_err("invalid input\n"); return false; } panel = container_of(dp_panel, struct dp_panel_private, dp_panel); return panel->major >= 1 && panel->vsc_supported && (panel->minor >= 4 || panel->vscext_supported); } static bool dp_panel_is_validate_hdr_state(struct dp_panel_private *panel, struct drm_msm_ext_hdr_metadata *hdr_meta) { Loading Loading @@ -731,7 +778,10 @@ static int dp_panel_setup_hdr(struct dp_panel *dp_panel, hdr->version = 0x01; hdr->length = 0x1A; if (panel->hdr_state) memcpy(&hdr->hdr_meta, hdr_meta, sizeof(hdr->hdr_meta)); else memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta)); panel->catalog->config_hdr(panel->catalog, panel->hdr_state); end: Loading Loading @@ -806,6 +856,7 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) dp_panel->tpg_config = dp_panel_tpg_config; dp_panel->spd_config = dp_panel_spd_config; dp_panel->setup_hdr = dp_panel_setup_hdr; dp_panel->hdr_supported = dp_panel_hdr_supported; dp_panel_edid_register(panel); Loading