Re: [PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-19 Thread Yakir Yang

Hi Sean,

On 09/12/2016 09:52 PM, Sean Paul wrote:

On Fri, Sep 9, 2016 at 5:45 AM, Yakir Yang <y...@rock-chips.com> wrote:

Make sure the request PSR state takes effect in analogix_dp_send_psr_spd()
function, or print the sink PSR error state if we failed to apply the
requested PSR setting.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v3:
- Update commit message
- Add DP_TIMEOUT_PSR_LOOP_MS marcos
- Correct the return values of analogix_dp_send_psr_spd()

Changes in v2:
- A bunch of good fixes from Sean

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 +++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 25 --
  3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5fe3982..c0ce16a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);

@@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = 0;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index d564e90..a27f1e3 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -20,6 +20,7 @@
  #define MAX_EQ_LOOP 5

  #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1)
+#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300)

Same comment here re: units.

300ms seems like a really long time. Why does it take this long?


This magic number '300ms' just come from my test, I haven't found the 
description in eDP 1.4a Spec about what exact time should Sink take to 
entry PSR.


- Yakir


Sean



  /* DP_MAX_LANE_COUNT */
  #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
@@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
  void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
  ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
  struct drm_dp_aux_msg *msg);
  #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 15a4cf0..7fd4ed0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
 writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
  }

-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
  {
+   unsigned long timeout;
 unsigned int val;
+   u8 sink;

 /* don't send info frame */
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
 val |= IF_EN;
 writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + DP_TIMEOUT_PSR_LOOP_MS;
+   while (time_before(jiffies, timeout)) {
+   val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, );
+   if (val != 1) {
+   dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val);
+   return -EBUSY;
+   }
+
+   if ((vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) ||
+   (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE))
+   return 0;
+
+   usleep_range(1000, 1500);
+   }
+
+   dev_warn(dp->dev, "Failed to apply PSR, sink state was [%x]", sink);
+
+   return -E

Re: [PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-19 Thread Yakir Yang

Hi Sean,

On 09/12/2016 09:52 PM, Sean Paul wrote:

On Fri, Sep 9, 2016 at 5:45 AM, Yakir Yang  wrote:

Make sure the request PSR state takes effect in analogix_dp_send_psr_spd()
function, or print the sink PSR error state if we failed to apply the
requested PSR setting.

Signed-off-by: Yakir Yang 
---
Changes in v3:
- Update commit message
- Add DP_TIMEOUT_PSR_LOOP_MS marcos
- Correct the return values of analogix_dp_send_psr_spd()

Changes in v2:
- A bunch of good fixes from Sean

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 +++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 25 --
  3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5fe3982..c0ce16a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);

@@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = 0;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index d564e90..a27f1e3 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -20,6 +20,7 @@
  #define MAX_EQ_LOOP 5

  #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1)
+#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300)

Same comment here re: units.

300ms seems like a really long time. Why does it take this long?


This magic number '300ms' just come from my test, I haven't found the 
description in eDP 1.4a Spec about what exact time should Sink take to 
entry PSR.


- Yakir


Sean



  /* DP_MAX_LANE_COUNT */
  #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
@@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
  void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
  ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
  struct drm_dp_aux_msg *msg);
  #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 15a4cf0..7fd4ed0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
 writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
  }

-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
  {
+   unsigned long timeout;
 unsigned int val;
+   u8 sink;

 /* don't send info frame */
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
 val |= IF_EN;
 writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + DP_TIMEOUT_PSR_LOOP_MS;
+   while (time_before(jiffies, timeout)) {
+   val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, );
+   if (val != 1) {
+   dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val);
+   return -EBUSY;
+   }
+
+   if ((vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) ||
+   (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE))
+   return 0;
+
+   usleep_range(1000, 1500);
+   }
+
+   dev_warn(dp->dev, "Failed to apply PSR, sink state was [%x]", sink);
+
+   return -ETIMEDOUT;
  }

  ssize_t analogix_dp_transfer(struct analogix_

Re: [PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop

2016-09-19 Thread Yakir Yang

Hi Sean,


On 09/12/2016 09:51 PM, Sean Paul wrote:

On Fri, Sep 9, 2016 at 5:44 AM, Yakir Yang <y...@rock-chips.com> wrote:

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v3:
- Suggested by Sean

Changes in v2: None

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  3 ++-
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 18 +-
  2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index a15f076..d564e90 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -16,10 +16,11 @@
  #include 
  #include 

-#define DP_TIMEOUT_LOOP_COUNT 100
  #define MAX_CR_LOOP 5
  #define MAX_EQ_LOOP 5

+#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1)

The name suggests the units here are ms, but you're storing jiffies.
Do the msecs_to_jiffies conversion down below.


I suddenly realized that 'analogix_dp_core.c' also used the 
'DP_TIMEOUT_LOOP_COUNT' macros, and 'analogix_dp_core.c' have four kinds 
of timeout,

  - DP_TIMEOUT_LOOP_COUNT * 1us
  - DP_TIMEOUT_LOOP_COUNT * 10us
  - DP_TIMEOUT_LOOP_COUNT * 100us
  - DP_TIMEOUT_LOOP_COUNT * 1000us

I may guess it's not necessary to replace the 'DP_TIMEOUT_LOOP_COUNT' 
now  :-)


- Yakir




+
  /* DP_MAX_LANE_COUNT */
  #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
  #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index a4d17b8..15a4cf0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct 
analogix_dp_device *dp,
  void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
  {
 u32 reg;
-   int timeout_loop = 0;
+   unsigned long timeout;

 analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);

@@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct analogix_dp_device 
*dp)
 if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
 analogix_dp_set_pll_power_down(dp, 0);

+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;

timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_MS);


 while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-   timeout_loop++;
-   if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+   if (time_after(jiffies, timeout)) {
 dev_err(dp->dev, "failed to get pll lock 
status\n");
 return;
 }
@@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct 
analogix_dp_device *dp)
  {
 int reg;
 int retval = 0;
-   int timeout_loop = 0;
+   unsigned long timeout;

 /* Enable AUX CH operation */
 reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
@@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct 
analogix_dp_device *dp)
 writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);

 /* Is AUX CH command reply received? */
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
 reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
 while (!(reg & RPLY_RECEIV)) {
-   timeout_loop++;
-   if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+   if (time_after(jiffies, timeout)) {
 dev_err(dp->dev, "AUX CH command reply failed!\n");
 return -ETIMEDOUT;
 }
@@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device 
*dp,
  {
 u32 reg;
 u8 *buffer = msg->buffer;
-   int timeout_loop = 0;
+   unsigned long timeout;
 unsigned int i;
 int num_transferred = 0;

@@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device 
*dp,

 /* Is AUX CH command reply received? */
 /* TODO: Wait for an interrupt instead of looping? */
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
 reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
 while (!(reg & RPLY_RECEIV)) {
-   timeout_loop++;
-   if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
+   if (time_after(jiffies, timeout)) {
 dev_err(dp->dev, "AUX CH command reply failed!\n");
 return -ETIMEDOUT;
 }
--
1.9.1










Re: [PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop

2016-09-19 Thread Yakir Yang

Hi Sean,


On 09/12/2016 09:51 PM, Sean Paul wrote:

On Fri, Sep 9, 2016 at 5:44 AM, Yakir Yang  wrote:

Signed-off-by: Yakir Yang 
---
Changes in v3:
- Suggested by Sean

Changes in v2: None

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  3 ++-
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 18 +-
  2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index a15f076..d564e90 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -16,10 +16,11 @@
  #include 
  #include 

-#define DP_TIMEOUT_LOOP_COUNT 100
  #define MAX_CR_LOOP 5
  #define MAX_EQ_LOOP 5

+#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1)

The name suggests the units here are ms, but you're storing jiffies.
Do the msecs_to_jiffies conversion down below.


I suddenly realized that 'analogix_dp_core.c' also used the 
'DP_TIMEOUT_LOOP_COUNT' macros, and 'analogix_dp_core.c' have four kinds 
of timeout,

  - DP_TIMEOUT_LOOP_COUNT * 1us
  - DP_TIMEOUT_LOOP_COUNT * 10us
  - DP_TIMEOUT_LOOP_COUNT * 100us
  - DP_TIMEOUT_LOOP_COUNT * 1000us

I may guess it's not necessary to replace the 'DP_TIMEOUT_LOOP_COUNT' 
now  :-)


- Yakir




+
  /* DP_MAX_LANE_COUNT */
  #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
  #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index a4d17b8..15a4cf0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct 
analogix_dp_device *dp,
  void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
  {
 u32 reg;
-   int timeout_loop = 0;
+   unsigned long timeout;

 analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);

@@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct analogix_dp_device 
*dp)
 if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
 analogix_dp_set_pll_power_down(dp, 0);

+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;

timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_MS);


 while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-   timeout_loop++;
-   if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+   if (time_after(jiffies, timeout)) {
 dev_err(dp->dev, "failed to get pll lock 
status\n");
 return;
 }
@@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct 
analogix_dp_device *dp)
  {
 int reg;
 int retval = 0;
-   int timeout_loop = 0;
+   unsigned long timeout;

 /* Enable AUX CH operation */
 reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
@@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct 
analogix_dp_device *dp)
 writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);

 /* Is AUX CH command reply received? */
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
 reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
 while (!(reg & RPLY_RECEIV)) {
-   timeout_loop++;
-   if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+   if (time_after(jiffies, timeout)) {
 dev_err(dp->dev, "AUX CH command reply failed!\n");
 return -ETIMEDOUT;
 }
@@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device 
*dp,
  {
 u32 reg;
 u8 *buffer = msg->buffer;
-   int timeout_loop = 0;
+   unsigned long timeout;
 unsigned int i;
 int num_transferred = 0;

@@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device 
*dp,

 /* Is AUX CH command reply received? */
 /* TODO: Wait for an interrupt instead of looping? */
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
 reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
 while (!(reg & RPLY_RECEIV)) {
-   timeout_loop++;
-   if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
+   if (time_after(jiffies, timeout)) {
 dev_err(dp->dev, "AUX CH command reply failed!\n");
 return -ETIMEDOUT;
 }
--
1.9.1










[PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop

2016-09-09 Thread Yakir Yang
Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v3:
- Suggested by Sean

Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  3 ++-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 18 +-
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index a15f076..d564e90 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -16,10 +16,11 @@
 #include 
 #include 
 
-#define DP_TIMEOUT_LOOP_COUNT 100
 #define MAX_CR_LOOP 5
 #define MAX_EQ_LOOP 5
 
+#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1)
+
 /* DP_MAX_LANE_COUNT */
 #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
 #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index a4d17b8..15a4cf0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct 
analogix_dp_device *dp,
 void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
 {
u32 reg;
-   int timeout_loop = 0;
+   unsigned long timeout;
 
analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
 
@@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct analogix_dp_device 
*dp)
if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
analogix_dp_set_pll_power_down(dp, 0);
 
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-   timeout_loop++;
-   if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+   if (time_after(jiffies, timeout)) {
dev_err(dp->dev, "failed to get pll lock 
status\n");
return;
}
@@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct 
analogix_dp_device *dp)
 {
int reg;
int retval = 0;
-   int timeout_loop = 0;
+   unsigned long timeout;
 
/* Enable AUX CH operation */
reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
@@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct 
analogix_dp_device *dp)
writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
 
/* Is AUX CH command reply received? */
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
while (!(reg & RPLY_RECEIV)) {
-   timeout_loop++;
-   if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+   if (time_after(jiffies, timeout)) {
dev_err(dp->dev, "AUX CH command reply failed!\n");
return -ETIMEDOUT;
}
@@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device 
*dp,
 {
u32 reg;
u8 *buffer = msg->buffer;
-   int timeout_loop = 0;
+   unsigned long timeout;
unsigned int i;
int num_transferred = 0;
 
@@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device 
*dp,
 
/* Is AUX CH command reply received? */
/* TODO: Wait for an interrupt instead of looping? */
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
while (!(reg & RPLY_RECEIV)) {
-   timeout_loop++;
-   if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
+   if (time_after(jiffies, timeout)) {
dev_err(dp->dev, "AUX CH command reply failed!\n");
return -ETIMEDOUT;
}
-- 
1.9.1




[PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-09 Thread Yakir Yang
Make sure the request PSR state takes effect in analogix_dp_send_psr_spd()
function, or print the sink PSR error state if we failed to apply the
requested PSR setting.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v3:
- Update commit message
- Add DP_TIMEOUT_PSR_LOOP_MS marcos
- Correct the return values of analogix_dp_send_psr_spd()

Changes in v2:
- A bunch of good fixes from Sean

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 +++--
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 25 --
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5fe3982..c0ce16a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
@@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = 0;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
 
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index d564e90..a27f1e3 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -20,6 +20,7 @@
 #define MAX_EQ_LOOP 5
 
 #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1)
+#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300)
 
 /* DP_MAX_LANE_COUNT */
 #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
@@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
 struct drm_dp_aux_msg *msg);
 #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 15a4cf0..7fd4ed0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
 }
 
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
 {
+   unsigned long timeout;
unsigned int val;
+   u8 sink;
 
/* don't send info frame */
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
val |= IF_EN;
writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + DP_TIMEOUT_PSR_LOOP_MS;
+   while (time_before(jiffies, timeout)) {
+   val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, );
+   if (val != 1) {
+   dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val);
+   return -EBUSY;
+   }
+
+   if ((vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) ||
+   (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE))
+   return 0;
+
+   usleep_range(1000, 1500);
+   }
+
+   dev_warn(dp->dev, "Failed to apply PSR, sink state was [%x]", sink);
+
+   return -ETIMEDOUT;
 }
 
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
-- 
1.9.1




[PATCH v3 2/3] drm/bridge: analogix_dp: use jiffies to simulate timeout loop

2016-09-09 Thread Yakir Yang
Signed-off-by: Yakir Yang 
---
Changes in v3:
- Suggested by Sean

Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  3 ++-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 18 +-
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index a15f076..d564e90 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -16,10 +16,11 @@
 #include 
 #include 
 
-#define DP_TIMEOUT_LOOP_COUNT 100
 #define MAX_CR_LOOP 5
 #define MAX_EQ_LOOP 5
 
+#define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1)
+
 /* DP_MAX_LANE_COUNT */
 #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
 #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index a4d17b8..15a4cf0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -335,7 +335,7 @@ void analogix_dp_set_analog_power_down(struct 
analogix_dp_device *dp,
 void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
 {
u32 reg;
-   int timeout_loop = 0;
+   unsigned long timeout;
 
analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
 
@@ -350,9 +350,9 @@ void analogix_dp_init_analog_func(struct analogix_dp_device 
*dp)
if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
analogix_dp_set_pll_power_down(dp, 0);
 
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-   timeout_loop++;
-   if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+   if (time_after(jiffies, timeout)) {
dev_err(dp->dev, "failed to get pll lock 
status\n");
return;
}
@@ -501,7 +501,7 @@ int analogix_dp_start_aux_transaction(struct 
analogix_dp_device *dp)
 {
int reg;
int retval = 0;
-   int timeout_loop = 0;
+   unsigned long timeout;
 
/* Enable AUX CH operation */
reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
@@ -509,10 +509,10 @@ int analogix_dp_start_aux_transaction(struct 
analogix_dp_device *dp)
writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
 
/* Is AUX CH command reply received? */
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
while (!(reg & RPLY_RECEIV)) {
-   timeout_loop++;
-   if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+   if (time_after(jiffies, timeout)) {
dev_err(dp->dev, "AUX CH command reply failed!\n");
return -ETIMEDOUT;
}
@@ -1055,7 +1055,7 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device 
*dp,
 {
u32 reg;
u8 *buffer = msg->buffer;
-   int timeout_loop = 0;
+   unsigned long timeout;
unsigned int i;
int num_transferred = 0;
 
@@ -1123,10 +1123,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device 
*dp,
 
/* Is AUX CH command reply received? */
/* TODO: Wait for an interrupt instead of looping? */
+   timeout = jiffies + DP_TIMEOUT_LOOP_MS;
reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
while (!(reg & RPLY_RECEIV)) {
-   timeout_loop++;
-   if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
+   if (time_after(jiffies, timeout)) {
dev_err(dp->dev, "AUX CH command reply failed!\n");
return -ETIMEDOUT;
}
-- 
1.9.1




[PATCH v3 3/3] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-09 Thread Yakir Yang
Make sure the request PSR state takes effect in analogix_dp_send_psr_spd()
function, or print the sink PSR error state if we failed to apply the
requested PSR setting.

Signed-off-by: Yakir Yang 
---
Changes in v3:
- Update commit message
- Add DP_TIMEOUT_PSR_LOOP_MS marcos
- Correct the return values of analogix_dp_send_psr_spd()

Changes in v2:
- A bunch of good fixes from Sean

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 +++--
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 25 --
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5fe3982..c0ce16a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
@@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = 0;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
 
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index d564e90..a27f1e3 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -20,6 +20,7 @@
 #define MAX_EQ_LOOP 5
 
 #define DP_TIMEOUT_LOOP_MS msecs_to_jiffies(1)
+#define DP_TIMEOUT_PSR_LOOP_MS msecs_to_jiffies(300)
 
 /* DP_MAX_LANE_COUNT */
 #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
@@ -248,8 +249,8 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
 struct drm_dp_aux_msg *msg);
 #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 15a4cf0..7fd4ed0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
 }
 
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
 {
+   unsigned long timeout;
unsigned int val;
+   u8 sink;
 
/* don't send info frame */
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
val |= IF_EN;
writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + DP_TIMEOUT_PSR_LOOP_MS;
+   while (time_before(jiffies, timeout)) {
+   val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, );
+   if (val != 1) {
+   dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val);
+   return -EBUSY;
+   }
+
+   if ((vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB) ||
+   (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE))
+   return 0;
+
+   usleep_range(1000, 1500);
+   }
+
+   dev_warn(dp->dev, "Failed to apply PSR, sink state was [%x]", sink);
+
+   return -ETIMEDOUT;
 }
 
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
-- 
1.9.1




Re: [PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-09 Thread Yakir Yang

On 09/08/2016 10:12 PM, Sean Paul wrote:

On Wed, Sep 7, 2016 at 11:48 PM, Yakir Yang <y...@rock-chips.com> wrote:

Make sure the request PSR state could effect in analogix_dp_send_psr_spd()
function, or printing the error Sink PSR state if we failed to effect
the request PSR setting.



Let's change to:

Make sure the request PSR state takes effect in analogix_dp_send_psr_spd()
function, or print the sink PSR error state if we failed to apply the
requested PSR
setting.

Done,

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v2:
- A bunch of good fixes from Sean

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 25 --
  3 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5fe3982..c0ce16a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);

@@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = 0;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index a15f076..6c07a50 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
  void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
  ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
  struct drm_dp_aux_msg *msg);
  #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index a4d17b8..09d703b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
 writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
  }

-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
  {
+   unsigned long timeout;
 unsigned int val;
+   u8 sink;

 /* don't send info frame */
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
 val |= IF_EN;
 writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT);

Mismatched units here. DP_TIMEOUT_LOOP_COUNT is defined as number of
retries, whereas you're using it as number of ms. Fortunately, the
retry number is so high that this works out :)

In a separate patch preceding this one, can you change
DP_TIMEOUT_LOOP_COUNT to DP_TIMEOUT_LOOP_MS and alter the other
timeout loops to use time_before() like this one instead of blindly
looping 100 times? After that, you can use DP_TIMEOUT_LOOP_MS here.


Done, and after do some experiments, I found we need to set the timeout 
to 300ms. Cause in some case we would take about 290ms here to get the 
right psr state.




+   while (time_before(jiffies, timeout)) {
+   val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, );
+   if (val != 1) {
+   dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val);
+   return val;

Ok, since this is my snippet this comment is my fault, and I apologize
for that :). However, this could return 0. If drm_dp_dpcd_readb
returns 0, you probably want to retry (same as -EBUSY).

done, just return -EBUSY



+   }
+
+   if (vs

Re: [PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-09 Thread Yakir Yang

On 09/08/2016 10:12 PM, Sean Paul wrote:

On Wed, Sep 7, 2016 at 11:48 PM, Yakir Yang  wrote:

Make sure the request PSR state could effect in analogix_dp_send_psr_spd()
function, or printing the error Sink PSR state if we failed to effect
the request PSR setting.



Let's change to:

Make sure the request PSR state takes effect in analogix_dp_send_psr_spd()
function, or print the sink PSR error state if we failed to apply the
requested PSR
setting.

Done,

Signed-off-by: Yakir Yang 
---
Changes in v2:
- A bunch of good fixes from Sean

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 25 --
  3 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5fe3982..c0ce16a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);

@@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = 0;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index a15f076..6c07a50 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
  void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
  ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
  struct drm_dp_aux_msg *msg);
  #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index a4d17b8..09d703b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
 writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
  }

-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
  {
+   unsigned long timeout;
 unsigned int val;
+   u8 sink;

 /* don't send info frame */
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
 val |= IF_EN;
 writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT);

Mismatched units here. DP_TIMEOUT_LOOP_COUNT is defined as number of
retries, whereas you're using it as number of ms. Fortunately, the
retry number is so high that this works out :)

In a separate patch preceding this one, can you change
DP_TIMEOUT_LOOP_COUNT to DP_TIMEOUT_LOOP_MS and alter the other
timeout loops to use time_before() like this one instead of blindly
looping 100 times? After that, you can use DP_TIMEOUT_LOOP_MS here.


Done, and after do some experiments, I found we need to set the timeout 
to 300ms. Cause in some case we would take about 290ms here to get the 
right psr state.




+   while (time_before(jiffies, timeout)) {
+   val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, );
+   if (val != 1) {
+   dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val);
+   return val;

Ok, since this is my snippet this comment is my fault, and I apologize
for that :). However, this could return 0. If drm_dp_dpcd_readb
returns 0, you probably want to retry (same as -EBUSY).

done, just return -EBUSY



+   }
+
+   if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB |

[PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-07 Thread Yakir Yang
Make sure the request PSR state could effect in analogix_dp_send_psr_spd()
function, or printing the error Sink PSR state if we failed to effect
the request PSR setting.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v2:
- A bunch of good fixes from Sean

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++--
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 25 --
 3 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5fe3982..c0ce16a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
@@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = 0;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
 
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index a15f076..6c07a50 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
 struct drm_dp_aux_msg *msg);
 #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index a4d17b8..09d703b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
 }
 
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
 {
+   unsigned long timeout;
unsigned int val;
+   u8 sink;
 
/* don't send info frame */
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
val |= IF_EN;
writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT);
+   while (time_before(jiffies, timeout)) {
+   val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, );
+   if (val != 1) {
+   dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val);
+   return val;
+   }
+
+   if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB ||
+   !vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)
+   break;
+
+   usleep_range(1000, 1500);
+   }
+
+   dev_warn(dp->dev, "Failed to effect PSR: %x", sink);
+
+   return -ETIMEDOUT;
 }
 
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
-- 
1.9.1




[PATCH v2 2/2] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-07 Thread Yakir Yang
Make sure the request PSR state could effect in analogix_dp_send_psr_spd()
function, or printing the error Sink PSR state if we failed to effect
the request PSR setting.

Signed-off-by: Yakir Yang 
---
Changes in v2:
- A bunch of good fixes from Sean

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++--
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 25 --
 3 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5fe3982..c0ce16a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -116,8 +116,7 @@ int analogix_dp_enable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
@@ -139,8 +138,7 @@ int analogix_dp_disable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = 0;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
 
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index a15f076..6c07a50 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -247,8 +247,8 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
 struct drm_dp_aux_msg *msg);
 #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index a4d17b8..09d703b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1004,10 +1004,12 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
 }
 
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
 {
+   unsigned long timeout;
unsigned int val;
+   u8 sink;
 
/* don't send info frame */
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@@ -1048,6 +1050,25 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
val |= IF_EN;
writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + msecs_to_jiffies(DP_TIMEOUT_LOOP_COUNT);
+   while (time_before(jiffies, timeout)) {
+   val = drm_dp_dpcd_readb(>aux, DP_PSR_STATUS, );
+   if (val != 1) {
+   dev_err(dp->dev, "PSR_STATUS read failed ret=%d", val);
+   return val;
+   }
+
+   if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB ||
+   !vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)
+   break;
+
+   usleep_range(1000, 1500);
+   }
+
+   dev_warn(dp->dev, "Failed to effect PSR: %x", sink);
+
+   return -ETIMEDOUT;
 }
 
 ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
-- 
1.9.1




[PATCH v2 1/2] drm/bridge: analogix_dp: Remove duplicated code v2

2016-09-07 Thread Yakir Yang
From: Tomeu Vizoso <tomeu.viz...@collabora.com>

Remove code for reading the EDID and DPCD fields and use the helpers
instead.

Besides the obvious code reduction, other helpers are being added to the
core that could be used in this driver and will be good to be able to
use them instead of duplicating them.

Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com>
Cc: Javier Martinez Canillas <jav...@osg.samsung.com>
Cc: Mika Kahola <mika.kah...@intel.com>
Cc: Yakir Yang <y...@rock-chips.com>
Cc: Daniel Vetter <daniel.vet...@intel.com>

Reviewed-by: Sean Paul <seanp...@chromium.org>
Reviewed-by: Yakir Yang <y...@rock-chips.com>
Tested-by: Javier Martinez Canillas <jav...@osg.samsung.com>
Tested-by: Sean Paul <seanp...@chromium.org>
---
Changes in v2:
- A bunch of good fixes from Sean and Yakir
- Moved the transfer function to analogix_dp_reg.c
- Removed reference to the EDID from the dp struct
- Rebase on Sean's next tree
git://people.freedesktop.org/~seanpaul/dogwood

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  41 +-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 451 ++---
 3 files changed, 204 insertions(+), 551 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index efac8ab..5fe3982 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -31,6 +31,7 @@
 #include 
 
 #include "analogix_dp_core.h"
+#include "analogix_dp_reg.h"
 
 #define to_dp(nm)  container_of(nm, struct analogix_dp_device, nm)
 
@@ -174,150 +175,21 @@ static void analogix_dp_enable_sink_psr(struct 
analogix_dp_device *dp)
analogix_dp_enable_psr_crc(dp);
 }
 
