diff options
Diffstat (limited to '')
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_aux.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_ctrl.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_display.c | 59 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_display.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_drm.c | 75 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_hpd.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_hpd.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_link.c | 19 |
8 files changed, 165 insertions, 33 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index eb40d8413bca..6d36f63c3338 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -33,6 +33,7 @@ struct dp_aux_private { bool read; bool no_send_addr; bool no_send_stop; + bool initted; u32 offset; u32 segment; @@ -331,6 +332,10 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, } mutex_lock(&aux->mutex); + if (!aux->initted) { + ret = -EIO; + goto exit; + } dp_aux_update_offset_and_segment(aux, msg); dp_aux_transfer_helper(aux, msg, true); @@ -380,6 +385,8 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, } aux->cmd_busy = false; + +exit: mutex_unlock(&aux->mutex); return ret; @@ -431,8 +438,13 @@ void dp_aux_init(struct drm_dp_aux *dp_aux) aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + mutex_lock(&aux->mutex); + dp_catalog_aux_enable(aux->catalog, true); aux->retry_cnt = 0; + aux->initted = true; + + mutex_unlock(&aux->mutex); } void dp_aux_deinit(struct drm_dp_aux *dp_aux) @@ -441,7 +453,12 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux) aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + mutex_lock(&aux->mutex); + + aux->initted = false; dp_catalog_aux_enable(aux->catalog, false); + + mutex_unlock(&aux->mutex); } int dp_aux_register(struct drm_dp_aux *dp_aux) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 62e75dc8afc6..c724cb0bde9d 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -119,13 +119,13 @@ void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) { u32 config = 0, tbd; - u8 *dpcd = ctrl->panel->dpcd; + const u8 *dpcd = ctrl->panel->dpcd; /* Default-> LSCLK DIV: 1/4 LCLK */ config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT); /* Scrambler reset enable */ - if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP) + if (drm_dp_alternate_scrambler_reset_cap(dpcd)) config |= DP_CONFIGURATION_CTRL_ASSR; tbd = dp_link_get_test_bits_depth(ctrl->link, @@ -1228,7 +1228,10 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, int *training_step) { int ret = 0; + const u8 *dpcd = ctrl->panel->dpcd; u8 encoding = DP_SET_ANSI_8B10B; + u8 ssc; + u8 assr; struct dp_link_info link_info = {0}; dp_ctrl_config_ctrl(ctrl); @@ -1238,9 +1241,21 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, link_info.capabilities = DP_LINK_CAP_ENHANCED_FRAMING; dp_aux_link_configure(ctrl->aux, &link_info); + + if (drm_dp_max_downspread(dpcd)) { + ssc = DP_SPREAD_AMP_0_5; + drm_dp_dpcd_write(ctrl->aux, DP_DOWNSPREAD_CTRL, &ssc, 1); + } + drm_dp_dpcd_write(ctrl->aux, DP_MAIN_LINK_CHANNEL_CODING_SET, &encoding, 1); + if (drm_dp_alternate_scrambler_reset_cap(dpcd)) { + assr = DP_ALTERNATE_SCRAMBLER_RESET_ENABLE; + drm_dp_dpcd_write(ctrl->aux, DP_EDP_CONFIGURATION_SET, + &assr, 1); + } + ret = dp_ctrl_link_train_1(ctrl, training_step); if (ret) { DRM_ERROR("link training #1 failed. ret=%d\n", ret); @@ -1312,9 +1327,11 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) struct dp_io *dp_io = &ctrl->parser->io; struct phy *phy = dp_io->phy; struct phy_configure_opts_dp *opts_dp = &dp_io->phy_opts.dp; + const u8 *dpcd = ctrl->panel->dpcd; opts_dp->lanes = ctrl->link->link_params.num_lanes; opts_dp->link_rate = ctrl->link->link_params.rate / 100; + opts_dp->ssc = drm_dp_max_downspread(dpcd); dp_ctrl_set_clock_rate(ctrl, DP_CTRL_PM, "ctrl_link", ctrl->link->link_params.rate * 1000); @@ -1406,7 +1423,7 @@ void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl) static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl) { - u8 *dpcd = ctrl->panel->dpcd; + const u8 *dpcd = ctrl->panel->dpcd; /* * For better interop experience, used a fixed NVID=0x8000 diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index aba8aa47ed76..7cc4d21f2091 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -135,8 +135,18 @@ static const struct msm_dp_config sc7180_dp_cfg = { .num_descs = 1, }; +static const struct msm_dp_config sc7280_dp_cfg = { + .descs = (const struct msm_dp_desc[]) { + [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, + [MSM_DP_CONTROLLER_1] = { .io_start = 0x0aea0000, .connector_type = DRM_MODE_CONNECTOR_eDP }, + }, + .num_descs = 2, +}; + static const struct of_device_id dp_dt_match[] = { { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_cfg }, + { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_cfg }, + { .compatible = "qcom,sc7280-edp", .data = &sc7280_dp_cfg }, {} }; @@ -224,13 +234,10 @@ static int dp_display_bind(struct device *dev, struct device *master, { int rc = 0; struct dp_display_private *dp = dev_get_dp_display_private(dev); - struct msm_drm_private *priv; - struct drm_device *drm; - - drm = dev_get_drvdata(master); + struct msm_drm_private *priv = dev_get_drvdata(master); + struct drm_device *drm = priv->dev; dp->dp_display.drm_dev = drm; - priv = drm->dev_private; priv->dp[dp->id] = &dp->dp_display; rc = dp->parser->parse(dp->parser, dp->dp_display.connector_type); @@ -266,8 +273,7 @@ static void dp_display_unbind(struct device *dev, struct device *master, void *data) { struct dp_display_private *dp = dev_get_dp_display_private(dev); - struct drm_device *drm = dev_get_drvdata(master); - struct msm_drm_private *priv = drm->dev_private; + struct msm_drm_private *priv = dev_get_drvdata(master); dp_power_client_deinit(dp->power); dp_aux_unregister(dp->aux); @@ -410,12 +416,11 @@ static int dp_display_usbpd_configure_cb(struct device *dev) static int dp_display_usbpd_disconnect_cb(struct device *dev) { - int rc = 0; struct dp_display_private *dp = dev_get_dp_display_private(dev); dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); - return rc; + return 0; } static void dp_display_handle_video_request(struct dp_display_private *dp) @@ -522,11 +527,8 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) dp->hpd_state = ST_CONNECT_PENDING; - hpd->hpd_high = 1; - ret = dp_display_usbpd_configure_cb(&dp->pdev->dev); if (ret) { /* link train failed */ - hpd->hpd_high = 0; dp->hpd_state = ST_DISCONNECTED; if (ret == -ECONNRESET) { /* cable unplugged */ @@ -603,7 +605,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) /* triggered by irq_hdp with sink_count = 0 */ if (dp->link->sink_count == 0) { dp_ctrl_off_phy(dp->ctrl); - hpd->hpd_high = 0; dp->core_initialized = false; } mutex_unlock(&dp->event_mutex); @@ -627,8 +628,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) /* disable HPD plug interrupts */ dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false); - hpd->hpd_high = 0; - /* * We don't need separate work for disconnect as * connect/attention interrupts are disabled @@ -693,9 +692,15 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) return 0; } - ret = dp_display_usbpd_attention_cb(&dp->pdev->dev); - if (ret == -ECONNRESET) { /* cable unplugged */ - dp->core_initialized = false; + /* + * dp core (ahb/aux clks) must be initialized before + * irq_hpd be handled + */ + if (dp->core_initialized) { + ret = dp_display_usbpd_attention_cb(&dp->pdev->dev); + if (ret == -ECONNRESET) { /* cable unplugged */ + dp->core_initialized = false; + } } DRM_DEBUG_DP("hpd_state=%d\n", state); @@ -707,9 +712,9 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) static void dp_display_deinit_sub_modules(struct dp_display_private *dp) { dp_debug_put(dp->debug); + dp_audio_put(dp->audio); dp_panel_put(dp->panel); dp_aux_put(dp->aux); - dp_audio_put(dp->audio); } static int dp_init_sub_modules(struct dp_display_private *dp) @@ -1481,6 +1486,18 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, } priv->connectors[priv->num_connectors++] = dp_display->connector; + + dp_display->bridge = msm_dp_bridge_init(dp_display, dev, encoder); + if (IS_ERR(dp_display->bridge)) { + ret = PTR_ERR(dp_display->bridge); + DRM_DEV_ERROR(dev->dev, + "failed to create dp bridge: %d\n", ret); + dp_display->bridge = NULL; + return ret; + } + + priv->bridges[priv->num_bridges++] = dp_display->bridge; + return 0; } @@ -1584,8 +1601,8 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder) } void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct dp_display_private *dp_display; diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 8e80e3bac394..e3adcd578a90 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -13,6 +13,7 @@ struct msm_dp { struct drm_device *drm_dev; struct device *codec_dev; + struct drm_bridge *bridge; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_bridge *panel_bridge; diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 76856c4ee1d6..d4d360d19eba 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -12,6 +12,14 @@ #include "msm_kms.h" #include "dp_drm.h" + +struct msm_dp_bridge { + struct drm_bridge bridge; + struct msm_dp *dp_display; +}; + +#define to_dp_display(x) container_of((x), struct msm_dp_bridge, bridge) + struct dp_connector { struct drm_connector base; struct msm_dp *dp_display; @@ -173,3 +181,70 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display) return connector; } + +static void dp_bridge_mode_set(struct drm_bridge *drm_bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + msm_dp_display_mode_set(dp_display, drm_bridge->encoder, mode, adjusted_mode); +} + +static void dp_bridge_enable(struct drm_bridge *drm_bridge) +{ + struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + msm_dp_display_enable(dp_display, drm_bridge->encoder); +} + +static void dp_bridge_disable(struct drm_bridge *drm_bridge) +{ + struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + msm_dp_display_pre_disable(dp_display, drm_bridge->encoder); +} + +static void dp_bridge_post_disable(struct drm_bridge *drm_bridge) +{ + struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + msm_dp_display_disable(dp_display, drm_bridge->encoder); +} + +static const struct drm_bridge_funcs dp_bridge_ops = { + .enable = dp_bridge_enable, + .disable = dp_bridge_disable, + .post_disable = dp_bridge_post_disable, + .mode_set = dp_bridge_mode_set, +}; + +struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, + struct drm_encoder *encoder) +{ + int rc; + struct msm_dp_bridge *dp_bridge; + struct drm_bridge *bridge; + + dp_bridge = devm_kzalloc(dev->dev, sizeof(*dp_bridge), GFP_KERNEL); + if (!dp_bridge) + return ERR_PTR(-ENOMEM); + + dp_bridge->dp_display = dp_display; + + bridge = &dp_bridge->bridge; + bridge->funcs = &dp_bridge_ops; + bridge->encoder = encoder; + + rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (rc) { + DRM_ERROR("failed to attach bridge, rc=%d\n", rc); + return ERR_PTR(rc); + } + + return bridge; +} diff --git a/drivers/gpu/drm/msm/dp/dp_hpd.c b/drivers/gpu/drm/msm/dp/dp_hpd.c index e1c90fa47411..db98a1d431eb 100644 --- a/drivers/gpu/drm/msm/dp/dp_hpd.c +++ b/drivers/gpu/drm/msm/dp/dp_hpd.c @@ -32,8 +32,6 @@ int dp_hpd_connect(struct dp_usbpd *dp_usbpd, bool hpd) hpd_priv = container_of(dp_usbpd, struct dp_hpd_private, dp_usbpd); - dp_usbpd->hpd_high = hpd; - if (!hpd_priv->dp_cb || !hpd_priv->dp_cb->configure || !hpd_priv->dp_cb->disconnect) { pr_err("hpd dp_cb not initialized\n"); diff --git a/drivers/gpu/drm/msm/dp/dp_hpd.h b/drivers/gpu/drm/msm/dp/dp_hpd.h index 5bc5bb64680f..8feec5aa5027 100644 --- a/drivers/gpu/drm/msm/dp/dp_hpd.h +++ b/drivers/gpu/drm/msm/dp/dp_hpd.h @@ -26,7 +26,6 @@ enum plug_orientation { * @multi_func: multi-function preferred * @usb_config_req: request to switch to usb * @exit_dp_mode: request exit from displayport mode - * @hpd_high: Hot Plug Detect signal is high. * @hpd_irq: Change in the status since last message * @alt_mode_cfg_done: bool to specify alt mode status * @debug_en: bool to specify debug mode @@ -39,7 +38,6 @@ struct dp_usbpd { bool multi_func; bool usb_config_req; bool exit_dp_mode; - bool hpd_high; bool hpd_irq; bool alt_mode_cfg_done; bool debug_en; diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index a5bdfc5029de..d4d31e5bda07 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -737,18 +737,25 @@ static int dp_link_parse_sink_count(struct dp_link *dp_link) return 0; } -static void dp_link_parse_sink_status_field(struct dp_link_private *link) +static int dp_link_parse_sink_status_field(struct dp_link_private *link) { int len = 0; link->prev_sink_count = link->dp_link.sink_count; - dp_link_parse_sink_count(&link->dp_link); + len = dp_link_parse_sink_count(&link->dp_link); + if (len < 0) { + DRM_ERROR("DP parse sink count failed\n"); + return len; + } len = drm_dp_dpcd_read_link_status(link->aux, link->link_status); - if (len < DP_LINK_STATUS_SIZE) + if (len < DP_LINK_STATUS_SIZE) { DRM_ERROR("DP link status read failed\n"); - dp_link_parse_request(link); + return len; + } + + return dp_link_parse_request(link); } /** @@ -1023,7 +1030,9 @@ int dp_link_process_request(struct dp_link *dp_link) dp_link_reset_data(link); - dp_link_parse_sink_status_field(link); + ret = dp_link_parse_sink_status_field(link); + if (ret) + return ret; if (link->request.test_requested == DP_TEST_LINK_EDID_READ) { dp_link->sink_request |= DP_TEST_LINK_EDID_READ; |