diff options
Diffstat (limited to 'drivers/gpu/drm/bridge/analogix')
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix-anx6345.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 370 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 157 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/anx7625.c | 177 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/anx7625.h | 10 |
9 files changed, 268 insertions, 536 deletions
diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig index 173dada218ec..4846b2e9be7c 100644 --- a/drivers/gpu/drm/bridge/analogix/Kconfig +++ b/drivers/gpu/drm/bridge/analogix/Kconfig @@ -37,7 +37,7 @@ config DRM_ANALOGIX_ANX7625 select DRM_DISPLAY_DP_HELPER select DRM_DISPLAY_HDCP_HELPER select DRM_DISPLAY_HELPER - select DRM_DP_AUX_BUS + select DRM_DISPLAY_DP_AUX_BUS select DRM_MIPI_DSI help ANX7625 is an ultra-low power 4K mobile HD transmitter diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index c9e35731e6a1..83d711ee3a2e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -47,7 +47,7 @@ struct anx6345 { struct drm_dp_aux aux; struct drm_bridge bridge; struct i2c_client *client; - struct edid *edid; + const struct drm_edid *drm_edid; struct drm_connector connector; struct drm_panel *panel; struct regulator *dvdd12; @@ -458,7 +458,7 @@ static int anx6345_get_modes(struct drm_connector *connector) mutex_lock(&anx6345->lock); - if (!anx6345->edid) { + if (!anx6345->drm_edid) { if (!anx6345->powered) { anx6345_poweron(anx6345); power_off = true; @@ -470,19 +470,18 @@ static int anx6345_get_modes(struct drm_connector *connector) goto unlock; } - anx6345->edid = drm_get_edid(connector, &anx6345->aux.ddc); - if (!anx6345->edid) + anx6345->drm_edid = drm_edid_read_ddc(connector, &anx6345->aux.ddc); + if (!anx6345->drm_edid) DRM_ERROR("Failed to read EDID from panel\n"); - err = drm_connector_update_edid_property(connector, - anx6345->edid); + err = drm_edid_connector_update(connector, anx6345->drm_edid); if (err) { DRM_ERROR("Failed to update EDID property: %d\n", err); goto unlock; } } - num_modes += drm_add_edid_modes(connector, anx6345->edid); + num_modes += drm_edid_connector_add_modes(connector); /* Driver currently supports only 6bpc */ connector->display_info.bpc = 6; @@ -528,11 +527,6 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge, return -EINVAL; } - if (!bridge->encoder) { - DRM_ERROR("Parent encoder object not found"); - return -ENODEV; - } - /* Register aux channel */ anx6345->aux.name = "DP-AUX"; anx6345->aux.dev = &anx6345->client->dev; @@ -793,13 +787,13 @@ static void anx6345_i2c_remove(struct i2c_client *client) unregister_i2c_dummy_clients(anx6345); - kfree(anx6345->edid); + drm_edid_free(anx6345->drm_edid); mutex_destroy(&anx6345->lock); } static const struct i2c_device_id anx6345_id[] = { - { "anx6345", 0 }, + { "anx6345" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, anx6345_id); diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index 5748a8581af4..f74694bb9c50 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -67,7 +67,7 @@ struct anx78xx { struct drm_dp_aux aux; struct drm_bridge bridge; struct i2c_client *client; - struct edid *edid; + const struct drm_edid *drm_edid; struct drm_connector connector; struct anx78xx_platform_data pdata; struct mutex lock; @@ -830,8 +830,8 @@ static int anx78xx_get_modes(struct drm_connector *connector) if (WARN_ON(!anx78xx->powered)) return 0; - if (anx78xx->edid) - return drm_add_edid_modes(connector, anx78xx->edid); + if (anx78xx->drm_edid) + return drm_edid_connector_add_modes(connector); mutex_lock(&anx78xx->lock); @@ -841,20 +841,21 @@ static int anx78xx_get_modes(struct drm_connector *connector) goto unlock; } - anx78xx->edid = drm_get_edid(connector, &anx78xx->aux.ddc); - if (!anx78xx->edid) { + anx78xx->drm_edid = drm_edid_read_ddc(connector, &anx78xx->aux.ddc); + + err = drm_edid_connector_update(connector, anx78xx->drm_edid); + + if (!anx78xx->drm_edid) { DRM_ERROR("Failed to read EDID\n"); goto unlock; } - err = drm_connector_update_edid_property(connector, - anx78xx->edid); if (err) { DRM_ERROR("Failed to update EDID property: %d\n", err); goto unlock; } - num_modes = drm_add_edid_modes(connector, anx78xx->edid); + num_modes = drm_edid_connector_add_modes(connector); unlock: mutex_unlock(&anx78xx->lock); @@ -897,11 +898,6 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge, return -EINVAL; } - if (!bridge->encoder) { - DRM_ERROR("Parent encoder object not found"); - return -ENODEV; - } - /* Register aux channel */ anx78xx->aux.name = "DP-AUX"; anx78xx->aux.dev = &anx78xx->client->dev; @@ -1091,8 +1087,8 @@ static bool anx78xx_handle_common_int_4(struct anx78xx *anx78xx, u8 irq) event = true; anx78xx_poweroff(anx78xx); /* Free cached EDID */ - kfree(anx78xx->edid); - anx78xx->edid = NULL; + drm_edid_free(anx78xx->drm_edid); + anx78xx->drm_edid = NULL; } else if (irq & SP_HPD_PLUG) { DRM_DEBUG_KMS("IRQ: Hot plug detect - cable plug\n"); event = true; @@ -1363,7 +1359,7 @@ static void anx78xx_i2c_remove(struct i2c_client *client) unregister_i2c_dummy_clients(anx78xx); - kfree(anx78xx->edid); + drm_edid_free(anx78xx->drm_edid); } static const struct of_device_id anx78xx_match_table[] = { diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index df9370e0ff23..bfa88409a7ff 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -36,15 +36,8 @@ static const bool verify_fast_training; -struct bridge_init { - struct i2c_client *client; - struct device_node *node; -}; - -static int analogix_dp_init_dp(struct analogix_dp_device *dp) +static void analogix_dp_init_dp(struct analogix_dp_device *dp) { - int ret; - analogix_dp_reset(dp); analogix_dp_swreset(dp); @@ -56,13 +49,9 @@ static int analogix_dp_init_dp(struct analogix_dp_device *dp) analogix_dp_enable_sw_function(dp); analogix_dp_config_interrupt(dp); - ret = analogix_dp_init_analog_func(dp); - if (ret) - return ret; analogix_dp_init_hpd(dp); analogix_dp_init_aux(dp); - return 0; } static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) @@ -234,32 +223,10 @@ static int analogix_dp_training_pattern_dis(struct analogix_dp_device *dp) return ret < 0 ? ret : 0; } -static void -analogix_dp_set_lane_lane_pre_emphasis(struct analogix_dp_device *dp, - int pre_emphasis, int lane) -{ - switch (lane) { - case 0: - analogix_dp_set_lane0_pre_emphasis(dp, pre_emphasis); - break; - case 1: - analogix_dp_set_lane1_pre_emphasis(dp, pre_emphasis); - break; - - case 2: - analogix_dp_set_lane2_pre_emphasis(dp, pre_emphasis); - break; - - case 3: - analogix_dp_set_lane3_pre_emphasis(dp, pre_emphasis); - break; - } -} - static int analogix_dp_link_start(struct analogix_dp_device *dp) { u8 buf[4]; - int lane, lane_count, pll_tries, retval; + int lane, lane_count, retval; lane_count = dp->link_train.lane_count; @@ -271,6 +238,16 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) /* Set link rate and count as you want to establish*/ analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); + retval = analogix_dp_wait_pll_locked(dp); + if (retval) { + DRM_DEV_ERROR(dp->dev, "Wait for pll lock failed %d\n", retval); + return retval; + } + /* + * MACRO_RST must be applied after the PLL_LOCK to avoid + * the DP inter pair skew issue for at least 10 us + */ + analogix_dp_reset_macro(dp); analogix_dp_set_lane_count(dp, dp->link_train.lane_count); /* Setup RX configuration */ @@ -286,22 +263,12 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) return retval; } - /* Set TX pre-emphasis to minimum */ + /* Set TX voltage-swing and pre-emphasis to minimum */ for (lane = 0; lane < lane_count; lane++) - analogix_dp_set_lane_lane_pre_emphasis(dp, - PRE_EMPHASIS_LEVEL_0, lane); - - /* Wait for PLL lock */ - pll_tries = 0; - while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - if (pll_tries == DP_TIMEOUT_LOOP_COUNT) { - dev_err(dp->dev, "Wait for PLL lock timed out\n"); - return -ETIMEDOUT; - } - - pll_tries++; - usleep_range(90, 120); - } + dp->link_train.training_lane[lane] = + DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | + DP_TRAIN_PRE_EMPH_LEVEL_0; + analogix_dp_set_lane_link_training(dp); /* Set training pattern 1 */ analogix_dp_set_training_pattern(dp, TRAINING_PTN1); @@ -384,54 +351,6 @@ static unsigned char analogix_dp_get_adjust_request_pre_emphasis( return ((link_value >> shift) & 0xc) >> 2; } -static void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp, - u8 training_lane_set, int lane) -{ - switch (lane) { - case 0: - analogix_dp_set_lane0_link_training(dp, training_lane_set); - break; - case 1: - analogix_dp_set_lane1_link_training(dp, training_lane_set); - break; - - case 2: - analogix_dp_set_lane2_link_training(dp, training_lane_set); - break; - - case 3: - analogix_dp_set_lane3_link_training(dp, training_lane_set); - break; - } -} - -static unsigned int -analogix_dp_get_lane_link_training(struct analogix_dp_device *dp, - int lane) -{ - u32 reg; - - switch (lane) { - case 0: - reg = analogix_dp_get_lane0_link_training(dp); - break; - case 1: - reg = analogix_dp_get_lane1_link_training(dp); - break; - case 2: - reg = analogix_dp_get_lane2_link_training(dp); - break; - case 3: - reg = analogix_dp_get_lane3_link_training(dp); - break; - default: - WARN_ON(1); - return 0; - } - - return reg; -} - static void analogix_dp_reduce_link_rate(struct analogix_dp_device *dp) { analogix_dp_training_pattern_dis(dp); @@ -478,11 +397,6 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) if (retval < 0) return retval; - retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, - adjust_request, 2); - if (retval < 0) - return retval; - if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { /* set training pattern 2 for EQ */ analogix_dp_set_training_pattern(dp, TRAINING_PTN2); @@ -495,38 +409,37 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) dev_dbg(dp->dev, "Link Training Clock Recovery success\n"); dp->link_train.lt_state = EQUALIZER_TRAINING; - } else { - for (lane = 0; lane < lane_count; lane++) { - training_lane = analogix_dp_get_lane_link_training( - dp, lane); - voltage_swing = analogix_dp_get_adjust_request_voltage( - adjust_request, lane); - pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis( - adjust_request, lane); - - if (DPCD_VOLTAGE_SWING_GET(training_lane) == - voltage_swing && - DPCD_PRE_EMPHASIS_GET(training_lane) == - pre_emphasis) - dp->link_train.cr_loop[lane]++; - - if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || - voltage_swing == VOLTAGE_LEVEL_3 || - pre_emphasis == PRE_EMPHASIS_LEVEL_3) { - dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", - dp->link_train.cr_loop[lane], - voltage_swing, pre_emphasis); - analogix_dp_reduce_link_rate(dp); - return -EIO; - } + + return 0; + } + + retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, + adjust_request, 2); + if (retval < 0) + return retval; + + for (lane = 0; lane < lane_count; lane++) { + training_lane = analogix_dp_get_lane_link_training(dp, lane); + voltage_swing = analogix_dp_get_adjust_request_voltage(adjust_request, lane); + pre_emphasis = analogix_dp_get_adjust_request_pre_emphasis(adjust_request, lane); + + if (DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing && + DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis) + dp->link_train.cr_loop[lane]++; + + if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || + voltage_swing == VOLTAGE_LEVEL_3 || + pre_emphasis == PRE_EMPHASIS_LEVEL_3) { + dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", + dp->link_train.cr_loop[lane], + voltage_swing, pre_emphasis); + analogix_dp_reduce_link_rate(dp); + return -EIO; } } analogix_dp_get_adjust_training_lane(dp, adjust_request); - - for (lane = 0; lane < lane_count; lane++) - analogix_dp_set_lane_link_training(dp, - dp->link_train.training_lane[lane], lane); + analogix_dp_set_lane_link_training(dp); retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->link_train.training_lane, lane_count); @@ -538,7 +451,7 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) { - int lane, lane_count, retval; + int lane_count, retval; u32 reg; u8 link_align, link_status[2], adjust_request[2]; @@ -598,9 +511,7 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) return -EIO; } - for (lane = 0; lane < lane_count; lane++) - analogix_dp_set_lane_link_training(dp, - dp->link_train.training_lane[lane], lane); + analogix_dp_set_lane_link_training(dp); retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->link_train.training_lane, lane_count); @@ -644,12 +555,6 @@ static int analogix_dp_full_link_train(struct analogix_dp_device *dp, int retval = 0; bool training_finished = false; - /* - * MACRO_RST must be applied after the PLL_LOCK to avoid - * the DP inter pair skew issue for at least 10 us - */ - analogix_dp_reset_macro(dp); - /* Initialize by reading RX's DPCD */ analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); @@ -712,28 +617,24 @@ static int analogix_dp_full_link_train(struct analogix_dp_device *dp, static int analogix_dp_fast_link_train(struct analogix_dp_device *dp) { - int i, ret; + int ret; u8 link_align, link_status[2]; - enum pll_status status; - - analogix_dp_reset_macro(dp); analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); - analogix_dp_set_lane_count(dp, dp->link_train.lane_count); - - for (i = 0; i < dp->link_train.lane_count; i++) { - analogix_dp_set_lane_link_training(dp, - dp->link_train.training_lane[i], i); - } - - ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status, - status != PLL_UNLOCKED, 120, - 120 * DP_TIMEOUT_LOOP_COUNT); + ret = analogix_dp_wait_pll_locked(dp); if (ret) { DRM_DEV_ERROR(dp->dev, "Wait for pll lock failed %d\n", ret); return ret; } + /* + * MACRO_RST must be applied after the PLL_LOCK to avoid + * the DP inter pair skew issue for at least 10 us + */ + analogix_dp_reset_macro(dp); + analogix_dp_set_lane_count(dp, dp->link_train.lane_count); + analogix_dp_set_lane_link_training(dp); + /* source Set training pattern 1 */ analogix_dp_set_training_pattern(dp, TRAINING_PTN1); /* From DP spec, pattern must be on-screen for a minimum 500us */ @@ -803,11 +704,6 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp) analogix_dp_set_video_color_format(dp); - if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - dev_err(dp->dev, "PLL is not locked yet.\n"); - return -EINVAL; - } - for (;;) { timeout_loop++; if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0) @@ -1108,7 +1004,7 @@ out: static int analogix_dp_get_modes(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int ret, num_modes = 0; if (dp->plat_data->panel) { @@ -1120,12 +1016,13 @@ static int analogix_dp_get_modes(struct drm_connector *connector) return 0; } - edid = drm_get_edid(connector, &dp->aux.ddc); - if (edid) { - drm_connector_update_edid_property(&dp->connector, - edid); - num_modes += drm_add_edid_modes(&dp->connector, edid); - kfree(edid); + drm_edid = drm_edid_read_ddc(connector, &dp->aux.ddc); + + drm_edid_connector_update(&dp->connector, drm_edid); + + if (drm_edid) { + num_modes += drm_edid_connector_add_modes(&dp->connector); + drm_edid_free(drm_edid); } ret = analogix_dp_prepare_panel(dp, false, false); @@ -1228,11 +1125,6 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge, return -EINVAL; } - if (!bridge->encoder) { - DRM_ERROR("Parent encoder object not found"); - return -ENODEV; - } - if (!dp->plat_data->skip_connector) { connector = &dp->connector; connector->polled = DRM_CONNECTOR_POLL_HPD; @@ -1335,20 +1227,9 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp) pm_runtime_get_sync(dp->dev); - ret = clk_prepare_enable(dp->clock); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret); - goto out_dp_clk_pre; - } - - if (dp->plat_data->power_on_start) - dp->plat_data->power_on_start(dp->plat_data); - - phy_power_on(dp->phy); - - ret = analogix_dp_init_dp(dp); + ret = analogix_dp_init_analog_func(dp); if (ret) - goto out_dp_init; + return ret; /* * According to DP spec v1.3 chap 3.5.1.2 Link Training, @@ -1367,18 +1248,10 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp) goto out_dp_init; } - if (dp->plat_data->power_on_end) - dp->plat_data->power_on_end(dp->plat_data); - enable_irq(dp->irq); return 0; out_dp_init: - phy_power_off(dp->phy); - if (dp->plat_data->power_off) - dp->plat_data->power_off(dp->plat_data); - clk_disable_unprepare(dp->clock); -out_dp_clk_pre: pm_runtime_put_sync(dp->dev); return ret; @@ -1441,13 +1314,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) disable_irq(dp->irq); - if (dp->plat_data->power_off) - dp->plat_data->power_off(dp->plat_data); - analogix_dp_set_analog_power_down(dp, POWER_ALL, 1); - phy_power_off(dp->phy); - - clk_disable_unprepare(dp->clock); pm_runtime_put_sync(dp->dev); @@ -1738,8 +1605,6 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) return ERR_CAST(dp->clock); } - clk_prepare_enable(dp->clock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dp->reg_base = devm_ioremap_resource(&pdev->dev, res); @@ -1801,6 +1666,40 @@ err_disable_clk: } EXPORT_SYMBOL_GPL(analogix_dp_probe); +int analogix_dp_suspend(struct analogix_dp_device *dp) +{ + phy_power_off(dp->phy); + + if (dp->plat_data->power_off) + dp->plat_data->power_off(dp->plat_data); + + clk_disable_unprepare(dp->clock); + + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_suspend); + +int analogix_dp_resume(struct analogix_dp_device *dp) +{ + int ret; + + ret = clk_prepare_enable(dp->clock); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret); + return ret; + } + + if (dp->plat_data->power_on) + dp->plat_data->power_on(dp->plat_data); + + phy_power_on(dp->phy); + + analogix_dp_init_dp(dp); + + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_resume); + int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev) { int ret; @@ -1808,31 +1707,44 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev) dp->drm_dev = drm_dev; dp->encoder = dp->plat_data->encoder; + if (IS_ENABLED(CONFIG_PM)) { + pm_runtime_use_autosuspend(dp->dev); + pm_runtime_set_autosuspend_delay(dp->dev, 100); + pm_runtime_enable(dp->dev); + } else { + ret = analogix_dp_resume(dp); + if (ret) + return ret; + } + dp->aux.name = "DP-AUX"; dp->aux.transfer = analogix_dpaux_transfer; dp->aux.dev = dp->dev; dp->aux.drm_dev = drm_dev; ret = drm_dp_aux_register(&dp->aux); - if (ret) - return ret; - - pm_runtime_use_autosuspend(dp->dev); - pm_runtime_set_autosuspend_delay(dp->dev, 100); - pm_runtime_enable(dp->dev); + if (ret) { + DRM_ERROR("failed to register AUX (%d)\n", ret); + goto err_disable_pm_runtime; + } ret = analogix_dp_create_bridge(drm_dev, dp); if (ret) { DRM_ERROR("failed to create bridge (%d)\n", ret); - goto err_disable_pm_runtime; + goto err_unregister_aux; } return 0; -err_disable_pm_runtime: - pm_runtime_dont_use_autosuspend(dp->dev); - pm_runtime_disable(dp->dev); +err_unregister_aux: drm_dp_aux_unregister(&dp->aux); +err_disable_pm_runtime: + if (IS_ENABLED(CONFIG_PM)) { + pm_runtime_dont_use_autosuspend(dp->dev); + pm_runtime_disable(dp->dev); + } else { + analogix_dp_suspend(dp); + } return ret; } @@ -1849,39 +1761,15 @@ void analogix_dp_unbind(struct analogix_dp_device *dp) } drm_dp_aux_unregister(&dp->aux); - pm_runtime_dont_use_autosuspend(dp->dev); - pm_runtime_disable(dp->dev); -} -EXPORT_SYMBOL_GPL(analogix_dp_unbind); -void analogix_dp_remove(struct analogix_dp_device *dp) -{ - clk_disable_unprepare(dp->clock); -} -EXPORT_SYMBOL_GPL(analogix_dp_remove); - -#ifdef CONFIG_PM -int analogix_dp_suspend(struct analogix_dp_device *dp) -{ - clk_disable_unprepare(dp->clock); - return 0; -} -EXPORT_SYMBOL_GPL(analogix_dp_suspend); - -int analogix_dp_resume(struct analogix_dp_device *dp) -{ - int ret; - - ret = clk_prepare_enable(dp->clock); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret); - return ret; + if (IS_ENABLED(CONFIG_PM)) { + pm_runtime_dont_use_autosuspend(dp->dev); + pm_runtime_disable(dp->dev); + } else { + analogix_dp_suspend(dp); } - - return 0; } -EXPORT_SYMBOL_GPL(analogix_dp_resume); -#endif +EXPORT_SYMBOL_GPL(analogix_dp_unbind); int analogix_dp_start_crc(struct drm_connector *connector) { diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 433f2d7efa0c..774d11574b09 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -95,11 +95,6 @@ enum dynamic_range { CEA }; -enum pll_status { - PLL_UNLOCKED, - PLL_LOCKED -}; - enum clock_recovery_m_value_type { CALCULATED_M, REGISTER_M @@ -191,7 +186,7 @@ void analogix_dp_swreset(struct analogix_dp_device *dp); void analogix_dp_config_interrupt(struct analogix_dp_device *dp); void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp); void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp); -enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp); +int analogix_dp_wait_pll_locked(struct analogix_dp_device *dp); void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable); void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, enum analog_power_block block, @@ -213,26 +208,8 @@ void analogix_dp_enable_enhanced_mode(struct analogix_dp_device *dp, bool enable); void analogix_dp_set_training_pattern(struct analogix_dp_device *dp, enum pattern_set pattern); -void analogix_dp_set_lane0_pre_emphasis(struct analogix_dp_device *dp, - u32 level); -void analogix_dp_set_lane1_pre_emphasis(struct analogix_dp_device *dp, - u32 level); -void analogix_dp_set_lane2_pre_emphasis(struct analogix_dp_device *dp, - u32 level); -void analogix_dp_set_lane3_pre_emphasis(struct analogix_dp_device *dp, - u32 level); -void analogix_dp_set_lane0_link_training(struct analogix_dp_device *dp, - u32 training_lane); -void analogix_dp_set_lane1_link_training(struct analogix_dp_device *dp, - u32 training_lane); -void analogix_dp_set_lane2_link_training(struct analogix_dp_device *dp, - u32 training_lane); -void analogix_dp_set_lane3_link_training(struct analogix_dp_device *dp, - u32 training_lane); -u32 analogix_dp_get_lane0_link_training(struct analogix_dp_device *dp); -u32 analogix_dp_get_lane1_link_training(struct analogix_dp_device *dp); -u32 analogix_dp_get_lane2_link_training(struct analogix_dp_device *dp); -u32 analogix_dp_get_lane3_link_training(struct analogix_dp_device *dp); +void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp); +u32 analogix_dp_get_lane_link_training(struct analogix_dp_device *dp, u8 lane); void analogix_dp_reset_macro(struct analogix_dp_device *dp); void analogix_dp_init_video(struct analogix_dp_device *dp); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 6a4f20fccf84..3afc73c858c4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -217,15 +217,13 @@ void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp) writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK); } -enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp) +int analogix_dp_wait_pll_locked(struct analogix_dp_device *dp) { - u32 reg; + u32 val; - reg = readl(dp->reg_base + ANALOGIX_DP_DEBUG_CTL); - if (reg & PLL_LOCK) - return PLL_LOCKED; - else - return PLL_UNLOCKED; + return readl_poll_timeout(dp->reg_base + ANALOGIX_DP_DEBUG_CTL, val, + val & PLL_LOCK, 120, + 120 * DP_TIMEOUT_LOOP_COUNT); } void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable) @@ -356,7 +354,6 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, int analogix_dp_init_analog_func(struct analogix_dp_device *dp) { u32 reg; - int timeout_loop = 0; analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); @@ -368,18 +365,7 @@ int analogix_dp_init_analog_func(struct analogix_dp_device *dp) writel(reg, dp->reg_base + ANALOGIX_DP_DEBUG_CTL); /* Power up PLL */ - if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - analogix_dp_set_pll_power_down(dp, 0); - - while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { - dev_err(dp->dev, "failed to get pll lock status\n"); - return -ETIMEDOUT; - } - usleep_range(10, 20); - } - } + analogix_dp_set_pll_power_down(dp, 0); /* Enable Serdes FIFO function and Link symbol clock domain module */ reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2); @@ -557,6 +543,20 @@ void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count) *count = reg; } +void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp) +{ + u8 lane; + + for (lane = 0; lane < dp->link_train.lane_count; lane++) + writel(dp->link_train.training_lane[lane], + dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane); +} + +u32 analogix_dp_get_lane_link_training(struct analogix_dp_device *dp, u8 lane) +{ + return readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane); +} + void analogix_dp_enable_enhanced_mode(struct analogix_dp_device *dp, bool enable) { @@ -606,106 +606,6 @@ void analogix_dp_set_training_pattern(struct analogix_dp_device *dp, } } -void analogix_dp_set_lane0_pre_emphasis(struct analogix_dp_device *dp, - u32 level) -{ - u32 reg; - - reg = readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); - reg &= ~PRE_EMPHASIS_SET_MASK; - reg |= level << PRE_EMPHASIS_SET_SHIFT; - writel(reg, dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); -} - -void analogix_dp_set_lane1_pre_emphasis(struct analogix_dp_device *dp, - u32 level) -{ - u32 reg; - - reg = readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); - reg &= ~PRE_EMPHASIS_SET_MASK; - reg |= level << PRE_EMPHASIS_SET_SHIFT; - writel(reg, dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); -} - -void analogix_dp_set_lane2_pre_emphasis(struct analogix_dp_device *dp, - u32 level) -{ - u32 reg; - - reg = readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); - reg &= ~PRE_EMPHASIS_SET_MASK; - reg |= level << PRE_EMPHASIS_SET_SHIFT; - writel(reg, dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); -} - -void analogix_dp_set_lane3_pre_emphasis(struct analogix_dp_device *dp, - u32 level) -{ - u32 reg; - - reg = readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); - reg &= ~PRE_EMPHASIS_SET_MASK; - reg |= level << PRE_EMPHASIS_SET_SHIFT; - writel(reg, dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); -} - -void analogix_dp_set_lane0_link_training(struct analogix_dp_device *dp, - u32 training_lane) -{ - u32 reg; - - reg = training_lane; - writel(reg, dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); -} - -void analogix_dp_set_lane1_link_training(struct analogix_dp_device *dp, - u32 training_lane) -{ - u32 reg; - - reg = training_lane; - writel(reg, dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); -} - -void analogix_dp_set_lane2_link_training(struct analogix_dp_device *dp, - u32 training_lane) -{ - u32 reg; - - reg = training_lane; - writel(reg, dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); -} - -void analogix_dp_set_lane3_link_training(struct analogix_dp_device *dp, - u32 training_lane) -{ - u32 reg; - - reg = training_lane; - writel(reg, dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); -} - -u32 analogix_dp_get_lane0_link_training(struct analogix_dp_device *dp) -{ - return readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); -} - -u32 analogix_dp_get_lane1_link_training(struct analogix_dp_device *dp) -{ - return readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); -} - -u32 analogix_dp_get_lane2_link_training(struct analogix_dp_device *dp) -{ - return readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); -} - -u32 analogix_dp_get_lane3_link_training(struct analogix_dp_device *dp) -{ - return readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); -} - void analogix_dp_reset_macro(struct analogix_dp_device *dp) { u32 reg; @@ -1024,10 +924,8 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg) { u32 reg; - u32 status_reg; u8 *buffer = msg->buffer; unsigned int i; - int num_transferred = 0; int ret; /* Buffer size of AUX CH is 16 bytes */ @@ -1079,7 +977,6 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, reg = buffer[i]; writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + 4 * i); - num_transferred++; } } @@ -1113,12 +1010,17 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, /* Clear interrupt source for AUX CH access error */ reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); - status_reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA); - if ((reg & AUX_ERR) || (status_reg & AUX_STATUS_MASK)) { + if ((reg & AUX_ERR)) { + u32 aux_status = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA) & + AUX_STATUS_MASK; + writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA); + if (aux_status == AUX_STATUS_TIMEOUT_ERROR) + return -ETIMEDOUT; + dev_warn(dp->dev, "AUX CH error happened: %#x (%d)\n", - status_reg & AUX_STATUS_MASK, !!(reg & AUX_ERR)); + aux_status, !!(reg & AUX_ERR)); goto aux_error; } @@ -1127,7 +1029,6 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + 4 * i); buffer[i] = (unsigned char)reg; - num_transferred++; } } @@ -1144,7 +1045,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ) msg->reply = DP_AUX_NATIVE_REPLY_ACK; - return num_transferred > 0 ? num_transferred : -EBUSY; + return msg->size; aux_error: /* if aux err happen, reset aux */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index e284ee8da58b..12735139046c 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h @@ -361,6 +361,15 @@ /* ANALOGIX_DP_AUX_CH_STA */ #define AUX_BUSY (0x1 << 4) #define AUX_STATUS_MASK (0xf << 0) +#define AUX_STATUS_OK (0x0 << 0) +#define AUX_STATUS_NACK_ERROR (0x1 << 0) +#define AUX_STATUS_TIMEOUT_ERROR (0x2 << 0) +#define AUX_STATUS_UNKNOWN_ERROR (0x3 << 0) +#define AUX_STATUS_MUCH_DEFER_ERROR (0x4 << 0) +#define AUX_STATUS_TX_SHORT_ERROR (0x5 << 0) +#define AUX_STATUS_RX_SHORT_ERROR (0x6 << 0) +#define AUX_STATUS_NACK_WITHOUT_M_ERROR (0x7 << 0) +#define AUX_STATUS_I2C_NACK_ERROR (0x8 << 0) /* ANALOGIX_DP_AUX_CH_DEFER_CTL */ #define DEFER_CTRL_EN (0x1 << 7) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 29d91493b101..4be34d5c7a3b 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -464,9 +464,11 @@ static int anx7625_odfc_config(struct anx7625_data *ctx, */ static int anx7625_set_k_value(struct anx7625_data *ctx) { - struct edid *edid = (struct edid *)ctx->slimport_edid_p.edid_raw_data; + struct drm_edid_product_id id; - if (edid->mfg_id[0] == IVO_MID0 && edid->mfg_id[1] == IVO_MID1) + drm_edid_get_product_id(ctx->cached_drm_edid, &id); + + if (be16_to_cpu(id.manufacturer_name) == IVO_MID) return anx7625_reg_write(ctx, ctx->i2c.rx_p1_client, MIPI_DIGITAL_ADJ_1, 0x3B); @@ -1526,7 +1528,8 @@ static int anx7625_wait_hpd_asserted(struct drm_dp_aux *aux, static void anx7625_remove_edid(struct anx7625_data *ctx) { - ctx->slimport_edid_p.edid_block_num = -1; + drm_edid_free(ctx->cached_drm_edid); + ctx->cached_drm_edid = NULL; } static void anx7625_dp_adjust_swing(struct anx7625_data *ctx) @@ -1644,25 +1647,15 @@ static int anx7625_get_swing_setting(struct device *dev, { int num_regs; - if (of_get_property(dev->of_node, - "analogix,lane0-swing", &num_regs)) { - if (num_regs > DP_TX_SWING_REG_CNT) - num_regs = DP_TX_SWING_REG_CNT; - + num_regs = of_property_read_variable_u8_array(dev->of_node, "analogix,lane0-swing", + pdata->lane0_reg_data, 1, DP_TX_SWING_REG_CNT); + if (num_regs > 0) pdata->dp_lane0_swing_reg_cnt = num_regs; - of_property_read_u8_array(dev->of_node, "analogix,lane0-swing", - pdata->lane0_reg_data, num_regs); - } - - if (of_get_property(dev->of_node, - "analogix,lane1-swing", &num_regs)) { - if (num_regs > DP_TX_SWING_REG_CNT) - num_regs = DP_TX_SWING_REG_CNT; + num_regs = of_property_read_variable_u8_array(dev->of_node, "analogix,lane1-swing", + pdata->lane1_reg_data, 1, DP_TX_SWING_REG_CNT); + if (num_regs > 0) pdata->dp_lane1_swing_reg_cnt = num_regs; - of_property_read_u8_array(dev->of_node, "analogix,lane1-swing", - pdata->lane1_reg_data, num_regs); - } return 0; } @@ -1784,40 +1777,35 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, return ret; } -static struct edid *anx7625_get_edid(struct anx7625_data *ctx) +static const struct drm_edid *anx7625_edid_read(struct anx7625_data *ctx) { struct device *dev = ctx->dev; - struct s_edid_data *p_edid = &ctx->slimport_edid_p; + u8 *edid_buf; int edid_num; - u8 *edid; - edid = kmalloc(FOUR_BLOCK_SIZE, GFP_KERNEL); - if (!edid) { - DRM_DEV_ERROR(dev, "Fail to allocate buffer\n"); - return NULL; - } + if (ctx->cached_drm_edid) + goto out; - if (ctx->slimport_edid_p.edid_block_num > 0) { - memcpy(edid, ctx->slimport_edid_p.edid_raw_data, - FOUR_BLOCK_SIZE); - return (struct edid *)edid; - } + edid_buf = kmalloc(FOUR_BLOCK_SIZE, GFP_KERNEL); + if (!edid_buf) + return NULL; pm_runtime_get_sync(dev); _anx7625_hpd_polling(ctx, 5000 * 100); - edid_num = sp_tx_edid_read(ctx, p_edid->edid_raw_data); + edid_num = sp_tx_edid_read(ctx, edid_buf); pm_runtime_put_sync(dev); if (edid_num < 1) { DRM_DEV_ERROR(dev, "Fail to read EDID: %d\n", edid_num); - kfree(edid); + kfree(edid_buf); return NULL; } - p_edid->edid_block_num = edid_num; + ctx->cached_drm_edid = drm_edid_alloc(edid_buf, FOUR_BLOCK_SIZE); + kfree(edid_buf); - memcpy(edid, ctx->slimport_edid_p.edid_raw_data, FOUR_BLOCK_SIZE); - return (struct edid *)edid; +out: + return drm_edid_dup(ctx->cached_drm_edid); } static enum drm_connector_status anx7625_sink_detect(struct anx7625_data *ctx) @@ -1964,7 +1952,8 @@ static void anx7625_audio_shutdown(struct device *dev, void *data) } static int anx7625_hdmi_i2s_get_dai_id(struct snd_soc_component *component, - struct device_node *endpoint) + struct device_node *endpoint, + void *data) { struct of_endpoint of_ep; int ret; @@ -2014,8 +2003,10 @@ static int anx7625_audio_get_eld(struct device *dev, void *data, memset(buf, 0, len); } else { dev_dbg(dev, "audio copy eld\n"); + mutex_lock(&ctx->connector->eld_mutex); memcpy(buf, ctx->connector->eld, min(sizeof(ctx->connector->eld), len)); + mutex_unlock(&ctx->connector->eld_mutex); } return 0; @@ -2076,10 +2067,8 @@ static int anx7625_setup_dsi_device(struct anx7625_data *ctx) }; host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node); - if (!host) { - DRM_DEV_ERROR(dev, "fail to find dsi host.\n"); - return -EPROBE_DEFER; - } + if (!host) + return dev_err_probe(dev, -EPROBE_DEFER, "fail to find dsi host.\n"); dsi = devm_mipi_dsi_device_register_full(dev, host, &info); if (IS_ERR(dsi)) { @@ -2151,49 +2140,6 @@ static void hdcp_check_work_func(struct work_struct *work) drm_modeset_unlock(&drm_dev->mode_config.connection_mutex); } -static int anx7625_connector_atomic_check(struct anx7625_data *ctx, - struct drm_connector_state *state) -{ - struct device *dev = ctx->dev; - int cp; - - dev_dbg(dev, "hdcp state check\n"); - cp = state->content_protection; - - if (cp == ctx->hdcp_cp) - return 0; - - if (cp == DRM_MODE_CONTENT_PROTECTION_DESIRED) { - if (ctx->dp_en) { - dev_dbg(dev, "enable HDCP\n"); - anx7625_hdcp_enable(ctx); - - queue_delayed_work(ctx->hdcp_workqueue, - &ctx->hdcp_work, - msecs_to_jiffies(2000)); - } - } - - if (cp == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { - if (ctx->hdcp_cp != DRM_MODE_CONTENT_PROTECTION_ENABLED) { - dev_err(dev, "current CP is not ENABLED\n"); - return -EINVAL; - } - anx7625_hdcp_disable(ctx); - ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; - drm_hdcp_update_content_protection(ctx->connector, - ctx->hdcp_cp); - dev_dbg(dev, "update CP to UNDESIRE\n"); - } - - if (cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) { - dev_err(dev, "Userspace illegal set to PROTECTION ENABLE\n"); - return -EINVAL; - } - - return 0; -} - static int anx7625_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -2205,11 +2151,6 @@ static int anx7625_bridge_attach(struct drm_bridge *bridge, if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) return -EINVAL; - if (!bridge->encoder) { - DRM_DEV_ERROR(dev, "Parent encoder object not found"); - return -ENODEV; - } - ctx->aux.drm_dev = bridge->dev; err = drm_dp_aux_register(&ctx->aux); if (err) { @@ -2435,7 +2376,7 @@ static int anx7625_bridge_atomic_check(struct drm_bridge *bridge, anx7625_bridge_mode_fixup(bridge, &crtc_state->mode, &crtc_state->adjusted_mode); - return anx7625_connector_atomic_check(ctx, conn_state); + return 0; } static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge, @@ -2444,14 +2385,10 @@ static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge, struct anx7625_data *ctx = bridge_to_anx7625(bridge); struct device *dev = ctx->dev; struct drm_connector *connector; + struct drm_connector_state *conn_state; dev_dbg(dev, "drm atomic enable\n"); - if (!bridge->encoder) { - dev_err(dev, "Parent encoder object not found"); - return; - } - connector = drm_atomic_get_new_connector_for_encoder(state->base.state, bridge->encoder); if (!connector) @@ -2463,6 +2400,22 @@ static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge, _anx7625_hpd_polling(ctx, 5000 * 100); anx7625_dp_start(ctx); + + conn_state = drm_atomic_get_new_connector_state(state->base.state, connector); + + if (WARN_ON(!conn_state)) + return; + + if (conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { + if (ctx->dp_en) { + dev_dbg(dev, "enable HDCP\n"); + anx7625_hdcp_enable(ctx); + + queue_delayed_work(ctx->hdcp_workqueue, + &ctx->hdcp_work, + msecs_to_jiffies(2000)); + } + } } static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, @@ -2473,6 +2426,17 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, dev_dbg(dev, "drm atomic disable\n"); + flush_workqueue(ctx->hdcp_workqueue); + + if (ctx->connector && + ctx->hdcp_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) { + anx7625_hdcp_disable(ctx); + ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_DESIRED; + drm_hdcp_update_content_protection(ctx->connector, + ctx->hdcp_cp); + dev_dbg(dev, "update CP to DESIRE\n"); + } + ctx->connector = NULL; anx7625_dp_stop(ctx); @@ -2481,26 +2445,33 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, mutex_unlock(&ctx->aux_lock); } +static void +anx7625_audio_update_connector_status(struct anx7625_data *ctx, + enum drm_connector_status status); + static enum drm_connector_status anx7625_bridge_detect(struct drm_bridge *bridge) { struct anx7625_data *ctx = bridge_to_anx7625(bridge); struct device *dev = ctx->dev; + enum drm_connector_status status; DRM_DEV_DEBUG_DRIVER(dev, "drm bridge detect\n"); - return anx7625_sink_detect(ctx); + status = anx7625_sink_detect(ctx); + anx7625_audio_update_connector_status(ctx, status); + return status; } -static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge, - struct drm_connector *connector) +static const struct drm_edid *anx7625_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { struct anx7625_data *ctx = bridge_to_anx7625(bridge); struct device *dev = ctx->dev; DRM_DEV_DEBUG_DRIVER(dev, "drm bridge get edid\n"); - return anx7625_get_edid(ctx); + return anx7625_edid_read(ctx); } static const struct drm_bridge_funcs anx7625_bridge_funcs = { @@ -2515,7 +2486,7 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = { .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_reset = drm_atomic_helper_bridge_reset, .detect = anx7625_bridge_detect, - .get_edid = anx7625_bridge_get_edid, + .edid_read = anx7625_bridge_edid_read, }; static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx, @@ -2568,6 +2539,8 @@ static int __maybe_unused anx7625_runtime_pm_suspend(struct device *dev) mutex_lock(&ctx->lock); anx7625_stop_dp_work(ctx); + if (!ctx->pdata.panel_bridge) + anx7625_remove_edid(ctx); anx7625_power_standby(ctx); mutex_unlock(&ctx->lock); @@ -2810,7 +2783,7 @@ static void anx7625_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id anx7625_id[] = { - {"anx7625", 0}, + { "anx7625" }, {} }; diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index 39ed35d33836..eb5580f1ab2f 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -286,8 +286,7 @@ #define MIPI_LANE_CTRL_10 0x0F #define MIPI_DIGITAL_ADJ_1 0x1B -#define IVO_MID0 0x26 -#define IVO_MID1 0xCF +#define IVO_MID 0x26CF #define MIPI_PLL_M_NUM_23_16 0x1E #define MIPI_PLL_M_NUM_15_8 0x1F @@ -417,11 +416,6 @@ enum audio_wd_len { #define EDID_TRY_CNT 3 #define SUPPORT_PIXEL_CLOCK 300000 -struct s_edid_data { - int edid_block_num; - u8 edid_raw_data[FOUR_BLOCK_SIZE]; -}; - /***************** Display End *****************/ #define MAX_LANES_SUPPORT 4 @@ -466,7 +460,7 @@ struct anx7625_data { struct anx7625_i2c_client i2c; struct i2c_client *last_client; struct timer_list hdcp_timer; - struct s_edid_data slimport_edid_p; + const struct drm_edid *cached_drm_edid; struct device *codec_dev; hdmi_codec_plugged_cb plugged_cb; struct work_struct work; |