-static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
-{
-   int i;
-   unsigned char sum = 0;
-
-   for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-   sum = sum + edid_data[i];
-
-   return sum;
-}
-
-static int analogix_dp_read_edid(struct analogix_dp_device *dp)
-{
-   unsigned char *edid = dp->edid;
-   unsigned int extend_block = 0;
-   unsigned char sum;
-   unsigned char test_vector;
-   int retval;
-
-   /*
-* EDID device address is 0x50.
-* However, if necessary, you must have set upper address
-* into E-EDID in I2C device, 0x30.
-*/
-
-   /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-   retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-   EDID_EXTENSION_FLAG,
-   _block);
-   if (retval)
-   return retval;
-
-   if (extend_block > 0) {
-   dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH,
-   [EDID_HEADER_PATTERN]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum(edid);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   /* Read additional EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_BLOCK_LENGTH,
-   EDID_BLOCK_LENGTH,
-   [EDID_BLOCK_LENGTH]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-   _vector);
-   if (test_vector & DP_TEST_LINK_EDID_READ) {
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_EDID_CHECKSUM,
-   edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-   analogix_dp_write_byte_to_dpcd(dp,
-   D

[PATCH v2 1/2] drm/bridge: analogix_dp: Remove duplicated code v2

2016-09-07 Thread Yakir Yang
From: Tomeu Vizoso 

Remove code for reading the EDID and DPCD fields and use the helpers
instead.

Besides the obvious code reduction, other helpers are being added to the
core that could be used in this driver and will be good to be able to
use them instead of duplicating them.

Signed-off-by: Tomeu Vizoso 
Cc: Javier Martinez Canillas 
Cc: Mika Kahola 
Cc: Yakir Yang 
Cc: Daniel Vetter 

Reviewed-by: Sean Paul 
Reviewed-by: Yakir Yang 
Tested-by: Javier Martinez Canillas 
Tested-by: Sean Paul 
---
Changes in v2:
- A bunch of good fixes from Sean and Yakir
- Moved the transfer function to analogix_dp_reg.c
- Removed reference to the EDID from the dp struct
- Rebase on Sean's next tree
git://people.freedesktop.org/~seanpaul/dogwood

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  41 +-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 451 ++---
 3 files changed, 204 insertions(+), 551 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index efac8ab..5fe3982 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -31,6 +31,7 @@
 #include 
 
 #include "analogix_dp_core.h"
+#include "analogix_dp_reg.h"
 
 #define to_dp(nm)  container_of(nm, struct analogix_dp_device, nm)
 
@@ -174,150 +175,21 @@ static void analogix_dp_enable_sink_psr(struct 
analogix_dp_device *dp)
analogix_dp_enable_psr_crc(dp);
 }
 
-static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
-{
-   int i;
-   unsigned char sum = 0;
-
-   for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-   sum = sum + edid_data[i];
-
-   return sum;
-}
-
-static int analogix_dp_read_edid(struct analogix_dp_device *dp)
-{
-   unsigned char *edid = dp->edid;
-   unsigned int extend_block = 0;
-   unsigned char sum;
-   unsigned char test_vector;
-   int retval;
-
-   /*
-* EDID device address is 0x50.
-* However, if necessary, you must have set upper address
-* into E-EDID in I2C device, 0x30.
-*/
-
-   /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-   retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-   EDID_EXTENSION_FLAG,
-   _block);
-   if (retval)
-   return retval;
-
-   if (extend_block > 0) {
-   dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH,
-   [EDID_HEADER_PATTERN]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum(edid);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   /* Read additional EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_BLOCK_LENGTH,
-   EDID_BLOCK_LENGTH,
-   [EDID_BLOCK_LENGTH]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-   _vector);
-   if (test_vector & DP_TEST_LINK_EDID_READ) {
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_EDID_CHECKSUM,
-   edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_RESPONSE,
-   DP_TEST_EDID_CHECKSUM_WRITE);
-   }
-   } else {
-   dev_info(dp->dev, "EDID data does not include any 
extensions.\n");
-
-   /* Read EDID data */
-   retval 

Re: [PATCH] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-06 Thread Yakir Yang

Sean,

Thanks for your comments.

On 09/07/2016 03:51 AM, Sean Paul wrote:

On Fri, Aug 26, 2016 at 6:19 AM, Yakir Yang <y...@rock-chips.com> wrote:

Make sure the request PSR state could effect in analogix_dp_send_psr_spd()
function, or printing the error Sink PSR state if we failed to effect
the request PSR setting.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 26 --
  3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index efac8ab..5a37de8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -115,8 +115,7 @@ int analogix_dp_enable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);

@@ -138,8 +137,7 @@ int analogix_dp_disable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = 0;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 473b980..f617a9d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -283,7 +283,7 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
  void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);

  #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 52c1b6b..505e9d8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1328,9 +1328,11 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
 writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
  }

-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
  {
+   unsigned long timeout;
+   unsigned char sink;

u8

Done

 unsigned int val;

 /* don't send info frame */
@@ -1372,4 +1374,24 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
 val |= IF_EN;
 writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + msecs_to_jiffies(100);

Pull 100 out into a #define

Done

+   while (1) {
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, );

You should be checking return value here.

Done

+
+   if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB)
+   break;
+
+   if (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)
+   break;
+
+   if (time_after(jiffies, timeout)) {
+   dev_warn(dp->dev, "Failed to effect PSR: %x", sink);
+   return -EBUSY;

-ETIMEDOUT is more appropriate

Done

+   }
+
+   usleep_range(1000, 1500);
+   }

The while(1) loop is a little scary. I'd rather do:

while (time_before(jiffies, timeout)) {
ret = analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, );
if (ret != 1) {
DRM_DEV_ERROR(dp->dev, "PSR_STATUS read failed
ret=%d", ret);
return ret;
}

if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB ||
!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)
return 0;

usleep_range(1000, 1500);
}

dev_warn(dp->dev, "Failed to effect PSR: %x", sink);
return -ETIMEDOUT;


Thanks for your code.

- Yakir





+
+   return 0;
  }
--
1.9.1


--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html








Re: [PATCH] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-09-06 Thread Yakir Yang

Sean,

Thanks for your comments.

On 09/07/2016 03:51 AM, Sean Paul wrote:

On Fri, Aug 26, 2016 at 6:19 AM, Yakir Yang  wrote:

Make sure the request PSR state could effect in analogix_dp_send_psr_spd()
function, or printing the error Sink PSR state if we failed to effect
the request PSR setting.

Signed-off-by: Yakir Yang 
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 26 --
  3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index efac8ab..5a37de8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -115,8 +115,7 @@ int analogix_dp_enable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);

@@ -138,8 +137,7 @@ int analogix_dp_disable_psr(struct device *dev)
 psr_vsc.DB0 = 0;
 psr_vsc.DB1 = 0;

-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
  }
  EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 473b980..f617a9d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -283,7 +283,7 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
  void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
  void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);

  #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 52c1b6b..505e9d8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1328,9 +1328,11 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
 writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
  }

-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
  {
+   unsigned long timeout;
+   unsigned char sink;

u8

Done

 unsigned int val;

 /* don't send info frame */
@@ -1372,4 +1374,24 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
 val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
 val |= IF_EN;
 writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + msecs_to_jiffies(100);

Pull 100 out into a #define

Done

+   while (1) {
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, );

You should be checking return value here.

Done

+
+   if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB)
+   break;
+
+   if (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)
+   break;
+
+   if (time_after(jiffies, timeout)) {
+   dev_warn(dp->dev, "Failed to effect PSR: %x", sink);
+   return -EBUSY;

-ETIMEDOUT is more appropriate

Done

+   }
+
+   usleep_range(1000, 1500);
+   }

The while(1) loop is a little scary. I'd rather do:

while (time_before(jiffies, timeout)) {
ret = analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, );
if (ret != 1) {
DRM_DEV_ERROR(dp->dev, "PSR_STATUS read failed
ret=%d", ret);
return ret;
}

if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB ||
!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)
return 0;

usleep_range(1000, 1500);
}

dev_warn(dp->dev, "Failed to effect PSR: %x", sink);
return -ETIMEDOUT;


Thanks for your code.

- Yakir





+
+   return 0;
  }
--
1.9.1


--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html








[PATCH] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-08-26 Thread Yakir Yang
Make sure the request PSR state could effect in analogix_dp_send_psr_spd()
function, or printing the error Sink PSR state if we failed to effect
the request PSR setting.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++--
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 26 --
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index efac8ab..5a37de8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -115,8 +115,7 @@ int analogix_dp_enable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
@@ -138,8 +137,7 @@ int analogix_dp_disable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = 0;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
 
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 473b980..f617a9d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -283,7 +283,7 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
 
 #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 52c1b6b..505e9d8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1328,9 +1328,11 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
 }
 
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
 {
+   unsigned long timeout;
+   unsigned char sink;
unsigned int val;
 
/* don't send info frame */
@@ -1372,4 +1374,24 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
val |= IF_EN;
writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + msecs_to_jiffies(100);
+   while (1) {
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, );
+
+   if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB)
+   break;
+
+   if (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)
+   break;
+
+   if (time_after(jiffies, timeout)) {
+   dev_warn(dp->dev, "Failed to effect PSR: %x", sink);
+   return -EBUSY;
+   }
+
+   usleep_range(1000, 1500);
+   }
+
+   return 0;
 }
-- 
1.9.1




[PATCH] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR

2016-08-26 Thread Yakir Yang
Make sure the request PSR state could effect in analogix_dp_send_psr_spd()
function, or printing the error Sink PSR state if we failed to effect
the request PSR setting.

Signed-off-by: Yakir Yang 
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  6 ++---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++--
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 26 --
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index efac8ab..5a37de8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -115,8 +115,7 @@ int analogix_dp_enable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
@@ -138,8 +137,7 @@ int analogix_dp_disable_psr(struct device *dev)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = 0;
 
-   analogix_dp_send_psr_spd(dp, _vsc);
-   return 0;
+   return analogix_dp_send_psr_spd(dp, _vsc);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
 
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 473b980..f617a9d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -283,7 +283,7 @@ void analogix_dp_config_video_slave_mode(struct 
analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc);
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc);
 
 #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 52c1b6b..505e9d8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1328,9 +1328,11 @@ void analogix_dp_enable_psr_crc(struct 
analogix_dp_device *dp)
writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
 }
 
-void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc)
+int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
+struct edp_vsc_psr *vsc)
 {
+   unsigned long timeout;
+   unsigned char sink;
unsigned int val;
 
/* don't send info frame */
@@ -1372,4 +1374,24 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device 
*dp,
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
val |= IF_EN;
writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+   timeout = jiffies + msecs_to_jiffies(100);
+   while (1) {
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_STATUS, );
+
+   if (vsc->DB1 && sink == DP_PSR_SINK_ACTIVE_RFB)
+   break;
+
+   if (!vsc->DB1 && sink == DP_PSR_SINK_INACTIVE)
+   break;
+
+   if (time_after(jiffies, timeout)) {
+   dev_warn(dp->dev, "Failed to effect PSR: %x", sink);
+   return -EBUSY;
+   }
+
+   usleep_range(1000, 1500);
+   }
+
+   return 0;
 }
-- 
1.9.1




Re: [PATCH v5 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-08-17 Thread Yakir Yang

Hello Archit,

On 08/17/2016 01:41 PM, Archit Taneja wrote:

Hi,

On 07/24/2016 12:27 PM, Yakir Yang wrote:

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()


Could this in any way mess things up if the dev_type is EXYNOS_DP?



Nop, I have enabled the panel PSR function by default (if driver detect 
panel support PSR), but this would active the PSR (cause eDP controller 
haven't send the right SDP header), which means panel would stay in 
normal refresh mode on Exynos platform.


I also have tested that case on RK3399 platform. Enable the panel PSR, 
but never call the analogix_dp_active_psr() symbols, and them I found 
panel still refresh normally.


Only when platform driver call the 
analogix_dp_active_psr()/analogix_dp_inactive_psr() symbols in vblank 
time, make the controller to send the active SDP header, then panel 
could enter into PSR mode.



Otherwise,

Reviewed-by: Archit Taneja <arch...@codeaurora.org>


Thanks for your reviewed.

- Yakir





Signed-off-by: Yakir Yang <y...@rock-chips.com>
Reviewed-by: Sean Paul <seanp...@chromium.org>
---
Changes in v5:
- Add reviewed flag from Sean.

Changes in v4.1:
- Take use of existing edp_psr_vsc struct to swap HBx and DBx 
setting. (Sean)

- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the unused read dpcd operations in 
analogix_dp_enable_sink_psr(). (Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. 
(Sean).

- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
 analogix_dp_detect_sink_psr()
 analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 
++

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 51 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 34 +
  include/drm/bridge/analogix_dp.h   |  3 +
  5 files changed, 174 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c

index 32715da..381b25e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct 
analogix_dp_device *dp)

  return 0;
  }

+int analogix_dp_enable_psr(struct device *dev)
+{
+struct analogix_dp_device *dp = dev_get_drvdata(dev);
+struct edp_vsc_psr psr_vsc;
+
+if (!dp->psr_support)
+return -EINVAL;
+
+/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+memset(_vsc, 0, sizeof(psr_vsc));
+psr_vsc.sdp_header.HB0 = 0;
+psr_vsc.sdp_header.HB1 = 0x7;
+psr_vsc.sdp_header.HB2 = 0x2;
+psr_vsc.sdp_header.HB3 = 0x8;
+
+psr_vsc.DB0 = 0;
+psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | 
EDP_VSC_PSR_CRC_VALUES_VALID;

+
+analogix_dp_send_psr_spd(dp, _vsc);
+return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+struct analogix_dp_device *dp = dev_get_drvdata(dev);
+struct edp_vsc_psr psr_vsc;
+
+if (!dp->psr_support)
+return -EINVAL;
+
+/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+memset(_vsc, 0, sizeof(psr_vsc));
+psr_vsc.sdp_header.HB0 = 0;
+psr_vsc.sdp_header.HB1 = 0x7;
+psr_vsc.sdp_header.HB2 = 0x2;
+psr_vsc.sdp_header.HB3 = 0x8;
+
+psr_vsc.DB0 = 0;
+psr_vsc.DB1 = 0;
+
+analogix_dp_send_psr_spd(dp, _vsc);
+return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+unsigned char psr_version;
+
+analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+unsigned char psr_en;
+
+/* Disable psr function */
+analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+psr_en &= ~DP_

Re: [PATCH v5 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-08-17 Thread Yakir Yang

Hello Archit,

On 08/17/2016 01:41 PM, Archit Taneja wrote:

Hi,

On 07/24/2016 12:27 PM, Yakir Yang wrote:

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()


Could this in any way mess things up if the dev_type is EXYNOS_DP?



Nop, I have enabled the panel PSR function by default (if driver detect 
panel support PSR), but this would active the PSR (cause eDP controller 
haven't send the right SDP header), which means panel would stay in 
normal refresh mode on Exynos platform.


I also have tested that case on RK3399 platform. Enable the panel PSR, 
but never call the analogix_dp_active_psr() symbols, and them I found 
panel still refresh normally.


Only when platform driver call the 
analogix_dp_active_psr()/analogix_dp_inactive_psr() symbols in vblank 
time, make the controller to send the active SDP header, then panel 
could enter into PSR mode.



Otherwise,

Reviewed-by: Archit Taneja 


Thanks for your reviewed.

- Yakir





Signed-off-by: Yakir Yang 
Reviewed-by: Sean Paul 
---
Changes in v5:
- Add reviewed flag from Sean.

Changes in v4.1:
- Take use of existing edp_psr_vsc struct to swap HBx and DBx 
setting. (Sean)

- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the unused read dpcd operations in 
analogix_dp_enable_sink_psr(). (Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. 
(Sean).

- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
 analogix_dp_detect_sink_psr()
 analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 
++

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 51 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 34 +
  include/drm/bridge/analogix_dp.h   |  3 +
  5 files changed, 174 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c

index 32715da..381b25e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct 
analogix_dp_device *dp)

  return 0;
  }

+int analogix_dp_enable_psr(struct device *dev)
+{
+struct analogix_dp_device *dp = dev_get_drvdata(dev);
+struct edp_vsc_psr psr_vsc;
+
+if (!dp->psr_support)
+return -EINVAL;
+
+/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+memset(_vsc, 0, sizeof(psr_vsc));
+psr_vsc.sdp_header.HB0 = 0;
+psr_vsc.sdp_header.HB1 = 0x7;
+psr_vsc.sdp_header.HB2 = 0x2;
+psr_vsc.sdp_header.HB3 = 0x8;
+
+psr_vsc.DB0 = 0;
+psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | 
EDP_VSC_PSR_CRC_VALUES_VALID;

+
+analogix_dp_send_psr_spd(dp, _vsc);
+return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+struct analogix_dp_device *dp = dev_get_drvdata(dev);
+struct edp_vsc_psr psr_vsc;
+
+if (!dp->psr_support)
+return -EINVAL;
+
+/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+memset(_vsc, 0, sizeof(psr_vsc));
+psr_vsc.sdp_header.HB0 = 0;
+psr_vsc.sdp_header.HB1 = 0x7;
+psr_vsc.sdp_header.HB2 = 0x2;
+psr_vsc.sdp_header.HB3 = 0x8;
+
+psr_vsc.DB0 = 0;
+psr_vsc.DB1 = 0;
+
+analogix_dp_send_psr_spd(dp, _vsc);
+return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+unsigned char psr_version;
+
+analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+unsigned char psr_en;
+
+/* Disable psr function */
+analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+psr_en &= ~DP_PSR_ENABLE;
+analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+/* 

Re: [PATCH v2] drm/bridge: analogix_dp: Ensure the panel is properly prepared/unprepared

2016-08-08 Thread Yakir Yang

+ Archit


On 08/09/2016 02:53 AM, Sean Paul wrote:

Instead of just preparing the panel on bind, actually prepare/unprepare
during modeset/disable. The panel must be prepared in order to read hpd
status and edid, so we need to keep state around the prepares in order
to ensure we don't accidentally turn the panel off at the wrong time.

Signed-off-by: Sean Paul <seanp...@chromium.org>


Reviewed-by: Yakir Yang <y...@rock-chips.com>

And I also tested this patch on RK3399 Kevin board, panel works rightly, so:
Tested-by: Yakir Yang <y...@rock-chips.com>

Also add Archit into CC list, guess this patch should go through his 
drm_bridge's tree.


Thanks,
- Yakir


---

Changes in v2:
  - Added panel_is_modeset state/lock to avoid racing detect with modeset 
(marcheu)
  - Added prepare/unprepare in .get_modes (yakir)

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 101 ++---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   3 +
  2 files changed, 93 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..47c449a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -923,11 +923,63 @@ static void analogix_dp_commit(struct analogix_dp_device 
*dp)
analogix_dp_start_video(dp);
  }
  
+/*

+ * This function is a bit of a catch-all for panel preparation, hopefully
+ * simplifying the logic of functions that need to prepare/unprepare the panel
+ * below.
+ *
+ * If @prepare is true, this function will prepare the panel. Conversely, if it
+ * is false, the panel will be unprepared.
+ *
+ * If @is_modeset_prepare is true, the function will disregard the current 
state
+ * of the panel and either prepare/unprepare the panel based on @prepare. Once
+ * it finishes, it will update dp->panel_is_modeset to reflect the current 
state
+ * of the panel.
+ */
+static int analogix_dp_prepare_panel(struct analogix_dp_device *dp,
+bool prepare, bool is_modeset_prepare)
+{
+   int ret = 0;
+
+   if (!dp->plat_data->panel)
+   return 0;
+
+   mutex_lock(>panel_lock);
+
+   /*
+* Exit early if this is a temporary prepare/unprepare and we're already
+* modeset (since we neither want to prepare twice or unprepare early).
+*/
+   if (dp->panel_is_modeset && !is_modeset_prepare)
+   goto out;
+
+   if (prepare)
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   else
+   ret = drm_panel_unprepare(dp->plat_data->panel);
+
+   if (ret)
+   goto out;
+
+   if (is_modeset_prepare)
+   dp->panel_is_modeset = prepare;
+
+out:
+   mutex_unlock(>panel_lock);
+   return ret;
+}
+
  int analogix_dp_get_modes(struct drm_connector *connector)
  {
struct analogix_dp_device *dp = to_dp(connector);
struct edid *edid = (struct edid *)dp->edid;
-   int num_modes = 0;
+   int ret, num_modes = 0;
+
+   ret = analogix_dp_prepare_panel(dp, true, false);
+   if (ret) {
+   DRM_ERROR("Failed to prepare panel (%d)\n", ret);
+   return 0;
+   }
  
  	if (analogix_dp_handle_edid(dp) == 0) {

drm_mode_connector_update_edid_property(>connector, edid);
@@ -940,6 +992,10 @@ int analogix_dp_get_modes(struct drm_connector *connector)
if (dp->plat_data->get_modes)
num_modes += dp->plat_data->get_modes(dp->plat_data, connector);
  
+	ret = analogix_dp_prepare_panel(dp, false, false);

+   if (ret)
+   DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
+
return num_modes;
  }
  
@@ -960,11 +1016,23 @@ enum drm_connector_status

  analogix_dp_detect(struct drm_connector *connector, bool force)
  {
struct analogix_dp_device *dp = to_dp(connector);
+   enum drm_connector_status status = connector_status_disconnected;
+   int ret;
  
-	if (analogix_dp_detect_hpd(dp))

+   ret = analogix_dp_prepare_panel(dp, true, false);
+   if (ret) {
+   DRM_ERROR("Failed to prepare panel (%d)\n", ret);
return connector_status_disconnected;
+   }
+
+   if (!analogix_dp_detect_hpd(dp))
+   status = connector_status_connected;
  
-	return connector_status_connected;

+   ret = analogix_dp_prepare_panel(dp, false, false);
+   if (ret)
+   DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
+
+   return status;
  }
  
  static void analogix_dp_connector_destroy(struct drm_connector *connector)

@@ -1035,6 +1103,16 @@ static int analogix_dp_bridge_attach(struct drm_bridge 
*bridge)
return 0;
  }
  
+static void analogix_dp_bridge_pre_enable(struc

Re: [PATCH v2] drm/bridge: analogix_dp: Ensure the panel is properly prepared/unprepared

2016-08-08 Thread Yakir Yang

+ Archit


On 08/09/2016 02:53 AM, Sean Paul wrote:

Instead of just preparing the panel on bind, actually prepare/unprepare
during modeset/disable. The panel must be prepared in order to read hpd
status and edid, so we need to keep state around the prepares in order
to ensure we don't accidentally turn the panel off at the wrong time.

Signed-off-by: Sean Paul 


Reviewed-by: Yakir Yang 

And I also tested this patch on RK3399 Kevin board, panel works rightly, so:
Tested-by: Yakir Yang 

Also add Archit into CC list, guess this patch should go through his 
drm_bridge's tree.


Thanks,
- Yakir


---

Changes in v2:
  - Added panel_is_modeset state/lock to avoid racing detect with modeset 
(marcheu)
  - Added prepare/unprepare in .get_modes (yakir)

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 101 ++---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   3 +
  2 files changed, 93 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..47c449a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -923,11 +923,63 @@ static void analogix_dp_commit(struct analogix_dp_device 
*dp)
analogix_dp_start_video(dp);
  }
  
+/*

+ * This function is a bit of a catch-all for panel preparation, hopefully
+ * simplifying the logic of functions that need to prepare/unprepare the panel
+ * below.
+ *
+ * If @prepare is true, this function will prepare the panel. Conversely, if it
+ * is false, the panel will be unprepared.
+ *
+ * If @is_modeset_prepare is true, the function will disregard the current 
state
+ * of the panel and either prepare/unprepare the panel based on @prepare. Once
+ * it finishes, it will update dp->panel_is_modeset to reflect the current 
state
+ * of the panel.
+ */
+static int analogix_dp_prepare_panel(struct analogix_dp_device *dp,
+bool prepare, bool is_modeset_prepare)
+{
+   int ret = 0;
+
+   if (!dp->plat_data->panel)
+   return 0;
+
+   mutex_lock(>panel_lock);
+
+   /*
+* Exit early if this is a temporary prepare/unprepare and we're already
+* modeset (since we neither want to prepare twice or unprepare early).
+*/
+   if (dp->panel_is_modeset && !is_modeset_prepare)
+   goto out;
+
+   if (prepare)
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   else
+   ret = drm_panel_unprepare(dp->plat_data->panel);
+
+   if (ret)
+   goto out;
+
+   if (is_modeset_prepare)
+   dp->panel_is_modeset = prepare;
+
+out:
+   mutex_unlock(>panel_lock);
+   return ret;
+}
+
  int analogix_dp_get_modes(struct drm_connector *connector)
  {
struct analogix_dp_device *dp = to_dp(connector);
struct edid *edid = (struct edid *)dp->edid;
-   int num_modes = 0;
+   int ret, num_modes = 0;
+
+   ret = analogix_dp_prepare_panel(dp, true, false);
+   if (ret) {
+   DRM_ERROR("Failed to prepare panel (%d)\n", ret);
+   return 0;
+   }
  
  	if (analogix_dp_handle_edid(dp) == 0) {

drm_mode_connector_update_edid_property(>connector, edid);
@@ -940,6 +992,10 @@ int analogix_dp_get_modes(struct drm_connector *connector)
if (dp->plat_data->get_modes)
num_modes += dp->plat_data->get_modes(dp->plat_data, connector);
  
+	ret = analogix_dp_prepare_panel(dp, false, false);

+   if (ret)
+   DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
+
return num_modes;
  }
  
@@ -960,11 +1016,23 @@ enum drm_connector_status

  analogix_dp_detect(struct drm_connector *connector, bool force)
  {
struct analogix_dp_device *dp = to_dp(connector);
+   enum drm_connector_status status = connector_status_disconnected;
+   int ret;
  
-	if (analogix_dp_detect_hpd(dp))

+   ret = analogix_dp_prepare_panel(dp, true, false);
+   if (ret) {
+   DRM_ERROR("Failed to prepare panel (%d)\n", ret);
return connector_status_disconnected;
+   }
+
+   if (!analogix_dp_detect_hpd(dp))
+   status = connector_status_connected;
  
-	return connector_status_connected;

+   ret = analogix_dp_prepare_panel(dp, false, false);
+   if (ret)
+   DRM_ERROR("Failed to unprepare panel (%d)\n", ret);
+
+   return status;
  }
  
  static void analogix_dp_connector_destroy(struct drm_connector *connector)

@@ -1035,6 +1103,16 @@ static int analogix_dp_bridge_attach(struct drm_bridge 
*bridge)
return 0;
  }
  
+static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge)

+{
+   struct analogix_dp_device *dp = bridge->dr

Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code v2

2016-08-08 Thread Yakir Yang

+ Archit

Tomeu,

Thanks for the update  :-)

But you have missed three tiny align problems, please see my inline 
notes, wish you could fix them. After that this patch looks good to me, so:


Reviewed-by: Yakir Yang <y...@rock-chips.com>

I guess this patch should go through Archit's drm_bridge tree, so I 
added him into the CC list.



- Yakir


On 08/05/2016 08:59 PM, Tomeu Vizoso wrote:

Remove code for reading the EDID and DPCD fields and use the helpers
instead.

Besides the obvious code reduction, other helpers are being added to the
core that could be used in this driver and will be good to be able to
use them instead of duplicating them.

Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com>
Tested-by: Javier Martinez Canillas <jav...@osg.samsung.com>
Tested-by: Sean Paul <seanp...@chromium.org>
Cc: Javier Martinez Canillas <jav...@osg.samsung.com>
Cc: Mika Kahola <mika.kah...@intel.com>
Cc: Yakir Yang <y...@rock-chips.com>
Cc: Daniel Vetter <daniel.vet...@intel.com>

v2:
 - A bunch of good fixes from Sean and Yakir
 - Moved the transfer function to analogix_dp_reg.c
 - Removed reference to the EDID from the dp struct
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  40 +-
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 451 ++---
  3 files changed, 204 insertions(+), 550 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715daf73cb..624fc4f44450 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -31,6 +31,7 @@
  #include 
  
  #include "analogix_dp_core.h"

+#include "analogix_dp_reg.h"
  
  #define to_dp(nm)	container_of(nm, struct analogix_dp_device, nm)
  
@@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)

return 0;
  }
  
-static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)

