[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, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_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, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_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, >>
[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 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, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_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, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_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(&dp->aux, DP_PSR_STATUS, &sink); + 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 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, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_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, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_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
[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, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_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, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_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(&dp->aux, DP_PSR_STATUS, &sink); + 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 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, - &extend_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[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[EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(&edid[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, - &test_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 *
[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, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_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, &psr_vsc); >> - return 0; >> + return analogix_dp_send_psr_spd(dp, &psr_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, &sink); > 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); >&
[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, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_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, &psr_vsc); - return 0; + return analogix_dp_send_psr_spd(dp, &psr_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, &sink); + + 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 2/3] drm/rockchip: Don't key off vblank for psr
Sean, Thanks for this good fix. On 08/19/2016 07:34 AM, Sean Paul wrote: > Instead of keying off vblank for psr, just flush every time > we get an atomic update. This ensures that cursor updates > will properly disable psr (without turning vblank on/off), > and unifies the paths between fb_dirty and atomic psr > enable/disable. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang Also I have verified this patch on RK3399 Kevin, eDP PSR works rightly, so Tested-by: Yakir Yang - Yakir > --- > drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 2 +- > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 72 > - > drivers/gpu/drm/rockchip/rockchip_drm_psr.h | 8 ++-- > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 10 ++-- > 4 files changed, 62 insertions(+), 30 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > index ba45d9d..10cafbc 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > @@ -70,7 +70,7 @@ static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, >struct drm_clip_rect *clips, >unsigned int num_clips) > { > - rockchip_drm_psr_flush(fb->dev); > + rockchip_drm_psr_flush_all(fb->dev); > return 0; > } > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index c6ac5d0..de6252f 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -31,6 +31,7 @@ struct psr_drv { > struct drm_encoder *encoder; > > spinlock_t lock; > + boolactive; > enum psr_state state; > > struct timer_list flush_timer; > @@ -67,11 +68,7 @@ static void psr_set_state_locked(struct psr_drv *psr, enum > psr_state state) >* v || >* PSR_DISABLE < - - - - - - - - - >*/ > - if (state == psr->state) > - return; > - > - /* Requesting a flush when disabled is a noop */ > - if (state == PSR_FLUSH && psr->state == PSR_DISABLE) > + if (state == psr->state || !psr->active) > return; > > psr->state = state; > @@ -115,45 +112,79 @@ static void psr_flush_handler(unsigned long data) > } > > /** > - * rockchip_drm_psr_enable - enable the encoder PSR which bind to given CRTC > + * rockchip_drm_psr_activate - activate PSR on the given pipe >* @crtc: CRTC to obtain the PSR encoder >* >* Returns: >* Zero on success, negative errno on failure. >*/ > -int rockchip_drm_psr_enable(struct drm_crtc *crtc) > +int rockchip_drm_psr_activate(struct drm_crtc *crtc) > { > struct psr_drv *psr = find_psr_by_crtc(crtc); > + unsigned long flags; > > if (IS_ERR(psr)) > return PTR_ERR(psr); > > - psr_set_state(psr, PSR_ENABLE); > + spin_lock_irqsave(&psr->lock, flags); > + psr->active = true; > + spin_unlock_irqrestore(&psr->lock, flags); > + > return 0; > } > -EXPORT_SYMBOL(rockchip_drm_psr_enable); > +EXPORT_SYMBOL(rockchip_drm_psr_activate); > > /** > - * rockchip_drm_psr_disable - disable the encoder PSR which bind to given > CRTC > + * rockchip_drm_psr_deactivate - deactivate PSR on the given pipe >* @crtc: CRTC to obtain the PSR encoder >* >* Returns: >* Zero on success, negative errno on failure. >*/ > -int rockchip_drm_psr_disable(struct drm_crtc *crtc) > +int rockchip_drm_psr_deactivate(struct drm_crtc *crtc) > { > struct psr_drv *psr = find_psr_by_crtc(crtc); > + unsigned long flags; > + > + if (IS_ERR(psr)) > + return PTR_ERR(psr); > + > + spin_lock_irqsave(&psr->lock, flags); > + psr->active = false; > + spin_unlock_irqrestore(&psr->lock, flags); > + del_timer_sync(&psr->flush_timer); > + > + return 0; > +} > +EXPORT_SYMBOL(rockchip_drm_psr_deactivate); > + > +static void rockchip_drm_do_flush(struct psr_drv *psr) > +{ > + mod_timer(&psr->flush_timer, > + round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT)); > + psr_set_state(psr, PSR_FLUSH); > +} > > +/** > + * rockchip_drm_psr_flush - flush a single pipe > + * @crtc: CRTC of the pipe to flush > + * > + * Returns: > + * 0 on success, -errno on fail > + */ > +int rockchip_drm_psr_flush(struct drm_crtc *crtc) > +{ >
[PATCH 3/3] drm/rockchip: Reduce psr flush time to 100ms
Sean, On 08/19/2016 07:34 AM, Sean Paul wrote: > 3 seconds is a bit too conservative, drop this to 100ms for > better power savings. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang > --- > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index de6252f..2cdd6eb 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -18,7 +18,7 @@ > #include "rockchip_drm_drv.h" > #include "rockchip_drm_psr.h" > > -#define PSR_FLUSH_TIMEOUTmsecs_to_jiffies(3000) /* 3 seconds */ > +#define PSR_FLUSH_TIMEOUTmsecs_to_jiffies(100) > > enum psr_state { > PSR_FLUSH,
[PATCH v3] drm/bridge: analogix_dp: Remove duplicated code
On 08/24/2016 10:54 PM, Sean Paul wrote: > 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 > Tested-by: Javier Martinez Canillas > Tested-by: Sean Paul > Reviewed-by: Sean Paul > Signed-off-by: Sean Paul > Cc: Javier Martinez Canillas > Cc: Mika Kahola > Cc: Yakir Yang > Cc: Daniel Vetter > Cc: Archit Taneja Reviewed-by: Yakir Yang > --- > > 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 > > v3: > - Rebased on top of Yakir's PSR series > - Fixed checkpatch warning about line length > > > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 274 - > drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 40 +- > drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 > ++--- > 3 files changed, 210 insertions(+), 555 deletions(-) -- next part -- An HTML attachment was scrubbed... URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20160825/a6944994/attachment.html>
[PATCH v2] drm/rockchip: Don't continue trying to enable crtc on failure
Sean, On 08/16/2016 07:12 AM, Sean Paul wrote: > If vop_enable fails, don't continue on, it causes system hangs. > > Signed-off-by: Sean Paul Also meet this problem on my Rk3399 Kevin board. VOP just failed to get the pm_runtime at resume time, but ï½ï½ï½ï½er still just continue without anything enable rightly, oops, and then system crashed :( So this patch looks good to me, and also fix my problem, thanks: ï¼²ï½ viewed-by: Yakir Yang Tested-by: Yakir Yang Thanks, - Yakir > --- > > This patch uses the new DRM_DEV_ERROR logging, so it should be applied on > top of "[PATCH 2/2] drm/rockchip: Use DRM_DEV_ERROR in vop". > > Changes in v2: > - Escalate dev_err to WARN_ON for clk_enable failures (Daniel Vetter) > > Sean > > > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 31 > - > 1 file changed, 17 insertions(+), 14 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index ec8ad00..a176d03 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > @@ -428,7 +428,7 @@ static void vop_dsp_hold_valid_irq_disable(struct vop > *vop) > spin_unlock_irqrestore(&vop->irq_lock, flags); > } > > -static void vop_enable(struct drm_crtc *crtc) > +static int vop_enable(struct drm_crtc *crtc) > { > struct vop *vop = to_vop(crtc); > int ret; > @@ -436,26 +436,20 @@ static void vop_enable(struct drm_crtc *crtc) > ret = pm_runtime_get_sync(vop->dev); > if (ret < 0) { > dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); > - return; > + goto err_put_pm_runtime; > } > > ret = clk_enable(vop->hclk); > - if (ret < 0) { > - dev_err(vop->dev, "failed to enable hclk - %d\n", ret); > - return; > - } > + if (WARN_ON(ret < 0)) > + goto err_put_pm_runtime; > > ret = clk_enable(vop->dclk); > - if (ret < 0) { > - dev_err(vop->dev, "failed to enable dclk - %d\n", ret); > + if (WARN_ON(ret < 0)) > goto err_disable_hclk; > - } > > ret = clk_enable(vop->aclk); > - if (ret < 0) { > - dev_err(vop->dev, "failed to enable aclk - %d\n", ret); > + if (WARN_ON(ret < 0)) > goto err_disable_dclk; > - } > > /* >* Slave iommu shares power, irq and clock with vop. It was associated > @@ -485,7 +479,7 @@ static void vop_enable(struct drm_crtc *crtc) > > drm_crtc_vblank_on(crtc); > > - return; > + return 0; > > err_disable_aclk: > clk_disable(vop->aclk); > @@ -493,6 +487,9 @@ err_disable_dclk: > clk_disable(vop->dclk); > err_disable_hclk: > clk_disable(vop->hclk); > +err_put_pm_runtime: > + pm_runtime_put_sync(vop->dev); > + return ret; > } > > static void vop_crtc_disable(struct drm_crtc *crtc) > @@ -912,10 +909,16 @@ static void vop_crtc_enable(struct drm_crtc *crtc) > u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start; > u16 vact_end = vact_st + vdisplay; > uint32_t val; > + int ret; > > WARN_ON(vop->event); > > - vop_enable(crtc); > + ret = vop_enable(crtc); > + if (ret) { > + DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret); > + return; > + } > + > /* >* If dclk rate is zero, mean that scanout is stop, >* we don't need wait any more.
[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(&psr_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, &psr_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(&psr_vsc, 0, sizeof(psr_vsc)); >> +
[PATCH v2 6/6] drm/rockchip: Enable vblank without event
Sean, On 08/17/2016 09:11 AM, Sean Paul wrote: > vblank should be enabled regardless of whether an event > is expected back. This is especially important for a cursor > plane. Yep, I also found that sometimes vblank haven't been enabled when I move the mouse lightly, that would cause eDP panel wound't exit from PSR active state, and then nothing would be updated on panel. After apply this patch, things work rightly now, thanks for fixing. Reviewed-by: Yakir Yang Tested-by: Yakir Yang > Signed-off-by: Sean Paul > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 15 ++- > 1 file changed, 10 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index d1e0e06..1787084 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > @@ -112,6 +112,7 @@ struct vop { > struct device *dev; > struct drm_device *drm_dev; > bool is_enabled; > + bool vblank_active; > > /* mutex vsync_ work */ > struct mutex vsync_mutex; > @@ -1107,10 +1108,11 @@ static void vop_crtc_atomic_begin(struct drm_crtc > *crtc, > struct vop *vop = to_vop(crtc); > > spin_lock_irq(&crtc->dev->event_lock); > - if (crtc->state->event) { > - WARN_ON(drm_crtc_vblank_get(crtc) != 0); > - WARN_ON(vop->event); > + vop->vblank_active = true; > + WARN_ON(drm_crtc_vblank_get(crtc) != 0); > + WARN_ON(vop->event); > > + if (crtc->state->event) { > vop->event = crtc->state->event; > crtc->state->event = NULL; > } > @@ -1197,12 +1199,14 @@ static void vop_handle_vblank(struct vop *vop) > > spin_lock_irqsave(&drm->event_lock, flags); > if (vop->event) { > - > drm_crtc_send_vblank_event(crtc, vop->event); > - drm_crtc_vblank_put(crtc); > vop->event = NULL; > > } > + if (vop->vblank_active) { > + vop->vblank_active = false; > + drm_crtc_vblank_put(crtc); > + } > spin_unlock_irqrestore(&drm->event_lock, flags); > > if (!completion_done(&vop->wait_update_complete)) > @@ -1472,6 +1476,7 @@ static int vop_initial(struct vop *vop) > clk_disable(vop->aclk); > > vop->is_enabled = false; > + vop->vblank_active = false; > > return 0; >
[PATCH v2 0/6] drm/rockchip: Some patches to update the PSR series
Sean, On 08/17/2016 10:45 AM, Sean Paul wrote: > > On Aug 16, 2016 7:41 PM, "Yakir Yang" <mailto:ykk at rock-chips.com>> wrote: > > > > Sean, > > > > Thanks a lot for your good fixes. I have reviewed most of them, and > all looks good to me. > > > > But I got a question for merging things. My PSR patch set still > under reviewing, haven't been picked up Mark or other maintainers. > > I've picked them up in my tree. I'll send a pull request to Dave once > all of the dependencies have been reviewed (marked NEEDS REVIEW). > Got it, thanks. - Yakir > Sean > > > Feel a little bit embarrassed, how could we handle this situation ? > > > > - Yakir > > > > > > On 08/17/2016 09:11 AM, Sean Paul wrote: > >> > >> This is a follow-on set to Yakir's original PSR set here: > >> https://lkml.org/lkml/2016/7/24/34 > >> and applies to the for-next branch at: > >> https://cgit.freedesktop.org/~seanpaul/dogwood > <https://cgit.freedesktop.org/%7Eseanpaul/dogwood> > >> > >> There are a few issues with the code that needed to be > >> shored up. > >> (1) The use of mutexes instead of spinlocks caused issues calling the > >> psr functions from vblank_enable/disable. > >> (2) The proliferation of workers due to (1) > >> (3) A bunch of races due to (2) > >> (4) vblank is not enabled unless an event is requested, this breaks > >> a lot of things, but most noticeable was cursor. > >> > >> Changes in v2: > >> - Rebased on https://cgit.freedesktop.org/~seanpaul/dogwood > <https://cgit.freedesktop.org/%7Eseanpaul/dogwood> > >> instead of random on-list patches (some of which had drifted) > >> - Added the "small fixes" patch to catch some nits > >> > >> > >> Sean Paul (6): > >>drm/rockchip: Convert psr_list_mutex to spinlock and use it > >>drm/rockchip: Don't use a delayed worker for psr state changes > >>drm/rockchip: Use a spinlock to protect psr state > >>drm/rockchip: A couple small fixes to psr > >>drm/rockchip: Improve analogix-dp psr handling > >>drm/rockchip: Enable vblank without event > >> > >> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 -- > >> drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > >> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- > >> drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 90 > - > >> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 15 +++-- > >> 5 files changed, 69 insertions(+), 59 deletions(-) > >> > > > > > -- next part -- An HTML attachment was scrubbed... URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20160817/6767c7a5/attachment.html>
[PATCH v2 0/6] drm/rockchip: Some patches to update the PSR series
Sean, On 08/17/2016 10:41 AM, Yakir Yang wrote: > Sean, > > Thanks a lot for your good fixes. I have reviewed most of them, and > all looks good to me. > > But I got a question for merging things. My PSR patch set still under > reviewing, haven't been picked up Mark or other maintainers. Feel a > little bit embarrassed, how could we handle this situation ? > > - Yakir > > On 08/17/2016 09:11 AM, Sean Paul wrote: >> This is a follow-on set to Yakir's original PSR set here: >> https://lkml.org/lkml/2016/7/24/34 >> and applies to the for-next branch at: >> https://cgit.freedesktop.org/~seanpaul/dogwood Oops, sorry for missing this comment, do you mean my PSR patch already have been site on your tree :-D - Yakir >> >> There are a few issues with the code that needed to be >> shored up. >> (1) The use of mutexes instead of spinlocks caused issues calling the >> psr functions from vblank_enable/disable. >> (2) The proliferation of workers due to (1) >> (3) A bunch of races due to (2) >> (4) vblank is not enabled unless an event is requested, this breaks >> a lot of things, but most noticeable was cursor. >> >> Changes in v2: >> - Rebased on https://cgit.freedesktop.org/~seanpaul/dogwood >> instead of random on-list patches (some of which had drifted) >> - Added the "small fixes" patch to catch some nits >> >> >> Sean Paul (6): >>drm/rockchip: Convert psr_list_mutex to spinlock and use it >>drm/rockchip: Don't use a delayed worker for psr state changes >>drm/rockchip: Use a spinlock to protect psr state >>drm/rockchip: A couple small fixes to psr >>drm/rockchip: Improve analogix-dp psr handling >>drm/rockchip: Enable vblank without event >> >> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 -- >> drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- >> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- >> drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 90 >> - >> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 15 +++-- >> 5 files changed, 69 insertions(+), 59 deletions(-) >> >
[PATCH v2 0/6] drm/rockchip: Some patches to update the PSR series
Sean, Thanks a lot for your good fixes. I have reviewed most of them, and all looks good to me. But I got a question for merging things. My PSR patch set still under reviewing, haven't been picked up Mark or other maintainers. Feel a little bit embarrassed, how could we handle this situation ? - Yakir On 08/17/2016 09:11 AM, Sean Paul wrote: > This is a follow-on set to Yakir's original PSR set here: > https://lkml.org/lkml/2016/7/24/34 > and applies to the for-next branch at: > https://cgit.freedesktop.org/~seanpaul/dogwood > > There are a few issues with the code that needed to be > shored up. > (1) The use of mutexes instead of spinlocks caused issues calling the > psr functions from vblank_enable/disable. > (2) The proliferation of workers due to (1) > (3) A bunch of races due to (2) > (4) vblank is not enabled unless an event is requested, this breaks > a lot of things, but most noticeable was cursor. > > Changes in v2: > - Rebased on https://cgit.freedesktop.org/~seanpaul/dogwood > instead of random on-list patches (some of which had drifted) > - Added the "small fixes" patch to catch some nits > > > Sean Paul (6): >drm/rockchip: Convert psr_list_mutex to spinlock and use it >drm/rockchip: Don't use a delayed worker for psr state changes >drm/rockchip: Use a spinlock to protect psr state >drm/rockchip: A couple small fixes to psr >drm/rockchip: Improve analogix-dp psr handling >drm/rockchip: Enable vblank without event > > drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 -- > drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 90 > - > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 15 +++-- > 5 files changed, 69 insertions(+), 59 deletions(-) >
[PATCH v2 5/6] drm/rockchip: Improve analogix-dp psr handling
On 08/17/2016 09:11 AM, Sean Paul wrote: > Remove the delayed worker, opting instead for the non-delayed > variety. Also introduce a lock to ensure we don't have races > with the worker and psr_state. Finally, cancel and wait for > the worker to finish when disabling the bridge. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 ++- > 1 file changed, 14 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c > b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c > index d6d0751..439b933 100644 > --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c > +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c > @@ -42,7 +42,6 @@ > > #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) > @@ -72,7 +71,8 @@ struct rockchip_dp_device { > struct regmap*grf; > struct reset_control *rst; > > - struct delayed_work psr_work; > + struct work_struct psr_work; > + spinlock_t psr_lock; > unsigned int psr_state; > > const struct rockchip_dp_chip_data *data; > @@ -83,25 +83,29 @@ struct rockchip_dp_device { > static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) > { > struct rockchip_dp_device *dp = to_dp(encoder); > + unsigned long flags; > > dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); > > + spin_lock_irqsave(&dp->psr_lock, flags); > if (enabled) > dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; > else > dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; > > - schedule_delayed_work(&dp->psr_work, PSR_SET_DELAY_TIME); > + schedule_work(&dp->psr_work); > + spin_unlock_irqrestore(&dp->psr_lock, flags); > } > > static void analogix_dp_psr_work(struct work_struct *work) > { > struct rockchip_dp_device *dp = > - container_of(work, typeof(*dp), psr_work.work); > + container_of(work, typeof(*dp), psr_work); > struct drm_crtc *crtc = dp->encoder.crtc; > int psr_state = dp->psr_state; > int vact_end; > int ret; > + unsigned long flags; > > if (!crtc) > return; > @@ -115,10 +119,12 @@ static void analogix_dp_psr_work(struct work_struct > *work) > return; > } > > + spin_lock_irqsave(&dp->psr_lock, flags); > if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) > analogix_dp_enable_psr(dp->dev); > else > analogix_dp_disable_psr(dp->dev); > + spin_unlock_irqrestore(&dp->psr_lock, flags); > } > > static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) > @@ -135,6 +141,8 @@ static int rockchip_dp_poweron(struct > analogix_dp_plat_data *plat_data) > struct rockchip_dp_device *dp = to_dp(plat_data); > int ret; > > + cancel_work_sync(&dp->psr_work); > + > ret = clk_prepare_enable(dp->pclk); > if (ret < 0) { > dev_err(dp->dev, "failed to enable pclk %d\n", ret); > @@ -390,8 +398,9 @@ 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; > > + spin_lock_init(&dp->psr_lock); > dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; > - INIT_DELAYED_WORK(&dp->psr_work, analogix_dp_psr_work); > + INIT_WORK(&dp->psr_work, analogix_dp_psr_work); > > rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); >
[PATCH v2 4/6] drm/rockchip: A couple small fixes to psr
On 08/17/2016 09:11 AM, Sean Paul wrote: > A few things that need tidying up, no functional changes. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang > --- > > Changes in v2: > - Introduced > > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 19 +++ > 1 file changed, 7 insertions(+), 12 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index 5bd54f2..c6ac5d0 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -62,27 +62,25 @@ static void psr_set_state_locked(struct psr_drv *psr, > enum psr_state state) >* Allowed finite state machine: >* >* PSR_ENABLE < = = = = = > PSR_FLUSH > - * | ^| > - * | || > - * v || > + * | ^| > + * | || > + * v || >* PSR_DISABLE < - - - - - - - - - >*/ > - > - /* Forbid no state change */ > if (state == psr->state) > return; > > - /* Forbid DISABLE change to FLUSH */ > + /* Requesting a flush when disabled is a noop */ > if (state == PSR_FLUSH && psr->state == PSR_DISABLE) > return; > > psr->state = state; > > - /* Allow but no need hardware change, just need assign the state */ > + /* Already disabled in flush, change the state, but not the hardware */ > if (state == PSR_DISABLE && psr->state == PSR_FLUSH) > return; > > - /* Refact to hardware state change */ > + /* Actually commit the state change to hardware */ > switch (psr->state) { > case PSR_ENABLE: > psr->set(psr->encoder, true); > @@ -109,10 +107,7 @@ static void psr_flush_handler(unsigned long data) > struct psr_drv *psr = (struct psr_drv *)data; > unsigned long flags; > > - if (!psr) > - return; > - > - /* State changed between flush time, then keep it */ > + /* If the state has changed since we initiated the flush, do nothing */ > spin_lock_irqsave(&psr->lock, flags); > if (psr->state == PSR_FLUSH) > psr_set_state_locked(psr, PSR_ENABLE);
[PATCH v2 3/6] drm/rockchip: Use a spinlock to protect psr state
On 08/17/2016 09:11 AM, Sean Paul wrote: > The handling of psr state is racey, shore that up with > a per-psr driver lock. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 26 +- > 1 file changed, 17 insertions(+), 9 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index 4c645d7..5bd54f2 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -30,6 +30,7 @@ struct psr_drv { > struct list_headlist; > struct drm_encoder *encoder; > > + spinlock_t lock; > enum psr_state state; > > struct timer_list flush_timer; > @@ -55,7 +56,7 @@ out: > return psr; > } > > -static void psr_set_state(struct psr_drv *psr, enum psr_state state) > +static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state) > { > /* >* Allowed finite state machine: > @@ -75,7 +76,6 @@ static void psr_set_state(struct psr_drv *psr, enum > psr_state state) > if (state == PSR_FLUSH && psr->state == PSR_DISABLE) > return; > > - /* Only wrote in this work, no need lock protection */ > psr->state = state; > > /* Allow but no need hardware change, just need assign the state */ > @@ -95,18 +95,28 @@ static void psr_set_state(struct psr_drv *psr, enum > psr_state state) > } > } > > +static void psr_set_state(struct psr_drv *psr, enum psr_state state) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&psr->lock, flags); > + psr_set_state_locked(psr, state); > + spin_unlock_irqrestore(&psr->lock, flags); > +} > + > static void psr_flush_handler(unsigned long data) > { > struct psr_drv *psr = (struct psr_drv *)data; > + unsigned long flags; > > if (!psr) > return; > > /* State changed between flush time, then keep it */ > - if (psr->state != PSR_FLUSH) > - return; > - > - psr_set_state(psr, PSR_ENABLE); > + spin_lock_irqsave(&psr->lock, flags); > + if (psr->state == PSR_FLUSH) > + psr_set_state_locked(psr, PSR_ENABLE); > + spin_unlock_irqrestore(&psr->lock, flags); > } > > /** > @@ -167,9 +177,6 @@ void rockchip_drm_psr_flush(struct drm_device *dev) > > spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_for_each_entry(psr, &drm_drv->psr_list, list) { > - if (psr->state == PSR_DISABLE) > - continue; > - > mod_timer(&psr->flush_timer, > round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT)); > > @@ -202,6 +209,7 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, > return -ENOMEM; > > setup_timer(&psr->flush_timer, psr_flush_handler, (unsigned long)psr); > + spin_lock_init(&psr->lock); > > psr->state = PSR_DISABLE; > psr->encoder = encoder;
[PATCH v2 2/6] drm/rockchip: Don't use a delayed worker for psr state changes
On 08/17/2016 09:11 AM, Sean Paul wrote: > The delayed worker isn't needed and is racey. Remove it and do > the state change in line. > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang Tested-by: Yakir Yang > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 38 > - > 1 file changed, 10 insertions(+), 28 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index bd25273..4c645d7 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -19,7 +19,6 @@ > #include "rockchip_drm_psr.h" > > #define PSR_FLUSH_TIMEOUT msecs_to_jiffies(3000) /* 3 seconds */ > -#define PSR_SET_DELAY_TIME msecs_to_jiffies(10) > > enum psr_state { > PSR_FLUSH, > @@ -31,11 +30,8 @@ struct psr_drv { > struct list_headlist; > struct drm_encoder *encoder; > > - enum psr_state request_state; > enum psr_state state; > > - struct delayed_work state_work; > - > struct timer_list flush_timer; > > void (*set)(struct drm_encoder *encoder, bool enable); > @@ -59,11 +55,8 @@ out: > return psr; > } > > -static void psr_state_work(struct work_struct *work) > +static void psr_set_state(struct psr_drv *psr, enum psr_state state) > { > - struct psr_drv *psr = container_of(work, typeof(*psr), state_work.work); > - enum psr_state request_state = psr->request_state; > - > /* >* Allowed finite state machine: >* > @@ -75,24 +68,22 @@ static void psr_state_work(struct work_struct *work) >*/ > > /* Forbid no state change */ > - if (request_state == psr->state) > + if (state == psr->state) > return; > > /* Forbid DISABLE change to FLUSH */ > - if (request_state == PSR_FLUSH && psr->state == PSR_DISABLE) > + if (state == PSR_FLUSH && psr->state == PSR_DISABLE) > return; > > + /* Only wrote in this work, no need lock protection */ > + psr->state = state; > + > /* Allow but no need hardware change, just need assign the state */ > - if (request_state == PSR_DISABLE && psr->state == PSR_FLUSH) { > - psr->state = request_state; > + if (state == PSR_DISABLE && psr->state == PSR_FLUSH) > return; > - } > - > - /* Only wrote in this work, no need lock protection */ > - psr->state = request_state; > > /* Refact to hardware state change */ > - switch (request_state) { > + switch (psr->state) { > case PSR_ENABLE: > psr->set(psr->encoder, true); > break; > @@ -104,13 +95,6 @@ static void psr_state_work(struct work_struct *work) > } > } > > -static void psr_set_state(struct psr_drv *psr, enum psr_state state) > -{ > - psr->request_state = state; > - > - schedule_delayed_work(&psr->state_work, PSR_SET_DELAY_TIME); > -} > - > static void psr_flush_handler(unsigned long data) > { > struct psr_drv *psr = (struct psr_drv *)data; > @@ -119,7 +103,7 @@ static void psr_flush_handler(unsigned long data) > return; > > /* State changed between flush time, then keep it */ > - if (psr->request_state != PSR_FLUSH) > + if (psr->state != PSR_FLUSH) > return; > > psr_set_state(psr, PSR_ENABLE); > @@ -183,7 +167,7 @@ void rockchip_drm_psr_flush(struct drm_device *dev) > > spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_for_each_entry(psr, &drm_drv->psr_list, list) { > - if (psr->request_state == PSR_DISABLE) > + if (psr->state == PSR_DISABLE) > continue; > > mod_timer(&psr->flush_timer, > @@ -219,8 +203,6 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, > > setup_timer(&psr->flush_timer, psr_flush_handler, (unsigned long)psr); > > - INIT_DELAYED_WORK(&psr->state_work, psr_state_work); > - > psr->state = PSR_DISABLE; > psr->encoder = encoder; > psr->set = psr_set;
[PATCH v2 1/6] drm/rockchip: Convert psr_list_mutex to spinlock and use it
On 08/17/2016 09:11 AM, Sean Paul wrote: > This patch converts the psr_list_mutex to a spinlock and locks > all access to psr_list to avoid races (however unlikely they > were). > > Signed-off-by: Sean Paul Reviewed-by: Yakir Yang > --- > > Changes in v2: > - Rebased on > https://cgit.freedesktop.org/~seanpaul/dogwood/log/?h=for-next > > drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- > drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 25 ++--- > 3 files changed, 20 insertions(+), 9 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c > b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c > index b43fe5d9..76eaf1d 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c > @@ -157,7 +157,7 @@ static int rockchip_drm_bind(struct device *dev) > drm_dev->dev_private = private; > > INIT_LIST_HEAD(&private->psr_list); > - mutex_init(&private->psr_list_mutex); > + spin_lock_init(&private->psr_list_lock); > > 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 9c34c9e..5c69845 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h > @@ -63,7 +63,7 @@ struct rockchip_drm_private { > struct drm_atomic_state *state; > > struct list_head psr_list; > - struct mutex psr_list_mutex; > + spinlock_t psr_list_lock; > }; > > int rockchip_register_crtc_funcs(struct drm_crtc *crtc, > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > index a6d3bd25..bd25273 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c > @@ -45,12 +45,18 @@ static struct psr_drv *find_psr_by_crtc(struct drm_crtc > *crtc) > { > struct rockchip_drm_private *drm_drv = crtc->dev->dev_private; > struct psr_drv *psr; > + unsigned long flags; > > - list_for_each_entry(psr, &drm_drv->psr_list, list) > + spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > + list_for_each_entry(psr, &drm_drv->psr_list, list) { > if (psr->encoder->crtc == crtc) > - return psr; > + goto out; > + } > + psr = ERR_PTR(-ENODEV); > > - return ERR_PTR(-ENODEV); > +out: > + spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); > + return psr; > } > > static void psr_state_work(struct work_struct *work) > @@ -173,7 +179,9 @@ void rockchip_drm_psr_flush(struct drm_device *dev) > { > struct rockchip_drm_private *drm_drv = dev->dev_private; > struct psr_drv *psr; > + unsigned long flags; > > + spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_for_each_entry(psr, &drm_drv->psr_list, list) { > if (psr->request_state == PSR_DISABLE) > continue; > @@ -183,6 +191,7 @@ void rockchip_drm_psr_flush(struct drm_device *dev) > > psr_set_state(psr, PSR_FLUSH); > } > + spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); > } > EXPORT_SYMBOL(rockchip_drm_psr_flush); > > @@ -199,6 +208,7 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, > { > struct rockchip_drm_private *drm_drv = encoder->dev->dev_private; > struct psr_drv *psr; > + unsigned long flags; > > if (!encoder || !psr_set) > return -EINVAL; > @@ -215,9 +225,9 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, > psr->encoder = encoder; > psr->set = psr_set; > > - mutex_lock(&drm_drv->psr_list_mutex); > + spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_add_tail(&psr->list, &drm_drv->psr_list); > - mutex_unlock(&drm_drv->psr_list_mutex); > + spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); > > return 0; > } > @@ -235,8 +245,9 @@ void rockchip_drm_psr_unregister(struct drm_encoder > *encoder) > { > struct rockchip_drm_private *drm_drv = encoder->dev->dev_private; > struct psr_drv *psr, *n; > + unsigned long flags; > > - mutex_lock(&drm_drv->psr_list_mutex); > + spin_lock_irqsave(&drm_drv->psr_list_lock, flags); > list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) { > if (psr->encoder == encoder) { > del_timer(&psr->flush_timer); > @@ -244,6 +255,6 @@ void rockchip_drm_psr_unregister(struct drm_encoder > *encoder) > kfree(psr); > } > } > - mutex_unlock(&drm_drv->psr_list_mutex); > + spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); > } > EXPORT_SYMBOL(rockchip_drm_psr_unregister);
[PATCH] drm/rockchip: Properly adjust to a true clock in adjusted_mode
Sean, On 08/09/2016 03:29 AM, Sean Paul wrote: > From: Douglas Anderson > > When fixing up the clock in vop_crtc_mode_fixup() we're not doing it > quite correctly. Specifically if we've got the true clock 26667 Hz, > we'll perform this calculation: > 26667 / 1000 => 26 > > Later when we try to set the clock we'll do clk_set_rate(26 * > 1000). The common clock framework won't actually pick the proper clock > in this case since it always wants clocks <= the specified one. > > Let's solve this by using DIV_ROUND_UP. > > Signed-off-by: Douglas Anderson > Signed-off-by: Sean Paul After discuss with Zheng Xing (Rockchip clock contributor), we think this patch looks good, so: Reviewed-by: Yakir Yang > --- > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index 31744fe..1bbffaf 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > @@ -891,7 +891,8 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, > struct vop *vop = to_vop(crtc); > > adjusted_mode->clock = > - clk_round_rate(vop->dclk, mode->clock * 1000) / 1000; > + DIV_ROUND_UP(clk_round_rate(vop->dclk, mode->clock * 1000), > + 1000); > > return true; > }
[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(&dp->panel_lock); > + > + /* > + * Exit early if this is a temporary prepare/unprepare and we're already > + * modeset (since we neither want to prepare twice or unprepare early). > + */ > + if (dp->panel_is_modeset && !is_modeset_prepare) > + goto out; > + > + if (prepare) > + ret = drm_panel_prepare(dp->plat_data->panel); > + else > + ret = drm_panel_unprepare(dp->plat_data->panel); > + > + if (ret) > + goto out; > + > + if (is_modeset_prepare) > + dp->panel_is_modeset = prepare; > + > +out: > + mutex_unlock(&dp->panel_lock); > + return ret; > +} > + > 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(&dp->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; >
[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, > - &extend_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[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[EDID_BLOCK_LENGTH]); > - if (retval != 0) { > - dev_err(dp->dev, "EDID Read failed!\n"); > - return -EIO; > - } > - sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); > - if (sum != 0) { > - dev_err(dp->dev, "EDID bad checksum!\n"); > - return -EIO; > - } > - > - analogix_dp_read_
[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, > - &extend_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[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[EDID_BLOCK_LENGTH]); > - if (retval != 0) { > - dev_err(dp->dev, "EDID Read failed!\n"); > - return -EIO; > - } > - sum = analogix_dp_calc_edid_check_sum(&edid[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, > - &test_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, > -
[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, > - &extend_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[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[EDID_BLOCK_LENGTH]); > - if (retval != 0) { > - dev_err(dp->dev, "EDID Read failed!\n"); > - return -EIO; > - } > - sum = analogix_dp_calc_edid_check_sum(&edid[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, > - &test_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); > -
[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, &frame, 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(&frame.audio); >> +faudio = (struct hdmi_audio_infoframe *)&frame; >> + >> +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
[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, &frame, 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(&frame.audio); > + faudio = (struct hdmi_audio_infoframe *)&frame; > + > + 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, &frame, INFOFRAME_AAI, 0, 0, 0); > +} > + > static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) > { > struct hdmi_data_info *data = &hdmi->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)
[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
[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
[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_m
[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(&pdev->dev, dp->irq, >> -- >> 1.9.1 >> >> >> >> >> > >
[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 >> at 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 >> at 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(&private->psr_list); >> +mutex_init(&private->psr_list_mutex); >> + >>
[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(&psr->state_mutex); >> + >> + if (psr->state == state) { >> + mutex_unlock(&psr->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(&psr->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 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 at 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(&dp->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(&dp->psr_work, analogix_dp_psr_work); + + rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); + return analogix_dp_bind(dev, dp->drm_dev, &dp->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(&dp->encoder); + return analogix_dp_unbind(dev, master, data); } -- 1.9.1
[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(&psr_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, &psr_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(&psr_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, &psr_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, &psr_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, &psr_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
[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 at 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 at 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(&private->psr_list); + mutex_init(&private->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" +#inclu
[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 at 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(&vop->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(&vop->irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(&vop->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(&vop->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(&vop->irq_lock, flags); +} + +static void vop_line_flag_irq_disable(struct vop *vop) +{ + unsigned long flags; + + if (WARN_ON(!vop->is_enabled)) + return; +
[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 at 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 at 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 at 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 at 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/rockchi
[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 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(&pdev->dev, dp->irq, -- 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
[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 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable
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 ** >> +*/ >> + 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(&pdev->dev, dp->irq, >> -- >> 1.9.1 >> >> > > -- next part -- An HTML attachment was scrubbed... URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20160722/5c4a6f5c/attachment.html>
[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(&pdev->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(&pdev->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 --- 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 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
[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(&psr_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, &psr_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(&psr_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, &psr_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, &psr_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
[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 >> at 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(&vop->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 +
[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(&psr_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, &psr_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(&psr_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, &psr_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, &psr_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, &psr_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 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 at 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(&vop->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(&vop->irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(&vop->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(&vop->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(&vop->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(&vop->irq_lock, flags); + + VOP_INTR_
[PATCH v4 3/4] drm/bridge: analogix_dp: add the PSR function support
Sean, On 07/15/2016 05:32 PM, Yakir Yang wrote: > Sean, > > On 07/14/2016 11:23 PM, Sean Paul wrote: >> On Thu, Jul 14, 2016 at 12:15:53PM +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 >>> --- >>> 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, &psr_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, &psr_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_VER
[PATCH v4 3/4] drm/bridge: analogix_dp: add the PSR function support
Sean, On 07/14/2016 11:23 PM, Sean Paul wrote: > On Thu, Jul 14, 2016 at 12:15:53PM +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 >> --- >> 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, &psr_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, &psr_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 v
[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 >> at 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(&dp->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(&dp->psr_work, analogix_dp_psr_work); >> + >> +rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); >> + >> return analogix_dp_bind(dev, dp->drm_dev, &dp->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(&dp->encoder); >> + >> return analogix_dp_unbind(dev, master, data); >> } >> >> -- >> 1.9.1 >> >> >> ___ >> dri-devel mailing list >> dri-devel at lists.freedesktop.org >> https://lists.freedesktop.org/mailman/listinfo/dri-devel > >
[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 >> at 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 >> at 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(&private->psr_list); >> +mutex_init(&private->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); >>
[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 >> at 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(&vop->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) >>
[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 at 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(&dp->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(&dp->psr_work, analogix_dp_psr_work); + + rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); + return analogix_dp_bind(dev, dp->drm_dev, &dp->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(&dp->encoder); + return analogix_dp_unbind(dev, master, data); } -- 1.9.1
[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, &psr_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, &psr_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
[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 at 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 at 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(&private->psr_list); + mutex_init(&private->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,
[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 at 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(&vop->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(&vop->irq_lock, flags); + + line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); + + spin_unlock_irqrestore(&vop->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(&vop->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(&vop->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(&vop->irq_lock, flags); + + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0); + + spin_unlock_irqrestore(&
[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 at 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 at 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 at 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 at 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 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 at 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) == -EPRO
[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 > > > >
[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 f
[PATCH v3 3/4] drm/bridge: analogix_dp: add the PSR function support
Sean, On 07/12/2016 11:29 PM, Sean Paul wrote: > On Thu, Jul 7, 2016 at 7:26 PM, Yakir Yang wrote: >> Sean, >> >> Thanks for your review. >> >> >> On 07/02/2016 03:46 AM, Sean Paul wrote: >>> On Fri, Jul 1, 2016 at 5:19 AM, 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 >>>> --- >>>> 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 | 64 >>>> ++ >>>>drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++ >>>>drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 54 >>>> ++ >>>>drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 ++ >>>>include/drm/bridge/analogix_dp.h | 3 + >>>>5 files changed, 153 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..b557097 100644 >>>> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >>>> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >>>> @@ -97,6 +97,66 @@ static int analogix_dp_detect_hpd(struct >>>> analogix_dp_device *dp) >>>> return 0; >>>>} >>>> >>>> +int analogix_dp_active_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_active_psr); >>>> + >>>> +int analogix_dp_inactive_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_inactive_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, >>>> &psr_version); >>>> + dev_info(dp->dev, "Panel PSR version : %x\n", psr_version); >>>> + >>> This info message is likely to be spammy since it's printed everytime >>> the panel toggle on. Perhaps downgrade to debug level. >> >> Okay, done. >> >>>> + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; >>>> +} >>>> + >>>> +static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) >>> Return type is int, but the function never fails and you don't check >>> the return value when calling it. Seems like this should be void. >> >> Done. >> >>>> +{ >>>> + unsigned char psr_en; >>>> + >>>> + /* Disable psr function */ >>>> + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_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 >>>> */ >>>> + analogix
[PATCH v1 6/6] drm/rockchip: dw_hdmi: introduce the pclk for grf
For RK3399's GRF module, if we want to operate the graphic related grf registers, we need to enable the pclk_vio_grf which supply power for VIO GRF IOs, so it's better to introduce an optional grf clock in driver. Signed-off-by: Yakir Yang --- .../bindings/display/rockchip/dw_hdmi-rockchip.txt | 3 ++- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 20 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index 4e23ca4..e22d70f 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -18,7 +18,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", - phandle to the VPLL clock, name should be "vpll". + phandle to the VPLL clock, name should be "vpll", + phandle to the GRF clock, name should be "grf". Example: hdmi: hdmi at ff98 { diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 701bb73..69e6efb 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -36,6 +36,7 @@ struct rockchip_hdmi { struct drm_encoder encoder; enum dw_hdmi_devtype dev_type; struct clk *vpll_clk; + struct clk *grf_clk; }; #define to_rockchip_hdmi(x)container_of(x, struct rockchip_hdmi, x) @@ -166,6 +167,16 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) return PTR_ERR(hdmi->vpll_clk); } + hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf"); + if (PTR_ERR(hdmi->grf_clk) == -ENOENT) { + hdmi->grf_clk = NULL; + } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (IS_ERR(hdmi->grf_clk)) { + dev_err(hdmi->dev, "failed to get grf clock\n"); + return PTR_ERR(hdmi->grf_clk); + } + ret = clk_prepare_enable(hdmi->vpll_clk); if (ret) { dev_err(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret); @@ -225,6 +236,7 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) u32 lcdsel_grf_reg, lcdsel_mask; u32 val; int mux; + int ret; switch (hdmi->dev_type) { case RK3288_HDMI: @@ -245,9 +257,17 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) else val = HIWORD_UPDATE(0, lcdsel_mask); + ret = clk_prepare_enable(hdmi->grf_clk); + if (ret < 0) { + dev_err(hdmi->dev, "failed to enable grfclk %d\n", ret); + return; + } + regmap_write(hdmi->regmap, lcdsel_grf_reg, val); dev_dbg(hdmi->dev, "vop %s output to hdmi\n", (mux) ? "LIT" : "BIG"); + + clk_disable_unprepare(hdmi->grf_clk); } static int -- 1.9.1
[PATCH v1 5/6] drm/rockchip: dw_hdmi: introduce the VPLL clock setting
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. Signed-off-by: Yakir Yang --- .../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 at 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) -- 1.9.1
[PATCH v1 4/6] drm/rockchip: dw_hdmi: add RK3399 HDMI support
RK3399 and RK3288 shared the same HDMI IP controller, only some light difference with GRF configure. Signed-off-by: Yakir Yang --- .../devicetree/bindings/display/bridge/dw_hdmi.txt | 1 + .../bindings/display/rockchip/dw_hdmi-rockchip.txt | 3 +- drivers/gpu/drm/bridge/dw-hdmi.c | 2 +- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c| 45 ++ include/drm/bridge/dw_hdmi.h | 6 +++ 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt index dc1452f..f50d4d5 100644 --- a/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt +++ b/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt @@ -6,6 +6,7 @@ Required properties: * "fsl,imx6q-hdmi" * "fsl,imx6dl-hdmi" * "rockchip,rk3288-dw-hdmi" + * "rockchip,rk3399-dw-hdmi" - reg: Physical base address and length of the controller's registers. - interrupts: The HDMI interrupt number - clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks, diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index 668091f..4e573d2 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -2,7 +2,8 @@ Rockchip specific extensions to the Synopsys Designware HDMI Required properties: -- compatible: "rockchip,rk3288-dw-hdmi"; +- compatible: "rockchip,rk3288-dw-hdmi", + "rockchip,rk3399-dw-hdmi"; - reg: Physical base address and length of the controller's registers. - clocks: phandle to hdmi iahb and isfr clocks. - clock-names: should be "iahb" "isfr" diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 70b1f7d..29f855a 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -833,7 +833,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, dw_hdmi_phy_gen2_txpwron(hdmi, 1); dw_hdmi_phy_gen2_pddq(hdmi, 0); - if (hdmi->dev_type == RK3288_HDMI) + if (is_rockchip(hdmi->dev_type)) dw_hdmi_phy_enable_spare(hdmi, 1); /*Wait for PHY PLL lock */ diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 8cb9ed2..329099b 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -21,13 +21,18 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" -#define GRF_SOC_CON60x025c -#define HDMI_SEL_VOP_LIT(1 << 4) +#define RK3288_GRF_SOC_CON60x025C +#define RK3288_HDMI_LCDC_SEL BIT(4) +#define RK3399_GRF_SOC_CON20 0x6250 +#define RK3399_HDMI_LCDC_SEL BIT(6) + +#define HIWORD_UPDATE(val, mask) (val | (mask) << 16) struct rockchip_hdmi { struct device *dev; struct regmap *regmap; struct drm_encoder encoder; + enum dw_hdmi_devtype dev_type; }; #define to_rockchip_hdmi(x)container_of(x, struct rockchip_hdmi, x) @@ -194,16 +199,30 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) { struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); + u32 lcdsel_grf_reg, lcdsel_mask; u32 val; int mux; + switch (hdmi->dev_type) { + case RK3288_HDMI: + lcdsel_grf_reg = RK3288_GRF_SOC_CON6; + lcdsel_mask = RK3288_HDMI_LCDC_SEL; + break; + case RK3399_HDMI: + lcdsel_grf_reg = RK3399_GRF_SOC_CON20; + lcdsel_mask = RK3399_HDMI_LCDC_SEL; + break; + default: + return; + }; + mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder); if (mux) - val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16); + val = HIWORD_UPDATE(lcdsel_mask, lcdsel_mask); else - val = HDMI_SEL_VOP_LIT << 16; + val = HIWORD_UPDATE(0, lcdsel_mask); - regmap_write(hdmi->regmap, GRF_SOC_CON6, val); + regmap_write(hdmi->regmap, lcdsel_grf_reg, val); dev_dbg(hdmi->dev, "vop %s output to hdmi\n", (mux) ? "LIT" : "BIG"); } @@ -229,7 +248,7 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun .atomic_check = dw_hdmi_rockchip_encoder_atomic_check, };
[PATCH v1 3/6] drm/rockchip: dw_hdmi: Use auto-generated tables
From: Douglas Anderson The previous tables for mpll_cfg and curr_ctrl were created using the 20-pages of example settings provided by the PHY vendor. Those example settings weren't particularly dense, so there were places where we were guessing what the settings would be for 10-bit and 12-bit (not that we use those anyway). It was also always a lot of extra work every time we wanted to add a new clock rate since we had to cross-reference several tables. In <http://crosreview.com/285855> I've gone through the work to figure out how to generate this table automatically. Let's now use the automatically generated table and then we'll never need to look at it again. We only support 8-bit mode right now and only support a small number of clock rates and and I've verified that the only 8-bit rate that was affected was 148.5. That mode appears to have been wrong in the old table. Signed-off-by: Douglas Anderson Signed-off-by: Yakir Yang Reviewed-by: Stéphane Marchesin --- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 130 +++- 1 file changed, 69 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index cdb63ac..8cb9ed2 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -34,80 +34,88 @@ struct rockchip_hdmi { static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { { - 2700, { - { 0x00b3, 0x}, - { 0x2153, 0x}, - { 0x40f3, 0x} + 30666000, { + { 0x00b3, 0x }, + { 0x2153, 0x }, + { 0x40f3, 0x }, }, - }, { - 3600, { - { 0x00b3, 0x}, - { 0x2153, 0x}, - { 0x40f3, 0x} + }, { + 3680, { + { 0x00b3, 0x }, + { 0x2153, 0x }, + { 0x40a2, 0x0001 }, }, - }, { - 4000, { - { 0x00b3, 0x}, - { 0x2153, 0x}, - { 0x40f3, 0x} + }, { + 4600, { + { 0x00b3, 0x }, + { 0x2142, 0x0001 }, + { 0x40a2, 0x0001 }, }, - }, { - 5400, { - { 0x0072, 0x0001}, - { 0x2142, 0x0001}, - { 0x40a2, 0x0001}, + }, { + 61333000, { + { 0x0072, 0x0001 }, + { 0x2142, 0x0001 }, + { 0x40a2, 0x0001 }, }, - }, { - 6500, { - { 0x0072, 0x0001}, - { 0x2142, 0x0001}, - { 0x40a2, 0x0001}, + }, { + 7360, { + { 0x0072, 0x0001 }, + { 0x2142, 0x0001 }, + { 0x4061, 0x0002 }, }, - }, { - 6600, { - { 0x013e, 0x0003}, - { 0x217e, 0x0002}, - { 0x4061, 0x0002} + }, { + 9200, { + { 0x0072, 0x0001 }, + { 0x2145, 0x0002 }, + { 0x4061, 0x0002 }, + }, + }, { + 122666000, { + { 0x0051, 0x0002 }, + { 0x2145, 0x0002 }, + { 0x4061, 0x0002 }, }, - }, { - 7425, { - { 0x0072, 0x0001}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} + }, { + 14720, { + { 0x0051, 0x0002 }, + { 0x2145, 0x0002 }, + { 0x4064, 0x0003 }, }, - }, { - 8350, { - { 0x0072, 0x0001}, + }, { + 18400, { + { 0x0051, 0x0002 }, + { 0x214c, 0x0003 }, + { 0x4064, 0x0003 }, }, - }, { - 10800, { - { 0x0051, 0x0002}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} + }, { + 22000, { + { 0x0040, 0x0003 }, + { 0x214c, 0x0003 }, + { 0x4064, 0x0003 }, }, - }, { - 10650, { - { 0x0051, 0x0002}, - { 0x2145, 0x0002}, -
[PATCH v1 2/6] drm/rockchip: dw_hdmi: adjust cklvl & txlvl for RF/EMI
Dut to the high HDMI signal voltage driver, Mickey have meet a serious RF/EMI problem, so we decided to reduce HDMI signal voltage to a proper value. The default params for phy is cklvl = 20 & txlvl = 13 (RF/EMI failed) ck: lvl = 13, term=100, vlo = 2.71, vhi=3.14, vswing = 0.43 tx: lvl = 20, term=100, vlo = 2.81, vhi=3.16, vswing = 0.35 1. We decided to reduce voltage value to lower, but VSwing still keep high, RF/EMI have been improved but still failed. ck: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 tx: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 2. We try to keep voltage value and vswing both lower, then RF/EMI test all passed ;) ck: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 tx: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 When we back to run HDMI different test and single-end test, we see different test passed, but signle-end test failed. The oscilloscope show that simgle-end clock's VL value is 1.78v (which remind LowLimit should not lower then 2.6v). 3. That's to say there are some different between PHY document and measure value. And according to experiment 2 results, we need to higher clock voltage and lower data voltage, then we can keep RF/EMI satisfied and single-end & differen test passed. ck: lvl = 9, term=100, vlo = 2.65, vhi=3.12, vswing = 0.47 tx: lvl = 16, term=100, vlo = 2.75, vhi=3.15, vswing = 0.39 Signed-off-by: Yakir Yang Reviewed-by: Douglas Anderson --- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index a621118..cdb63ac 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -124,7 +124,7 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { static const struct dw_hdmi_phy_config rockchip_phy_config[] = { /*pixelclk symbol term vlev*/ { 7425, 0x8009, 0x0004, 0x0272}, - { 14850, 0x802b, 0x0004, 0x028d}, + { 16500, 0x802b, 0x0004, 0x0209}, { 29700, 0x8039, 0x0005, 0x028d}, { ~0UL, 0x, 0x, 0x} }; -- 1.9.1
[PATCH v1 1/6] drm/rockchip: dw_hdmi: Set cur_ctr to 0 always
From: Douglas Anderson Jitter was improved by lowering the MPLL bandwidth to account for high frequency noise in the rk3288 PLL. In each case MPLL bandwidth was lowered only enough to get us a comfortable margin. We believe that lowering the bandwidth like this is safe given sufficient testing. Signed-off-by: Douglas Anderson Signed-off-by: Yakir Yang --- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++-- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 801110f..a621118 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -115,20 +115,8 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { /* pixelclkbpp8bpp10 bpp12 */ { - 4000, { 0x0018, 0x0018, 0x0018 }, - }, { - 6500, { 0x0028, 0x0028, 0x0028 }, - }, { - 6600, { 0x0038, 0x0038, 0x0038 }, - }, { - 7425, { 0x0028, 0x0038, 0x0038 }, - }, { - 8350, { 0x0028, 0x0038, 0x0038 }, - }, { - 14625, { 0x0038, 0x0038, 0x0038 }, - }, { - 14850, { 0x, 0x0038, 0x0038 }, - }, { + 6, { 0x, 0x, 0x }, + }, { ~0UL, { 0x, 0x, 0x}, } }; -- 1.9.1
[PATCH v1 0/6] Add RK3399 HDMI Support
Mark, RK3399 and RK3288 shared the same HDMI IP controller, only some light difference with GRF configure, and an external VPLL clock need to configure. Thanks, - Yakir Douglas Anderson (2): drm/rockchip: dw_hdmi: Set cur_ctr to 0 always drm/rockchip: dw_hdmi: Use auto-generated tables Yakir Yang (4): drm/rockchip: dw_hdmi: adjust cklvl & txlvl for RF/EMI drm/rockchip: dw_hdmi: add RK3399 HDMI support drm/rockchip: dw_hdmi: introduce the VPLL clock setting drm/rockchip: dw_hdmi: introduce the pclk for grf .../devicetree/bindings/display/bridge/dw_hdmi.txt | 1 + .../bindings/display/rockchip/dw_hdmi-rockchip.txt | 7 +- drivers/gpu/drm/bridge/dw-hdmi.c | 2 +- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c| 238 + include/drm/bridge/dw_hdmi.h | 6 + 5 files changed, 167 insertions(+), 87 deletions(-) -- 1.9.1
[PATCH v3 3/4] drm/bridge: analogix_dp: add the PSR function support
On 07/08/2016 10:26 AM, Yakir Yang wrote: > Sean, > > Thanks for your review. > > On 07/02/2016 03:46 AM, Sean Paul wrote: >> On Fri, Jul 1, 2016 at 5:19 AM, 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 >>> --- >>> 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 | 64 >>> ++ >>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++ >>> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 54 >>> ++ >>> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 ++ >>> include/drm/bridge/analogix_dp.h | 3 + >>> 5 files changed, 153 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..b557097 100644 >>> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >>> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >>> @@ -97,6 +97,66 @@ static int analogix_dp_detect_hpd(struct >>> analogix_dp_device *dp) >>> return 0; >>> } >>> >>> +int analogix_dp_active_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_active_psr); >>> + >>> +int analogix_dp_inactive_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_inactive_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, >>> &psr_version); >>> + dev_info(dp->dev, "Panel PSR version : %x\n", psr_version); >>> + >> This info message is likely to be spammy since it's printed everytime >> the panel toggle on. Perhaps downgrade to debug level. > > Okay, done. > >>> + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; >>> +} >>> + >>> +static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) >> Return type is int, but the function never fails and you don't check >> the return value when calling it. Seems like this should be void. > > Done. > >>> +{ >>> + unsigned char psr_en; >>> + >>> + /* Disable psr function */ >>> + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_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 */ >>> + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); >>> + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; >> Why read psr_en if you're just going to overwrite it? Perhaps you >> meant |= here. >> > > Yes, it's my mistaken, no need to read the DP_PSR_EN_CFG, just > configure it directly is enough. > >>> + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); >>> + >>> + /* Enable psr function */ >&g
[PATCH v3 4/4] drm/rockchip: analogix_dp: implement PSR function
Sean, On 07/02/2016 04:05 AM, Sean Paul wrote: > On Fri, Jul 1, 2016 at 5:19 AM, 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 >> --- >> 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 | 52 >> + >> 1 file changed, 52 insertions(+) >> >> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> index e81e19a..80a60a6 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 >> @@ -68,11 +69,53 @@ 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 int analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) > Again, this function doesn't fail, but its return type is int. > Fortunately you don't check the return in rockchip_drm_psr.c, so this > also seems like a good void candidate. Okay, done. >> +{ >> + 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(&dp->psr_work, msecs_to_jiffies(10)); > Pull 10 out into a #define Done >> + >> + return 0; >> +} >> + >> +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, 100); > > Pull 100 out into a #define > Done. >> + if (ret == 0) { > if (ret) { > dev_err(... "line flag interrupt did not arrive"); > return; > } Done. Thanks - Yakir >> + if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) >> + analogix_dp_active_psr(dp->dev); >> + else >> + analogix_dp_inactive_psr(dp->dev); >> + } >> +} >> + >> static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) >> { >> reset_control_assert(dp->rst); >> @@ -340,12 +383,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(&dp->psr_work, analogix_dp_psr_work); >> + >> + rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); >> + >> return analogix_dp_bind(dev, dp->drm_dev, &dp->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(&dp->encoder); >> + >> return analogix_dp_unbind(dev, master, data); >> } >> >> -- >> 1.9.1 >> >> > >
[PATCH v3 1/4] drm/rockchip: vop: export line flag function
Sean, On 07/01/2016 11:32 PM, Sean Paul wrote: > On Fri, Jul 1, 2016 at 11:30 AM, Sean Paul wrote: >> On Fri, Jul 1, 2016 at 5:19 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 >>> --- >>> 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 | 103 >>> >>> drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 3 + >>> drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 ++ >>> 4 files changed, 113 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..cd3cac5 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,59 @@ static void vop_dsp_hold_valid_irq_disable(struct vop >>> *vop) >>> spin_unlock_irqrestore(&vop->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 void vop_line_flag_irq_enable(struct vop *vop, int line_num) >>>
[PATCH v3 3/4] drm/bridge: analogix_dp: add the PSR function support
Sean, Thanks for your review. On 07/02/2016 03:46 AM, Sean Paul wrote: > On Fri, Jul 1, 2016 at 5:19 AM, 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 >> --- >> 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 | 64 >> ++ >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++ >> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 54 ++ >> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 ++ >> include/drm/bridge/analogix_dp.h | 3 + >> 5 files changed, 153 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..b557097 100644 >> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> @@ -97,6 +97,66 @@ static int analogix_dp_detect_hpd(struct >> analogix_dp_device *dp) >> return 0; >> } >> >> +int analogix_dp_active_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_active_psr); >> + >> +int analogix_dp_inactive_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_inactive_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, &psr_version); >> + dev_info(dp->dev, "Panel PSR version : %x\n", psr_version); >> + > This info message is likely to be spammy since it's printed everytime > the panel toggle on. Perhaps downgrade to debug level. Okay, done. >> + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; >> +} >> + >> +static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) > Return type is int, but the function never fails and you don't check > the return value when calling it. Seems like this should be void. Done. >> +{ >> + unsigned char psr_en; >> + >> + /* Disable psr function */ >> + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_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 */ >> + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); >> + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; > Why read psr_en if you're just going to overwrite it? Perhaps you meant |= > here. > Yes, it's my mistaken, no need to read the DP_PSR_EN_CFG, just configure it directly is enough. >> + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); >> + >> + /* Enable psr function */ >> + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); >> + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | >> +DP_PSR_CRC_VERIFICATION; > Again, no need to read if you're just overwriting. Yes, ditto >> + analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en); >> + >> + analogix_dp_enable_psr_crc(dp); >> + >> + return 0; >> +} >> + >> static
[PATCH v3 2/4] drm/rockchip: add an common abstracted PSR driver
Sean, On 07/02/2016 02:00 AM, 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. I split the psr code into a separate driver, cause it seems make things more clearly. 'rockchip_drm_vop.c' need to call the PSR enable/disable interfaces, and 'rockchip_drm_drv.c' need to call the PSR flush interface. If I put the whole psr code into analogix_dp-rockchip driver, then the Rockchip drm core driver would tie to analogix_dp-rockchip driver very deeply, and hard to expand if there are two PSR device in further. > 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
[PATCH v3 4/6] drm/panel: simple: Add support for Samsung LSN122DL01-C01 2560x1600 panel
Doug, On 06/14/2016 01:00 AM, Doug Anderson wrote: > Yakir, > > On Sat, Jun 11, 2016 at 7:56 PM, Yakir Yang wrote: >> The Samsung LSN122DL01-C01 is an 12.2" 2560x1600 (WQXGA) TFT-LCD panel >> connected using eDP interfaces. >> >> Signed-off-by: Yakir Yang >> --- >> Changes in v3: >> - Correct the size of panel_desc to active area 262mmx164mm (Emil, Stéphane) >> >> Changes in v2: None >> >> drivers/gpu/drm/panel/panel-simple.c | 25 + >> 1 file changed, 25 insertions(+) >> >> diff --git a/drivers/gpu/drm/panel/panel-simple.c >> b/drivers/gpu/drm/panel/panel-simple.c >> index 2d40a21..17cc973 100644 >> --- a/drivers/gpu/drm/panel/panel-simple.c >> +++ b/drivers/gpu/drm/panel/panel-simple.c >> @@ -1246,6 +1246,28 @@ static const struct panel_desc qd43003c0_40 = { >> .bus_format = MEDIA_BUS_FMT_RGB888_1X24, >> }; >> >> +static const struct drm_display_mode samsung_lsn122dl01_c01_mode = { >> + .clock = 271560, >> + .hdisplay = 2560, >> + .hsync_start = 2560 + 48, >> + .hsync_end = 2560 + 48 + 32, >> + .htotal = 2560 + 48 + 32 + 80, >> + .vdisplay = 1600, >> + .vsync_start = 1600 + 2, >> + .vsync_end = 1600 + 2 + 5, >> + .vtotal = 1600 + 2 + 5 + 57, >> + .vrefresh = 60, >> +}; >> + >> +static const struct panel_desc samsung_lsn122dl01_c01 = { >> + .modes = &samsung_lsn122dl01_c01_mode, >> + .num_modes = 1, >> + .size = { >> + .width = 262, >> + .height = 164, > Earlier you said that the active area of this panel was: > >> Display area 262.656(H) X 164.16(V) (12.2âdiagonal) > In other panels I looked at the EDID tended to round numbers, not > truncate them. For instance the Starry panel that I sent the patch > for says in the manual "262.7712 (H) x 164.232 (V)" but then the EDID > says "263 x 164". Ah, got it, done. Thanks, - Yakir > That would mean your width should be 263 mm, not 262 mm. > > -Doug > > >
[GIT PULL] drm/bridge: analogix-dp: misc fixes & add RK3399 eDP support
Hi Dave, Please consider merging this tag, which contains the v4 misc fixes and add RK3399 eDP support patches[0] I sent on 2016-06-29, rebased onto v4.7-rc5. This tag have been reviewed by : - Tomasz Figa - Sean Paul - Douglas Anderson - Stéphane Marchesin And acked by : - Mark Yao Also tested on Exynos platform successfully by : Javier Martinez Canillas Besides I also have set up a tree[1] to verify the eDP function on RK3399 EVB board. That tree is based on v4.7-rc5, but need to apply some patches to make things work on RK3399 board, like: - Apply Mark Yao's RK3399 VOP thread - Apply ShunQian Zheng's RK3399 IOMMU thread - Directly update the i2c & rk808 driver to our develop branch - Directly update the dtsi to our develop branch [0]: https://lkml.org/lkml/2016/6/29/186 [1]: https://github.com/yakir-Yang/linux/tree/test/analogix-dp-20160705 Thanks, - Yakir The following changes since commit d9c900b0270a18101403cf5e95c1639fccd43a9f: drm/rockchip: analogix_dp: split the lcdc select setting into device data (2016-07-05 09:16:33 +0800) are available in the git repository at: git at github.com:yakir-Yang/linux.git upstream/analogix-dp-20160705 for you to fetch changes up to 4787b4343fef2e3227b0a69934a8f89e53091fb9: dt-bindings: analogix_dp: rockchip: correct the wrong compatible name (2016-07-05 09:18:32 +0800) -------- Yakir Yang (10): drm/bridge: analogix_dp: correct the register bit define error in ANALOGIX_DP_PLL_REG_1 drm/bridge: analogix_dp: some rockchip chips need to flip REF_CLK bit setting drm/rockchip: analogix_dp: add rk3399 eDP support drm/rockchip: analogix_dp: make panel detect to an optional action drm/bridge: analogix_dp: passing the connector as an argument in .get_modes() drm/rockchip: analogix_dp: correct the connector display color format and bpc drm/rockchip: analogix_dp: update the comments about why need to hardcode VOP output mode drm/bridge: analogix_dp: fix no drm hpd event when panel plug in drm/rockchip: analogix_dp: introduce the pclk for grf dt-bindings: analogix_dp: rockchip: correct the wrong compatible name Documentation/devicetree/bindings/display/bridge/analogix_dp.txt | 1 + Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt | 9 +- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 2 +- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 8 ++--- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 12 --- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 5 +-- drivers/gpu/drm/exynos/exynos_dp.c | 4 +-- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 127 +++ include/drm/bridge/analogix_dp.h | 9 +- 9 files changed, 122 insertions(+), 55 deletions(-) -- next part -- An HTML attachment was scrubbed... URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20160706/4c92aa6c/attachment-0001.html>
[PATCH v3 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 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 | 52 + 1 file changed, 52 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index e81e19a..80a60a6 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 @@ -68,11 +69,53 @@ 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 int 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(&dp->psr_work, msecs_to_jiffies(10)); + + return 0; +} + +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, 100); + if (ret == 0) { + if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) + analogix_dp_active_psr(dp->dev); + else + analogix_dp_inactive_psr(dp->dev); + } +} + static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) { reset_control_assert(dp->rst); @@ -340,12 +383,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(&dp->psr_work, analogix_dp_psr_work); + + rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); + return analogix_dp_bind(dev, dp->drm_dev, &dp->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(&dp->encoder); + return analogix_dp_unbind(dev, master, data); } -- 1.9.1
[PATCH v3 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 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 | 64 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 54 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 ++ include/drm/bridge/analogix_dp.h | 3 + 5 files changed, 153 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..b557097 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -97,6 +97,66 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } +int analogix_dp_active_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_active_psr); + +int analogix_dp_inactive_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_inactive_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, &psr_version); + dev_info(dp->dev, "Panel PSR version : %x\n", psr_version); + + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} + +static int 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, &psr_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 */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); + 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 */ + analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en); + 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); + + return 0; +} + static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; @@ -921,6 +981,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_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, int db1); + #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 48030f0..e8372c7 100644 --- a/driver
[PATCH v3 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 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); + +enum psr_state { + PSR_FLUSH, + PSR_ENABLE, + PSR_DISABLE, +}; + +struct psr_drv { + struct list_head list; + enum psr_state state; + struct mutex state_mutex; + + struct timer_list flush_timer; + + struct drm_encoder *encoder; + int (*set)(struct drm_encoder *encoder, bool enable); +}; + +static struct psr_drv *find_psr_by_crtc(struct drm_crtc *crtc) +{ + struct psr_drv *psr; + + mutex_lock(&psr_list_mutex); + list_for_each_entry(psr, &psr_list, list) { + if (psr->encoder->crtc == crtc) { + mutex_unlock(&psr_list_mutex); + return psr; + } + } + mutex_unlock(&psr_list_mutex); + + return ERR_PTR(-ENODEV); +} + +static void psr_enable(struct psr_drv *psr) +{ + if (psr->state == PSR_ENABLE) + return; + + mutex_lock(&psr->state_mutex); + psr->state = PSR_ENABLE; + psr->set(psr->encoder, true); + mutex_unlock(&psr->state_mutex); +} + +static void psr_disable(struct psr_drv *psr) +{ + if (psr->state == PS
[PATCH v3 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 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 | 103 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 3 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 ++ 4 files changed, 113 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..cd3cac5 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,59 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(&vop->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 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(&vop->irq_lock, flags); + + VOP_CTRL_SET(vop, line_flag_num_0, line_num); + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); + vop_cfg_done(vop); + + spin_unlock_irqrestore(&vop->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(&vop->irq_lock, flags); + + VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0); + + spin_unlock_irqrestore(&vop->irq_lock, flags); +} + static void vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); @@ -1157,6 +1212,13 @@ static irqreturn_t vop_isr(int irq, void *data) ret = IRQ_HANDLED; } + if (active_irqs & LINE_FLAG_INTR) { + if (!completion_done(&vop->line_flag_completion)) + complete(&vop->line_flag_completion); + active_irqs &= ~LINE_FLAG_INTR; + ret = IRQ_HANDLED; + } + if (active_irqs & FS_INTR) { drm_crtc_handle_vblank(crtc); vop_handle_vblank(vop); @
[PATCH v3 0/4] Add PSR function support for Analogix/Rockchip DP
Hi all, 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/ Thanks, - Yakir Changes in v3: - Remove the notify for waiting line_flag event (Daniel) - implement the 'fb->dirty' callback function (Daniel) - avoid to use notify to acqiure for vact event (Daniel) - split the psr flow into an common abstracted PSR driver - Export the 'rockchip_drm_wait_line_flag' symbol, and document it. - Add 'line_flag_num_0' for RK3288/RK3036 - 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 | 64 +++ drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 4 + drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 54 ++ drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 28 +++ drivers/gpu/drm/rockchip/Makefile | 2 +- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 52 ++ 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| 200 + drivers/gpu/drm/rockchip/rockchip_drm_psr.h| 12 ++ drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 127 + drivers/gpu/drm/rockchip/rockchip_drm_vop.h| 3 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c| 4 + include/drm/bridge/analogix_dp.h | 3 + 14 files changed, 567 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 0/11] Misc fixup and add RK3399 eDP support to Analogix DP driver[Involving remittance information, please pay attention to the safety of property]
Sean, On 06/29/2016 10:01 PM, Sean Paul wrote: > On Wed, Jun 29, 2016 at 5:14 AM, Yakir Yang wrote: >> RK3399 and RK3288 shared the same eDP IP controller, only some light >> difference with VOP configure and GRF configure. >> > The whole set looks good to me. All patches should have my R-b now, > thanks for the update. Thanks :-D - Yakir > Sean > > > >> Also same misc fix to analogix_dp driver: >> - Hotplug invalid which report by Dan Carpenter >> - Make panel detect to an optional action >> - correct the register bit define error in ANALOGIX_DP_PLL_REG_1 >> >> Changes in v4: >> - Assigned the GRF setting magic numbers to a #define that corresponds to >>a TRM name. (Sean & Heiko) >> - Pass the chip type to device type directly. (Sean) >> - Add reviewed flag from Tomasz. >> - Add reviewed flag from Sean >> - Remove subdev_type number, and add 'is_rockchip(type)' helper function >> (Sean) >> - Add reviewed flag from Tomasz. >> - Improved the overly complicated .atomic_check function. (Sean) >> - Add reviewed flag from Tomasz >> - Move of_node_put(panel_node) directly below of_drm_find_panel (Sean) >> - Add reviewed flag from Tomasz >> - Add reviewed flag from Sean. >> - Add reviewed flag from Tomasz. >> - Using mask variable to collect the YUV video format. (Sean) >> - Add reviewed flag from Tomasz. >> - Correct the misspell of 'contoller'. (Sean) >> - Add reviewed flag from Sean. >> - Add reviewed flag from Tomasz. >> - Add reviewed flag from Doug. >> - Add reviewed flag from Tomasz. >> - Fix compiled error, sorry. >>"dp->cgfclk" --> 'dp->grfclk' >> - Check the the error code properly, 'EPROBE_DEFER' should be returned, >>'ENOENT' should assign a NULL point to grfclk, other errors should be >>regarded as failed. (Tomasz, Doug, reviewed at Google Gerrit) >> >> [https://chromium-review.googlesource.com/#/c/351821/20/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> at 249] >> - Add the document about optional 'grf' clock (Tomasz, Doug, reviewed at >> Google Gerrit) >> [https://chromium-review.googlesource.com/#/c/351821/] >> - Add reviewed flag from Doug. >> - Add reviewed flag from Tomasz. >> >> Changes in v3: >> - Write a kerneldoc-style comment explaining the chips data fields (Tomasz, >> reviewed at Google Gerrit) >> >> [https://chromium-review.googlesource.com/#/c/346313/10/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> at 39] >> - Drop the '.lcdcsel_mask' number in chips data field (Tomasz, reviewed at >> Google Gerrit) >> >> [https://chromium-review.googlesource.com/#/c/346313/10/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> at 382] >> - Add acked flag from Mark. >> - Add reviewed flag from Tomasz. >> [https://chromium-review.googlesource.com/#/c/346315/15] >> - Add tested flag from Javier >> - Make this hack code more clear (Tomasz, reviewed at Google Gerrit) >>reg = ~reg & REF_CLK_MASK; ---> reg ^= REF_CLK_MASK; >> >> [https://chromium-review.googlesource.com/#/c/346852/7/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c >> at 80] >> - Add tested flag from Javier >> - Give the "rk3399-edp" a separate line for clarity in document (Tomasz, >> reviewed at Google Gerrit) >> >> [https://chromium-review.googlesource.com/#/c/346314/10/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt >> at 5] >> - Move 'output_type' setting before the return statement (Tomasz, reviewed >> at Google Gerrit) >> >> [https://chromium-review.googlesource.com/#/c/346314/10/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> at 154] >> - Add the acked flag from Mark. >> - Add the acked flag from Mark. >> - Avoid to change any internal driver state in .mode_valid interface. >> (Tomasz, reviewed at Google Gerrit) >> >> [https://chromium-review.googlesource.com/#/c/346318/10/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c >> at 113] >> - Hook the connector's color_formats in .get_modes directly. (Tomasz, >> reviewed at Google Gerrit) >> [https://chromium-review.googlesource.com/#/c/346317/15] >> - Add the acked flag from Mark. >> - Add the reviewed flag from Tomasz. >> [https://chromium-review.googlesource.com/#/c/346853/12] >> - Add the acked flag from Mark. >> - Add reviewed flag from Stéphane. >> [https:
[PATCH 1/3] drm: bridge: add DesignWare HDMI I2S audio support
Kuninori, On 06/24/2016 10:40 AM, Kuninori Morimoto wrote: > From: Kuninori Morimoto > > Current dw-hdmi is supporting sound via AHB bus, but it has > I2S audio feature too. This patch adds I2S audio support to dw-hdmi. > This HDMI I2S is supported by using ALSA SoC common HDMI encoder > driver. > > Signed-off-by: Kuninori Morimoto > --- > drivers/gpu/drm/bridge/Kconfig | 8 ++ > drivers/gpu/drm/bridge/Makefile| 1 + > drivers/gpu/drm/bridge/dw-hdmi-audio.h | 7 ++ > drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 123 > + > drivers/gpu/drm/bridge/dw-hdmi.c | 22 +- > drivers/gpu/drm/bridge/dw-hdmi.h | 21 + > 6 files changed, 180 insertions(+), 2 deletions(-) > create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c > > diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig > index 8f7423f..8e2a22d 100644 > --- a/drivers/gpu/drm/bridge/Kconfig > +++ b/drivers/gpu/drm/bridge/Kconfig > @@ -32,6 +32,14 @@ config DRM_DW_HDMI_AHB_AUDIO > Designware HDMI block. This is used in conjunction with > the i.MX6 HDMI driver. > > +config DRM_DW_HDMI_I2S_AUDIO > + tristate "Synopsis Designware I2S Audio interface" > + depends on DRM_DW_HDMI > + select SND_SOC_HDMI_CODEC > + help > + Support the I2S Audio interface which is part of the Synopsis > + Designware HDMI block. > + > config DRM_NXP_PTN3460 > tristate "NXP PTN3460 DP/LVDS bridge" > depends on OF > diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile > index 96b13b3..1af92ad 100644 > --- a/drivers/gpu/drm/bridge/Makefile > +++ b/drivers/gpu/drm/bridge/Makefile > @@ -3,6 +3,7 @@ ccflags-y := -Iinclude/drm > obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o > obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o > obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o > +obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o > obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o > obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o > obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ > diff --git a/drivers/gpu/drm/bridge/dw-hdmi-audio.h > b/drivers/gpu/drm/bridge/dw-hdmi-audio.h > index 91f631b..fd1f745 100644 > --- a/drivers/gpu/drm/bridge/dw-hdmi-audio.h > +++ b/drivers/gpu/drm/bridge/dw-hdmi-audio.h > @@ -11,4 +11,11 @@ struct dw_hdmi_audio_data { > u8 *eld; > }; > > +struct dw_hdmi_i2s_audio_data { > + struct dw_hdmi *hdmi; > + > + void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); > + u8 (*read)(struct dw_hdmi *hdmi, int offset); > +}; > + > #endif > diff --git a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c > b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c > new file mode 100644 > index 000..df1519c > --- /dev/null > +++ b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c > @@ -0,0 +1,123 @@ > +/* > + * dw-hdmi-i2s-audio.c > + * > + * Copyright (c) 2016 Kuninori Morimoto > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > +#include > + > +#include > + > +#include "dw-hdmi.h" > +#include "dw-hdmi-audio.h" > + > +#define DRIVER_NAME "dw-hdmi-i2s-audio" > + > +static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio, u8 val, > int offset) > +{ > + struct dw_hdmi *hdmi = audio->hdmi; > + > + audio->write(hdmi, val, offset); > +} > + > +static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset) > +{ > + struct dw_hdmi *hdmi = audio->hdmi; > + > + return audio->read(hdmi, offset); > +} > + > +static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, > + struct hdmi_codec_daifmt *fmt, > + struct hdmi_codec_params *hparms) > +{ > + struct dw_hdmi_i2s_audio_data *audio = data; > + struct dw_hdmi *hdmi = audio->hdmi; > + u8 conf0 = 0; > + u8 conf1 = 0; > + u8 inputclkfs = 0; > + > + /* it cares I2S only */ > + if ((fmt->fmt != HDMI_I2S) || > + (fmt->bit_clk_master | fmt->frame_clk_master)) { > + dev_err(dev, "unsupported format/settings\n"); > + return -EINVAL; > + } > + > + inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; > + conf0 = HDMI_AUD_CONF0_I2S_ALL_ENABLE; > + > + switch(hparms->sample_width) { > + case 16: > + conf1 = HDMI_AUD_CONF1_WIDTH_16; > + break; > + case 24: > + case 32: > + conf1 = HDMI_AUD_CONF1_WIDTH_24; > + break; > + } > + > + dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); > + > + hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); > + hdmi_write(audio, conf0, HDMI_AUD_CONF0); > + hdmi_write(audio, conf1, HDMI_AUD_CONF1); > + > + dw_hdmi_audio_enable(hdmi); > + > + return 0
[PATCH v4 11/11] dt-bindings: analogix_dp: rockchip: correct the wrong compatible name
The document about rockchip platform make a mistaken in available compatible name of "rk3288-edp", we should correct it to "rk3288-dp" which correspond to the compatible name in driver. This mistaken was introduced in commit be91c36247089 ("dt-bindings: add document for rockchip variant of analogix_dp"). Reported-by: Tomasz Figa Signed-off-by: Yakir Yang Reviewed-by: Douglas Anderson Reviewed-by: Tomasz Figa --- Changes in v4: - Add reviewed flag from Doug. - Add reviewed flag from Tomasz. Changes in v3: - Add this patch in v3 .../devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt index 0b39256..01cced1 100644 --- a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt @@ -2,7 +2,7 @@ Rockchip RK3288 specific extensions to the Analogix Display Port Required properties: -- compatible: "rockchip,rk3288-edp", +- compatible: "rockchip,rk3288-dp", "rockchip,rk3399-edp"; - reg: physical base address of the controller and length -- 1.9.1
[PATCH v4 10/11] drm/rockchip: analogix_dp: introduce the pclk for grf
For RK3399's GRF module, if we want to operate the graphic related grf registers, we need to enable the pclk_vio_grf which supply power for VIO GRF IOs, so it's better to introduce an optional grf clock in driver. Signed-off-by: Yakir Yang Reviewed-by: Douglas Anderson Reviewed-by: Tomasz Figa --- Changes in v4: - Add reviewed flag from Doug. - Add reviewed flag from Tomasz. - Fix compiled error, sorry. "dp->cgfclk" --> 'dp->grfclk' - Check the the error code properly, 'EPROBE_DEFER' should be returned, 'ENOENT' should assign a NULL point to grfclk, other errors should be regarded as failed. (Tomasz, Doug, reviewed at Google Gerrit) [https://chromium-review.googlesource.com/#/c/351821/20/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c at 249] - Add the document about optional 'grf' clock (Tomasz, Doug, reviewed at Google Gerrit) [https://chromium-review.googlesource.com/#/c/351821/] Changes in v3: - Add this patch in v3 .../display/rockchip/analogix_dp-rockchip.txt | 6 ++ drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 23 +++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt index 726c945..0b39256 100644 --- a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt @@ -28,6 +28,12 @@ Required properties: Port 0: contained 2 endpoints, connecting to the output of vop. Port 1: contained 1 endpoint, connecting to the input of panel. +Optional property for different chips: +- clocks: from common clock binding: handle to grf_vio clock. + +- clock-names: from common clock binding: + Required elements: "grf" + For the below properties, please refer to Analogix DP binding document: * Documentation/devicetree/bindings/drm/bridge/analogix_dp.txt - phys (required) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 850edc4..e81e19a 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -64,6 +64,7 @@ struct rockchip_dp_device { struct drm_display_mode mode; struct clk *pclk; + struct clk *grfclk; struct regmap*grf; struct reset_control *rst; @@ -160,11 +161,17 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); - ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); - if (ret != 0) { - dev_err(dp->dev, "Could not write to GRF: %d\n", ret); + ret = clk_prepare_enable(dp->grfclk); + if (ret < 0) { + dev_err(dp->dev, "failed to enable grfclk %d\n", ret); return; } + + ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); + if (ret != 0) + dev_err(dp->dev, "Could not write to GRF: %d\n", ret); + + clk_disable_unprepare(dp->grfclk); } static void rockchip_dp_drm_encoder_nop(struct drm_encoder *encoder) @@ -234,6 +241,16 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp) return PTR_ERR(dp->grf); } + dp->grfclk = devm_clk_get(dev, "grf"); + if (PTR_ERR(dp->grfclk) == -ENOENT) { + dp->grfclk = NULL; + } else if (PTR_ERR(dp->grfclk) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (IS_ERR(dp->grfclk)) { + dev_err(dev, "failed to get grf clock\n"); + return PTR_ERR(dp->grfclk); + } + dp->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dp->pclk)) { dev_err(dev, "failed to get pclk property\n"); -- 1.9.1
[PATCH v4 09/11] drm/bridge: analogix_dp: fix no drm hpd event when panel plug in
The enum value of DP_IRQ_TYPE_HP_CABLE_IN is zero, but driver only send drm hp event when the irq_type and the enum value is true. if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN || ...) drm_helper_hpd_irq_event(dp->drm_dev); So there would no drm hpd event when cable plug in, to fix that just need to assign all hotplug enum with no-zero values. Reported-by: Dan Carpenter Signed-off-by: Yakir Yang Reviewed-by: Sean Paul Reviewed-by: Stéphane Marchesin Reviewed-by: Tomasz Figa Tested-by: Javier Martinez Canillas --- Changes in v4: - Add reviewed flag from Sean. - Add reviewed flag from Tomasz. Changes in v3: - Add reviewed flag from Stéphane. [https://chromium-review.googlesource.com/#/c/346319/15] - Add tested flag from Javier drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index f09275d..b456380 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -127,10 +127,10 @@ enum analog_power_block { }; enum dp_irq_type { - DP_IRQ_TYPE_HP_CABLE_IN, - DP_IRQ_TYPE_HP_CABLE_OUT, - DP_IRQ_TYPE_HP_CHANGE, - DP_IRQ_TYPE_UNKNOWN, + DP_IRQ_TYPE_HP_CABLE_IN = BIT(0), + DP_IRQ_TYPE_HP_CABLE_OUT = BIT(1), + DP_IRQ_TYPE_HP_CHANGE= BIT(2), + DP_IRQ_TYPE_UNKNOWN = BIT(3), }; struct video_info { -- 1.9.1
[PATCH v4 08/11] drm/rockchip: analogix_dp: update the comments about why need to hardcode VOP output mode
The hardware IC designed that VOP must output the RGB10 video format to eDP contoller, and if eDP panel only support RGB8, then eDP contoller should cut down the video data, not via VOP contoller, that's why we need to hardcode the VOP output mode to RGA10 here. Signed-off-by: Yakir Yang Acked-by: Mark Yao Reviewed-by: Tomasz Figa --- Changes in v4: - Correct the misspell of 'contoller'. (Sean) Changes in v3: - Add the reviewed flag from Tomasz. [https://chromium-review.googlesource.com/#/c/346853/12] - Add the acked flag from Mark. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 16 +--- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 0a0fb3a..850edc4 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -182,17 +182,11 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, int ret; /* -* FIXME(Yakir): driver should configure the CRTC output video -* mode with the display information which indicated the monitor -* support colorimetry. -* -* But don't know why the CRTC driver seems could only output the -* RGBaaa rightly. For example, if connect the "innolux,n116bge" -* eDP screen, EDID would indicated that screen only accepted the -* 6bpc mode. But if I configure CRTC to RGB666 output, then eDP -* screen would show a blue picture (RGB888 show a green picture). -* But if I configure CTRC to RGBaaa, and eDP driver still keep -* RGB666 input video mode, then screen would works prefect. +* The hardware IC designed that VOP must output the RGB10 video +* format to eDP controller, and if eDP panel only support RGB8, +* then eDP controller should cut down the video data, not via VOP +* controller, that's why we need to hardcode the VOP output mode +* to RGA10 here. */ s->output_mode = ROCKCHIP_OUT_MODE_; -- 1.9.1
[PATCH v4 07/11] drm/rockchip: analogix_dp: correct the connector display color format and bpc
Rockchip VOP couldn't output YUV video format for eDP controller, so when driver detect connector support YUV video format, we need to hack it down to RGB888. Signed-off-by: Yakir Yang Acked-by: Mark Yao Reviewed-by: Tomasz Figa --- Changes in v4: - Using mask variable to collect the YUV video format. (Sean) - Add reviewed flag from Tomasz. Changes in v3: - Hook the connector's color_formats in .get_modes directly. (Tomasz, reviewed at Google Gerrit) [https://chromium-review.googlesource.com/#/c/346317/15] - Add the acked flag from Mark. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 0755573..0a0fb3a 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -110,6 +110,23 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) return 0; } +static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data, +struct drm_connector *connector) +{ + struct drm_display_info *di = &connector->display_info; + /* VOP couldn't output YUV video format for eDP rightly */ + u32 mask = DRM_COLOR_FORMAT_YCRCB444 | DRM_COLOR_FORMAT_YCRCB422; + + if ((di->color_formats & mask)) { + DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); + di->color_formats &= ~mask; + di->color_formats |= DRM_COLOR_FORMAT_RGB444; + di->bpc = 8; + } + + return 0; +} + static bool rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, @@ -310,6 +327,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.dev_type = dp->data->chip_type; dp->plat_data.power_on = rockchip_dp_poweron; dp->plat_data.power_off = rockchip_dp_powerdown; + dp->plat_data.get_modes = rockchip_dp_get_modes; return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data); } -- 1.9.1
[PATCH v4 06/11] drm/bridge: analogix_dp: passing the connector as an argument in .get_modes()
It's better to pass the connector to platform driver in .get_modes() callback, just like what the .get_modes() helper function designed. Signed-off-by: Yakir Yang Reviewed-by: Sean Paul Reviewed-by: Tomasz Figa --- Changes in v4: - Add reviewed flag from Sean. - Add reviewed flag from Tomasz. Changes in v3: - Avoid to change any internal driver state in .mode_valid interface. (Tomasz, reviewed at Google Gerrit) [https://chromium-review.googlesource.com/#/c/346318/10/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c at 113] drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 2 +- drivers/gpu/drm/exynos/exynos_dp.c | 4 ++-- include/drm/bridge/analogix_dp.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 7699597..a5e5ae4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -938,7 +938,7 @@ int analogix_dp_get_modes(struct drm_connector *connector) num_modes += drm_panel_get_modes(dp->plat_data->panel); if (dp->plat_data->get_modes) - num_modes += dp->plat_data->get_modes(dp->plat_data); + num_modes += dp->plat_data->get_modes(dp->plat_data, connector); return num_modes; } diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 468498e..8a555ed 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -67,10 +67,10 @@ static int exynos_dp_poweroff(struct analogix_dp_plat_data *plat_data) return exynos_dp_crtc_clock_enable(plat_data, false); } -static int exynos_dp_get_modes(struct analogix_dp_plat_data *plat_data) +static int exynos_dp_get_modes(struct analogix_dp_plat_data *plat_data, + struct drm_connector *connector) { struct exynos_dp_device *dp = to_dp(plat_data); - struct drm_connector *connector = &dp->connector; struct drm_display_mode *mode; int num_modes = 0; diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index fc4aea3..261b86d 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -34,7 +34,8 @@ struct analogix_dp_plat_data { int (*power_off)(struct analogix_dp_plat_data *); int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *, struct drm_connector *); - int (*get_modes)(struct analogix_dp_plat_data *); + int (*get_modes)(struct analogix_dp_plat_data *, +struct drm_connector *); }; int analogix_dp_resume(struct device *dev); -- 1.9.1
[PATCH v4 05/11] drm/rockchip: analogix_dp: make panel detect to an optional action
Some boards don't need to declare a panel device node, like the display interface is DP monitors, so it's necessary to make the panel detect to an optional action. Signed-off-by: Yakir Yang Acked-by: Mark Yao Reviewed-by: Tomasz Figa --- Changes in v4: - Move of_node_put(panel_node) directly below of_drm_find_panel (Sean) - Add reviewed flag from Tomasz Changes in v3: - Add the acked flag from Mark. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 47 +++-- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 8557a08..0755573 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -329,38 +329,33 @@ static int rockchip_dp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *panel_node, *port, *endpoint; + struct drm_panel *panel = NULL; struct rockchip_dp_device *dp; - struct drm_panel *panel; port = of_graph_get_port_by_id(dev->of_node, 1); - if (!port) { - dev_err(dev, "can't find output port\n"); - return -EINVAL; - } - - endpoint = of_get_child_by_name(port, "endpoint"); - of_node_put(port); - if (!endpoint) { - dev_err(dev, "no output endpoint found\n"); - return -EINVAL; - } - - panel_node = of_graph_get_remote_port_parent(endpoint); - of_node_put(endpoint); - if (!panel_node) { - dev_err(dev, "no output node found\n"); - return -EINVAL; - } - - panel = of_drm_find_panel(panel_node); - if (!panel) { - DRM_ERROR("failed to find panel\n"); + if (port) { + endpoint = of_get_child_by_name(port, "endpoint"); + of_node_put(port); + if (!endpoint) { + dev_err(dev, "no output endpoint found\n"); + return -EINVAL; + } + + panel_node = of_graph_get_remote_port_parent(endpoint); + of_node_put(endpoint); + if (!panel_node) { + dev_err(dev, "no output node found\n"); + return -EINVAL; + } + + panel = of_drm_find_panel(panel_node); of_node_put(panel_node); - return -EPROBE_DEFER; + if (!panel) { + DRM_ERROR("failed to find panel\n"); + return -EPROBE_DEFER; + } } - of_node_put(panel_node); - dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); if (!dp) return -ENOMEM; -- 1.9.1
[PATCH v4 04/11] drm/rockchip: analogix_dp: add rk3399 eDP support
RK3399 and RK3288 shared the same eDP IP controller, only some light difference with VOP configure and GRF configure. Signed-off-by: Yakir Yang Acked-by: Mark Yao Reviewed-by: Tomasz Figa --- Changes in v4: - Improved the overly complicated .atomic_check function. (Sean) - Add reviewed flag from Tomasz Changes in v3: - Give the "rk3399-edp" a separate line for clarity in document (Tomasz, reviewed at Google Gerrit) [https://chromium-review.googlesource.com/#/c/346314/10/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt at 5] - Move 'output_type' setting before the return statement (Tomasz, reviewed at Google Gerrit) [https://chromium-review.googlesource.com/#/c/346314/10/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c at 154] - Add the acked flag from Mark. .../bindings/display/bridge/analogix_dp.txt| 1 + .../display/rockchip/analogix_dp-rockchip.txt | 3 ++- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c| 23 ++ include/drm/bridge/analogix_dp.h | 3 ++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt index 4f2ba8c..4a0f4f7 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt @@ -5,6 +5,7 @@ Required properties for dp-controller: platform specific such as: * "samsung,exynos5-dp" * "rockchip,rk3288-dp" +* "rockchip,rk3399-edp" -reg: physical base address of the controller and length of memory mapped region. diff --git a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt index e832ff9..726c945 100644 --- a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt @@ -2,7 +2,8 @@ Rockchip RK3288 specific extensions to the Analogix Display Port Required properties: -- compatible: "rockchip,rk3288-edp"; +- compatible: "rockchip,rk3288-edp", + "rockchip,rk3399-edp"; - reg: physical base address of the controller and length diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 0a30931..8557a08 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -36,6 +36,8 @@ #define RK3288_GRF_SOC_CON60x25c #define RK3288_EDP_LCDC_SELBIT(5) +#define RK3399_GRF_SOC_CON20 0x6250 +#define RK3399_EDP_LCDC_SELBIT(5) #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) @@ -159,6 +161,8 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct rockchip_dp_device *dp = to_dp(encoder); + int ret; /* * FIXME(Yakir): driver should configure the CRTC output video @@ -173,8 +177,19 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, * But if I configure CTRC to RGBaaa, and eDP driver still keep * RGB666 input video mode, then screen would works prefect. */ + s->output_mode = ROCKCHIP_OUT_MODE_; s->output_type = DRM_MODE_CONNECTOR_eDP; + if (dp->data->chip_type == RK3399_EDP) { + /* +* For RK3399, VOP Lit must code the out mode to RGB888, +* VOP Big must code the out mode to RGB10. +*/ + ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, + encoder); + if (ret > 0) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + } return 0; } @@ -378,6 +393,13 @@ static const struct dev_pm_ops rockchip_dp_pm_ops = { #endif }; +static const struct rockchip_dp_chip_data rk3399_edp = { + .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, + .lcdsel_big = HIWORD_UPDATE(0, RK3399_EDP_LCDC_SEL), + .lcdsel_lit = HIWORD_UPDATE(RK3399_EDP_LCDC_SEL, RK3399_EDP_LCDC_SEL), + .chip_type = RK3399_EDP, +}; + static const struct rockchip_dp_chip_data rk3288_dp = { .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, .lcdsel_big = HIWORD_UPDATE(0, RK3288_EDP_LCDC_SEL), @@ -387,6 +409,7 @@ static const struct rockchip_dp_chip_data rk3288_dp = { static const struct of_device_id rockchip_dp_dt_ids[] = {
[PATCH v4 03/11] drm/bridge: analogix_dp: some rockchip chips need to flip REF_CLK bit setting
As vendor document indicate, when REF_CLK bit set 0, then DP phy's REF_CLK should switch to 24M source clock. But due to IC PHY layout mistaken, some chips need to flip this bit(like RK3288), and unfortunately they didn't indicate in the DP version register. That's why we have to make this little hack. Signed-off-by: Yakir Yang Reviewed-by: Tomasz Figa Tested-by: Javier Martinez Canillas --- Changes in v4: - Remove subdev_type number, and add 'is_rockchip(type)' helper function (Sean) - Add reviewed flag from Tomasz. Changes in v3: - Make this hack code more clear (Tomasz, reviewed at Google Gerrit) reg = ~reg & REF_CLK_MASK; ---> reg ^= REF_CLK_MASK; [https://chromium-review.googlesource.com/#/c/346852/7/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c at 80] - Add tested flag from Javier drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 12 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 1 + include/drm/bridge/analogix_dp.h | 5 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 49205ef..48030f0 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -74,8 +74,12 @@ void analogix_dp_init_analog_param(struct analogix_dp_device *dp) reg = SEL_24M | TX_DVDD_BIT_1_0625V; writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2); - if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) { - writel(REF_CLK_24M, dp->reg_base + ANALOGIX_DP_PLL_REG_1); + if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) { + reg = REF_CLK_24M; + if (dp->plat_data->dev_type == RK3288_DP) + reg ^= REF_CLK_MASK; + + writel(reg, dp->reg_base + ANALOGIX_DP_PLL_REG_1); writel(0x95, dp->reg_base + ANALOGIX_DP_PLL_REG_2); writel(0x40, dp->reg_base + ANALOGIX_DP_PLL_REG_3); writel(0x58, dp->reg_base + ANALOGIX_DP_PLL_REG_4); @@ -244,7 +248,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, u32 reg; u32 phy_pd_addr = ANALOGIX_DP_PHY_PD; - if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) + if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) phy_pd_addr = ANALOGIX_DP_PD; switch (block) { @@ -448,7 +452,7 @@ void analogix_dp_init_aux(struct analogix_dp_device *dp) analogix_dp_reset_aux(dp); /* Disable AUX transaction H/W retry */ - if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) + if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) reg = AUX_BIT_PERIOD_EXPECTED_DELAY(0) | AUX_HW_RETRY_COUNT_SEL(3) | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index 88d56ad..cdcc6c5 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h @@ -165,6 +165,7 @@ /* ANALOGIX_DP_PLL_REG_1 */ #define REF_CLK_24M(0x1 << 0) #define REF_CLK_27M(0x0 << 0) +#define REF_CLK_MASK (0x1 << 0) /* ANALOGIX_DP_LANE_MAP */ #define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 25afb31..790ab5d 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -18,6 +18,11 @@ enum analogix_dp_devtype { RK3288_DP, }; +static inline bool is_rockchip(enum analogix_dp_devtype type) +{ + return type == RK3288_DP; +} + struct analogix_dp_plat_data { enum analogix_dp_devtype dev_type; struct drm_panel *panel; -- 1.9.1
[PATCH v4 02/11] drm/bridge: analogix_dp: correct the register bit define error in ANALOGIX_DP_PLL_REG_1
There're an register define error in ANALOGIX_DP_PLL_REG_1 which introduced by commit bcec20fd5ad6 ("drm: bridge: analogix/dp: add some rk3288 special registers setting"). The PHY PLL input clock source is selected by ANALOGIX_DP_PLL_REG_1 BIT 0, not BIT 1. Signed-off-by: Yakir Yang Reviewed-by: Sean Paul Reviewed-by: Tomasz Figa Tested-by: Javier Martinez Canillas --- Changes in v4: - Add reviewed flag from Sean Changes in v3: - Add reviewed flag from Tomasz. [https://chromium-review.googlesource.com/#/c/346315/15] - Add tested flag from Javier drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index 337912b..88d56ad 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h @@ -163,8 +163,8 @@ #define HSYNC_POLARITY_CFG (0x1 << 0) /* ANALOGIX_DP_PLL_REG_1 */ -#define REF_CLK_24M(0x1 << 1) -#define REF_CLK_27M(0x0 << 1) +#define REF_CLK_24M(0x1 << 0) +#define REF_CLK_27M(0x0 << 0) /* ANALOGIX_DP_LANE_MAP */ #define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) -- 1.9.1
[PATCH v4 01/11] drm/rockchip: analogix_dp: split the lcdc select setting into device data
eDP controller need to declare which vop provide the video source, and it's defined in GRF registers. But different chips have different GRF register address, so we need to create a device data to declare the GRF messages for each chips. Signed-off-by: Yakir Yang Acked-by: Mark Yao Reviewed-by: Tomasz Figa --- Changes in v4: - Assigned the GRF setting magic numbers to a #define that corresponds to a TRM name. (Sean & Heiko) - Pass the chip type to device type directly. (Sean) - Add reviewed flag from Tomasz. Changes in v3: - Write a kerneldoc-style comment explaining the chips data fields (Tomasz, reviewed at Google Gerrit) [https://chromium-review.googlesource.com/#/c/346313/10/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c at 39] - Drop the '.lcdcsel_mask' number in chips data field (Tomasz, reviewed at Google Gerrit) [https://chromium-review.googlesource.com/#/c/346313/10/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c at 382] - Add acked flag from Mark. drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 49 - 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index c120172..0a30931 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -33,13 +34,26 @@ #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" +#define RK3288_GRF_SOC_CON60x25c +#define RK3288_EDP_LCDC_SELBIT(5) + +#define HIWORD_UPDATE(val, mask) (val | (mask) << 16) + #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) -/* dp grf register offset */ -#define GRF_SOC_CON60x025c -#define GRF_EDP_LCD_SEL_MASKBIT(5) -#define GRF_EDP_SEL_VOP_LIT BIT(5) -#define GRF_EDP_SEL_VOP_BIG 0 +/** + * struct rockchip_dp_chip_data - splite the grf setting of kind of chips + * @lcdsel_grf_reg: grf register offset of lcdc select + * @lcdsel_big: reg value of selecting vop big for eDP + * @lcdsel_lit: reg value of selecting vop little for eDP + * @chip_type: specific chip type + */ +struct rockchip_dp_chip_data { + u32 lcdsel_grf_reg; + u32 lcdsel_big; + u32 lcdsel_lit; + u32 chip_type; +}; struct rockchip_dp_device { struct drm_device*drm_dev; @@ -51,6 +65,8 @@ struct rockchip_dp_device { struct regmap*grf; struct reset_control *rst; + const struct rockchip_dp_chip_data *data; + struct analogix_dp_plat_data plat_data; }; @@ -119,13 +135,13 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder) return; if (ret) - val = GRF_EDP_SEL_VOP_LIT | (GRF_EDP_LCD_SEL_MASK << 16); + val = dp->data->lcdsel_lit; else - val = GRF_EDP_SEL_VOP_BIG | (GRF_EDP_LCD_SEL_MASK << 16); + val = dp->data->lcdsel_big; dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); - ret = regmap_write(dp->grf, GRF_SOC_CON6, val); + ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val); if (ret != 0) { dev_err(dp->dev, "Could not write to GRF: %d\n", ret); return; @@ -246,6 +262,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, void *data) { struct rockchip_dp_device *dp = dev_get_drvdata(dev); + const struct rockchip_dp_chip_data *dp_data; struct drm_device *drm_dev = data; int ret; @@ -256,10 +273,15 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, */ dev_set_drvdata(dev, NULL); + dp_data = of_device_get_match_data(dev); + if (!dp_data) + return -ENODEV; + ret = rockchip_dp_init(dp); if (ret < 0) return ret; + dp->data = dp_data; dp->drm_dev = drm_dev; ret = rockchip_dp_drm_create_encoder(dp); @@ -270,7 +292,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, dp->plat_data.encoder = &dp->encoder; - dp->plat_data.dev_type = RK3288_DP; + dp->plat_data.dev_type = dp->data->chip_type; dp->plat_data.power_on = rockchip_dp_poweron; dp->plat_data.power_off = rockchip_dp_powerdown; @@ -356,8 +378,15 @@ static const struct dev_pm_ops rockchip_dp_pm_ops = { #endif }; +static const struct rockchip_dp_chip_data rk3288_dp = { + .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, + .lcdsel_big = HIWORD_UPDATE(0, RK3288_E