drm/rockchip: dw-dp: support dynamic control power domain

Change-Id: I8692e967d2873a10385bec5d6998ad73cf8f4fa7
Signed-off-by: Zhang Yubing <yubing.zhang@rock-chips.com>
This commit is contained in:
Zhang Yubing
2024-06-19 19:32:37 +08:00
parent 010bf50479
commit b41a87b16c

View File

@@ -449,6 +449,7 @@ struct dw_dp {
struct work_struct hpd_work;
struct gpio_desc *hpd_gpio;
bool force_hpd;
bool dynamic_pd_ctrl;
struct dw_dp_hotplug hotplug;
struct mutex irq_lock;
@@ -1126,7 +1127,7 @@ static bool dw_dp_bandwidth_ok(struct dw_dp *dp,
return true;
}
static bool dw_dp_detect(struct dw_dp *dp)
static bool dw_dp_detect_no_power(struct dw_dp *dp)
{
u32 value;
int ret;
@@ -1145,6 +1146,20 @@ static bool dw_dp_detect(struct dw_dp *dp)
return FIELD_GET(HPD_STATE, value) == SOURCE_STATE_PLUG;
}
static bool dw_dp_detect(struct dw_dp *dp)
{
bool detected;
pm_runtime_get_sync(dp->dev);
detected = dw_dp_detect_no_power(dp);
pm_runtime_mark_last_busy(dp->dev);
pm_runtime_put_autosuspend(dp->dev);
return detected;
}
static enum drm_connector_status
dw_dp_connector_detect(struct drm_connector *connector, bool force)
{
@@ -2840,7 +2855,7 @@ static irqreturn_t dw_dp_hpd_irq_handler(int irq, void *arg)
static void dw_dp_hpd_init(struct dw_dp *dp)
{
dp->hotplug.status = dw_dp_detect(dp);
dp->hotplug.status = dw_dp_detect_no_power(dp);
if (dp->hpd_gpio || dp->force_hpd) {
regmap_update_bits(dp->regmap, DPTX_CCTL, FORCE_HPD,
@@ -3077,19 +3092,23 @@ static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux,
if (WARN_ON(msg->size > 16))
return -E2BIG;
pm_runtime_get_sync(dp->dev);
phy_set_mode_ext(dp->phy, PHY_MODE_DP, 0);
switch (msg->request & ~DP_AUX_I2C_MOT) {
case DP_AUX_NATIVE_WRITE:
case DP_AUX_I2C_WRITE:
case DP_AUX_I2C_WRITE_STATUS_UPDATE:
ret = dw_dp_aux_write_data(dp, msg->buffer, msg->size);
if (ret < 0)
return ret;
goto out;
break;
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
break;
default:
return -EINVAL;
ret = -EINVAL;
goto out;
}
if (msg->size > 0)
@@ -3103,12 +3122,15 @@ static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux,
status = wait_for_completion_timeout(&dp->complete, timeout);
if (!status) {
dev_dbg(dp->dev, "timeout waiting for AUX reply\n");
return -ETIMEDOUT;
ret = -ETIMEDOUT;
goto out;
}
regmap_read(dp->regmap, DPTX_AUX_STATUS, &value);
if (value & AUX_TIMEOUT)
return -ETIMEDOUT;
if (value & AUX_TIMEOUT) {
ret = -ETIMEDOUT;
goto out;
}
msg->reply = FIELD_GET(AUX_STATUS, value);
@@ -3116,15 +3138,21 @@ static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux,
if (msg->request & DP_AUX_I2C_READ) {
size_t count = FIELD_GET(AUX_BYTES_READ, value) - 1;
if (count != msg->size)
return -EBUSY;
if (count != msg->size) {
ret = -EBUSY;
goto out;
}
ret = dw_dp_aux_read_data(dp, msg->buffer, count);
if (ret < 0)
return ret;
goto out;
}
}
out:
pm_runtime_mark_last_busy(dp->dev);
pm_runtime_put_autosuspend(dp->dev);
return ret;
}
@@ -3688,6 +3716,8 @@ static void dw_dp_mst_encoder_atomic_enable(struct drm_encoder *encoder,
int ret;
bool first_mst_stream;
pm_runtime_get_sync(dp->dev);
drm_mode_copy(m, &crtc_state->adjusted_mode);
first_mst_stream = dp->active_mst_links == 0;
@@ -3846,6 +3876,8 @@ static void dw_dp_mst_encoder_atomic_disable(struct drm_encoder *encoder,
dw_dp_reset(dp);
}
pm_runtime_mark_last_busy(dp->dev);
pm_runtime_put_autosuspend(dp->dev);
}
static int dw_dp_mst_encoder_atomic_check(struct drm_encoder *encoder,
@@ -4302,6 +4334,8 @@ static void dw_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
struct drm_crtc_state *crtc_state = bridge->encoder->crtc->state;
struct drm_display_mode *m = &video->mode;
pm_runtime_get_sync(dp->dev);
drm_mode_copy(m, &crtc_state->adjusted_mode);
if (dp->split_mode || dp->dual_connector_split)
@@ -4319,6 +4353,9 @@ dw_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
if (dp->panel)
drm_panel_unprepare(dp->panel);
pm_runtime_mark_last_busy(dp->dev);
pm_runtime_put_autosuspend(dp->dev);
}
static bool dw_dp_needs_link_retrain(struct dw_dp *dp)
@@ -5081,6 +5118,7 @@ static int dw_dp_audio_hw_params(struct device *dev, void *data,
clk_prepare_enable(audio->spdif_clk);
clk_prepare_enable(audio->i2s_clk);
pm_runtime_get_sync(dp->dev);
regmap_update_bits(dp->regmap, DPTX_AUD_CONFIG1_N(audio->id),
AUDIO_DATA_IN_EN | NUM_CHANNELS | AUDIO_DATA_WIDTH |
AUDIO_INF_SELECT,
@@ -5088,6 +5126,8 @@ static int dw_dp_audio_hw_params(struct device *dev, void *data,
FIELD_PREP(NUM_CHANNELS, num_channels) |
FIELD_PREP(AUDIO_DATA_WIDTH, params->sample_width) |
FIELD_PREP(AUDIO_INF_SELECT, audio_inf_select));
pm_runtime_mark_last_busy(dp->dev);
pm_runtime_put_autosuspend(dp->dev);
/* Wait for inf switch */
usleep_range(20, 40);
@@ -5148,7 +5188,9 @@ static int dw_dp_audio_startup(struct device *dev, void *data)
{
struct dw_dp *dp = dev_get_drvdata(dev);
struct dw_dp_audio *audio = (struct dw_dp_audio *)data;
int ret = 0;
pm_runtime_get_sync(dp->dev);
regmap_update_bits(dp->regmap, DPTX_SDP_VERTICAL_CTRL_N(audio->id),
EN_AUDIO_STREAM_SDP | EN_AUDIO_TIMESTAMP_SDP,
FIELD_PREP(EN_AUDIO_STREAM_SDP, 1) |
@@ -5156,8 +5198,11 @@ static int dw_dp_audio_startup(struct device *dev, void *data)
regmap_update_bits(dp->regmap, DPTX_SDP_HORIZONTAL_CTRL_N(audio->id),
EN_AUDIO_STREAM_SDP,
FIELD_PREP(EN_AUDIO_STREAM_SDP, 1));
ret = dw_dp_audio_infoframe_send(dp, audio);
pm_runtime_mark_last_busy(dp->dev);
pm_runtime_put_autosuspend(dp->dev);
return dw_dp_audio_infoframe_send(dp, audio);
return ret;
}
static void dw_dp_audio_shutdown(struct device *dev, void *data)
@@ -5165,8 +5210,11 @@ static void dw_dp_audio_shutdown(struct device *dev, void *data)
struct dw_dp *dp = dev_get_drvdata(dev);
struct dw_dp_audio *audio = (struct dw_dp_audio *)data;
pm_runtime_get_sync(dp->dev);
regmap_update_bits(dp->regmap, DPTX_AUD_CONFIG1_N(audio->id), AUDIO_DATA_IN_EN,
FIELD_PREP(AUDIO_DATA_IN_EN, 0));
pm_runtime_mark_last_busy(dp->dev);
pm_runtime_put_autosuspend(dp->dev);
if (audio->format == AFMT_SPDIF)
clk_disable_unprepare(audio->spdif_clk);
@@ -5448,8 +5496,11 @@ static int dw_dp_bind(struct device *dev, struct device *master, void *data)
dp->aux.transfer = dw_dp_sim_aux_transfer;
}
pm_runtime_use_autosuspend(dp->dev);
pm_runtime_set_autosuspend_delay(dp->dev, 500);
pm_runtime_enable(dp->dev);
pm_runtime_get_sync(dp->dev);
if (!dp->dynamic_pd_ctrl)
pm_runtime_get_sync(dp->dev);
enable_irq(dp->irq);
if (dp->hpd_gpio)
@@ -5472,7 +5523,9 @@ static void dw_dp_unbind(struct device *dev, struct device *master, void *data)
disable_irq(dp->hpd_irq);
disable_irq(dp->irq);
pm_runtime_put(dp->dev);
if (!dp->dynamic_pd_ctrl)
pm_runtime_put(dp->dev);
pm_runtime_dont_use_autosuspend(dp->dev);
pm_runtime_disable(dp->dev);
drm_encoder_cleanup(&dp->encoder);
@@ -5718,6 +5771,9 @@ static int dw_dp_probe(struct platform_device *pdev)
if (ret)
return ret;
if (dp->hpd_gpio || dp->force_hpd)
dp->dynamic_pd_ctrl = true;
dp->irq = platform_get_irq(pdev, 0);
if (dp->irq < 0)
return dp->irq;