MLK-16918-16: drm/mxsfb: Add support for suspend/resume
authorRobert Chiras <robert.chiras@nxp.com>
Wed, 22 Nov 2017 09:47:18 +0000 (11:47 +0200)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
Update the MXSFB DRM driver to support the PM Runtime and System
Sleep suspend/resume routines.

Signed-off-by: Robert Chiras <robert.chiras@nxp.com>
drivers/gpu/drm/mxsfb/mxsfb_crtc.c
drivers/gpu/drm/mxsfb/mxsfb_drv.c
drivers/gpu/drm/mxsfb/mxsfb_drv.h
drivers/gpu/drm/mxsfb/mxsfb_regs.h

index aa1c1ac..0b0c365 100644 (file)
@@ -128,9 +128,6 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
 {
        u32 reg;
 
-       if (mxsfb->enabled)
-               return;
-
        if (mxsfb->clk_disp_axi)
                clk_prepare_enable(mxsfb->clk_disp_axi);
        clk_prepare_enable(mxsfb->clk);
@@ -151,17 +148,12 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
        writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
 
        writel(CTRL1_RECOVERY_ON_UNDERFLOW, mxsfb->base + LCDC_CTRL1 + REG_SET);
-
-       mxsfb->enabled = true;
 }
 
 static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
 {
        u32 reg;
 
-       if (!mxsfb->enabled)
-               return;
-
        writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_CLR);
 
        /*
@@ -184,8 +176,6 @@ static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
        if (mxsfb->clk_disp_axi)
                clk_disable_unprepare(mxsfb->clk_disp_axi);
        clk_disable_unprepare(mxsfb->clk);
-
-       mxsfb->enabled = false;
 }
 
 /*
@@ -305,14 +295,24 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
 
 void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
 {
+       if (mxsfb->enabled)
+               return;
+
        writel(0, mxsfb->base + LCDC_CTRL);
        mxsfb_crtc_mode_set_nofb(mxsfb);
        mxsfb_enable_controller(mxsfb);
+
+       mxsfb->enabled = true;
 }
 
 void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
 {
+       if (!mxsfb->enabled)
+               return;
+
        mxsfb_disable_controller(mxsfb);
+
+       mxsfb->enabled = false;
 }
 
 void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
@@ -323,12 +323,10 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
        struct drm_framebuffer *fb = pipe->plane.state->fb;
        struct drm_pending_vblank_event *event;
        struct drm_gem_cma_object *gem;
-       u32 val;
 
        if (!crtc)
                return;
 
-
        spin_lock_irq(&crtc->dev->event_lock);
        event = crtc->state->event;
        if (event) {
@@ -346,7 +344,6 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
                return;
 
        gem = drm_fb_cma_get_gem_obj(fb, 0);
-       pr_info("GEM paddr=0x%llx\n", gem->paddr);
 
        if (!mxsfb->enabled) {
                mxsfb->gem = gem;
@@ -356,9 +353,4 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
        mxsfb_enable_axi_clk(mxsfb);
        writel(gem->paddr, mxsfb->base + mxsfb->devdata->next_buf);
        mxsfb_disable_axi_clk(mxsfb);
-
-       val = readl(mxsfb->base + mxsfb->devdata->cur_buf);
-       pr_info("REG[%02X]=%08x\n", mxsfb->devdata->cur_buf, val);
-       val = readl(mxsfb->base + mxsfb->devdata->next_buf);
-       pr_info("REG[%02X]=%08x\n", mxsfb->devdata->next_buf, val);
 }
index b080854..c41550d 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of_reserved_mem.h>
 #include <linux/pm_runtime.h>
 #include <linux/reservation.h>
+#include <linux/busfreq-imx.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
@@ -57,6 +58,7 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
                .hs_wdth_mask   = 0xff,
                .hs_wdth_shift  = 24,
                .ipversion      = 3,
+               .flags          = MXSFB_FLAG_NULL,
        },
        [MXSFB_V4] = {
                .transfer_count = LCDC_V4_TRANSFER_COUNT,
@@ -66,6 +68,7 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
                .hs_wdth_mask   = 0x3fff,
                .hs_wdth_shift  = 18,
                .ipversion      = 4,
+               .flags          = MXSFB_FLAG_BUSFREQ,
        },
 };
 
@@ -107,6 +110,7 @@ static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
        drm_panel_prepare(mxsfb->panel);
        mxsfb_crtc_enable(mxsfb);
        drm_panel_enable(mxsfb->panel);
+       pm_runtime_get_sync(mxsfb->dev);
 }
 
 static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
@@ -116,6 +120,7 @@ static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
        drm_panel_disable(mxsfb->panel);
        mxsfb_crtc_disable(mxsfb);
        drm_panel_unprepare(mxsfb->panel);
+       pm_runtime_put_sync(mxsfb->dev);
 }
 
 static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
@@ -172,6 +177,9 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags)
 
        drm->dev_private = mxsfb;
        mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+       mxsfb->dev = &pdev->dev;
+
+       platform_set_drvdata(pdev, drm);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mxsfb->base = devm_ioremap_resource(drm->dev, res);
@@ -264,7 +272,6 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags)
                goto err_cma;
        }
 
-       platform_set_drvdata(pdev, drm);
 
        drm_helper_hpd_irq_event(drm);
 
@@ -425,6 +432,65 @@ static int mxsfb_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int mxsfb_runtime_suspend(struct device *dev)
+{
+       struct drm_device *drm = dev_get_drvdata(dev);
+       struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+       if (!drm->registered)
+               return 0;
+
+       mxsfb_crtc_disable(mxsfb);
+
+       if (mxsfb->devdata->flags & MXSFB_FLAG_BUSFREQ)
+               release_bus_freq(BUS_FREQ_HIGH);
+
+       return 0;
+}
+
+static int mxsfb_runtime_resume(struct device *dev)
+{
+       struct drm_device *drm = dev_get_drvdata(dev);
+       struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+       if (!drm->registered)
+               return 0;
+
+       if (mxsfb->devdata->flags & MXSFB_FLAG_BUSFREQ)
+               request_bus_freq(BUS_FREQ_HIGH);
+
+       mxsfb_crtc_enable(mxsfb);
+
+       return 0;
+}
+
+static int mxsfb_suspend(struct device *dev)
+{
+       struct drm_device *drm = dev_get_drvdata(dev);
+       struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+       mxsfb_crtc_disable(mxsfb);
+
+       return 0;
+}
+
+static int mxsfb_resume(struct device *dev)
+{
+       struct drm_device *drm = dev_get_drvdata(dev);
+       struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+       mxsfb_crtc_enable(mxsfb);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops mxsfb_pm_ops = {
+       SET_RUNTIME_PM_OPS(mxsfb_runtime_suspend, mxsfb_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(mxsfb_suspend, mxsfb_resume)
+};
+
 static struct platform_driver mxsfb_platform_driver = {
        .probe          = mxsfb_probe,
        .remove         = mxsfb_remove,
@@ -432,6 +498,7 @@ static struct platform_driver mxsfb_platform_driver = {
        .driver = {
                .name           = "mxsfb",
                .of_match_table = mxsfb_dt_ids,
+               .pm = &mxsfb_pm_ops,
        },
 };
 
index 3340997..71e62b0 100644 (file)
@@ -24,9 +24,11 @@ struct mxsfb_devdata {
        unsigned int     hs_wdth_mask;
        unsigned int     hs_wdth_shift;
        unsigned int     ipversion;
+       unsigned int     flags;
 };
 
 struct mxsfb_drm_private {
+       struct device                   *dev;
        const struct mxsfb_devdata      *devdata;
 
        void __iomem                    *base;  /* registers */
index c5b5e40..fc14d7d 100644 (file)
 #define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT        (1 << 6)
 #define MXSFB_SYNC_DOTCLK_FALLING_ACT  (1 << 7) /* negative edge sampling */
 
+#define MXSFB_FLAG_NULL BIT(0)
+#define MXSFB_FLAG_BUSFREQ BIT(1)
+
 #endif /* __MXSFB_REGS_H__ */