{
u32 reg;
- if (mxsfb->enabled)
- return;
-
if (mxsfb->clk_disp_axi)
clk_prepare_enable(mxsfb->clk_disp_axi);
clk_prepare_enable(mxsfb->clk);
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);
/*
if (mxsfb->clk_disp_axi)
clk_disable_unprepare(mxsfb->clk_disp_axi);
clk_disable_unprepare(mxsfb->clk);
-
- mxsfb->enabled = false;
}
/*
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,
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) {
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;
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);
}
#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>
.hs_wdth_mask = 0xff,
.hs_wdth_shift = 24,
.ipversion = 3,
+ .flags = MXSFB_FLAG_NULL,
},
[MXSFB_V4] = {
.transfer_count = LCDC_V4_TRANSFER_COUNT,
.hs_wdth_mask = 0x3fff,
.hs_wdth_shift = 18,
.ipversion = 4,
+ .flags = MXSFB_FLAG_BUSFREQ,
},
};
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)
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,
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);
goto err_cma;
}
- platform_set_drvdata(pdev, drm);
drm_helper_hpd_irq_event(drm);
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,
.driver = {
.name = "mxsfb",
.of_match_table = mxsfb_dt_ids,
+ .pm = &mxsfb_pm_ops,
},
};