-{
-   int i;
-   unsigned char sum = 0;
-
-   for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-   sum = sum + edid_data[i];
-
-   return sum;
-}
-
-static int analogix_dp_read_edid(struct analogix_dp_device *dp)
-{
-   unsigned char *edid = dp->edid;
-   unsigned int extend_block = 0;
-   unsigned char sum;
-   unsigned char test_vector;
-   int retval;
-
-   /*
-* EDID device address is 0x50.
-* However, if necessary, you must have set upper address
-* into E-EDID in I2C device, 0x30.
-*/
-
-   /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-   retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-   EDID_EXTENSION_FLAG,
-   _block);
-   if (retval)
-   return retval;
-
-   if (extend_block > 0) {
-   dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH,
-   [EDID_HEADER_PATTERN]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum(edid);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   /* Read additional EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_BLOCK_LENGTH,
-   EDID_BLOCK_LENGTH,
-   [EDID_BLOCK_LENGTH]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-   _vector);
-   if (test_vector & DP_TEST_LINK_EDID_READ) {
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_

Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code v2

2016-08-08 Thread Yakir Yang

+ Archit

Tomeu,

Thanks for the update  :-)

But you have missed three tiny align problems, please see my inline 
notes, wish you could fix them. After that this patch looks good to me, so:


Reviewed-by: Yakir Yang 

I guess this patch should go through Archit's drm_bridge tree, so I 
added him into the CC list.



- Yakir


On 08/05/2016 08:59 PM, Tomeu Vizoso wrote:

Remove code for reading the EDID and DPCD fields and use the helpers
instead.

Besides the obvious code reduction, other helpers are being added to the
core that could be used in this driver and will be good to be able to
use them instead of duplicating them.

Signed-off-by: Tomeu Vizoso 
Tested-by: Javier Martinez Canillas 
Tested-by: Sean Paul 
Cc: Javier Martinez Canillas 
Cc: Mika Kahola 
Cc: Yakir Yang 
Cc: Daniel Vetter 

v2:
 - A bunch of good fixes from Sean and Yakir
 - Moved the transfer function to analogix_dp_reg.c
 - Removed reference to the EDID from the dp struct
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  40 +-
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 451 ++---
  3 files changed, 204 insertions(+), 550 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715daf73cb..624fc4f44450 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -31,6 +31,7 @@
  #include 
  
  #include "analogix_dp_core.h"

+#include "analogix_dp_reg.h"
  
  #define to_dp(nm)	container_of(nm, struct analogix_dp_device, nm)
  
@@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)

return 0;
  }
  
-static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)

-{
-   int i;
-   unsigned char sum = 0;
-
-   for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-   sum = sum + edid_data[i];
-
-   return sum;
-}
-
-static int analogix_dp_read_edid(struct analogix_dp_device *dp)
-{
-   unsigned char *edid = dp->edid;
-   unsigned int extend_block = 0;
-   unsigned char sum;
-   unsigned char test_vector;
-   int retval;
-
-   /*
-* EDID device address is 0x50.
-* However, if necessary, you must have set upper address
-* into E-EDID in I2C device, 0x30.
-*/
-
-   /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-   retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-   EDID_EXTENSION_FLAG,
-   _block);
-   if (retval)
-   return retval;
-
-   if (extend_block > 0) {
-   dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH,
-   [EDID_HEADER_PATTERN]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum(edid);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   /* Read additional EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_BLOCK_LENGTH,
-   EDID_BLOCK_LENGTH,
-   [EDID_BLOCK_LENGTH]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-   _vector);
-   if (test_vector & DP_TEST_LINK_EDID_READ) {
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_EDID_CHECKSUM,
-   edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_RESPONSE,
-   DP_TEST_EDID_CHECKSUM_WRITE);
- 

Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code

2016-08-05 Thread Yakir Yang

Tomeu,

o_O

Ignore my previous email, seems I make a mistaken about the email 
format, and mess up the patch format.


I have move my previous comments to this one :-)

On 08/04/2016 02:23 PM, Tomeu Vizoso wrote:

Remove code for reading the EDID and DPCD fields and use the helpers
instead.

Besides the obvious code reduction, other helpers are being added to the
core that could be used in this driver and will be good to be able to
use them instead of duplicating them.

Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com>
Cc: Javier Martinez Canillas <jav...@osg.samsung.com>
Cc: Mika Kahola <mika.kah...@intel.com>
Cc: Yakir Yang <y...@rock-chips.com>
Cc: Daniel Vetter <daniel.vet...@intel.com>
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 +++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  39 +--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 324 -
  3 files changed, 201 insertions(+), 552 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715daf73cb..c81cb37e56b6 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -31,6 +31,7 @@
  #include 
  
  #include "analogix_dp_core.h"

+#include "analogix_dp_reg.h"
  
  #define to_dp(nm)	container_of(nm, struct analogix_dp_device, nm)
  
@@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)

return 0;
  }
  
-static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)

-{
-   int i;
-   unsigned char sum = 0;
-
-   for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-   sum = sum + edid_data[i];
-
-   return sum;
-}
-
-static int analogix_dp_read_edid(struct analogix_dp_device *dp)
-{
-   unsigned char *edid = dp->edid;
-   unsigned int extend_block = 0;
-   unsigned char sum;
-   unsigned char test_vector;
-   int retval;
-
-   /*
-* EDID device address is 0x50.
-* However, if necessary, you must have set upper address
-* into E-EDID in I2C device, 0x30.
-*/
-
-   /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-   retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-   EDID_EXTENSION_FLAG,
-   _block);
-   if (retval)
-   return retval;
-
-   if (extend_block > 0) {
-   dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH,
-   [EDID_HEADER_PATTERN]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum(edid);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   /* Read additional EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_BLOCK_LENGTH,
-   EDID_BLOCK_LENGTH,
-   [EDID_BLOCK_LENGTH]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-   _vector);
-   if (test_vector & DP_TEST_LINK_EDID_READ) {
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_EDID_CHECKSUM,
-   edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_RESPONSE,
-   DP_TEST_EDID_CHECKSUM_WRITE);
-   }
-   } else {
-   dev_info(dp->dev, "EDID data does not include any 
extensions.\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_by

Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code

2016-08-05 Thread Yakir Yang

Tomeu,

o_O

Ignore my previous email, seems I make a mistaken about the email 
format, and mess up the patch format.


I have move my previous comments to this one :-)

On 08/04/2016 02:23 PM, Tomeu Vizoso wrote:

Remove code for reading the EDID and DPCD fields and use the helpers
instead.

Besides the obvious code reduction, other helpers are being added to the
core that could be used in this driver and will be good to be able to
use them instead of duplicating them.

Signed-off-by: Tomeu Vizoso 
Cc: Javier Martinez Canillas 
Cc: Mika Kahola 
Cc: Yakir Yang 
Cc: Daniel Vetter 
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 +++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  39 +--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 324 -
  3 files changed, 201 insertions(+), 552 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715daf73cb..c81cb37e56b6 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -31,6 +31,7 @@
  #include 
  
  #include "analogix_dp_core.h"

+#include "analogix_dp_reg.h"
  
  #define to_dp(nm)	container_of(nm, struct analogix_dp_device, nm)
  
@@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)

return 0;
  }
  
-static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)

-{
-   int i;
-   unsigned char sum = 0;
-
-   for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-   sum = sum + edid_data[i];
-
-   return sum;
-}
-
-static int analogix_dp_read_edid(struct analogix_dp_device *dp)
-{
-   unsigned char *edid = dp->edid;
-   unsigned int extend_block = 0;
-   unsigned char sum;
-   unsigned char test_vector;
-   int retval;
-
-   /*
-* EDID device address is 0x50.
-* However, if necessary, you must have set upper address
-* into E-EDID in I2C device, 0x30.
-*/
-
-   /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-   retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-   EDID_EXTENSION_FLAG,
-   _block);
-   if (retval)
-   return retval;
-
-   if (extend_block > 0) {
-   dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH,
-   [EDID_HEADER_PATTERN]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum(edid);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   /* Read additional EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_BLOCK_LENGTH,
-   EDID_BLOCK_LENGTH,
-   [EDID_BLOCK_LENGTH]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-   _vector);
-   if (test_vector & DP_TEST_LINK_EDID_READ) {
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_EDID_CHECKSUM,
-   edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_RESPONSE,
-   DP_TEST_EDID_CHECKSUM_WRITE);
-   }
-   } else {
-   dev_info(dp->dev, "EDID data does not include any 
extensions.\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH, [EDID_HEA

Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code

2016-08-05 Thread Yakir Yang

Tomeu,

Nice job ! Have a few nits bellow.  ;)

On 08/04/2016 02:23 PM, Tomeu Vizoso wrote:

Remove code for reading the EDID and DPCD fields and use the helpers
instead.

Besides the obvious code reduction, other helpers are being added to the
core that could be used in this driver and will be good to be able to
use them instead of duplicating them.

Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com>
Cc: Javier Martinez Canillas <jav...@osg.samsung.com>
Cc: Mika Kahola <mika.kah...@intel.com>
Cc: Yakir Yang <y...@rock-chips.com>
Cc: Daniel Vetter <daniel.vet...@intel.com>
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 +++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  39 +--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 324 -
  3 files changed, 201 insertions(+), 552 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715daf73cb..c81cb37e56b6 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -31,6 +31,7 @@
  #include 
  
  #include "analogix_dp_core.h"

+#include "analogix_dp_reg.h"
  
  #define to_dp(nm)	container_of(nm, struct analogix_dp_device, nm)
  
@@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)

return 0;
  }
  
-static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)

-{
-   int i;
-   unsigned char sum = 0;
-
-   for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-   sum = sum + edid_data[i];
-
-   return sum;
-}
-
-static int analogix_dp_read_edid(struct analogix_dp_device *dp)
-{
-   unsigned char *edid = dp->edid;
-   unsigned int extend_block = 0;
-   unsigned char sum;
-   unsigned char test_vector;
-   int retval;
-
-   /*
-* EDID device address is 0x50.
-* However, if necessary, you must have set upper address
-* into E-EDID in I2C device, 0x30.
-*/
-
-   /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-   retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-   EDID_EXTENSION_FLAG,
-   _block);
-   if (retval)
-   return retval;
-
-   if (extend_block > 0) {
-   dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH,
-   [EDID_HEADER_PATTERN]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum(edid);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   /* Read additional EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_BLOCK_LENGTH,
-   EDID_BLOCK_LENGTH,
-   [EDID_BLOCK_LENGTH]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-   _vector);
-   if (test_vector & DP_TEST_LINK_EDID_READ) {
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_EDID_CHECKSUM,
-   edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_RESPONSE,
-   DP_TEST_EDID_CHECKSUM_WRITE);
-   }
-   } else {
-   dev_info(dp->dev, "EDID data does not include any 
extensions.\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN,
- 

Re: [PATCH] drm/bridge: analogix_dp: Remove duplicated code

2016-08-05 Thread Yakir Yang

Tomeu,

Nice job ! Have a few nits bellow.  ;)

On 08/04/2016 02:23 PM, Tomeu Vizoso wrote:

Remove code for reading the EDID and DPCD fields and use the helpers
instead.

Besides the obvious code reduction, other helpers are being added to the
core that could be used in this driver and will be good to be able to
use them instead of duplicating them.

Signed-off-by: Tomeu Vizoso 
Cc: Javier Martinez Canillas 
Cc: Mika Kahola 
Cc: Yakir Yang 
Cc: Daniel Vetter 
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 390 +++--
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  39 +--
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 324 -
  3 files changed, 201 insertions(+), 552 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715daf73cb..c81cb37e56b6 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -31,6 +31,7 @@
  #include 
  
  #include "analogix_dp_core.h"

+#include "analogix_dp_reg.h"
  
  #define to_dp(nm)	container_of(nm, struct analogix_dp_device, nm)
  
@@ -97,150 +98,21 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)

return 0;
  }
  
-static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)

-{
-   int i;
-   unsigned char sum = 0;
-
-   for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-   sum = sum + edid_data[i];
-
-   return sum;
-}
-
-static int analogix_dp_read_edid(struct analogix_dp_device *dp)
-{
-   unsigned char *edid = dp->edid;
-   unsigned int extend_block = 0;
-   unsigned char sum;
-   unsigned char test_vector;
-   int retval;
-
-   /*
-* EDID device address is 0x50.
-* However, if necessary, you must have set upper address
-* into E-EDID in I2C device, 0x30.
-*/
-
-   /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-   retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-   EDID_EXTENSION_FLAG,
-   _block);
-   if (retval)
-   return retval;
-
-   if (extend_block > 0) {
-   dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH,
-   [EDID_HEADER_PATTERN]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum(edid);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   /* Read additional EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR,
-   EDID_BLOCK_LENGTH,
-   EDID_BLOCK_LENGTH,
-   [EDID_BLOCK_LENGTH]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!\n");
-   return -EIO;
-   }
-   sum = analogix_dp_calc_edid_check_sum([EDID_BLOCK_LENGTH]);
-   if (sum != 0) {
-   dev_err(dp->dev, "EDID bad checksum!\n");
-   return -EIO;
-   }
-
-   analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
-   _vector);
-   if (test_vector & DP_TEST_LINK_EDID_READ) {
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_EDID_CHECKSUM,
-   edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-   analogix_dp_write_byte_to_dpcd(dp,
-   DP_TEST_RESPONSE,
-   DP_TEST_EDID_CHECKSUM_WRITE);
-   }
-   } else {
-   dev_info(dp->dev, "EDID data does not include any 
extensions.\n");
-
-   /* Read EDID data */
-   retval = analogix_dp_read_bytes_from_i2c(dp,
-   I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN,
-   EDID_BLOCK_LENGTH, [EDID_HEADER_PATTERN]);
-   if (retval != 0) {
-   dev_err(dp->dev, "EDID Read failed!

Re: [PATCH 1/3] drm/rockchip: inno_hdmi: add audio support

2016-08-03 Thread Yakir Yang

Mark,


Got it, would rebase soonest :-)


Thanks,
- Yakir

On 08/04/2016 10:01 AM, Mark yao wrote:

Hi Yakir

After apply your patch, I got following warning messge:

drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: initialization 
from incompatible pointer type [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: (near 
initialization for 'audio_codec_ops.hw_params') [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: initialization 
from incompatible pointer type [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: (near 
initialization for 'audio_codec_ops.audio_shutdown') [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: initialization 
from incompatible pointer type [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: (near 
initialization for 'audio_codec_ops.digital_mute') [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: initialization 
from incompatible pointer type [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: (near 
initialization for 'audio_codec_ops.get_eld') [enabled by default]


since the commit "efc9194 ASoC: hdmi-codec: callback function will be 
called with private data",

the hdmi_codec_ops had some changes.
Can you rebase your patch to the newest kernel?

Thanks.
On 2016年06月15日 21:28, Yakir Yang wrote:

Using the common hdmi-codec driver to support hdmi audio function.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
  drivers/gpu/drm/rockchip/inno_hdmi.c | 237 
++-

  drivers/gpu/drm/rockchip/inno_hdmi.h |   2 +
  2 files changed, 237 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c 
b/drivers/gpu/drm/rockchip/inno_hdmi.c

index f8b4feb..c31dc07 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -29,6 +29,8 @@
  #include 
  #include 
  +#include 
+
  #include "rockchip_drm_drv.h"
  #include "rockchip_drm_vop.h"
  @@ -36,6 +38,12 @@
#define to_inno_hdmi(x)container_of(x, struct inno_hdmi, x)
  +struct audio_info {
+int sample_rate;
+int channels;
+int sample_width;
+};
+
  struct hdmi_data_info {
  int vic;
  bool sink_is_hdmi;
@@ -71,6 +79,9 @@ struct inno_hdmi {
unsigned int tmds_rate;
  +struct platform_device *audio_pdev;
+bool audio_enable;
+
  struct hdmi_data_infohdmi_data;
  struct drm_display_mode previous_mode;
  };
@@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct 
inno_hdmi *hdmi,
  return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AVI, 
0, 0, 0);

  }
  +static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi,
+  struct audio_info *audio)
+{
+struct hdmi_audio_infoframe *faudio;
+union hdmi_infoframe frame;
+int rc;
+
+rc = hdmi_audio_infoframe_init();
+faudio = (struct hdmi_audio_infoframe *)
+
+faudio->channels = audio->channels;
+
+switch (audio->sample_width) {
+case 16:
+faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+break;
+case 20:
+faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20;
+break;
+case 24:
+faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24;
+break;
+}
+
+switch (audio->sample_rate) {
+case 32000:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000;
+break;
+case 44100:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100;
+break;
+case 48000:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000;
+break;
+case 88200:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200;
+break;
+case 96000:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000;
+break;
+case 176400:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400;
+break;
+case 192000:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000;
+break;
+}
+
+return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AAI, 
0, 0, 0);

+}
+
  static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
  {
  struct hdmi_data_info *data = >hdmi_data;
@@ -478,8 +540,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
  inno_hdmi_i2c_init(hdmi);
/* Unmute video and audio output */
-hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
-  v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
+hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0));
+if (hdmi->audio_enable)
+hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0));
return 0;
  }
@@ -616,6 +679,174 @@ static struct drm_connector_helper_funcs 
inno_hdmi_connector_helper_funcs = {

  .best_encoder = inno_hdmi_connector_best_encoder,
  };

Re: [PATCH 1/3] drm/rockchip: inno_hdmi: add audio support

2016-08-03 Thread Yakir Yang

Mark,


Got it, would rebase soonest :-)


Thanks,
- Yakir

On 08/04/2016 10:01 AM, Mark yao wrote:

Hi Yakir

After apply your patch, I got following warning messge:

drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: initialization 
from incompatible pointer type [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:818:2: warning: (near 
initialization for 'audio_codec_ops.hw_params') [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: initialization 
from incompatible pointer type [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:819:2: warning: (near 
initialization for 'audio_codec_ops.audio_shutdown') [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: initialization 
from incompatible pointer type [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:820:2: warning: (near 
initialization for 'audio_codec_ops.digital_mute') [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: initialization 
from incompatible pointer type [enabled by default]
drivers/gpu/drm/rockchip/inno_hdmi.c:821:2: warning: (near 
initialization for 'audio_codec_ops.get_eld') [enabled by default]


since the commit "efc9194 ASoC: hdmi-codec: callback function will be 
called with private data",

the hdmi_codec_ops had some changes.
Can you rebase your patch to the newest kernel?

Thanks.
On 2016年06月15日 21:28, Yakir Yang wrote:

Using the common hdmi-codec driver to support hdmi audio function.

Signed-off-by: Yakir Yang 
---
  drivers/gpu/drm/rockchip/inno_hdmi.c | 237 
++-

  drivers/gpu/drm/rockchip/inno_hdmi.h |   2 +
  2 files changed, 237 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c 
b/drivers/gpu/drm/rockchip/inno_hdmi.c

index f8b4feb..c31dc07 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -29,6 +29,8 @@
  #include 
  #include 
  +#include 
+
  #include "rockchip_drm_drv.h"
  #include "rockchip_drm_vop.h"
  @@ -36,6 +38,12 @@
#define to_inno_hdmi(x)container_of(x, struct inno_hdmi, x)
  +struct audio_info {
+int sample_rate;
+int channels;
+int sample_width;
+};
+
  struct hdmi_data_info {
  int vic;
  bool sink_is_hdmi;
@@ -71,6 +79,9 @@ struct inno_hdmi {
unsigned int tmds_rate;
  +struct platform_device *audio_pdev;
+bool audio_enable;
+
  struct hdmi_data_infohdmi_data;
  struct drm_display_mode previous_mode;
  };
@@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct 
inno_hdmi *hdmi,
  return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AVI, 
0, 0, 0);

  }
  +static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi,
+  struct audio_info *audio)
+{
+struct hdmi_audio_infoframe *faudio;
+union hdmi_infoframe frame;
+int rc;
+
+rc = hdmi_audio_infoframe_init();
+faudio = (struct hdmi_audio_infoframe *)
+
+faudio->channels = audio->channels;
+
+switch (audio->sample_width) {
+case 16:
+faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+break;
+case 20:
+faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20;
+break;
+case 24:
+faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24;
+break;
+}
+
+switch (audio->sample_rate) {
+case 32000:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000;
+break;
+case 44100:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100;
+break;
+case 48000:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000;
+break;
+case 88200:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200;
+break;
+case 96000:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000;
+break;
+case 176400:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400;
+break;
+case 192000:
+faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000;
+break;
+}
+
+return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AAI, 
0, 0, 0);

+}
+
  static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
  {
  struct hdmi_data_info *data = >hdmi_data;
@@ -478,8 +540,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
  inno_hdmi_i2c_init(hdmi);
/* Unmute video and audio output */
-hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
-  v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
+hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0));
+if (hdmi->audio_enable)
+hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0));
return 0;
  }
@@ -616,6 +679,174 @@ static struct drm_connector_helper_funcs 
inno_hdmi_connector_helper_funcs = {

  .best_encoder = inno_hdmi_connector_best_encoder,
  };
  +int inno_hdmi_audio_conf

Re: [PATCH 1/3] drm/rockchip: inno_hdmi: add audio support

2016-08-01 Thread Yakir Yang

Hi Mark & Heiko,

Ping..

Thanks,
- Yakir

On 06/15/2016 09:28 PM, Yakir Yang wrote:

Using the common hdmi-codec driver to support hdmi audio function.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
  drivers/gpu/drm/rockchip/inno_hdmi.c | 237 ++-
  drivers/gpu/drm/rockchip/inno_hdmi.h |   2 +
  2 files changed, 237 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c 
b/drivers/gpu/drm/rockchip/inno_hdmi.c
index f8b4feb..c31dc07 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -29,6 +29,8 @@
  #include 
  #include 
  
+#include 

+
  #include "rockchip_drm_drv.h"
  #include "rockchip_drm_vop.h"
  
@@ -36,6 +38,12 @@
  
  #define to_inno_hdmi(x)	container_of(x, struct inno_hdmi, x)
  
+struct audio_info {

+   int sample_rate;
+   int channels;
+   int sample_width;
+};
+
  struct hdmi_data_info {
int vic;
bool sink_is_hdmi;
@@ -71,6 +79,9 @@ struct inno_hdmi {
  
  	unsigned int tmds_rate;
  
+	struct platform_device *audio_pdev;

+   bool audio_enable;
+
struct hdmi_data_info   hdmi_data;
struct drm_display_mode previous_mode;
  };
@@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi 
*hdmi,
return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AVI, 0, 0, 0);
  }
  
+static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi,

+ struct audio_info *audio)
+{
+   struct hdmi_audio_infoframe *faudio;
+   union hdmi_infoframe frame;
+   int rc;
+
+   rc = hdmi_audio_infoframe_init();
+   faudio = (struct hdmi_audio_infoframe *)
+
+   faudio->channels = audio->channels;
+
+   switch (audio->sample_width) {
+   case 16:
+   faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+   break;
+   case 20:
+   faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20;
+   break;
+   case 24:
+   faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24;
+   break;
+   }
+
+   switch (audio->sample_rate) {
+   case 32000:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000;
+   break;
+   case 44100:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100;
+   break;
+   case 48000:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000;
+   break;
+   case 88200:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200;
+   break;
+   case 96000:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000;
+   break;
+   case 176400:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400;
+   break;
+   case 192000:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000;
+   break;
+   }
+
+   return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AAI, 0, 0, 0);
+}
+
  static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
  {
struct hdmi_data_info *data = >hdmi_data;
@@ -478,8 +540,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
inno_hdmi_i2c_init(hdmi);
  
  	/* Unmute video and audio output */

-   hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
- v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
+   hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0));
+   if (hdmi->audio_enable)
+   hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0));
  
  	return 0;

  }
@@ -616,6 +679,174 @@ static struct drm_connector_helper_funcs 
inno_hdmi_connector_helper_funcs = {
.best_encoder = inno_hdmi_connector_best_encoder,
  };
  
+int inno_hdmi_audio_config_set(struct inno_hdmi *hdmi, struct audio_info *audio)

