diff options
Diffstat (limited to 'drivers/gpu/drm/mxsfb')
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_drv.c | 80 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_out.c | 2 |
4 files changed, 71 insertions, 21 deletions
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c index 94a6d16d469c..6c9a5efb3ab8 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c @@ -158,9 +158,9 @@ err: return -EINVAL; } -static u32 get_bus_format_from_bpp(u32 bpp) +static u32 get_bus_format_from_width(u32 width) { - switch (bpp) { + switch (width) { case 16: return MEDIA_BUS_FMT_RGB565_1X16; case 18: @@ -177,7 +177,7 @@ static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb) struct drm_crtc *crtc = &mxsfb->pipe.crtc; unsigned int bits_per_pixel = crtc->primary->state->fb->format->depth; struct drm_device *drm = crtc->dev; - u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; + u32 bus_format = get_bus_format_from_width(mxsfb->bus_width); int num_bus_formats = mxsfb->connector->display_info.num_bus_formats; const u32 *bus_formats = mxsfb->connector->display_info.bus_formats; u32 reg = 0; @@ -185,7 +185,7 @@ static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb) /* match the user requested bus_format to one supported by the panel */ if (num_bus_formats) { - u32 user_bus_format = get_bus_format_from_bpp(bits_per_pixel); + u32 user_bus_format = get_bus_format_from_width(bits_per_pixel); bus_format = bus_formats[0]; for (i = 0; i < num_bus_formats; i++) { diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 24bb09fdc5fd..183c3652100b 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -44,6 +44,27 @@ #include "mxsfb_drv.h" #include "mxsfb_regs.h" +/* + * There are non-atomic versions of clk_enable()/clk_disable() callbacks + * used in IMX8QM/IMX8QXP, so we can't manage axi clk in interrupt handlers + */ +#if defined(CONFIG_ARCH_FSL_IMX8QM) || defined(CONFIG_ARCH_FSL_IMX8QXP) +# define mxsfb_enable_axi_clk(mxsfb) +# define mxsfb_disable_axi_clk(mxsfb) +#else +static inline void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb) +{ + if (mxsfb->clk_axi) + clk_prepare_enable(mxsfb->clk_axi); +} + +static inline void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb) +{ + if (mxsfb->clk_axi) + clk_disable_unprepare(mxsfb->clk_axi); +} +#endif + /* The eLCDIF max possible CRTCs */ #define MAX_CRTCS 1 @@ -56,6 +77,9 @@ enum mxsfb_devtype { MXSFB_V4, }; +/* default output bus width */ +#define MXSFB_DEFAULT_BUS_WIDTH 24 + /* * When adding new formats, make sure to update the num_formats from * mxsfb_devdata below. @@ -336,9 +360,17 @@ static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, drm_crtc_vblank_on(&mxsfb->pipe.crtc); pm_runtime_get_sync(drm->dev); - drm_panel_prepare(mxsfb->panel); - mxsfb_crtc_enable(mxsfb); - drm_panel_enable(mxsfb->panel); + if (mxsfb->panel) { + drm_panel_prepare(mxsfb->panel); + mxsfb_crtc_enable(mxsfb); + drm_panel_enable(mxsfb->panel); + } + + if (mxsfb->bridge) { + drm_bridge_pre_enable(mxsfb->bridge); + mxsfb_crtc_enable(mxsfb); + drm_bridge_enable(mxsfb->bridge); + } } static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) @@ -348,9 +380,18 @@ static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) struct drm_crtc *crtc = &pipe->crtc; struct drm_pending_vblank_event *event; - drm_panel_disable(mxsfb->panel); - mxsfb_crtc_disable(mxsfb); - drm_panel_unprepare(mxsfb->panel); + if (mxsfb->bridge) { + drm_bridge_disable(mxsfb->bridge); + mxsfb_crtc_disable(mxsfb); + drm_bridge_post_disable(mxsfb->bridge); + } + + if (mxsfb->panel) { + drm_panel_disable(mxsfb->panel); + mxsfb_crtc_disable(mxsfb); + drm_panel_unprepare(mxsfb->panel); + } + pm_runtime_put_sync(drm->dev); spin_lock_irq(&drm->event_lock); @@ -398,6 +439,7 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) struct mxsfb_drm_private *mxsfb; struct resource *res; u32 max_res[2] = {0, 0}; + u32 bus_width = MXSFB_DEFAULT_BUS_WIDTH; int ret; mxsfb = devm_kzalloc(&pdev->dev, sizeof(*mxsfb), GFP_KERNEL); @@ -493,6 +535,10 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) } } + /* bus width is needed to set up correct bus format */ + of_property_read_u32(drm->dev->of_node, "bus-width", &bus_width); + mxsfb->bus_width = bus_width; + of_property_read_u32_array(drm->dev->of_node, "max-res", &max_res[0], 2); if (!max_res[0]) @@ -531,13 +577,15 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) drm_helper_hpd_irq_event(drm); pm_runtime_enable(drm->dev); + pm_runtime_get_sync(drm->dev); return 0; err_cma: drm_irq_uninstall(drm); err_irq: - drm_panel_detach(mxsfb->panel); + if (mxsfb->panel) + drm_panel_detach(mxsfb->panel); return ret; } @@ -566,6 +614,7 @@ static void mxsfb_unload(struct drm_device *drm) drm->dev_private = NULL; + pm_runtime_put_sync(drm->dev); pm_runtime_disable(drm->dev); } @@ -581,14 +630,13 @@ static int mxsfb_enable_vblank(struct drm_device *drm, unsigned int crtc) struct mxsfb_drm_private *mxsfb = drm->dev_private; int ret = 0; - ret = clk_prepare_enable(mxsfb->clk_axi); - if (ret) - return ret; + mxsfb_enable_axi_clk(mxsfb); /* Clear and enable VBLANK IRQ */ writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET); - clk_disable_unprepare(mxsfb->clk_axi); + + mxsfb_disable_axi_clk(mxsfb); return ret; } @@ -597,13 +645,13 @@ static void mxsfb_disable_vblank(struct drm_device *drm, unsigned int crtc) { struct mxsfb_drm_private *mxsfb = drm->dev_private; - if (clk_prepare_enable(mxsfb->clk_axi)) - return; + mxsfb_enable_axi_clk(mxsfb); /* Disable and clear VBLANK IRQ */ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR); writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); - clk_disable_unprepare(mxsfb->clk_axi); + + mxsfb_disable_axi_clk(mxsfb); } static void mxsfb_irq_preinstall(struct drm_device *drm) @@ -617,7 +665,7 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *data) struct mxsfb_drm_private *mxsfb = drm->dev_private; u32 reg; - clk_prepare_enable(mxsfb->clk_axi); + mxsfb_enable_axi_clk(mxsfb); reg = readl(mxsfb->base + LCDC_CTRL1); @@ -626,7 +674,7 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *data) writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); - clk_disable_unprepare(mxsfb->clk_axi); + mxsfb_disable_axi_clk(mxsfb); return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h index 24d573fe5aee..ead101bc4e17 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h @@ -56,6 +56,8 @@ struct mxsfb_drm_private { struct drm_bridge *bridge; struct drm_fbdev_cma *fbdev; + u32 bus_width; + struct list_head valid_modes; }; diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c index 044d5fbfbce5..66b1095f310b 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_out.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c @@ -100,7 +100,7 @@ int mxsfb_create_output(struct drm_device *drm) &mxsfb_panel_connector_helper_funcs); ret = drm_connector_init(drm, mxsfb->connector, &mxsfb_panel_connector_funcs, - DRM_MODE_CONNECTOR_Unknown); + DRM_MODE_CONNECTOR_DPI); } return ret; |