diff options
author | Vinod Polimera <quic_vpolimer@quicinc.com> | 2023-03-02 19:33:12 +0300 |
---|---|---|
committer | Dmitry Baryshkov <dmitry.baryshkov@linaro.org> | 2023-03-13 04:43:49 +0300 |
commit | cd779808cccd50a6b079753e1d061a315effa207 (patch) | |
tree | bc6fb97440394982e01c9b4d41d39be365d94bee /drivers/gpu/drm/msm/dp/dp_catalog.c | |
parent | cdfd0e6246c49dd3f798ce802a5211bc3948f9ac (diff) | |
download | linux-cd779808cccd50a6b079753e1d061a315effa207.tar.xz |
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 <quic_sbillaka@quicinc.com>
Signed-off-by: Vinod Polimera <quic_vpolimer@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/524734/
Link: https://lore.kernel.org/r/1677774797-31063-10-git-send-email-quic_vpolimer@quicinc.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Diffstat (limited to 'drivers/gpu/drm/msm/dp/dp_catalog.c')
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_catalog.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 676279d0ca8d..c12a5d9647bb 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,23 @@ 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); + + 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 +635,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, 0x0); +} + +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 +711,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog) return isr & (mask | ~DP_DP_HPD_INT_MASK); } +u32 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, |