summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/mxsfb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/mxsfb')
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_crtc.c8
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.c73
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.h1
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_out.c2
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;