+{
+   int rate, N, channel;
+
+   if (audio->channels < 3)
+   channel = I2S_CHANNEL_1_2;
+   else if (audio->channels < 5)
+   channel = I2S_CHANNEL_3_4;
+   else if (audio->channels < 7)
+   channel = I2S_CHANNEL_5_6;
+   else
+   channel = I2S_CHANNEL_7_8;
+
+   switch (audio->sample_rate) {
+   case 32000:
+   rate = AUDIO_32K;
+   N = N_32K;
+   break;
+   case 44100:
+   rate = AUDIO_441K;
+   N = N_441K;
+   break;
+   case 48000:
+   rate = AUDIO_48K;
+   N = N_48K;
+   break;
+   case 88200:
+   rate = AUDIO_882K;
+   N = N_882K;
+   break;
+   case 96000:
+   rate = AUDIO_96K;
+   N = N_96K;
+   break;
+   case 176400:
+   rate = AUDIO_1764K;
+  

Re: [PATCH 1/3] drm/rockchip: inno_hdmi: add audio support

2016-08-01 Thread Yakir Yang

Hi Mark & Heiko,

Ping..

Thanks,
- Yakir

On 06/15/2016 09:28 PM, Yakir Yang wrote:

Using the common hdmi-codec driver to support hdmi audio function.

Signed-off-by: Yakir Yang 
---
  drivers/gpu/drm/rockchip/inno_hdmi.c | 237 ++-
  drivers/gpu/drm/rockchip/inno_hdmi.h |   2 +
  2 files changed, 237 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c 
b/drivers/gpu/drm/rockchip/inno_hdmi.c
index f8b4feb..c31dc07 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -29,6 +29,8 @@
  #include 
  #include 
  
+#include 

+
  #include "rockchip_drm_drv.h"
  #include "rockchip_drm_vop.h"
  
@@ -36,6 +38,12 @@
  
  #define to_inno_hdmi(x)	container_of(x, struct inno_hdmi, x)
  
+struct audio_info {

+   int sample_rate;
+   int channels;
+   int sample_width;
+};
+
  struct hdmi_data_info {
int vic;
bool sink_is_hdmi;
@@ -71,6 +79,9 @@ struct inno_hdmi {
  
  	unsigned int tmds_rate;
  
+	struct platform_device *audio_pdev;

+   bool audio_enable;
+
struct hdmi_data_info   hdmi_data;
struct drm_display_mode previous_mode;
  };
@@ -306,6 +317,57 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi 
*hdmi,
return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AVI, 0, 0, 0);
  }
  
+static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi,

+ struct audio_info *audio)
+{
+   struct hdmi_audio_infoframe *faudio;
+   union hdmi_infoframe frame;
+   int rc;
+
+   rc = hdmi_audio_infoframe_init();
+   faudio = (struct hdmi_audio_infoframe *)
+
+   faudio->channels = audio->channels;
+
+   switch (audio->sample_width) {
+   case 16:
+   faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_16;
+   break;
+   case 20:
+   faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_20;
+   break;
+   case 24:
+   faudio->sample_size = HDMI_AUDIO_SAMPLE_SIZE_24;
+   break;
+   }
+
+   switch (audio->sample_rate) {
+   case 32000:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000;
+   break;
+   case 44100:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100;
+   break;
+   case 48000:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000;
+   break;
+   case 88200:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200;
+   break;
+   case 96000:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000;
+   break;
+   case 176400:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400;
+   break;
+   case 192000:
+   faudio->sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000;
+   break;
+   }
+
+   return inno_hdmi_upload_frame(hdmi, rc, , INFOFRAME_AAI, 0, 0, 0);
+}
+
  static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
  {
struct hdmi_data_info *data = >hdmi_data;
@@ -478,8 +540,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
inno_hdmi_i2c_init(hdmi);
  
  	/* Unmute video and audio output */

-   hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
- v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
+   hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0));
+   if (hdmi->audio_enable)
+   hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0));
  
  	return 0;

  }
@@ -616,6 +679,174 @@ static struct drm_connector_helper_funcs 
inno_hdmi_connector_helper_funcs = {
.best_encoder = inno_hdmi_connector_best_encoder,
  };
  
+int inno_hdmi_audio_config_set(struct inno_hdmi *hdmi, struct audio_info *audio)

+{
+   int rate, N, channel;
+
+   if (audio->channels < 3)
+   channel = I2S_CHANNEL_1_2;
+   else if (audio->channels < 5)
+   channel = I2S_CHANNEL_3_4;
+   else if (audio->channels < 7)
+   channel = I2S_CHANNEL_5_6;
+   else
+   channel = I2S_CHANNEL_7_8;
+
+   switch (audio->sample_rate) {
+   case 32000:
+   rate = AUDIO_32K;
+   N = N_32K;
+   break;
+   case 44100:
+   rate = AUDIO_441K;
+   N = N_441K;
+   break;
+   case 48000:
+   rate = AUDIO_48K;
+   N = N_48K;
+   break;
+   case 88200:
+   rate = AUDIO_882K;
+   N = N_882K;
+   break;
+   case 96000:
+   rate = AUDIO_96K;
+   N = N_96K;
+   break;
+   case 176400:
+   rate = AUDIO_1764K;
+   N = N_1764K;
+  

Re: [PATCH] drm/analogix_dp: Ensure the panel is properly prepared/unprepared

2016-07-31 Thread Yakir Yang

Sean,

On 07/30/2016 03:16 AM, Sean Paul wrote:

Instead of just preparing the panel on bind, actually prepare/unprepare
during modeset/disable. The panel must be prepared in order to read hpd
status, so we need to refcount the prepares in order to ensure we don't
accidentally turn the panel off at the wrong time.

Signed-off-by: Sean Paul 
---


Hi Yakir,
This is what I was talking about upthread. I've tested it and it seems to be 
working.

What do you think?


Thanks for your patch, and it works. But I have introduced two 
questions, and I haven't found a way to fixed them.



Sean



drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 48 +-
  1 file changed, 37 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..7b764a4 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -960,11 +960,27 @@ enum drm_connector_status
  analogix_dp_detect(struct drm_connector *connector, bool force)
  {
struct analogix_dp_device *dp = to_dp(connector);
+   enum drm_connector_status status = connector_status_disconnected;
+   int ret;
  
-	if (analogix_dp_detect_hpd(dp))

-   return connector_status_disconnected;
+   if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret) {
+   DRM_ERROR("failed to setup panel (%d)\n", ret);
+   return connector_status_disconnected;
+   }
+   }
+
+   if (!analogix_dp_detect_hpd(dp))
+   status = connector_status_connected;
+
+   if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) {
+   ret = drm_panel_unprepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }
  
-	return connector_status_connected;

+   return status;


1. Panel would flicker at system boot time. Your patch would flash the 
panel power in connector->detect() function when dp->dpms_mode isn't 
DRM_MODE_DPMS_OFF. So when userspace keep detect the connector status in 
boot time, we could see panel would flicker (light up for a while, and 
turn off again, and keep loop for several time). I have copied some 
kernel logs:



[   11.065267] YKK - analogix_dp_detect:1052
[   11.729596] YKK - analogix_dp_get_modes:1016
[   11.737608] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.749229] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.760799] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!

[   13.315962] YKK - analogix_dp_detect:1052
[   13.984702] YKK - analogix_dp_get_modes:1016
[   13.992977] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   14.004414] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   14.015842] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!

[   14.183109] YKK - analogix_dp_bridge_pre_enable:1147
[   14.306301] rockchip-dp ff97.edp: Link Training Clock Recovery 
success

[   14.319130] rockchip-dp ff97.edp: Link Training success!
[   14.326388] rockchip-dp ff97.edp: wait SYS_CTL_2.
[   14.437247] rockchip-dp ff97.edp: Timeout of video streamclk ok
[   14.443585] rockchip-dp ff97.edp: unable to config video



  }
  
  static void analogix_dp_connector_destroy(struct drm_connector *connector)

@@ -1035,6 +1051,18 @@ static int analogix_dp_bridge_attach(struct drm_bridge 
*bridge)
return 0;
  }
  
+static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge)

+{
+   struct analogix_dp_device *dp = bridge->driver_private;
+   int ret;
+
+   if (dp->plat_data->panel) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }


2. Driver would failed to read EDID in some case. Panel would only be 
powered up in bridge->pre_enable() function which later than 
connector->get_modes() function, and this would caused DPCD transfer 
failed in analogix_dp_handle_edid(). This seem won't caused too big 
issue, cause userspace would read EDID again after bridge/encoder is 
enabled. But it's better to avoid this potential bug.



[   11.065267] YKK - analogix_dp_detect:1052
[   11.729596] YKK - analogix_dp_get_modes:1016
[   11.737608] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.749229] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.760799] 

Re: [PATCH] drm/analogix_dp: Ensure the panel is properly prepared/unprepared

2016-07-31 Thread Yakir Yang

Sean,

On 07/30/2016 03:16 AM, Sean Paul wrote:

Instead of just preparing the panel on bind, actually prepare/unprepare
during modeset/disable. The panel must be prepared in order to read hpd
status, so we need to refcount the prepares in order to ensure we don't
accidentally turn the panel off at the wrong time.

Signed-off-by: Sean Paul 
---


Hi Yakir,
This is what I was talking about upthread. I've tested it and it seems to be 
working.

What do you think?


Thanks for your patch, and it works. But I have introduced two 
questions, and I haven't found a way to fixed them.



Sean



drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 48 +-
  1 file changed, 37 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..7b764a4 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -960,11 +960,27 @@ enum drm_connector_status
  analogix_dp_detect(struct drm_connector *connector, bool force)
  {
struct analogix_dp_device *dp = to_dp(connector);
+   enum drm_connector_status status = connector_status_disconnected;
+   int ret;
  
-	if (analogix_dp_detect_hpd(dp))

-   return connector_status_disconnected;
+   if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret) {
+   DRM_ERROR("failed to setup panel (%d)\n", ret);
+   return connector_status_disconnected;
+   }
+   }
+
+   if (!analogix_dp_detect_hpd(dp))
+   status = connector_status_connected;
+
+   if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) {
+   ret = drm_panel_unprepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }
  
-	return connector_status_connected;

+   return status;


1. Panel would flicker at system boot time. Your patch would flash the 
panel power in connector->detect() function when dp->dpms_mode isn't 
DRM_MODE_DPMS_OFF. So when userspace keep detect the connector status in 
boot time, we could see panel would flicker (light up for a while, and 
turn off again, and keep loop for several time). I have copied some 
kernel logs:



[   11.065267] YKK - analogix_dp_detect:1052
[   11.729596] YKK - analogix_dp_get_modes:1016
[   11.737608] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.749229] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.760799] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!

[   13.315962] YKK - analogix_dp_detect:1052
[   13.984702] YKK - analogix_dp_get_modes:1016
[   13.992977] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   14.004414] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   14.015842] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!

[   14.183109] YKK - analogix_dp_bridge_pre_enable:1147
[   14.306301] rockchip-dp ff97.edp: Link Training Clock Recovery 
success

[   14.319130] rockchip-dp ff97.edp: Link Training success!
[   14.326388] rockchip-dp ff97.edp: wait SYS_CTL_2.
[   14.437247] rockchip-dp ff97.edp: Timeout of video streamclk ok
[   14.443585] rockchip-dp ff97.edp: unable to config video



  }
  
  static void analogix_dp_connector_destroy(struct drm_connector *connector)

@@ -1035,6 +1051,18 @@ static int analogix_dp_bridge_attach(struct drm_bridge 
*bridge)
return 0;
  }
  
+static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge)

+{
+   struct analogix_dp_device *dp = bridge->driver_private;
+   int ret;
+
+   if (dp->plat_data->panel) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }


2. Driver would failed to read EDID in some case. Panel would only be 
powered up in bridge->pre_enable() function which later than 
connector->get_modes() function, and this would caused DPCD transfer 
failed in analogix_dp_handle_edid(). This seem won't caused too big 
issue, cause userspace would read EDID again after bridge/encoder is 
enabled. But it's better to avoid this potential bug.



[   11.065267] YKK - analogix_dp_detect:1052
[   11.729596] YKK - analogix_dp_get_modes:1016
[   11.737608] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.749229] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.760799] rockchip-dp ff97.edp: 

Re: [PATCH] drm/analogix_dp: Ensure the panel is properly prepared/unprepared

2016-07-31 Thread Yakir Yang

Sean,

On 07/30/2016 03:16 AM, Sean Paul wrote:

Instead of just preparing the panel on bind, actually prepare/unprepare
during modeset/disable. The panel must be prepared in order to read hpd
status, so we need to refcount the prepares in order to ensure we don't
accidentally turn the panel off at the wrong time.

Signed-off-by: Sean Paul 
---


Hi Yakir,
This is what I was talking about upthread. I've tested it and it seems to be 
working.

What do you think?


Thanks for your patch, and it works. But I have introduced two 
questions, and I haven't found a way to fixed them.



Sean



drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 48 +-
  1 file changed, 37 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..7b764a4 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -960,11 +960,27 @@ enum drm_connector_status
  analogix_dp_detect(struct drm_connector *connector, bool force)
  {
struct analogix_dp_device *dp = to_dp(connector);
+   enum drm_connector_status status = connector_status_disconnected;
+   int ret;
  
-	if (analogix_dp_detect_hpd(dp))

-   return connector_status_disconnected;
+   if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret) {
+   DRM_ERROR("failed to setup panel (%d)\n", ret);
+   return connector_status_disconnected;
+   }
+   }
+
+   if (!analogix_dp_detect_hpd(dp))
+   status = connector_status_connected;
+
+   if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) {
+   ret = drm_panel_unprepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }
  
-	return connector_status_connected;

+   return status;


1. Panel would flicker at system boot time. Your patch would flash the 
panel power in connector->detect() function when dp->dpms_mode isn't 
DRM_MODE_DPMS_OFF. So when userspace keep detect the connector status in 
boot time, we could see panel would flicker (light up for a while, and 
turn off again, and keep loop for several time). I have copied some 
kernel logs:



[   11.065267] YKK - analogix_dp_detect:1052
[   11.729596] YKK - analogix_dp_get_modes:1016
[   11.737608] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.749229] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.760799] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!

[   13.315962] YKK - analogix_dp_detect:1052
[   13.984702] YKK - analogix_dp_get_modes:1016
[   13.992977] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   14.004414] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   14.015842] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!

[   14.183109] YKK - analogix_dp_bridge_pre_enable:1147
[   14.306301] rockchip-dp ff97.edp: Link Training Clock Recovery 
success

[   14.319130] rockchip-dp ff97.edp: Link Training success!
[   14.326388] rockchip-dp ff97.edp: wait SYS_CTL_2.
[   14.437247] rockchip-dp ff97.edp: Timeout of video streamclk ok
[   14.443585] rockchip-dp ff97.edp: unable to config video



  }
  
  static void analogix_dp_connector_destroy(struct drm_connector *connector)

@@ -1035,6 +1051,18 @@ static int analogix_dp_bridge_attach(struct drm_bridge 
*bridge)
return 0;
  }
  
+static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge)

+{
+   struct analogix_dp_device *dp = bridge->driver_private;
+   int ret;
+
+   if (dp->plat_data->panel) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }


2. Driver would failed to read EDID in some case. Panel would only be 
powered up in bridge->pre_enable() function which later than 
connector->get_modes() function, and this would caused DPCD transfer 
failed in analogix_dp_handle_edid(). This seem won't caused too big 
issue, cause userspace would read EDID again after bridge/encoder is 
enabled. But it's better to avoid this potential bug.



[   11.065267] YKK - analogix_dp_detect:1052
[   11.729596] YKK - analogix_dp_get_modes:1016
[   11.737608] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.749229] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.760799] 

Re: [PATCH] drm/analogix_dp: Ensure the panel is properly prepared/unprepared

2016-07-31 Thread Yakir Yang

Sean,

On 07/30/2016 03:16 AM, Sean Paul wrote:

Instead of just preparing the panel on bind, actually prepare/unprepare
during modeset/disable. The panel must be prepared in order to read hpd
status, so we need to refcount the prepares in order to ensure we don't
accidentally turn the panel off at the wrong time.

Signed-off-by: Sean Paul 
---


Hi Yakir,
This is what I was talking about upthread. I've tested it and it seems to be 
working.

What do you think?


Thanks for your patch, and it works. But I have introduced two 
questions, and I haven't found a way to fixed them.



Sean



drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 48 +-
  1 file changed, 37 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..7b764a4 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -960,11 +960,27 @@ enum drm_connector_status
  analogix_dp_detect(struct drm_connector *connector, bool force)
  {
struct analogix_dp_device *dp = to_dp(connector);
+   enum drm_connector_status status = connector_status_disconnected;
+   int ret;
  
-	if (analogix_dp_detect_hpd(dp))

-   return connector_status_disconnected;
+   if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret) {
+   DRM_ERROR("failed to setup panel (%d)\n", ret);
+   return connector_status_disconnected;
+   }
+   }
+
+   if (!analogix_dp_detect_hpd(dp))
+   status = connector_status_connected;
+
+   if (dp->plat_data->panel && dp->dpms_mode != DRM_MODE_DPMS_ON) {
+   ret = drm_panel_unprepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }
  
-	return connector_status_connected;

+   return status;


1. Panel would flicker at system boot time. Your patch would flash the 
panel power in connector->detect() function when dp->dpms_mode isn't 
DRM_MODE_DPMS_OFF. So when userspace keep detect the connector status in 
boot time, we could see panel would flicker (light up for a while, and 
turn off again, and keep loop for several time). I have copied some 
kernel logs:



[   11.065267] YKK - analogix_dp_detect:1052
[   11.729596] YKK - analogix_dp_get_modes:1016
[   11.737608] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.749229] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.760799] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!

[   13.315962] YKK - analogix_dp_detect:1052
[   13.984702] YKK - analogix_dp_get_modes:1016
[   13.992977] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   14.004414] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   14.015842] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!

[   14.183109] YKK - analogix_dp_bridge_pre_enable:1147
[   14.306301] rockchip-dp ff97.edp: Link Training Clock Recovery 
success

[   14.319130] rockchip-dp ff97.edp: Link Training success!
[   14.326388] rockchip-dp ff97.edp: wait SYS_CTL_2.
[   14.437247] rockchip-dp ff97.edp: Timeout of video streamclk ok
[   14.443585] rockchip-dp ff97.edp: unable to config video



  }
  
  static void analogix_dp_connector_destroy(struct drm_connector *connector)

@@ -1035,6 +1051,18 @@ static int analogix_dp_bridge_attach(struct drm_bridge 
*bridge)
return 0;
  }
  
+static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge)

+{
+   struct analogix_dp_device *dp = bridge->driver_private;
+   int ret;
+
+   if (dp->plat_data->panel) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }


2. Driver would failed to read EDID in some case. Panel would only be 
powered up in bridge->pre_enable() function which later than 
connector->get_modes() function, and this would caused DPCD transfer 
failed in analogix_dp_handle_edid(). This seem won't caused too big 
issue, cause userspace would read EDID again after bridge/encoder is 
enabled. But it's better to avoid this potential bug.



[   11.065267] YKK - analogix_dp_detect:1052
[   11.729596] YKK - analogix_dp_get_modes:1016
[   11.737608] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.749229] rockchip-dp ff97.edp: 
analogix_dp_read_bytes_from_dpcd: Aux Transaction fail!
[   11.760799] rockchip-dp ff97.edp: 

Re: [PATCH v14 0/17] Add Analogix Core Display Port Driver

2016-07-31 Thread Yakir Yang


On 07/29/2016 04:38 PM, Tomeu Vizoso wrote:

On 5 April 2016 at 04:06, Yakir Yang <y...@rock-chips.com> wrote:

Hi Daniel,


On 03/31/2016 06:15 PM, Daniel Vetter wrote:

On Mon, Feb 15, 2016 at 07:08:05PM +0800, Yakir Yang wrote:

Hi all,

The Samsung Exynos eDP controller and Rockchip RK3288 eDP controller
share the same IP, so a lot of parts can be re-used. I split the common
code into bridge directory, then rk3288 and exynos only need to keep
some platform code. Cause I can't find the exact IP name of exynos dp
controller, so I decide to name dp core driver with "analogix" which I
find in rk3288 eDP TRM

But there are still three light registers setting different between
exynos and rk3288.
1. RK3288 have five special pll registers which not indicate in exynos
 dp controller.
2. The address of DP_PHY_PD(dp phy power manager register) are different
 between rk3288 and exynos.
3. Rk3288 and exynos have different setting with AUX_HW_RETRY_CTL(dp
debug
 register).

Due to Mark Yao have introduced the ATOMIC support to Rockchip drm, so
it's
okay to use the ATOMIC helpers functions in connector_funcs. No need to
splict
the connector init to platform driver anymore, and this is the biggest
change
since version 11.

This v14 didn't have lots of new changes which seems not the correct time
to
upgrade the version number, but I have changed ordering of patches
(adding 2
more, and removing 2 out). Especially to prevent confusing people, so I
updated
the whole series.

So I'm jumping into this part way late, but just noticed (well Thierry
pointed this out to me) that the exynos dp driver reinvents all the dp and
dp-aux helpers we already. That's somewhat okish for a private driver (and
exynos has a reputation for that kind of stuff), but imo not ok for a
shared driver.

Not saying this should block merging this patch, but it really needs to be
addressed. All the dp aux and edid read code in the current
exynos_dp_core/reg.c files needs to be replaced with dp helpers and the
core i2c edid reading code.

Who's going to sign up to do this?


Volunteer to that, after finish this thread, I would send new series to
switch to take use of dp helper.

Hi Yakir,

do you have plans to do this work in the short term? If not, I can tackle it.


Wow, that would be great if you like to tackle it  :-D

I always keep this in my mind, but haven't found an chance
to finish it. I would like to sit in your Cc list when you post
them out  ;)

Best Regards,
- Yakir


Regards,

Tomeu


:-D
- Yakir



-Daniel


Thanks,
- Yakir


Changes in v14:
- Rebase the new changes in imx-dp driver
- Split up this patch into 3 parts, make this easy to review (Heiko)
- Remove the Rockchip DP PHY to an separate thread (Heiko)
  https://patchwork.kernel.org/patch/8312701/

Changes in v13:
- Use .enable instead of preprare/commit in encoder_helper_funcs (Heiko)
- Fix the missing parameters with drm_encoder_init() helper function.
(Heiko)

Changes in v12:
- Move the connector init to analogix_dp driver, and using ATOMIC helper
(Heiko)
- Add the ack from Jingoo
- Remove the enum link_rate_type struct, using the marcos in
drm_dp_helper.h (Jingoo)

Changes in v11:
- Uses tabs to fix the indentation issues in analogix_dp_core.h (Heiko)
- Rename the "analogix,need-force-hpd" to common 'force-hpd' (Rob)
- Add the ack from Rob Herring
- Revert parts of Gustavo Padovan's changes in commit:
 drm/exynos: do not start enabling DP at bind() phase
Add dp phy poweron function in bind time.
- Move the panel prepare from get_modes time to bind time, and move
the panel unprepare from bridge->disable to unbind time. (Heiko)

Changes in v10:
- Add the ack from Rob Herring
- Correct the ROCKCHIP_ANALOGIX_DP indentation in Kconfig to tabs here
(Heiko)
- Add the ack from Rob Herring
- Remove the surplus "plat_data" check. (Heiko)
-   switch (dp->plat_data && dp->plat_data->dev_type) {
+   switch (dp->plat_data->dev_type) {

Changes in v9:
- Document more details for 'ports' property.

Changes in v8:
- Correct the right document path of display-timing.txt (Heiko)
- Correct the misspell of 'from' to 'frm'. (Heiko)
- Modify the commit subject name. (Heiko)

Changes in v7:
- Back to use the of_property_read_bool() interfacs to provoid backward
compatibility of "hsync-active-high" "vsync-active-high" "interlaced"
to avoid -EOVERFLOW error (Krzysztof)

Changes in v6:
- Fix the Kconfig recursive dependency (Javier)
- Fix Peach Pit hpd property name error:
-   hpd-gpio = < 6 0>;
+   hpd-gpios = < 6 0>;

Changes in v5:
- Correct the check condition of gpio_is_valid when driver try to get
the "hpd-gpios" DT propery. (Heiko)
- Move the platform attach callback in the front of core driver bridge
attch function. Cause once platform failed at attach, core driver
should
still failed, so no need to i

Re: [PATCH v14 0/17] Add Analogix Core Display Port Driver

2016-07-31 Thread Yakir Yang


On 07/29/2016 04:38 PM, Tomeu Vizoso wrote:

On 5 April 2016 at 04:06, Yakir Yang  wrote:

Hi Daniel,


On 03/31/2016 06:15 PM, Daniel Vetter wrote:

On Mon, Feb 15, 2016 at 07:08:05PM +0800, Yakir Yang wrote:

Hi all,

The Samsung Exynos eDP controller and Rockchip RK3288 eDP controller
share the same IP, so a lot of parts can be re-used. I split the common
code into bridge directory, then rk3288 and exynos only need to keep
some platform code. Cause I can't find the exact IP name of exynos dp
controller, so I decide to name dp core driver with "analogix" which I
find in rk3288 eDP TRM

But there are still three light registers setting different between
exynos and rk3288.
1. RK3288 have five special pll registers which not indicate in exynos
 dp controller.
2. The address of DP_PHY_PD(dp phy power manager register) are different
 between rk3288 and exynos.
3. Rk3288 and exynos have different setting with AUX_HW_RETRY_CTL(dp
debug
 register).

Due to Mark Yao have introduced the ATOMIC support to Rockchip drm, so
it's
okay to use the ATOMIC helpers functions in connector_funcs. No need to
splict
the connector init to platform driver anymore, and this is the biggest
change
since version 11.

This v14 didn't have lots of new changes which seems not the correct time
to
upgrade the version number, but I have changed ordering of patches
(adding 2
more, and removing 2 out). Especially to prevent confusing people, so I
updated
the whole series.

So I'm jumping into this part way late, but just noticed (well Thierry
pointed this out to me) that the exynos dp driver reinvents all the dp and
dp-aux helpers we already. That's somewhat okish for a private driver (and
exynos has a reputation for that kind of stuff), but imo not ok for a
shared driver.

Not saying this should block merging this patch, but it really needs to be
addressed. All the dp aux and edid read code in the current
exynos_dp_core/reg.c files needs to be replaced with dp helpers and the
core i2c edid reading code.

Who's going to sign up to do this?


Volunteer to that, after finish this thread, I would send new series to
switch to take use of dp helper.

Hi Yakir,

do you have plans to do this work in the short term? If not, I can tackle it.


Wow, that would be great if you like to tackle it  :-D

I always keep this in my mind, but haven't found an chance
to finish it. I would like to sit in your Cc list when you post
them out  ;)

Best Regards,
- Yakir


Regards,

Tomeu


:-D
- Yakir



-Daniel


Thanks,
- Yakir


Changes in v14:
- Rebase the new changes in imx-dp driver
- Split up this patch into 3 parts, make this easy to review (Heiko)
- Remove the Rockchip DP PHY to an separate thread (Heiko)
  https://patchwork.kernel.org/patch/8312701/

Changes in v13:
- Use .enable instead of preprare/commit in encoder_helper_funcs (Heiko)
- Fix the missing parameters with drm_encoder_init() helper function.
(Heiko)

Changes in v12:
- Move the connector init to analogix_dp driver, and using ATOMIC helper
(Heiko)
- Add the ack from Jingoo
- Remove the enum link_rate_type struct, using the marcos in
drm_dp_helper.h (Jingoo)

Changes in v11:
- Uses tabs to fix the indentation issues in analogix_dp_core.h (Heiko)
- Rename the "analogix,need-force-hpd" to common 'force-hpd' (Rob)
- Add the ack from Rob Herring
- Revert parts of Gustavo Padovan's changes in commit:
 drm/exynos: do not start enabling DP at bind() phase
Add dp phy poweron function in bind time.
- Move the panel prepare from get_modes time to bind time, and move
the panel unprepare from bridge->disable to unbind time. (Heiko)

