summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/bridge/analogix
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/bridge/analogix')
-rw-r--r--drivers/gpu/drm/bridge/analogix/Kconfig2
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-anx6345.c63
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c61
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c541
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.h32
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c209
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h9
-rw-r--r--drivers/gpu/drm/bridge/analogix/anx7625.c208
-rw-r--r--drivers/gpu/drm/bridge/analogix/anx7625.h10
9 files changed, 399 insertions, 736 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..f3fe47b12edc 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;
@@ -143,35 +143,7 @@ static int anx6345_dp_link_training(struct anx6345 *anx6345)
if (err)
return err;
- /*
- * Power up the sink (DP_SET_POWER register is only available on DPCD
- * v1.1 and later).
- */
- if (anx6345->dpcd[DP_DPCD_REV] >= 0x11) {
- err = drm_dp_dpcd_readb(&anx6345->aux, DP_SET_POWER, &dpcd[0]);
- if (err < 0) {
- DRM_ERROR("Failed to read DP_SET_POWER register: %d\n",
- err);
- return err;
- }
-
- dpcd[0] &= ~DP_SET_POWER_MASK;
- dpcd[0] |= DP_SET_POWER_D0;
-
- err = drm_dp_dpcd_writeb(&anx6345->aux, DP_SET_POWER, dpcd[0]);
- if (err < 0) {
- DRM_ERROR("Failed to power up DisplayPort link: %d\n",
- err);
- return err;
- }
-
- /*
- * According to the DP 1.1 specification, a "Sink Device must
- * exit the power saving state within 1 ms" (Section 2.5.3.1,
- * Table 5-52, "Sink Control Field" (register 0x600).
- */
- usleep_range(1000, 2000);
- }
+ drm_dp_link_power_up(&anx6345->aux, anx6345->dpcd[DP_DPCD_REV]);
/* Possibly enable downspread on the sink */
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
@@ -458,7 +430,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 +442,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;
@@ -518,6 +489,7 @@ static const struct drm_connector_funcs anx6345_connector_funcs = {
};
static int anx6345_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
@@ -528,11 +500,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;
@@ -559,7 +526,7 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge,
anx6345->connector.polled = DRM_CONNECTOR_POLL_HPD;
err = drm_connector_attach_encoder(&anx6345->connector,
- bridge->encoder);
+ encoder);
if (err) {
DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
goto connector_cleanup;
@@ -697,9 +664,10 @@ static int anx6345_i2c_probe(struct i2c_client *client)
struct device *dev;
int i, err;
- anx6345 = devm_kzalloc(&client->dev, sizeof(*anx6345), GFP_KERNEL);
- if (!anx6345)
- return -ENOMEM;
+ anx6345 = devm_drm_bridge_alloc(&client->dev, struct anx6345, bridge,
+ &anx6345_bridge_funcs);
+ if (IS_ERR(anx6345))
+ return PTR_ERR(anx6345);
mutex_init(&anx6345->lock);
@@ -771,7 +739,6 @@ static int anx6345_i2c_probe(struct i2c_client *client)
/* Look for supported chip ID */
anx6345_poweron(anx6345);
if (anx6345_get_chip_id(anx6345)) {
- anx6345->bridge.funcs = &anx6345_bridge_funcs;
drm_bridge_add(&anx6345->bridge);
return 0;
@@ -793,13 +760,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..a83020d6576f 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;
@@ -656,35 +656,7 @@ static int anx78xx_dp_link_training(struct anx78xx *anx78xx)
if (err)
return err;
- /*
- * Power up the sink (DP_SET_POWER register is only available on DPCD
- * v1.1 and later).
- */
- if (anx78xx->dpcd[DP_DPCD_REV] >= 0x11) {
- err = drm_dp_dpcd_readb(&anx78xx->aux, DP_SET_POWER, &dpcd[0]);
- if (err < 0) {
- DRM_ERROR("Failed to read DP_SET_POWER register: %d\n",
- err);
- return err;
- }
-
- dpcd[0] &= ~DP_SET_POWER_MASK;
- dpcd[0] |= DP_SET_POWER_D0;
-
- err = drm_dp_dpcd_writeb(&anx78xx->aux, DP_SET_POWER, dpcd[0]);
- if (err < 0) {
- DRM_ERROR("Failed to power up DisplayPort link: %d\n",
- err);
- return err;
- }
-
- /*
- * According to the DP 1.1 specification, a "Sink Device must
- * exit the power saving state within 1 ms" (Section 2.5.3.1,
- * Table 5-52, "Sink Control Field" (register 0x600).
- */
- usleep_range(1000, 2000);
- }
+ drm_dp_link_power_up(&anx78xx->aux, anx78xx->dpcd[DP_DPCD_REV]);
/* Possibly enable downspread on the sink */
err = regmap_write(anx78xx->map[I2C_IDX_TX_P0],
@@ -830,8 +802,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 +813,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);
@@ -887,6 +860,7 @@ static const struct drm_connector_funcs anx78xx_connector_funcs = {
};
static int anx78xx_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct anx78xx *anx78xx = bridge_to_anx78xx(bridge);
@@ -897,11 +871,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;
@@ -928,7 +897,7 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge,
anx78xx->connector.polled = DRM_CONNECTOR_POLL_HPD;
err = drm_connector_attach_encoder(&anx78xx->connector,
- bridge->encoder);
+ encoder);
if (err) {
DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
goto connector_cleanup;
@@ -1091,8 +1060,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 +1332,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..a761941bc3c2 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)
@@ -942,10 +838,7 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
int ret;
/* Keep the panel disabled while we configure video */
- if (dp->plat_data->panel) {
- if (drm_panel_disable(dp->plat_data->panel))
- DRM_ERROR("failed to disable the panel\n");
- }
+ drm_panel_disable(dp->plat_data->panel);
ret = analogix_dp_train_link(dp);
if (ret) {
@@ -967,13 +860,7 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
}
/* Safe to enable the panel now */
- if (dp->plat_data->panel) {
- ret = drm_panel_enable(dp->plat_data->panel);
- if (ret) {
- DRM_ERROR("failed to enable the panel\n");
- return ret;
- }
- }
+ drm_panel_enable(dp->plat_data->panel);
/* Check whether panel supports fast training */
ret = analogix_dp_fast_link_train_detection(dp);
@@ -1059,78 +946,23 @@ static int analogix_dp_disable_psr(struct analogix_dp_device *dp)
return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
}
-/*
- * This function is a bit of a catch-all for panel preparation, hopefully
- * simplifying the logic of functions that need to prepare/unprepare the panel
- * below.
- *
- * If @prepare is true, this function will prepare the panel. Conversely, if it
- * is false, the panel will be unprepared.
- *
- * If @is_modeset_prepare is true, the function will disregard the current state
- * of the panel and either prepare/unprepare the panel based on @prepare. Once
- * it finishes, it will update dp->panel_is_modeset to reflect the current state
- * of the panel.
- */
-static int analogix_dp_prepare_panel(struct analogix_dp_device *dp,
- bool prepare, bool is_modeset_prepare)
-{
- int ret = 0;
-
- if (!dp->plat_data->panel)
- return 0;
-
- mutex_lock(&dp->panel_lock);
-
- /*
- * Exit early if this is a temporary prepare/unprepare and we're already
- * modeset (since we neither want to prepare twice or unprepare early).
- */
- if (dp->panel_is_modeset && !is_modeset_prepare)
- goto out;
-
- if (prepare)
- ret = drm_panel_prepare(dp->plat_data->panel);
- else
- ret = drm_panel_unprepare(dp->plat_data->panel);
-
- if (ret)
- goto out;
-
- if (is_modeset_prepare)
- dp->panel_is_modeset = prepare;
-
-out:
- mutex_unlock(&dp->panel_lock);
- return ret;
-}
-
static int analogix_dp_get_modes(struct drm_connector *connector)
{
struct analogix_dp_device *dp = to_dp(connector);
- struct edid *edid;
- int ret, num_modes = 0;
+ const struct drm_edid *drm_edid;
+ int num_modes = 0;
if (dp->plat_data->panel) {
num_modes += drm_panel_get_modes(dp->plat_data->panel, connector);
} else {
- ret = analogix_dp_prepare_panel(dp, true, false);
- if (ret) {
- DRM_ERROR("Failed to prepare panel (%d)\n", ret);
- return 0;
- }
+ drm_edid = drm_edid_read_ddc(connector, &dp->aux.ddc);
- 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_connector_update(&dp->connector, drm_edid);
- ret = analogix_dp_prepare_panel(dp, false, false);
- if (ret)
- DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
+ if (drm_edid) {
+ num_modes += drm_edid_connector_add_modes(&dp->connector);
+ drm_edid_free(drm_edid);
+ }
}
if (dp->plat_data->get_modes)
@@ -1185,24 +1017,13 @@ analogix_dp_detect(struct drm_connector *connector, bool force)
{
struct analogix_dp_device *dp = to_dp(connector);
enum drm_connector_status status = connector_status_disconnected;
- int ret;
if (dp->plat_data->panel)
return connector_status_connected;
- ret = analogix_dp_prepare_panel(dp, true, false);
- if (ret) {
- DRM_ERROR("Failed to prepare panel (%d)\n", ret);
- return connector_status_disconnected;
- }
-
if (!analogix_dp_detect_hpd(dp))
status = connector_status_connected;
- ret = analogix_dp_prepare_panel(dp, false, false);
- if (ret)
- DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
-
return status;
}
@@ -1216,10 +1037,10 @@ static const struct drm_connector_funcs analogix_dp_connector_funcs = {
};
static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct analogix_dp_device *dp = bridge->driver_private;
- struct drm_encoder *encoder = dp->encoder;
struct drm_connector *connector = NULL;
int ret = 0;
@@ -1228,11 +1049,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;
@@ -1305,15 +1121,12 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp,
return conn_state->crtc;
}
-static void
-analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *old_state)
{
- struct drm_atomic_state *old_state = old_bridge_state->base.state;
struct analogix_dp_device *dp = bridge->driver_private;
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
- int ret;
crtc = analogix_dp_get_new_crtc(dp, old_state);
if (!crtc)
@@ -1324,9 +1137,7 @@ analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
if (old_crtc_state && old_crtc_state->self_refresh_active)
return;
- ret = analogix_dp_prepare_panel(dp, true, true);
- if (ret)
- DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+ drm_panel_prepare(dp->plat_data->panel);
}
static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
@@ -1335,20 +1146,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,28 +1167,18 @@ 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;
}
-static void
-analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *old_state)
{
- struct drm_atomic_state *old_state = old_bridge_state->base.state;
struct analogix_dp_device *dp = bridge->driver_private;
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
@@ -1427,44 +1217,28 @@ analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
{
struct analogix_dp_device *dp = bridge->driver_private;
- int ret;
if (dp->dpms_mode != DRM_MODE_DPMS_ON)
return;
- if (dp->plat_data->panel) {
- if (drm_panel_disable(dp->plat_data->panel)) {
- DRM_ERROR("failed to disable the panel\n");
- return;
- }
- }
+ drm_panel_disable(dp->plat_data->panel);
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);
- ret = analogix_dp_prepare_panel(dp, false, true);
- if (ret)
- DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+ drm_panel_unprepare(dp->plat_data->panel);
dp->fast_train_enable = false;
dp->psr_supported = false;
dp->dpms_mode = DRM_MODE_DPMS_OFF;
}
-static void
-analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *old_state)
{
- struct drm_atomic_state *old_state = old_bridge_state->base.state;
struct analogix_dp_device *dp = bridge->driver_private;
struct drm_crtc *old_crtc, *new_crtc;
struct drm_crtc_state *old_crtc_state = NULL;
@@ -1500,11 +1274,9 @@ out:
analogix_dp_bridge_disable(bridge);
}
-static void
-analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_bridge_state)
+static void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *old_state)
{
- struct drm_atomic_state *old_state = old_bridge_state->base.state;
struct analogix_dp_device *dp = bridge->driver_private;
struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state;
@@ -1646,6 +1418,10 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
video_info->max_link_rate = 0x0A;
video_info->max_lane_count = 0x04;
break;
+ case RK3588_EDP:
+ video_info->max_link_rate = 0x14;
+ video_info->max_lane_count = 0x04;
+ break;
case EXYNOS_DP:
/*
* NOTE: those property parseing code is used for
@@ -1681,12 +1457,31 @@ out:
return ret;
}
+static int analogix_dpaux_wait_hpd_asserted(struct drm_dp_aux *aux, unsigned long wait_us)
+{
+ struct analogix_dp_device *dp = to_dp(aux);
+ int val;
+ int ret;
+
+ if (dp->force_hpd)
+ return 0;
+
+ pm_runtime_get_sync(dp->dev);
+
+ ret = readx_poll_timeout(analogix_dp_get_plug_in_status, dp, val, !val,
+ wait_us / 100, wait_us);
+
+ pm_runtime_mark_last_busy(dp->dev);
+ pm_runtime_put_autosuspend(dp->dev);
+
+ return ret;
+}
+
struct analogix_dp_device *
analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
{
struct platform_device *pdev = to_platform_device(dev);
struct analogix_dp_device *dp;
- struct resource *res;
unsigned int irq_flags;
int ret;
@@ -1702,9 +1497,6 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
dp->dev = &pdev->dev;
dp->dpms_mode = DRM_MODE_DPMS_OFF;
- mutex_init(&dp->panel_lock);
- dp->panel_is_modeset = false;
-
/*
* platform dp driver need containor_of the plat_data to get
* the driver private data, so we need to store the point of
@@ -1738,11 +1530,7 @@ 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);
+ dp->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dp->reg_base)) {
ret = PTR_ERR(dp->reg_base);
goto err_disable_clk;
@@ -1771,10 +1559,10 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
* that we can get the current state of the GPIO.
*/
dp->irq = gpiod_to_irq(dp->hpd_gpiod);
- irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+ irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN;
} else {
dp->irq = platform_get_irq(pdev, 0);
- irq_flags = 0;
+ irq_flags = IRQF_NO_AUTOEN;
}
if (dp->irq == -ENXIO) {
@@ -1791,7 +1579,18 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
dev_err(&pdev->dev, "failed to request irq\n");
goto err_disable_clk;
}
- disable_irq(dp->irq);
+
+ dp->aux.name = "DP-AUX";
+ dp->aux.transfer = analogix_dpaux_transfer;
+ dp->aux.wait_hpd_asserted = analogix_dpaux_wait_hpd_asserted;
+ dp->aux.dev = dp->dev;
+ drm_dp_aux_init(&dp->aux);
+
+ pm_runtime_use_autosuspend(dp->dev);
+ pm_runtime_set_autosuspend_delay(dp->dev, 100);
+ ret = devm_pm_runtime_enable(dp->dev);
+ if (ret)
+ goto err_disable_clk;
return dp;
@@ -1801,6 +1600,41 @@ 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_set_mode(dp->phy, PHY_MODE_DP);
+ 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,30 +1642,23 @@ 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;
- 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)
+ if (ret) {
+ DRM_ERROR("failed to register AUX (%d)\n", ret);
return ret;
-
- pm_runtime_use_autosuspend(dp->dev);
- pm_runtime_set_autosuspend_delay(dp->dev, 100);
- pm_runtime_enable(dp->dev);
+ }
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);
return ret;
@@ -1843,46 +1670,12 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
analogix_dp_bridge_disable(dp->bridge);
dp->connector.funcs->destroy(&dp->connector);
- if (dp->plat_data->panel) {
- if (drm_panel_unprepare(dp->plat_data->panel))
- DRM_ERROR("failed to turnoff the panel\n");
- }
+ drm_panel_unprepare(dp->plat_data->panel);
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;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(analogix_dp_resume);
-#endif
-
int analogix_dp_start_crc(struct drm_connector *connector)
{
struct analogix_dp_device *dp = to_dp(connector);
@@ -1905,6 +1698,20 @@ int analogix_dp_stop_crc(struct drm_connector *connector)
}
EXPORT_SYMBOL_GPL(analogix_dp_stop_crc);
+struct analogix_dp_plat_data *analogix_dp_aux_to_plat_data(struct drm_dp_aux *aux)
+{
+ struct analogix_dp_device *dp = to_dp(aux);
+
+ return dp->plat_data;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_aux_to_plat_data);
+
+struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp)
+{
+ return &dp->aux;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_get_aux);
+
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
MODULE_DESCRIPTION("Analogix DP Core Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 433f2d7efa0c..2b54120ba4a3 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
@@ -174,9 +169,6 @@ struct analogix_dp_device {
bool fast_train_enable;
bool psr_supported;
- struct mutex panel_lock;
- bool panel_is_modeset;
-
struct analogix_dp_plat_data *plat_data;
};
@@ -191,7 +183,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 +205,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..38fd8d5014d2 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -11,6 +11,7 @@
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/iopoll.h>
+#include <linux/phy/phy.h>
#include <drm/bridge/analogix_dp.h>
@@ -217,15 +218,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 +355,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 +366,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);
@@ -527,10 +514,24 @@ void analogix_dp_enable_sw_function(struct analogix_dp_device *dp)
void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype)
{
u32 reg;
+ int ret;
reg = bwtype;
if ((bwtype == DP_LINK_BW_2_7) || (bwtype == DP_LINK_BW_1_62))
writel(reg, dp->reg_base + ANALOGIX_DP_LINK_BW_SET);
+
+ if (dp->phy) {
+ union phy_configure_opts phy_cfg = {0};
+
+ phy_cfg.dp.link_rate =
+ drm_dp_bw_code_to_link_rate(dp->link_train.link_rate) / 100;
+ phy_cfg.dp.set_rate = true;
+ ret = phy_configure(dp->phy, &phy_cfg);
+ if (ret && ret != -EOPNOTSUPP) {
+ dev_err(dp->dev, "%s: phy_configure() failed: %d\n", __func__, ret);
+ return;
+ }
+ }
}
void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype)
@@ -544,9 +545,22 @@ void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype)
void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count)
{
u32 reg;
+ int ret;
reg = count;
writel(reg, dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET);
+
+ if (dp->phy) {
+ union phy_configure_opts phy_cfg = {0};
+
+ phy_cfg.dp.lanes = dp->link_train.lane_count;
+ phy_cfg.dp.set_lanes = true;
+ ret = phy_configure(dp->phy, &phy_cfg);
+ if (ret && ret != -EOPNOTSUPP) {
+ dev_err(dp->dev, "%s: phy_configure() failed: %d\n", __func__, ret);
+ return;
+ }
+ }
}
void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count)
@@ -557,6 +571,44 @@ 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;
+ int ret;
+
+ 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);
+
+ if (dp->phy) {
+ union phy_configure_opts phy_cfg = {0};
+
+ for (lane = 0; lane < dp->link_train.lane_count; lane++) {
+ u8 training_lane = dp->link_train.training_lane[lane];
+ u8 vs, pe;
+
+ vs = (training_lane & DP_TRAIN_VOLTAGE_SWING_MASK) >>
+ DP_TRAIN_VOLTAGE_SWING_SHIFT;
+ pe = (training_lane & DP_TRAIN_PRE_EMPHASIS_MASK) >>
+ DP_TRAIN_PRE_EMPHASIS_SHIFT;
+ phy_cfg.dp.voltage[lane] = vs;
+ phy_cfg.dp.pre[lane] = pe;
+ }
+
+ phy_cfg.dp.set_voltages = true;
+ ret = phy_configure(dp->phy, &phy_cfg);
+ if (ret && ret != -EOPNOTSUPP) {
+ dev_err(dp->dev, "%s: phy_configure() failed: %d\n", __func__, ret);
+ return;
+ }
+ }
+}
+
+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 +658,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 +976,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 +1029,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 +1062,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 +1081,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 +1097,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 9d96d28d6fe8..8a9079c2ed5c 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);
@@ -1255,10 +1257,10 @@ static void anx7625_power_on(struct anx7625_data *ctx)
usleep_range(11000, 12000);
/* Power on pin enable */
- gpiod_set_value(ctx->pdata.gpio_p_on, 1);
+ gpiod_set_value_cansleep(ctx->pdata.gpio_p_on, 1);
usleep_range(10000, 11000);
/* Power reset pin enable */
- gpiod_set_value(ctx->pdata.gpio_reset, 1);
+ gpiod_set_value_cansleep(ctx->pdata.gpio_reset, 1);
usleep_range(10000, 11000);
DRM_DEV_DEBUG_DRIVER(dev, "power on !\n");
@@ -1278,9 +1280,9 @@ static void anx7625_power_standby(struct anx7625_data *ctx)
return;
}
- gpiod_set_value(ctx->pdata.gpio_reset, 0);
+ gpiod_set_value_cansleep(ctx->pdata.gpio_reset, 0);
usleep_range(1000, 1100);
- gpiod_set_value(ctx->pdata.gpio_p_on, 0);
+ gpiod_set_value_cansleep(ctx->pdata.gpio_p_on, 0);
usleep_range(1000, 1100);
ret = regulator_bulk_disable(ARRAY_SIZE(ctx->pdata.supplies),
@@ -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;
}
@@ -1787,27 +1780,32 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux,
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;
- if (ctx->slimport_edid_p.edid_block_num > 0)
+ if (ctx->cached_drm_edid)
goto out;
+ 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_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);
out:
- return drm_edid_alloc(ctx->slimport_edid_p.edid_raw_data,
- FOUR_BLOCK_SIZE);
+ return drm_edid_dup(ctx->cached_drm_edid);
}
static enum drm_connector_status anx7625_sink_detect(struct anx7625_data *ctx)
@@ -1816,9 +1814,6 @@ static enum drm_connector_status anx7625_sink_detect(struct anx7625_data *ctx)
DRM_DEV_DEBUG_DRIVER(dev, "sink detect\n");
- if (ctx->pdata.panel_bridge)
- return connector_status_connected;
-
return ctx->hpd_status ? connector_status_connected :
connector_status_disconnected;
}
@@ -1954,7 +1949,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;
@@ -2004,8 +2000,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;
@@ -2066,10 +2064,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)) {
@@ -2141,50 +2137,8 @@ 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,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
@@ -2195,11 +2149,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) {
@@ -2208,7 +2157,7 @@ static int anx7625_bridge_attach(struct drm_bridge *bridge,
}
if (ctx->pdata.panel_bridge) {
- err = drm_bridge_attach(bridge->encoder,
+ err = drm_bridge_attach(encoder,
ctx->pdata.panel_bridge,
&ctx->bridge, flags);
if (err)
@@ -2425,24 +2374,20 @@ 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,
- struct drm_bridge_state *state)
+ struct drm_atomic_state *state)
{
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,
+ connector = drm_atomic_get_new_connector_for_encoder(state,
bridge->encoder);
if (!connector)
return;
@@ -2453,16 +2398,43 @@ 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, 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,
- struct drm_bridge_state *old)
+ struct drm_atomic_state *state)
{
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
struct device *dev = ctx->dev;
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);
@@ -2471,15 +2443,22 @@ 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 const struct drm_edid *anx7625_bridge_edid_read(struct drm_bridge *bridge,
@@ -2493,6 +2472,22 @@ static const struct drm_edid *anx7625_bridge_edid_read(struct drm_bridge *bridge
return anx7625_edid_read(ctx);
}
+static void anx7625_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+ struct anx7625_data *ctx = bridge_to_anx7625(bridge);
+ struct device *dev = ctx->dev;
+
+ pm_runtime_get_sync(dev);
+}
+
+static void anx7625_bridge_hpd_disable(struct drm_bridge *bridge)
+{
+ struct anx7625_data *ctx = bridge_to_anx7625(bridge);
+ struct device *dev = ctx->dev;
+
+ pm_runtime_put_sync(dev);
+}
+
static const struct drm_bridge_funcs anx7625_bridge_funcs = {
.attach = anx7625_bridge_attach,
.detach = anx7625_bridge_detach,
@@ -2506,6 +2501,8 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = {
.atomic_reset = drm_atomic_helper_bridge_reset,
.detect = anx7625_bridge_detect,
.edid_read = anx7625_bridge_edid_read,
+ .hpd_enable = anx7625_bridge_hpd_enable,
+ .hpd_disable = anx7625_bridge_hpd_disable,
};
static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx,
@@ -2558,6 +2555,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);
@@ -2585,12 +2584,6 @@ static const struct dev_pm_ops anx7625_pm_ops = {
anx7625_runtime_pm_resume, NULL)
};
-static void anx7625_runtime_disable(void *data)
-{
- pm_runtime_dont_use_autosuspend(data);
- pm_runtime_disable(data);
-}
-
static int anx7625_link_bridge(struct drm_dp_aux *aux)
{
struct anx7625_data *platform = container_of(aux, struct anx7625_data, aux);
@@ -2607,9 +2600,8 @@ static int anx7625_link_bridge(struct drm_dp_aux *aux)
platform->bridge.of_node = dev->of_node;
if (!anx7625_of_panel_on_aux_bus(dev))
platform->bridge.ops |= DRM_BRIDGE_OP_EDID;
- if (!platform->pdata.panel_bridge)
- platform->bridge.ops |= DRM_BRIDGE_OP_HPD |
- DRM_BRIDGE_OP_DETECT;
+ if (!platform->pdata.panel_bridge || !anx7625_of_panel_on_aux_bus(dev))
+ platform->bridge.ops |= DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_DETECT;
platform->bridge.type = platform->pdata.panel_bridge ?
DRM_MODE_CONNECTOR_eDP :
DRM_MODE_CONNECTOR_DisplayPort;
@@ -2724,11 +2716,10 @@ static int anx7625_i2c_probe(struct i2c_client *client)
goto free_wq;
}
- pm_runtime_enable(dev);
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_use_autosuspend(dev);
pm_suspend_ignore_children(dev, true);
- ret = devm_add_action_or_reset(dev, anx7625_runtime_disable, dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
goto free_wq;
@@ -2788,7 +2779,6 @@ static void anx7625_i2c_remove(struct i2c_client *client)
if (platform->hdcp_workqueue) {
cancel_delayed_work(&platform->hdcp_work);
- flush_workqueue(platform->hdcp_workqueue);
destroy_workqueue(platform->hdcp_workqueue);
}
@@ -2800,7 +2790,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;