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 | 73 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_out.c | 2 |
4 files changed, 66 insertions, 18 deletions
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c index 5607fc0d61a6..0097fc563c46 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c @@ -151,9 +151,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: @@ -170,7 +170,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; @@ -178,7 +178,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 bf60a1c52e17..9bec17a6c31e 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -44,6 +44,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. @@ -88,6 +91,25 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { }, }; +/* + * 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) 0 +# define mxsfb_disable_axi_clk(mxsfb) +#else +static inline int mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb) +{ + return clk_prepare_enable(mxsfb->clk_axi); +} + +static inline void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb) +{ + clk_disable_unprepare(mxsfb->clk_axi); +} +#endif + static struct mxsfb_drm_private * drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe) { @@ -232,9 +254,17 @@ static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, } 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) @@ -244,9 +274,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); @@ -274,14 +313,14 @@ static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); int ret = 0; - ret = clk_prepare_enable(mxsfb->clk_axi); + ret = mxsfb_enable_axi_clk(mxsfb); if (ret) return ret; /* 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; } @@ -290,13 +329,13 @@ static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) { struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); - if (clk_prepare_enable(mxsfb->clk_axi)) + if (mxsfb_enable_axi_clk(mxsfb)) return; /* 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 struct drm_simple_display_pipe_funcs mxsfb_funcs = { @@ -315,6 +354,7 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) struct platform_device *pdev = to_platform_device(drm->dev); struct mxsfb_drm_private *mxsfb; struct resource *res; + u32 bus_width = MXSFB_DEFAULT_BUS_WIDTH; int ret; mxsfb = devm_kzalloc(&pdev->dev, sizeof(*mxsfb), GFP_KERNEL); @@ -349,6 +389,7 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) return ret; pm_runtime_enable(drm->dev); + pm_runtime_get_sync(drm->dev); ret = drm_vblank_init(drm, drm->mode_config.num_crtc); if (ret < 0) { @@ -396,6 +437,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; + drm->mode_config.min_width = MXSFB_MIN_XRES; drm->mode_config.min_height = MXSFB_MIN_YRES; drm->mode_config.max_width = MXSFB_MAX_XRES; @@ -423,7 +468,8 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) return 0; err_irq: - drm_panel_detach(mxsfb->panel); + if (mxsfb->panel) + drm_panel_detach(mxsfb->panel); err_vblank: pm_runtime_disable(drm->dev); @@ -441,6 +487,7 @@ static void mxsfb_unload(struct drm_device *drm) drm->dev_private = NULL; + pm_runtime_put_sync(drm->dev); pm_runtime_disable(drm->dev); } @@ -457,7 +504,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); @@ -466,7 +513,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 54c06445be96..dffe4b8f52f7 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h @@ -34,6 +34,7 @@ struct mxsfb_drm_private { struct drm_bridge *bridge; u32 max_bw; + u32 bus_width; }; int mxsfb_setup_crtc(struct drm_device *dev); diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c index 4eb94744c526..582e771cf726 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_out.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c @@ -92,7 +92,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; |