Changes in v10:
- Add the ack from Rob Herring
- Correct the ROCKCHIP_ANALOGIX_DP indentation in Kconfig to tabs here
(Heiko)
- Add the ack from Rob Herring
- Remove the surplus "plat_data" check. (Heiko)
-   switch (dp->plat_data && dp->plat_data->dev_type) {
+   switch (dp->plat_data->dev_type) {

Changes in v9:
- Document more details for 'ports' property.

Changes in v8:
- Correct the right document path of display-timing.txt (Heiko)
- Correct the misspell of 'from' to 'frm'. (Heiko)
- Modify the commit subject name. (Heiko)

Changes in v7:
- Back to use the of_property_read_bool() interfacs to provoid backward
compatibility of "hsync-active-high" "vsync-active-high" "interlaced"
to avoid -EOVERFLOW error (Krzysztof)

Changes in v6:
- Fix the Kconfig recursive dependency (Javier)
- Fix Peach Pit hpd property name error:
-   hpd-gpio = < 6 0>;
+   hpd-gpios = < 6 0>;

Changes in v5:
- Correct the check condition of gpio_is_valid when driver try to get
the "hpd-gpios" DT propery. (Heiko)
- Move the platform attach callback in the front of core driver bridge
attch function. Cause once platform failed at attach, core driver
should
still failed, so no need to init connector before platform attach

Re: [PATCH v1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable

2016-07-27 Thread Yakir Yang

Sean,

Oops, sorry about miss your suggest :(

On 07/22/2016 11:03 PM, Sean Paul wrote:

On Thu, Jul 21, 2016 at 9:00 PM, Yakir Yang <y...@rock-chips.com> wrote:

Sean,

Thanks for your fast respond :-)

But this patch is not the latest one, I have upgraded this to "v1.1" version
to fix the eDP can't be disabled problem:
 [PATCH v1.1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP
need to disable
 Changes in v1.1: - unprepare the panel at the end of
bridge->disable() function

In spite of this, I would take your comments with my "v1.1" patch.

On 07/21/2016 10:28 PM, Sean Paul wrote:

On Thu, Jul 21, 2016 at 9:14 AM, Yakir Yang <y...@rock-chips.com> wrote:

Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP
controller stop to send valid video signal, otherwhise panel would
go burn in, and keep flicker and flicker.

So it's better to turn off the panel when eDP need to disable, and
we need to turn on the panel in connector->detect() callback, so
that driver would detect panel status rightly.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 18 ++
  1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..ea059b3 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector,
bool force)
  {
 struct analogix_dp_device *dp = to_dp(connector);

+   /*
+* Panle would prepare for several times here, but don't worry it

s/Panle/Panel/


Done

+* would only enable the hardware at the first prepare time.

Errr, this shouldn't go in detect. How about putting this in
bridge_enable instead?


Nope, if we put this in bridge_enable, then eDP would never be enabled.
Here're the calling flow.

--> analogix_dp_probe
   --> analogix_dp_bind  # we still haven't prepared the panel here, that
means panel have been powered up
 --> analogix_dp_detect  # Oops, losing panel valid hotplug signal, cause
panel have been powered up
 --> ** Keep detecting **


Yeah, after playing around with the patch yesterday I discovered this
for myself. I still don't think detect() should be changing hardware
state. Perhaps you could add a matching unprepare() after you attempt
to detect the panel?


Hmm, I don't understand the meaning of "add a matching unprepare()".

I didn't see there is an unprepare() callback in drm_crtc_helper.h, would
you like to share some simple code :-D

Thanks,
- Yakir


Sean


+*/
+   if (dp->plat_data->panel)
+   if (drm_panel_prepare(dp->plat_data->panel))

Personally, I don't like doing work in a conditional since you're
throwing the return code away. Could you break this out into:

ret = drm_panel_prepare(dp->plat_data->panel);
if (ret)
   DRM_ERROR("failed to setup the panel ret=%d\n", ret);


Okay


+   DRM_ERROR("failed to setup the panel\n");
+
 if (analogix_dp_detect_hpd(dp))
 return connector_status_disconnected;

@@ -1063,7 +1071,8 @@ static void analogix_dp_bridge_disable(struct
drm_bridge *bridge)
 return;

 if (dp->plat_data->panel) {
-   if (drm_panel_disable(dp->plat_data->panel)) {
+   if (drm_panel_disable(dp->plat_data->panel) ||
+   drm_panel_unprepare(dp->plat_data->panel)) {

Same comment here, please break this out into separate statements for
better readability/logging.


Okay,


Thanks,
- Yakir


 DRM_ERROR("failed to disable the panel\n");
 return;
 }
@@ -1333,13 +1342,6 @@ int analogix_dp_bind(struct device *dev, struct
drm_device *drm_dev,

 phy_power_on(dp->phy);

-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
 analogix_dp_init_dp(dp);

 ret = devm_request_threaded_irq(>dev, dp->irq,
--
1.9.1













Re: [PATCH v1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable

2016-07-27 Thread Yakir Yang

Sean,

Oops, sorry about miss your suggest :(

On 07/22/2016 11:03 PM, Sean Paul wrote:

On Thu, Jul 21, 2016 at 9:00 PM, Yakir Yang  wrote:

Sean,

Thanks for your fast respond :-)

But this patch is not the latest one, I have upgraded this to "v1.1" version
to fix the eDP can't be disabled problem:
 [PATCH v1.1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP
need to disable
 Changes in v1.1: - unprepare the panel at the end of
bridge->disable() function

In spite of this, I would take your comments with my "v1.1" patch.

On 07/21/2016 10:28 PM, Sean Paul wrote:

On Thu, Jul 21, 2016 at 9:14 AM, Yakir Yang  wrote:

Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP
controller stop to send valid video signal, otherwhise panel would
go burn in, and keep flicker and flicker.

So it's better to turn off the panel when eDP need to disable, and
we need to turn on the panel in connector->detect() callback, so
that driver would detect panel status rightly.

Signed-off-by: Yakir Yang 
---
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 18 ++
  1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..ea059b3 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector,
bool force)
  {
 struct analogix_dp_device *dp = to_dp(connector);

+   /*
+* Panle would prepare for several times here, but don't worry it

s/Panle/Panel/


Done

+* would only enable the hardware at the first prepare time.

Errr, this shouldn't go in detect. How about putting this in
bridge_enable instead?


Nope, if we put this in bridge_enable, then eDP would never be enabled.
Here're the calling flow.

--> analogix_dp_probe
   --> analogix_dp_bind  # we still haven't prepared the panel here, that
means panel have been powered up
 --> analogix_dp_detect  # Oops, losing panel valid hotplug signal, cause
panel have been powered up
 --> ** Keep detecting **


Yeah, after playing around with the patch yesterday I discovered this
for myself. I still don't think detect() should be changing hardware
state. Perhaps you could add a matching unprepare() after you attempt
to detect the panel?


Hmm, I don't understand the meaning of "add a matching unprepare()".

I didn't see there is an unprepare() callback in drm_crtc_helper.h, would
you like to share some simple code :-D

Thanks,
- Yakir


Sean


+*/
+   if (dp->plat_data->panel)
+   if (drm_panel_prepare(dp->plat_data->panel))

Personally, I don't like doing work in a conditional since you're
throwing the return code away. Could you break this out into:

ret = drm_panel_prepare(dp->plat_data->panel);
if (ret)
   DRM_ERROR("failed to setup the panel ret=%d\n", ret);


Okay


+   DRM_ERROR("failed to setup the panel\n");
+
 if (analogix_dp_detect_hpd(dp))
 return connector_status_disconnected;

@@ -1063,7 +1071,8 @@ static void analogix_dp_bridge_disable(struct
drm_bridge *bridge)
 return;

 if (dp->plat_data->panel) {
-   if (drm_panel_disable(dp->plat_data->panel)) {
+   if (drm_panel_disable(dp->plat_data->panel) ||
+   drm_panel_unprepare(dp->plat_data->panel)) {

Same comment here, please break this out into separate statements for
better readability/logging.


Okay,


Thanks,
- Yakir


 DRM_ERROR("failed to disable the panel\n");
 return;
 }
@@ -1333,13 +1342,6 @@ int analogix_dp_bind(struct device *dev, struct
drm_device *drm_dev,

 phy_power_on(dp->phy);

-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
 analogix_dp_init_dp(dp);

 ret = devm_request_threaded_irq(>dev, dp->irq,
--
1.9.1













Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-24 Thread Yakir Yang

Sean,

On 07/14/2016 11:14 PM, Sean Paul wrote:

On Thu, Jul 14, 2016 at 12:15:49PM +0800, Yakir Yang wrote:

The PSR driver have exported four symbols for specific device driver:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.

Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang <y...@rock-chips.com>


I still don't think it's a good idea to pull this out into a separate PSR
driver, but I suppose we can integrate it at a later time if it becomes
cumbersome.

Reviewed-by: Sean Paul <seanp...@chromium.org>


In order to make it safely to call those symbols at interrupt context, i 
have made lots of changes about this patch. It's not suitable to take 
your reviewed flag at the v5, if you're happy to review the new one [0], 
that would be very nice  :-D


[0]: https://patchwork.kernel.org/patch/9244805/

Thanks,
- Yakir





---
Changes in v4:
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)
 
[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]

Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

  drivers/gpu/drm/rockchip/Makefile   |   2 +-
  drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   4 +
  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
  drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 
  drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  26 
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  29 
  7 files changed, 298 insertions(+), 1 deletion(-)
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
  
  rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \

-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
  rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
  
  obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index d665fb0..26c12b3 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev)
  
  	drm_dev->dev_private = private;
  
+	INIT_LIST_HEAD(>psr_list);

+   mutex_init(>psr_list_mutex);
+
drm_mode_config_init(drm_dev);
  
  	rockchip_drm_mode_config_init(drm_dev);

@@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev)
  
  	if (is_support_iommu)

arm_iommu_release_mapping(mapping);
+
return 0;
  err_fbdev_fini:
rockchip_drm_fbdev_fini(drm_dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 239b830..9c34c9e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -61,6 +61,9 @@ struct rockchip_drm_private {
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
struct drm_atomic_state *state;
+
+   struct list_head psr_list;
+   struct mutex psr_list_mutex;
 

Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-24 Thread Yakir Yang

Sean,

On 07/14/2016 11:14 PM, Sean Paul wrote:

On Thu, Jul 14, 2016 at 12:15:49PM +0800, Yakir Yang wrote:

The PSR driver have exported four symbols for specific device driver:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.

Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang 


I still don't think it's a good idea to pull this out into a separate PSR
driver, but I suppose we can integrate it at a later time if it becomes
cumbersome.

Reviewed-by: Sean Paul 


In order to make it safely to call those symbols at interrupt context, i 
have made lots of changes about this patch. It's not suitable to take 
your reviewed flag at the v5, if you're happy to review the new one [0], 
that would be very nice  :-D


[0]: https://patchwork.kernel.org/patch/9244805/

Thanks,
- Yakir





---
Changes in v4:
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)
 
[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]

Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

  drivers/gpu/drm/rockchip/Makefile   |   2 +-
  drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   4 +
  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
  drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 
  drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  26 
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  29 
  7 files changed, 298 insertions(+), 1 deletion(-)
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
  
  rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \

-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
  rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
  
  obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index d665fb0..26c12b3 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev)
  
  	drm_dev->dev_private = private;
  
+	INIT_LIST_HEAD(>psr_list);

+   mutex_init(>psr_list_mutex);
+
drm_mode_config_init(drm_dev);
  
  	rockchip_drm_mode_config_init(drm_dev);

@@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev)
  
  	if (is_support_iommu)

arm_iommu_release_mapping(mapping);
+
return 0;
  err_fbdev_fini:
rockchip_drm_fbdev_fini(drm_dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 239b830..9c34c9e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -61,6 +61,9 @@ struct rockchip_drm_private {
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
struct drm_atomic_state *state;
+
+   struct list_head psr_list;
+   struct mutex psr_list_mutex;
  };
  
  int rockchip_register_crtc_funcs(struct drm_crtc 

Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-24 Thread Yakir Yang

Doug,

On 07/23/2016 12:04 PM, Doug Anderson wrote:

Yakir,

On Wed, Jul 13, 2016 at 9:15 PM, Yakir Yang <y...@rock-chips.com> wrote:

+static void psr_set_state(struct psr_drv *psr, enum psr_state state)
+{
+   mutex_lock(>state_mutex);
+
+   if (psr->state == state) {
+   mutex_unlock(>state_mutex);
+   return;
+   }
+
+   psr->state = state;
+   switch (state) {
+   case PSR_ENABLE:
+   psr->set(psr->encoder, true);
+   break;
+
+   case PSR_DISABLE:
+   case PSR_FLUSH:
+   psr->set(psr->encoder, false);
+   break;
+   };
+
+   mutex_unlock(>state_mutex);
+}
+
+static void psr_flush_handler(unsigned long data)
+{
+   struct psr_drv *psr = (struct psr_drv *)data;
+
+   if (!psr || psr->state != PSR_FLUSH)
+   return;
+
+   psr_set_state(psr, PSR_ENABLE);

As mentioned in a separate thread, this is probably not OK.
psr_set_state() grabs a mutex and that might sleep.  ...but
psr_flush_handler() is a timer.  I'm nearly certain that timers can't
sleep.

I believe this is the source of "sleeping function called from invalid
context" that I've seen at times.


Thanks for your reported, i have wrote a patch[0] to fix this problem in 
my v5. If you're happy to review, that would be great ;)


[0]: https://patchwork.kernel.org/patch/9244805/

- Yakir



-Doug








Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-24 Thread Yakir Yang

Doug,

On 07/23/2016 12:04 PM, Doug Anderson wrote:

Yakir,

On Wed, Jul 13, 2016 at 9:15 PM, Yakir Yang  wrote:

+static void psr_set_state(struct psr_drv *psr, enum psr_state state)
+{
+   mutex_lock(>state_mutex);
+
+   if (psr->state == state) {
+   mutex_unlock(>state_mutex);
+   return;
+   }
+
+   psr->state = state;
+   switch (state) {
+   case PSR_ENABLE:
+   psr->set(psr->encoder, true);
+   break;
+
+   case PSR_DISABLE:
+   case PSR_FLUSH:
+   psr->set(psr->encoder, false);
+   break;
+   };
+
+   mutex_unlock(>state_mutex);
+}
+
+static void psr_flush_handler(unsigned long data)
+{
+   struct psr_drv *psr = (struct psr_drv *)data;
+
+   if (!psr || psr->state != PSR_FLUSH)
+   return;
+
+   psr_set_state(psr, PSR_ENABLE);

As mentioned in a separate thread, this is probably not OK.
psr_set_state() grabs a mutex and that might sleep.  ...but
psr_flush_handler() is a timer.  I'm nearly certain that timers can't
sleep.

I believe this is the source of "sleeping function called from invalid
context" that I've seen at times.


Thanks for your reported, i have wrote a patch[0] to fix this problem in 
my v5. If you're happy to review, that would be great ;)


[0]: https://patchwork.kernel.org/patch/9244805/

- Yakir



-Doug








[PATCH v5 1/4] drm/rockchip: vop: export line flag function

2016-07-24 Thread Yakir Yang
VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang <y...@rock-chips.com>
Reviewed-by: Sean Paul <seanp...@chromium.org>
---
Changes in v5:
- Add reviewed flag from Sean.

Changes in v4.1:
- Remove the completion_done() check in irq handler (Sean)

Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
 4 files changed, 126 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index bc08b50..90a7e62 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
/* protected by dev->event_lock */
struct drm_pending_vblank_event *event;
 
+   struct completion line_flag_completion;
+
const struct vop_data *data;
 
uint32_t *regsbak;
@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(>irq_lock, flags);
 }
 
+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_ir

[PATCH v5 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-07-24 Thread Yakir Yang
The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()

Signed-off-by: Yakir Yang <y...@rock-chips.com>
Reviewed-by: Sean Paul <seanp...@chromium.org>
---
Changes in v5:
- Add reviewed flag from Sean.

Changes in v4.1:
- Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean)
- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 51 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 34 +
 include/drm/bridge/analogix_dp.h   |  3 +
 5 files changed, 174 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..381b25e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device 
*dp)
return 0;
 }
 
+int analogix_dp_enable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = 0;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_version;
+
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+   dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+   return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_en;
+
+   /* Disable psr function */
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+   psr_en &= ~DP_PSR_ENABLE;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Main-Link transmitter remains active during PSR active states */
+   psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Enable psr function */
+   psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   analogix_dp_enable_psr_crc(dp);
+}
+
 static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
 {
int i;
@@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device 
*dp)
 
/* Enable video */
analogix_dp_start_video(dp);
+
+   dp->psr_support 

[PATCH v5 1/4] drm/rockchip: vop: export line flag function

2016-07-24 Thread Yakir Yang
VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang 
Reviewed-by: Sean Paul 
---
Changes in v5:
- Add reviewed flag from Sean.

Changes in v4.1:
- Remove the completion_done() check in irq handler (Sean)

Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
 4 files changed, 126 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index bc08b50..90a7e62 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
/* protected by dev->event_lock */
struct drm_pending_vblank_event *event;
 
+   struct completion line_flag_completion;
+
const struct vop_data *data;
 
uint32_t *regsbak;
@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(>irq_lock, flags);
 }
 
+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   V

[PATCH v5 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-07-24 Thread Yakir Yang
The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()

Signed-off-by: Yakir Yang 
Reviewed-by: Sean Paul 
---
Changes in v5:
- Add reviewed flag from Sean.

Changes in v4.1:
- Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean)
- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 51 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 34 +
 include/drm/bridge/analogix_dp.h   |  3 +
 5 files changed, 174 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..381b25e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device 
*dp)
return 0;
 }
 
+int analogix_dp_enable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = 0;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_version;
+
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+   dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+   return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_en;
+
+   /* Disable psr function */
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+   psr_en &= ~DP_PSR_ENABLE;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Main-Link transmitter remains active during PSR active states */
+   psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Enable psr function */
+   psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   analogix_dp_enable_psr_crc(dp);
+}
+
 static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
 {
int i;
@@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device 
*dp)
 
/* Enable video */
analogix_dp_start_video(dp);
+
+   dp->psr_support = analogix_dp_detect_sink_psr(dp);
+   if (dp->psr_support)
+

[PATCH v5 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-24 Thread Yakir Yang
The PSR driver have exported four symbols for specific device driver, and
it's safe to call them in interrupt context:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.

Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v5:
- Only keep 'psr_list_mutex' at register/unregister time.
- Remove unused global variables.
- Make list traversal safely at rockchip_drm_psr_unregister().
- Make psr_set_state() to a delay work, safe to call exported symbols at
  interrupt context.
- Remove the repeated psr delay work in vop driver.

Changes in v4:
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)

[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]

Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

 drivers/gpu/drm/rockchip/Makefile   |   2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
 drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 249 
 drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  26 +++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |   9 +
 7 files changed, 303 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index a822d49..b43fe5d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev)
 
drm_dev->dev_private = private;
 
+   INIT_LIST_HEAD(>psr_list);
+   mutex_init(>psr_list_mutex);
+
drm_mode_config_init(drm_dev);
 
rockchip_drm_mode_config_init(drm_dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 239b830..9c34c9e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -61,6 +61,9 @@ struct rockchip_drm_private {
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
struct drm_atomic_state *state;
+
+   struct list_head psr_list;
+   struct mutex psr_list_mutex;
 };
 
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 55c5273..ba45d9d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -22,6 +22,7 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
+#include "rockchip_drm_psr.h"
 
 #define to_rockchip_fb

[PATCH v5 0/4] Add PSR function support for Analogix/Rockchip DP

2016-07-24 Thread Yakir Yang

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make a lots
of sense to save the power consumption.

The v5 version have made the psr_set_state() to a delay work, which is
the biggest changes from v4.

The v3 version have splited an common PSR driver for Rockchip, which is
biggest changes from v2.

This thread is based on Mark's RK3399 VOP thread[0].

[0]: https://patchwork.kernel.org/patch/8886041/


Changes in v5:
- Add reviewed flag from Sean.
- Only keep 'psr_list_mutex' at register/unregister time.
- Remove unused global variables.
- Make list traversal safely at rockchip_drm_psr_unregister().
- Make psr_set_state() to a delay work, safe to call exported symbols at
  interrupt context.
- Remove the repeated psr delay work in vop driver.
- Add reviewed flag from Sean.
- Add reviewed flag from Sean.

Changes in v4.1:
- Remove the completion_done() check in irq handler (Sean)
- Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean)
- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)

[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)

[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments
- split the common psr logic into a seperate driver, make this to a
  simple sub-psr device driver.

Changes in v2:
- Introduce in v2, split VOP line flag changes out
- introduce in v2, splite the common Analogix DP changes out
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

Yakir Yang (4):
  drm/rockchip: vop: export line flag function
  drm/rockchip: add an common abstracted PSR driver
  drm/bridge: analogix_dp: add the PSR function support
  drm/rockchip: analogix_dp: implement PSR function

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  81 +++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   5 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  |  51 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  |  34 +++
 drivers/gpu/drm/rockchip/Makefile  |   2 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c|  57 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c|   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h|   6 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c |  12 +
 drivers/gpu/drm/rockchip/rockchip_drm_psr.c| 249 +
 drivers/gpu/drm/roc

[PATCH v5 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-24 Thread Yakir Yang
The PSR driver have exported four symbols for specific device driver, and
it's safe to call them in interrupt context:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.

Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang 
---
Changes in v5:
- Only keep 'psr_list_mutex' at register/unregister time.
- Remove unused global variables.
- Make list traversal safely at rockchip_drm_psr_unregister().
- Make psr_set_state() to a delay work, safe to call exported symbols at
  interrupt context.
- Remove the repeated psr delay work in vop driver.

Changes in v4:
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)

[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]

Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

 drivers/gpu/drm/rockchip/Makefile   |   2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
 drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 249 
 drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  26 +++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |   9 +
 7 files changed, 303 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index a822d49..b43fe5d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev)
 
drm_dev->dev_private = private;
 
+   INIT_LIST_HEAD(>psr_list);
+   mutex_init(>psr_list_mutex);
+
drm_mode_config_init(drm_dev);
 
rockchip_drm_mode_config_init(drm_dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 239b830..9c34c9e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -61,6 +61,9 @@ struct rockchip_drm_private {
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
struct drm_atomic_state *state;
+
+   struct list_head psr_list;
+   struct mutex psr_list_mutex;
 };
 
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 55c5273..ba45d9d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -22,6 +22,7 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
+#include "rockchip_drm_psr.h"
 
 #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
 
@@ -63,9 +6

[PATCH v5 0/4] Add PSR function support for Analogix/Rockchip DP

2016-07-24 Thread Yakir Yang

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make a lots
of sense to save the power consumption.

The v5 version have made the psr_set_state() to a delay work, which is
the biggest changes from v4.

The v3 version have splited an common PSR driver for Rockchip, which is
biggest changes from v2.

This thread is based on Mark's RK3399 VOP thread[0].

[0]: https://patchwork.kernel.org/patch/8886041/


Changes in v5:
- Add reviewed flag from Sean.
- Only keep 'psr_list_mutex' at register/unregister time.
- Remove unused global variables.
- Make list traversal safely at rockchip_drm_psr_unregister().
- Make psr_set_state() to a delay work, safe to call exported symbols at
  interrupt context.
- Remove the repeated psr delay work in vop driver.
- Add reviewed flag from Sean.
- Add reviewed flag from Sean.

Changes in v4.1:
- Remove the completion_done() check in irq handler (Sean)
- Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean)
- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)

[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)

[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments
- split the common psr logic into a seperate driver, make this to a
  simple sub-psr device driver.

Changes in v2:
- Introduce in v2, split VOP line flag changes out
- introduce in v2, splite the common Analogix DP changes out
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

Yakir Yang (4):
  drm/rockchip: vop: export line flag function
  drm/rockchip: add an common abstracted PSR driver
  drm/bridge: analogix_dp: add the PSR function support
  drm/rockchip: analogix_dp: implement PSR function

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  81 +++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   5 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  |  51 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  |  34 +++
 drivers/gpu/drm/rockchip/Makefile  |   2 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c|  57 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c|   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h|   6 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c |  12 +
 drivers/gpu/drm/rockchip/rockchip_drm_psr.c| 249 +
 drivers/gpu/drm/roc

[PATCH v5 4/4] drm/rockchip: analogix_dp: implement PSR function

2016-07-24 Thread Yakir Yang
Alway enable the PSR function for Rockchip analogix_dp driver. If panel
don't support PSR, then the core analogix_dp would ignore this setting.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
Reviewed-by: Sean Paul <seanp...@chromium.org>
---
Changes in v5:
- Add reviewed flag from Sean.

Changes in v4:
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)

[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- split the common psr logic into a seperate driver, make this to a
  simple sub-psr device driver.

Changes in v2:
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 +
 1 file changed, 57 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c 
b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index e81e19a..aa916f4 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -32,6 +32,7 @@
 #include 
 
 #include "rockchip_drm_drv.h"
+#include "rockchip_drm_psr.h"
 #include "rockchip_drm_vop.h"
 
 #define RK3288_GRF_SOC_CON60x25c
@@ -41,6 +42,9 @@
 
 #define HIWORD_UPDATE(val, mask)   (val | (mask) << 16)
 
+#define PSR_SET_DELAY_TIME msecs_to_jiffies(10)
+#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS  100
+
 #define to_dp(nm)  container_of(nm, struct rockchip_dp_device, nm)
 
 /**
@@ -68,11 +72,55 @@ struct rockchip_dp_device {
struct regmap*grf;
struct reset_control *rst;
 
+   struct delayed_work  psr_work;
+   unsigned int psr_state;
+
const struct rockchip_dp_chip_data *data;
 
struct analogix_dp_plat_data plat_data;
 };
 
+static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
+{
+   struct rockchip_dp_device *dp = to_dp(encoder);
+
+   dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
+
+   if (enabled)
+   dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
+   else
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+
+   schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME);
+}
+
+static void analogix_dp_psr_work(struct work_struct *work)
+{
+   struct rockchip_dp_device *dp =
+   container_of(work, typeof(*dp), psr_work.work);
+   struct drm_crtc *crtc = dp->encoder.crtc;
+   int psr_state = dp->psr_state;
+   int vact_end;
+   int ret;
+
+   if (!crtc)
+   return;
+
+   vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + 
crtc->mode.vdisplay;
+
+   ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end,
+ PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
+   if (ret) {
+   dev_err(dp->dev, "line flag interrupt did not arrive\n");
+   return;
+   }
+
+   if (psr_state == EDP_VSC_PSR_STATE_ACTIVE)
+   analogix_dp_enable_psr(dp->dev);
+   else
+   analogix_dp_disable_psr(dp->dev);
+}
+
 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
 {
reset_control_assert(dp->rst);
@@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct 
device *master,
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
 
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+   INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work);
+
+   rockchip_drm_psr_register(>encoder, analogix_dp_psr_set);
+
return analogix_dp_bind(dev, dp->drm_dev, >plat_data);
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
   void *data)
 {
+   struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+   rockchip_drm_psr_unregister(>encoder);
+
return analogix_dp_unbind(dev, master, data);
 }
 
-- 
1.9.1




[PATCH v5 4/4] drm/rockchip: analogix_dp: implement PSR function

2016-07-24 Thread Yakir Yang
Alway enable the PSR function for Rockchip analogix_dp driver. If panel
don't support PSR, then the core analogix_dp would ignore this setting.

Signed-off-by: Yakir Yang 
Reviewed-by: Sean Paul 
---
Changes in v5:
- Add reviewed flag from Sean.

Changes in v4:
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)

[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- split the common psr logic into a seperate driver, make this to a
  simple sub-psr device driver.

Changes in v2:
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 +
 1 file changed, 57 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c 
b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index e81e19a..aa916f4 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -32,6 +32,7 @@
 #include 
 
 #include "rockchip_drm_drv.h"
+#include "rockchip_drm_psr.h"
 #include "rockchip_drm_vop.h"
 
 #define RK3288_GRF_SOC_CON60x25c
@@ -41,6 +42,9 @@
 
 #define HIWORD_UPDATE(val, mask)   (val | (mask) << 16)
 
+#define PSR_SET_DELAY_TIME msecs_to_jiffies(10)
+#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS  100
+
 #define to_dp(nm)  container_of(nm, struct rockchip_dp_device, nm)
 
 /**
@@ -68,11 +72,55 @@ struct rockchip_dp_device {
struct regmap*grf;
struct reset_control *rst;
 
+   struct delayed_work  psr_work;
+   unsigned int psr_state;
+
const struct rockchip_dp_chip_data *data;
 
struct analogix_dp_plat_data plat_data;
 };
 
+static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
+{
+   struct rockchip_dp_device *dp = to_dp(encoder);
+
+   dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
+
+   if (enabled)
+   dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
+   else
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+
+   schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME);
+}
+
+static void analogix_dp_psr_work(struct work_struct *work)
+{
+   struct rockchip_dp_device *dp =
+   container_of(work, typeof(*dp), psr_work.work);
+   struct drm_crtc *crtc = dp->encoder.crtc;
+   int psr_state = dp->psr_state;
+   int vact_end;
+   int ret;
+
+   if (!crtc)
+   return;
+
+   vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + 
crtc->mode.vdisplay;
+
+   ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end,
+ PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
+   if (ret) {
+   dev_err(dp->dev, "line flag interrupt did not arrive\n");
+   return;
+   }
+
+   if (psr_state == EDP_VSC_PSR_STATE_ACTIVE)
+   analogix_dp_enable_psr(dp->dev);
+   else
+   analogix_dp_disable_psr(dp->dev);
+}
+
 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
 {
reset_control_assert(dp->rst);
@@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct 
device *master,
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
 
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+   INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work);
+
+   rockchip_drm_psr_register(>encoder, analogix_dp_psr_set);
+
return analogix_dp_bind(dev, dp->drm_dev, >plat_data);
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
   void *data)
 {
+   struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+   rockchip_drm_psr_unregister(>encoder);
+
return analogix_dp_unbind(dev, master, data);
 }
 
-- 
1.9.1




[PATCH v2 2/3] drm/bridge: analogix_dp: turn off the panel when eDP need to disable

2016-07-21 Thread Yakir Yang
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP
controller stop to send valid video signal, otherwhise panel would
go burn in, and keep flicker and flicker.

So it's better to turn off the panel when eDP need to disable, and
we need to turn on the panel in connector->detect() callback, so
that driver would detect panel status rightly.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v2:
- s/Panle/Panel/ (Sean)
- Move the drm_panel_ out of a conditional, and throw the return
  code away (Sean)
- Add comments about why we need unprepare the panel in bridge_disable (Sean)
- Unprepare the panel at the end of bridge->disable() function.

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 37 --
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..0ddaf93 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -960,6 +960,17 @@ enum drm_connector_status
 analogix_dp_detect(struct drm_connector *connector, bool force)
 {
struct analogix_dp_device *dp = to_dp(connector);
+   int ret;
+
+   /*
+* Panel would prepare for several times here, but don't worry, it
+* would only enable the hardware at the first prepare time.
+*/
+   if (dp->plat_data->panel) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }
 
if (analogix_dp_detect_hpd(dp))
return connector_status_disconnected;
@@ -1058,13 +1069,15 @@ static void analogix_dp_bridge_enable(struct drm_bridge 
*bridge)
 static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 {
struct analogix_dp_device *dp = bridge->driver_private;
+   int ret;
 
if (dp->dpms_mode != DRM_MODE_DPMS_ON)
return;
 
if (dp->plat_data->panel) {
-   if (drm_panel_disable(dp->plat_data->panel)) {
-   DRM_ERROR("failed to disable the panel\n");
+   ret = drm_panel_disable(dp->plat_data->panel);
+   if (ret) {
+   DRM_ERROR("failed to disable the panel [%d]\n", ret);
return;
}
}
@@ -1077,6 +1090,19 @@ static void analogix_dp_bridge_disable(struct drm_bridge 
*bridge)
 
pm_runtime_put_sync(dp->dev);
 
+   /*
+* Some panels need to be turn off when eDP controller stop to send
+* valid video signal, otherwhise panel would go burn in, and keep
+* flicker and flicker.
+*/
+   if (dp->plat_data->panel) {
+ret = drm_panel_unprepare(dp->plat_data->panel);
+if (ret) {
+   DRM_ERROR("failed to turnoff the panel [%d]\n", ret);
+   return;
+   }
+   }
+
dp->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
@@ -1333,13 +1359,6 @@ int analogix_dp_bind(struct device *dev, struct 
drm_device *drm_dev,
 
phy_power_on(dp->phy);
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
analogix_dp_init_dp(dp);
 
ret = devm_request_threaded_irq(>dev, dp->irq,
-- 
1.9.1




[PATCH v2 3/3] drm/bridge: analogix_dp: remove the panel prepare/unprepare in suspend/resume

2016-07-21 Thread Yakir Yang
We already manager the panel power status in bridge_disable and
connector->detect functions, then we don't need to manager the
panel power status at suspend/resume in particular.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 12 
 1 file changed, 12 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 0ddaf93..3dadad2 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1413,11 +1413,6 @@ int analogix_dp_suspend(struct device *dev)
 
clk_disable_unprepare(dp->clock);
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_unprepare(dp->plat_data->panel))
-   DRM_ERROR("failed to turnoff the panel\n");
-   }
-
return 0;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_suspend);
@@ -1433,13 +1428,6 @@ int analogix_dp_resume(struct device *dev)
return ret;
}
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
return 0;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_resume);
-- 
1.9.1




[PATCH v2 2/3] drm/bridge: analogix_dp: turn off the panel when eDP need to disable

2016-07-21 Thread Yakir Yang
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP
controller stop to send valid video signal, otherwhise panel would
go burn in, and keep flicker and flicker.

So it's better to turn off the panel when eDP need to disable, and
we need to turn on the panel in connector->detect() callback, so
that driver would detect panel status rightly.

Signed-off-by: Yakir Yang 
---
Changes in v2:
- s/Panle/Panel/ (Sean)
- Move the drm_panel_ out of a conditional, and throw the return
  code away (Sean)
- Add comments about why we need unprepare the panel in bridge_disable (Sean)
- Unprepare the panel at the end of bridge->disable() function.

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 37 --
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..0ddaf93 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -960,6 +960,17 @@ enum drm_connector_status
 analogix_dp_detect(struct drm_connector *connector, bool force)
 {
struct analogix_dp_device *dp = to_dp(connector);
+   int ret;
+
+   /*
+* Panel would prepare for several times here, but don't worry, it
+* would only enable the hardware at the first prepare time.
+*/
+   if (dp->plat_data->panel) {
+   ret = drm_panel_prepare(dp->plat_data->panel);
+   if (ret)
+   DRM_ERROR("failed to setup the panel ret = %d\n", ret);
+   }
 
if (analogix_dp_detect_hpd(dp))
return connector_status_disconnected;
@@ -1058,13 +1069,15 @@ static void analogix_dp_bridge_enable(struct drm_bridge 
*bridge)
 static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 {
struct analogix_dp_device *dp = bridge->driver_private;
+   int ret;
 
if (dp->dpms_mode != DRM_MODE_DPMS_ON)
return;
 
if (dp->plat_data->panel) {
-   if (drm_panel_disable(dp->plat_data->panel)) {
-   DRM_ERROR("failed to disable the panel\n");
+   ret = drm_panel_disable(dp->plat_data->panel);
+   if (ret) {
+   DRM_ERROR("failed to disable the panel [%d]\n", ret);
return;
}
}
@@ -1077,6 +1090,19 @@ static void analogix_dp_bridge_disable(struct drm_bridge 
*bridge)
 
pm_runtime_put_sync(dp->dev);
 
+   /*
+* Some panels need to be turn off when eDP controller stop to send
+* valid video signal, otherwhise panel would go burn in, and keep
+* flicker and flicker.
+*/
+   if (dp->plat_data->panel) {
+ret = drm_panel_unprepare(dp->plat_data->panel);
+if (ret) {
+   DRM_ERROR("failed to turnoff the panel [%d]\n", ret);
+   return;
+   }
+   }
+
dp->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
@@ -1333,13 +1359,6 @@ int analogix_dp_bind(struct device *dev, struct 
drm_device *drm_dev,
 
phy_power_on(dp->phy);
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
analogix_dp_init_dp(dp);
 
ret = devm_request_threaded_irq(>dev, dp->irq,
-- 
1.9.1




[PATCH v2 3/3] drm/bridge: analogix_dp: remove the panel prepare/unprepare in suspend/resume

2016-07-21 Thread Yakir Yang
We already manager the panel power status in bridge_disable and
connector->detect functions, then we don't need to manager the
panel power status at suspend/resume in particular.

Signed-off-by: Yakir Yang 
---
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 12 
 1 file changed, 12 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 0ddaf93..3dadad2 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1413,11 +1413,6 @@ int analogix_dp_suspend(struct device *dev)
 
clk_disable_unprepare(dp->clock);
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_unprepare(dp->plat_data->panel))
-   DRM_ERROR("failed to turnoff the panel\n");
-   }
-
return 0;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_suspend);
@@ -1433,13 +1428,6 @@ int analogix_dp_resume(struct device *dev)
return ret;
}
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
return 0;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_resume);
-- 
1.9.1




[PATCH v2 1/3] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31

2016-07-21 Thread Yakir Yang
According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the
missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus
t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and
panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~).

Signed-off-by: Yakir Yang <y...@rock-chips.com>
Reviewed-by: Sean Paul <seanp...@chromium.org>
---
Changes in v2:
- Add the reviewed tag from Sean.

 drivers/gpu/drm/panel/panel-simple.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c 
b/drivers/gpu/drm/panel/panel-simple.c
index 85143d1..f178998 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = {
.width = 259,
.height = 173,
},
+   .delay = {
+   .prepare = 110,
+   .enable = 50,
+   .unprepare = 550,
+   },
 };
 
 static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
