summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/dp/dp_catalog.c
diff options
context:
space:
mode:
authorVinod Polimera <quic_vpolimer@quicinc.com>2023-03-02 19:33:12 +0300
committerDmitry Baryshkov <dmitry.baryshkov@linaro.org>2023-03-13 04:43:49 +0300
commitcd779808cccd50a6b079753e1d061a315effa207 (patch)
treebc6fb97440394982e01c9b4d41d39be365d94bee /drivers/gpu/drm/msm/dp/dp_catalog.c
parentcdfd0e6246c49dd3f798ce802a5211bc3948f9ac (diff)
downloadlinux-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.c80
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,