Re: [Freedreno] [v3 1/5] drm/msm/dp: Add basic PSR support for eDP
Hi Dmitry, >On 21/06/2022 13:53, Vinod Polimera wrote: >> Add support for basic panel self refresh (PSR) feature for eDP. >> Add a new interface to set PSR state in the sink from DPU. >> Program the eDP controller to issue PSR enter and exit SDP to the >> sink. >> >> Signed-off-by: Sankeerth Billakanti >> Signed-off-by: Vinod Polimera >> --- >> drivers/gpu/drm/msm/dp/dp_catalog.c | 81 ++ >> drivers/gpu/drm/msm/dp/dp_catalog.h | 4 + >> drivers/gpu/drm/msm/dp/dp_ctrl.c| 76 - >> drivers/gpu/drm/msm/dp/dp_ctrl.h| 3 + >> drivers/gpu/drm/msm/dp/dp_display.c | 14 +++ >> drivers/gpu/drm/msm/dp/dp_display.h | 2 + >> drivers/gpu/drm/msm/dp/dp_drm.c | 166 >+++- >> drivers/gpu/drm/msm/dp/dp_link.c| 36 >> drivers/gpu/drm/msm/dp/dp_panel.c | 22 + >> drivers/gpu/drm/msm/dp/dp_panel.h | 6 ++ >> drivers/gpu/drm/msm/dp/dp_reg.h | 27 ++ >> 11 files changed, 433 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c >> b/drivers/gpu/drm/msm/dp/dp_catalog.c >> index 7257515..b9021ed 100644 >> --- a/drivers/gpu/drm/msm/dp/dp_catalog.c >> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c >> @@ -47,6 +47,14 @@ >> #define DP_INTERRUPT_STATUS2_MASK \ >> (DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT) >> >> +#define DP_INTERRUPT_STATUS4 \ >> +(PSR_UPDATE_INT | PSR_CAPTURE_INT | PSR_EXIT_INT | \ >> +PSR_UPDATE_ERROR_INT | PSR_WAKE_ERROR_INT) >> + >> +#define DP_INTERRUPT_MASK4 \ >> +(PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \ >> +PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK) >> + >> struct dp_catalog_private { >> struct device *dev; >> struct drm_device *drm_dev; >> @@ -359,6 +367,24 @@ void dp_catalog_ctrl_lane_mapping(struct >dp_catalog *dp_catalog) >> ln_mapping); >> } >> >> +void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, >> +bool enable) >> +{ >> +u32 val; >> +struct dp_catalog_private *catalog = container_of(dp_catalog, >> +struct dp_catalog_private, dp_catalog); >> + >> +val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); >> +val &= ~DP_MAINLINK_CTRL_ENABLE; >> + >> +if (enable) >> +val |= DP_MAINLINK_CTRL_ENABLE; >> +else >> +val &= ~DP_MAINLINK_CTRL_ENABLE; >> + >> +dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val); } >> + >> void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, >> bool enable) >> { >> @@ -610,6 +636,47 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog >*dp_catalog) >> dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, >DP_DP_HPD_CTRL_HPD_EN); >> } >> >> +static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog) >> +{ >> +/* trigger sdp */ >> +dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP); >> +dp_write_link(catalog, MMSS_DP_SDP_CFG3, !UPDATE_SDP); } >> + >> +void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog) { >> +struct dp_catalog_private *catalog = container_of(dp_catalog, >> +struct dp_catalog_private, dp_catalog); >> +u32 config; >> + >> +/* enable PSR1 function */ >> +config = dp_read_link(catalog, REG_PSR_CONFIG); >> +config |= PSR1_SUPPORTED; >> +dp_write_link(catalog, REG_PSR_CONFIG, config); >> + >> +dp_write_ahb(catalog, REG_DP_INTR_MASK4, >DP_INTERRUPT_MASK4); >> +dp_catalog_enable_sdp(catalog); >> +} >> + >> +void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool >> +enter) { >> +struct dp_catalog_private *catalog = container_of(dp_catalog, >> +struct dp_catalog_private, dp_catalog); >> +u32 cmd; >> + >> +cmd = dp_read_link(catalog, REG_PSR_CMD); >> + >> +cmd &= ~(PSR_ENTER | PSR_EXIT); >> + >> +if (enter) >> +cmd |= PSR_ENTER; >> +else >> +cmd |= PSR_EXIT; >> + >> +dp_catalog_enable_sdp(catalog); >> +dp_write_link(catalog, REG_PSR_CMD, cmd); } >> + >> u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog) >> { >> struct dp_catalog_private *catalog = container_of(dp_catalog, @@ >> -645,6 +712,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog >*dp_catalog) >> return isr & (mask | ~DP_DP_HPD_INT_MASK); >> } >> >> +int dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog >> +*dp_catalog) { >> +struct dp_catalog_private *catalog = container_of(dp_catalog, >> +struct dp_catalog_private, dp_catalog); >> +u32 intr, intr_ack; >> + >> +intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4); >> +intr_ack = (intr & DP_INTERRUPT_STATUS4) >> +<< DP_INTERRUPT_STATUS_ACK_SHIFT; >> +dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack); >> + >> +return intr; >> +} >> + >>
Re: [Freedreno] [v3 1/5] drm/msm/dp: Add basic PSR support for eDP
On 21/06/2022 13:53, Vinod Polimera wrote: Add support for basic panel self refresh (PSR) feature for eDP. Add a new interface to set PSR state in the sink from DPU. Program the eDP controller to issue PSR enter and exit SDP to the sink. Signed-off-by: Sankeerth Billakanti Signed-off-by: Vinod Polimera --- drivers/gpu/drm/msm/dp/dp_catalog.c | 81 ++ drivers/gpu/drm/msm/dp/dp_catalog.h | 4 + drivers/gpu/drm/msm/dp/dp_ctrl.c| 76 - drivers/gpu/drm/msm/dp/dp_ctrl.h| 3 + drivers/gpu/drm/msm/dp/dp_display.c | 14 +++ drivers/gpu/drm/msm/dp/dp_display.h | 2 + drivers/gpu/drm/msm/dp/dp_drm.c | 166 +++- drivers/gpu/drm/msm/dp/dp_link.c| 36 drivers/gpu/drm/msm/dp/dp_panel.c | 22 + drivers/gpu/drm/msm/dp/dp_panel.h | 6 ++ drivers/gpu/drm/msm/dp/dp_reg.h | 27 ++ 11 files changed, 433 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 7257515..b9021ed 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -47,6 +47,14 @@ #define DP_INTERRUPT_STATUS2_MASK \ (DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT) +#define DP_INTERRUPT_STATUS4 \ + (PSR_UPDATE_INT | PSR_CAPTURE_INT | PSR_EXIT_INT | \ + PSR_UPDATE_ERROR_INT | PSR_WAKE_ERROR_INT) + +#define DP_INTERRUPT_MASK4 \ + (PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \ + PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK) + struct dp_catalog_private { struct device *dev; struct drm_device *drm_dev; @@ -359,6 +367,24 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog) ln_mapping); } +void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, + bool enable) +{ + u32 val; + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); + val &= ~DP_MAINLINK_CTRL_ENABLE; + + if (enable) + val |= DP_MAINLINK_CTRL_ENABLE; + else + val &= ~DP_MAINLINK_CTRL_ENABLE; + + dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val); +} + void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable) { @@ -610,6 +636,47 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog) dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN); } +static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog) +{ + /* trigger sdp */ + dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP); + dp_write_link(catalog, MMSS_DP_SDP_CFG3, !UPDATE_SDP); +} + +void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + u32 config; + + /* enable PSR1 function */ + config = dp_read_link(catalog, REG_PSR_CONFIG); + config |= PSR1_SUPPORTED; + dp_write_link(catalog, REG_PSR_CONFIG, config); + + dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4); + dp_catalog_enable_sdp(catalog); +} + +void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + u32 cmd; + + cmd = dp_read_link(catalog, REG_PSR_CMD); + + cmd &= ~(PSR_ENTER | PSR_EXIT); + + if (enter) + cmd |= PSR_ENTER; + else + cmd |= PSR_EXIT; + + dp_catalog_enable_sdp(catalog); + dp_write_link(catalog, REG_PSR_CMD, cmd); +} + u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog) { struct dp_catalog_private *catalog = container_of(dp_catalog, @@ -645,6 +712,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog) return isr & (mask | ~DP_DP_HPD_INT_MASK); } +int dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + u32 intr, intr_ack; + + intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4); + intr_ack = (intr & DP_INTERRUPT_STATUS4) + << DP_INTERRUPT_STATUS_ACK_SHIFT; + dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack); + + return intr; +} + int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog) { struct dp_catalog_private *catalog = container_of(dp_catalog, diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h
[Freedreno] [v3 1/5] drm/msm/dp: Add basic PSR support for eDP
Add support for basic panel self refresh (PSR) feature for eDP. Add a new interface to set PSR state in the sink from DPU. Program the eDP controller to issue PSR enter and exit SDP to the sink. Signed-off-by: Sankeerth Billakanti Signed-off-by: Vinod Polimera --- drivers/gpu/drm/msm/dp/dp_catalog.c | 81 ++ drivers/gpu/drm/msm/dp/dp_catalog.h | 4 + drivers/gpu/drm/msm/dp/dp_ctrl.c| 76 - drivers/gpu/drm/msm/dp/dp_ctrl.h| 3 + drivers/gpu/drm/msm/dp/dp_display.c | 14 +++ drivers/gpu/drm/msm/dp/dp_display.h | 2 + drivers/gpu/drm/msm/dp/dp_drm.c | 166 +++- drivers/gpu/drm/msm/dp/dp_link.c| 36 drivers/gpu/drm/msm/dp/dp_panel.c | 22 + drivers/gpu/drm/msm/dp/dp_panel.h | 6 ++ drivers/gpu/drm/msm/dp/dp_reg.h | 27 ++ 11 files changed, 433 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 7257515..b9021ed 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -47,6 +47,14 @@ #define DP_INTERRUPT_STATUS2_MASK \ (DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT) +#define DP_INTERRUPT_STATUS4 \ + (PSR_UPDATE_INT | PSR_CAPTURE_INT | PSR_EXIT_INT | \ + PSR_UPDATE_ERROR_INT | PSR_WAKE_ERROR_INT) + +#define DP_INTERRUPT_MASK4 \ + (PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \ + PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK) + struct dp_catalog_private { struct device *dev; struct drm_device *drm_dev; @@ -359,6 +367,24 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog) ln_mapping); } +void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, + bool enable) +{ + u32 val; + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); + val &= ~DP_MAINLINK_CTRL_ENABLE; + + if (enable) + val |= DP_MAINLINK_CTRL_ENABLE; + else + val &= ~DP_MAINLINK_CTRL_ENABLE; + + dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val); +} + void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable) { @@ -610,6 +636,47 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog) dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN); } +static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog) +{ + /* trigger sdp */ + dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP); + dp_write_link(catalog, MMSS_DP_SDP_CFG3, !UPDATE_SDP); +} + +void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + u32 config; + + /* enable PSR1 function */ + config = dp_read_link(catalog, REG_PSR_CONFIG); + config |= PSR1_SUPPORTED; + dp_write_link(catalog, REG_PSR_CONFIG, config); + + dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4); + dp_catalog_enable_sdp(catalog); +} + +void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + u32 cmd; + + cmd = dp_read_link(catalog, REG_PSR_CMD); + + cmd &= ~(PSR_ENTER | PSR_EXIT); + + if (enter) + cmd |= PSR_ENTER; + else + cmd |= PSR_EXIT; + + dp_catalog_enable_sdp(catalog); + dp_write_link(catalog, REG_PSR_CMD, cmd); +} + u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog) { struct dp_catalog_private *catalog = container_of(dp_catalog, @@ -645,6 +712,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog) return isr & (mask | ~DP_DP_HPD_INT_MASK); } +int dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + u32 intr, intr_ack; + + intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4); + intr_ack = (intr & DP_INTERRUPT_STATUS4) + << DP_INTERRUPT_STATUS_ACK_SHIFT; + dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack); + + return intr; +} + int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog) { struct dp_catalog_private *catalog = container_of(dp_catalog, diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h index 1f717f4..6454845 100644 ---