-- 
1.9.1




[PATCH v2 1/3] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31

2016-07-21 Thread Yakir Yang
According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the
missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus
t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and
panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~).

Signed-off-by: Yakir Yang 
Reviewed-by: Sean Paul 
---
Changes in v2:
- Add the reviewed tag from Sean.

 drivers/gpu/drm/panel/panel-simple.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c 
b/drivers/gpu/drm/panel/panel-simple.c
index 85143d1..f178998 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = {
.width = 259,
.height = 173,
},
+   .delay = {
+   .prepare = 110,
+   .enable = 50,
+   .unprepare = 550,
+   },
 };
 
 static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
-- 
1.9.1




Re: [PATCH v1 1/2] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31

2016-07-21 Thread Yakir Yang

Sean,

On 07/21/2016 10:30 PM, Sean Paul wrote:

On Thu, Jul 21, 2016 at 9:14 AM, Yakir Yang <y...@rock-chips.com> wrote:

According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the
missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus
t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and
panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~).

Signed-off-by: Yakir Yang <y...@rock-chips.com>

Reviewed-by: Sean Paul <seanp...@chromium.org>


Thanks  :-D

- Yakir


---
  drivers/gpu/drm/panel/panel-simple.c | 5 +
  1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c 
b/drivers/gpu/drm/panel/panel-simple.c
index 85143d1..f178998 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = {
 .width = 259,
 .height = 173,
 },
+   .delay = {
+   .prepare = 110,
+   .enable = 50,
+   .unprepare = 550,
+   },
  };

  static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
--
1.9.1










Re: [PATCH v1 1/2] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31

2016-07-21 Thread Yakir Yang

Sean,

On 07/21/2016 10:30 PM, Sean Paul wrote:

On Thu, Jul 21, 2016 at 9:14 AM, Yakir Yang  wrote:

According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the
missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus
t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and
panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~).

Signed-off-by: Yakir Yang 

Reviewed-by: Sean Paul 


Thanks  :-D

- Yakir


---
  drivers/gpu/drm/panel/panel-simple.c | 5 +
  1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c 
b/drivers/gpu/drm/panel/panel-simple.c
index 85143d1..f178998 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = {
 .width = 259,
 .height = 173,
 },
+   .delay = {
+   .prepare = 110,
+   .enable = 50,
+   .unprepare = 550,
+   },
  };

  static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
--
1.9.1










[PATCH v1.1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable

2016-07-21 Thread Yakir Yang
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP
controller stop to send valid video signal, otherwhise panel would
go burn in, and keep flicker and flicker.

So it's better to turn off the panel when eDP need to disable, and
we need to turn on the panel in connector->detect() callback, so
that driver would detect panel status rightly.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---

Changes in v1.1:
- unprepare the panel at the end of bridge->disable() function

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 22 +++---
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..2e519bd 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool 
force)
 {
struct analogix_dp_device *dp = to_dp(connector);
 
+   /*
+* Panle would prepare for several times here, but don't worry it
+* would only enable the hardware at the first prepare time.
+*/
+   if (dp->plat_data->panel)
+   if (drm_panel_prepare(dp->plat_data->panel))
+   DRM_ERROR("failed to setup the panel\n");
+
if (analogix_dp_detect_hpd(dp))
return connector_status_disconnected;
 
@@ -1077,6 +1085,13 @@ static void analogix_dp_bridge_disable(struct drm_bridge 
*bridge)
 
pm_runtime_put_sync(dp->dev);
 
+   if (dp->plat_data->panel) {
+   if (drm_panel_unprepare(dp->plat_data->panel)) {
+   DRM_ERROR("failed to turnoff the panel\n");
+   return;
+   }
+   }
+
dp->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
@@ -1333,13 +1348,6 @@ int analogix_dp_bind(struct device *dev, struct 
drm_device *drm_dev,
 
phy_power_on(dp->phy);
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
analogix_dp_init_dp(dp);
 
ret = devm_request_threaded_irq(>dev, dp->irq,
-- 
1.9.1




[PATCH v1.1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable

2016-07-21 Thread Yakir Yang
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP
controller stop to send valid video signal, otherwhise panel would
go burn in, and keep flicker and flicker.

So it's better to turn off the panel when eDP need to disable, and
we need to turn on the panel in connector->detect() callback, so
that driver would detect panel status rightly.

Signed-off-by: Yakir Yang 
---

Changes in v1.1:
- unprepare the panel at the end of bridge->disable() function

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 22 +++---
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..2e519bd 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool 
force)
 {
struct analogix_dp_device *dp = to_dp(connector);
 
+   /*
+* Panle would prepare for several times here, but don't worry it
+* would only enable the hardware at the first prepare time.
+*/
+   if (dp->plat_data->panel)
+   if (drm_panel_prepare(dp->plat_data->panel))
+   DRM_ERROR("failed to setup the panel\n");
+
if (analogix_dp_detect_hpd(dp))
return connector_status_disconnected;
 
@@ -1077,6 +1085,13 @@ static void analogix_dp_bridge_disable(struct drm_bridge 
*bridge)
 
pm_runtime_put_sync(dp->dev);
 
+   if (dp->plat_data->panel) {
+   if (drm_panel_unprepare(dp->plat_data->panel)) {
+   DRM_ERROR("failed to turnoff the panel\n");
+   return;
+   }
+   }
+
dp->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
@@ -1333,13 +1348,6 @@ int analogix_dp_bind(struct device *dev, struct 
drm_device *drm_dev,
 
phy_power_on(dp->phy);
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
analogix_dp_init_dp(dp);
 
ret = devm_request_threaded_irq(>dev, dp->irq,
-- 
1.9.1




[PATCH v1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable

2016-07-21 Thread Yakir Yang
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP
controller stop to send valid video signal, otherwhise panel would
go burn in, and keep flicker and flicker.

So it's better to turn off the panel when eDP need to disable, and
we need to turn on the panel in connector->detect() callback, so
that driver would detect panel status rightly.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 18 ++
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..ea059b3 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool 
force)
 {
struct analogix_dp_device *dp = to_dp(connector);
 
+   /*
+* Panle would prepare for several times here, but don't worry it
+* would only enable the hardware at the first prepare time.
+*/
+   if (dp->plat_data->panel)
+   if (drm_panel_prepare(dp->plat_data->panel))
+   DRM_ERROR("failed to setup the panel\n");
+
if (analogix_dp_detect_hpd(dp))
return connector_status_disconnected;
 
@@ -1063,7 +1071,8 @@ static void analogix_dp_bridge_disable(struct drm_bridge 
*bridge)
return;
 
if (dp->plat_data->panel) {
-   if (drm_panel_disable(dp->plat_data->panel)) {
+   if (drm_panel_disable(dp->plat_data->panel) ||
+   drm_panel_unprepare(dp->plat_data->panel)) {
DRM_ERROR("failed to disable the panel\n");
return;
}
@@ -1333,13 +1342,6 @@ int analogix_dp_bind(struct device *dev, struct 
drm_device *drm_dev,
 
phy_power_on(dp->phy);
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
analogix_dp_init_dp(dp);
 
ret = devm_request_threaded_irq(>dev, dp->irq,
-- 
1.9.1




[PATCH v1 2/2] drm/bridge: analogix_dp: turn off the panel when eDP need to disable

2016-07-21 Thread Yakir Yang
Some panels (like Sharp LQ123P1JX31) need to be turn off when eDP
controller stop to send valid video signal, otherwhise panel would
go burn in, and keep flicker and flicker.

So it's better to turn off the panel when eDP need to disable, and
we need to turn on the panel in connector->detect() callback, so
that driver would detect panel status rightly.

Signed-off-by: Yakir Yang 
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 18 ++
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..ea059b3 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -961,6 +961,14 @@ analogix_dp_detect(struct drm_connector *connector, bool 
force)
 {
struct analogix_dp_device *dp = to_dp(connector);
 
+   /*
+* Panle would prepare for several times here, but don't worry it
+* would only enable the hardware at the first prepare time.
+*/
+   if (dp->plat_data->panel)
+   if (drm_panel_prepare(dp->plat_data->panel))
+   DRM_ERROR("failed to setup the panel\n");
+
if (analogix_dp_detect_hpd(dp))
return connector_status_disconnected;
 
@@ -1063,7 +1071,8 @@ static void analogix_dp_bridge_disable(struct drm_bridge 
*bridge)
return;
 
if (dp->plat_data->panel) {
-   if (drm_panel_disable(dp->plat_data->panel)) {
+   if (drm_panel_disable(dp->plat_data->panel) ||
+   drm_panel_unprepare(dp->plat_data->panel)) {
DRM_ERROR("failed to disable the panel\n");
return;
}
@@ -1333,13 +1342,6 @@ int analogix_dp_bind(struct device *dev, struct 
drm_device *drm_dev,
 
phy_power_on(dp->phy);
 
-   if (dp->plat_data->panel) {
-   if (drm_panel_prepare(dp->plat_data->panel)) {
-   DRM_ERROR("failed to setup the panel\n");
-   return -EBUSY;
-   }
-   }
-
analogix_dp_init_dp(dp);
 
ret = devm_request_threaded_irq(>dev, dp->irq,
-- 
1.9.1




[PATCH v1 1/2] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31

2016-07-21 Thread Yakir Yang
According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the
missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus
t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and
panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~).

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
 drivers/gpu/drm/panel/panel-simple.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c 
b/drivers/gpu/drm/panel/panel-simple.c
index 85143d1..f178998 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = {
.width = 259,
.height = 173,
},
+   .delay = {
+   .prepare = 110,
+   .enable = 50,
+   .unprepare = 550,
+   },
 };
 
 static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
-- 
1.9.1




[PATCH v1 1/2] drm/panel: simple-panel: add the delay timing for Sharp LQ123P1JX31

2016-07-21 Thread Yakir Yang
According to page 16 of Sharp LQ123P1JX31 datasheet, we need to add the
missing delay timing. Panel prepare time should be t1 (0.5ms~10ms) plus
t3 (0ms~100ms), and panel enable time should equal to t7 (0ms~50ms), and
panel unprepare time should be t11 (1ms~50ms) plus t12 (500ms~).

Signed-off-by: Yakir Yang 
---
 drivers/gpu/drm/panel/panel-simple.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c 
b/drivers/gpu/drm/panel/panel-simple.c
index 85143d1..f178998 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1384,6 +1384,11 @@ static const struct panel_desc sharp_lq123p1jx31 = {
.width = 259,
.height = 173,
},
+   .delay = {
+   .prepare = 110,
+   .enable = 50,
+   .unprepare = 550,
+   },
 };
 
 static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
-- 
1.9.1




Re: [PATCH v3 1/6] dt-bindings: add LG LP097QX1-SPA1 panel binding

2016-07-18 Thread Yakir Yang

Thierry,

On 07/08/2016 05:57 AM, Thierry Reding wrote:

On Thu, Jul 07, 2016 at 11:55:23PM +0200, Thierry Reding wrote:

On Sun, Jun 12, 2016 at 10:53:30AM +0800, Yakir Yang wrote:

The LG LP097QX1-SPA1 is an 9.7", 2048x1536 (QXGA) TFT-LCD panel
connected using eDP interfaces.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
Acked-by: Rob Herring <r...@kernel.org>
---
Changes in v3: None
Changes in v2:
- Add Rob's acked for dt-bindings of LG LP097QX1-SPA1 panel

  .../devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt | 7 +++
  1 file changed, 7 insertions(+)
  create mode 100644 
Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt

Applied all six patches, though I modified 3/6 as Doug suggested.

I mean patch 4/6, of course.


Wow, good news, thanks a lot :-D

- Yakir


Thierry





Re: [PATCH v3 1/6] dt-bindings: add LG LP097QX1-SPA1 panel binding

2016-07-18 Thread Yakir Yang

Thierry,

On 07/08/2016 05:57 AM, Thierry Reding wrote:

On Thu, Jul 07, 2016 at 11:55:23PM +0200, Thierry Reding wrote:

On Sun, Jun 12, 2016 at 10:53:30AM +0800, Yakir Yang wrote:

The LG LP097QX1-SPA1 is an 9.7", 2048x1536 (QXGA) TFT-LCD panel
connected using eDP interfaces.

Signed-off-by: Yakir Yang 
Acked-by: Rob Herring 
---
Changes in v3: None
Changes in v2:
- Add Rob's acked for dt-bindings of LG LP097QX1-SPA1 panel

  .../devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt | 7 +++
  1 file changed, 7 insertions(+)
  create mode 100644 
Documentation/devicetree/bindings/display/panel/lg,lp097qx1-spa1.txt

Applied all six patches, though I modified 3/6 as Doug suggested.

I mean patch 4/6, of course.


Wow, good news, thanks a lot :-D

- Yakir


Thierry





Re: [PATCH v4.1 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-07-15 Thread Yakir Yang

Sean,

On 07/15/2016 09:13 PM, Sean Paul wrote:

On Fri, Jul 15, 2016 at 06:55:17PM +0800, Yakir Yang wrote:

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()

Signed-off-by: Yakir Yang <y...@rock-chips.com>

Reviewed-by: Sean Paul <seanp...@chromium.org>


Thanks for your reviewed  :-D

- Yakir




---
Changes in v4.1:
- Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean)
- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
 analogix_dp_detect_sink_psr()
 analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 51 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 34 +
  include/drm/bridge/analogix_dp.h   |  3 +
  5 files changed, 174 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..381b25e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device 
*dp)
return 0;
  }
  
+int analogix_dp_enable_psr(struct device *dev)

+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = 0;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_version;
+
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+   dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+   return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_en;
+
+   /* Disable psr function */
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+   psr_en &= ~DP_PSR_ENABLE;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Main-Link transmitter remains active during PSR active states */
+   psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Enable psr function */
+   psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   analogix_dp_enable_psr_crc(dp);
+}
+
  static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
  {
int i;
@@ -921,6 +998,10 @@ static void analogix_dp_c

Re: [PATCH v4.1 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-07-15 Thread Yakir Yang

Sean,

On 07/15/2016 09:13 PM, Sean Paul wrote:

On Fri, Jul 15, 2016 at 06:55:17PM +0800, Yakir Yang wrote:

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()

Signed-off-by: Yakir Yang 

Reviewed-by: Sean Paul 


Thanks for your reviewed  :-D

- Yakir




---
Changes in v4.1:
- Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean)
- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
 analogix_dp_detect_sink_psr()
 analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 51 ++
  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 34 +
  include/drm/bridge/analogix_dp.h   |  3 +
  5 files changed, 174 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..381b25e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device 
*dp)
return 0;
  }
  
+int analogix_dp_enable_psr(struct device *dev)

+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = 0;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_version;
+
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+   dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+   return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_en;
+
+   /* Disable psr function */
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+   psr_en &= ~DP_PSR_ENABLE;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Main-Link transmitter remains active during PSR active states */
+   psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Enable psr function */
+   psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   analogix_dp_enable_psr_crc(dp);
+}
+
  static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
  {
int i;
@@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device 
*dp)
  
  	/* Enable video */

analogi

Re: [PATCH v4.1 1/4] drm/rockchip: vop: export line flag function

2016-07-15 Thread Yakir Yang

Sean,

On 07/15/2016 09:04 PM, Sean Paul wrote:

On Fri, Jul 15, 2016 at 6:55 AM, Yakir Yang <y...@rock-chips.com> wrote:

VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang <y...@rock-chips.com>


Thanks for the update.

Reviewed-by: Sean Paul <seanp...@chromium.org>


Thanks for your reviewed  :-D

- Yakir


---
Changes in v4.1:
- Remove the completion_done() check in irq handler (Sean)

Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 
  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
  drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
  4 files changed, 126 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
struct device *dev);
  void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
 struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
  #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index c8a62a8..8a4f36e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
 /* protected by dev->event_lock */
 struct drm_pending_vblank_event *event;

+   struct completion line_flag_completion;
+
 const struct vop_data *data;

 uint32_t *regsbak;
@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
 spin_unlock_irqrestore(>irq_lock, flags);
  }

+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);

Re: [PATCH v4.1 1/4] drm/rockchip: vop: export line flag function

2016-07-15 Thread Yakir Yang

Sean,

On 07/15/2016 09:04 PM, Sean Paul wrote:

On Fri, Jul 15, 2016 at 6:55 AM, Yakir Yang  wrote:

VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang 


Thanks for the update.

Reviewed-by: Sean Paul 


Thanks for your reviewed  :-D

- Yakir


---
Changes in v4.1:
- Remove the completion_done() check in irq handler (Sean)

Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 
  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
  drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
  4 files changed, 126 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
struct device *dev);
  void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
 struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
  #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index c8a62a8..8a4f36e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
 /* protected by dev->event_lock */
 struct drm_pending_vblank_event *event;

+   struct completion line_flag_completion;
+
 const struct vop_data *data;

 uint32_t *regsbak;
@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
 spin_unlock_irqrestore(>irq_lock, flags);
  }

+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+   unsigned long flag

[PATCH v4.1 1/4] drm/rockchip: vop: export line flag function

2016-07-15 Thread Yakir Yang
VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v4.1:
- Remove the completion_done() check in irq handler (Sean)

Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
 4 files changed, 126 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index c8a62a8..8a4f36e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
/* protected by dev->event_lock */
struct drm_pending_vblank_event *event;
 
+   struct completion line_flag_completion;
+
const struct vop_data *data;
 
uint32_t *regsbak;
@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(>irq_lock, flags);
 }
 
+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0);
+
+   s

[PATCH v4.1 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-07-15 Thread Yakir Yang
The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v4.1:
- Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean)
- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 51 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 34 +
 include/drm/bridge/analogix_dp.h   |  3 +
 5 files changed, 174 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..381b25e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device 
*dp)
return 0;
 }
 
