Hi Andrzej,
This is the rebased version of v6 series. This patchset includes cleanups,
improvements, and bug fixes for Rockchip DRM driver and PSR support.
This version is a RESEND of v6 with few changes. The following two
patches are not included and will be send in a separate patchset for
further discussion.
- [PATCH v6 24/30] drm/rockchip: Disable PSR on input events
- [PATCH v6 25/30] drm/rockchip: Cancel PSR enable work before changing
the state
The following patch was remove as is not needed.
- [PATCH v6 28/30] drm/rockchip: Disable PSR from reboot notifier
I think that the other patches have the required tags and are ready to
be merged.
Regards,
Enric
Changes in v6:
- Removed the following patches as are already applied.
[PATCH v5 01/36] drm/bridge: analogix_dp: detect Sink PSR state after
configuring the PSR
[PATCH v5 02/36] drm/rockchip: Remove analogix psr worker
[PATCH v5 03/36] drm/bridge: analogix_dp: Don't change psr while
bridge is disabled
- Explain in the commit message why we need to increase
the delay in the timeout loop in
[PATCH v5 07/36] drm/bridge: analogix_dp: Move enable video into
config_video()
- Add Reviewed-by: Archit Taneja <[email protected]> for the
drm/bridge parts
- Add Reviewed-by: Heiko Stuebner <[email protected]> for
[PATCH v5 19/36] drm/rockchip: Restore psr->state when enable/disable
psr failed
Changes in v5:
- Removed the following patches as are already applied.
[PATCH v4 01/38] drm/bridge: analogix_dp: set psr activate/deactivate
when enable/disable bridge
[PATCH v4 02/38] drm/rockchip: Don't use atomic constructs for psr
- Add Mareks tested-tag and including the missing people.
- [PATCH v4 15/38] move analogix_dp_set_analog_power_down() before
phy_power_off() to fix Exynos issue.
Changes in v4:
- Rebased all on top of drm-misc-next
- Removed the following patches as are already applied.
[PATCH v3 01/43] drm/rockchip: Get rid of unnecessary struct fields
[PATCH v3 02/43] drm/rockchip: support prime import sg table
[PATCH v3 03/43] drm/rockchip: Respect page offset for PRIME mmap
calls
- Removed the following patches as now are part of another patchset
[PATCH v3 05/43] drm/bridge: analogix_dp: Don't power bridge in
analogix_dp_bind
[PATCH v3 33/43] drm/panel: simple: Change mode for Sharp lq123p1jx31
Changes in v3:
- Addressed some of the comments from Sean on the v2
Changes in v2:
- A few patches have been replaced by newer and cleaner versions from
the ChromeOS kernel gerrit, especially about disallowing PSR for the
whole atomic commit.
Douglas Anderson (4):
drm/bridge: analogix_dp: Reorder plat_data->power_off to happen sooner
drm/bridge: analogix_dp: Properly log AUX CH errors
drm/bridge: analogix_dp: Properly disable aux chan retries on rockchip
drm/bridge: analogix_dp: Split the platform-specific poweron in two
parts
Lin Huang (6):
drm/bridge: analogix_dp: Move enable video into config_video()
drm/bridge: analogix_dp: Check AUX_EN status when doing AUX transfer
drm/bridge: analogix_dp: Ensure edp is disabled when shutting down the
panel
drm/bridge: analogix_dp: Extend hpd check time to 100ms
drm/bridge: analogix_dp: Check dpcd write/read status
drm/bridge: analogix_dp: Reset aux channel if an error occurred
Mark Yao (1):
drm/rockchip: pre dither down when output bpc is 8bit
Tomasz Figa (5):
drm/rockchip: analogix_dp: Do not call Analogix code before bind
drm/rockchip: psr: Avoid redundant calls to .set() callback
drm/rockchip: psr: Sanitize semantics of allow/inhibit API
drm/rockchip: Disallow PSR for the whole atomic commit
drm/rockchip: psr: Remove flush by CRTC
zain wang (11):
drm/bridge: analogix_dp: Don't use fast link training when panel just
powered up
drm/bridge: analogix_dp: Retry bridge enable when it failed
drm/bridge: analogix_dp: Wait for HPD signal before configuring link
drm/bridge: analogix_dp: Set PD_INC_BG first when powering up edp phy
drm/bridge: analogix_dp: Fix incorrect usage of enhanced mode
drm/bridge: analogix_dp: Fix AUX_PD bit for Rockchip
drm/rockchip: Restore psr->state when enable/disable psr failed
drm/bridge: analogix_dp: Don't use ANALOGIX_DP_PLL_CTL to control pll
drm/bridge: analogix_dp: Fix timeout of video streamclk config
drm/bridge: analogix_dp: Fix incorrect operations with register
ANALOGIX_DP_FUNC_EN_1
drm/bridge: analogix_dp: Move fast link training detect to set_bridge
.../drm/bridge/analogix/analogix_dp_core.c | 331 +++++++++++++-----
.../drm/bridge/analogix/analogix_dp_core.h | 5 +-
.../gpu/drm/bridge/analogix/analogix_dp_reg.c | 236 +++++++------
.../gpu/drm/bridge/analogix/analogix_dp_reg.h | 7 +
drivers/gpu/drm/exynos/exynos_dp.c | 2 +-
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 37 +-
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 61 +++-
drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 158 ++++-----
drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 7 +-
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 13 +-
drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 1 +
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 +
include/drm/bridge/analogix_dp.h | 3 +-
14 files changed, 559 insertions(+), 304 deletions(-)
--
2.17.0
From: zain wang <[email protected]>
Panel would reset its setting when it powers down. It would forget the last
succeeded link training setting. So we can't use the last successful link
training setting to do fast link training. Let's reset fast_train_enable in
analogix_dp_bridge_disable();
Cc: Stéphane Marchesin <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 9 +++++----
drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 2 +-
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 05a0ca4af057..85dbb1ca9886 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -579,14 +579,14 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
if (retval != 1) {
dev_err(dp->dev, "failed to read downspread %d\n",
retval);
- dp->fast_train_support = false;
+ dp->fast_train_enable = false;
} else {
- dp->fast_train_support =
+ dp->fast_train_enable =
(spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING) ?
true : false;
}
dev_dbg(dp->dev, "fast link training %s\n",
- dp->fast_train_support ? "supported" : "unsupported");
+ dp->fast_train_enable ? "supported" : "unsupported");
/* set enhanced mode if available */
analogix_dp_set_enhanced_mode(dp);
@@ -793,7 +793,7 @@ static int analogix_dp_fast_link_train(struct analogix_dp_device *dp)
static int analogix_dp_train_link(struct analogix_dp_device *dp)
{
- if (dp->fast_train_support)
+ if (dp->fast_train_enable)
return analogix_dp_fast_link_train(dp);
return analogix_dp_full_link_train(dp, dp->video_info.max_lane_count,
@@ -1197,6 +1197,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
DRM_ERROR("failed to setup the panel ret = %d\n", ret);
dp->psr_enable = false;
+ dp->fast_train_enable = false;
dp->dpms_mode = DRM_MODE_DPMS_OFF;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 6a96ef7e6934..403ff853464b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -173,7 +173,7 @@ struct analogix_dp_device {
int hpd_gpio;
bool force_hpd;
bool psr_enable;
- bool fast_train_support;
+ bool fast_train_enable;
struct mutex panel_lock;
bool panel_is_modeset;
--
2.17.0
From: Lin Huang <[email protected]>
When panel is shut down, we should make sure edp can be disabled to avoid
undefined behavior.
Cc: Stéphane Marchesin <[email protected]>
Signed-off-by: Lin Huang <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 3269deec739d..5957e2338071 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1160,6 +1160,12 @@ 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)
dp->plat_data->power_on(dp->plat_data);
@@ -1191,6 +1197,8 @@ static int analogix_dp_set_bridge(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);
+out_dp_clk_pre:
pm_runtime_put_sync(dp->dev);
return ret;
@@ -1233,11 +1241,14 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
}
disable_irq(dp->irq);
+ analogix_dp_set_analog_power_down(dp, POWER_ALL, 1);
phy_power_off(dp->phy);
if (dp->plat_data->power_off)
dp->plat_data->power_off(dp->plat_data);
+ clk_disable_unprepare(dp->clock);
+
pm_runtime_put_sync(dp->dev);
ret = analogix_dp_prepare_panel(dp, false, true);
--
2.17.0
From: zain wang <[email protected]>
Register ANALOGIX_DP_FUNC_EN_1(offset 0x18), Rockchip is different to
Exynos:
on Exynos edp phy,
BIT 7 MASTER_VID_FUNC_EN_N
BIT 6 reserved
BIT 5 SLAVE_VID_FUNC_EN_N
on Rockchip edp phy,
BIT 7 reserved
BIT 6 RK_VID_CAP_FUNC_EN_N
BIT 5 RK_VID_FIFO_FUNC_EN_N
So, we should do some private operations to Rockchip.
Cc: Tomasz Figa <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
.../gpu/drm/bridge/analogix/analogix_dp_reg.c | 19 ++++++++++++++-----
.../gpu/drm/bridge/analogix/analogix_dp_reg.h | 2 ++
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 02ab1aaa9993..4eae206ec31b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -126,9 +126,14 @@ void analogix_dp_reset(struct analogix_dp_device *dp)
analogix_dp_stop_video(dp);
analogix_dp_enable_video_mute(dp, 0);
- reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
- AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
- HDCP_FUNC_EN_N | SW_FUNC_EN_N;
+ if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
+ reg = RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N |
+ SW_FUNC_EN_N;
+ else
+ reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
+ AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
+ HDCP_FUNC_EN_N | SW_FUNC_EN_N;
+
writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
@@ -971,8 +976,12 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp)
u32 reg;
reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
- reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);
- reg |= MASTER_VID_FUNC_EN_N;
+ if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {
+ reg &= ~(RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N);
+ } else {
+ reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);
+ reg |= MASTER_VID_FUNC_EN_N;
+ }
writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index b633a4a5082a..0cf27c731727 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -127,7 +127,9 @@
/* ANALOGIX_DP_FUNC_EN_1 */
#define MASTER_VID_FUNC_EN_N (0x1 << 7)
+#define RK_VID_CAP_FUNC_EN_N (0x1 << 6)
#define SLAVE_VID_FUNC_EN_N (0x1 << 5)
+#define RK_VID_FIFO_FUNC_EN_N (0x1 << 5)
#define AUD_FIFO_FUNC_EN_N (0x1 << 4)
#define AUD_FUNC_EN_N (0x1 << 3)
#define HDCP_FUNC_EN_N (0x1 << 2)
--
2.17.0
From: Tomasz Figa <[email protected]>
The first time after we call rockchip_drm_do_flush() after
rockchip_drm_psr_register(), we go from PSR_DISABLE to PSR_FLUSH. The
difference between PSR_DISABLE and PSR_FLUSH is whether or not we have a
delayed work pending - PSR is off in either state. However
psr_set_state() only catches the transition from PSR_FLUSH to
PSR_DISABLE (which never happens), while going from PSR_DISABLE to
PSR_FLUSH triggers a call to psr->set() to disable PSR while it's
already disabled. This triggers the eDP PHY power-on sequence without
being shut down first and this seems to occasionally leave the encoder
unable to later enable PSR. Let's just simplify the state machine and
simply consider PSR_DISABLE and PSR_FLUSH the same state.
Signed-off-by: Tomasz Figa <[email protected]>
Signed-off-by: Kristian H. Kristensen <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
---
drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 80 +++++++--------------
1 file changed, 24 insertions(+), 56 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
index 9376f4396b6b..1a6157ffecec 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
@@ -20,19 +20,13 @@
#define PSR_FLUSH_TIMEOUT_MS 100
-enum psr_state {
- PSR_FLUSH,
- PSR_ENABLE,
- PSR_DISABLE,
-};
-
struct psr_drv {
struct list_head list;
struct drm_encoder *encoder;
struct mutex lock;
bool active;
- enum psr_state state;
+ bool enabled;
struct delayed_work flush_work;
@@ -73,52 +67,22 @@ static struct psr_drv *find_psr_by_encoder(struct drm_encoder *encoder)
return psr;
}
-static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state)
+static int psr_set_state_locked(struct psr_drv *psr, bool enable)
{
- /*
- * Allowed finite state machine:
- *
- * PSR_ENABLE < = = = = = > PSR_FLUSH
- * | ^ |
- * | | |
- * v | |
- * PSR_DISABLE < - - - - - - - - -
- */
- if (state == psr->state || !psr->active)
- return;
-
- /* Already disabled in flush, change the state, but not the hardware */
- if (state == PSR_DISABLE && psr->state == PSR_FLUSH) {
- psr->state = state;
- return;
- }
+ int ret;
- /* Actually commit the state change to hardware */
- switch (state) {
- case PSR_ENABLE:
- if (psr->set(psr->encoder, true))
- return;
- break;
-
- case PSR_DISABLE:
- case PSR_FLUSH:
- if (psr->set(psr->encoder, false))
- return;
- break;
-
- default:
- pr_err("%s: Unknown state %d\n", __func__, state);
- return;
- }
+ if (!psr->active)
+ return -EINVAL;
- psr->state = state;
-}
+ if (enable == psr->enabled)
+ return 0;
-static void psr_set_state(struct psr_drv *psr, enum psr_state state)
-{
- mutex_lock(&psr->lock);
- psr_set_state_locked(psr, state);
- mutex_unlock(&psr->lock);
+ ret = psr->set(psr->encoder, enable);
+ if (ret)
+ return ret;
+
+ psr->enabled = enable;
+ return 0;
}
static void psr_flush_handler(struct work_struct *work)
@@ -126,10 +90,8 @@ static void psr_flush_handler(struct work_struct *work)
struct psr_drv *psr = container_of(to_delayed_work(work),
struct psr_drv, flush_work);
- /* If the state has changed since we initiated the flush, do nothing */
mutex_lock(&psr->lock);
- if (psr->state == PSR_FLUSH)
- psr_set_state_locked(psr, PSR_ENABLE);
+ psr_set_state_locked(psr, true);
mutex_unlock(&psr->lock);
}
@@ -171,6 +133,7 @@ int rockchip_drm_psr_deactivate(struct drm_encoder *encoder)
mutex_lock(&psr->lock);
psr->active = false;
+ psr->enabled = false;
mutex_unlock(&psr->lock);
cancel_delayed_work_sync(&psr->flush_work);
@@ -180,8 +143,13 @@ EXPORT_SYMBOL(rockchip_drm_psr_deactivate);
static void rockchip_drm_do_flush(struct psr_drv *psr)
{
- psr_set_state(psr, PSR_FLUSH);
- mod_delayed_work(system_wq, &psr->flush_work, PSR_FLUSH_TIMEOUT_MS);
+ cancel_delayed_work_sync(&psr->flush_work);
+
+ mutex_lock(&psr->lock);
+ if (!psr_set_state_locked(psr, false))
+ mod_delayed_work(system_wq, &psr->flush_work,
+ PSR_FLUSH_TIMEOUT_MS);
+ mutex_unlock(&psr->lock);
}
/**
@@ -250,8 +218,8 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder,
INIT_DELAYED_WORK(&psr->flush_work, psr_flush_handler);
mutex_init(&psr->lock);
- psr->active = true;
- psr->state = PSR_DISABLE;
+ psr->active = false;
+ psr->enabled = false;
psr->encoder = encoder;
psr->set = psr_set;
--
2.17.0
From: zain wang <[email protected]>
There is no register named ANALOGIX_DP_PLL_CTL in Rockchip edp phy reg
list. We should use BIT_4 in ANALOGIX_DP_PD to control the pll power
instead of ANALOGIX_DP_PLL_CTL.
Cc: Douglas Anderson <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
.../gpu/drm/bridge/analogix/analogix_dp_reg.c | 20 +++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 7b7fd227e1f9..02ab1aaa9993 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -230,16 +230,20 @@ enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp)
void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable)
{
u32 reg;
+ u32 mask = DP_PLL_PD;
+ u32 pd_addr = ANALOGIX_DP_PLL_CTL;
- if (enable) {
- reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL);
- reg |= DP_PLL_PD;
- writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL);
- } else {
- reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL);
- reg &= ~DP_PLL_PD;
- writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL);
+ if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {
+ pd_addr = ANALOGIX_DP_PD;
+ mask = RK_PLL_PD;
}
+
+ reg = readl(dp->reg_base + pd_addr);
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ writel(reg, dp->reg_base + pd_addr);
}
void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
--
2.17.0
From: Tomasz Figa <[email protected]>
Currently PSR flush is triggered from CRTC's .atomic_begin() callback,
which is executed after modeset disables and enables and before plane
updates are committed. Since PSR flush and re-enable can be triggered
asynchronously by external sources (input event, delayed work), it can
race with hardware programming done in the aforementioned stages.
This patch blocks the PSR completely before hardware programming part
begins and unblock after it ends. This relies on reference counted PSR
disable introduced with previous patch.
Cc: Kristian H. Kristensen <[email protected]>
Signed-off-by: Tomasz Figa <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
---
drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 61 ++++++++++++++++++++-
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 7 ---
2 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index e266539e04e5..d4f4118b482d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -167,8 +167,67 @@ rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
return ERR_PTR(ret);
}
+static void
+rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ struct drm_encoder *encoder;
+ u32 encoder_mask = 0;
+ int i;
+
+ for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
+ encoder_mask |= crtc_state->encoder_mask;
+ encoder_mask |= crtc->state->encoder_mask;
+ }
+
+ drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
+ rockchip_drm_psr_inhibit_get(encoder);
+}
+
+static void
+rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ struct drm_encoder *encoder;
+ u32 encoder_mask = 0;
+ int i;
+
+ for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
+ encoder_mask |= crtc_state->encoder_mask;
+ encoder_mask |= crtc->state->encoder_mask;
+ }
+
+ drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
+ rockchip_drm_psr_inhibit_put(encoder);
+}
+
+static void
+rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = old_state->dev;
+
+ rockchip_drm_psr_inhibit_get_state(old_state);
+
+ drm_atomic_helper_commit_modeset_disables(dev, old_state);
+
+ drm_atomic_helper_commit_modeset_enables(dev, old_state);
+
+ drm_atomic_helper_commit_planes(dev, old_state,
+ DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+ rockchip_drm_psr_inhibit_put_state(old_state);
+
+ drm_atomic_helper_commit_hw_done(old_state);
+
+ drm_atomic_helper_wait_for_vblanks(dev, old_state);
+
+ drm_atomic_helper_cleanup_planes(dev, old_state);
+}
+
static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
- .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+ .atomic_commit_tail = rockchip_atomic_helper_commit_tail_rpm,
};
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 00f7f3441cf6..f14a10ca4792 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1029,16 +1029,9 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
}
}
-static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
- struct drm_crtc_state *old_crtc_state)
-{
- rockchip_drm_psr_flush(crtc);
-}
-
static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
.mode_fixup = vop_crtc_mode_fixup,
.atomic_flush = vop_crtc_atomic_flush,
- .atomic_begin = vop_crtc_atomic_begin,
.atomic_enable = vop_crtc_atomic_enable,
.atomic_disable = vop_crtc_atomic_disable,
};
--
2.17.0
From: Tomasz Figa <[email protected]>
It is not used anymore after last changes and it was not even correct to
begin with as it assumed a 1:1 relation between a CRTC and encoder,
while in fact a CRTC can be attached to multiple encoders.
Signed-off-by: Tomasz Figa <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
---
drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 35 ---------------------
drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 1 -
2 files changed, 36 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
index 74f6a6a887dd..79d00d861a31 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
@@ -33,23 +33,6 @@ struct psr_drv {
int (*set)(struct drm_encoder *encoder, bool enable);
};
-static struct psr_drv *find_psr_by_crtc(struct drm_crtc *crtc)
-{
- struct rockchip_drm_private *drm_drv = crtc->dev->dev_private;
- struct psr_drv *psr;
-
- mutex_lock(&drm_drv->psr_list_lock);
- list_for_each_entry(psr, &drm_drv->psr_list, list) {
- if (psr->encoder->crtc == crtc)
- goto out;
- }
- psr = ERR_PTR(-ENODEV);
-
-out:
- mutex_unlock(&drm_drv->psr_list_lock);
- return psr;
-}
-
static struct psr_drv *find_psr_by_encoder(struct drm_encoder *encoder)
{
struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
@@ -166,24 +149,6 @@ static void rockchip_drm_do_flush(struct psr_drv *psr)
mutex_unlock(&psr->lock);
}
-/**
- * rockchip_drm_psr_flush - flush a single pipe
- * @crtc: CRTC of the pipe to flush
- *
- * Returns:
- * 0 on success, -errno on fail
- */
-int rockchip_drm_psr_flush(struct drm_crtc *crtc)
-{
- struct psr_drv *psr = find_psr_by_crtc(crtc);
- if (IS_ERR(psr))
- return PTR_ERR(psr);
-
- rockchip_drm_do_flush(psr);
- return 0;
-}
-EXPORT_SYMBOL(rockchip_drm_psr_flush);
-
/**
* rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
* @dev: drm device
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
index 40e026c14168..860c62494496 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
@@ -16,7 +16,6 @@
#define __ROCKCHIP_DRM_PSR___
void rockchip_drm_psr_flush_all(struct drm_device *dev);
-int rockchip_drm_psr_flush(struct drm_crtc *crtc);
int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder);
int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder);
--
2.17.0
From: Douglas Anderson <[email protected]>
The comments in analogix_dp_init_aux() claim that we're disabling aux
channel retries, but then right below it for Rockchip it sets them to
3. If we actually need 3 retries for Rockchip then we could adjust
the comment, but it seems more likely that we want the same retry
behavior across all platforms.
Cc: Stéphane Marchesin <[email protected]>
Cc: 征增 王 <[email protected]>
Signed-off-by: Douglas Anderson <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 58e8a28e99aa..a5f2763d72e4 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -481,15 +481,16 @@ void analogix_dp_init_aux(struct analogix_dp_device *dp)
analogix_dp_reset_aux(dp);
- /* Disable AUX transaction H/W retry */
+ /* AUX_BIT_PERIOD_EXPECTED_DELAY doesn't apply to Rockchip IP */
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
- reg = AUX_BIT_PERIOD_EXPECTED_DELAY(0) |
- AUX_HW_RETRY_COUNT_SEL(3) |
- AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
+ reg = 0;
else
- reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) |
- AUX_HW_RETRY_COUNT_SEL(0) |
- AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
+ reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3);
+
+ /* Disable AUX transaction H/W retry */
+ reg |= AUX_HW_RETRY_COUNT_SEL(0) |
+ AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
+
writel(reg, dp->reg_base + ANALOGIX_DP_AUX_HW_RETRY_CTL);
/* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
--
2.17.0
From: Tomasz Figa <[email protected]>
Currently both rockchip_drm_psr_activate() and _deactivate() only set the
boolean "active" flag without actually making sure that hardware state
complies with it.
Since we are going to extend the usage of this API to properly lock PSR
for the duration of atomic commits, we change the semantics in following
way:
- a counter is used to track the number of inhibit requests,
- PSR is actually disabled in hardware on first inhibit request,
- PSR enable work is scheduled on last allow request.
The above allows using the API as a way to deterministically synchronize
PSR state changes with other DRM events, i.e. atomic commits and cursor
updates. As a nice side effect, the naming is sorted out and we have
"inhibit" for stopping the software logic and "enable" for hardware
state.
Signed-off-by: Tomasz Figa <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
---
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 4 +-
drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 55 ++++++++++++++-----
drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 4 +-
3 files changed, 46 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 6d45d62466b3..080f05352195 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -134,7 +134,7 @@ static int rockchip_dp_poweron_end(struct analogix_dp_plat_data *plat_data)
{
struct rockchip_dp_device *dp = to_dp(plat_data);
- return rockchip_drm_psr_activate(&dp->encoder);
+ return rockchip_drm_psr_inhibit_put(&dp->encoder);
}
static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
@@ -142,7 +142,7 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
struct rockchip_dp_device *dp = to_dp(plat_data);
int ret;
- ret = rockchip_drm_psr_deactivate(&dp->encoder);
+ ret = rockchip_drm_psr_inhibit_get(&dp->encoder);
if (ret != 0)
return ret;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
index 1a6157ffecec..74f6a6a887dd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
@@ -25,7 +25,7 @@ struct psr_drv {
struct drm_encoder *encoder;
struct mutex lock;
- bool active;
+ int inhibit_count;
bool enabled;
struct delayed_work flush_work;
@@ -71,7 +71,7 @@ static int psr_set_state_locked(struct psr_drv *psr, bool enable)
{
int ret;
- if (!psr->active)
+ if (psr->inhibit_count > 0)
return -EINVAL;
if (enable == psr->enabled)
@@ -96,13 +96,18 @@ static void psr_flush_handler(struct work_struct *work)
}
/**
- * rockchip_drm_psr_activate - activate PSR on the given pipe
+ * rockchip_drm_psr_inhibit_put - release PSR inhibit on given encoder
* @encoder: encoder to obtain the PSR encoder
*
+ * Decrements PSR inhibit count on given encoder. Should be called only
+ * for a PSR inhibit count increment done before. If PSR inhibit counter
+ * reaches zero, PSR flush work is scheduled to make the hardware enter
+ * PSR mode in PSR_FLUSH_TIMEOUT_MS.
+ *
* Returns:
* Zero on success, negative errno on failure.
*/
-int rockchip_drm_psr_activate(struct drm_encoder *encoder)
+int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder)
{
struct psr_drv *psr = find_psr_by_encoder(encoder);
@@ -110,21 +115,30 @@ int rockchip_drm_psr_activate(struct drm_encoder *encoder)
return PTR_ERR(psr);
mutex_lock(&psr->lock);
- psr->active = true;
+ --psr->inhibit_count;
+ WARN_ON(psr->inhibit_count < 0);
+ if (!psr->inhibit_count)
+ mod_delayed_work(system_wq, &psr->flush_work,
+ PSR_FLUSH_TIMEOUT_MS);
mutex_unlock(&psr->lock);
return 0;
}
-EXPORT_SYMBOL(rockchip_drm_psr_activate);
+EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put);
/**
- * rockchip_drm_psr_deactivate - deactivate PSR on the given pipe
+ * rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder
* @encoder: encoder to obtain the PSR encoder
*
+ * Increments PSR inhibit count on given encoder. This function guarantees
+ * that after it returns PSR is turned off on given encoder and no PSR-related
+ * hardware state change occurs at least until a matching call to
+ * rockchip_drm_psr_inhibit_put() is done.
+ *
* Returns:
* Zero on success, negative errno on failure.
*/
-int rockchip_drm_psr_deactivate(struct drm_encoder *encoder)
+int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder)
{
struct psr_drv *psr = find_psr_by_encoder(encoder);
@@ -132,14 +146,14 @@ int rockchip_drm_psr_deactivate(struct drm_encoder *encoder)
return PTR_ERR(psr);
mutex_lock(&psr->lock);
- psr->active = false;
- psr->enabled = false;
+ psr_set_state_locked(psr, false);
+ ++psr->inhibit_count;
mutex_unlock(&psr->lock);
cancel_delayed_work_sync(&psr->flush_work);
return 0;
}
-EXPORT_SYMBOL(rockchip_drm_psr_deactivate);
+EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get);
static void rockchip_drm_do_flush(struct psr_drv *psr)
{
@@ -199,6 +213,11 @@ EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
* @encoder: encoder that obtain the PSR function
* @psr_set: call back to set PSR state
*
+ * The function returns with PSR inhibit counter initialized with one
+ * and the caller (typically encoder driver) needs to call
+ * rockchip_drm_psr_inhibit_put() when it becomes ready to accept PSR
+ * enable request.
+ *
* Returns:
* Zero on success, negative errno on failure.
*/
@@ -218,7 +237,7 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder,
INIT_DELAYED_WORK(&psr->flush_work, psr_flush_handler);
mutex_init(&psr->lock);
- psr->active = false;
+ psr->inhibit_count = 1;
psr->enabled = false;
psr->encoder = encoder;
psr->set = psr_set;
@@ -236,6 +255,11 @@ EXPORT_SYMBOL(rockchip_drm_psr_register);
* @encoder: encoder that obtain the PSR function
* @psr_set: call back to set PSR state
*
+ * It is expected that the PSR inhibit counter is 1 when this function is
+ * called, which corresponds to a state when related encoder has been
+ * disconnected from any CRTCs and its driver called
+ * rockchip_drm_psr_inhibit_get() to stop the PSR logic.
+ *
* Returns:
* Zero on success, negative errno on failure.
*/
@@ -247,7 +271,12 @@ void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
mutex_lock(&drm_drv->psr_list_lock);
list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
if (psr->encoder == encoder) {
- cancel_delayed_work_sync(&psr->flush_work);
+ /*
+ * Any other value would mean that the encoder
+ * is still in use.
+ */
+ WARN_ON(psr->inhibit_count != 1);
+
list_del(&psr->list);
kfree(psr);
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
index 06537ee27565..40e026c14168 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
@@ -18,8 +18,8 @@
void rockchip_drm_psr_flush_all(struct drm_device *dev);
int rockchip_drm_psr_flush(struct drm_crtc *crtc);
-int rockchip_drm_psr_activate(struct drm_encoder *encoder);
-int rockchip_drm_psr_deactivate(struct drm_encoder *encoder);
+int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder);
+int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder);
int rockchip_drm_psr_register(struct drm_encoder *encoder,
int (*psr_set)(struct drm_encoder *, bool enable));
--
2.17.0
From: zain wang <[email protected]>
It's too early to detect fast link training, if other step after it
failed, we will set fast_link flag to 1, and retry set_bridge again. In
this case we will power down and power up panel power supply, and we
will do fast link training since we have set fast_link flag to 1. In
fact, we should do full link training now, not the fast link training.
So we should move the fast link detection at the end of set_bridge.
Cc: Tomasz Figa <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Douglas Anderson <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
.../drm/bridge/analogix/analogix_dp_core.c | 42 ++++++++++++-------
1 file changed, 26 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index a72e454a7292..69b2c16e5776 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -601,7 +601,7 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
{
int lane, lane_count, retval;
u32 reg;
- u8 link_align, link_status[2], adjust_request[2], spread;
+ u8 link_align, link_status[2], adjust_request[2];
usleep_range(400, 401);
@@ -645,20 +645,6 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
dev_dbg(dp->dev, "final lane count = %.2x\n",
dp->link_train.lane_count);
- retval = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD,
- &spread);
- if (retval != 1) {
- dev_err(dp->dev, "failed to read downspread %d\n",
- retval);
- dp->fast_train_enable = false;
- } else {
- dp->fast_train_enable =
- (spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING) ?
- true : false;
- }
- dev_dbg(dp->dev, "fast link training %s\n",
- dp->fast_train_enable ? "supported" : "unsupported");
-
dp->link_train.lt_state = FINISHED;
return 0;
@@ -996,6 +982,22 @@ static irqreturn_t analogix_dp_irq_thread(int irq, void *arg)
return IRQ_HANDLED;
}
+static int analogix_dp_fast_link_train_detection(struct analogix_dp_device *dp)
+{
+ int ret;
+ u8 spread;
+
+ ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &spread);
+ if (ret != 1) {
+ dev_err(dp->dev, "failed to read downspread %d\n", ret);
+ return ret;
+ }
+ dp->fast_train_enable = !!(spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING);
+ dev_dbg(dp->dev, "fast link training %s\n",
+ dp->fast_train_enable ? "supported" : "unsupported");
+ return 0;
+}
+
static int analogix_dp_commit(struct analogix_dp_device *dp)
{
int ret;
@@ -1038,8 +1040,16 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
if (ret)
return ret;
- if (dp->psr_enable)
+ if (dp->psr_enable) {
ret = analogix_dp_enable_sink_psr(dp);
+ if (ret)
+ return ret;
+ }
+
+ /* Check whether panel supports fast training */
+ ret = analogix_dp_fast_link_train_detection(dp);
+ if (ret)
+ dp->psr_enable = false;
return ret;
}
--
2.17.0
From: Douglas Anderson <[email protected]>
Some of the platform-specific stuff in rockchip_dp_poweron() needs to
happen before the generic code. Some needs to happen after. Let's
split the callback in two.
Specifically we can't start doing PSR work until _after_ the whole
controller is up, so don't set the enable until the end.
Cc: Kristian H. Kristensen <[email protected]>
Signed-off-by: Douglas Anderson <[email protected]>
[seanpaul added exynos change]
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 7 +++++--
drivers/gpu/drm/exynos/exynos_dp.c | 2 +-
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 12 ++++++++++--
include/drm/bridge/analogix_dp.h | 3 ++-
4 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index a260de4f0bd8..2bcbfadb6ac5 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1260,8 +1260,8 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
goto out_dp_clk_pre;
}
- if (dp->plat_data->power_on)
- dp->plat_data->power_on(dp->plat_data);
+ if (dp->plat_data->power_on_start)
+ dp->plat_data->power_on_start(dp->plat_data);
phy_power_on(dp->phy);
@@ -1286,6 +1286,9 @@ 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;
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 964831dab102..86330f396784 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -162,7 +162,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
dp->drm_dev = drm_dev;
dp->plat_data.dev_type = EXYNOS_DP;
- dp->plat_data.power_on = exynos_dp_poweron;
+ dp->plat_data.power_on_start = exynos_dp_poweron;
dp->plat_data.power_off = exynos_dp_poweroff;
dp->plat_data.attach = exynos_dp_bridge_attach;
dp->plat_data.get_modes = exynos_dp_get_modes;
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index b3f46ed24cdc..23317a2269e1 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -109,7 +109,7 @@ static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
return 0;
}
-static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
+static int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data)
{
struct rockchip_dp_device *dp = to_dp(plat_data);
int ret;
@@ -127,6 +127,13 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
return ret;
}
+ return ret;
+}
+
+static int rockchip_dp_poweron_end(struct analogix_dp_plat_data *plat_data)
+{
+ struct rockchip_dp_device *dp = to_dp(plat_data);
+
return rockchip_drm_psr_activate(&dp->encoder);
}
@@ -330,7 +337,8 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
dp->plat_data.encoder = &dp->encoder;
dp->plat_data.dev_type = dp->data->chip_type;
- dp->plat_data.power_on = rockchip_dp_poweron;
+ dp->plat_data.power_on_start = rockchip_dp_poweron_start;
+ dp->plat_data.power_on_end = rockchip_dp_poweron_end;
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index e9a1116d2f8e..475b706b49de 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -33,7 +33,8 @@ struct analogix_dp_plat_data {
struct drm_connector *connector;
bool skip_connector;
- int (*power_on)(struct analogix_dp_plat_data *);
+ int (*power_on_start)(struct analogix_dp_plat_data *);
+ int (*power_on_end)(struct analogix_dp_plat_data *);
int (*power_off)(struct analogix_dp_plat_data *);
int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *,
struct drm_connector *);
--
2.17.0
From: Tomasz Figa <[email protected]>
Driver callbacks, such as system suspend or resume can be called any
time, specifically they can be called before the component bind
callback. Let's use dp->adp pointer as a safeguard and skip calling
Analogix entry points if it is an ERR_PTR().
Signed-off-by: Tomasz Figa <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 23317a2269e1..6d45d62466b3 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -368,6 +368,8 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
analogix_dp_unbind(dp->adp);
rockchip_drm_psr_unregister(&dp->encoder);
dp->encoder.funcs->destroy(&dp->encoder);
+
+ dp->adp = ERR_PTR(-ENODEV);
}
static const struct component_ops rockchip_dp_component_ops = {
@@ -391,6 +393,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
return -ENOMEM;
dp->dev = dev;
+ dp->adp = ERR_PTR(-ENODEV);
dp->plat_data.panel = panel;
ret = rockchip_dp_of_probe(dp);
@@ -414,6 +417,9 @@ static int rockchip_dp_suspend(struct device *dev)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+ if (IS_ERR(dp->adp))
+ return 0;
+
return analogix_dp_suspend(dp->adp);
}
@@ -421,6 +427,9 @@ static int rockchip_dp_resume(struct device *dev)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+ if (IS_ERR(dp->adp))
+ return 0;
+
return analogix_dp_resume(dp->adp);
}
#endif
--
2.17.0
From: Douglas Anderson <[email protected]>
The code in analogix_dp_transfer() that was supposed to print out:
AUX CH error happened
Was actually dead code. That's because the previous check (whether
the interrupt status indicated any errors) would have hit for all
errors anyway.
Let's combine the two error checks so we can actually see AUX CH
errors. We'll also downgrade the message to a warning since some of
these types of errors might be expected for some displays. If this
gets too noisy we can downgrade again to debug.
Cc: 征增 王 <[email protected]>
Signed-off-by: Douglas Anderson <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 4eae206ec31b..58e8a28e99aa 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1105,6 +1105,7 @@ 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;
@@ -1193,16 +1194,12 @@ 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);
- if (reg & AUX_ERR) {
+ status_reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA);
+ if ((reg & AUX_ERR) || (status_reg & AUX_STATUS_MASK)) {
writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA);
- goto aux_error;
- }
- /* Check AUX CH error access status */
- reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA);
- if ((reg & AUX_STATUS_MASK)) {
- dev_err(dp->dev, "AUX CH error happened: %d\n\n",
- reg & AUX_STATUS_MASK);
+ dev_warn(dp->dev, "AUX CH error happened: %#x (%d)\n",
+ status_reg & AUX_STATUS_MASK, !!(reg & AUX_ERR));
goto aux_error;
}
--
2.17.0
From: Mark Yao <[email protected]>
Some encoder have a crc verification check, crc check fail if
input and output data is not equal.
That means encoder input and output need use same color depth,
vop can output 10bit data to encoder, but some panel only support
8bit depth, that would make crc check die.
So pre dither down vop data to 8bit if panel's bpc is 8.
Signed-off-by: Mark Yao <[email protected]>
[seanpaul resolved conflict in rockchip_drm_vop.c]
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 2 ++
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 6 ++++++
drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 1 +
drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 +
5 files changed, 11 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 8c884f9ce713..b3f46ed24cdc 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -218,6 +218,7 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+ struct drm_display_info *di = &conn_state->connector->display_info;
/*
* The hardware IC designed that VOP must output the RGB10 video
@@ -229,6 +230,7 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
s->output_type = DRM_MODE_CONNECTOR_eDP;
+ s->output_bpc = di->bpc;
return 0;
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 9c064a40458b..3a6ebfc26036 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -36,6 +36,7 @@ struct rockchip_crtc_state {
struct drm_crtc_state base;
int output_type;
int output_mode;
+ int output_bpc;
};
#define to_rockchip_crtc_state(s) \
container_of(s, struct rockchip_crtc_state, base)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 53d4afe15278..00f7f3441cf6 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -925,6 +925,12 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
!(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10))
s->output_mode = ROCKCHIP_OUT_MODE_P888;
+
+ if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && s->output_bpc == 8)
+ VOP_REG_SET(vop, common, pre_dither_down, 1);
+ else
+ VOP_REG_SET(vop, common, pre_dither_down, 0);
+
VOP_REG_SET(vop, common, out_mode, s->output_mode);
VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 56bbd2e2a8ef..084acdd0019a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -67,6 +67,7 @@ struct vop_common {
struct vop_reg cfg_done;
struct vop_reg dsp_blank;
struct vop_reg data_blank;
+ struct vop_reg pre_dither_down;
struct vop_reg dither_down;
struct vop_reg dither_up;
struct vop_reg gate_en;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 2e4eea3459fe..08023d3ecb76 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -264,6 +264,7 @@ static const struct vop_common rk3288_common = {
.standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22),
.gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
.mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
+ .pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1),
.dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1),
.dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
.data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
--
2.17.0
From: zain wang <[email protected]>
The STRM_VALID bit in register ANALOGIX_DP_SYS_CTL_3 may be unstable,
so we may hit the error log "Timeout of video streamclk ok" since
checked this unstable bit.
In fact, we can go continue and the streamclk is ok if we wait enough time,
it does no effect on display.
Let's change this error to warn.
Cc: Douglas Anderson <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5540e2dfc2ec..a72e454a7292 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -921,8 +921,9 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
done_count = 0;
}
if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
- dev_err(dp->dev, "Timeout of video streamclk ok\n");
- return -ETIMEDOUT;
+ dev_warn(dp->dev,
+ "Ignoring timeout of video streamclk ok\n");
+ break;
}
usleep_range(1000, 1001);
--
2.17.0
From: zain wang <[email protected]>
If we failed disable psr, it would hang the display until next psr
cycle coming. So we should restore psr->state when it failed.
Cc: Tomasz Figa <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Douglas Anderson <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Heiko Stuebner <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
.../drm/bridge/analogix/analogix_dp_core.c | 4 +++-
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 10 +++++-----
drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 20 ++++++++++++-------
drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 2 +-
4 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 75e61ebf6722..5540e2dfc2ec 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -153,8 +153,10 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp)
psr_vsc.DB1 = 0;
ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
- if (ret != 1)
+ if (ret != 1) {
dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret);
+ return ret;
+ }
return analogix_dp_send_psr_spd(dp, &psr_vsc, false);
}
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 3e8bf79bea58..8c884f9ce713 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -77,13 +77,13 @@ struct rockchip_dp_device {
struct analogix_dp_plat_data plat_data;
};
-static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
+static int analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
{
struct rockchip_dp_device *dp = to_dp(encoder);
int ret;
if (!analogix_dp_psr_enabled(dp->adp))
- return;
+ return 0;
DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
@@ -91,13 +91,13 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
if (ret) {
DRM_DEV_ERROR(dp->dev, "line flag interrupt did not arrive\n");
- return;
+ return -ETIMEDOUT;
}
if (enabled)
- analogix_dp_enable_psr(dp->adp);
+ return analogix_dp_enable_psr(dp->adp);
else
- analogix_dp_disable_psr(dp->adp);
+ return analogix_dp_disable_psr(dp->adp);
}
static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
index b339ca943139..9376f4396b6b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
@@ -36,7 +36,7 @@ struct psr_drv {
struct delayed_work flush_work;
- void (*set)(struct drm_encoder *encoder, bool enable);
+ int (*set)(struct drm_encoder *encoder, bool enable);
};
static struct psr_drv *find_psr_by_crtc(struct drm_crtc *crtc)
@@ -93,19 +93,25 @@ static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state)
return;
}
- psr->state = state;
-
/* Actually commit the state change to hardware */
- switch (psr->state) {
+ switch (state) {
case PSR_ENABLE:
- psr->set(psr->encoder, true);
+ if (psr->set(psr->encoder, true))
+ return;
break;
case PSR_DISABLE:
case PSR_FLUSH:
- psr->set(psr->encoder, false);
+ if (psr->set(psr->encoder, false))
+ return;
break;
+
+ default:
+ pr_err("%s: Unknown state %d\n", __func__, state);
+ return;
}
+
+ psr->state = state;
}
static void psr_set_state(struct psr_drv *psr, enum psr_state state)
@@ -229,7 +235,7 @@ EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
* Zero on success, negative errno on failure.
*/
int rockchip_drm_psr_register(struct drm_encoder *encoder,
- void (*psr_set)(struct drm_encoder *, bool enable))
+ int (*psr_set)(struct drm_encoder *, bool enable))
{
struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
struct psr_drv *psr;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
index b1ea0155e57c..06537ee27565 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
@@ -22,7 +22,7 @@ int rockchip_drm_psr_activate(struct drm_encoder *encoder);
int rockchip_drm_psr_deactivate(struct drm_encoder *encoder);
int rockchip_drm_psr_register(struct drm_encoder *encoder,
- void (*psr_set)(struct drm_encoder *, bool enable));
+ int (*psr_set)(struct drm_encoder *, bool enable));
void rockchip_drm_psr_unregister(struct drm_encoder *encoder);
#endif /* __ROCKCHIP_DRM_PSR__ */
--
2.17.0
From: zain wang <[email protected]>
There are some different bits between Rockchip and Exynos in register
"AUX_PD". This patch fixes the incorrect operations about it.
Cc: Douglas Anderson <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
.../gpu/drm/bridge/analogix/analogix_dp_reg.c | 117 ++++++++++--------
.../gpu/drm/bridge/analogix/analogix_dp_reg.h | 2 +
2 files changed, 65 insertions(+), 54 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index bb72f8b0e603..dee1ba109b5f 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -248,76 +248,85 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
{
u32 reg;
u32 phy_pd_addr = ANALOGIX_DP_PHY_PD;
+ u32 mask;
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
phy_pd_addr = ANALOGIX_DP_PD;
switch (block) {
case AUX_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg |= AUX_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- } else {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg &= ~AUX_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- }
+ if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
+ mask = RK_AUX_PD;
+ else
+ mask = AUX_PD;
+
+ reg = readl(dp->reg_base + phy_pd_addr);
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ writel(reg, dp->reg_base + phy_pd_addr);
break;
case CH0_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg |= CH0_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- } else {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg &= ~CH0_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- }
+ mask = CH0_PD;
+ reg = readl(dp->reg_base + phy_pd_addr);
+
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ writel(reg, dp->reg_base + phy_pd_addr);
break;
case CH1_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg |= CH1_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- } else {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg &= ~CH1_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- }
+ mask = CH1_PD;
+ reg = readl(dp->reg_base + phy_pd_addr);
+
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ writel(reg, dp->reg_base + phy_pd_addr);
break;
case CH2_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg |= CH2_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- } else {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg &= ~CH2_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- }
+ mask = CH2_PD;
+ reg = readl(dp->reg_base + phy_pd_addr);
+
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ writel(reg, dp->reg_base + phy_pd_addr);
break;
case CH3_BLOCK:
- if (enable) {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg |= CH3_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- } else {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg &= ~CH3_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- }
+ mask = CH3_PD;
+ reg = readl(dp->reg_base + phy_pd_addr);
+
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ writel(reg, dp->reg_base + phy_pd_addr);
break;
case ANALOG_TOTAL:
- if (enable) {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg |= DP_PHY_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- } else {
- reg = readl(dp->reg_base + phy_pd_addr);
- reg &= ~DP_PHY_PD;
- writel(reg, dp->reg_base + phy_pd_addr);
- }
+ /*
+ * There is no bit named DP_PHY_PD, so We used DP_INC_BG
+ * to power off everything instead of DP_PHY_PD in
+ * Rockchip
+ */
+ if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
+ mask = DP_INC_BG;
+ else
+ mask = DP_PHY_PD;
+
+ reg = readl(dp->reg_base + phy_pd_addr);
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+
+ writel(reg, dp->reg_base + phy_pd_addr);
+ if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
+ usleep_range(10, 15);
break;
case POWER_ALL:
if (enable) {
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index 9602668669f4..b633a4a5082a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -345,7 +345,9 @@
#define DP_INC_BG (0x1 << 7)
#define DP_EXP_BG (0x1 << 6)
#define DP_PHY_PD (0x1 << 5)
+#define RK_AUX_PD (0x1 << 5)
#define AUX_PD (0x1 << 4)
+#define RK_PLL_PD (0x1 << 4)
#define CH3_PD (0x1 << 3)
#define CH2_PD (0x1 << 2)
#define CH1_PD (0x1 << 1)
--
2.17.0
From: Lin Huang <[email protected]>
We need to check the dpcd write/read return value to see whether the
write/read was successful
Cc: Kristian H. Kristensen <[email protected]>
Signed-off-by: Lin Huang <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Douglas Anderson <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
.../drm/bridge/analogix/analogix_dp_core.c | 169 +++++++++++++-----
1 file changed, 127 insertions(+), 42 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 1e1743b59c77..75e61ebf6722 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -160,80 +160,137 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp)
}
EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
-static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+static int analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
{
unsigned char psr_version;
+ int ret;
+
+ ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version);
+ if (ret != 1) {
+ dev_err(dp->dev, "failed to get PSR version, disable it\n");
+ return ret;
+ }
- drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version);
dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
- return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+ dp->psr_enable = (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+
+ return 0;
}
-static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
{
unsigned char psr_en;
+ int ret;
/* Disable psr function */
- drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en);
+ ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en);
+ if (ret != 1) {
+ dev_err(dp->dev, "failed to get psr config\n");
+ goto end;
+ }
+
psr_en &= ~DP_PSR_ENABLE;
- drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
+ ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
+ if (ret != 1) {
+ dev_err(dp->dev, "failed to disable panel psr\n");
+ goto end;
+ }
/* Main-Link transmitter remains active during PSR active states */
psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
- drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
+ ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
+ if (ret != 1) {
+ dev_err(dp->dev, "failed to set panel psr\n");
+ goto end;
+ }
/* Enable psr function */
psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
DP_PSR_CRC_VERIFICATION;
- drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
+ ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
+ if (ret != 1) {
+ dev_err(dp->dev, "failed to set panel psr\n");
+ goto end;
+ }
analogix_dp_enable_psr_crc(dp);
+
+ return 0;
+end:
+ dev_err(dp->dev, "enable psr fail, force to disable psr\n");
+ dp->psr_enable = false;
+
+ return ret;
}
-static void
+static int
analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp,
bool enable)
{
u8 data;
+ int ret;
- drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data);
+ ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data);
+ if (ret != 1)
+ return ret;
if (enable)
- drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
- DP_LANE_COUNT_ENHANCED_FRAME_EN |
- DPCD_LANE_COUNT_SET(data));
+ ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
+ DP_LANE_COUNT_ENHANCED_FRAME_EN |
+ DPCD_LANE_COUNT_SET(data));
else
- drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
- DPCD_LANE_COUNT_SET(data));
+ ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
+ DPCD_LANE_COUNT_SET(data));
+
+ return ret < 0 ? ret : 0;
}
-static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp)
+static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp,
+ u8 *enhanced_mode_support)
{
u8 data;
- int retval;
+ int ret;
- drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
- retval = DPCD_ENHANCED_FRAME_CAP(data);
+ ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
+ if (ret != 1) {
+ *enhanced_mode_support = 0;
+ return ret;
+ }
- return retval;
+ *enhanced_mode_support = DPCD_ENHANCED_FRAME_CAP(data);
+
+ return 0;
}
-static void analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp)
+static int analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp)
{
u8 data;
+ int ret;
+
+ ret = analogix_dp_is_enhanced_mode_available(dp, &data);
+ if (ret < 0)
+ return ret;
+
+ ret = analogix_dp_enable_rx_to_enhanced_mode(dp, data);
+ if (ret < 0)
+ return ret;
- data = analogix_dp_is_enhanced_mode_available(dp);
- analogix_dp_enable_rx_to_enhanced_mode(dp, data);
analogix_dp_enable_enhanced_mode(dp, data);
+
+ return 0;
}
-static void analogix_dp_training_pattern_dis(struct analogix_dp_device *dp)
+static int analogix_dp_training_pattern_dis(struct analogix_dp_device *dp)
{
+ int ret;
+
analogix_dp_set_training_pattern(dp, DP_NONE);
- drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
- DP_TRAINING_PATTERN_DISABLE);
+ ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
+ DP_TRAINING_PATTERN_DISABLE);
+
+ return ret < 0 ? ret : 0;
}
static void
@@ -282,7 +339,11 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
if (retval < 0)
return retval;
/* set enhanced mode if available */
- analogix_dp_set_enhanced_mode(dp);
+ retval = analogix_dp_set_enhanced_mode(dp);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to set enhance mode\n");
+ return retval;
+ }
/* Set TX pre-emphasis to minimum */
for (lane = 0; lane < lane_count; lane++)
@@ -567,10 +628,11 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) {
/* traing pattern Set to Normal */
- analogix_dp_training_pattern_dis(dp);
+ retval = analogix_dp_training_pattern_dis(dp);
+ if (retval < 0)
+ return retval;
dev_info(dp->dev, "Link Training success!\n");
-
analogix_dp_get_link_bandwidth(dp, ®);
dp->link_train.link_rate = reg;
dev_dbg(dp->dev, "final bandwidth = %.2x\n",
@@ -867,24 +929,32 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
return 0;
}
-static void analogix_dp_enable_scramble(struct analogix_dp_device *dp,
- bool enable)
+static int analogix_dp_enable_scramble(struct analogix_dp_device *dp,
+ bool enable)
{
u8 data;
+ int ret;
if (enable) {
analogix_dp_enable_scrambling(dp);
- drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data);
- drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
+ ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
+ &data);
+ if (ret != 1)
+ return ret;
+ ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
(u8)(data & ~DP_LINK_SCRAMBLING_DISABLE));
} else {
analogix_dp_disable_scrambling(dp);
- drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data);
- drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
+ ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
+ &data);
+ if (ret != 1)
+ return ret;
+ ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
(u8)(data | DP_LINK_SCRAMBLING_DISABLE));
}
+ return ret < 0 ? ret : 0;
}
static irqreturn_t analogix_dp_hardirq(int irq, void *arg)
@@ -939,23 +1009,36 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
return ret;
}
- analogix_dp_enable_scramble(dp, 1);
+ ret = analogix_dp_enable_scramble(dp, 1);
+ if (ret < 0) {
+ dev_err(dp->dev, "can not enable scramble\n");
+ return ret;
+ }
analogix_dp_init_video(dp);
ret = analogix_dp_config_video(dp);
- if (ret)
+ if (ret) {
dev_err(dp->dev, "unable to config video\n");
+ return ret;
+ }
/* Safe to enable the panel now */
if (dp->plat_data->panel) {
- if (drm_panel_enable(dp->plat_data->panel))
+ ret = drm_panel_enable(dp->plat_data->panel);
+ if (ret) {
DRM_ERROR("failed to enable the panel\n");
+ return ret;
+ }
}
- dp->psr_enable = analogix_dp_detect_sink_psr(dp);
+ ret = analogix_dp_detect_sink_psr(dp);
+ if (ret)
+ return ret;
+
if (dp->psr_enable)
- analogix_dp_enable_sink_psr(dp);
- return 0;
+ ret = analogix_dp_enable_sink_psr(dp);
+
+ return ret;
}
/*
@@ -1185,8 +1268,10 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
}
ret = analogix_dp_commit(dp);
- if (ret)
+ if (ret) {
+ DRM_ERROR("dp commit error, ret = %d\n", ret);
goto out_dp_init;
+ }
enable_irq(dp->irq);
return 0;
--
2.17.0
From: zain wang <[email protected]>
When we enable bridge failed, we have to retry it, otherwise we would get
the abnormal display.
Cc: Stéphane Marchesin <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
.../drm/bridge/analogix/analogix_dp_core.c | 65 +++++++++++++++----
.../drm/bridge/analogix/analogix_dp_core.h | 3 +-
.../gpu/drm/bridge/analogix/analogix_dp_reg.c | 5 +-
3 files changed, 56 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 85dbb1ca9886..bf805f156272 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -43,8 +43,10 @@ struct bridge_init {
struct device_node *node;
};
-static void analogix_dp_init_dp(struct analogix_dp_device *dp)
+static int analogix_dp_init_dp(struct analogix_dp_device *dp)
{
+ int ret;
+
analogix_dp_reset(dp);
analogix_dp_swreset(dp);
@@ -56,10 +58,13 @@ static void analogix_dp_init_dp(struct analogix_dp_device *dp)
analogix_dp_enable_sw_function(dp);
analogix_dp_config_interrupt(dp);
- analogix_dp_init_analog_func(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)
@@ -918,7 +923,7 @@ static irqreturn_t analogix_dp_irq_thread(int irq, void *arg)
return IRQ_HANDLED;
}
-static void analogix_dp_commit(struct analogix_dp_device *dp)
+static int analogix_dp_commit(struct analogix_dp_device *dp)
{
int ret;
@@ -928,11 +933,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
DRM_ERROR("failed to disable the panel\n");
}
- ret = readx_poll_timeout(analogix_dp_train_link, dp, ret, !ret, 100,
- DP_TIMEOUT_TRAINING_US * 5);
+ ret = analogix_dp_train_link(dp);
if (ret) {
dev_err(dp->dev, "unable to do link train, ret=%d\n", ret);
- return;
+ return ret;
}
analogix_dp_enable_scramble(dp, 1);
@@ -953,6 +957,7 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
dp->psr_enable = analogix_dp_detect_sink_psr(dp);
if (dp->psr_enable)
analogix_dp_enable_sink_psr(dp);
+ return 0;
}
/*
@@ -1149,12 +1154,9 @@ static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge)
DRM_ERROR("failed to setup the panel ret = %d\n", ret);
}
-static void analogix_dp_bridge_enable(struct drm_bridge *bridge)
+static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
{
- struct analogix_dp_device *dp = bridge->driver_private;
-
- if (dp->dpms_mode == DRM_MODE_DPMS_ON)
- return;
+ int ret;
pm_runtime_get_sync(dp->dev);
@@ -1162,11 +1164,46 @@ static void analogix_dp_bridge_enable(struct drm_bridge *bridge)
dp->plat_data->power_on(dp->plat_data);
phy_power_on(dp->phy);
- analogix_dp_init_dp(dp);
+
+ ret = analogix_dp_init_dp(dp);
+ if (ret)
+ goto out_dp_init;
+
+ ret = analogix_dp_commit(dp);
+ if (ret)
+ goto out_dp_init;
+
enable_irq(dp->irq);
- analogix_dp_commit(dp);
+ return 0;
- dp->dpms_mode = DRM_MODE_DPMS_ON;
+out_dp_init:
+ phy_power_off(dp->phy);
+ if (dp->plat_data->power_off)
+ dp->plat_data->power_off(dp->plat_data);
+ pm_runtime_put_sync(dp->dev);
+
+ return ret;
+}
+
+static void analogix_dp_bridge_enable(struct drm_bridge *bridge)
+{
+ struct analogix_dp_device *dp = bridge->driver_private;
+ int timeout_loop = 0;
+
+ if (dp->dpms_mode == DRM_MODE_DPMS_ON)
+ return;
+
+ while (timeout_loop < MAX_PLL_LOCK_LOOP) {
+ if (analogix_dp_set_bridge(dp) == 0) {
+ dp->dpms_mode = DRM_MODE_DPMS_ON;
+ return;
+ }
+ dev_err(dp->dev, "failed to set bridge, retry: %d\n",
+ timeout_loop);
+ timeout_loop++;
+ usleep_range(10, 11);
+ }
+ dev_err(dp->dev, "too many times retry set bridge, give it up\n");
}
static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 403ff853464b..769255dc6e99 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -19,6 +19,7 @@
#define DP_TIMEOUT_LOOP_COUNT 100
#define MAX_CR_LOOP 5
#define MAX_EQ_LOOP 5
+#define MAX_PLL_LOCK_LOOP 5
/* Training takes 22ms if AUX channel comm fails. Use this as retry interval */
#define DP_TIMEOUT_TRAINING_US 22000
@@ -197,7 +198,7 @@ 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,
bool enable);
-void analogix_dp_init_analog_func(struct analogix_dp_device *dp);
+int analogix_dp_init_analog_func(struct analogix_dp_device *dp);
void analogix_dp_init_hpd(struct analogix_dp_device *dp);
void analogix_dp_force_hpd(struct analogix_dp_device *dp);
enum dp_irq_type analogix_dp_get_irq_type(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 e78c861b9e06..b47c5af43560 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -333,7 +333,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
}
}
-void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
+int analogix_dp_init_analog_func(struct analogix_dp_device *dp)
{
u32 reg;
int timeout_loop = 0;
@@ -355,7 +355,7 @@ void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
timeout_loop++;
if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
dev_err(dp->dev, "failed to get pll lock status\n");
- return;
+ return -ETIMEDOUT;
}
usleep_range(10, 20);
}
@@ -366,6 +366,7 @@ void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
| AUX_FUNC_EN_N);
writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
+ return 0;
}
void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp)
--
2.17.0
From: Lin Huang <[email protected]>
There was a 1ms delay to detect the hpd signal, which is too short to
detect a short pulse. This patch extends this delay to 100ms.
Cc: Stéphane Marchesin <[email protected]>
Cc: 征增 王 <[email protected]>
Signed-off-by: Lin Huang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5957e2338071..1f4f34149019 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -76,7 +76,7 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
return 0;
timeout_loop++;
- usleep_range(10, 11);
+ usleep_range(1000, 1100);
}
/*
--
2.17.0
From: zain wang <[email protected]>
Following the correct power up sequence:
dp_pd=ff => dp_pd=7f => wait 10us => dp_pd=00
Cc: Stéphane Marchesin <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 10 ++++++++--
drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 3 +++
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index b47c5af43560..bb72f8b0e603 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -321,10 +321,16 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
break;
case POWER_ALL:
if (enable) {
- reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
- CH1_PD | CH0_PD;
+ reg = DP_ALL_PD;
writel(reg, dp->reg_base + phy_pd_addr);
} else {
+ reg = DP_ALL_PD;
+ writel(reg, dp->reg_base + phy_pd_addr);
+ usleep_range(10, 15);
+ reg &= ~DP_INC_BG;
+ writel(reg, dp->reg_base + phy_pd_addr);
+ usleep_range(10, 15);
+
writel(0x00, dp->reg_base + phy_pd_addr);
}
break;
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index 40200c652533..9602668669f4 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -342,12 +342,15 @@
#define DP_PLL_REF_BIT_1_2500V (0x7 << 0)
/* ANALOGIX_DP_PHY_PD */
+#define DP_INC_BG (0x1 << 7)
+#define DP_EXP_BG (0x1 << 6)
#define DP_PHY_PD (0x1 << 5)
#define AUX_PD (0x1 << 4)
#define CH3_PD (0x1 << 3)
#define CH2_PD (0x1 << 2)
#define CH1_PD (0x1 << 1)
#define CH0_PD (0x1 << 0)
+#define DP_ALL_PD (0xff)
/* ANALOGIX_DP_PHY_TEST */
#define MACRO_RST (0x1 << 5)
--
2.17.0
From: Lin Huang <[email protected]>
AUX errors are caused by many different reasons. We may not know what
happened in aux channel on failure, so let's reset aux channel if some
errors occurred.
Cc: 征增 王 <[email protected]>
Cc: Douglas Anderson <[email protected]>
Signed-off-by: Lin Huang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
---
.../gpu/drm/bridge/analogix/analogix_dp_reg.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index dee1ba109b5f..7b7fd227e1f9 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -466,6 +466,10 @@ void analogix_dp_init_aux(struct analogix_dp_device *dp)
reg = RPLY_RECEIV | AUX_ERR;
writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA);
+ analogix_dp_set_analog_power_down(dp, AUX_BLOCK, true);
+ usleep_range(10, 11);
+ analogix_dp_set_analog_power_down(dp, AUX_BLOCK, false);
+
analogix_dp_reset_aux(dp);
/* Disable AUX transaction H/W retry */
@@ -1159,7 +1163,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
reg, !(reg & AUX_EN), 25, 500 * 1000);
if (ret) {
dev_err(dp->dev, "AUX CH enable timeout!\n");
- return -ETIMEDOUT;
+ goto aux_error;
}
/* TODO: Wait for an interrupt instead of looping? */
@@ -1168,7 +1172,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
reg, reg & RPLY_RECEIV, 10, 20 * 1000);
if (ret) {
dev_err(dp->dev, "AUX CH cmd reply timeout!\n");
- return -ETIMEDOUT;
+ goto aux_error;
}
/* Clear interrupt source for AUX CH command reply */
@@ -1178,7 +1182,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
if (reg & AUX_ERR) {
writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA);
- return -EREMOTEIO;
+ goto aux_error;
}
/* Check AUX CH error access status */
@@ -1186,7 +1190,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
if ((reg & AUX_STATUS_MASK)) {
dev_err(dp->dev, "AUX CH error happened: %d\n\n",
reg & AUX_STATUS_MASK);
- return -EREMOTEIO;
+ goto aux_error;
}
if (msg->request & DP_AUX_I2C_READ) {
@@ -1212,4 +1216,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
msg->reply = DP_AUX_NATIVE_REPLY_ACK;
return num_transferred > 0 ? num_transferred : -EBUSY;
+
+aux_error:
+ /* if aux err happen, reset aux */
+ analogix_dp_init_aux(dp);
+
+ return -EREMOTEIO;
}
--
2.17.0
From: Douglas Anderson <[email protected]>
The current user of the analogix power_off is "analogix_dp-rockchip".
That driver does this:
- deactivate PSR
- turn off a clock
Both of these things (especially deactive PSR) should be done before
we turn the PHY power off and turn off analog power. Let's move the
callback up.
Note that without this patch (and with
https://patchwork.kernel.org/patch/9553349/ [seanpaul: this patch was
not applied, but it seems like the race can still occur]), I experienced
an error in reboot testing where one thread was at:
rockchip_drm_psr_deactivate
rockchip_dp_powerdown
analogix_dp_bridge_disable
drm_bridge_disable
...and the other thread was at:
analogix_dp_send_psr_spd
analogix_dp_enable_psr
analogix_dp_psr_set
psr_flush_handler
The flush handler thread was finding AUX channel errors and eventually
reported "Failed to apply PSR", where I had a kgdb breakpoint. Presumably
the device would have eventually given up and shut down anyway, but it
seems better to fix the order to be more correct.
Cc: Kristian H. Kristensen <[email protected]>
Signed-off-by: Douglas Anderson <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 69b2c16e5776..a260de4f0bd8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1337,12 +1337,13 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
}
disable_irq(dp->irq);
- analogix_dp_set_analog_power_down(dp, POWER_ALL, 1);
- phy_power_off(dp->phy);
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);
--
2.17.0
From: Lin Huang <[email protected]>
We should check AUX_EN bit to confirm the AUX CH operation is completed.
Cc: Stéphane Marchesin <[email protected]>
Signed-off-by: Lin Huang <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
.../gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 +++++++++++--------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 9df2f3ef000c..e78c861b9e06 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1073,9 +1073,9 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
{
u32 reg;
u8 *buffer = msg->buffer;
- int timeout_loop = 0;
unsigned int i;
int num_transferred = 0;
+ int ret;
/* Buffer size of AUX CH is 16 bytes */
if (WARN_ON(msg->size > 16))
@@ -1139,17 +1139,20 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
- /* Is AUX CH command reply received? */
+ ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2,
+ reg, !(reg & AUX_EN), 25, 500 * 1000);
+ if (ret) {
+ dev_err(dp->dev, "AUX CH enable timeout!\n");
+ return -ETIMEDOUT;
+ }
+
/* TODO: Wait for an interrupt instead of looping? */
- reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
- while (!(reg & RPLY_RECEIV)) {
- timeout_loop++;
- if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
- dev_err(dp->dev, "AUX CH command reply failed!\n");
- return -ETIMEDOUT;
- }
- reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
- usleep_range(10, 11);
+ /* Is AUX CH command reply received? */
+ ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_INT_STA,
+ reg, reg & RPLY_RECEIV, 10, 20 * 1000);
+ if (ret) {
+ dev_err(dp->dev, "AUX CH cmd reply timeout!\n");
+ return -ETIMEDOUT;
}
/* Clear interrupt source for AUX CH command reply */
--
2.17.0
From: zain wang <[email protected]>
Enhanced mode is required by the eDP 1.2 specification, and not doing it
early could result in a period of time where we have a link transmitting
idle packets without it. Since there is no reason to disable it, we just
enable it at the beginning of link training and then keep it on all the
time.
Cc: Tomasz Figa <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 1f4f34149019..1e1743b59c77 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -281,6 +281,8 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2);
if (retval < 0)
return retval;
+ /* set enhanced mode if available */
+ analogix_dp_set_enhanced_mode(dp);
/* Set TX pre-emphasis to minimum */
for (lane = 0; lane < lane_count; lane++)
@@ -593,8 +595,6 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
dev_dbg(dp->dev, "fast link training %s\n",
dp->fast_train_enable ? "supported" : "unsupported");
- /* set enhanced mode if available */
- analogix_dp_set_enhanced_mode(dp);
dp->link_train.lt_state = FINISHED;
return 0;
@@ -940,8 +940,6 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
}
analogix_dp_enable_scramble(dp, 1);
- analogix_dp_enable_rx_to_enhanced_mode(dp, 1);
- analogix_dp_enable_enhanced_mode(dp, 1);
analogix_dp_init_video(dp);
ret = analogix_dp_config_video(dp);
--
2.17.0
From: Lin Huang <[email protected]>
We need to enable video before analogix_dp_is_video_stream_on(), so
we can get the right video stream status.
We needed to increase the delay in the timeout loop because there is
random "Timeout of video streamclk ok" message happen when debug edp
panel, this time do not define in the spec.
Cc: 征增 王 <[email protected]>
Cc: Stéphane Marchesin <[email protected]>
Signed-off-by: Lin Huang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Reviewed-by: Andrzej Hajda <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5c52307146c7..05a0ca4af057 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -819,11 +819,10 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0)
break;
if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
- dev_err(dp->dev, "Timeout of video streamclk ok\n");
+ dev_err(dp->dev, "Timeout of slave video streamclk ok\n");
return -ETIMEDOUT;
}
-
- usleep_range(1, 2);
+ usleep_range(1000, 1001);
}
/* Set to use the register calculated M/N video */
@@ -838,6 +837,9 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
/* Configure video slave mode */
analogix_dp_enable_video_master(dp, 0);
+ /* Enable video */
+ analogix_dp_start_video(dp);
+
timeout_loop = 0;
for (;;) {
@@ -948,9 +950,6 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
DRM_ERROR("failed to enable the panel\n");
}
- /* Enable video */
- analogix_dp_start_video(dp);
-
dp->psr_enable = analogix_dp_detect_sink_psr(dp);
if (dp->psr_enable)
analogix_dp_enable_sink_psr(dp);
--
2.17.0
From: zain wang <[email protected]>
According to DP spec v1.3 chap 3.5.1.2 Link Training, Link Policy Maker
must first detect that the HPD signal is asserted high by the Downstream
Device before establishing a link with it.
Cc: Stéphane Marchesin <[email protected]>
Signed-off-by: zain wang <[email protected]>
Signed-off-by: Sean Paul <[email protected]>
Signed-off-by: Thierry Escande <[email protected]>
Signed-off-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Marek Szyprowski <[email protected]>
Reviewed-by: Archit Taneja <[email protected]>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index bf805f156272..3269deec739d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1169,6 +1169,17 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
if (ret)
goto out_dp_init;
+ /*
+ * According to DP spec v1.3 chap 3.5.1.2 Link Training,
+ * We should first make sure the HPD signal is asserted high by device
+ * when we want to establish a link with it.
+ */
+ ret = analogix_dp_detect_hpd(dp);
+ if (ret) {
+ DRM_ERROR("failed to get hpd single ret = %d\n", ret);
+ goto out_dp_init;
+ }
+
ret = analogix_dp_commit(dp);
if (ret)
goto out_dp_init;
--
2.17.0
On Monday, April 23, 2018 6:50 AM, Enric Balletbo i Serra wrote:
>
> From: zain wang <[email protected]>
>
> There is no register named ANALOGIX_DP_PLL_CTL in Rockchip edp phy reg
> list. We should use BIT_4 in ANALOGIX_DP_PD to control the pll power
> instead of ANALOGIX_DP_PLL_CTL.
>
> Cc: Douglas Anderson <[email protected]>
> Signed-off-by: zain wang <[email protected]>
> Signed-off-by: Sean Paul <[email protected]>
> Signed-off-by: Thierry Escande <[email protected]>
> Reviewed-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Enric Balletbo i Serra <[email protected]>
> Tested-by: Marek Szyprowski <[email protected]>
> Reviewed-by: Archit Taneja <[email protected]>
Acked-by: Jingoo Han <[email protected]>
Best regards,
Jingoo Han
> ---
>
> .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 20 +++++++++++--------
> 1 file changed, 12 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> index 7b7fd227e1f9..02ab1aaa9993 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> @@ -230,16 +230,20 @@ enum pll_status
> analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp)
> void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool
> enable)
> {
> u32 reg;
> + u32 mask = DP_PLL_PD;
> + u32 pd_addr = ANALOGIX_DP_PLL_CTL;
>
> - if (enable) {
> - reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL);
> - reg |= DP_PLL_PD;
> - writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL);
> - } else {
> - reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL);
> - reg &= ~DP_PLL_PD;
> - writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL);
> + if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {
> + pd_addr = ANALOGIX_DP_PD;
> + mask = RK_PLL_PD;
> }
> +
> + reg = readl(dp->reg_base + pd_addr);
> + if (enable)
> + reg |= mask;
> + else
> + reg &= ~mask;
> + writel(reg, dp->reg_base + pd_addr);
> }
>
> void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
> --
> 2.17.0
On Monday, April 23, 2018 6:50 AM, Enric Balletbo i Serra wrote:
>
> From: zain wang <[email protected]>
>
> Register ANALOGIX_DP_FUNC_EN_1(offset 0x18), Rockchip is different to
> Exynos:
>
> on Exynos edp phy,
> BIT 7 MASTER_VID_FUNC_EN_N
> BIT 6 reserved
> BIT 5 SLAVE_VID_FUNC_EN_N
>
> on Rockchip edp phy,
> BIT 7 reserved
> BIT 6 RK_VID_CAP_FUNC_EN_N
> BIT 5 RK_VID_FIFO_FUNC_EN_N
>
> So, we should do some private operations to Rockchip.
>
> Cc: Tomasz Figa <[email protected]>
> Signed-off-by: zain wang <[email protected]>
> Signed-off-by: Sean Paul <[email protected]>
> Signed-off-by: Thierry Escande <[email protected]>
> Reviewed-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Enric Balletbo i Serra <[email protected]>
> Tested-by: Marek Szyprowski <[email protected]>
> Reviewed-by: Archit Taneja <[email protected]>
Acked-by: Jingoo Han <[email protected]>
Best regards,
Jingoo Han
> ---
>
> .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 19 ++++++++++++++-----
> .../gpu/drm/bridge/analogix/analogix_dp_reg.h | 2 ++
> 2 files changed, 16 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> index 02ab1aaa9993..4eae206ec31b 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> @@ -126,9 +126,14 @@ void analogix_dp_reset(struct analogix_dp_device *dp)
> analogix_dp_stop_video(dp);
> analogix_dp_enable_video_mute(dp, 0);
>
> - reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
> - AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
> - HDCP_FUNC_EN_N | SW_FUNC_EN_N;
> + if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
> + reg = RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N |
> + SW_FUNC_EN_N;
> + else
> + reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
> + AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
> + HDCP_FUNC_EN_N | SW_FUNC_EN_N;
> +
> writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
>
> reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
> @@ -971,8 +976,12 @@ void analogix_dp_config_video_slave_mode(struct
> analogix_dp_device *dp)
> u32 reg;
>
> reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
> - reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);
> - reg |= MASTER_VID_FUNC_EN_N;
> + if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {
> + reg &= ~(RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N);
> + } else {
> + reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);
> + reg |= MASTER_VID_FUNC_EN_N;
> + }
> writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
>
> reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> index b633a4a5082a..0cf27c731727 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> @@ -127,7 +127,9 @@
>
> /* ANALOGIX_DP_FUNC_EN_1 */
> #define MASTER_VID_FUNC_EN_N (0x1 << 7)
> +#define RK_VID_CAP_FUNC_EN_N (0x1 << 6)
> #define SLAVE_VID_FUNC_EN_N (0x1 << 5)
> +#define RK_VID_FIFO_FUNC_EN_N (0x1 << 5)
> #define AUD_FIFO_FUNC_EN_N (0x1 << 4)
> #define AUD_FUNC_EN_N (0x1 << 3)
> #define HDCP_FUNC_EN_N (0x1 << 2)
> --
> 2.17.0
On 23.04.2018 12:49, Enric Balletbo i Serra wrote:
> Hi Andrzej,
>
> This is the rebased version of v6 series. This patchset includes cleanups,
> improvements, and bug fixes for Rockchip DRM driver and PSR support.
>
> This version is a RESEND of v6 with few changes. The following two
> patches are not included and will be send in a separate patchset for
> further discussion.
>
> - [PATCH v6 24/30] drm/rockchip: Disable PSR on input events
> - [PATCH v6 25/30] drm/rockchip: Cancel PSR enable work before changing
> the state
>
> The following patch was remove as is not needed.
>
> - [PATCH v6 28/30] drm/rockchip: Disable PSR from reboot notifier
>
> I think that the other patches have the required tags and are ready to
> be merged.
Queued to drm-misc-next.
Regards
Andrzej
>
> Regards,
> Enric
>
> Changes in v6:
> - Removed the following patches as are already applied.
> [PATCH v5 01/36] drm/bridge: analogix_dp: detect Sink PSR state after
> configuring the PSR
> [PATCH v5 02/36] drm/rockchip: Remove analogix psr worker
> [PATCH v5 03/36] drm/bridge: analogix_dp: Don't change psr while
> bridge is disabled
> - Explain in the commit message why we need to increase
> the delay in the timeout loop in
> [PATCH v5 07/36] drm/bridge: analogix_dp: Move enable video into
> config_video()
> - Add Reviewed-by: Archit Taneja <[email protected]> for the
> drm/bridge parts
> - Add Reviewed-by: Heiko Stuebner <[email protected]> for
> [PATCH v5 19/36] drm/rockchip: Restore psr->state when enable/disable
> psr failed
>
> Changes in v5:
> - Removed the following patches as are already applied.
> [PATCH v4 01/38] drm/bridge: analogix_dp: set psr activate/deactivate
> when enable/disable bridge
> [PATCH v4 02/38] drm/rockchip: Don't use atomic constructs for psr
> - Add Mareks tested-tag and including the missing people.
> - [PATCH v4 15/38] move analogix_dp_set_analog_power_down() before
> phy_power_off() to fix Exynos issue.
>
> Changes in v4:
> - Rebased all on top of drm-misc-next
> - Removed the following patches as are already applied.
> [PATCH v3 01/43] drm/rockchip: Get rid of unnecessary struct fields
> [PATCH v3 02/43] drm/rockchip: support prime import sg table
> [PATCH v3 03/43] drm/rockchip: Respect page offset for PRIME mmap
> calls
> - Removed the following patches as now are part of another patchset
> [PATCH v3 05/43] drm/bridge: analogix_dp: Don't power bridge in
> analogix_dp_bind
> [PATCH v3 33/43] drm/panel: simple: Change mode for Sharp lq123p1jx31
>
> Changes in v3:
> - Addressed some of the comments from Sean on the v2
>
> Changes in v2:
> - A few patches have been replaced by newer and cleaner versions from
> the ChromeOS kernel gerrit, especially about disallowing PSR for the
> whole atomic commit.
>
>
> Douglas Anderson (4):
> drm/bridge: analogix_dp: Reorder plat_data->power_off to happen sooner
> drm/bridge: analogix_dp: Properly log AUX CH errors
> drm/bridge: analogix_dp: Properly disable aux chan retries on rockchip
> drm/bridge: analogix_dp: Split the platform-specific poweron in two
> parts
>
> Lin Huang (6):
> drm/bridge: analogix_dp: Move enable video into config_video()
> drm/bridge: analogix_dp: Check AUX_EN status when doing AUX transfer
> drm/bridge: analogix_dp: Ensure edp is disabled when shutting down the
> panel
> drm/bridge: analogix_dp: Extend hpd check time to 100ms
> drm/bridge: analogix_dp: Check dpcd write/read status
> drm/bridge: analogix_dp: Reset aux channel if an error occurred
>
> Mark Yao (1):
> drm/rockchip: pre dither down when output bpc is 8bit
>
> Tomasz Figa (5):
> drm/rockchip: analogix_dp: Do not call Analogix code before bind
> drm/rockchip: psr: Avoid redundant calls to .set() callback
> drm/rockchip: psr: Sanitize semantics of allow/inhibit API
> drm/rockchip: Disallow PSR for the whole atomic commit
> drm/rockchip: psr: Remove flush by CRTC
>
> zain wang (11):
> drm/bridge: analogix_dp: Don't use fast link training when panel just
> powered up
> drm/bridge: analogix_dp: Retry bridge enable when it failed
> drm/bridge: analogix_dp: Wait for HPD signal before configuring link
> drm/bridge: analogix_dp: Set PD_INC_BG first when powering up edp phy
> drm/bridge: analogix_dp: Fix incorrect usage of enhanced mode
> drm/bridge: analogix_dp: Fix AUX_PD bit for Rockchip
> drm/rockchip: Restore psr->state when enable/disable psr failed
> drm/bridge: analogix_dp: Don't use ANALOGIX_DP_PLL_CTL to control pll
> drm/bridge: analogix_dp: Fix timeout of video streamclk config
> drm/bridge: analogix_dp: Fix incorrect operations with register
> ANALOGIX_DP_FUNC_EN_1
> drm/bridge: analogix_dp: Move fast link training detect to set_bridge
>
> .../drm/bridge/analogix/analogix_dp_core.c | 331 +++++++++++++-----
> .../drm/bridge/analogix/analogix_dp_core.h | 5 +-
> .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 236 +++++++------
> .../gpu/drm/bridge/analogix/analogix_dp_reg.h | 7 +
> drivers/gpu/drm/exynos/exynos_dp.c | 2 +-
> .../gpu/drm/rockchip/analogix_dp-rockchip.c | 37 +-
> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
> drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 61 +++-
> drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 158 ++++-----
> drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 7 +-
> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 13 +-
> drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 1 +
> drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 +
> include/drm/bridge/analogix_dp.h | 3 +-
> 14 files changed, 559 insertions(+), 304 deletions(-)
>
On Monday, April 23, 2018 6:50 AM, Enric Balletbo i Serra wrote:
>
> From: Lin Huang <[email protected]>
>
> We need to check the dpcd write/read return value to see whether the
> write/read was successful
>
> Cc: Kristian H. Kristensen <[email protected]>
> Signed-off-by: Lin Huang <[email protected]>
> Signed-off-by: zain wang <[email protected]>
> Signed-off-by: Douglas Anderson <[email protected]>
> Signed-off-by: Sean Paul <[email protected]>
> Signed-off-by: Thierry Escande <[email protected]>
> Reviewed-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Enric Balletbo i Serra <[email protected]>
> Tested-by: Marek Szyprowski <[email protected]>
> Reviewed-by: Archit Taneja <[email protected]>
Acked-by: Jingoo Han <[email protected]>
Best regards,
Jingoo Han
> ---
>
> .../drm/bridge/analogix/analogix_dp_core.c | 169 +++++++++++++-----
> 1 file changed, 127 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 1e1743b59c77..75e61ebf6722 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -160,80 +160,137 @@ int analogix_dp_disable_psr(struct
> analogix_dp_device *dp)
> }
> EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
>
> -static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
> +static int analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
> {
> unsigned char psr_version;
> + int ret;
> +
> + ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version);
> + if (ret != 1) {
> + dev_err(dp->dev, "failed to get PSR version, disable it\n");
> + return ret;
> + }
>
> - drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version);
> dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
>
> - return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
> + dp->psr_enable = (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
> +
> + return 0;
> }
>
> -static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
> +static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
> {
> unsigned char psr_en;
> + int ret;
>
> /* Disable psr function */
> - drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en);
> + ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en);
> + if (ret != 1) {
> + dev_err(dp->dev, "failed to get psr config\n");
> + goto end;
> + }
> +
> psr_en &= ~DP_PSR_ENABLE;
> - drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
> + ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
> + if (ret != 1) {
> + dev_err(dp->dev, "failed to disable panel psr\n");
> + goto end;
> + }
>
> /* Main-Link transmitter remains active during PSR active states */
> psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
> - drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
> + ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
> + if (ret != 1) {
> + dev_err(dp->dev, "failed to set panel psr\n");
> + goto end;
> + }
>
> /* Enable psr function */
> psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
> DP_PSR_CRC_VERIFICATION;
> - drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
> + ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
> + if (ret != 1) {
> + dev_err(dp->dev, "failed to set panel psr\n");
> + goto end;
> + }
>
> analogix_dp_enable_psr_crc(dp);
> +
> + return 0;
> +end:
> + dev_err(dp->dev, "enable psr fail, force to disable psr\n");
> + dp->psr_enable = false;
> +
> + return ret;
> }
>
> -static void
> +static int
> analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp,
> bool enable)
> {
> u8 data;
> + int ret;
>
> - drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data);
> + ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data);
> + if (ret != 1)
> + return ret;
>
> if (enable)
> - drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
> - DP_LANE_COUNT_ENHANCED_FRAME_EN |
> - DPCD_LANE_COUNT_SET(data));
> + ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
> + DP_LANE_COUNT_ENHANCED_FRAME_EN |
> + DPCD_LANE_COUNT_SET(data));
> else
> - drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
> - DPCD_LANE_COUNT_SET(data));
> + ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
> + DPCD_LANE_COUNT_SET(data));
> +
> + return ret < 0 ? ret : 0;
> }
>
> -static int analogix_dp_is_enhanced_mode_available(struct
> analogix_dp_device *dp)
> +static int analogix_dp_is_enhanced_mode_available(struct
> analogix_dp_device *dp,
> + u8 *enhanced_mode_support)
> {
> u8 data;
> - int retval;
> + int ret;
>
> - drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
> - retval = DPCD_ENHANCED_FRAME_CAP(data);
> + ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
> + if (ret != 1) {
> + *enhanced_mode_support = 0;
> + return ret;
> + }
>
> - return retval;
> + *enhanced_mode_support = DPCD_ENHANCED_FRAME_CAP(data);
> +
> + return 0;
> }
>
> -static void analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp)
> +static int analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp)
> {
> u8 data;
> + int ret;
> +
> + ret = analogix_dp_is_enhanced_mode_available(dp, &data);
> + if (ret < 0)
> + return ret;
> +
> + ret = analogix_dp_enable_rx_to_enhanced_mode(dp, data);
> + if (ret < 0)
> + return ret;
>
> - data = analogix_dp_is_enhanced_mode_available(dp);
> - analogix_dp_enable_rx_to_enhanced_mode(dp, data);
> analogix_dp_enable_enhanced_mode(dp, data);
> +
> + return 0;
> }
>
> -static void analogix_dp_training_pattern_dis(struct analogix_dp_device
> *dp)
> +static int analogix_dp_training_pattern_dis(struct analogix_dp_device
*dp)
> {
> + int ret;
> +
> analogix_dp_set_training_pattern(dp, DP_NONE);
>
> - drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
> - DP_TRAINING_PATTERN_DISABLE);
> + ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
> + DP_TRAINING_PATTERN_DISABLE);
> +
> + return ret < 0 ? ret : 0;
> }
>
> static void
> @@ -282,7 +339,11 @@ static int analogix_dp_link_start(struct
> analogix_dp_device *dp)
> if (retval < 0)
> return retval;
> /* set enhanced mode if available */
> - analogix_dp_set_enhanced_mode(dp);
> + retval = analogix_dp_set_enhanced_mode(dp);
> + if (retval < 0) {
> + dev_err(dp->dev, "failed to set enhance mode\n");
> + return retval;
> + }
>
> /* Set TX pre-emphasis to minimum */
> for (lane = 0; lane < lane_count; lane++)
> @@ -567,10 +628,11 @@ static int
> analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
>
> if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count))
> {
> /* traing pattern Set to Normal */
> - analogix_dp_training_pattern_dis(dp);
> + retval = analogix_dp_training_pattern_dis(dp);
> + if (retval < 0)
> + return retval;
>
> dev_info(dp->dev, "Link Training success!\n");
> -
> analogix_dp_get_link_bandwidth(dp, ®);
> dp->link_train.link_rate = reg;
> dev_dbg(dp->dev, "final bandwidth = %.2x\n",
> @@ -867,24 +929,32 @@ static int analogix_dp_config_video(struct
> analogix_dp_device *dp)
> return 0;
> }
>
> -static void analogix_dp_enable_scramble(struct analogix_dp_device *dp,
> - bool enable)
> +static int analogix_dp_enable_scramble(struct analogix_dp_device *dp,
> + bool enable)
> {
> u8 data;
> + int ret;
>
> if (enable) {
> analogix_dp_enable_scrambling(dp);
>
> - drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data);
> - drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
> + ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
> + &data);
> + if (ret != 1)
> + return ret;
> + ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
> (u8)(data &
~DP_LINK_SCRAMBLING_DISABLE));
> } else {
> analogix_dp_disable_scrambling(dp);
>
> - drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data);
> - drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
> + ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
> + &data);
> + if (ret != 1)
> + return ret;
> + ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
> (u8)(data | DP_LINK_SCRAMBLING_DISABLE));
> }
> + return ret < 0 ? ret : 0;
> }
>
> static irqreturn_t analogix_dp_hardirq(int irq, void *arg)
> @@ -939,23 +1009,36 @@ static int analogix_dp_commit(struct
> analogix_dp_device *dp)
> return ret;
> }
>
> - analogix_dp_enable_scramble(dp, 1);
> + ret = analogix_dp_enable_scramble(dp, 1);
> + if (ret < 0) {
> + dev_err(dp->dev, "can not enable scramble\n");
> + return ret;
> + }
>
> analogix_dp_init_video(dp);
> ret = analogix_dp_config_video(dp);
> - if (ret)
> + if (ret) {
> dev_err(dp->dev, "unable to config video\n");
> + return ret;
> + }
>
> /* Safe to enable the panel now */
> if (dp->plat_data->panel) {
> - if (drm_panel_enable(dp->plat_data->panel))
> + ret = drm_panel_enable(dp->plat_data->panel);
> + if (ret) {
> DRM_ERROR("failed to enable the panel\n");
> + return ret;
> + }
> }
>
> - dp->psr_enable = analogix_dp_detect_sink_psr(dp);
> + ret = analogix_dp_detect_sink_psr(dp);
> + if (ret)
> + return ret;
> +
> if (dp->psr_enable)
> - analogix_dp_enable_sink_psr(dp);
> - return 0;
> + ret = analogix_dp_enable_sink_psr(dp);
> +
> + return ret;
> }
>
> /*
> @@ -1185,8 +1268,10 @@ static int analogix_dp_set_bridge(struct
> analogix_dp_device *dp)
> }
>
> ret = analogix_dp_commit(dp);
> - if (ret)
> + if (ret) {
> + DRM_ERROR("dp commit error, ret = %d\n", ret);
> goto out_dp_init;
> + }
>
> enable_irq(dp->irq);
> return 0;
> --
> 2.17.0
On Monday, April 23, 2018 6:50 AM, Enric Balletbo i Serra wrote:
>
> From: zain wang <[email protected]>
>
> There are some different bits between Rockchip and Exynos in register
> "AUX_PD". This patch fixes the incorrect operations about it.
>
> Cc: Douglas Anderson <[email protected]>
> Signed-off-by: zain wang <[email protected]>
> Signed-off-by: Sean Paul <[email protected]>
> Signed-off-by: Thierry Escande <[email protected]>
> Reviewed-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Enric Balletbo i Serra <[email protected]>
> Tested-by: Marek Szyprowski <[email protected]>
> Reviewed-by: Archit Taneja <[email protected]>
Acked-by: Jingoo Han <[email protected]>
Best regards,
Jingoo Han
> ---
>
> .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 117 ++++++++++--------
> .../gpu/drm/bridge/analogix/analogix_dp_reg.h | 2 +
> 2 files changed, 65 insertions(+), 54 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> index bb72f8b0e603..dee1ba109b5f 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> @@ -248,76 +248,85 @@ void analogix_dp_set_analog_power_down(struct
> analogix_dp_device *dp,
> {
> u32 reg;
> u32 phy_pd_addr = ANALOGIX_DP_PHY_PD;
> + u32 mask;
>
> if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
> phy_pd_addr = ANALOGIX_DP_PD;
>
> switch (block) {
> case AUX_BLOCK:
> - if (enable) {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg |= AUX_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - } else {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg &= ~AUX_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - }
> + if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
> + mask = RK_AUX_PD;
> + else
> + mask = AUX_PD;
> +
> + reg = readl(dp->reg_base + phy_pd_addr);
> + if (enable)
> + reg |= mask;
> + else
> + reg &= ~mask;
> + writel(reg, dp->reg_base + phy_pd_addr);
> break;
> case CH0_BLOCK:
> - if (enable) {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg |= CH0_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - } else {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg &= ~CH0_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - }
> + mask = CH0_PD;
> + reg = readl(dp->reg_base + phy_pd_addr);
> +
> + if (enable)
> + reg |= mask;
> + else
> + reg &= ~mask;
> + writel(reg, dp->reg_base + phy_pd_addr);
> break;
> case CH1_BLOCK:
> - if (enable) {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg |= CH1_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - } else {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg &= ~CH1_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - }
> + mask = CH1_PD;
> + reg = readl(dp->reg_base + phy_pd_addr);
> +
> + if (enable)
> + reg |= mask;
> + else
> + reg &= ~mask;
> + writel(reg, dp->reg_base + phy_pd_addr);
> break;
> case CH2_BLOCK:
> - if (enable) {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg |= CH2_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - } else {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg &= ~CH2_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - }
> + mask = CH2_PD;
> + reg = readl(dp->reg_base + phy_pd_addr);
> +
> + if (enable)
> + reg |= mask;
> + else
> + reg &= ~mask;
> + writel(reg, dp->reg_base + phy_pd_addr);
> break;
> case CH3_BLOCK:
> - if (enable) {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg |= CH3_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - } else {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg &= ~CH3_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - }
> + mask = CH3_PD;
> + reg = readl(dp->reg_base + phy_pd_addr);
> +
> + if (enable)
> + reg |= mask;
> + else
> + reg &= ~mask;
> + writel(reg, dp->reg_base + phy_pd_addr);
> break;
> case ANALOG_TOTAL:
> - if (enable) {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg |= DP_PHY_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - } else {
> - reg = readl(dp->reg_base + phy_pd_addr);
> - reg &= ~DP_PHY_PD;
> - writel(reg, dp->reg_base + phy_pd_addr);
> - }
> + /*
> + * There is no bit named DP_PHY_PD, so We used DP_INC_BG
> + * to power off everything instead of DP_PHY_PD in
> + * Rockchip
> + */
> + if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
> + mask = DP_INC_BG;
> + else
> + mask = DP_PHY_PD;
> +
> + reg = readl(dp->reg_base + phy_pd_addr);
> + if (enable)
> + reg |= mask;
> + else
> + reg &= ~mask;
> +
> + writel(reg, dp->reg_base + phy_pd_addr);
> + if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
> + usleep_range(10, 15);
> break;
> case POWER_ALL:
> if (enable) {
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> index 9602668669f4..b633a4a5082a 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> @@ -345,7 +345,9 @@
> #define DP_INC_BG (0x1 << 7)
> #define DP_EXP_BG (0x1 << 6)
> #define DP_PHY_PD (0x1 << 5)
> +#define RK_AUX_PD (0x1 << 5)
> #define AUX_PD (0x1 << 4)
> +#define RK_PLL_PD (0x1 << 4)
> #define CH3_PD (0x1 << 3)
> #define CH2_PD (0x1 << 2)
> #define CH1_PD (0x1 << 1)
> --
> 2.17.0
On Monday, April 23, 2018 6:50 AM, Enric Balletbo i Serra wrote:
>
> From: Douglas Anderson <[email protected]>
>
> Some of the platform-specific stuff in rockchip_dp_poweron() needs to
> happen before the generic code. Some needs to happen after. Let's
> split the callback in two.
>
> Specifically we can't start doing PSR work until _after_ the whole
> controller is up, so don't set the enable until the end.
>
> Cc: Kristian H. Kristensen <[email protected]>
> Signed-off-by: Douglas Anderson <[email protected]>
> [seanpaul added exynos change]
> Signed-off-by: Sean Paul <[email protected]>
> Signed-off-by: Thierry Escande <[email protected]>
> Reviewed-by: Andrzej Hajda <[email protected]>
> Signed-off-by: Enric Balletbo i Serra <[email protected]>
> Tested-by: Marek Szyprowski <[email protected]>
> Reviewed-by: Archit Taneja <[email protected]>
Acked-by: Jingoo Han <[email protected]>
Best regards,
Jingoo Han
> ---
>
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 7 +++++--
> drivers/gpu/drm/exynos/exynos_dp.c | 2 +-
> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 12 ++++++++++--
> include/drm/bridge/analogix_dp.h | 3 ++-
> 4 files changed, 18 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index a260de4f0bd8..2bcbfadb6ac5 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1260,8 +1260,8 @@ static int analogix_dp_set_bridge(struct
> analogix_dp_device *dp)
> goto out_dp_clk_pre;
> }
>
> - if (dp->plat_data->power_on)
> - dp->plat_data->power_on(dp->plat_data);
> + if (dp->plat_data->power_on_start)
> + dp->plat_data->power_on_start(dp->plat_data);
>
> phy_power_on(dp->phy);
>
> @@ -1286,6 +1286,9 @@ 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;
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c
> b/drivers/gpu/drm/exynos/exynos_dp.c
> index 964831dab102..86330f396784 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -162,7 +162,7 @@ static int exynos_dp_bind(struct device *dev, struct
> device *master, void *data)
> dp->drm_dev = drm_dev;
>
> dp->plat_data.dev_type = EXYNOS_DP;
> - dp->plat_data.power_on = exynos_dp_poweron;
> + dp->plat_data.power_on_start = exynos_dp_poweron;
> dp->plat_data.power_off = exynos_dp_poweroff;
> dp->plat_data.attach = exynos_dp_bridge_attach;
> dp->plat_data.get_modes = exynos_dp_get_modes;
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index b3f46ed24cdc..23317a2269e1 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -109,7 +109,7 @@ static int rockchip_dp_pre_init(struct
> rockchip_dp_device *dp)
> return 0;
> }
>
> -static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
> +static int rockchip_dp_poweron_start(struct analogix_dp_plat_data
> *plat_data)
> {
> struct rockchip_dp_device *dp = to_dp(plat_data);
> int ret;
> @@ -127,6 +127,13 @@ static int rockchip_dp_poweron(struct
> analogix_dp_plat_data *plat_data)
> return ret;
> }
>
> + return ret;
> +}
> +
> +static int rockchip_dp_poweron_end(struct analogix_dp_plat_data
> *plat_data)
> +{
> + struct rockchip_dp_device *dp = to_dp(plat_data);
> +
> return rockchip_drm_psr_activate(&dp->encoder);
> }
>
> @@ -330,7 +337,8 @@ static int rockchip_dp_bind(struct device *dev, struct
> device *master,
> dp->plat_data.encoder = &dp->encoder;
>
> dp->plat_data.dev_type = dp->data->chip_type;
> - dp->plat_data.power_on = rockchip_dp_poweron;
> + dp->plat_data.power_on_start = rockchip_dp_poweron_start;
> + dp->plat_data.power_on_end = rockchip_dp_poweron_end;
> dp->plat_data.power_off = rockchip_dp_powerdown;
> dp->plat_data.get_modes = rockchip_dp_get_modes;
>
> diff --git a/include/drm/bridge/analogix_dp.h
> b/include/drm/bridge/analogix_dp.h
> index e9a1116d2f8e..475b706b49de 100644
> --- a/include/drm/bridge/analogix_dp.h
> +++ b/include/drm/bridge/analogix_dp.h
> @@ -33,7 +33,8 @@ struct analogix_dp_plat_data {
> struct drm_connector *connector;
> bool skip_connector;
>
> - int (*power_on)(struct analogix_dp_plat_data *);
> + int (*power_on_start)(struct analogix_dp_plat_data *);
> + int (*power_on_end)(struct analogix_dp_plat_data *);
> int (*power_off)(struct analogix_dp_plat_data *);
> int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *,
> struct drm_connector *);
> --
> 2.17.0
On Monday, April 23, 2018 6:50 AM, Enric Balletbo i Serra wrote:
>
> From: zain wang <[email protected]>
>
> If we failed disable psr, it would hang the display until next psr
> cycle coming. So we should restore psr->state when it failed.
>
> Cc: Tomasz Figa <[email protected]>
> Signed-off-by: zain wang <[email protected]>
> Signed-off-by: Douglas Anderson <[email protected]>
> Signed-off-by: Sean Paul <[email protected]>
> Signed-off-by: Thierry Escande <[email protected]>
> Signed-off-by: Enric Balletbo i Serra <[email protected]>
> Tested-by: Marek Szyprowski <[email protected]>
> Reviewed-by: Heiko Stuebner <[email protected]>
> Reviewed-by: Archit Taneja <[email protected]>
Acked-by: Jingoo Han <[email protected]>
Best regards,
Jingoo Han
> ---
>
> .../drm/bridge/analogix/analogix_dp_core.c | 4 +++-
> .../gpu/drm/rockchip/analogix_dp-rockchip.c | 10 +++++-----
> drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 20 ++++++++++++-------
> drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 2 +-
> 4 files changed, 22 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 75e61ebf6722..5540e2dfc2ec 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -153,8 +153,10 @@ int analogix_dp_disable_psr(struct analogix_dp_device
> *dp)
> psr_vsc.DB1 = 0;
>
> ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
> - if (ret != 1)
> + if (ret != 1) {
> dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret);
> + return ret;
> + }
>
> return analogix_dp_send_psr_spd(dp, &psr_vsc, false);
> }
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index 3e8bf79bea58..8c884f9ce713 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -77,13 +77,13 @@ struct rockchip_dp_device {
> struct analogix_dp_plat_data plat_data;
> };
>
> -static void analogix_dp_psr_set(struct drm_encoder *encoder, bool
enabled)
> +static int analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
> {
> struct rockchip_dp_device *dp = to_dp(encoder);
> int ret;
>
> if (!analogix_dp_psr_enabled(dp->adp))
> - return;
> + return 0;
>
> DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
>
> @@ -91,13 +91,13 @@ static void analogix_dp_psr_set(struct drm_encoder
> *encoder, bool enabled)
> PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
> if (ret) {
> DRM_DEV_ERROR(dp->dev, "line flag interrupt did not
> arrive\n");
> - return;
> + return -ETIMEDOUT;
> }
>
> if (enabled)
> - analogix_dp_enable_psr(dp->adp);
> + return analogix_dp_enable_psr(dp->adp);
> else
> - analogix_dp_disable_psr(dp->adp);
> + return analogix_dp_disable_psr(dp->adp);
> }
>
> static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
> b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
> index b339ca943139..9376f4396b6b 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
> @@ -36,7 +36,7 @@ struct psr_drv {
>
> struct delayed_work flush_work;
>
> - void (*set)(struct drm_encoder *encoder, bool enable);
> + int (*set)(struct drm_encoder *encoder, bool enable);
> };
>
> static struct psr_drv *find_psr_by_crtc(struct drm_crtc *crtc)
> @@ -93,19 +93,25 @@ static void psr_set_state_locked(struct psr_drv *psr,
> enum psr_state state)
> return;
> }
>
> - psr->state = state;
> -
> /* Actually commit the state change to hardware */
> - switch (psr->state) {
> + switch (state) {
> case PSR_ENABLE:
> - psr->set(psr->encoder, true);
> + if (psr->set(psr->encoder, true))
> + return;
> break;
>
> case PSR_DISABLE:
> case PSR_FLUSH:
> - psr->set(psr->encoder, false);
> + if (psr->set(psr->encoder, false))
> + return;
> break;
> +
> + default:
> + pr_err("%s: Unknown state %d\n", __func__, state);
> + return;
> }
> +
> + psr->state = state;
> }
>
> static void psr_set_state(struct psr_drv *psr, enum psr_state state)
> @@ -229,7 +235,7 @@ EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
> * Zero on success, negative errno on failure.
> */
> int rockchip_drm_psr_register(struct drm_encoder *encoder,
> - void (*psr_set)(struct drm_encoder *, bool enable))
> + int (*psr_set)(struct drm_encoder *, bool enable))
> {
> struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
> struct psr_drv *psr;
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
> b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
> index b1ea0155e57c..06537ee27565 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
> @@ -22,7 +22,7 @@ int rockchip_drm_psr_activate(struct drm_encoder
> *encoder);
> int rockchip_drm_psr_deactivate(struct drm_encoder *encoder);
>
> int rockchip_drm_psr_register(struct drm_encoder *encoder,
> - void (*psr_set)(struct drm_encoder *, bool enable));
> + int (*psr_set)(struct drm_encoder *, bool enable));
> void rockchip_drm_psr_unregister(struct drm_encoder *encoder);
>
> #endif /* __ROCKCHIP_DRM_PSR__ */
> --
> 2.17.0