Re: [PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Hi Sean, On 09/12/2016 09:52 PM, Sean Paul wrote: On Fri, Sep 9, 2016 at 5:45 AM, Yakir Yang <y...@rock-chips.com> wrote: Make sure the request PSR state takes effect in analogix_dp_send_psr_spd() function, or print the sink PSR error state if we failed to apply the requested PSR setting. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v3: - Update commit message - Add DP_TIMEOUT_PSR_LOOP_MS marcos - Correct the return values of analogix_dp_send_psr_spd() Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 +++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index d564e90..a27f1e3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -20,6 +20,7 @@ #define MAX_EQ_LOOP 5 #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) +#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300) Same comment here re: units. 300ms seems like a really long time. Why does it take this long? This magic number '300ms' just come from my test, I haven't found the description in eDP 1.4a Spec about what exact time should Sink take to entry PSR. - Yakir Sean /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) @@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 15a4cf0..7fd4ed0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + DP_TIMEOUT_PSR_LOOP_MS; + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, ); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return -EBUSY; + } + + if ((vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) || + (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)) + return 0; + + usleep_range(1000, 1500); + } + + dev_warn(dp->dev, "Failed to apply PSR, sink state was [%x]", sink); + + return -E
Re: [PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Hi Sean, On 09/12/2016 09:52 PM, Sean Paul wrote: On Fri, Sep 9, 2016 at 5:45 AM, Yakir Yang wrote: Make sure the request PSR state takes effect in analogix_dp_send_psr_spd() function, or print the sink PSR error state if we failed to apply the requested PSR setting. Signed-off-by: Yakir Yang --- Changes in v3: - Update commit message - Add DP_TIMEOUT_PSR_LOOP_MS marcos - Correct the return values of analogix_dp_send_psr_spd() Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 +++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index d564e90..a27f1e3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -20,6 +20,7 @@ #define MAX_EQ_LOOP 5 #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) +#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300) Same comment here re: units. 300ms seems like a really long time. Why does it take this long? This magic number '300ms' just come from my test, I haven't found the description in eDP 1.4a Spec about what exact time should Sink take to entry PSR. - Yakir Sean /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) @@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 15a4cf0..7fd4ed0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + DP_TIMEOUT_PSR_LOOP_MS; + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, ); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return -EBUSY; + } + + if ((vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) || + (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)) + return 0; + + usleep_range(1000, 1500); + } + + dev_warn(dp->dev, "Failed to apply PSR, sink state was [%x]", sink); + + return -ETIMEDOUT; } ssize_t analogix_dp_transfer(struct analogix_
Re: [PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop
Hi Sean, On 09/12/2016 09:51 PM, Sean Paul wrote: On Fri, Sep 9, 2016 at 5:44 AM, Yakir Yang <y...@rock-chips.com> wrote: Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v3: - Suggested by Sean Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 3 ++- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 18 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..d564e90 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -16,10 +16,11 @@ #include #include -#define DP_TIMEOUT_LOOP_COUNT 100 #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 +#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) The name suggests the units here are ms, but you're storing jiffies. Do the msecs_to_jiffies conversion down below. I suddenly realized that 'analogix_dp_core.c' also used the 'DP_TIMEOUT_LOOP_COUNT' macros, and 'analogix_dp_core.c' have four kinds of timeout, - DP_TIMEOUT_LOOP_COUNT * 1us - DP_TIMEOUT_LOOP_COUNT * 10us - DP_TIMEOUT_LOOP_COUNT * 100us - DP_TIMEOUT_LOOP_COUNT * 1000us I may guess it's not necessary to replace the 'DP_TIMEOUT_LOOP_COUNT' now :-) - Yakir + /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..15a4cf0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, void analogix_dp_init_analog_func(struct analogix_dp_device *dp) { u32 reg; - int timeout_loop = 0; + unsigned long timeout; analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); @@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct analogix_dp_device *dp) if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { analogix_dp_set_pll_power_down(dp, 0); + timeout = jiffies + DP_TIMEOUT_LOOP_MS; timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_MS); while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "failed to get pll lock status\n"); return; } @@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) { int reg; int retval = 0; - int timeout_loop = 0; + unsigned long timeout; /* Enable AUX CH operation */ reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); @@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); /* Is AUX CH command reply received? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } @@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, { u32 reg; u8 *buffer = msg->buffer; - int timeout_loop = 0; + unsigned long timeout; unsigned int i; int num_transferred = 0; @@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, /* Is AUX CH command reply received? */ /* TODO: Wait for an interrupt instead of looping? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } -- 1.9.1
Re: [PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop
Hi Sean, On 09/12/2016 09:51 PM, Sean Paul wrote: On Fri, Sep 9, 2016 at 5:44 AM, Yakir Yang wrote: Signed-off-by: Yakir Yang --- Changes in v3: - Suggested by Sean Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 3 ++- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 18 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..d564e90 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -16,10 +16,11 @@ #include #include -#define DP_TIMEOUT_LOOP_COUNT 100 #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 +#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) The name suggests the units here are ms, but you're storing jiffies. Do the msecs_to_jiffies conversion down below. I suddenly realized that 'analogix_dp_core.c' also used the 'DP_TIMEOUT_LOOP_COUNT' macros, and 'analogix_dp_core.c' have four kinds of timeout, - DP_TIMEOUT_LOOP_COUNT * 1us - DP_TIMEOUT_LOOP_COUNT * 10us - DP_TIMEOUT_LOOP_COUNT * 100us - DP_TIMEOUT_LOOP_COUNT * 1000us I may guess it's not necessary to replace the 'DP_TIMEOUT_LOOP_COUNT' now :-) - Yakir + /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..15a4cf0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, void analogix_dp_init_analog_func(struct analogix_dp_device *dp) { u32 reg; - int timeout_loop = 0; + unsigned long timeout; analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); @@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct analogix_dp_device *dp) if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { analogix_dp_set_pll_power_down(dp, 0); + timeout = jiffies + DP_TIMEOUT_LOOP_MS; timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_MS); while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "failed to get pll lock status\n"); return; } @@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) { int reg; int retval = 0; - int timeout_loop = 0; + unsigned long timeout; /* Enable AUX CH operation */ reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); @@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); /* Is AUX CH command reply received? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } @@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, { u32 reg; u8 *buffer = msg->buffer; - int timeout_loop = 0; + unsigned long timeout; unsigned int i; int num_transferred = 0; @@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, /* Is AUX CH command reply received? */ /* TODO: Wait for an interrupt instead of looping? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } -- 1.9.1
[PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop
Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v3: - Suggested by Sean Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 3 ++- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 18 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..d564e90 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -16,10 +16,11 @@ #include #include -#define DP_TIMEOUT_LOOP_COUNT 100 #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 +#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) + /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..15a4cf0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, void analogix_dp_init_analog_func(struct analogix_dp_device *dp) { u32 reg; - int timeout_loop = 0; + unsigned long timeout; analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); @@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct analogix_dp_device *dp) if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { analogix_dp_set_pll_power_down(dp, 0); + timeout = jiffies + DP_TIMEOUT_LOOP_MS; while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "failed to get pll lock status\n"); return; } @@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) { int reg; int retval = 0; - int timeout_loop = 0; + unsigned long timeout; /* Enable AUX CH operation */ reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); @@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); /* Is AUX CH command reply received? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } @@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, { u32 reg; u8 *buffer = msg->buffer; - int timeout_loop = 0; + unsigned long timeout; unsigned int i; int num_transferred = 0; @@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, /* Is AUX CH command reply received? */ /* TODO: Wait for an interrupt instead of looping? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } -- 1.9.1
[PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Make sure the request PSR state takes effect in analogix_dp_send_psr_spd() function, or print the sink PSR error state if we failed to apply the requested PSR setting. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v3: - Update commit message - Add DP_TIMEOUT_PSR_LOOP_MS marcos - Correct the return values of analogix_dp_send_psr_spd() Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 +++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index d564e90..a27f1e3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -20,6 +20,7 @@ #define MAX_EQ_LOOP 5 #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) +#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300) /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) @@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 15a4cf0..7fd4ed0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + DP_TIMEOUT_PSR_LOOP_MS; + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, ); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return -EBUSY; + } + + if ((vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) || + (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)) + return 0; + + usleep_range(1000, 1500); + } + + dev_warn(dp->dev, "Failed to apply PSR, sink state was [%x]", sink); + + return -ETIMEDOUT; } ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, -- 1.9.1
[PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop
Signed-off-by: Yakir Yang --- Changes in v3: - Suggested by Sean Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 3 ++- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 18 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..d564e90 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -16,10 +16,11 @@ #include #include -#define DP_TIMEOUT_LOOP_COUNT 100 #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 +#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) + /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..15a4cf0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, void analogix_dp_init_analog_func(struct analogix_dp_device *dp) { u32 reg; - int timeout_loop = 0; + unsigned long timeout; analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); @@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct analogix_dp_device *dp) if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { analogix_dp_set_pll_power_down(dp, 0); + timeout = jiffies + DP_TIMEOUT_LOOP_MS; while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "failed to get pll lock status\n"); return; } @@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) { int reg; int retval = 0; - int timeout_loop = 0; + unsigned long timeout; /* Enable AUX CH operation */ reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); @@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp) writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); /* Is AUX CH command reply received? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } @@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, { u32 reg; u8 *buffer = msg->buffer; - int timeout_loop = 0; + unsigned long timeout; unsigned int i; int num_transferred = 0; @@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, /* Is AUX CH command reply received? */ /* TODO: Wait for an interrupt instead of looping? */ + timeout = jiffies + DP_TIMEOUT_LOOP_MS; reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { + if (time_after(jiffies, timeout)) { dev_err(dp->dev, "AUX CH command reply failed!\n"); return -ETIMEDOUT; } -- 1.9.1
[PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Make sure the request PSR state takes effect in analogix_dp_send_psr_spd() function, or print the sink PSR error state if we failed to apply the requested PSR setting. Signed-off-by: Yakir Yang --- Changes in v3: - Update commit message - Add DP_TIMEOUT_PSR_LOOP_MS marcos - Correct the return values of analogix_dp_send_psr_spd() Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 +++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index d564e90..a27f1e3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -20,6 +20,7 @@ #define MAX_EQ_LOOP 5 #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1) +#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300) /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) @@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 15a4cf0..7fd4ed0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + DP_TIMEOUT_PSR_LOOP_MS; + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, ); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return -EBUSY; + } + + if ((vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) || + (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)) + return 0; + + usleep_range(1000, 1500); + } + + dev_warn(dp->dev, "Failed to apply PSR, sink state was [%x]", sink); + + return -ETIMEDOUT; } ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, -- 1.9.1
Re: [PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
On 09/08/2016 10:12 PM, Sean Paul wrote: On Wed, Sep 7, 2016 at 11:48 PM, Yakir Yang <y...@rock-chips.com> wrote: Make sure the request PSR state could effect in analogix_dp_send_psr_spd() function, or printing the error Sink PSR state if we failed to effect the request PSR setting. Let's change to: Make sure the request PSR state takes effect in analogix_dp_send_psr_spd() function, or print the sink PSR error state if we failed to apply the requested PSR setting. Done, Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..6c07a50 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..09d703b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT); Mismatched units here. DP_TIMEOUT_LOOP_COUNT is defined as number of retries, whereas you're using it as number of ms. Fortunately, the retry number is so high that this works out :) In a separate patch preceding this one, can you change DP_TIMEOUT_LOOP_COUNT to DP_TIMEOUT_LOOP_MS and alter the other timeout loops to use time_before() like this one instead of blindly looping 100 times? After that, you can use DP_TIMEOUT_LOOP_MS here. Done, and after do some experiments, I found we need to set the timeout to 300ms. Cause in some case we would take about 290ms here to get the right psr state. + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, ); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return val; Ok, since this is my snippet this comment is my fault, and I apologize for that :). However, this could return 0. If drm_dp_dpcd_readb returns 0, you probably want to retry (same as -EBUSY). done, just return -EBUSY + } + + if (vs
Re: [PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
On 09/08/2016 10:12 PM, Sean Paul wrote: On Wed, Sep 7, 2016 at 11:48 PM, Yakir Yang wrote: Make sure the request PSR state could effect in analogix_dp_send_psr_spd() function, or printing the error Sink PSR state if we failed to effect the request PSR setting. Let's change to: Make sure the request PSR state takes effect in analogix_dp_send_psr_spd() function, or print the sink PSR error state if we failed to apply the requested PSR setting. Done, Signed-off-by: Yakir Yang --- Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..6c07a50 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..09d703b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT); Mismatched units here. DP_TIMEOUT_LOOP_COUNT is defined as number of retries, whereas you're using it as number of ms. Fortunately, the retry number is so high that this works out :) In a separate patch preceding this one, can you change DP_TIMEOUT_LOOP_COUNT to DP_TIMEOUT_LOOP_MS and alter the other timeout loops to use time_before() like this one instead of blindly looping 100 times? After that, you can use DP_TIMEOUT_LOOP_MS here. Done, and after do some experiments, I found we need to set the timeout to 300ms. Cause in some case we would take about 290ms here to get the right psr state. + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, ); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return val; Ok, since this is my snippet this comment is my fault, and I apologize for that :). However, this could return 0. If drm_dp_dpcd_readb returns 0, you probably want to retry (same as -EBUSY). done, just return -EBUSY + } + + if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB |
[PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Make sure the request PSR state could effect in analogix_dp_send_psr_spd() function, or printing the error Sink PSR state if we failed to effect the request PSR setting. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..6c07a50 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..09d703b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT); + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, ); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return val; + } + + if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB || + !vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) + break; + + usleep_range(1000, 1500); + } + + dev_warn(dp->dev, "Failed to effect PSR: %x", sink); + + return -ETIMEDOUT; } ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, -- 1.9.1
[PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Make sure the request PSR state could effect in analogix_dp_send_psr_spd() function, or printing the error Sink PSR state if we failed to effect the request PSR setting. Signed-off-by: Yakir Yang --- Changes in v2: - A bunch of good fixes from Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 25 -- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 5fe3982..c0ce16a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index a15f076..6c07a50 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index a4d17b8..09d703b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; unsigned int val; + u8 sink; /* don't send info frame */ val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); @@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT); + while (time_before(jiffies, timeout)) { + val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, ); + if (val != 1) { + dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val); + return val; + } + + if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB || + !vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) + break; + + usleep_range(1000, 1500); + } + + dev_warn(dp->dev, "Failed to effect PSR: %x", sink); + + return -ETIMEDOUT; } ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, -- 1.9.1
[PATCH v2 1/2] drm/bridge: analogix_dp: Remove duplicated code v2
From: Tomeu Vizoso <tomeu.viz...@collabora.com> Remove code for reading the EDID and DPCD fields and use the helpers instead. Besides the obvious code reduction, other helpers are being added to the core that could be used in this driver and will be good to be able to use them instead of duplicating them. Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com> Cc: Javier Martinez Canillas <jav...@osg.samsung.com> Cc: Mika Kahola <mika.kah...@intel.com> Cc: Yakir Yang <y...@rock-chips.com> Cc: Daniel Vetter <daniel.vet...@intel.com> Reviewed-by: Sean Paul <seanp...@chromium.org> Reviewed-by: Yakir Yang <y...@rock-chips.com> Tested-by: Javier Martinez Canillas <jav...@osg.samsung.com> Tested-by: Sean Paul <seanp...@chromium.org> --- Changes in v2: - A bunch of good fixes from Sean and Yakir - Moved the transfer function to analogix_dp_reg.c - Removed reference to the EDID from the dp struct - Rebase on Sean's next tree git://people.freedesktop.org/~seanpaul/dogwood drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 41 +- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 ++--- 3 files changed, 204 insertions(+), 551 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index efac8ab..5fe3982 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -174,150 +175,21 @@ static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) analogix_dp_enable_psr_crc(dp); } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* -* EDID device address is 0x50. -* However, if necessary, you must have set upper address -* into E-EDID in I2C device, 0x30. -*/ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - _block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - [EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - [EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - _vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - D
[PATCH v2 1/2] drm/bridge: analogix_dp: Remove duplicated code v2
From: Tomeu Vizoso Remove code for reading the EDID and DPCD fields and use the helpers instead. Besides the obvious code reduction, other helpers are being added to the core that could be used in this driver and will be good to be able to use them instead of duplicating them. Signed-off-by: Tomeu Vizoso Cc: Javier Martinez Canillas Cc: Mika Kahola Cc: Yakir Yang Cc: Daniel Vetter Reviewed-by: Sean Paul Reviewed-by: Yakir Yang Tested-by: Javier Martinez Canillas Tested-by: Sean Paul --- Changes in v2: - A bunch of good fixes from Sean and Yakir - Moved the transfer function to analogix_dp_reg.c - Removed reference to the EDID from the dp struct - Rebase on Sean's next tree git://people.freedesktop.org/~seanpaul/dogwood drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 41 +- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 ++--- 3 files changed, 204 insertions(+), 551 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index efac8ab..5fe3982 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -174,150 +175,21 @@ static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) analogix_dp_enable_psr_crc(dp); } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* -* EDID device address is 0x50. -* However, if necessary, you must have set upper address -* into E-EDID in I2C device, 0x30. -*/ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - _block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - [EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - [EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - _vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, - DP_TEST_EDID_CHECKSUM_WRITE); - } - } else { - dev_info(dp->dev, "EDID data does not include any extensions.\n"); - - /* Read EDID data */ - retval
Re: [PATCH] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Sean, Thanks for your comments. On 09/07/2016 03:51 AM, Sean Paul wrote: On Fri, Aug 26, 2016 at 6:19 AM, Yakir Yang <y...@rock-chips.com> wrote: Make sure the request PSR state could effect in analogix_dp_send_psr_spd() function, or printing the error Sink PSR state if we failed to effect the request PSR setting. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++--- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 26 -- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index efac8ab..5a37de8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -115,8 +115,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -138,8 +137,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 473b980..f617a9d 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -283,7 +283,7 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 52c1b6b..505e9d8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1328,9 +1328,11 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; + unsigned char sink; u8 Done unsigned int val; /* don't send info frame */ @@ -1372,4 +1374,24 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + msecs_to_jiffies(100); Pull 100 out into a #define Done + while (1) { + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, ); You should be checking return value here. Done + + if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) + break; + + if (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) + break; + + if (time_after(jiffies, timeout)) { + dev_warn(dp->dev, "Failed to effect PSR: %x", sink); + return -EBUSY; -ETIMEDOUT is more appropriate Done + } + + usleep_range(1000, 1500); + } The while(1) loop is a little scary. I'd rather do: while (time_before(jiffies, timeout)) { ret = analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, ); if (ret != 1) { DRM_DEV_ERROR(dp->dev, "PSR_STATUS read failed ret=%d", ret); return ret; } if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB || !vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) return 0; usleep_range(1000, 1500); } dev_warn(dp->dev, "Failed to effect PSR: %x", sink); return -ETIMEDOUT; Thanks for your code. - Yakir + + return 0; } -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Sean, Thanks for your comments. On 09/07/2016 03:51 AM, Sean Paul wrote: On Fri, Aug 26, 2016 at 6:19 AM, Yakir Yang wrote: Make sure the request PSR state could effect in analogix_dp_send_psr_spd() function, or printing the error Sink PSR state if we failed to effect the request PSR setting. Signed-off-by: Yakir Yang --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++--- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 26 -- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index efac8ab..5a37de8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -115,8 +115,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -138,8 +137,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 473b980..f617a9d 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -283,7 +283,7 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 52c1b6b..505e9d8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1328,9 +1328,11 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; + unsigned char sink; u8 Done unsigned int val; /* don't send info frame */ @@ -1372,4 +1374,24 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + msecs_to_jiffies(100); Pull 100 out into a #define Done + while (1) { + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, ); You should be checking return value here. Done + + if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) + break; + + if (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) + break; + + if (time_after(jiffies, timeout)) { + dev_warn(dp->dev, "Failed to effect PSR: %x", sink); + return -EBUSY; -ETIMEDOUT is more appropriate Done + } + + usleep_range(1000, 1500); + } The while(1) loop is a little scary. I'd rather do: while (time_before(jiffies, timeout)) { ret = analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, ); if (ret != 1) { DRM_DEV_ERROR(dp->dev, "PSR_STATUS read failed ret=%d", ret); return ret; } if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB || !vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) return 0; usleep_range(1000, 1500); } dev_warn(dp->dev, "Failed to effect PSR: %x", sink); return -ETIMEDOUT; Thanks for your code. - Yakir + + return 0; } -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Make sure the request PSR state could effect in analogix_dp_send_psr_spd() function, or printing the error Sink PSR state if we failed to effect the request PSR setting. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++--- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 26 -- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index efac8ab..5a37de8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -115,8 +115,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -138,8 +137,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 473b980..f617a9d 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -283,7 +283,7 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 52c1b6b..505e9d8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1328,9 +1328,11 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; + unsigned char sink; unsigned int val; /* don't send info frame */ @@ -1372,4 +1374,24 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + msecs_to_jiffies(100); + while (1) { + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, ); + + if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) + break; + + if (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) + break; + + if (time_after(jiffies, timeout)) { + dev_warn(dp->dev, "Failed to effect PSR: %x", sink); + return -EBUSY; + } + + usleep_range(1000, 1500); + } + + return 0; } -- 1.9.1
[PATCH] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
Make sure the request PSR state could effect in analogix_dp_send_psr_spd() function, or printing the error Sink PSR state if we failed to effect the request PSR setting. Signed-off-by: Yakir Yang --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 6 ++--- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 26 -- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index efac8ab..5a37de8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -115,8 +115,7 @@ int analogix_dp_enable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); @@ -138,8 +137,7 @@ int analogix_dp_disable_psr(struct device *dev) psr_vsc.DB0 = 0; psr_vsc.DB1 = 0; - analogix_dp_send_psr_spd(dp, _vsc); - return 0; + return analogix_dp_send_psr_spd(dp, _vsc); } EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 473b980..f617a9d 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -283,7 +283,7 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc); +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 52c1b6b..505e9d8 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1328,9 +1328,11 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); } -void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, - struct edp_vsc_psr *vsc) +int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, +struct edp_vsc_psr *vsc) { + unsigned long timeout; + unsigned char sink; unsigned int val; /* don't send info frame */ @@ -1372,4 +1374,24 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); val |= IF_EN; writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + timeout = jiffies + msecs_to_jiffies(100); + while (1) { + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, ); + + if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) + break; + + if (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE) + break; + + if (time_after(jiffies, timeout)) { + dev_warn(dp->dev, "Failed to effect PSR: %x", sink); + return -EBUSY; + } + + usleep_range(1000, 1500); + } + + return 0; } -- 1.9.1
Re: [PATCH v5 3/4] drm/bridge: analogix_dp: add the PSR function support
Hello Archit, On 08/17/2016 01:41 PM, Archit Taneja wrote: Hi, On 07/24/2016 12:27 PM, Yakir Yang wrote: The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Could this in any way mess things up if the dev_type is EXYNOS_DP? Nop, I have enabled the panel PSR function by default (if driver detect panel support PSR), but this would active the PSR (cause eDP controller haven't send the right SDP header), which means panel would stay in normal refresh mode on Exynos platform. I also have tested that case on RK3399 platform. Enable the panel PSR, but never call the analogix_dp_active_psr() symbols, and them I found panel still refresh normally. Only when platform driver call the analogix_dp_active_psr()/analogix_dp_inactive_psr() symbols in vblank time, make the controller to send the active SDP header, then panel could enter into PSR mode. Otherwise, Reviewed-by: Archit Taneja <arch...@codeaurora.org> Thanks for your reviewed. - Yakir Signed-off-by: Yakir Yang <y...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> --- Changes in v5: - Add reviewed flag from Sean. Changes in v4.1: - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 + include/drm/bridge/analogix_dp.h | 3 + 5 files changed, 174 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..381b25e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ +struct analogix_dp_device *dp = dev_get_drvdata(dev); +struct edp_vsc_psr psr_vsc; + +if (!dp->psr_support) +return -EINVAL; + +/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ +memset(_vsc, 0, sizeof(psr_vsc)); +psr_vsc.sdp_header.HB0 = 0; +psr_vsc.sdp_header.HB1 = 0x7; +psr_vsc.sdp_header.HB2 = 0x2; +psr_vsc.sdp_header.HB3 = 0x8; + +psr_vsc.DB0 = 0; +psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; + +analogix_dp_send_psr_spd(dp, _vsc); +return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ +struct analogix_dp_device *dp = dev_get_drvdata(dev); +struct edp_vsc_psr psr_vsc; + +if (!dp->psr_support) +return -EINVAL; + +/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ +memset(_vsc, 0, sizeof(psr_vsc)); +psr_vsc.sdp_header.HB0 = 0; +psr_vsc.sdp_header.HB1 = 0x7; +psr_vsc.sdp_header.HB2 = 0x2; +psr_vsc.sdp_header.HB3 = 0x8; + +psr_vsc.DB0 = 0; +psr_vsc.DB1 = 0; + +analogix_dp_send_psr_spd(dp, _vsc); +return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ +unsigned char psr_version; + +analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); +dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + +return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ +unsigned char psr_en; + +/* Disable psr function */ +analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); +psr_en &= ~DP_
Re: [PATCH v5 3/4] drm/bridge: analogix_dp: add the PSR function support
Hello Archit, On 08/17/2016 01:41 PM, Archit Taneja wrote: Hi, On 07/24/2016 12:27 PM, Yakir Yang wrote: The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Could this in any way mess things up if the dev_type is EXYNOS_DP? Nop, I have enabled the panel PSR function by default (if driver detect panel support PSR), but this would active the PSR (cause eDP controller haven't send the right SDP header), which means panel would stay in normal refresh mode on Exynos platform. I also have tested that case on RK3399 platform. Enable the panel PSR, but never call the analogix_dp_active_psr() symbols, and them I found panel still refresh normally. Only when platform driver call the analogix_dp_active_psr()/analogix_dp_inactive_psr() symbols in vblank time, make the controller to send the active SDP header, then panel could enter into PSR mode. Otherwise, Reviewed-by: Archit Taneja Thanks for your reviewed. - Yakir Signed-off-by: Yakir Yang Reviewed-by: Sean Paul --- Changes in v5: - Add reviewed flag from Sean. Changes in v4.1: - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 + include/drm/bridge/analogix_dp.h | 3 + 5 files changed, 174 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..381b25e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ +struct analogix_dp_device *dp = dev_get_drvdata(dev); +struct edp_vsc_psr psr_vsc; + +if (!dp->psr_support) +return -EINVAL; + +/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ +memset(_vsc, 0, sizeof(psr_vsc)); +psr_vsc.sdp_header.HB0 = 0; +psr_vsc.sdp_header.HB1 = 0x7; +psr_vsc.sdp_header.HB2 = 0x2; +psr_vsc.sdp_header.HB3 = 0x8; + +psr_vsc.DB0 = 0; +psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; + +analogix_dp_send_psr_spd(dp, _vsc); +return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ +struct analogix_dp_device *dp = dev_get_drvdata(dev); +struct edp_vsc_psr psr_vsc; + +if (!dp->psr_support) +return -EINVAL; + +/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ +memset(_vsc, 0, sizeof(psr_vsc)); +psr_vsc.sdp_header.HB0 = 0; +psr_vsc.sdp_header.HB1 = 0x7; +psr_vsc.sdp_header.HB2 = 0x2; +psr_vsc.sdp_header.HB3 = 0x8; + +psr_vsc.DB0 = 0; +psr_vsc.DB1 = 0; + +analogix_dp_send_psr_spd(dp, _vsc); +return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ +unsigned char psr_version; + +analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); +dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + +return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ +unsigned char psr_en; + +/* Disable psr function */ +analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); +psr_en &= ~DP_PSR_ENABLE; +analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + +/*
Re: [PATCH v2] drm/bridge: analogix_dp: Ensure the panel is properly prepared/unprepared
+ Archit On 08/09/2016 02:53 AM, Sean Paul wrote: Instead of just preparing the panel on bind, actually prepare/unprepare during modeset/disable. The panel must be prepared in order to read hpd status and edid, so we need to keep state around the prepares in order to ensure we don't accidentally turn the panel off at the wrong time. Signed-off-by: Sean Paul <seanp...@chromium.org> Reviewed-by: Yakir Yang <y...@rock-chips.com> And I also tested this patch on RK3399 Kevin board, panel works rightly, so: Tested-by: Yakir Yang <y...@rock-chips.com> Also add Archit into CC list, guess this patch should go through his drm_bridge's tree. Thanks, - Yakir --- Changes in v2: - Added panel_is_modeset state/lock to avoid racing detect with modeset (marcheu) - Added prepare/unprepare in .get_modes (yakir) drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 101 ++--- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 3 + 2 files changed, 93 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..47c449a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -923,11 +923,63 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) analogix_dp_start_video(dp); } +/* + * This function is a bit of a catch-all for panel preparation, hopefully + * simplifying the logic of functions that need to prepare/unprepare the panel + * below. + * + * If @prepare is true, this function will prepare the panel. Conversely, if it + * is false, the panel will be unprepared. + * + * If @is_modeset_prepare is true, the function will disregard the current state + * of the panel and either prepare/unprepare the panel based on @prepare. Once + * it finishes, it will update dp->panel_is_modeset to reflect the current state + * of the panel. + */ +static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, +bool prepare, bool is_modeset_prepare) +{ + int ret = 0; + + if (!dp->plat_data->panel) + return 0; + + mutex_lock(>panel_lock); + + /* +* Exit early if this is a temporary prepare/unprepare and we're already +* modeset (since we neither want to prepare twice or unprepare early). +*/ + if (dp->panel_is_modeset && !is_modeset_prepare) + goto out; + + if (prepare) + ret = drm_panel_prepare(dp->plat_data->panel); + else + ret = drm_panel_unprepare(dp->plat_data->panel); + + if (ret) + goto out; + + if (is_modeset_prepare) + dp->panel_is_modeset = prepare; + +out: + mutex_unlock(>panel_lock); + return ret; +} + int analogix_dp_get_modes(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); struct edid *edid = (struct edid *)dp->edid; - int num_modes = 0; + int ret, num_modes = 0; + + ret = analogix_dp_prepare_panel(dp, true, false); + if (ret) { + DRM_ERROR("Failed to prepare panel (%d)\n", ret); + return 0; + } if (analogix_dp_handle_edid(dp) == 0) { drm_mode_connector_update_edid_property(>connector, edid); @@ -940,6 +992,10 @@ int analogix_dp_get_modes(struct drm_connector *connector) if (dp->plat_data->get_modes) num_modes += dp->plat_data->get_modes(dp->plat_data, connector); + ret = analogix_dp_prepare_panel(dp, false, false); + if (ret) + DRM_ERROR("Failed to unprepare panel (%d)\n", ret); + return num_modes; } @@ -960,11 +1016,23 @@ enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + enum drm_connector_status status = connector_status_disconnected; + int ret; - if (analogix_dp_detect_hpd(dp)) + ret = analogix_dp_prepare_panel(dp, true, false); + if (ret) { + DRM_ERROR("Failed to prepare panel (%d)\n", ret); return connector_status_disconnected; + } + + if (!analogix_dp_detect_hpd(dp)) + status = connector_status_connected; - return connector_status_connected; + ret = analogix_dp_prepare_panel(dp, false, false); + if (ret) + DRM_ERROR("Failed to unprepare panel (%d)\n", ret); + + return status; } static void analogix_dp_connector_destroy(struct drm_connector *connector) @@ -1035,6 +1103,16 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) return 0; } +static void analogix_dp_bridge_pre_enable(struc
Re: [PATCH v2] drm/bridge: analogix_dp: Ensure the panel is properly prepared/unprepared
+ Archit On 08/09/2016 02:53 AM, Sean Paul wrote: Instead of just preparing the panel on bind, actually prepare/unprepare during modeset/disable. The panel must be prepared in order to read hpd status and edid, so we need to keep state around the prepares in order to ensure we don't accidentally turn the panel off at the wrong time. Signed-off-by: Sean Paul Reviewed-by: Yakir Yang And I also tested this patch on RK3399 Kevin board, panel works rightly, so: Tested-by: Yakir Yang Also add Archit into CC list, guess this patch should go through his drm_bridge's tree. Thanks, - Yakir --- Changes in v2: - Added panel_is_modeset state/lock to avoid racing detect with modeset (marcheu) - Added prepare/unprepare in .get_modes (yakir) drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 101 ++--- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 3 + 2 files changed, 93 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..47c449a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -923,11 +923,63 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) analogix_dp_start_video(dp); } +/* + * This function is a bit of a catch-all for panel preparation, hopefully + * simplifying the logic of functions that need to prepare/unprepare the panel + * below. + * + * If @prepare is true, this function will prepare the panel. Conversely, if it + * is false, the panel will be unprepared. + * + * If @is_modeset_prepare is true, the function will disregard the current state + * of the panel and either prepare/unprepare the panel based on @prepare. Once + * it finishes, it will update dp->panel_is_modeset to reflect the current state + * of the panel. + */ +static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, +bool prepare, bool is_modeset_prepare) +{ + int ret = 0; + + if (!dp->plat_data->panel) + return 0; + + mutex_lock(>panel_lock); + + /* +* Exit early if this is a temporary prepare/unprepare and we're already +* modeset (since we neither want to prepare twice or unprepare early). +*/ + if (dp->panel_is_modeset && !is_modeset_prepare) + goto out; + + if (prepare) + ret = drm_panel_prepare(dp->plat_data->panel); + else + ret = drm_panel_unprepare(dp->plat_data->panel); + + if (ret) + goto out; + + if (is_modeset_prepare) + dp->panel_is_modeset = prepare; + +out: + mutex_unlock(>panel_lock); + return ret; +} + int analogix_dp_get_modes(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); struct edid *edid = (struct edid *)dp->edid; - int num_modes = 0; + int ret, num_modes = 0; + + ret = analogix_dp_prepare_panel(dp, true, false); + if (ret) { + DRM_ERROR("Failed to prepare panel (%d)\n", ret); + return 0; + } if (analogix_dp_handle_edid(dp) == 0) { drm_mode_connector_update_edid_property(>connector, edid); @@ -940,6 +992,10 @@ int analogix_dp_get_modes(struct drm_connector *connector) if (dp->plat_data->get_modes) num_modes += dp->plat_data->get_modes(dp->plat_data, connector); + ret = analogix_dp_prepare_panel(dp, false, false); + if (ret) + DRM_ERROR("Failed to unprepare panel (%d)\n", ret); + return num_modes; } @@ -960,11 +1016,23 @@ enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + enum drm_connector_status status = connector_status_disconnected; + int ret; - if (analogix_dp_detect_hpd(dp)) + ret = analogix_dp_prepare_panel(dp, true, false); + if (ret) { + DRM_ERROR("Failed to prepare panel (%d)\n", ret); return connector_status_disconnected; + } + + if (!analogix_dp_detect_hpd(dp)) + status = connector_status_connected; - return connector_status_connected; + ret = analogix_dp_prepare_panel(dp, false, false); + if (ret) + DRM_ERROR("Failed to unprepare panel (%d)\n", ret); + + return status; } static void analogix_dp_connector_destroy(struct drm_connector *connector) @@ -1035,6 +1103,16 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) return 0; } +static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct analogix_dp_device *dp = bridge->dr
Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code v2
+ Archit Tomeu, Thanks for the update :-) But you have missed three tiny align problems, please see my inline notes, wish you could fix them. After that this patch looks good to me, so: Reviewed-by: Yakir Yang <y...@rock-chips.com> I guess this patch should go through Archit's drm_bridge tree, so I added him into the CC list. - Yakir On 08/05/2016 08:59 PM, Tomeu Vizoso wrote: Remove code for reading the EDID and DPCD fields and use the helpers instead. Besides the obvious code reduction, other helpers are being added to the core that could be used in this driver and will be good to be able to use them instead of duplicating them. Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com> Tested-by: Javier Martinez Canillas <jav...@osg.samsung.com> Tested-by: Sean Paul <seanp...@chromium.org> Cc: Javier Martinez Canillas <jav...@osg.samsung.com> Cc: Mika Kahola <mika.kah...@intel.com> Cc: Yakir Yang <y...@rock-chips.com> Cc: Daniel Vetter <daniel.vet...@intel.com> v2: - A bunch of good fixes from Sean and Yakir - Moved the transfer function to analogix_dp_reg.c - Removed reference to the EDID from the dp struct --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 40 +- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 ++--- 3 files changed, 204 insertions(+), 550 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715daf73cb..624fc4f44450 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* -* EDID device address is 0x50. -* However, if necessary, you must have set upper address -* into E-EDID in I2C device, 0x30. -*/ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - _block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - [EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - [EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - _vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_
Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code v2
+ Archit Tomeu, Thanks for the update :-) But you have missed three tiny align problems, please see my inline notes, wish you could fix them. After that this patch looks good to me, so: Reviewed-by: Yakir Yang I guess this patch should go through Archit's drm_bridge tree, so I added him into the CC list. - Yakir On 08/05/2016 08:59 PM, Tomeu Vizoso wrote: Remove code for reading the EDID and DPCD fields and use the helpers instead. Besides the obvious code reduction, other helpers are being added to the core that could be used in this driver and will be good to be able to use them instead of duplicating them. Signed-off-by: Tomeu Vizoso Tested-by: Javier Martinez Canillas Tested-by: Sean Paul Cc: Javier Martinez Canillas Cc: Mika Kahola Cc: Yakir Yang Cc: Daniel Vetter v2: - A bunch of good fixes from Sean and Yakir - Moved the transfer function to analogix_dp_reg.c - Removed reference to the EDID from the dp struct --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 40 +- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 ++--- 3 files changed, 204 insertions(+), 550 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715daf73cb..624fc4f44450 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* -* EDID device address is 0x50. -* However, if necessary, you must have set upper address -* into E-EDID in I2C device, 0x30. -*/ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - _block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - [EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - [EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - _vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, - DP_TEST_EDID_CHECKSUM_WRITE); -
Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code
Tomeu, o_O Ignore my previous email, seems I make a mistaken about the email format, and mess up the patch format. I have move my previous comments to this one :-) On 08/04/2016 02:23 PM, Tomeu Vizoso wrote: Remove code for reading the EDID and DPCD fields and use the helpers instead. Besides the obvious code reduction, other helpers are being added to the core that could be used in this driver and will be good to be able to use them instead of duplicating them. Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com> Cc: Javier Martinez Canillas <jav...@osg.samsung.com> Cc: Mika Kahola <mika.kah...@intel.com> Cc: Yakir Yang <y...@rock-chips.com> Cc: Daniel Vetter <daniel.vet...@intel.com> --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 +++-- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 39 +-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 324 - 3 files changed, 201 insertions(+), 552 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715daf73cb..c81cb37e56b6 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* -* EDID device address is 0x50. -* However, if necessary, you must have set upper address -* into E-EDID in I2C device, 0x30. -*/ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - _block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - [EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - [EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - _vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, - DP_TEST_EDID_CHECKSUM_WRITE); - } - } else { - dev_info(dp->dev, "EDID data does not include any extensions.\n"); - - /* Read EDID data */ - retval = analogix_dp_read_by
Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code
Tomeu, o_O Ignore my previous email, seems I make a mistaken about the email format, and mess up the patch format. I have move my previous comments to this one :-) On 08/04/2016 02:23 PM, Tomeu Vizoso wrote: Remove code for reading the EDID and DPCD fields and use the helpers instead. Besides the obvious code reduction, other helpers are being added to the core that could be used in this driver and will be good to be able to use them instead of duplicating them. Signed-off-by: Tomeu Vizoso Cc: Javier Martinez Canillas Cc: Mika Kahola Cc: Yakir Yang Cc: Daniel Vetter --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 +++-- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 39 +-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 324 - 3 files changed, 201 insertions(+), 552 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715daf73cb..c81cb37e56b6 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* -* EDID device address is 0x50. -* However, if necessary, you must have set upper address -* into E-EDID in I2C device, 0x30. -*/ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - _block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - [EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - [EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - _vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, - DP_TEST_EDID_CHECKSUM_WRITE); - } - } else { - dev_info(dp->dev, "EDID data does not include any extensions.\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, [EDID_HEA
Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code
Tomeu, Nice job ! Have a few nits bellow. ;) On 08/04/2016 02:23 PM, Tomeu Vizoso wrote: Remove code for reading the EDID and DPCD fields and use the helpers instead. Besides the obvious code reduction, other helpers are being added to the core that could be used in this driver and will be good to be able to use them instead of duplicating them. Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com> Cc: Javier Martinez Canillas <jav...@osg.samsung.com> Cc: Mika Kahola <mika.kah...@intel.com> Cc: Yakir Yang <y...@rock-chips.com> Cc: Daniel Vetter <daniel.vet...@intel.com> --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 +++-- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 39 +-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 324 - 3 files changed, 201 insertions(+), 552 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715daf73cb..c81cb37e56b6 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* -* EDID device address is 0x50. -* However, if necessary, you must have set upper address -* into E-EDID in I2C device, 0x30. -*/ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - _block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - [EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - [EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - _vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, - DP_TEST_EDID_CHECKSUM_WRITE); - } - } else { - dev_info(dp->dev, "EDID data does not include any extensions.\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, -
Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code
Tomeu, Nice job ! Have a few nits bellow. ;) On 08/04/2016 02:23 PM, Tomeu Vizoso wrote: Remove code for reading the EDID and DPCD fields and use the helpers instead. Besides the obvious code reduction, other helpers are being added to the core that could be used in this driver and will be good to be able to use them instead of duplicating them. Signed-off-by: Tomeu Vizoso Cc: Javier Martinez Canillas Cc: Mika Kahola Cc: Yakir Yang Cc: Daniel Vetter --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 +++-- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 39 +-- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 324 - 3 files changed, 201 insertions(+), 552 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715daf73cb..c81cb37e56b6 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* -* EDID device address is 0x50. -* However, if necessary, you must have set upper address -* into E-EDID in I2C device, 0x30. -*/ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - _block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - [EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - [EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - _vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, - DP_TEST_EDID_CHECKSUM_WRITE); - } - } else { - dev_info(dp->dev, "EDID data does not include any extensions.\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, [EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!
Re: [PATCH 1/3] drm/rockchip: inno_hdmi: add audio support
Mark, Got it, would rebase soonest :-) Thanks, - Yakir On 08/04/2016 10:01 AM, Mark yao wrote: Hi Yakir After apply your patch, I got following warning messge: drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: initialization from incompatible pointer type [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: (near initialization for 'audio_codec_ops.hw_params') [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: initialization from incompatible pointer type [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: (near initialization for 'audio_codec_ops.audio_shutdown') [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: initialization from incompatible pointer type [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: (near initialization for 'audio_codec_ops.digital_mute') [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: initialization from incompatible pointer type [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: (near initialization for 'audio_codec_ops.get_eld') [enabled by default] since the commit "efc9194 ASoC: hdmi-codec: callback function will be called with private data", the hdmi_codec_ops had some changes. Can you rebase your patch to the newest kernel? Thanks. On 2016年06月15日 21:28, Yakir Yang wrote: Using the common hdmi-codec driver to support hdmi audio function. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- drivers/gpu/drm/rockchip/inno_hdmi.c | 237 ++- drivers/gpu/drm/rockchip/inno_hdmi.h | 2 + 2 files changed, 237 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f8b4feb..c31dc07 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -29,6 +29,8 @@ #include #include +#include + #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" @@ -36,6 +38,12 @@ #define to_inno_hdmi(x)container_of(x, struct inno_hdmi, x) +struct audio_info { +int sample_rate; +int channels; +int sample_width; +}; + struct hdmi_data_info { int vic; bool sink_is_hdmi; @@ -71,6 +79,9 @@ struct inno_hdmi { unsigned int tmds_rate; +struct platform_device *audio_pdev; +bool audio_enable; + struct hdmi_data_infohdmi_data; struct drm_display_mode previous_mode; }; @@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AVI, 0, 0, 0); } +static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi, + struct audio_info *audio) +{ +struct hdmi_audio_infoframe *faudio; +union hdmi_infoframe frame; +int rc; + +rc = hdmi_audio_infoframe_init(); +faudio = (struct hdmi_audio_infoframe *) + +faudio->channels = audio->channels; + +switch (audio->sample_width) { +case 16: +faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16; +break; +case 20: +faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; +break; +case 24: +faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24; +break; +} + +switch (audio->sample_rate) { +case 32000: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000; +break; +case 44100: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100; +break; +case 48000: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000; +break; +case 88200: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200; +break; +case 96000: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000; +break; +case 176400: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400; +break; +case 192000: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000; +break; +} + +return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AAI, 0, 0, 0); +} + static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) { struct hdmi_data_info *data = >hdmi_data; @@ -478,8 +540,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, inno_hdmi_i2c_init(hdmi); /* Unmute video and audio output */ -hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, - v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); +hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0)); +if (hdmi->audio_enable) +hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0)); return 0; } @@ -616,6 +679,174 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { .best_encoder = inno_hdmi_connector_best_encoder, };
Re: [PATCH 1/3] drm/rockchip: inno_hdmi: add audio support
Mark, Got it, would rebase soonest :-) Thanks, - Yakir On 08/04/2016 10:01 AM, Mark yao wrote: Hi Yakir After apply your patch, I got following warning messge: drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: initialization from incompatible pointer type [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: (near initialization for 'audio_codec_ops.hw_params') [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: initialization from incompatible pointer type [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: (near initialization for 'audio_codec_ops.audio_shutdown') [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: initialization from incompatible pointer type [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: (near initialization for 'audio_codec_ops.digital_mute') [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: initialization from incompatible pointer type [enabled by default] drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: (near initialization for 'audio_codec_ops.get_eld') [enabled by default] since the commit "efc9194 ASoC: hdmi-codec: callback function will be called with private data", the hdmi_codec_ops had some changes. Can you rebase your patch to the newest kernel? Thanks. On 2016年06月15日 21:28, Yakir Yang wrote: Using the common hdmi-codec driver to support hdmi audio function. Signed-off-by: Yakir Yang --- drivers/gpu/drm/rockchip/inno_hdmi.c | 237 ++- drivers/gpu/drm/rockchip/inno_hdmi.h | 2 + 2 files changed, 237 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f8b4feb..c31dc07 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -29,6 +29,8 @@ #include #include +#include + #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" @@ -36,6 +38,12 @@ #define to_inno_hdmi(x)container_of(x, struct inno_hdmi, x) +struct audio_info { +int sample_rate; +int channels; +int sample_width; +}; + struct hdmi_data_info { int vic; bool sink_is_hdmi; @@ -71,6 +79,9 @@ struct inno_hdmi { unsigned int tmds_rate; +struct platform_device *audio_pdev; +bool audio_enable; + struct hdmi_data_infohdmi_data; struct drm_display_mode previous_mode; }; @@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AVI, 0, 0, 0); } +static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi, + struct audio_info *audio) +{ +struct hdmi_audio_infoframe *faudio; +union hdmi_infoframe frame; +int rc; + +rc = hdmi_audio_infoframe_init(); +faudio = (struct hdmi_audio_infoframe *) + +faudio->channels = audio->channels; + +switch (audio->sample_width) { +case 16: +faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16; +break; +case 20: +faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; +break; +case 24: +faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24; +break; +} + +switch (audio->sample_rate) { +case 32000: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000; +break; +case 44100: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100; +break; +case 48000: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000; +break; +case 88200: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200; +break; +case 96000: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000; +break; +case 176400: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400; +break; +case 192000: +faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000; +break; +} + +return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AAI, 0, 0, 0); +} + static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) { struct hdmi_data_info *data = >hdmi_data; @@ -478,8 +540,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, inno_hdmi_i2c_init(hdmi); /* Unmute video and audio output */ -hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, - v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); +hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0)); +if (hdmi->audio_enable) +hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0)); return 0; } @@ -616,6 +679,174 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { .best_encoder = inno_hdmi_connector_best_encoder, }; +int inno_hdmi_audio_conf
Re: [PATCH 1/3] drm/rockchip: inno_hdmi: add audio support
Hi Mark & Heiko, Ping.. Thanks, - Yakir On 06/15/2016 09:28 PM, Yakir Yang wrote: Using the common hdmi-codec driver to support hdmi audio function. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- drivers/gpu/drm/rockchip/inno_hdmi.c | 237 ++- drivers/gpu/drm/rockchip/inno_hdmi.h | 2 + 2 files changed, 237 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f8b4feb..c31dc07 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -29,6 +29,8 @@ #include #include +#include + #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" @@ -36,6 +38,12 @@ #define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x) +struct audio_info { + int sample_rate; + int channels; + int sample_width; +}; + struct hdmi_data_info { int vic; bool sink_is_hdmi; @@ -71,6 +79,9 @@ struct inno_hdmi { unsigned int tmds_rate; + struct platform_device *audio_pdev; + bool audio_enable; + struct hdmi_data_info hdmi_data; struct drm_display_mode previous_mode; }; @@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AVI, 0, 0, 0); } +static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi, + struct audio_info *audio) +{ + struct hdmi_audio_infoframe *faudio; + union hdmi_infoframe frame; + int rc; + + rc = hdmi_audio_infoframe_init(); + faudio = (struct hdmi_audio_infoframe *) + + faudio->channels = audio->channels; + + switch (audio->sample_width) { + case 16: + faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16; + break; + case 20: + faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; + break; + case 24: + faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24; + break; + } + + switch (audio->sample_rate) { + case 32000: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000; + break; + case 44100: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100; + break; + case 48000: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000; + break; + case 88200: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200; + break; + case 96000: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000; + break; + case 176400: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400; + break; + case 192000: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000; + break; + } + + return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AAI, 0, 0, 0); +} + static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) { struct hdmi_data_info *data = >hdmi_data; @@ -478,8 +540,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, inno_hdmi_i2c_init(hdmi); /* Unmute video and audio output */ - hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, - v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); + hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0)); + if (hdmi->audio_enable) + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0)); return 0; } @@ -616,6 +679,174 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { .best_encoder = inno_hdmi_connector_best_encoder, }; +int inno_hdmi_audio_config_set(struct inno_hdmi *hdmi, struct audio_info *audio) +{ + int rate, N, channel; + + if (audio->channels < 3) + channel = I2S_CHANNEL_1_2; + else if (audio->channels < 5) + channel = I2S_CHANNEL_3_4; + else if (audio->channels < 7) + channel = I2S_CHANNEL_5_6; + else + channel = I2S_CHANNEL_7_8; + + switch (audio->sample_rate) { + case 32000: + rate = AUDIO_32K; + N = N_32K; + break; + case 44100: + rate = AUDIO_441K; + N = N_441K; + break; + case 48000: + rate = AUDIO_48K; + N = N_48K; + break; + case 88200: + rate = AUDIO_882K; + N = N_882K; + break; + case 96000: + rate = AUDIO_96K; + N = N_96K; + break; + case 176400: + rate = AUDIO_1764K; +
Re: [PATCH 1/3] drm/rockchip: inno_hdmi: add audio support
Hi Mark & Heiko, Ping.. Thanks, - Yakir On 06/15/2016 09:28 PM, Yakir Yang wrote: Using the common hdmi-codec driver to support hdmi audio function. Signed-off-by: Yakir Yang --- drivers/gpu/drm/rockchip/inno_hdmi.c | 237 ++- drivers/gpu/drm/rockchip/inno_hdmi.h | 2 + 2 files changed, 237 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f8b4feb..c31dc07 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -29,6 +29,8 @@ #include #include +#include + #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" @@ -36,6 +38,12 @@ #define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x) +struct audio_info { + int sample_rate; + int channels; + int sample_width; +}; + struct hdmi_data_info { int vic; bool sink_is_hdmi; @@ -71,6 +79,9 @@ struct inno_hdmi { unsigned int tmds_rate; + struct platform_device *audio_pdev; + bool audio_enable; + struct hdmi_data_info hdmi_data; struct drm_display_mode previous_mode; }; @@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AVI, 0, 0, 0); } +static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi, + struct audio_info *audio) +{ + struct hdmi_audio_infoframe *faudio; + union hdmi_infoframe frame; + int rc; + + rc = hdmi_audio_infoframe_init(); + faudio = (struct hdmi_audio_infoframe *) + + faudio->channels = audio->channels; + + switch (audio->sample_width) { + case 16: + faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16; + break; + case 20: + faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; + break; + case 24: + faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24; + break; + } + + switch (audio->sample_rate) { + case 32000: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000; + break; + case 44100: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100; + break; + case 48000: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000; + break; + case 88200: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200; + break; + case 96000: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000; + break; + case 176400: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400; + break; + case 192000: + faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000; + break; + } + + return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AAI, 0, 0, 0); +} + static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) { struct hdmi_data_info *data = >hdmi_data; @@ -478,8 +540,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, inno_hdmi_i2c_init(hdmi); /* Unmute video and audio output */ - hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, - v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); + hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0)); + if (hdmi->audio_enable) + hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0)); return 0; } @@ -616,6 +679,174 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { .best_encoder = inno_hdmi_connector_best_encoder, }; +int inno_hdmi_audio_config_set(struct inno_hdmi *hdmi, struct audio_info *audio) +{ + int rate, N, channel; + + if (audio->channels < 3) + channel = I2S_CHANNEL_1_2; + else if (audio->channels < 5) + channel = I2S_CHANNEL_3_4; + else if (audio->channels < 7) + channel = I2S_CHANNEL_5_6; + else + channel = I2S_CHANNEL_7_8; + + switch (audio->sample_rate) { + case 32000: + rate = AUDIO_32K; + N = N_32K; + break; + case 44100: + rate = AUDIO_441K; + N = N_441K; + break; + case 48000: + rate = AUDIO_48K; + N = N_48K; + break; + case 88200: + rate = AUDIO_882K; + N = N_882K; + break; + case 96000: + rate = AUDIO_96K; + N = N_96K; + break; + case 176400: + rate = AUDIO_1764K; + N = N_1764K; +
Re: [PATCH] drm/analogix_dp: Ensure the panel is properly prepared/unprepared
Sean, On 07/30/2016 03:16 AM, Sean Paul wrote: Instead of just preparing the panel on bind, actually prepare/unprepare during modeset/disable. The panel must be prepared in order to read hpd status, so we need to refcount the prepares in order to ensure we don't accidentally turn the panel off at the wrong time. Signed-off-by: Sean Paul--- Hi Yakir, This is what I was talking about upthread. I've tested it and it seems to be working. What do you think? Thanks for your patch, and it works. But I have introduced two questions, and I haven't found a way to fixed them. Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 48 +- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..7b764a4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -960,11 +960,27 @@ enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + enum drm_connector_status status = connector_status_disconnected; + int ret; - if (analogix_dp_detect_hpd(dp)) - return connector_status_disconnected; + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) { + DRM_ERROR("failed to setup panel (%d)\n", ret); + return connector_status_disconnected; + } + } + + if (!analogix_dp_detect_hpd(dp)) + status = connector_status_connected; + + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { + ret = drm_panel_unprepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } - return connector_status_connected; + return status; 1. Panel would flicker at system boot time. Your patch would flash the panel power in connector->detect() function when dp->dpms_mode isn't DRM_MODE_DPMS_OFF. So when userspace keep detect the connector status in boot time, we could see panel would flicker (light up for a while, and turn off again, and keep loop for several time). I have copied some kernel logs: [ 11.065267] YKK - analogix_dp_detect:1052 [ 11.729596] YKK - analogix_dp_get_modes:1016 [ 11.737608] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.749229] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.760799] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 13.315962] YKK - analogix_dp_detect:1052 [ 13.984702] YKK - analogix_dp_get_modes:1016 [ 13.992977] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.004414] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.015842] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.183109] YKK - analogix_dp_bridge_pre_enable:1147 [ 14.306301] rockchip-dp ff97.edp: Link Training Clock Recovery success [ 14.319130] rockchip-dp ff97.edp: Link Training success! [ 14.326388] rockchip-dp ff97.edp: wait SYS_CTL_2. [ 14.437247] rockchip-dp ff97.edp: Timeout of video streamclk ok [ 14.443585] rockchip-dp ff97.edp: unable to config video } static void analogix_dp_connector_destroy(struct drm_connector *connector) @@ -1035,6 +1051,18 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) return 0; } +static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct analogix_dp_device *dp = bridge->driver_private; + int ret; + + if (dp->plat_data->panel) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } 2. Driver would failed to read EDID in some case. Panel would only be powered up in bridge->pre_enable() function which later than connector->get_modes() function, and this would caused DPCD transfer failed in analogix_dp_handle_edid(). This seem won't caused too big issue, cause userspace would read EDID again after bridge/encoder is enabled. But it's better to avoid this potential bug. [ 11.065267] YKK - analogix_dp_detect:1052 [ 11.729596] YKK - analogix_dp_get_modes:1016 [ 11.737608] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.749229] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.760799]
Re: [PATCH] drm/analogix_dp: Ensure the panel is properly prepared/unprepared
Sean, On 07/30/2016 03:16 AM, Sean Paul wrote: Instead of just preparing the panel on bind, actually prepare/unprepare during modeset/disable. The panel must be prepared in order to read hpd status, so we need to refcount the prepares in order to ensure we don't accidentally turn the panel off at the wrong time. Signed-off-by: Sean Paul --- Hi Yakir, This is what I was talking about upthread. I've tested it and it seems to be working. What do you think? Thanks for your patch, and it works. But I have introduced two questions, and I haven't found a way to fixed them. Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 48 +- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..7b764a4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -960,11 +960,27 @@ enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + enum drm_connector_status status = connector_status_disconnected; + int ret; - if (analogix_dp_detect_hpd(dp)) - return connector_status_disconnected; + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) { + DRM_ERROR("failed to setup panel (%d)\n", ret); + return connector_status_disconnected; + } + } + + if (!analogix_dp_detect_hpd(dp)) + status = connector_status_connected; + + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { + ret = drm_panel_unprepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } - return connector_status_connected; + return status; 1. Panel would flicker at system boot time. Your patch would flash the panel power in connector->detect() function when dp->dpms_mode isn't DRM_MODE_DPMS_OFF. So when userspace keep detect the connector status in boot time, we could see panel would flicker (light up for a while, and turn off again, and keep loop for several time). I have copied some kernel logs: [ 11.065267] YKK - analogix_dp_detect:1052 [ 11.729596] YKK - analogix_dp_get_modes:1016 [ 11.737608] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.749229] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.760799] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 13.315962] YKK - analogix_dp_detect:1052 [ 13.984702] YKK - analogix_dp_get_modes:1016 [ 13.992977] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.004414] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.015842] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.183109] YKK - analogix_dp_bridge_pre_enable:1147 [ 14.306301] rockchip-dp ff97.edp: Link Training Clock Recovery success [ 14.319130] rockchip-dp ff97.edp: Link Training success! [ 14.326388] rockchip-dp ff97.edp: wait SYS_CTL_2. [ 14.437247] rockchip-dp ff97.edp: Timeout of video streamclk ok [ 14.443585] rockchip-dp ff97.edp: unable to config video } static void analogix_dp_connector_destroy(struct drm_connector *connector) @@ -1035,6 +1051,18 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) return 0; } +static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct analogix_dp_device *dp = bridge->driver_private; + int ret; + + if (dp->plat_data->panel) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } 2. Driver would failed to read EDID in some case. Panel would only be powered up in bridge->pre_enable() function which later than connector->get_modes() function, and this would caused DPCD transfer failed in analogix_dp_handle_edid(). This seem won't caused too big issue, cause userspace would read EDID again after bridge/encoder is enabled. But it's better to avoid this potential bug. [ 11.065267] YKK - analogix_dp_detect:1052 [ 11.729596] YKK - analogix_dp_get_modes:1016 [ 11.737608] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.749229] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.760799] rockchip-dp ff97.edp:
Re: [PATCH] drm/analogix_dp: Ensure the panel is properly prepared/unprepared
Sean, On 07/30/2016 03:16 AM, Sean Paul wrote: Instead of just preparing the panel on bind, actually prepare/unprepare during modeset/disable. The panel must be prepared in order to read hpd status, so we need to refcount the prepares in order to ensure we don't accidentally turn the panel off at the wrong time. Signed-off-by: Sean Paul--- Hi Yakir, This is what I was talking about upthread. I've tested it and it seems to be working. What do you think? Thanks for your patch, and it works. But I have introduced two questions, and I haven't found a way to fixed them. Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 48 +- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..7b764a4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -960,11 +960,27 @@ enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + enum drm_connector_status status = connector_status_disconnected; + int ret; - if (analogix_dp_detect_hpd(dp)) - return connector_status_disconnected; + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) { + DRM_ERROR("failed to setup panel (%d)\n", ret); + return connector_status_disconnected; + } + } + + if (!analogix_dp_detect_hpd(dp)) + status = connector_status_connected; + + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { + ret = drm_panel_unprepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } - return connector_status_connected; + return status; 1. Panel would flicker at system boot time. Your patch would flash the panel power in connector->detect() function when dp->dpms_mode isn't DRM_MODE_DPMS_OFF. So when userspace keep detect the connector status in boot time, we could see panel would flicker (light up for a while, and turn off again, and keep loop for several time). I have copied some kernel logs: [ 11.065267] YKK - analogix_dp_detect:1052 [ 11.729596] YKK - analogix_dp_get_modes:1016 [ 11.737608] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.749229] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.760799] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 13.315962] YKK - analogix_dp_detect:1052 [ 13.984702] YKK - analogix_dp_get_modes:1016 [ 13.992977] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.004414] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.015842] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.183109] YKK - analogix_dp_bridge_pre_enable:1147 [ 14.306301] rockchip-dp ff97.edp: Link Training Clock Recovery success [ 14.319130] rockchip-dp ff97.edp: Link Training success! [ 14.326388] rockchip-dp ff97.edp: wait SYS_CTL_2. [ 14.437247] rockchip-dp ff97.edp: Timeout of video streamclk ok [ 14.443585] rockchip-dp ff97.edp: unable to config video } static void analogix_dp_connector_destroy(struct drm_connector *connector) @@ -1035,6 +1051,18 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) return 0; } +static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct analogix_dp_device *dp = bridge->driver_private; + int ret; + + if (dp->plat_data->panel) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } 2. Driver would failed to read EDID in some case. Panel would only be powered up in bridge->pre_enable() function which later than connector->get_modes() function, and this would caused DPCD transfer failed in analogix_dp_handle_edid(). This seem won't caused too big issue, cause userspace would read EDID again after bridge/encoder is enabled. But it's better to avoid this potential bug. [ 11.065267] YKK - analogix_dp_detect:1052 [ 11.729596] YKK - analogix_dp_get_modes:1016 [ 11.737608] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.749229] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.760799]
Re: [PATCH] drm/analogix_dp: Ensure the panel is properly prepared/unprepared
Sean, On 07/30/2016 03:16 AM, Sean Paul wrote: Instead of just preparing the panel on bind, actually prepare/unprepare during modeset/disable. The panel must be prepared in order to read hpd status, so we need to refcount the prepares in order to ensure we don't accidentally turn the panel off at the wrong time. Signed-off-by: Sean Paul --- Hi Yakir, This is what I was talking about upthread. I've tested it and it seems to be working. What do you think? Thanks for your patch, and it works. But I have introduced two questions, and I haven't found a way to fixed them. Sean drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 48 +- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..7b764a4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -960,11 +960,27 @@ enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + enum drm_connector_status status = connector_status_disconnected; + int ret; - if (analogix_dp_detect_hpd(dp)) - return connector_status_disconnected; + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) { + DRM_ERROR("failed to setup panel (%d)\n", ret); + return connector_status_disconnected; + } + } + + if (!analogix_dp_detect_hpd(dp)) + status = connector_status_connected; + + if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) { + ret = drm_panel_unprepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } - return connector_status_connected; + return status; 1. Panel would flicker at system boot time. Your patch would flash the panel power in connector->detect() function when dp->dpms_mode isn't DRM_MODE_DPMS_OFF. So when userspace keep detect the connector status in boot time, we could see panel would flicker (light up for a while, and turn off again, and keep loop for several time). I have copied some kernel logs: [ 11.065267] YKK - analogix_dp_detect:1052 [ 11.729596] YKK - analogix_dp_get_modes:1016 [ 11.737608] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.749229] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.760799] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 13.315962] YKK - analogix_dp_detect:1052 [ 13.984702] YKK - analogix_dp_get_modes:1016 [ 13.992977] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.004414] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.015842] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 14.183109] YKK - analogix_dp_bridge_pre_enable:1147 [ 14.306301] rockchip-dp ff97.edp: Link Training Clock Recovery success [ 14.319130] rockchip-dp ff97.edp: Link Training success! [ 14.326388] rockchip-dp ff97.edp: wait SYS_CTL_2. [ 14.437247] rockchip-dp ff97.edp: Timeout of video streamclk ok [ 14.443585] rockchip-dp ff97.edp: unable to config video } static void analogix_dp_connector_destroy(struct drm_connector *connector) @@ -1035,6 +1051,18 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) return 0; } +static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct analogix_dp_device *dp = bridge->driver_private; + int ret; + + if (dp->plat_data->panel) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } 2. Driver would failed to read EDID in some case. Panel would only be powered up in bridge->pre_enable() function which later than connector->get_modes() function, and this would caused DPCD transfer failed in analogix_dp_handle_edid(). This seem won't caused too big issue, cause userspace would read EDID again after bridge/encoder is enabled. But it's better to avoid this potential bug. [ 11.065267] YKK - analogix_dp_detect:1052 [ 11.729596] YKK - analogix_dp_get_modes:1016 [ 11.737608] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.749229] rockchip-dp ff97.edp: analogix_dp_read_bytes_from_dpcd: Aux Transaction fail! [ 11.760799] rockchip-dp ff97.edp:
Re: [PATCH v14 0/17] Add Analogix Core Display Port Driver
On 07/29/2016 04:38 PM, Tomeu Vizoso wrote: On 5 April 2016 at 04:06, Yakir Yang <y...@rock-chips.com> wrote: Hi Daniel, On 03/31/2016 06:15 PM, Daniel Vetter wrote: On Mon, Feb 15, 2016 at 07:08:05PM +0800, Yakir Yang wrote: Hi all, The Samsung Exynos eDP controller and Rockchip RK3288 eDP controller share the same IP, so a lot of parts can be re-used. I split the common code into bridge directory, then rk3288 and exynos only need to keep some platform code. Cause I can't find the exact IP name of exynos dp controller, so I decide to name dp core driver with "analogix" which I find in rk3288 eDP TRM But there are still three light registers setting different between exynos and rk3288. 1. RK3288 have five special pll registers which not indicate in exynos dp controller. 2. The address of DP_PHY_PD(dp phy power manager register) are different between rk3288 and exynos. 3. Rk3288 and exynos have different setting with AUX_HW_RETRY_CTL(dp debug register). Due to Mark Yao have introduced the ATOMIC support to Rockchip drm, so it's okay to use the ATOMIC helpers functions in connector_funcs. No need to splict the connector init to platform driver anymore, and this is the biggest change since version 11. This v14 didn't have lots of new changes which seems not the correct time to upgrade the version number, but I have changed ordering of patches (adding 2 more, and removing 2 out). Especially to prevent confusing people, so I updated the whole series. So I'm jumping into this part way late, but just noticed (well Thierry pointed this out to me) that the exynos dp driver reinvents all the dp and dp-aux helpers we already. That's somewhat okish for a private driver (and exynos has a reputation for that kind of stuff), but imo not ok for a shared driver. Not saying this should block merging this patch, but it really needs to be addressed. All the dp aux and edid read code in the current exynos_dp_core/reg.c files needs to be replaced with dp helpers and the core i2c edid reading code. Who's going to sign up to do this? Volunteer to that, after finish this thread, I would send new series to switch to take use of dp helper. Hi Yakir, do you have plans to do this work in the short term? If not, I can tackle it. Wow, that would be great if you like to tackle it :-D I always keep this in my mind, but haven't found an chance to finish it. I would like to sit in your Cc list when you post them out ;) Best Regards, - Yakir Regards, Tomeu :-D - Yakir -Daniel Thanks, - Yakir Changes in v14: - Rebase the new changes in imx-dp driver - Split up this patch into 3 parts, make this easy to review (Heiko) - Remove the Rockchip DP PHY to an separate thread (Heiko) https://patchwork.kernel.org/patch/8312701/ Changes in v13: - Use .enable instead of preprare/commit in encoder_helper_funcs (Heiko) - Fix the missing parameters with drm_encoder_init() helper function. (Heiko) Changes in v12: - Move the connector init to analogix_dp driver, and using ATOMIC helper (Heiko) - Add the ack from Jingoo - Remove the enum link_rate_type struct, using the marcos in drm_dp_helper.h (Jingoo) Changes in v11: - Uses tabs to fix the indentation issues in analogix_dp_core.h (Heiko) - Rename the "analogix,need-force-hpd" to common 'force-hpd' (Rob) - Add the ack from Rob Herring - Revert parts of Gustavo Padovan's changes in commit: drm/exynos: do not start enabling DP at bind() phase Add dp phy poweron function in bind time. - Move the panel prepare from get_modes time to bind time, and move the panel unprepare from bridge->disable to unbind time. (Heiko) Changes in v10: - Add the ack from Rob Herring - Correct the ROCKCHIP_ANALOGIX_DP indentation in Kconfig to tabs here (Heiko) - Add the ack from Rob Herring - Remove the surplus "plat_data" check. (Heiko) - switch (dp->plat_data && dp->plat_data->dev_type) { + switch (dp->plat_data->dev_type) { Changes in v9: - Document more details for 'ports' property. Changes in v8: - Correct the right document path of display-timing.txt (Heiko) - Correct the misspell of 'from' to 'frm'. (Heiko) - Modify the commit subject name. (Heiko) Changes in v7: - Back to use the of_property_read_bool() interfacs to provoid backward compatibility of "hsync-active-high" "vsync-active-high" "interlaced" to avoid -EOVERFLOW error (Krzysztof) Changes in v6: - Fix the Kconfig recursive dependency (Javier) - Fix Peach Pit hpd property name error: - hpd-gpio = < 6 0>; + hpd-gpios = < 6 0>; Changes in v5: - Correct the check condition of gpio_is_valid when driver try to get the "hpd-gpios" DT propery. (Heiko) - Move the platform attach callback in the front of core driver bridge attch function. Cause once platform failed at attach, core driver should still failed, so no need to i
Re: [PATCH v14 0/17] Add Analogix Core Display Port Driver
On 07/29/2016 04:38 PM, Tomeu Vizoso wrote: On 5 April 2016 at 04:06, Yakir Yang wrote: Hi Daniel, On 03/31/2016 06:15 PM, Daniel Vetter wrote: On Mon, Feb 15, 2016 at 07:08:05PM +0800, Yakir Yang wrote: Hi all, The Samsung Exynos eDP controller and Rockchip RK3288 eDP controller share the same IP, so a lot of parts can be re-used. I split the common code into bridge directory, then rk3288 and exynos only need to keep some platform code. Cause I can't find the exact IP name of exynos dp controller, so I decide to name dp core driver with "analogix" which I find in rk3288 eDP TRM But there are still three light registers setting different between exynos and rk3288. 1. RK3288 have five special pll registers which not indicate in exynos dp controller. 2. The address of DP_PHY_PD(dp phy power manager register) are different between rk3288 and exynos. 3. Rk3288 and exynos have different setting with AUX_HW_RETRY_CTL(dp debug register). Due to Mark Yao have introduced the ATOMIC support to Rockchip drm, so it's okay to use the ATOMIC helpers functions in connector_funcs. No need to splict the connector init to platform driver anymore, and this is the biggest change since version 11. This v14 didn't have lots of new changes which seems not the correct time to upgrade the version number, but I have changed ordering of patches (adding 2 more, and removing 2 out). Especially to prevent confusing people, so I updated the whole series. So I'm jumping into this part way late, but just noticed (well Thierry pointed this out to me) that the exynos dp driver reinvents all the dp and dp-aux helpers we already. That's somewhat okish for a private driver (and exynos has a reputation for that kind of stuff), but imo not ok for a shared driver. Not saying this should block merging this patch, but it really needs to be addressed. All the dp aux and edid read code in the current exynos_dp_core/reg.c files needs to be replaced with dp helpers and the core i2c edid reading code. Who's going to sign up to do this? Volunteer to that, after finish this thread, I would send new series to switch to take use of dp helper. Hi Yakir, do you have plans to do this work in the short term? If not, I can tackle it. Wow, that would be great if you like to tackle it :-D I always keep this in my mind, but haven't found an chance to finish it. I would like to sit in your Cc list when you post them out ;) Best Regards, - Yakir Regards, Tomeu :-D - Yakir -Daniel Thanks, - Yakir Changes in v14: - Rebase the new changes in imx-dp driver - Split up this patch into 3 parts, make this easy to review (Heiko) - Remove the Rockchip DP PHY to an separate thread (Heiko) https://patchwork.kernel.org/patch/8312701/ Changes in v13: - Use .enable instead of preprare/commit in encoder_helper_funcs (Heiko) - Fix the missing parameters with drm_encoder_init() helper function. (Heiko) Changes in v12: - Move the connector init to analogix_dp driver, and using ATOMIC helper (Heiko) - Add the ack from Jingoo - Remove the enum link_rate_type struct, using the marcos in drm_dp_helper.h (Jingoo) Changes in v11: - Uses tabs to fix the indentation issues in analogix_dp_core.h (Heiko) - Rename the "analogix,need-force-hpd" to common 'force-hpd' (Rob) - Add the ack from Rob Herring - Revert parts of Gustavo Padovan's changes in commit: drm/exynos: do not start enabling DP at bind() phase Add dp phy poweron function in bind time. - Move the panel prepare from get_modes time to bind time, and move the panel unprepare from bridge->disable to unbind time. (Heiko) Changes in v10: - Add the ack from Rob Herring - Correct the ROCKCHIP_ANALOGIX_DP indentation in Kconfig to tabs here (Heiko) - Add the ack from Rob Herring - Remove the surplus "plat_data" check. (Heiko) - switch (dp->plat_data && dp->plat_data->dev_type) { + switch (dp->plat_data->dev_type) { Changes in v9: - Document more details for 'ports' property. Changes in v8: - Correct the right document path of display-timing.txt (Heiko) - Correct the misspell of 'from' to 'frm'. (Heiko) - Modify the commit subject name. (Heiko) Changes in v7: - Back to use the of_property_read_bool() interfacs to provoid backward compatibility of "hsync-active-high" "vsync-active-high" "interlaced" to avoid -EOVERFLOW error (Krzysztof) Changes in v6: - Fix the Kconfig recursive dependency (Javier) - Fix Peach Pit hpd property name error: - hpd-gpio = < 6 0>; + hpd-gpios = < 6 0>; Changes in v5: - Correct the check condition of gpio_is_valid when driver try to get the "hpd-gpios" DT propery. (Heiko) - Move the platform attach callback in the front of core driver bridge attch function. Cause once platform failed at attach, core driver should still failed, so no need to init connector before platform attach
Re: [PATCH v1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable
Sean, Oops, sorry about miss your suggest :( On 07/22/2016 11:03 PM, Sean Paul wrote: On Thu, Jul 21, 2016 at 9:00 PM, Yakir Yang <y...@rock-chips.com> wrote: Sean, Thanks for your fast respond :-) But this patch is not the latest one, I have upgraded this to "v1.1" version to fix the eDP can't be disabled problem: [PATCH v1.1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable Changes in v1.1: - unprepare the panel at the end of bridge->disable() function In spite of this, I would take your comments with my "v1.1" patch. On 07/21/2016 10:28 PM, Sean Paul wrote: On Thu, Jul 21, 2016 at 9:14 AM, Yakir Yang <y...@rock-chips.com> wrote: Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP controller stop to send valid video signal, otherwhise panel would go burn in, and keep flicker and flicker. So it's better to turn off the panel when eDP need to disable, and we need to turn on the panel in connector->detect() callback, so that driver would detect panel status rightly. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 18 ++ 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..ea059b3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + /* +* Panle would prepare for several times here, but don't worry it s/Panle/Panel/ Done +* would only enable the hardware at the first prepare time. Errr, this shouldn't go in detect. How about putting this in bridge_enable instead? Nope, if we put this in bridge_enable, then eDP would never be enabled. Here're the calling flow. --> analogix_dp_probe --> analogix_dp_bind # we still haven't prepared the panel here, that means panel have been powered up --> analogix_dp_detect # Oops, losing panel valid hotplug signal, cause panel have been powered up --> ** Keep detecting ** Yeah, after playing around with the patch yesterday I discovered this for myself. I still don't think detect() should be changing hardware state. Perhaps you could add a matching unprepare() after you attempt to detect the panel? Hmm, I don't understand the meaning of "add a matching unprepare()". I didn't see there is an unprepare() callback in drm_crtc_helper.h, would you like to share some simple code :-D Thanks, - Yakir Sean +*/ + if (dp->plat_data->panel) + if (drm_panel_prepare(dp->plat_data->panel)) Personally, I don't like doing work in a conditional since you're throwing the return code away. Could you break this out into: ret = drm_panel_prepare(dp->plat_data->panel); if (ret) DRM_ERROR("failed to setup the panel ret=%d\n", ret); Okay + DRM_ERROR("failed to setup the panel\n"); + if (analogix_dp_detect_hpd(dp)) return connector_status_disconnected; @@ -1063,7 +1071,8 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) return; if (dp->plat_data->panel) { - if (drm_panel_disable(dp->plat_data->panel)) { + if (drm_panel_disable(dp->plat_data->panel) || + drm_panel_unprepare(dp->plat_data->panel)) { Same comment here, please break this out into separate statements for better readability/logging. Okay, Thanks, - Yakir DRM_ERROR("failed to disable the panel\n"); return; } @@ -1333,13 +1342,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_on(dp->phy); - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - analogix_dp_init_dp(dp); ret = devm_request_threaded_irq(>dev, dp->irq, -- 1.9.1
Re: [PATCH v1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable
Sean, Oops, sorry about miss your suggest :( On 07/22/2016 11:03 PM, Sean Paul wrote: On Thu, Jul 21, 2016 at 9:00 PM, Yakir Yang wrote: Sean, Thanks for your fast respond :-) But this patch is not the latest one, I have upgraded this to "v1.1" version to fix the eDP can't be disabled problem: [PATCH v1.1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable Changes in v1.1: - unprepare the panel at the end of bridge->disable() function In spite of this, I would take your comments with my "v1.1" patch. On 07/21/2016 10:28 PM, Sean Paul wrote: On Thu, Jul 21, 2016 at 9:14 AM, Yakir Yang wrote: Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP controller stop to send valid video signal, otherwhise panel would go burn in, and keep flicker and flicker. So it's better to turn off the panel when eDP need to disable, and we need to turn on the panel in connector->detect() callback, so that driver would detect panel status rightly. Signed-off-by: Yakir Yang --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 18 ++ 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..ea059b3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + /* +* Panle would prepare for several times here, but don't worry it s/Panle/Panel/ Done +* would only enable the hardware at the first prepare time. Errr, this shouldn't go in detect. How about putting this in bridge_enable instead? Nope, if we put this in bridge_enable, then eDP would never be enabled. Here're the calling flow. --> analogix_dp_probe --> analogix_dp_bind # we still haven't prepared the panel here, that means panel have been powered up --> analogix_dp_detect # Oops, losing panel valid hotplug signal, cause panel have been powered up --> ** Keep detecting ** Yeah, after playing around with the patch yesterday I discovered this for myself. I still don't think detect() should be changing hardware state. Perhaps you could add a matching unprepare() after you attempt to detect the panel? Hmm, I don't understand the meaning of "add a matching unprepare()". I didn't see there is an unprepare() callback in drm_crtc_helper.h, would you like to share some simple code :-D Thanks, - Yakir Sean +*/ + if (dp->plat_data->panel) + if (drm_panel_prepare(dp->plat_data->panel)) Personally, I don't like doing work in a conditional since you're throwing the return code away. Could you break this out into: ret = drm_panel_prepare(dp->plat_data->panel); if (ret) DRM_ERROR("failed to setup the panel ret=%d\n", ret); Okay + DRM_ERROR("failed to setup the panel\n"); + if (analogix_dp_detect_hpd(dp)) return connector_status_disconnected; @@ -1063,7 +1071,8 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) return; if (dp->plat_data->panel) { - if (drm_panel_disable(dp->plat_data->panel)) { + if (drm_panel_disable(dp->plat_data->panel) || + drm_panel_unprepare(dp->plat_data->panel)) { Same comment here, please break this out into separate statements for better readability/logging. Okay, Thanks, - Yakir DRM_ERROR("failed to disable the panel\n"); return; } @@ -1333,13 +1342,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_on(dp->phy); - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - analogix_dp_init_dp(dp); ret = devm_request_threaded_irq(>dev, dp->irq, -- 1.9.1
Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver
Sean, On 07/14/2016 11:14 PM, Sean Paul wrote: On Thu, Jul 14, 2016 at 12:15:49PM +0800, Yakir Yang wrote: The PSR driver have exported four symbols for specific device driver: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang <y...@rock-chips.com> I still don't think it's a good idea to pull this out into a separate PSR driver, but I suppose we can integrate it at a later time if it becomes cumbersome. Reviewed-by: Sean Paul <seanp...@chromium.org> In order to make it safely to call those symbols at interrupt context, i have made lots of changes about this patch. It's not suitable to take your reviewed flag at the v5, if you're happy to review the new one [0], that would be very nice :-D [0]: https://patchwork.kernel.org/patch/9244805/ Thanks, - Yakir --- Changes in v4: - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 26 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 7 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d665fb0..26c12b3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev) drm_dev->dev_private = private; + INIT_LIST_HEAD(>psr_list); + mutex_init(>psr_list_mutex); + drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); @@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev) if (is_support_iommu) arm_iommu_release_mapping(mapping); + return 0; err_fbdev_fini: rockchip_drm_fbdev_fini(drm_dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 239b830..9c34c9e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -61,6 +61,9 @@ struct rockchip_drm_private { struct drm_gem_object *fbdev_bo; const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; struct drm_atomic_state *state; + + struct list_head psr_list; + struct mutex psr_list_mutex;
Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver
Sean, On 07/14/2016 11:14 PM, Sean Paul wrote: On Thu, Jul 14, 2016 at 12:15:49PM +0800, Yakir Yang wrote: The PSR driver have exported four symbols for specific device driver: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang I still don't think it's a good idea to pull this out into a separate PSR driver, but I suppose we can integrate it at a later time if it becomes cumbersome. Reviewed-by: Sean Paul In order to make it safely to call those symbols at interrupt context, i have made lots of changes about this patch. It's not suitable to take your reviewed flag at the v5, if you're happy to review the new one [0], that would be very nice :-D [0]: https://patchwork.kernel.org/patch/9244805/ Thanks, - Yakir --- Changes in v4: - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 26 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 7 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d665fb0..26c12b3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev) drm_dev->dev_private = private; + INIT_LIST_HEAD(>psr_list); + mutex_init(>psr_list_mutex); + drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); @@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev) if (is_support_iommu) arm_iommu_release_mapping(mapping); + return 0; err_fbdev_fini: rockchip_drm_fbdev_fini(drm_dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 239b830..9c34c9e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -61,6 +61,9 @@ struct rockchip_drm_private { struct drm_gem_object *fbdev_bo; const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; struct drm_atomic_state *state; + + struct list_head psr_list; + struct mutex psr_list_mutex; }; int rockchip_register_crtc_funcs(struct drm_crtc
Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver
Doug, On 07/23/2016 12:04 PM, Doug Anderson wrote: Yakir, On Wed, Jul 13, 2016 at 9:15 PM, Yakir Yang <y...@rock-chips.com> wrote: +static void psr_set_state(struct psr_drv *psr, enum psr_state state) +{ + mutex_lock(>state_mutex); + + if (psr->state == state) { + mutex_unlock(>state_mutex); + return; + } + + psr->state = state; + switch (state) { + case PSR_ENABLE: + psr->set(psr->encoder, true); + break; + + case PSR_DISABLE: + case PSR_FLUSH: + psr->set(psr->encoder, false); + break; + }; + + mutex_unlock(>state_mutex); +} + +static void psr_flush_handler(unsigned long data) +{ + struct psr_drv *psr = (struct psr_drv *)data; + + if (!psr || psr->state != PSR_FLUSH) + return; + + psr_set_state(psr, PSR_ENABLE); As mentioned in a separate thread, this is probably not OK. psr_set_state() grabs a mutex and that might sleep. ...but psr_flush_handler() is a timer. I'm nearly certain that timers can't sleep. I believe this is the source of "sleeping function called from invalid context" that I've seen at times. Thanks for your reported, i have wrote a patch[0] to fix this problem in my v5. If you're happy to review, that would be great ;) [0]: https://patchwork.kernel.org/patch/9244805/ - Yakir -Doug
Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver
Doug, On 07/23/2016 12:04 PM, Doug Anderson wrote: Yakir, On Wed, Jul 13, 2016 at 9:15 PM, Yakir Yang wrote: +static void psr_set_state(struct psr_drv *psr, enum psr_state state) +{ + mutex_lock(>state_mutex); + + if (psr->state == state) { + mutex_unlock(>state_mutex); + return; + } + + psr->state = state; + switch (state) { + case PSR_ENABLE: + psr->set(psr->encoder, true); + break; + + case PSR_DISABLE: + case PSR_FLUSH: + psr->set(psr->encoder, false); + break; + }; + + mutex_unlock(>state_mutex); +} + +static void psr_flush_handler(unsigned long data) +{ + struct psr_drv *psr = (struct psr_drv *)data; + + if (!psr || psr->state != PSR_FLUSH) + return; + + psr_set_state(psr, PSR_ENABLE); As mentioned in a separate thread, this is probably not OK. psr_set_state() grabs a mutex and that might sleep. ...but psr_flush_handler() is a timer. I'm nearly certain that timers can't sleep. I believe this is the source of "sleeping function called from invalid context" that I've seen at times. Thanks for your reported, i have wrote a patch[0] to fix this problem in my v5. If you're happy to review, that would be great ;) [0]: https://patchwork.kernel.org/patch/9244805/ - Yakir -Doug
[PATCH v5 1/4] drm/rockchip: vop: export line flag function
VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang <y...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> --- Changes in v5: - Add reviewed flag from Sean. Changes in v4.1: - Remove the completion_done() check in irq handler (Sean) Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 126 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index bc08b50..90a7e62 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_ir
[PATCH v5 3/4] drm/bridge: analogix_dp: add the PSR function support
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Signed-off-by: Yakir Yang <y...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> --- Changes in v5: - Add reviewed flag from Sean. Changes in v4.1: - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 + include/drm/bridge/analogix_dp.h | 3 + 5 files changed, 174 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..381b25e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = 0; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_version; + + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); + dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_en; + + /* Disable psr function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); + psr_en &= ~DP_PSR_ENABLE; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Main-Link transmitter remains active during PSR active states */ + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Enable psr function */ + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | +DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + analogix_dp_enable_psr_crc(dp); +} + static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; @@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogix_dp_start_video(dp); + + dp->psr_support
[PATCH v5 1/4] drm/rockchip: vop: export line flag function
VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang Reviewed-by: Sean Paul --- Changes in v5: - Add reviewed flag from Sean. Changes in v4.1: - Remove the completion_done() check in irq handler (Sean) Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 126 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index bc08b50..90a7e62 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + V
[PATCH v5 3/4] drm/bridge: analogix_dp: add the PSR function support
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Signed-off-by: Yakir Yang Reviewed-by: Sean Paul --- Changes in v5: - Add reviewed flag from Sean. Changes in v4.1: - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 + include/drm/bridge/analogix_dp.h | 3 + 5 files changed, 174 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..381b25e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = 0; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_version; + + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); + dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_en; + + /* Disable psr function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); + psr_en &= ~DP_PSR_ENABLE; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Main-Link transmitter remains active during PSR active states */ + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Enable psr function */ + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | +DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + analogix_dp_enable_psr_crc(dp); +} + static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; @@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogix_dp_start_video(dp); + + dp->psr_support = analogix_dp_detect_sink_psr(dp); + if (dp->psr_support) +
[PATCH v5 2/4] drm/rockchip: add an common abstracted PSR driver
The PSR driver have exported four symbols for specific device driver, and it's safe to call them in interrupt context: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v5: - Only keep 'psr_list_mutex' at register/unregister time. - Remove unused global variables. - Make list traversal safely at rockchip_drm_psr_unregister(). - Make psr_set_state() to a delay work, safe to call exported symbols at interrupt context. - Remove the repeated psr delay work in vop driver. Changes in v4: - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 3 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 249 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 26 +++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 9 + 7 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index a822d49..b43fe5d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev) drm_dev->dev_private = private; + INIT_LIST_HEAD(>psr_list); + mutex_init(>psr_list_mutex); + drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 239b830..9c34c9e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -61,6 +61,9 @@ struct rockchip_drm_private { struct drm_gem_object *fbdev_bo; const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; struct drm_atomic_state *state; + + struct list_head psr_list; + struct mutex psr_list_mutex; }; int rockchip_register_crtc_funcs(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 55c5273..ba45d9d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -22,6 +22,7 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_fb.h" #include "rockchip_drm_gem.h" +#include "rockchip_drm_psr.h" #define to_rockchip_fb
[PATCH v5 0/4] Add PSR function support for Analogix/Rockchip DP
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make a lots of sense to save the power consumption. The v5 version have made the psr_set_state() to a delay work, which is the biggest changes from v4. The v3 version have splited an common PSR driver for Rockchip, which is biggest changes from v2. This thread is based on Mark's RK3399 VOP thread[0]. [0]: https://patchwork.kernel.org/patch/8886041/ Changes in v5: - Add reviewed flag from Sean. - Only keep 'psr_list_mutex' at register/unregister time. - Remove unused global variables. - Make list traversal safely at rockchip_drm_psr_unregister(). - Make psr_set_state() to a delay work, safe to call exported symbols at interrupt context. - Remove the repeated psr delay work in vop driver. - Add reviewed flag from Sean. - Add reviewed flag from Sean. Changes in v4.1: - Remove the completion_done() check in irq handler (Sean) - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - Introduce in v2, split VOP line flag changes out - introduce in v2, splite the common Analogix DP changes out - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. Yakir Yang (4): drm/rockchip: vop: export line flag function drm/rockchip: add an common abstracted PSR driver drm/bridge: analogix_dp: add the PSR function support drm/rockchip: analogix_dp: implement PSR function drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 +++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 +++ drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 57 + drivers/gpu/drm/rockchip/rockchip_drm_drv.c| 3 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h| 6 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 + drivers/gpu/drm/rockchip/rockchip_drm_psr.c| 249 + drivers/gpu/drm/roc
[PATCH v5 2/4] drm/rockchip: add an common abstracted PSR driver
The PSR driver have exported four symbols for specific device driver, and it's safe to call them in interrupt context: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang --- Changes in v5: - Only keep 'psr_list_mutex' at register/unregister time. - Remove unused global variables. - Make list traversal safely at rockchip_drm_psr_unregister(). - Make psr_set_state() to a delay work, safe to call exported symbols at interrupt context. - Remove the repeated psr delay work in vop driver. Changes in v4: - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 3 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 249 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 26 +++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 9 + 7 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index a822d49..b43fe5d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev) drm_dev->dev_private = private; + INIT_LIST_HEAD(>psr_list); + mutex_init(>psr_list_mutex); + drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 239b830..9c34c9e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -61,6 +61,9 @@ struct rockchip_drm_private { struct drm_gem_object *fbdev_bo; const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; struct drm_atomic_state *state; + + struct list_head psr_list; + struct mutex psr_list_mutex; }; int rockchip_register_crtc_funcs(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 55c5273..ba45d9d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -22,6 +22,7 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_fb.h" #include "rockchip_drm_gem.h" +#include "rockchip_drm_psr.h" #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb) @@ -63,9 +6
[PATCH v5 0/4] Add PSR function support for Analogix/Rockchip DP
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make a lots of sense to save the power consumption. The v5 version have made the psr_set_state() to a delay work, which is the biggest changes from v4. The v3 version have splited an common PSR driver for Rockchip, which is biggest changes from v2. This thread is based on Mark's RK3399 VOP thread[0]. [0]: https://patchwork.kernel.org/patch/8886041/ Changes in v5: - Add reviewed flag from Sean. - Only keep 'psr_list_mutex' at register/unregister time. - Remove unused global variables. - Make list traversal safely at rockchip_drm_psr_unregister(). - Make psr_set_state() to a delay work, safe to call exported symbols at interrupt context. - Remove the repeated psr delay work in vop driver. - Add reviewed flag from Sean. - Add reviewed flag from Sean. Changes in v4.1: - Remove the completion_done() check in irq handler (Sean) - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - Introduce in v2, split VOP line flag changes out - introduce in v2, splite the common Analogix DP changes out - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. Yakir Yang (4): drm/rockchip: vop: export line flag function drm/rockchip: add an common abstracted PSR driver drm/bridge: analogix_dp: add the PSR function support drm/rockchip: analogix_dp: implement PSR function drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 +++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 +++ drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 57 + drivers/gpu/drm/rockchip/rockchip_drm_drv.c| 3 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h| 6 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 + drivers/gpu/drm/rockchip/rockchip_drm_psr.c| 249 + drivers/gpu/drm/roc
[PATCH v5 4/4] drm/rockchip: analogix_dp: implement PSR function
Alway enable the PSR function for Rockchip analogix_dp driver. If panel don't support PSR, then the core analogix_dp would ignore this setting. Signed-off-by: Yakir Yang <y...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> --- Changes in v5: - Add reviewed flag from Sean. Changes in v4: - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 + 1 file changed, 57 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index e81e19a..aa916f4 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -32,6 +32,7 @@ #include #include "rockchip_drm_drv.h" +#include "rockchip_drm_psr.h" #include "rockchip_drm_vop.h" #define RK3288_GRF_SOC_CON60x25c @@ -41,6 +42,9 @@ #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) +#define PSR_SET_DELAY_TIME msecs_to_jiffies(10) +#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100 + #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) /** @@ -68,11 +72,55 @@ struct rockchip_dp_device { struct regmap*grf; struct reset_control *rst; + struct delayed_work psr_work; + unsigned int psr_state; + const struct rockchip_dp_chip_data *data; struct analogix_dp_plat_data plat_data; }; +static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) +{ + struct rockchip_dp_device *dp = to_dp(encoder); + + dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); + + if (enabled) + dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; + else + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + + schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME); +} + +static void analogix_dp_psr_work(struct work_struct *work) +{ + struct rockchip_dp_device *dp = + container_of(work, typeof(*dp), psr_work.work); + struct drm_crtc *crtc = dp->encoder.crtc; + int psr_state = dp->psr_state; + int vact_end; + int ret; + + if (!crtc) + return; + + vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay; + + ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end, + PSR_WAIT_LINE_FLAG_TIMEOUT_MS); + if (ret) { + dev_err(dp->dev, "line flag interrupt did not arrive\n"); + return; + } + + if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) + analogix_dp_enable_psr(dp->dev); + else + analogix_dp_disable_psr(dp->dev); +} + static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) { reset_control_assert(dp->rst); @@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.power_off = rockchip_dp_powerdown; dp->plat_data.get_modes = rockchip_dp_get_modes; + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work); + + rockchip_drm_psr_register(>encoder, analogix_dp_psr_set); + return analogix_dp_bind(dev, dp->drm_dev, >plat_data); } static void rockchip_dp_unbind(struct device *dev, struct device *master, void *data) { + struct rockchip_dp_device *dp = dev_get_drvdata(dev); + + rockchip_drm_psr_unregister(>encoder); + return analogix_dp_unbind(dev, master, data); } -- 1.9.1
[PATCH v5 4/4] drm/rockchip: analogix_dp: implement PSR function
Alway enable the PSR function for Rockchip analogix_dp driver. If panel don't support PSR, then the core analogix_dp would ignore this setting. Signed-off-by: Yakir Yang Reviewed-by: Sean Paul --- Changes in v5: - Add reviewed flag from Sean. Changes in v4: - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 + 1 file changed, 57 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index e81e19a..aa916f4 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -32,6 +32,7 @@ #include #include "rockchip_drm_drv.h" +#include "rockchip_drm_psr.h" #include "rockchip_drm_vop.h" #define RK3288_GRF_SOC_CON60x25c @@ -41,6 +42,9 @@ #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) +#define PSR_SET_DELAY_TIME msecs_to_jiffies(10) +#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100 + #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) /** @@ -68,11 +72,55 @@ struct rockchip_dp_device { struct regmap*grf; struct reset_control *rst; + struct delayed_work psr_work; + unsigned int psr_state; + const struct rockchip_dp_chip_data *data; struct analogix_dp_plat_data plat_data; }; +static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) +{ + struct rockchip_dp_device *dp = to_dp(encoder); + + dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); + + if (enabled) + dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; + else + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + + schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME); +} + +static void analogix_dp_psr_work(struct work_struct *work) +{ + struct rockchip_dp_device *dp = + container_of(work, typeof(*dp), psr_work.work); + struct drm_crtc *crtc = dp->encoder.crtc; + int psr_state = dp->psr_state; + int vact_end; + int ret; + + if (!crtc) + return; + + vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay; + + ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end, + PSR_WAIT_LINE_FLAG_TIMEOUT_MS); + if (ret) { + dev_err(dp->dev, "line flag interrupt did not arrive\n"); + return; + } + + if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) + analogix_dp_enable_psr(dp->dev); + else + analogix_dp_disable_psr(dp->dev); +} + static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) { reset_control_assert(dp->rst); @@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.power_off = rockchip_dp_powerdown; dp->plat_data.get_modes = rockchip_dp_get_modes; + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work); + + rockchip_drm_psr_register(>encoder, analogix_dp_psr_set); + return analogix_dp_bind(dev, dp->drm_dev, >plat_data); } static void rockchip_dp_unbind(struct device *dev, struct device *master, void *data) { + struct rockchip_dp_device *dp = dev_get_drvdata(dev); + + rockchip_drm_psr_unregister(>encoder); + return analogix_dp_unbind(dev, master, data); } -- 1.9.1
[PATCH v2 2/3] drm/bridge: analogix_dp: turn off the panel when eDP need to disable
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP controller stop to send valid video signal, otherwhise panel would go burn in, and keep flicker and flicker. So it's better to turn off the panel when eDP need to disable, and we need to turn on the panel in connector->detect() callback, so that driver would detect panel status rightly. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v2: - s/Panle/Panel/ (Sean) - Move the drm_panel_ out of a conditional, and throw the return code away (Sean) - Add comments about why we need unprepare the panel in bridge_disable (Sean) - Unprepare the panel at the end of bridge->disable() function. drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 37 -- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..0ddaf93 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -960,6 +960,17 @@ enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + int ret; + + /* +* Panel would prepare for several times here, but don't worry, it +* would only enable the hardware at the first prepare time. +*/ + if (dp->plat_data->panel) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } if (analogix_dp_detect_hpd(dp)) return connector_status_disconnected; @@ -1058,13 +1069,15 @@ static void analogix_dp_bridge_enable(struct drm_bridge *bridge) static void analogix_dp_bridge_disable(struct drm_bridge *bridge) { struct analogix_dp_device *dp = bridge->driver_private; + int ret; if (dp->dpms_mode != DRM_MODE_DPMS_ON) return; if (dp->plat_data->panel) { - if (drm_panel_disable(dp->plat_data->panel)) { - DRM_ERROR("failed to disable the panel\n"); + ret = drm_panel_disable(dp->plat_data->panel); + if (ret) { + DRM_ERROR("failed to disable the panel [%d]\n", ret); return; } } @@ -1077,6 +1090,19 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) pm_runtime_put_sync(dp->dev); + /* +* Some panels need to be turn off when eDP controller stop to send +* valid video signal, otherwhise panel would go burn in, and keep +* flicker and flicker. +*/ + if (dp->plat_data->panel) { +ret = drm_panel_unprepare(dp->plat_data->panel); +if (ret) { + DRM_ERROR("failed to turnoff the panel [%d]\n", ret); + return; + } + } + dp->dpms_mode = DRM_MODE_DPMS_OFF; } @@ -1333,13 +1359,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_on(dp->phy); - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - analogix_dp_init_dp(dp); ret = devm_request_threaded_irq(>dev, dp->irq, -- 1.9.1
[PATCH v2 3/3] drm/bridge: analogix_dp: remove the panel prepare/unprepare in suspend/resume
We already manager the panel power status in bridge_disable and connector->detect functions, then we don't need to manager the panel power status at suspend/resume in particular. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 12 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 0ddaf93..3dadad2 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1413,11 +1413,6 @@ int analogix_dp_suspend(struct device *dev) clk_disable_unprepare(dp->clock); - if (dp->plat_data->panel) { - if (drm_panel_unprepare(dp->plat_data->panel)) - DRM_ERROR("failed to turnoff the panel\n"); - } - return 0; } EXPORT_SYMBOL_GPL(analogix_dp_suspend); @@ -1433,13 +1428,6 @@ int analogix_dp_resume(struct device *dev) return ret; } - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - return 0; } EXPORT_SYMBOL_GPL(analogix_dp_resume); -- 1.9.1
[PATCH v2 2/3] drm/bridge: analogix_dp: turn off the panel when eDP need to disable
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP controller stop to send valid video signal, otherwhise panel would go burn in, and keep flicker and flicker. So it's better to turn off the panel when eDP need to disable, and we need to turn on the panel in connector->detect() callback, so that driver would detect panel status rightly. Signed-off-by: Yakir Yang --- Changes in v2: - s/Panle/Panel/ (Sean) - Move the drm_panel_ out of a conditional, and throw the return code away (Sean) - Add comments about why we need unprepare the panel in bridge_disable (Sean) - Unprepare the panel at the end of bridge->disable() function. drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 37 -- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..0ddaf93 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -960,6 +960,17 @@ enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + int ret; + + /* +* Panel would prepare for several times here, but don't worry, it +* would only enable the hardware at the first prepare time. +*/ + if (dp->plat_data->panel) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + } if (analogix_dp_detect_hpd(dp)) return connector_status_disconnected; @@ -1058,13 +1069,15 @@ static void analogix_dp_bridge_enable(struct drm_bridge *bridge) static void analogix_dp_bridge_disable(struct drm_bridge *bridge) { struct analogix_dp_device *dp = bridge->driver_private; + int ret; if (dp->dpms_mode != DRM_MODE_DPMS_ON) return; if (dp->plat_data->panel) { - if (drm_panel_disable(dp->plat_data->panel)) { - DRM_ERROR("failed to disable the panel\n"); + ret = drm_panel_disable(dp->plat_data->panel); + if (ret) { + DRM_ERROR("failed to disable the panel [%d]\n", ret); return; } } @@ -1077,6 +1090,19 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) pm_runtime_put_sync(dp->dev); + /* +* Some panels need to be turn off when eDP controller stop to send +* valid video signal, otherwhise panel would go burn in, and keep +* flicker and flicker. +*/ + if (dp->plat_data->panel) { +ret = drm_panel_unprepare(dp->plat_data->panel); +if (ret) { + DRM_ERROR("failed to turnoff the panel [%d]\n", ret); + return; + } + } + dp->dpms_mode = DRM_MODE_DPMS_OFF; } @@ -1333,13 +1359,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_on(dp->phy); - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - analogix_dp_init_dp(dp); ret = devm_request_threaded_irq(>dev, dp->irq, -- 1.9.1
[PATCH v2 3/3] drm/bridge: analogix_dp: remove the panel prepare/unprepare in suspend/resume
We already manager the panel power status in bridge_disable and connector->detect functions, then we don't need to manager the panel power status at suspend/resume in particular. Signed-off-by: Yakir Yang --- Changes in v2: None drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 12 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 0ddaf93..3dadad2 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1413,11 +1413,6 @@ int analogix_dp_suspend(struct device *dev) clk_disable_unprepare(dp->clock); - if (dp->plat_data->panel) { - if (drm_panel_unprepare(dp->plat_data->panel)) - DRM_ERROR("failed to turnoff the panel\n"); - } - return 0; } EXPORT_SYMBOL_GPL(analogix_dp_suspend); @@ -1433,13 +1428,6 @@ int analogix_dp_resume(struct device *dev) return ret; } - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - return 0; } EXPORT_SYMBOL_GPL(analogix_dp_resume); -- 1.9.1
[PATCH v2 1/3] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31
According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~). Signed-off-by: Yakir Yang <y...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> --- Changes in v2: - Add the reviewed tag from Sean. drivers/gpu/drm/panel/panel-simple.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 85143d1..f178998 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = { .width = 259, .height = 173, }, + .delay = { + .prepare = 110, + .enable = 50, + .unprepare = 550, + }, }; static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = { -- 1.9.1
[PATCH v2 1/3] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31
According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~). Signed-off-by: Yakir Yang Reviewed-by: Sean Paul --- Changes in v2: - Add the reviewed tag from Sean. drivers/gpu/drm/panel/panel-simple.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 85143d1..f178998 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = { .width = 259, .height = 173, }, + .delay = { + .prepare = 110, + .enable = 50, + .unprepare = 550, + }, }; static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = { -- 1.9.1
Re: [PATCH v1 1/2] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31
Sean, On 07/21/2016 10:30 PM, Sean Paul wrote: On Thu, Jul 21, 2016 at 9:14 AM, Yakir Yang <y...@rock-chips.com> wrote: According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~). Signed-off-by: Yakir Yang <y...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> Thanks :-D - Yakir --- drivers/gpu/drm/panel/panel-simple.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 85143d1..f178998 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = { .width = 259, .height = 173, }, + .delay = { + .prepare = 110, + .enable = 50, + .unprepare = 550, + }, }; static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = { -- 1.9.1
Re: [PATCH v1 1/2] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31
Sean, On 07/21/2016 10:30 PM, Sean Paul wrote: On Thu, Jul 21, 2016 at 9:14 AM, Yakir Yang wrote: According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~). Signed-off-by: Yakir Yang Reviewed-by: Sean Paul Thanks :-D - Yakir --- drivers/gpu/drm/panel/panel-simple.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 85143d1..f178998 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = { .width = 259, .height = 173, }, + .delay = { + .prepare = 110, + .enable = 50, + .unprepare = 550, + }, }; static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = { -- 1.9.1
[PATCH v1.1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP controller stop to send valid video signal, otherwhise panel would go burn in, and keep flicker and flicker. So it's better to turn off the panel when eDP need to disable, and we need to turn on the panel in connector->detect() callback, so that driver would detect panel status rightly. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v1.1: - unprepare the panel at the end of bridge->disable() function drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 22 +++--- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..2e519bd 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + /* +* Panle would prepare for several times here, but don't worry it +* would only enable the hardware at the first prepare time. +*/ + if (dp->plat_data->panel) + if (drm_panel_prepare(dp->plat_data->panel)) + DRM_ERROR("failed to setup the panel\n"); + if (analogix_dp_detect_hpd(dp)) return connector_status_disconnected; @@ -1077,6 +1085,13 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) pm_runtime_put_sync(dp->dev); + if (dp->plat_data->panel) { + if (drm_panel_unprepare(dp->plat_data->panel)) { + DRM_ERROR("failed to turnoff the panel\n"); + return; + } + } + dp->dpms_mode = DRM_MODE_DPMS_OFF; } @@ -1333,13 +1348,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_on(dp->phy); - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - analogix_dp_init_dp(dp); ret = devm_request_threaded_irq(>dev, dp->irq, -- 1.9.1
[PATCH v1.1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP controller stop to send valid video signal, otherwhise panel would go burn in, and keep flicker and flicker. So it's better to turn off the panel when eDP need to disable, and we need to turn on the panel in connector->detect() callback, so that driver would detect panel status rightly. Signed-off-by: Yakir Yang --- Changes in v1.1: - unprepare the panel at the end of bridge->disable() function drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 22 +++--- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..2e519bd 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + /* +* Panle would prepare for several times here, but don't worry it +* would only enable the hardware at the first prepare time. +*/ + if (dp->plat_data->panel) + if (drm_panel_prepare(dp->plat_data->panel)) + DRM_ERROR("failed to setup the panel\n"); + if (analogix_dp_detect_hpd(dp)) return connector_status_disconnected; @@ -1077,6 +1085,13 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) pm_runtime_put_sync(dp->dev); + if (dp->plat_data->panel) { + if (drm_panel_unprepare(dp->plat_data->panel)) { + DRM_ERROR("failed to turnoff the panel\n"); + return; + } + } + dp->dpms_mode = DRM_MODE_DPMS_OFF; } @@ -1333,13 +1348,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_on(dp->phy); - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - analogix_dp_init_dp(dp); ret = devm_request_threaded_irq(>dev, dp->irq, -- 1.9.1
[PATCH v1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP controller stop to send valid video signal, otherwhise panel would go burn in, and keep flicker and flicker. So it's better to turn off the panel when eDP need to disable, and we need to turn on the panel in connector->detect() callback, so that driver would detect panel status rightly. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 18 ++ 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..ea059b3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + /* +* Panle would prepare for several times here, but don't worry it +* would only enable the hardware at the first prepare time. +*/ + if (dp->plat_data->panel) + if (drm_panel_prepare(dp->plat_data->panel)) + DRM_ERROR("failed to setup the panel\n"); + if (analogix_dp_detect_hpd(dp)) return connector_status_disconnected; @@ -1063,7 +1071,8 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) return; if (dp->plat_data->panel) { - if (drm_panel_disable(dp->plat_data->panel)) { + if (drm_panel_disable(dp->plat_data->panel) || + drm_panel_unprepare(dp->plat_data->panel)) { DRM_ERROR("failed to disable the panel\n"); return; } @@ -1333,13 +1342,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_on(dp->phy); - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - analogix_dp_init_dp(dp); ret = devm_request_threaded_irq(>dev, dp->irq, -- 1.9.1
[PATCH v1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP controller stop to send valid video signal, otherwhise panel would go burn in, and keep flicker and flicker. So it's better to turn off the panel when eDP need to disable, and we need to turn on the panel in connector->detect() callback, so that driver would detect panel status rightly. Signed-off-by: Yakir Yang --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 18 ++ 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..ea059b3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + /* +* Panle would prepare for several times here, but don't worry it +* would only enable the hardware at the first prepare time. +*/ + if (dp->plat_data->panel) + if (drm_panel_prepare(dp->plat_data->panel)) + DRM_ERROR("failed to setup the panel\n"); + if (analogix_dp_detect_hpd(dp)) return connector_status_disconnected; @@ -1063,7 +1071,8 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) return; if (dp->plat_data->panel) { - if (drm_panel_disable(dp->plat_data->panel)) { + if (drm_panel_disable(dp->plat_data->panel) || + drm_panel_unprepare(dp->plat_data->panel)) { DRM_ERROR("failed to disable the panel\n"); return; } @@ -1333,13 +1342,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_on(dp->phy); - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - analogix_dp_init_dp(dp); ret = devm_request_threaded_irq(>dev, dp->irq, -- 1.9.1
[PATCH v1 1/2] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31
According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~). Signed-off-by: Yakir Yang <y...@rock-chips.com> --- drivers/gpu/drm/panel/panel-simple.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 85143d1..f178998 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = { .width = 259, .height = 173, }, + .delay = { + .prepare = 110, + .enable = 50, + .unprepare = 550, + }, }; static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = { -- 1.9.1
[PATCH v1 1/2] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31
According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~). Signed-off-by: Yakir Yang --- drivers/gpu/drm/panel/panel-simple.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 85143d1..f178998 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = { .width = 259, .height = 173, }, + .delay = { + .prepare = 110, + .enable = 50, + .unprepare = 550, + }, }; static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = { -- 1.9.1
Re: [PATCH v3 1/6] dt-bindings: add LG LP097QX1-SPA1 panel binding
Thierry, On 07/08/2016 05:57 AM, Thierry Reding wrote: On Thu, Jul 07, 2016 at 11:55:23PM +0200, Thierry Reding wrote: On Sun, Jun 12, 2016 at 10:53:30AM +0800, Yakir Yang wrote: The LG LP097QX1-SPA1 is an 9.7", 2048x1536 (QXGA) TFT-LCD panel connected using eDP interfaces. Signed-off-by: Yakir Yang <y...@rock-chips.com> Acked-by: Rob Herring <r...@kernel.org> --- Changes in v3: None Changes in v2: - Add Rob's acked for dt-bindings of LG LP097QX1-SPA1 panel .../devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt | 7 +++ 1 file changed, 7 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt Applied all six patches, though I modified 3/6 as Doug suggested. I mean patch 4/6, of course. Wow, good news, thanks a lot :-D - Yakir Thierry
Re: [PATCH v3 1/6] dt-bindings: add LG LP097QX1-SPA1 panel binding
Thierry, On 07/08/2016 05:57 AM, Thierry Reding wrote: On Thu, Jul 07, 2016 at 11:55:23PM +0200, Thierry Reding wrote: On Sun, Jun 12, 2016 at 10:53:30AM +0800, Yakir Yang wrote: The LG LP097QX1-SPA1 is an 9.7", 2048x1536 (QXGA) TFT-LCD panel connected using eDP interfaces. Signed-off-by: Yakir Yang Acked-by: Rob Herring --- Changes in v3: None Changes in v2: - Add Rob's acked for dt-bindings of LG LP097QX1-SPA1 panel .../devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt | 7 +++ 1 file changed, 7 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt Applied all six patches, though I modified 3/6 as Doug suggested. I mean patch 4/6, of course. Wow, good news, thanks a lot :-D - Yakir Thierry
Re: [PATCH v4.1 3/4] drm/bridge: analogix_dp: add the PSR function support
Sean, On 07/15/2016 09:13 PM, Sean Paul wrote: On Fri, Jul 15, 2016 at 06:55:17PM +0800, Yakir Yang wrote: The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Signed-off-by: Yakir Yang <y...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> Thanks for your reviewed :-D - Yakir --- Changes in v4.1: - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 + include/drm/bridge/analogix_dp.h | 3 + 5 files changed, 174 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..381b25e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = 0; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_version; + + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); + dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_en; + + /* Disable psr function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); + psr_en &= ~DP_PSR_ENABLE; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Main-Link transmitter remains active during PSR active states */ + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Enable psr function */ + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | +DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + analogix_dp_enable_psr_crc(dp); +} + static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; @@ -921,6 +998,10 @@ static void analogix_dp_c
Re: [PATCH v4.1 3/4] drm/bridge: analogix_dp: add the PSR function support
Sean, On 07/15/2016 09:13 PM, Sean Paul wrote: On Fri, Jul 15, 2016 at 06:55:17PM +0800, Yakir Yang wrote: The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Signed-off-by: Yakir Yang Reviewed-by: Sean Paul Thanks for your reviewed :-D - Yakir --- Changes in v4.1: - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 + include/drm/bridge/analogix_dp.h | 3 + 5 files changed, 174 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..381b25e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = 0; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_version; + + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); + dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_en; + + /* Disable psr function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); + psr_en &= ~DP_PSR_ENABLE; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Main-Link transmitter remains active during PSR active states */ + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Enable psr function */ + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | +DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + analogix_dp_enable_psr_crc(dp); +} + static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; @@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogi
Re: [PATCH v4.1 1/4] drm/rockchip: vop: export line flag function
Sean, On 07/15/2016 09:04 PM, Sean Paul wrote: On Fri, Jul 15, 2016 at 6:55 AM, Yakir Yang <y...@rock-chips.com> wrote: VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang <y...@rock-chips.com> Thanks for the update. Reviewed-by: Sean Paul <seanp...@chromium.org> Thanks for your reviewed :-D - Yakir --- Changes in v4.1: - Remove the completion_done() check in irq handler (Sean) Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 126 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c8a62a8..8a4f36e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags);
Re: [PATCH v4.1 1/4] drm/rockchip: vop: export line flag function
Sean, On 07/15/2016 09:04 PM, Sean Paul wrote: On Fri, Jul 15, 2016 at 6:55 AM, Yakir Yang wrote: VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang Thanks for the update. Reviewed-by: Sean Paul Thanks for your reviewed :-D - Yakir --- Changes in v4.1: - Remove the completion_done() check in irq handler (Sean) Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 126 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c8a62a8..8a4f36e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flag
[PATCH v4.1 1/4] drm/rockchip: vop: export line flag function
VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v4.1: - Remove the completion_done() check in irq handler (Sean) Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 126 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c8a62a8..8a4f36e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0); + + s
[PATCH v4.1 3/4] drm/bridge: analogix_dp: add the PSR function support
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v4.1: - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 + include/drm/bridge/analogix_dp.h | 3 + 5 files changed, 174 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..381b25e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = 0; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_version; + + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); + dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_en; + + /* Disable psr function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); + psr_en &= ~DP_PSR_ENABLE; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Main-Link transmitter remains active during PSR active states */ + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Enable psr function */ + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | +DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + analogix_dp_enable_psr_crc(dp); +} + static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; @@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogix_dp_start_video(dp); + + dp->psr_support = analogix_dp_detect_sink_psr(dp); + if (dp->psr_support) + analogix_dp_enable_sink_ps
[PATCH v4.1 1/4] drm/rockchip: vop: export line flag function
VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang --- Changes in v4.1: - Remove the completion_done() check in irq handler (Sean) Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 126 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c8a62a8..8a4f36e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0); + + spin_unlock_irqrestore(>irq
[PATCH v4.1 3/4] drm/bridge: analogix_dp: add the PSR function support
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Signed-off-by: Yakir Yang --- Changes in v4.1: - Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean) - Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc(). - Add comment about PBx magic numbers. (Sean) Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 5 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 51 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 + include/drm/bridge/analogix_dp.h | 3 + 5 files changed, 174 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..381b25e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; + + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = 0; + + analogix_dp_send_psr_spd(dp, _vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_version; + + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); + dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_en; + + /* Disable psr function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); + psr_en &= ~DP_PSR_ENABLE; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Main-Link transmitter remains active during PSR active states */ + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Enable psr function */ + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | +DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + analogix_dp_enable_psr_crc(dp); +} + static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; @@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogix_dp_start_video(dp); + + dp->psr_support = analogix_dp_detect_sink_psr(dp); + if (dp->psr_support) + analogix_dp_enable_sink_psr(dp); } int analogix_dp_
Re: [PATCH v4 4/4] drm/rockchip: analogix_dp: implement PSR function
Sean, On 07/14/2016 11:26 PM, Sean Paul wrote: On Thu, Jul 14, 2016 at 12:15:58PM +0800, Yakir Yang wrote: Alway enable the PSR function for Rockchip analogix_dp driver. If panel don't support PSR, then the core analogix_dp would ignore this setting. Signed-off-by: Yakir Yang <y...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> Thanks :-D - Yakir --- Changes in v4: - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 + 1 file changed, 57 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index e81e19a..aa916f4 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -32,6 +32,7 @@ #include #include "rockchip_drm_drv.h" +#include "rockchip_drm_psr.h" #include "rockchip_drm_vop.h" #define RK3288_GRF_SOC_CON6 0x25c @@ -41,6 +42,9 @@ #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) +#define PSR_SET_DELAY_TIME msecs_to_jiffies(10) +#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100 + #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) /** @@ -68,11 +72,55 @@ struct rockchip_dp_device { struct regmap*grf; struct reset_control *rst; + struct delayed_work psr_work; + unsigned int psr_state; + const struct rockchip_dp_chip_data *data; struct analogix_dp_plat_data plat_data; }; +static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) +{ + struct rockchip_dp_device *dp = to_dp(encoder); + + dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); + + if (enabled) + dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; + else + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + + schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME); +} + +static void analogix_dp_psr_work(struct work_struct *work) +{ + struct rockchip_dp_device *dp = + container_of(work, typeof(*dp), psr_work.work); + struct drm_crtc *crtc = dp->encoder.crtc; + int psr_state = dp->psr_state; + int vact_end; + int ret; + + if (!crtc) + return; + + vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay; + + ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end, + PSR_WAIT_LINE_FLAG_TIMEOUT_MS); + if (ret) { + dev_err(dp->dev, "line flag interrupt did not arrive\n"); + return; + } + + if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) + analogix_dp_enable_psr(dp->dev); + else + analogix_dp_disable_psr(dp->dev); +} + static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) { reset_control_assert(dp->rst); @@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.power_off = rockchip_dp_powerdown; dp->plat_data.get_modes = rockchip_dp_get_modes; + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work); + + rockchip_drm_psr_register(>encoder, analogix_dp_psr_set); + return analogix_dp_bind(dev, dp->drm_dev, >plat_data); } static void rockchip_dp_unbind(struct device *dev, struct device *master, void *data) { + struct rockchip_dp_device *dp = dev_get_drvdata(dev); + + rockchip_drm_psr_unregister(>encoder); + return analogix_dp_unbind(dev, master, data); } -- 1.9.1 ___ dri-devel mailing list dri-de...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v4 4/4] drm/rockchip: analogix_dp: implement PSR function
Sean, On 07/14/2016 11:26 PM, Sean Paul wrote: On Thu, Jul 14, 2016 at 12:15:58PM +0800, Yakir Yang wrote: Alway enable the PSR function for Rockchip analogix_dp driver. If panel don't support PSR, then the core analogix_dp would ignore this setting. Signed-off-by: Yakir Yang Reviewed-by: Sean Paul Thanks :-D - Yakir --- Changes in v4: - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 + 1 file changed, 57 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index e81e19a..aa916f4 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -32,6 +32,7 @@ #include #include "rockchip_drm_drv.h" +#include "rockchip_drm_psr.h" #include "rockchip_drm_vop.h" #define RK3288_GRF_SOC_CON6 0x25c @@ -41,6 +42,9 @@ #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) +#define PSR_SET_DELAY_TIME msecs_to_jiffies(10) +#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100 + #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) /** @@ -68,11 +72,55 @@ struct rockchip_dp_device { struct regmap*grf; struct reset_control *rst; + struct delayed_work psr_work; + unsigned int psr_state; + const struct rockchip_dp_chip_data *data; struct analogix_dp_plat_data plat_data; }; +static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) +{ + struct rockchip_dp_device *dp = to_dp(encoder); + + dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); + + if (enabled) + dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; + else + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + + schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME); +} + +static void analogix_dp_psr_work(struct work_struct *work) +{ + struct rockchip_dp_device *dp = + container_of(work, typeof(*dp), psr_work.work); + struct drm_crtc *crtc = dp->encoder.crtc; + int psr_state = dp->psr_state; + int vact_end; + int ret; + + if (!crtc) + return; + + vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay; + + ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end, + PSR_WAIT_LINE_FLAG_TIMEOUT_MS); + if (ret) { + dev_err(dp->dev, "line flag interrupt did not arrive\n"); + return; + } + + if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) + analogix_dp_enable_psr(dp->dev); + else + analogix_dp_disable_psr(dp->dev); +} + static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) { reset_control_assert(dp->rst); @@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.power_off = rockchip_dp_powerdown; dp->plat_data.get_modes = rockchip_dp_get_modes; + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work); + + rockchip_drm_psr_register(>encoder, analogix_dp_psr_set); + return analogix_dp_bind(dev, dp->drm_dev, >plat_data); } static void rockchip_dp_unbind(struct device *dev, struct device *master, void *data) { + struct rockchip_dp_device *dp = dev_get_drvdata(dev); + + rockchip_drm_psr_unregister(>encoder); + return analogix_dp_unbind(dev, master, data); } -- 1.9.1 ___ dri-devel mailing list dri-de...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver
Sean, On 07/14/2016 11:14 PM, Sean Paul wrote: On Thu, Jul 14, 2016 at 12:15:49PM +0800, Yakir Yang wrote: The PSR driver have exported four symbols for specific device driver: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang <y...@rock-chips.com> I still don't think it's a good idea to pull this out into a separate PSR driver, but I suppose we can integrate it at a later time if it becomes cumbersome. Reviewed-by: Sean Paul <seanp...@chromium.org> Thanks :-D - Yakir --- Changes in v4: - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 26 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 7 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d665fb0..26c12b3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev) drm_dev->dev_private = private; + INIT_LIST_HEAD(>psr_list); + mutex_init(>psr_list_mutex); + drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); @@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev) if (is_support_iommu) arm_iommu_release_mapping(mapping); + return 0; err_fbdev_fini: rockchip_drm_fbdev_fini(drm_dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 239b830..9c34c9e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -61,6 +61,9 @@ struct rockchip_drm_private { struct drm_gem_object *fbdev_bo; const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; struct drm_atomic_state *state; + + struct list_head psr_list; + struct mutex psr_list_mutex; }; int rockchip_register_crtc_funcs(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 20f12bc..36afd9c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_d
Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver
Sean, On 07/14/2016 11:14 PM, Sean Paul wrote: On Thu, Jul 14, 2016 at 12:15:49PM +0800, Yakir Yang wrote: The PSR driver have exported four symbols for specific device driver: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang I still don't think it's a good idea to pull this out into a separate PSR driver, but I suppose we can integrate it at a later time if it becomes cumbersome. Reviewed-by: Sean Paul Thanks :-D - Yakir --- Changes in v4: - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 26 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 7 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d665fb0..26c12b3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev) drm_dev->dev_private = private; + INIT_LIST_HEAD(>psr_list); + mutex_init(>psr_list_mutex); + drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); @@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev) if (is_support_iommu) arm_iommu_release_mapping(mapping); + return 0; err_fbdev_fini: rockchip_drm_fbdev_fini(drm_dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 239b830..9c34c9e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -61,6 +61,9 @@ struct rockchip_drm_private { struct drm_gem_object *fbdev_bo; const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; struct drm_atomic_state *state; + + struct list_head psr_list; + struct mutex psr_list_mutex; }; int rockchip_register_crtc_funcs(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 20f12bc..36afd9c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -21,6 +21,7 @@ #include "rockchip_drm_drv.
Re: [PATCH v4 1/4] drm/rockchip: vop: export line flag function
Sean, On 07/14/2016 10:46 PM, Sean Paul wrote: On Thu, Jul 14, 2016 at 12:15:44PM +0800, Yakir Yang wrote: VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 118 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 127 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c8a62a8..69d32f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + +
Re: [PATCH v4 1/4] drm/rockchip: vop: export line flag function
Sean, On 07/14/2016 10:46 PM, Sean Paul wrote: On Thu, Jul 14, 2016 at 12:15:44PM +0800, Yakir Yang wrote: VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang --- Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 118 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 127 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c8a62a8..69d32f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0); +
[PATCH v4 4/4] drm/rockchip: analogix_dp: implement PSR function
Alway enable the PSR function for Rockchip analogix_dp driver. If panel don't support PSR, then the core analogix_dp would ignore this setting. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v4: - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 + 1 file changed, 57 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index e81e19a..aa916f4 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -32,6 +32,7 @@ #include #include "rockchip_drm_drv.h" +#include "rockchip_drm_psr.h" #include "rockchip_drm_vop.h" #define RK3288_GRF_SOC_CON60x25c @@ -41,6 +42,9 @@ #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) +#define PSR_SET_DELAY_TIME msecs_to_jiffies(10) +#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100 + #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) /** @@ -68,11 +72,55 @@ struct rockchip_dp_device { struct regmap*grf; struct reset_control *rst; + struct delayed_work psr_work; + unsigned int psr_state; + const struct rockchip_dp_chip_data *data; struct analogix_dp_plat_data plat_data; }; +static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) +{ + struct rockchip_dp_device *dp = to_dp(encoder); + + dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); + + if (enabled) + dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; + else + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + + schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME); +} + +static void analogix_dp_psr_work(struct work_struct *work) +{ + struct rockchip_dp_device *dp = + container_of(work, typeof(*dp), psr_work.work); + struct drm_crtc *crtc = dp->encoder.crtc; + int psr_state = dp->psr_state; + int vact_end; + int ret; + + if (!crtc) + return; + + vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay; + + ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end, + PSR_WAIT_LINE_FLAG_TIMEOUT_MS); + if (ret) { + dev_err(dp->dev, "line flag interrupt did not arrive\n"); + return; + } + + if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) + analogix_dp_enable_psr(dp->dev); + else + analogix_dp_disable_psr(dp->dev); +} + static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) { reset_control_assert(dp->rst); @@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.power_off = rockchip_dp_powerdown; dp->plat_data.get_modes = rockchip_dp_get_modes; + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work); + + rockchip_drm_psr_register(>encoder, analogix_dp_psr_set); + return analogix_dp_bind(dev, dp->drm_dev, >plat_data); } static void rockchip_dp_unbind(struct device *dev, struct device *master, void *data) { + struct rockchip_dp_device *dp = dev_get_drvdata(dev); + + rockchip_drm_psr_unregister(>encoder); + return analogix_dp_unbind(dev, master, data); } -- 1.9.1
[PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver
The PSR driver have exported four symbols for specific device driver: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v4: - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 26 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 7 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d665fb0..26c12b3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev) drm_dev->dev_private = private; + INIT_LIST_HEAD(>psr_list); + mutex_init(>psr_list_mutex); + drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); @@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev) if (is_support_iommu) arm_iommu_release_mapping(mapping); + return 0; err_fbdev_fini: rockchip_drm_fbdev_fini(drm_dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 239b830..9c34c9e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -61,6 +61,9 @@ struct rockchip_drm_private { struct drm_gem_object *fbdev_bo; const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; struct drm_atomic_state *state; + + struct list_head psr_list; + struct mutex psr_list_mutex; }; int rockchip_register_crtc_funcs(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 20f12bc..36afd9c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -21,6 +21,7 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" +#include "rockchip_drm_psr.h" #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb) @@ -66,9 +67,20 @@ static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb, rockchip_fb->obj[0],
[PATCH v4 4/4] drm/rockchip: analogix_dp: implement PSR function
Alway enable the PSR function for Rockchip analogix_dp driver. If panel don't support PSR, then the core analogix_dp would ignore this setting. Signed-off-by: Yakir Yang --- Changes in v4: - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 + 1 file changed, 57 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index e81e19a..aa916f4 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -32,6 +32,7 @@ #include #include "rockchip_drm_drv.h" +#include "rockchip_drm_psr.h" #include "rockchip_drm_vop.h" #define RK3288_GRF_SOC_CON60x25c @@ -41,6 +42,9 @@ #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) +#define PSR_SET_DELAY_TIME msecs_to_jiffies(10) +#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100 + #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) /** @@ -68,11 +72,55 @@ struct rockchip_dp_device { struct regmap*grf; struct reset_control *rst; + struct delayed_work psr_work; + unsigned int psr_state; + const struct rockchip_dp_chip_data *data; struct analogix_dp_plat_data plat_data; }; +static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) +{ + struct rockchip_dp_device *dp = to_dp(encoder); + + dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); + + if (enabled) + dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; + else + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + + schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME); +} + +static void analogix_dp_psr_work(struct work_struct *work) +{ + struct rockchip_dp_device *dp = + container_of(work, typeof(*dp), psr_work.work); + struct drm_crtc *crtc = dp->encoder.crtc; + int psr_state = dp->psr_state; + int vact_end; + int ret; + + if (!crtc) + return; + + vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + crtc->mode.vdisplay; + + ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end, + PSR_WAIT_LINE_FLAG_TIMEOUT_MS); + if (ret) { + dev_err(dp->dev, "line flag interrupt did not arrive\n"); + return; + } + + if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) + analogix_dp_enable_psr(dp->dev); + else + analogix_dp_disable_psr(dp->dev); +} + static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) { reset_control_assert(dp->rst); @@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.power_off = rockchip_dp_powerdown; dp->plat_data.get_modes = rockchip_dp_get_modes; + dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; + INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work); + + rockchip_drm_psr_register(>encoder, analogix_dp_psr_set); + return analogix_dp_bind(dev, dp->drm_dev, >plat_data); } static void rockchip_dp_unbind(struct device *dev, struct device *master, void *data) { + struct rockchip_dp_device *dp = dev_get_drvdata(dev); + + rockchip_drm_psr_unregister(>encoder); + return analogix_dp_unbind(dev, master, data); } -- 1.9.1
[PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver
The PSR driver have exported four symbols for specific device driver: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang --- Changes in v4: - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 26 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 7 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d665fb0..26c12b3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev) drm_dev->dev_private = private; + INIT_LIST_HEAD(>psr_list); + mutex_init(>psr_list_mutex); + drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); @@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev) if (is_support_iommu) arm_iommu_release_mapping(mapping); + return 0; err_fbdev_fini: rockchip_drm_fbdev_fini(drm_dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 239b830..9c34c9e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -61,6 +61,9 @@ struct rockchip_drm_private { struct drm_gem_object *fbdev_bo; const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC]; struct drm_atomic_state *state; + + struct list_head psr_list; + struct mutex psr_list_mutex; }; int rockchip_register_crtc_funcs(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 20f12bc..36afd9c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -21,6 +21,7 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" +#include "rockchip_drm_psr.h" #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb) @@ -66,9 +67,20 @@ static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb, rockchip_fb->obj[0], handle
[PATCH v4 3/4] drm/bridge: analogix_dp: add the PSR function support
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 60 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 49 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 ++ include/drm/bridge/analogix_dp.h | 3 ++ 5 files changed, 144 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..1fec91a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,62 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + + if (!dp->psr_support) + return -EINVAL; + + analogix_dp_send_psr_spd(dp, EDP_VSC_PSR_STATE_ACTIVE | +EDP_VSC_PSR_CRC_VALUES_VALID); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + + if (!dp->psr_support) + return -EINVAL; + + analogix_dp_send_psr_spd(dp, 0); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_version; + + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); + dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_en; + + /* Disable psr function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); + psr_en &= ~DP_PSR_ENABLE; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Main-Link transmitter remains active during PSR active states */ + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Enable psr function */ + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | +DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + analogix_dp_enable_psr_crc(dp); +} + static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; @@ -921,6 +977,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogix_dp_start_video(dp); + + dp->psr_support = analogix_dp_detect_sink_psr(dp); + if (dp->psr_support) + analogix_dp_enable_sink_psr(dp); } int analogix_dp_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index b456380..6ca5dde 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -177,6 +177,7 @@ struct analogix_dp_device { int hpd_gpio; boolforce_hpd; unsigned char edid[EDID_BLOCK_LENGTH * 2]; + boolpsr_support; struct analogix_dp_plat_data *plat_data; }; @@ -278,4 +279,7 @@ int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp); void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_
[PATCH v4 3/4] drm/bridge: analogix_dp: add the PSR function support
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make lots of sense to save the power consumption. This patch have exported two symbols for platform driver to implement the PSR function in hardware side: - analogix_dp_active_psr() - analogix_dp_inactive_psr() Signed-off-by: Yakir Yang --- Changes in v4: - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). Changes in v3: - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments Changes in v2: - introduce in v2, splite the common Analogix DP changes out drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 60 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 49 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 ++ include/drm/bridge/analogix_dp.h | 3 ++ 5 files changed, 144 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715da..1fec91a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,62 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_enable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + + if (!dp->psr_support) + return -EINVAL; + + analogix_dp_send_psr_spd(dp, EDP_VSC_PSR_STATE_ACTIVE | +EDP_VSC_PSR_CRC_VALUES_VALID); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); + +int analogix_dp_disable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + + if (!dp->psr_support) + return -EINVAL; + + analogix_dp_send_psr_spd(dp, 0); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); + +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_version; + + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version); + dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); + + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_en; + + /* Disable psr function */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en); + psr_en &= ~DP_PSR_ENABLE; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Main-Link transmitter remains active during PSR active states */ + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + /* Enable psr function */ + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | +DP_PSR_CRC_VERIFICATION; + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); + + analogix_dp_enable_psr_crc(dp); +} + static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; @@ -921,6 +977,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogix_dp_start_video(dp); + + dp->psr_support = analogix_dp_detect_sink_psr(dp); + if (dp->psr_support) + analogix_dp_enable_sink_psr(dp); } int analogix_dp_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index b456380..6ca5dde 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -177,6 +177,7 @@ struct analogix_dp_device { int hpd_gpio; boolforce_hpd; unsigned char edid[EDID_BLOCK_LENGTH * 2]; + boolpsr_support; struct analogix_dp_plat_data *plat_data; }; @@ -278,4 +279,7 @@ int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp); void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_dis
[PATCH v4 0/4] Add PSR function support for Analogix/Rockchip DP
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make a lots of sense to save the power consumption. This v3 version have splited an common PSR driver for Rockchip, which is biggest changes from v2. This thread is based on Mark's RK3399 VOP thread[0] and my RK3399 eDP thread[1]. [0]: https://patchwork.kernel.org/patch/8886041/ [1]: https://patchwork.kernel.org/patch/9204497/ Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - Introduce in v2, split VOP line flag changes out - introduce in v2, splite the common Analogix DP changes out - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. Yakir Yang (4): drm/rockchip: vop: export line flag function drm/rockchip: add an common abstracted PSR driver drm/bridge: analogix_dp: add the PSR function support drm/rockchip: analogix_dp: implement PSR function drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 60 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 49 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 +++ drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 57 ++ drivers/gpu/drm/rockchip/rockchip_drm_drv.c| 4 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h| 6 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c| 223 + drivers/gpu/drm/rockchip/rockchip_drm_psr.h| 26 +++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 147 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop.h| 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c| 4 + include/drm/bridge/analogix_dp.h | 3 + 15 files changed, 626 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h -- 1.9.1
[PATCH v4 1/4] drm/rockchip: vop: export line flag function
VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 118 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 127 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c8a62a8..69d32f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0); + + spin_unlock_irqrestore(>irq_lock, flags); +} + static void vop_enable(st
[PATCH v4 0/4] Add PSR function support for Analogix/Rockchip DP
The full name of PSR is Panel Self Refresh, panel device could refresh itself with the hardware framebuffer in panel, this would make a lots of sense to save the power consumption. This v3 version have splited an common PSR driver for Rockchip, which is biggest changes from v2. This thread is based on Mark's RK3399 VOP thread[0] and my RK3399 eDP thread[1]. [0]: https://patchwork.kernel.org/patch/8886041/ [1]: https://patchwork.kernel.org/patch/9204497/ Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] - Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. (Sean) - Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean) - Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean) - Collect psr_enable() and psr_disable() into psr_set_state() - s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean) - Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475] - Add the missing file head with license. (Stéphane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3] - Downgrade the PSR version print message to debug level. (Sean) - Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean) - Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). (Sean) - Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean). - Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean) - Rename "active/inactive" to "enable/disable". (Sean, Dominik) - Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc(). - Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean) - Pull the 10ms delay time out into a #define. (Sean) - Improved the code of analogix_dp_psr_work(). (Sean) - Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, reviewed at Google gerrit) [https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 - split analogix_dp_enable_psr(), make it more clearly analogix_dp_detect_sink_psr() analogix_dp_enable_sink_psr() - remove some nosie register setting comments - split the common psr logic into a seperate driver, make this to a simple sub-psr device driver. Changes in v2: - Introduce in v2, split VOP line flag changes out - introduce in v2, splite the common Analogix DP changes out - remove vblank notify out (Daniel) - create a psr_active() callback in vop data struct. Yakir Yang (4): drm/rockchip: vop: export line flag function drm/rockchip: add an common abstracted PSR driver drm/bridge: analogix_dp: add the PSR function support drm/rockchip: analogix_dp: implement PSR function drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 60 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 49 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 +++ drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 57 ++ drivers/gpu/drm/rockchip/rockchip_drm_drv.c| 4 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h| 6 + drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c| 223 + drivers/gpu/drm/rockchip/rockchip_drm_psr.h| 26 +++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 147 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop.h| 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c| 4 + include/drm/bridge/analogix_dp.h | 3 + 15 files changed, 626 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h -- 1.9.1
[PATCH v4 1/4] drm/rockchip: vop: export line flag function
VOP have integrated a hardware counter which indicate the exact display line that vop is scanning. And if we're interested in a specific line, we can set the line number to vop line_flag register, and then vop would generate a line_flag interrupt for it. For example eDP PSR function is interested in the vertical blanking period, then driver could set the line number to zero. This patch have exported a symbol that allow other driver to listen the line flag event with given timeout limit: - rockchip_drm_wait_line_flag() Signed-off-by: Yakir Yang --- Changes in v4: - Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean) - Make line_flag_num_x to an array. (Sean) - Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, reviewed in Google gerrit) [https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466] Changes in v3: - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - Remove the notify for waiting line_flag event (Daniel) Changes in v2: - Introduce in v2, split VOP line flag changes out drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 118 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 + 4 files changed, 127 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index ea39329..239b830 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); +int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, + unsigned int mstimeout); + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c8a62a8..69d32f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -121,6 +121,8 @@ struct vop { /* protected by dev->event_lock */ struct drm_pending_vblank_event *event; + struct completion line_flag_completion; + const struct vop_data *data; uint32_t *regsbak; @@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +/* + * (1) each frame starts at the start of the Vsync pulse which is signaled by + * the "FRAME_SYNC" interrupt. + * (2) the active data region of each frame ends at dsp_vact_end + * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num, + * to get "LINE_FLAG" interrupt at the end of the active on screen data. + * + * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end + * Interrupts + * LINE_FLAG ---+ + * FRAME_SYNC + | + *| | + *v v + *| Vsync | Vbp | Vactive | Vfp | + *^ ^ ^ ^ + *| | | | + *| | | | + * dsp_vs_end + | | | VOP_DSP_VTOTAL_VS_END + * dsp_vact_start --+ | | VOP_DSP_VACT_ST_END + * dsp_vact_end + | VOP_DSP_VACT_ST_END + * dsp_total -+ VOP_DSP_VTOTAL_VS_END + */ +static bool vop_line_flag_irq_is_enabled(struct vop *vop) +{ + uint32_t line_flag_irq; + unsigned long flags; + + spin_lock_irqsave(>irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(>irq_lock, flags); + + return !!line_flag_irq; +} + +static void vop_line_flag_irq_enable(struct vop *vop, int line_num) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num[0], line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + + spin_unlock_irqrestore(>irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; + + spin_lock_irqsave(>irq_lock, flags); + + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0); + + spin_unlock_irqrestore(>irq_lock, flags); +} + static void vop_enable(struct drm_crtc *crtc) {
Re: [PATCH v1 5/6] drm/rockchip: dw_hdmi: introduce the VPLL clock setting
Heiko, On 07/12/2016 10:27 PM, Heiko Stübner wrote: Hi Yakir, Am Montag, 11. Juli 2016, 19:05:49 schrieb Yakir Yang: For RK3399 HDMI, there is an external clock need for HDMI PHY, and it should keep the same clock rate with VOP DCLK. VPLL have supported the clock for HDMI PHY, but there is no clock divider bewteen VPLL and HDMI PHY. So we need to set the VPLL rate manually in HDMI driver. I don't think reserving the vpll for the hdmi at all times is the right way to go. While I do agree that reserving the VPLL (and NPLL on the rk3288) for graphics use looks like the right way, I think the core Rockchip drm driver should be responsible for managing it and also for deciding which output encoder gets to use it. While true that on the Chromebook device-types the edp is static and hdmi needs the broad range of dynamic frequencies, this is not necessarily the case for all future device types and/or socs. In the other thread we discussed adding that as rockchip,dclk-pll = <&...>; to the base display-subsystem node, Doug didn't manage to find time to respond yet though - and is on vacation right now. Great idea. Let a separate drm-pll driver to maintain all connector's clock requirement. I still believe that would be the best solution :-) . That property could list 1 or even 2 plls, depending on the soc or board layout - maybe someone frees up the cpll in some special layout or something. If none are listed, then the drm driver would need to cope with its available clocks. Implementation-wise you could even still keep your shortcut until we encounter a device with different , let the drm use the pll for hdmi only until someone comes up with a better concept, but still the binding should be correct and versatile from the start. Someone should start to prepare the drm core pll driver, it's great idea. BR, - Yakir Heiko --- .../bindings/display/rockchip/dw_hdmi-rockchip.txt | 3 ++- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c| 25 +- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index 4e573d2..4e23ca4 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -17,7 +17,8 @@ Required properties: Optional properties - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing -- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec" +- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec", + phandle to the VPLL clock, name should be "vpll". Example: hdmi: hdmi@ff98 { diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 329099b..701bb73 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -7,10 +7,12 @@ * (at your option) any later version. */ +#include +#include #include #include -#include #include + #include #include #include @@ -33,6 +35,7 @@ struct rockchip_hdmi { struct regmap *regmap; struct drm_encoder encoder; enum dw_hdmi_devtype dev_type; + struct clk *vpll_clk; }; #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) @@ -145,6 +148,7 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) { struct device_node *np = hdmi->dev->of_node; + int ret; hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(hdmi->regmap)) { @@ -152,6 +156,22 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) return PTR_ERR(hdmi->regmap); } + hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll"); + if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) { + hdmi->vpll_clk = NULL; + } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (IS_ERR(hdmi->vpll_clk)) { + dev_err(hdmi->dev, "failed to get grf clock\n"); + return PTR_ERR(hdmi->vpll_clk); + } + + ret = clk_prepare_enable(hdmi->vpll_clk); + if (ret) { + dev_err(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret); + return ret; + } + return 0; } @@ -194,6 +214,9 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { + struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); + + clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000); } static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
Re: [PATCH v1 5/6] drm/rockchip: dw_hdmi: introduce the VPLL clock setting
Heiko, On 07/12/2016 10:27 PM, Heiko Stübner wrote: Hi Yakir, Am Montag, 11. Juli 2016, 19:05:49 schrieb Yakir Yang: For RK3399 HDMI, there is an external clock need for HDMI PHY, and it should keep the same clock rate with VOP DCLK. VPLL have supported the clock for HDMI PHY, but there is no clock divider bewteen VPLL and HDMI PHY. So we need to set the VPLL rate manually in HDMI driver. I don't think reserving the vpll for the hdmi at all times is the right way to go. While I do agree that reserving the VPLL (and NPLL on the rk3288) for graphics use looks like the right way, I think the core Rockchip drm driver should be responsible for managing it and also for deciding which output encoder gets to use it. While true that on the Chromebook device-types the edp is static and hdmi needs the broad range of dynamic frequencies, this is not necessarily the case for all future device types and/or socs. In the other thread we discussed adding that as rockchip,dclk-pll = <&...>; to the base display-subsystem node, Doug didn't manage to find time to respond yet though - and is on vacation right now. Great idea. Let a separate drm-pll driver to maintain all connector's clock requirement. I still believe that would be the best solution :-) . That property could list 1 or even 2 plls, depending on the soc or board layout - maybe someone frees up the cpll in some special layout or something. If none are listed, then the drm driver would need to cope with its available clocks. Implementation-wise you could even still keep your shortcut until we encounter a device with different , let the drm use the pll for hdmi only until someone comes up with a better concept, but still the binding should be correct and versatile from the start. Someone should start to prepare the drm core pll driver, it's great idea. BR, - Yakir Heiko --- .../bindings/display/rockchip/dw_hdmi-rockchip.txt | 3 ++- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c| 25 +- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index 4e573d2..4e23ca4 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -17,7 +17,8 @@ Required properties: Optional properties - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing -- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec" +- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec", + phandle to the VPLL clock, name should be "vpll". Example: hdmi: hdmi@ff98 { diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 329099b..701bb73 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -7,10 +7,12 @@ * (at your option) any later version. */ +#include +#include #include #include -#include #include + #include #include #include @@ -33,6 +35,7 @@ struct rockchip_hdmi { struct regmap *regmap; struct drm_encoder encoder; enum dw_hdmi_devtype dev_type; + struct clk *vpll_clk; }; #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) @@ -145,6 +148,7 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) { struct device_node *np = hdmi->dev->of_node; + int ret; hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(hdmi->regmap)) { @@ -152,6 +156,22 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) return PTR_ERR(hdmi->regmap); } + hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll"); + if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) { + hdmi->vpll_clk = NULL; + } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (IS_ERR(hdmi->vpll_clk)) { + dev_err(hdmi->dev, "failed to get grf clock\n"); + return PTR_ERR(hdmi->vpll_clk); + } + + ret = clk_prepare_enable(hdmi->vpll_clk); + if (ret) { + dev_err(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret); + return ret; + } + return 0; } @@ -194,6 +214,9 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { + struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); + + clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000); } static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
Re: [PATCH v1 4/6] drm/rockchip: dw_hdmi: add RK3399 HDMI support
Philipp, On 07/11/2016 07:51 PM, Philipp Zabel wrote: Am Montag, den 11.07.2016, 19:05 +0800 schrieb Yakir Yang: RK3399 and RK3288 shared the same HDMI IP controller, only some light difference with GRF configure. Signed-off-by: Yakir Yang <y...@rock-chips.com> Reviewed-by: Philipp Zabel <p.za...@pengutronix.de> Thanks for your fast respond :-D - Yakir regards Philipp
Re: [PATCH v1 4/6] drm/rockchip: dw_hdmi: add RK3399 HDMI support
Philipp, On 07/11/2016 07:51 PM, Philipp Zabel wrote: Am Montag, den 11.07.2016, 19:05 +0800 schrieb Yakir Yang: RK3399 and RK3288 shared the same HDMI IP controller, only some light difference with GRF configure. Signed-off-by: Yakir Yang Reviewed-by: Philipp Zabel Thanks for your fast respond :-D - Yakir regards Philipp
Re: [PATCH v3 2/4] drm/rockchip: add an common abstracted PSR driver
Daniel, On 07/12/2016 08:38 PM, Daniel Vetter wrote: On Fri, Jul 01, 2016 at 02:00:00PM -0400, Sean Paul wrote: On Fri, Jul 1, 2016 at 5:19 AM, Yakir Yang <y...@rock-chips.com> wrote: The PSR driver have exported four symbols for specific device driver: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. This feels overly complicated. It seems like you could cut out a bunch of code by just coding the psr functions into vop and analogix_dp-rockchip. I suppose the only reason to keep it abstracted would be if you plan on supporting psr in a different encoder or crtc in rockchip, or if you're planning on moving this into drm core. Agreed on the layers of indirection. Also, you end up with 3 delayed timers in total: - defio timer from fbdev emulation - timer in this abstraction - delayed work in the psr backend driver I'd cut out at least the middle one. But since this seems to correctly use the ->dirty callback it gets my Ack either way ;-) Aha, thanks :-D - Yakir Cheers, Daniel Perhaps others will disagree with this sentiment and this is the right thing to do. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang <y...@rock-chips.com> --- Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 200 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 24 5 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 20f12bc..0fec18f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -21,6 +21,7 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" +#include "rockchip_drm_psr.h" #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb) @@ -66,9 +67,20 @@ static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb, rockchip_fb->obj[0], handle); } +static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, +struct drm_file *file, +unsigned int flags, unsigned int color, +struct drm_clip_rect *clips, +unsigned int num_clips) +{ + rockchip_drm_psr_flush(); + return 0; +} + static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = { .destroy= rockchip_drm_fb_destroy, .create_handle = rockchip_drm_fb_create_handle, + .dirty = rockchip_drm_fb_dirty, }; static struct rockchip_drm_fb * diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c new file mode 100644 index 000..c03 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c @@ -0,0 +1,200 @@ +#include + +#include "rockchip_drm_psr.h" + +#define PSR_FLUSH_TIMEOUT msecs_to_jiffies(3000) /* 3 seconds */ + +static LIST_HEAD(psr_list); +static DEFINE_MUTEX(psr_list_mutex); I'm not crazy about these globals. Perhaps you can initialize them with the rockchip driver and tuck them in a driver-level struct (rockchip_drm_private or somethin
Re: [PATCH v3 2/4] drm/rockchip: add an common abstracted PSR driver
Daniel, On 07/12/2016 08:38 PM, Daniel Vetter wrote: On Fri, Jul 01, 2016 at 02:00:00PM -0400, Sean Paul wrote: On Fri, Jul 1, 2016 at 5:19 AM, Yakir Yang wrote: The PSR driver have exported four symbols for specific device driver: - rockchip_drm_psr_register() - rockchip_drm_psr_unregister() - rockchip_drm_psr_enable() - rockchip_drm_psr_disable() - rockchip_drm_psr_flush() Encoder driver should call the register/unregister interfaces to hook itself into common PSR driver, encoder have implement the 'psr_set' callback which use the set PSR state in hardware side. Crtc driver would call the enable/disable interfaces when vblank is enable/disable, after that the common PSR driver would call the encoder registered callback to set the PSR state. This feels overly complicated. It seems like you could cut out a bunch of code by just coding the psr functions into vop and analogix_dp-rockchip. I suppose the only reason to keep it abstracted would be if you plan on supporting psr in a different encoder or crtc in rockchip, or if you're planning on moving this into drm core. Agreed on the layers of indirection. Also, you end up with 3 delayed timers in total: - defio timer from fbdev emulation - timer in this abstraction - delayed work in the psr backend driver I'd cut out at least the middle one. But since this seems to correctly use the ->dirty callback it gets my Ack either way ;-) Aha, thanks :-D - Yakir Cheers, Daniel Perhaps others will disagree with this sentiment and this is the right thing to do. Fb driver would call the flush interface in 'fb->dirty' callback, this helper function would force all PSR enabled encoders to exit from PSR for 3 seconds. Signed-off-by: Yakir Yang --- Changes in v3: - split the psr flow into an common abstracted PSR driver - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - remove psr_active() callback which introduce in v2 Changes in v2: None drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 200 drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 24 5 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 05d0713..9746365 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 20f12bc..0fec18f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -21,6 +21,7 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_gem.h" +#include "rockchip_drm_psr.h" #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb) @@ -66,9 +67,20 @@ static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb, rockchip_fb->obj[0], handle); } +static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, +struct drm_file *file, +unsigned int flags, unsigned int color, +struct drm_clip_rect *clips, +unsigned int num_clips) +{ + rockchip_drm_psr_flush(); + return 0; +} + static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = { .destroy= rockchip_drm_fb_destroy, .create_handle = rockchip_drm_fb_create_handle, + .dirty = rockchip_drm_fb_dirty, }; static struct rockchip_drm_fb * diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c new file mode 100644 index 000..c03 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c @@ -0,0 +1,200 @@ +#include + +#include "rockchip_drm_psr.h" + +#define PSR_FLUSH_TIMEOUT msecs_to_jiffies(3000) /* 3 seconds */ + +static LIST_HEAD(psr_list); +static DEFINE_MUTEX(psr_list_mutex); I'm not crazy about these globals. Perhaps you can initialize them with the rockchip driver and tuck them in a driver-level struct (rockchip_drm_private or something). + +enum psr_state { + PSR_FLUSH, + PS