+int analogix_dp_enable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = 0;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_version;
+
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+   dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+   return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_en;
+
+   /* Disable psr function */
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+   psr_en &= ~DP_PSR_ENABLE;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Main-Link transmitter remains active during PSR active states */
+   psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Enable psr function */
+   psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   analogix_dp_enable_psr_crc(dp);
+}
+
 static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
 {
int i;
@@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device 
*dp)
 
/* Enable video */
analogix_dp_start_video(dp);
+
+   dp->psr_support = analogix_dp_detect_sink_psr(dp);
+   if (dp->psr_support)
+   analogix_dp_enable_sink_ps

[PATCH v4.1 1/4] drm/rockchip: vop: export line flag function

2016-07-15 Thread Yakir Yang
VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang 
---
Changes in v4.1:
- Remove the completion_done() check in irq handler (Sean)

Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 117 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
 4 files changed, 126 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index c8a62a8..8a4f36e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
/* protected by dev->event_lock */
struct drm_pending_vblank_event *event;
 
+   struct completion line_flag_completion;
+
const struct vop_data *data;
 
uint32_t *regsbak;
@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(>irq_lock, flags);
 }
 
+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0);
+
+   spin_unlock_irqrestore(>irq

[PATCH v4.1 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-07-15 Thread Yakir Yang
The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()

Signed-off-by: Yakir Yang 
---
Changes in v4.1:
- Take use of existing edp_psr_vsc struct to swap HBx and DBx setting. (Sean)
- Remove PSR_VID_CRC_FLUSH setting analogix_dp_enable_psr_crc().
- Add comment about PBx magic numbers. (Sean)

Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 81 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 51 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 34 +
 include/drm/bridge/analogix_dp.h   |  3 +
 5 files changed, 174 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..381b25e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,83 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device 
*dp)
return 0;
 }
 
+int analogix_dp_enable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+   struct edp_vsc_psr psr_vsc;
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+   memset(_vsc, 0, sizeof(psr_vsc));
+   psr_vsc.sdp_header.HB0 = 0;
+   psr_vsc.sdp_header.HB1 = 0x7;
+   psr_vsc.sdp_header.HB2 = 0x2;
+   psr_vsc.sdp_header.HB3 = 0x8;
+
+   psr_vsc.DB0 = 0;
+   psr_vsc.DB1 = 0;
+
+   analogix_dp_send_psr_spd(dp, _vsc);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_version;
+
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+   dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+   return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_en;
+
+   /* Disable psr function */
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+   psr_en &= ~DP_PSR_ENABLE;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Main-Link transmitter remains active during PSR active states */
+   psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Enable psr function */
+   psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   analogix_dp_enable_psr_crc(dp);
+}
+
 static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
 {
int i;
@@ -921,6 +998,10 @@ static void analogix_dp_commit(struct analogix_dp_device 
*dp)
 
/* Enable video */
analogix_dp_start_video(dp);
+
+   dp->psr_support = analogix_dp_detect_sink_psr(dp);
+   if (dp->psr_support)
+   analogix_dp_enable_sink_psr(dp);
 }
 
 int analogix_dp_

Re: [PATCH v4 4/4] drm/rockchip: analogix_dp: implement PSR function

2016-07-14 Thread Yakir Yang

Sean,

On 07/14/2016 11:26 PM, Sean Paul wrote:

On Thu, Jul 14, 2016 at 12:15:58PM +0800, Yakir Yang wrote:

Alway enable the PSR function for Rockchip analogix_dp driver. If panel
don't support PSR, then the core analogix_dp would ignore this setting.

Signed-off-by: Yakir Yang <y...@rock-chips.com>

Reviewed-by: Sean Paul <seanp...@chromium.org>


Thanks :-D

- Yakir


---
Changes in v4:
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- split the common psr logic into a seperate driver, make this to a
   simple sub-psr device driver.

Changes in v2:
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 +
  1 file changed, 57 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c 
b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index e81e19a..aa916f4 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -32,6 +32,7 @@
  #include 
  
  #include "rockchip_drm_drv.h"

+#include "rockchip_drm_psr.h"
  #include "rockchip_drm_vop.h"
  
  #define RK3288_GRF_SOC_CON6		0x25c

@@ -41,6 +42,9 @@
  
  #define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)
  
+#define PSR_SET_DELAY_TIME		msecs_to_jiffies(10)

+#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS  100
+
  #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm)
  
  /**

@@ -68,11 +72,55 @@ struct rockchip_dp_device {
struct regmap*grf;
struct reset_control *rst;
  
+	struct delayed_work  psr_work;

+   unsigned int psr_state;
+
const struct rockchip_dp_chip_data *data;
  
  	struct analogix_dp_plat_data plat_data;

  };
  
+static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)

+{
+   struct rockchip_dp_device *dp = to_dp(encoder);
+
+   dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
+
+   if (enabled)
+   dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
+   else
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+
+   schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME);
+}
+
+static void analogix_dp_psr_work(struct work_struct *work)
+{
+   struct rockchip_dp_device *dp =
+   container_of(work, typeof(*dp), psr_work.work);
+   struct drm_crtc *crtc = dp->encoder.crtc;
+   int psr_state = dp->psr_state;
+   int vact_end;
+   int ret;
+
+   if (!crtc)
+   return;
+
+   vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + 
crtc->mode.vdisplay;
+
+   ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end,
+ PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
+   if (ret) {
+   dev_err(dp->dev, "line flag interrupt did not arrive\n");
+   return;
+   }
+
+   if (psr_state == EDP_VSC_PSR_STATE_ACTIVE)
+   analogix_dp_enable_psr(dp->dev);
+   else
+   analogix_dp_disable_psr(dp->dev);
+}
+
  static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
  {
reset_control_assert(dp->rst);
@@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct 
device *master,
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
  
+	dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;

+   INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work);
+
+   rockchip_drm_psr_register(>encoder, analogix_dp_psr_set);
+
return analogix_dp_bind(dev, dp->drm_dev, >plat_data);
  }
  
  static void rockchip_dp_unbind(struct device *dev, struct device *master,

   void *data)
  {
+   struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+   rockchip_drm_psr_unregister(>encoder);
+
return analogix_dp_unbind(dev, master, data);
  }
  
--

1.9.1


___
dri-devel mailing list
dri-de...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel








Re: [PATCH v4 4/4] drm/rockchip: analogix_dp: implement PSR function

2016-07-14 Thread Yakir Yang

Sean,

On 07/14/2016 11:26 PM, Sean Paul wrote:

On Thu, Jul 14, 2016 at 12:15:58PM +0800, Yakir Yang wrote:

Alway enable the PSR function for Rockchip analogix_dp driver. If panel
don't support PSR, then the core analogix_dp would ignore this setting.

Signed-off-by: Yakir Yang 

Reviewed-by: Sean Paul 


Thanks :-D

- Yakir


---
Changes in v4:
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- split the common psr logic into a seperate driver, make this to a
   simple sub-psr device driver.

Changes in v2:
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 +
  1 file changed, 57 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c 
b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index e81e19a..aa916f4 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -32,6 +32,7 @@
  #include 
  
  #include "rockchip_drm_drv.h"

+#include "rockchip_drm_psr.h"
  #include "rockchip_drm_vop.h"
  
  #define RK3288_GRF_SOC_CON6		0x25c

@@ -41,6 +42,9 @@
  
  #define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)
  
+#define PSR_SET_DELAY_TIME		msecs_to_jiffies(10)

+#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS  100
+
  #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm)
  
  /**

@@ -68,11 +72,55 @@ struct rockchip_dp_device {
struct regmap*grf;
struct reset_control *rst;
  
+	struct delayed_work  psr_work;

+   unsigned int psr_state;
+
const struct rockchip_dp_chip_data *data;
  
  	struct analogix_dp_plat_data plat_data;

  };
  
+static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)

+{
+   struct rockchip_dp_device *dp = to_dp(encoder);
+
+   dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
+
+   if (enabled)
+   dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
+   else
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+
+   schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME);
+}
+
+static void analogix_dp_psr_work(struct work_struct *work)
+{
+   struct rockchip_dp_device *dp =
+   container_of(work, typeof(*dp), psr_work.work);
+   struct drm_crtc *crtc = dp->encoder.crtc;
+   int psr_state = dp->psr_state;
+   int vact_end;
+   int ret;
+
+   if (!crtc)
+   return;
+
+   vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + 
crtc->mode.vdisplay;
+
+   ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end,
+ PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
+   if (ret) {
+   dev_err(dp->dev, "line flag interrupt did not arrive\n");
+   return;
+   }
+
+   if (psr_state == EDP_VSC_PSR_STATE_ACTIVE)
+   analogix_dp_enable_psr(dp->dev);
+   else
+   analogix_dp_disable_psr(dp->dev);
+}
+
  static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
  {
reset_control_assert(dp->rst);
@@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct 
device *master,
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
  
+	dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;

+   INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work);
+
+   rockchip_drm_psr_register(>encoder, analogix_dp_psr_set);
+
return analogix_dp_bind(dev, dp->drm_dev, >plat_data);
  }
  
  static void rockchip_dp_unbind(struct device *dev, struct device *master,

   void *data)
  {
+   struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+   rockchip_drm_psr_unregister(>encoder);
+
return analogix_dp_unbind(dev, master, data);
  }
  
--

1.9.1


___
dri-devel mailing list
dri-de...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel








Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-14 Thread Yakir Yang

Sean,

On 07/14/2016 11:14 PM, Sean Paul wrote:

On Thu, Jul 14, 2016 at 12:15:49PM +0800, Yakir Yang wrote:

The PSR driver have exported four symbols for specific device driver:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.

Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang <y...@rock-chips.com>


I still don't think it's a good idea to pull this out into a separate PSR
driver, but I suppose we can integrate it at a later time if it becomes
cumbersome.

Reviewed-by: Sean Paul <seanp...@chromium.org>


Thanks :-D

- Yakir




---
Changes in v4:
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)
 
[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]

Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

  drivers/gpu/drm/rockchip/Makefile   |   2 +-
  drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   4 +
  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
  drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 
  drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  26 
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  29 
  7 files changed, 298 insertions(+), 1 deletion(-)
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
  
  rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \

-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
  rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
  
  obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index d665fb0..26c12b3 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev)
  
  	drm_dev->dev_private = private;
  
+	INIT_LIST_HEAD(>psr_list);

+   mutex_init(>psr_list_mutex);
+
drm_mode_config_init(drm_dev);
  
  	rockchip_drm_mode_config_init(drm_dev);

@@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev)
  
  	if (is_support_iommu)

arm_iommu_release_mapping(mapping);
+
return 0;
  err_fbdev_fini:
rockchip_drm_fbdev_fini(drm_dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 239b830..9c34c9e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -61,6 +61,9 @@ struct rockchip_drm_private {
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
struct drm_atomic_state *state;
+
+   struct list_head psr_list;
+   struct mutex psr_list_mutex;
  };
  
  int rockchip_register_crtc_funcs(struct drm_crtc *crtc,

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 20f12bc..36afd9c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_d

Re: [PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-14 Thread Yakir Yang

Sean,

On 07/14/2016 11:14 PM, Sean Paul wrote:

On Thu, Jul 14, 2016 at 12:15:49PM +0800, Yakir Yang wrote:

The PSR driver have exported four symbols for specific device driver:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.

Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang 


I still don't think it's a good idea to pull this out into a separate PSR
driver, but I suppose we can integrate it at a later time if it becomes
cumbersome.

Reviewed-by: Sean Paul 


Thanks :-D

- Yakir




---
Changes in v4:
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)
 
[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]

Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

  drivers/gpu/drm/rockchip/Makefile   |   2 +-
  drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   4 +
  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
  drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 
  drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  26 
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  29 
  7 files changed, 298 insertions(+), 1 deletion(-)
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
  
  rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \

-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
  rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
  
  obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index d665fb0..26c12b3 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev)
  
  	drm_dev->dev_private = private;
  
+	INIT_LIST_HEAD(>psr_list);

+   mutex_init(>psr_list_mutex);
+
drm_mode_config_init(drm_dev);
  
  	rockchip_drm_mode_config_init(drm_dev);

@@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev)
  
  	if (is_support_iommu)

arm_iommu_release_mapping(mapping);
+
return 0;
  err_fbdev_fini:
rockchip_drm_fbdev_fini(drm_dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 239b830..9c34c9e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -61,6 +61,9 @@ struct rockchip_drm_private {
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
struct drm_atomic_state *state;
+
+   struct list_head psr_list;
+   struct mutex psr_list_mutex;
  };
  
  int rockchip_register_crtc_funcs(struct drm_crtc *crtc,

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 20f12bc..36afd9c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -21,6 +21,7 @@
  
  #include "rockchip_drm_drv.

Re: [PATCH v4 1/4] drm/rockchip: vop: export line flag function

2016-07-14 Thread Yakir Yang

Sean,

On 07/14/2016 10:46 PM, Sean Paul wrote:

On Thu, Jul 14, 2016 at 12:15:44PM +0800, Yakir Yang wrote:

VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 118 
  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
  drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
  4 files changed, 127 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
   struct device *dev);
  void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
  #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index c8a62a8..69d32f1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
/* protected by dev->event_lock */
struct drm_pending_vblank_event *event;
  
+	struct completion line_flag_completion;

+
const struct vop_data *data;
  
  	uint32_t *regsbak;

@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(>irq_lock, flags);
  }
  
+/*

+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+  

Re: [PATCH v4 1/4] drm/rockchip: vop: export line flag function

2016-07-14 Thread Yakir Yang

Sean,

On 07/14/2016 10:46 PM, Sean Paul wrote:

On Thu, Jul 14, 2016 at 12:15:44PM +0800, Yakir Yang wrote:

VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang 
---
Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)
 
[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 118 
  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
  drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
  4 files changed, 127 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
   struct device *dev);
  void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
  #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index c8a62a8..69d32f1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
/* protected by dev->event_lock */
struct drm_pending_vblank_event *event;
  
+	struct completion line_flag_completion;

+
const struct vop_data *data;
  
  	uint32_t *regsbak;

@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(>irq_lock, flags);
  }
  
+/*

+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0);
+

[PATCH v4 4/4] drm/rockchip: analogix_dp: implement PSR function

2016-07-13 Thread Yakir Yang
Alway enable the PSR function for Rockchip analogix_dp driver. If panel
don't support PSR, then the core analogix_dp would ignore this setting.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v4:
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)

[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- split the common psr logic into a seperate driver, make this to a
  simple sub-psr device driver.

Changes in v2:
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 +
 1 file changed, 57 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c 
b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index e81e19a..aa916f4 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -32,6 +32,7 @@
 #include 
 
 #include "rockchip_drm_drv.h"
+#include "rockchip_drm_psr.h"
 #include "rockchip_drm_vop.h"
 
 #define RK3288_GRF_SOC_CON60x25c
@@ -41,6 +42,9 @@
 
 #define HIWORD_UPDATE(val, mask)   (val | (mask) << 16)
 
+#define PSR_SET_DELAY_TIME msecs_to_jiffies(10)
+#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS  100
+
 #define to_dp(nm)  container_of(nm, struct rockchip_dp_device, nm)
 
 /**
@@ -68,11 +72,55 @@ struct rockchip_dp_device {
struct regmap*grf;
struct reset_control *rst;
 
+   struct delayed_work  psr_work;
+   unsigned int psr_state;
+
const struct rockchip_dp_chip_data *data;
 
struct analogix_dp_plat_data plat_data;
 };
 
+static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
+{
+   struct rockchip_dp_device *dp = to_dp(encoder);
+
+   dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
+
+   if (enabled)
+   dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
+   else
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+
+   schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME);
+}
+
+static void analogix_dp_psr_work(struct work_struct *work)
+{
+   struct rockchip_dp_device *dp =
+   container_of(work, typeof(*dp), psr_work.work);
+   struct drm_crtc *crtc = dp->encoder.crtc;
+   int psr_state = dp->psr_state;
+   int vact_end;
+   int ret;
+
+   if (!crtc)
+   return;
+
+   vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + 
crtc->mode.vdisplay;
+
+   ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end,
+ PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
+   if (ret) {
+   dev_err(dp->dev, "line flag interrupt did not arrive\n");
+   return;
+   }
+
+   if (psr_state == EDP_VSC_PSR_STATE_ACTIVE)
+   analogix_dp_enable_psr(dp->dev);
+   else
+   analogix_dp_disable_psr(dp->dev);
+}
+
 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
 {
reset_control_assert(dp->rst);
@@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct 
device *master,
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
 
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+   INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work);
+
+   rockchip_drm_psr_register(>encoder, analogix_dp_psr_set);
+
return analogix_dp_bind(dev, dp->drm_dev, >plat_data);
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
   void *data)
 {
+   struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+   rockchip_drm_psr_unregister(>encoder);
+
return analogix_dp_unbind(dev, master, data);
 }
 
-- 
1.9.1




[PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-13 Thread Yakir Yang
The PSR driver have exported four symbols for specific device driver:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.

Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v4:
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)

[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]

Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

 drivers/gpu/drm/rockchip/Makefile   |   2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   4 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
 drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 
 drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  26 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  29 
 7 files changed, 298 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index d665fb0..26c12b3 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev)
 
drm_dev->dev_private = private;
 
+   INIT_LIST_HEAD(>psr_list);
+   mutex_init(>psr_list_mutex);
+
drm_mode_config_init(drm_dev);
 
rockchip_drm_mode_config_init(drm_dev);
@@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev)
 
if (is_support_iommu)
arm_iommu_release_mapping(mapping);
+
return 0;
 err_fbdev_fini:
rockchip_drm_fbdev_fini(drm_dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 239b830..9c34c9e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -61,6 +61,9 @@ struct rockchip_drm_private {
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
struct drm_atomic_state *state;
+
+   struct list_head psr_list;
+   struct mutex psr_list_mutex;
 };
 
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 20f12bc..36afd9c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -21,6 +21,7 @@
 
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
+#include "rockchip_drm_psr.h"
 
 #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
 
@@ -66,9 +67,20 @@ static int rockchip_drm_fb_create_handle(struct 
drm_framebuffer *fb,
 rockchip_fb->obj[0], 

[PATCH v4 4/4] drm/rockchip: analogix_dp: implement PSR function

2016-07-13 Thread Yakir Yang
Alway enable the PSR function for Rockchip analogix_dp driver. If panel
don't support PSR, then the core analogix_dp would ignore this setting.

Signed-off-by: Yakir Yang 
---
Changes in v4:
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)

[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- split the common psr logic into a seperate driver, make this to a
  simple sub-psr device driver.

Changes in v2:
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 57 +
 1 file changed, 57 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c 
b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index e81e19a..aa916f4 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -32,6 +32,7 @@
 #include 
 
 #include "rockchip_drm_drv.h"
+#include "rockchip_drm_psr.h"
 #include "rockchip_drm_vop.h"
 
 #define RK3288_GRF_SOC_CON60x25c
@@ -41,6 +42,9 @@
 
 #define HIWORD_UPDATE(val, mask)   (val | (mask) << 16)
 
+#define PSR_SET_DELAY_TIME msecs_to_jiffies(10)
+#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS  100
+
 #define to_dp(nm)  container_of(nm, struct rockchip_dp_device, nm)
 
 /**
@@ -68,11 +72,55 @@ struct rockchip_dp_device {
struct regmap*grf;
struct reset_control *rst;
 
+   struct delayed_work  psr_work;
+   unsigned int psr_state;
+
const struct rockchip_dp_chip_data *data;
 
struct analogix_dp_plat_data plat_data;
 };
 
+static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
+{
+   struct rockchip_dp_device *dp = to_dp(encoder);
+
+   dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
+
+   if (enabled)
+   dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
+   else
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+
+   schedule_delayed_work(>psr_work, PSR_SET_DELAY_TIME);
+}
+
+static void analogix_dp_psr_work(struct work_struct *work)
+{
+   struct rockchip_dp_device *dp =
+   container_of(work, typeof(*dp), psr_work.work);
+   struct drm_crtc *crtc = dp->encoder.crtc;
+   int psr_state = dp->psr_state;
+   int vact_end;
+   int ret;
+
+   if (!crtc)
+   return;
+
+   vact_end = crtc->mode.vtotal - crtc->mode.vsync_start + 
crtc->mode.vdisplay;
+
+   ret = rockchip_drm_wait_line_flag(dp->encoder.crtc, vact_end,
+ PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
+   if (ret) {
+   dev_err(dp->dev, "line flag interrupt did not arrive\n");
+   return;
+   }
+
+   if (psr_state == EDP_VSC_PSR_STATE_ACTIVE)
+   analogix_dp_enable_psr(dp->dev);
+   else
+   analogix_dp_disable_psr(dp->dev);
+}
+
 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
 {
reset_control_assert(dp->rst);
@@ -340,12 +388,21 @@ static int rockchip_dp_bind(struct device *dev, struct 
device *master,
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
 
+   dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
+   INIT_DELAYED_WORK(>psr_work, analogix_dp_psr_work);
+
+   rockchip_drm_psr_register(>encoder, analogix_dp_psr_set);
+
return analogix_dp_bind(dev, dp->drm_dev, >plat_data);
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
   void *data)
 {
+   struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+   rockchip_drm_psr_unregister(>encoder);
+
return analogix_dp_unbind(dev, master, data);
 }
 
-- 
1.9.1




[PATCH v4 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-13 Thread Yakir Yang
The PSR driver have exported four symbols for specific device driver:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.

Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang 
---
Changes in v4:
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)

[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]

Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

 drivers/gpu/drm/rockchip/Makefile   |   2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   4 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
 drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 223 
 drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  26 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  29 
 7 files changed, 298 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index d665fb0..26c12b3 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -156,6 +156,9 @@ static int rockchip_drm_bind(struct device *dev)
 
drm_dev->dev_private = private;
 
+   INIT_LIST_HEAD(>psr_list);
+   mutex_init(>psr_list_mutex);
+
drm_mode_config_init(drm_dev);
 
rockchip_drm_mode_config_init(drm_dev);
@@ -218,6 +221,7 @@ static int rockchip_drm_bind(struct device *dev)
 
if (is_support_iommu)
arm_iommu_release_mapping(mapping);
+
return 0;
 err_fbdev_fini:
rockchip_drm_fbdev_fini(drm_dev);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 239b830..9c34c9e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -61,6 +61,9 @@ struct rockchip_drm_private {
struct drm_gem_object *fbdev_bo;
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];
struct drm_atomic_state *state;
+
+   struct list_head psr_list;
+   struct mutex psr_list_mutex;
 };
 
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 20f12bc..36afd9c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -21,6 +21,7 @@
 
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
+#include "rockchip_drm_psr.h"
 
 #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
 
@@ -66,9 +67,20 @@ static int rockchip_drm_fb_create_handle(struct 
drm_framebuffer *fb,
 rockchip_fb->obj[0], handle

[PATCH v4 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-07-13 Thread Yakir Yang
The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 60 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 49 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 28 ++
 include/drm/bridge/analogix_dp.h   |  3 ++
 5 files changed, 144 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..1fec91a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,62 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device 
*dp)
return 0;
 }
 
+int analogix_dp_enable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   analogix_dp_send_psr_spd(dp, EDP_VSC_PSR_STATE_ACTIVE |
+EDP_VSC_PSR_CRC_VALUES_VALID);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   analogix_dp_send_psr_spd(dp, 0);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_version;
+
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+   dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+   return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_en;
+
+   /* Disable psr function */
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+   psr_en &= ~DP_PSR_ENABLE;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Main-Link transmitter remains active during PSR active states */
+   psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Enable psr function */
+   psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   analogix_dp_enable_psr_crc(dp);
+}
+
 static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
 {
int i;
@@ -921,6 +977,10 @@ static void analogix_dp_commit(struct analogix_dp_device 
*dp)
 
/* Enable video */
analogix_dp_start_video(dp);
+
+   dp->psr_support = analogix_dp_detect_sink_psr(dp);
+   if (dp->psr_support)
+   analogix_dp_enable_sink_psr(dp);
 }
 
 int analogix_dp_get_modes(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index b456380..6ca5dde 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -177,6 +177,7 @@ struct analogix_dp_device {
int hpd_gpio;
boolforce_hpd;
unsigned char   edid[EDID_BLOCK_LENGTH * 2];
+   boolpsr_support;
 
struct analogix_dp_plat_data *plat_data;
 };
@@ -278,4 +279,7 @@ int analogix_dp_is_video_stream_on(struct 
analogix_dp_device *dp);
 void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_

[PATCH v4 3/4] drm/bridge: analogix_dp: add the PSR function support

2016-07-13 Thread Yakir Yang
The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make lots of
sense to save the power consumption.

This patch have exported two symbols for platform driver to implement
the PSR function in hardware side:
- analogix_dp_active_psr()
- analogix_dp_inactive_psr()

Signed-off-by: Yakir Yang 
---
Changes in v4:
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().

Changes in v3:
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments

Changes in v2:
- introduce in v2, splite the common Analogix DP changes out

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 60 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  4 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 49 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 28 ++
 include/drm/bridge/analogix_dp.h   |  3 ++
 5 files changed, 144 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 32715da..1fec91a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -97,6 +97,62 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device 
*dp)
return 0;
 }
 
