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 <ykk@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, &psr_version);
+ dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
+
+ return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
+}
+
+static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
+{
+ unsigned char psr_en;
+
+ /* Disable psr function */
+ analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en);
+ psr_en &= ~DP_PSR_ENABLE;
+ analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+ /* Main-Link transmitter remains active during PSR active states */
+ psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+ analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+ /* Enable psr function */
+ psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+ DP_PSR_CRC_VERIFICATION;
+ analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+ analogix_dp_enable_psr_crc(dp);
+}
+
static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data)
{
int i;
@@ -921,6 +977,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
/* Enable video */
analogix_dp_start_video(dp);
+
+ dp->psr_support = analogix_dp_detect_sink_psr(dp);
+ if (dp->psr_support)
+ analogix_dp_enable_sink_psr(dp);
}
int analogix_dp_get_modes(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index b456380..6ca5dde 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -177,6 +177,7 @@ struct analogix_dp_device {
int hpd_gpio;
bool force_hpd;
unsigned char edid[EDID_BLOCK_LENGTH * 2];
+ bool psr_support;
struct analogix_dp_plat_data *plat_data;
};
@@ -278,4 +279,7 @@ int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp);
void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp);
void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
+void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
+void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, int db1);
+
#endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 48030f0..26446ae 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -26,6 +26,9 @@
#define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG)
#define INT_STA_MASK INT_HPD
+static u32 psr_spd_hbx[] = { 0x00, 0x07, 0x02, 0x08 };
+static u32 psr_spd_pbx[] = { 0x00, 0x16, 0xCE, 0x5D };