+int analogix_dp_enable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   analogix_dp_send_psr_spd(dp, EDP_VSC_PSR_STATE_ACTIVE |
+EDP_VSC_PSR_CRC_VALUES_VALID);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
+
+int analogix_dp_disable_psr(struct device *dev)
+{
+   struct analogix_dp_device *dp = dev_get_drvdata(dev);
+
+   if (!dp->psr_support)
+   return -EINVAL;
+
+   analogix_dp_send_psr_spd(dp, 0);
+   return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
+
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_version;
+
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, _version);
+   dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+   return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+   unsigned char psr_en;
+
+   /* Disable psr function */
+   analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, _en);
+   psr_en &= ~DP_PSR_ENABLE;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Main-Link transmitter remains active during PSR active states */
+   psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   /* Enable psr function */
+   psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+DP_PSR_CRC_VERIFICATION;
+   analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+   analogix_dp_enable_psr_crc(dp);
+}
+
 static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
 {
int i;
@@ -921,6 +977,10 @@ static void analogix_dp_commit(struct analogix_dp_device 
*dp)
 
/* Enable video */
analogix_dp_start_video(dp);
+
+   dp->psr_support = analogix_dp_detect_sink_psr(dp);
+   if (dp->psr_support)
+   analogix_dp_enable_sink_psr(dp);
 }
 
 int analogix_dp_get_modes(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h 
b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index b456380..6ca5dde 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -177,6 +177,7 @@ struct analogix_dp_device {
int hpd_gpio;
boolforce_hpd;
unsigned char   edid[EDID_BLOCK_LENGTH * 2];
+   boolpsr_support;
 
struct analogix_dp_plat_data *plat_data;
 };
@@ -278,4 +279,7 @@ int analogix_dp_is_video_stream_on(struct 
analogix_dp_device *dp);
 void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_dis

[PATCH v4 0/4] Add PSR function support for Analogix/Rockchip DP

2016-07-13 Thread Yakir Yang

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make a lots
of sense to save the power consumption.

This v3 version have splited an common PSR driver for Rockchip, which is
biggest changes from v2.

This thread is based on Mark's RK3399 VOP thread[0] and my RK3399 eDP
thread[1].

[0]: https://patchwork.kernel.org/patch/8886041/
[1]: https://patchwork.kernel.org/patch/9204497/


Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)

[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)

[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments
- split the common psr logic into a seperate driver, make this to a
  simple sub-psr device driver.

Changes in v2:
- Introduce in v2, split VOP line flag changes out
- introduce in v2, splite the common Analogix DP changes out
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

Yakir Yang (4):
  drm/rockchip: vop: export line flag function
  drm/rockchip: add an common abstracted PSR driver
  drm/bridge: analogix_dp: add the PSR function support
  drm/rockchip: analogix_dp: implement PSR function

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  60 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   4 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  |  49 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  |  28 +++
 drivers/gpu/drm/rockchip/Makefile  |   2 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c|  57 ++
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c|   4 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h|   6 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c |  12 ++
 drivers/gpu/drm/rockchip/rockchip_drm_psr.c| 223 +
 drivers/gpu/drm/rockchip/rockchip_drm_psr.h|  26 +++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 147 ++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h|   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c|   4 +
 include/drm/bridge/analogix_dp.h   |   3 +
 15 files changed, 626 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

-- 
1.9.1




[PATCH v4 1/4] drm/rockchip: vop: export line flag function

2016-07-13 Thread Yakir Yang
VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 118 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
 4 files changed, 127 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index c8a62a8..69d32f1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
/* protected by dev->event_lock */
struct drm_pending_vblank_event *event;
 
+   struct completion line_flag_completion;
+
const struct vop_data *data;
 
uint32_t *regsbak;
@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(>irq_lock, flags);
 }
 
+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
 static void vop_enable(st

[PATCH v4 0/4] Add PSR function support for Analogix/Rockchip DP

2016-07-13 Thread Yakir Yang

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make a lots
of sense to save the power consumption.

This v3 version have splited an common PSR driver for Rockchip, which is
biggest changes from v2.

This thread is based on Mark's RK3399 VOP thread[0] and my RK3399 eDP
thread[1].

[0]: https://patchwork.kernel.org/patch/8886041/
[1]: https://patchwork.kernel.org/patch/9204497/


Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]
- Tuck the global "psr_list" & "psr_list_mutex" in struct rockchip_drm_private. 
(Sean)
- Move the access of "psr->state" under "psr->state_mutex"'s protect. (Sean)
- Let "psr->state = PSR_FLUSH" under "psr->state_mutex"'s protect. (Sean)
- Collect psr_enable() and psr_disable() into psr_set_state()
- s/5\ second/PSR_FLUSH_TIMEOUT/ (Sean)
- Flush the psr callback in vop_crtc_disable(). (Stéphane, reviewed in Google 
gerrit)

[https://chromium-review.googlesource.com/#/c/349084/6/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@475]
- Add the missing file head with license. (Stéphane, reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/357563/1/drivers/gpu/drm/rockchip/rockchip_drm_psr.h@3]
- Downgrade the PSR version print message to debug level. (Sean)
- Return 'void' instead of 'int' in analogix_dp_enable_sink_psr(). (Sean)
- Delete the unused read dpcd operations in analogix_dp_enable_sink_psr(). 
(Sean)
- Delete the arbitrary usleep_range in analogix_dp_enable_psr_crc. (Sean).
- Clean up the hardcoded values in analogix_dp_send_psr_spd(). (Sean)
- Rename "active/inactive" to "enable/disable". (Sean, Dominik)
- Keep set the PSR_VID_CRC_FLUSH gate in analogix_dp_enable_psr_crc().
- Return 'void' instead of 'int' in analogix_dp_psr_set(). (Sean)
- Pull the 10ms delay time out into a #define. (Sean)
- Improved the code of analogix_dp_psr_work(). (Sean)
- Indented with spaces for new numbers in rockchip_dp_device struct. (Stéphane, 
reviewed at Google gerrit)

[https://chromium-review.googlesource.com/#/c/349085/33/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@83]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2
- split analogix_dp_enable_psr(), make it more clearly
analogix_dp_detect_sink_psr()
analogix_dp_enable_sink_psr()
- remove some nosie register setting comments
- split the common psr logic into a seperate driver, make this to a
  simple sub-psr device driver.

Changes in v2:
- Introduce in v2, split VOP line flag changes out
- introduce in v2, splite the common Analogix DP changes out
- remove vblank notify out (Daniel)
- create a psr_active() callback in vop data struct.

Yakir Yang (4):
  drm/rockchip: vop: export line flag function
  drm/rockchip: add an common abstracted PSR driver
  drm/bridge: analogix_dp: add the PSR function support
  drm/rockchip: analogix_dp: implement PSR function

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  60 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   4 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  |  49 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  |  28 +++
 drivers/gpu/drm/rockchip/Makefile  |   2 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c|  57 ++
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c|   4 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h|   6 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c |  12 ++
 drivers/gpu/drm/rockchip/rockchip_drm_psr.c| 223 +
 drivers/gpu/drm/rockchip/rockchip_drm_psr.h|  26 +++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c| 147 ++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h|   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c|   4 +
 include/drm/bridge/analogix_dp.h   |   3 +
 15 files changed, 626 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

-- 
1.9.1




[PATCH v4 1/4] drm/rockchip: vop: export line flag function

2016-07-13 Thread Yakir Yang
VOP have integrated a hardware counter which indicate the exact display
line that vop is scanning. And if we're interested in a specific line,
we can set the line number to vop line_flag register, and then vop would
generate a line_flag interrupt for it.

For example eDP PSR function is interested in the vertical blanking
period, then driver could set the line number to zero.

This patch have exported a symbol that allow other driver to listen the
line flag event with given timeout limit:
-  rockchip_drm_wait_line_flag()

Signed-off-by: Yakir Yang 
---
Changes in v4:
- Avoid the weird behavior in rockchip_drm_wait_line_flag(). (Sean)
- Make line_flag_num_x to an array. (Sean)
- Remove the unused vop_cfg_done() in vop_line_flag_irq_enable(). (Stephane, 
reviewed in Google gerrit)

[https://chromium-review.googlesource.com/#/c/349084/33/drivers/gpu/drm/rockchip/rockchip_drm_vop.c@466]

Changes in v3:
- Export the 'rockchip_drm_wait_line_flag' symbol, and document it.
- Add 'line_flag_num_0' for RK3288/RK3036
- Remove the notify for waiting line_flag event (Daniel)

Changes in v2:
- Introduce in v2, split VOP line flag changes out

 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 118 
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   4 +
 4 files changed, 127 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index ea39329..239b830 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,4 +70,7 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num,
+   unsigned int mstimeout);
+
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index c8a62a8..69d32f1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -121,6 +121,8 @@ struct vop {
/* protected by dev->event_lock */
struct drm_pending_vblank_event *event;
 
+   struct completion line_flag_completion;
+
const struct vop_data *data;
 
uint32_t *regsbak;
@@ -431,6 +433,71 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
spin_unlock_irqrestore(>irq_lock, flags);
 }
 
+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ * the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into 
dsp_line_frag_num,
+ *  to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG ---+
+ * FRAME_SYNC + |
+ *| |
+ *v v
+ *| Vsync | Vbp |  Vactive  | Vfp |
+ *^ ^   ^ ^
+ *| |   | |
+ *| |   | |
+ * dsp_vs_end + |   | |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --+   | |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end + |   VOP_DSP_VACT_ST_END
+ * dsp_total -+   VOP_DSP_VTOTAL_VS_END
+ */
+static bool vop_line_flag_irq_is_enabled(struct vop *vop)
+{
+   uint32_t line_flag_irq;
+   unsigned long flags;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+
+   return !!line_flag_irq;
+}
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_CTRL_SET(vop, line_flag_num[0], line_num);
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+   unsigned long flags;
+
+   if (WARN_ON(!vop->is_enabled))
+   return;
+
+   spin_lock_irqsave(>irq_lock, flags);
+
+   VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0);
+
+   spin_unlock_irqrestore(>irq_lock, flags);
+}
+
 static void vop_enable(struct drm_crtc *crtc)
 {

Re: [PATCH v1 5/6] drm/rockchip: dw_hdmi: introduce the VPLL clock setting

2016-07-13 Thread Yakir Yang

Heiko,

On 07/12/2016 10:27 PM, Heiko Stübner wrote:

Hi Yakir,

Am Montag, 11. Juli 2016, 19:05:49 schrieb Yakir Yang:

For RK3399 HDMI, there is an external clock need for HDMI PHY,
and it should keep the same clock rate with VOP DCLK.

VPLL have supported the clock for HDMI PHY, but there is no
clock divider bewteen VPLL and HDMI PHY. So we need to set the
VPLL rate manually in HDMI driver.

I don't think reserving the vpll for the hdmi at all times is the right way to
go.

While I do agree that reserving the VPLL (and NPLL on the rk3288) for graphics
use looks like the right way, I think the core Rockchip drm driver should be
responsible for managing it and also for deciding which output encoder gets to
use it.
While true that on the Chromebook device-types the edp is static and hdmi
needs the broad range of dynamic frequencies, this is not necessarily the case
for all future device types and/or socs.

In the other thread we discussed adding that as rockchip,dclk-pll = <&...>; to
the base display-subsystem node, Doug didn't manage to find time to respond yet
though - and is on vacation right now.


Great idea. Let a separate drm-pll driver to maintain all connector's 
clock requirement.



I still believe that would be the best solution :-) .


That property could list 1 or even 2 plls, depending on the soc or board
layout - maybe someone frees up the cpll in some special layout or something.
If none are listed, then the drm driver would need to cope with its available
clocks.

Implementation-wise you could even still keep your shortcut until we encounter
a device with different , let the drm use the pll for hdmi only until someone
comes up with a better concept, but still the binding should be correct and
versatile from the start.


Someone should start to prepare the drm core pll driver, it's great idea.

BR,
- Yakir



Heiko


---
  .../bindings/display/rockchip/dw_hdmi-rockchip.txt |  3 ++-
  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c| 25
+- 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git
a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
index 4e573d2..4e23ca4 100644
---
a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
+++
b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
@@ -17,7 +17,8 @@ Required properties:

  Optional properties
  - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
+- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec",
+  phandle to the VPLL clock, name should be "vpll".

  Example:
  hdmi: hdmi@ff98 {
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 329099b..701bb73 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -7,10 +7,12 @@
   * (at your option) any later version.
   */

+#include 
+#include 
  #include 
  #include 
-#include 
  #include 
+
  #include 
  #include 
  #include 
@@ -33,6 +35,7 @@ struct rockchip_hdmi {
struct regmap *regmap;
struct drm_encoder encoder;
enum dw_hdmi_devtype dev_type;
+   struct clk *vpll_clk;
  };

  #define to_rockchip_hdmi(x)   container_of(x, struct rockchip_hdmi, x)
@@ -145,6 +148,7 @@ static const struct dw_hdmi_phy_config
rockchip_phy_config[] = { static int rockchip_hdmi_parse_dt(struct
rockchip_hdmi *hdmi)
  {
struct device_node *np = hdmi->dev->of_node;
+   int ret;

hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(hdmi->regmap)) {
@@ -152,6 +156,22 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi
*hdmi) return PTR_ERR(hdmi->regmap);
}

+   hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll");
+   if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) {
+   hdmi->vpll_clk = NULL;
+   } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) {
+   return -EPROBE_DEFER;
+   } else if (IS_ERR(hdmi->vpll_clk)) {
+   dev_err(hdmi->dev, "failed to get grf clock\n");
+   return PTR_ERR(hdmi->vpll_clk);
+   }
+
+   ret = clk_prepare_enable(hdmi->vpll_clk);
+   if (ret) {
+   dev_err(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret);
+   return ret;
+   }
+
return 0;
  }

@@ -194,6 +214,9 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct
drm_encoder *encoder, struct drm_display_mode *mode,
  struct drm_display_mode *adj_mode)
  {
+   struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
+
+   clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
  }

  static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)









Re: [PATCH v1 5/6] drm/rockchip: dw_hdmi: introduce the VPLL clock setting

2016-07-13 Thread Yakir Yang

Heiko,

On 07/12/2016 10:27 PM, Heiko Stübner wrote:

Hi Yakir,

Am Montag, 11. Juli 2016, 19:05:49 schrieb Yakir Yang:

For RK3399 HDMI, there is an external clock need for HDMI PHY,
and it should keep the same clock rate with VOP DCLK.

VPLL have supported the clock for HDMI PHY, but there is no
clock divider bewteen VPLL and HDMI PHY. So we need to set the
VPLL rate manually in HDMI driver.

I don't think reserving the vpll for the hdmi at all times is the right way to
go.

While I do agree that reserving the VPLL (and NPLL on the rk3288) for graphics
use looks like the right way, I think the core Rockchip drm driver should be
responsible for managing it and also for deciding which output encoder gets to
use it.
While true that on the Chromebook device-types the edp is static and hdmi
needs the broad range of dynamic frequencies, this is not necessarily the case
for all future device types and/or socs.

In the other thread we discussed adding that as rockchip,dclk-pll = <&...>; to
the base display-subsystem node, Doug didn't manage to find time to respond yet
though - and is on vacation right now.


Great idea. Let a separate drm-pll driver to maintain all connector's 
clock requirement.



I still believe that would be the best solution :-) .


That property could list 1 or even 2 plls, depending on the soc or board
layout - maybe someone frees up the cpll in some special layout or something.
If none are listed, then the drm driver would need to cope with its available
clocks.

Implementation-wise you could even still keep your shortcut until we encounter
a device with different , let the drm use the pll for hdmi only until someone
comes up with a better concept, but still the binding should be correct and
versatile from the start.


Someone should start to prepare the drm core pll driver, it's great idea.

BR,
- Yakir



Heiko


---
  .../bindings/display/rockchip/dw_hdmi-rockchip.txt |  3 ++-
  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c| 25
+- 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git
a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
index 4e573d2..4e23ca4 100644
---
a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
+++
b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
@@ -17,7 +17,8 @@ Required properties:

  Optional properties
  - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
-- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
+- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec",
+  phandle to the VPLL clock, name should be "vpll".

  Example:
  hdmi: hdmi@ff98 {
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 329099b..701bb73 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -7,10 +7,12 @@
   * (at your option) any later version.
   */

+#include 
+#include 
  #include 
  #include 
-#include 
  #include 
+
  #include 
  #include 
  #include 
@@ -33,6 +35,7 @@ struct rockchip_hdmi {
struct regmap *regmap;
struct drm_encoder encoder;
enum dw_hdmi_devtype dev_type;
+   struct clk *vpll_clk;
  };

  #define to_rockchip_hdmi(x)   container_of(x, struct rockchip_hdmi, x)
@@ -145,6 +148,7 @@ static const struct dw_hdmi_phy_config
rockchip_phy_config[] = { static int rockchip_hdmi_parse_dt(struct
rockchip_hdmi *hdmi)
  {
struct device_node *np = hdmi->dev->of_node;
+   int ret;

hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(hdmi->regmap)) {
@@ -152,6 +156,22 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi
*hdmi) return PTR_ERR(hdmi->regmap);
}

+   hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll");
+   if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) {
+   hdmi->vpll_clk = NULL;
+   } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) {
+   return -EPROBE_DEFER;
+   } else if (IS_ERR(hdmi->vpll_clk)) {
+   dev_err(hdmi->dev, "failed to get grf clock\n");
+   return PTR_ERR(hdmi->vpll_clk);
+   }
+
+   ret = clk_prepare_enable(hdmi->vpll_clk);
+   if (ret) {
+   dev_err(hdmi->dev, "Failed to enable HDMI vpll: %d\n", ret);
+   return ret;
+   }
+
return 0;
  }

@@ -194,6 +214,9 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct
drm_encoder *encoder, struct drm_display_mode *mode,
  struct drm_display_mode *adj_mode)
  {
+   struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
+
+   clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
  }

  static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)









Re: [PATCH v1 4/6] drm/rockchip: dw_hdmi: add RK3399 HDMI support

2016-07-13 Thread Yakir Yang

Philipp,

On 07/11/2016 07:51 PM, Philipp Zabel wrote:

Am Montag, den 11.07.2016, 19:05 +0800 schrieb Yakir Yang:

RK3399 and RK3288 shared the same HDMI IP controller, only some light
difference with GRF configure.

Signed-off-by: Yakir Yang <y...@rock-chips.com>

Reviewed-by: Philipp Zabel <p.za...@pengutronix.de>


Thanks for your fast respond :-D
- Yakir


regards
Philipp









Re: [PATCH v1 4/6] drm/rockchip: dw_hdmi: add RK3399 HDMI support

2016-07-13 Thread Yakir Yang

Philipp,

On 07/11/2016 07:51 PM, Philipp Zabel wrote:

Am Montag, den 11.07.2016, 19:05 +0800 schrieb Yakir Yang:

RK3399 and RK3288 shared the same HDMI IP controller, only some light
difference with GRF configure.

Signed-off-by: Yakir Yang 

Reviewed-by: Philipp Zabel 


Thanks for your fast respond :-D
- Yakir


regards
Philipp









Re: [PATCH v3 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-12 Thread Yakir Yang

Daniel,

On 07/12/2016 08:38 PM, Daniel Vetter wrote:

On Fri, Jul 01, 2016 at 02:00:00PM -0400, Sean Paul wrote:

On Fri, Jul 1, 2016 at 5:19 AM, Yakir Yang <y...@rock-chips.com> wrote:

The PSR driver have exported four symbols for specific device driver:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.


This feels overly complicated. It seems like you could cut out a bunch
of code by just coding the psr functions into vop and
analogix_dp-rockchip. I suppose the only reason to keep it abstracted
would be if you plan on supporting psr in a different encoder or crtc
in rockchip, or if you're planning on moving this into drm core.

Agreed on the layers of indirection. Also, you end up with 3 delayed
timers in total:
- defio timer from fbdev emulation
- timer in this abstraction
- delayed work in the psr backend driver

I'd cut out at least the middle one.

But since this seems to correctly use the ->dirty callback it gets my Ack
either way ;-)


Aha, thanks :-D

- Yakir


Cheers, Daniel


Perhaps others will disagree with this sentiment and this is the right
thing to do.


Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

  drivers/gpu/drm/rockchip/Makefile   |   2 +-
  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
  drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 200 
  drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  12 ++
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  24 
  5 files changed, 249 insertions(+), 1 deletion(-)
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.

  rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
  rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o

  obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 20f12bc..0fec18f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -21,6 +21,7 @@

  #include "rockchip_drm_drv.h"
  #include "rockchip_drm_gem.h"
+#include "rockchip_drm_psr.h"

  #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)

@@ -66,9 +67,20 @@ static int rockchip_drm_fb_create_handle(struct 
drm_framebuffer *fb,
  rockchip_fb->obj[0], handle);
  }

+static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
+struct drm_file *file,
+unsigned int flags, unsigned int color,
+struct drm_clip_rect *clips,
+unsigned int num_clips)
+{
+   rockchip_drm_psr_flush();
+   return 0;
+}
+
  static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
 .destroy= rockchip_drm_fb_destroy,
 .create_handle  = rockchip_drm_fb_create_handle,
+   .dirty  = rockchip_drm_fb_dirty,
  };

  static struct rockchip_drm_fb *
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
new file mode 100644
index 000..c03
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
@@ -0,0 +1,200 @@
+#include 
+
+#include "rockchip_drm_psr.h"
+
+#define PSR_FLUSH_TIMEOUT  msecs_to_jiffies(3000) /* 3 seconds */
+
+static LIST_HEAD(psr_list);
+static DEFINE_MUTEX(psr_list_mutex);

I'm not crazy about these globals. Perhaps you can initialize them
with the rockchip driver and tuck them in a driver-level struct
(rockchip_drm_private or somethin

Re: [PATCH v3 2/4] drm/rockchip: add an common abstracted PSR driver

2016-07-12 Thread Yakir Yang

Daniel,

On 07/12/2016 08:38 PM, Daniel Vetter wrote:

On Fri, Jul 01, 2016 at 02:00:00PM -0400, Sean Paul wrote:

On Fri, Jul 1, 2016 at 5:19 AM, Yakir Yang  wrote:

The PSR driver have exported four symbols for specific device driver:
- rockchip_drm_psr_register()
- rockchip_drm_psr_unregister()
- rockchip_drm_psr_enable()
- rockchip_drm_psr_disable()
- rockchip_drm_psr_flush()

Encoder driver should call the register/unregister interfaces to hook
itself into common PSR driver, encoder have implement the 'psr_set'
callback which use the set PSR state in hardware side.

Crtc driver would call the enable/disable interfaces when vblank is
enable/disable, after that the common PSR driver would call the encoder
registered callback to set the PSR state.


This feels overly complicated. It seems like you could cut out a bunch
of code by just coding the psr functions into vop and
analogix_dp-rockchip. I suppose the only reason to keep it abstracted
would be if you plan on supporting psr in a different encoder or crtc
in rockchip, or if you're planning on moving this into drm core.

Agreed on the layers of indirection. Also, you end up with 3 delayed
timers in total:
- defio timer from fbdev emulation
- timer in this abstraction
- delayed work in the psr backend driver

I'd cut out at least the middle one.

But since this seems to correctly use the ->dirty callback it gets my Ack
either way ;-)


Aha, thanks :-D

- Yakir


Cheers, Daniel


Perhaps others will disagree with this sentiment and this is the right
thing to do.


Fb driver would call the flush interface in 'fb->dirty' callback, this
helper function would force all PSR enabled encoders to exit from PSR
for 3 seconds.

Signed-off-by: Yakir Yang 
---
Changes in v3:
- split the psr flow into an common abstracted PSR driver
- implement the 'fb->dirty' callback function (Daniel)
- avoid to use notify to acqiure for vact event (Daniel)
- remove psr_active() callback which introduce in v2

Changes in v2: None

  drivers/gpu/drm/rockchip/Makefile   |   2 +-
  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  12 ++
  drivers/gpu/drm/rockchip/rockchip_drm_psr.c | 200 
  drivers/gpu/drm/rockchip/rockchip_drm_psr.h |  12 ++
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  24 
  5 files changed, 249 insertions(+), 1 deletion(-)
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/rockchip/Makefile 
b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..9746365 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.

  rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-   rockchip_drm_gem.o rockchip_drm_vop.o
+   rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o
  rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o

  obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 20f12bc..0fec18f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -21,6 +21,7 @@

  #include "rockchip_drm_drv.h"
  #include "rockchip_drm_gem.h"
+#include "rockchip_drm_psr.h"

  #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)

@@ -66,9 +67,20 @@ static int rockchip_drm_fb_create_handle(struct 
drm_framebuffer *fb,
  rockchip_fb->obj[0], handle);
  }

+static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
+struct drm_file *file,
+unsigned int flags, unsigned int color,
+struct drm_clip_rect *clips,
+unsigned int num_clips)
+{
+   rockchip_drm_psr_flush();
+   return 0;
+}
+
  static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
 .destroy= rockchip_drm_fb_destroy,
 .create_handle  = rockchip_drm_fb_create_handle,
+   .dirty  = rockchip_drm_fb_dirty,
  };

  static struct rockchip_drm_fb *
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
new file mode 100644
index 000..c03
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
@@ -0,0 +1,200 @@
+#include 
+
+#include "rockchip_drm_psr.h"
+
+#define PSR_FLUSH_TIMEOUT  msecs_to_jiffies(3000) /* 3 seconds */
+
+static LIST_HEAD(psr_list);
+static DEFINE_MUTEX(psr_list_mutex);

I'm not crazy about these globals. Perhaps you can initialize them
with the rockchip driver and tuck them in a driver-level struct
(rockchip_drm_private or something).



+
+enum psr_state {
+   PSR_FLUSH,
+   PS

  1   2   3   4   5   6   7   8   9   10   >