aboutsummaryrefslogtreecommitdiffstats
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/Kconfig8
-rw-r--r--drivers/gpu/drm/mxsfb/Makefile2
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_crtc.c343
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.c273
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.h42
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_kms.c571
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_out.c99
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_regs.h107
8 files changed, 760 insertions, 685 deletions
diff --git a/drivers/gpu/drm/mxsfb/Kconfig b/drivers/gpu/drm/mxsfb/Kconfig
index 0dca8f27169e..0143d539f8f8 100644
--- a/drivers/gpu/drm/mxsfb/Kconfig
+++ b/drivers/gpu/drm/mxsfb/Kconfig
@@ -5,7 +5,7 @@ config DRM_MXS
Choose this option to select drivers for MXS FB devices
config DRM_MXSFB
- tristate "i.MX23/i.MX28/i.MX6SX MXSFB LCD controller"
+ tristate "i.MX (e)LCDIF LCD controller"
depends on DRM && OF
depends on COMMON_CLK
select DRM_MXS
@@ -13,8 +13,10 @@ config DRM_MXSFB
select DRM_KMS_FB_HELPER
select DRM_KMS_CMA_HELPER
select DRM_PANEL
+ select DRM_PANEL_BRIDGE
help
- Choose this option if you have an i.MX23/i.MX28/i.MX6SX MXSFB
- LCD controller.
+ Choose this option if you have an LCDIF or eLCDIF LCD controller.
+ Those devices are found in various i.MX SoC (including i.MX23,
+ i.MX28, i.MX6SX, i.MX7 and i.MX8M).
If M is selected the module will be called mxsfb.
diff --git a/drivers/gpu/drm/mxsfb/Makefile b/drivers/gpu/drm/mxsfb/Makefile
index ff6e358088fa..26d153896d72 100644
--- a/drivers/gpu/drm/mxsfb/Makefile
+++ b/drivers/gpu/drm/mxsfb/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-mxsfb-y := mxsfb_drv.o mxsfb_crtc.o mxsfb_out.o
+mxsfb-y := mxsfb_drv.o mxsfb_kms.o
obj-$(CONFIG_DRM_MXSFB) += mxsfb.o
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
deleted file mode 100644
index b69ace8bf526..000000000000
--- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
+++ /dev/null
@@ -1,343 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Marek Vasut <marex@denx.de>
- *
- * This code is based on drivers/video/fbdev/mxsfb.c :
- * Copyright (C) 2010 Juergen Beisert, Pengutronix
- * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-#include <linux/clk.h>
-#include <linux/iopoll.h>
-#include <linux/of_graph.h>
-#include <linux/platform_data/simplefb.h>
-
-#include <video/videomode.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_of.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
-#include <drm/drm_vblank.h>
-
-#include "mxsfb_drv.h"
-#include "mxsfb_regs.h"
-
-#define MXS_SET_ADDR 0x4
-#define MXS_CLR_ADDR 0x8
-#define MODULE_CLKGATE BIT(30)
-#define MODULE_SFTRST BIT(31)
-/* 1 second delay should be plenty of time for block reset */
-#define RESET_TIMEOUT 1000000
-
-static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
-{
- return (val & mxsfb->devdata->hs_wdth_mask) <<
- mxsfb->devdata->hs_wdth_shift;
-}
-
-/* Setup the MXSFB registers for decoding the pixels out of the framebuffer */
-static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb)
-{
- struct drm_crtc *crtc = &mxsfb->pipe.crtc;
- struct drm_device *drm = crtc->dev;
- const u32 format = crtc->primary->state->fb->format->format;
- u32 ctrl, ctrl1;
-
- ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
-
- /*
- * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to
- * match the selected mode here. This differs from the original
- * MXSFB driver, which had the option to configure the bus width
- * to arbitrary value. This limitation should not pose an issue.
- */
-
- /* CTRL1 contains IRQ config and status bits, preserve those. */
- ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
- ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
-
- switch (format) {
- case DRM_FORMAT_RGB565:
- dev_dbg(drm->dev, "Setting up RGB565 mode\n");
- ctrl |= CTRL_SET_WORD_LENGTH(0);
- ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
- break;
- case DRM_FORMAT_XRGB8888:
- dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
- ctrl |= CTRL_SET_WORD_LENGTH(3);
- /* Do not use packed pixels = one pixel per word instead. */
- ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
- break;
- default:
- dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
- return -EINVAL;
- }
-
- writel(ctrl1, mxsfb->base + LCDC_CTRL1);
- writel(ctrl, mxsfb->base + LCDC_CTRL);
-
- return 0;
-}
-
-static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
-{
- struct drm_crtc *crtc = &mxsfb->pipe.crtc;
- struct drm_device *drm = crtc->dev;
- u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
- u32 reg;
-
- reg = readl(mxsfb->base + LCDC_CTRL);
-
- if (mxsfb->connector->display_info.num_bus_formats)
- bus_format = mxsfb->connector->display_info.bus_formats[0];
-
- DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
- bus_format);
-
- reg &= ~CTRL_BUS_WIDTH_MASK;
- switch (bus_format) {
- case MEDIA_BUS_FMT_RGB565_1X16:
- reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
- break;
- case MEDIA_BUS_FMT_RGB666_1X18:
- reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
- break;
- case MEDIA_BUS_FMT_RGB888_1X24:
- reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
- break;
- default:
- dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
- break;
- }
- writel(reg, mxsfb->base + LCDC_CTRL);
-}
-
-static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
-{
- u32 reg;
-
- if (mxsfb->clk_disp_axi)
- clk_prepare_enable(mxsfb->clk_disp_axi);
- clk_prepare_enable(mxsfb->clk);
-
- /* If it was disabled, re-enable the mode again */
- writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
-
- /* Enable the SYNC signals first, then the DMA engine */
- reg = readl(mxsfb->base + LCDC_VDCTRL4);
- reg |= VDCTRL4_SYNC_SIGNALS_ON;
- writel(reg, mxsfb->base + LCDC_VDCTRL4);
-
- writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
-}
-
-static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
-{
- u32 reg;
-
- /*
- * Even if we disable the controller here, it will still continue
- * until its FIFOs are running out of data
- */
- writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
-
- readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
- 0, 1000);
-
- reg = readl(mxsfb->base + LCDC_VDCTRL4);
- reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
- writel(reg, mxsfb->base + LCDC_VDCTRL4);
-
- clk_disable_unprepare(mxsfb->clk);
- if (mxsfb->clk_disp_axi)
- clk_disable_unprepare(mxsfb->clk_disp_axi);
-}
-
-/*
- * Clear the bit and poll it cleared. This is usually called with
- * a reset address and mask being either SFTRST(bit 31) or CLKGATE
- * (bit 30).
- */
-static int clear_poll_bit(void __iomem *addr, u32 mask)
-{
- u32 reg;
-
- writel(mask, addr + MXS_CLR_ADDR);
- return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
-}
-
-static int mxsfb_reset_block(void __iomem *reset_addr)
-{
- int ret;
-
- ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
- if (ret)
- return ret;
-
- writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
-
- ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
- if (ret)
- return ret;
-
- return clear_poll_bit(reset_addr, MODULE_CLKGATE);
-}
-
-static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb)
-{
- struct drm_framebuffer *fb = mxsfb->pipe.plane.state->fb;
- struct drm_gem_cma_object *gem;
-
- if (!fb)
- return 0;
-
- gem = drm_fb_cma_get_gem_obj(fb, 0);
- if (!gem)
- return 0;
-
- return gem->paddr;
-}
-
-static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
-{
- struct drm_device *drm = mxsfb->pipe.crtc.dev;
- struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
- u32 bus_flags = mxsfb->connector->display_info.bus_flags;
- u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
- int err;
-
- /*
- * It seems, you can't re-program the controller if it is still
- * running. This may lead to shifted pictures (FIFO issue?), so
- * first stop the controller and drain its FIFOs.
- */
-
- /* Mandatory eLCDIF reset as per the Reference Manual */
- err = mxsfb_reset_block(mxsfb->base);
- if (err)
- return;
-
- /* Clear the FIFOs */
- writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
-
- err = mxsfb_set_pixel_fmt(mxsfb);
- if (err)
- return;
-
- clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
-
- if (mxsfb->bridge && mxsfb->bridge->timings)
- bus_flags = mxsfb->bridge->timings->input_bus_flags;
-
- DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
- m->crtc_clock,
- (int)(clk_get_rate(mxsfb->clk) / 1000));
- DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
- bus_flags);
- DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
-
- writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
- TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
- mxsfb->base + mxsfb->devdata->transfer_count);
-
- vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
-
- vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */
- VDCTRL0_VSYNC_PERIOD_UNIT |
- VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
- VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
- if (m->flags & DRM_MODE_FLAG_PHSYNC)
- vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
- if (m->flags & DRM_MODE_FLAG_PVSYNC)
- vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
- /* Make sure Data Enable is high active by default */
- if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
- vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
- /*
- * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric,
- * controllers VDCTRL0_DOTCLK is display centric.
- * Drive on positive edge -> display samples on falling edge
- * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
- */
- if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
- vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
-
- writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
-
- mxsfb_set_bus_fmt(mxsfb);
-
- /* Frame length in lines. */
- writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
-
- /* Line length in units of clocks or pixels. */
- hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
- writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
- VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
- mxsfb->base + LCDC_VDCTRL2);
-
- writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
- SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
- mxsfb->base + LCDC_VDCTRL3);
-
- writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
- mxsfb->base + LCDC_VDCTRL4);
-}
-
-void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
-{
- dma_addr_t paddr;
-
- mxsfb_enable_axi_clk(mxsfb);
- mxsfb_crtc_mode_set_nofb(mxsfb);
-
- /* Write cur_buf as well to avoid an initial corrupt frame */
- paddr = mxsfb_get_fb_paddr(mxsfb);
- if (paddr) {
- writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
- writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
- }
-
- mxsfb_enable_controller(mxsfb);
-}
-
-void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
-{
- mxsfb_disable_controller(mxsfb);
- mxsfb_disable_axi_clk(mxsfb);
-}
-
-void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
- struct drm_plane_state *state)
-{
- struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
- struct drm_crtc *crtc = &pipe->crtc;
- struct drm_pending_vblank_event *event;
- dma_addr_t paddr;
-
- spin_lock_irq(&crtc->dev->event_lock);
- event = crtc->state->event;
- if (event) {
- crtc->state->event = NULL;
-
- if (drm_crtc_vblank_get(crtc) == 0) {
- drm_crtc_arm_vblank_event(crtc, event);
- } else {
- drm_crtc_send_vblank_event(crtc, event);
- }
- }
- spin_unlock_irq(&crtc->dev->event_lock);
-
- paddr = mxsfb_get_fb_paddr(mxsfb);
- if (paddr) {
- mxsfb_enable_axi_clk(mxsfb);
- writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
- mxsfb_disable_axi_clk(mxsfb);
- }
-}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
index 508764fccd27..35122aef037b 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -9,30 +9,25 @@
*/
#include <linux/clk.h>
-#include <linux/component.h>
#include <linux/dma-mapping.h>
-#include <linux/list.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
-#include <linux/of_graph.h>
-#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <linux/dma-resv.h>
-#include <linux/spinlock.h>
-#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_irq.h>
+#include <drm/drm_mode_config.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_vblank.h>
#include "mxsfb_drv.h"
@@ -41,6 +36,11 @@
enum mxsfb_devtype {
MXSFB_V3,
MXSFB_V4,
+ /*
+ * Starting at i.MX6 the hardware version register is gone, use the
+ * i.MX family number as the version.
+ */
+ MXSFB_V6,
};
static const struct mxsfb_devdata mxsfb_devdata[] = {
@@ -48,38 +48,28 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
.transfer_count = LCDC_V3_TRANSFER_COUNT,
.cur_buf = LCDC_V3_CUR_BUF,
.next_buf = LCDC_V3_NEXT_BUF,
- .debug0 = LCDC_V3_DEBUG0,
.hs_wdth_mask = 0xff,
.hs_wdth_shift = 24,
- .ipversion = 3,
+ .has_overlay = false,
},
[MXSFB_V4] = {
.transfer_count = LCDC_V4_TRANSFER_COUNT,
.cur_buf = LCDC_V4_CUR_BUF,
.next_buf = LCDC_V4_NEXT_BUF,
- .debug0 = LCDC_V4_DEBUG0,
.hs_wdth_mask = 0x3fff,
.hs_wdth_shift = 18,
- .ipversion = 4,
+ .has_overlay = false,
+ },
+ [MXSFB_V6] = {
+ .transfer_count = LCDC_V4_TRANSFER_COUNT,
+ .cur_buf = LCDC_V4_CUR_BUF,
+ .next_buf = LCDC_V4_NEXT_BUF,
+ .hs_wdth_mask = 0x3fff,
+ .hs_wdth_shift = 18,
+ .has_overlay = true,
},
};
-static const uint32_t mxsfb_formats[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_RGB565
-};
-
-static const uint64_t mxsfb_modifiers[] = {
- DRM_FORMAT_MOD_LINEAR,
- DRM_FORMAT_MOD_INVALID
-};
-
-static struct mxsfb_drm_private *
-drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
-{
- return container_of(pipe, struct mxsfb_drm_private, pipe);
-}
-
void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb)
{
if (mxsfb->clk_axi)
@@ -92,8 +82,26 @@ void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb)
clk_disable_unprepare(mxsfb->clk_axi);
}
+static struct drm_framebuffer *
+mxsfb_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ const struct drm_format_info *info;
+
+ info = drm_get_format_info(dev, mode_cmd);
+ if (!info)
+ return ERR_PTR(-EINVAL);
+
+ if (mode_cmd->width * info->cpp[0] != mode_cmd->pitches[0]) {
+ dev_dbg(dev->dev, "Invalid pitch: fb width must match pitch\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return drm_gem_fb_create(dev, file_priv, mode_cmd);
+}
+
static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = {
- .fb_create = drm_gem_fb_create,
+ .fb_create = mxsfb_fb_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
@@ -102,101 +110,51 @@ static const struct drm_mode_config_helper_funcs mxsfb_mode_config_helpers = {
.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
};
-static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
- struct drm_crtc_state *crtc_state,
- struct drm_plane_state *plane_state)
+static int mxsfb_attach_bridge(struct mxsfb_drm_private *mxsfb)
{
- struct drm_connector *connector;
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
- struct drm_device *drm = pipe->plane.dev;
-
- if (!mxsfb->connector) {
- list_for_each_entry(connector,
- &drm->mode_config.connector_list,
- head)
- if (connector->encoder == &mxsfb->pipe.encoder) {
- mxsfb->connector = connector;
- break;
- }
- }
-
- if (!mxsfb->connector) {
- dev_warn(drm->dev, "No connector attached, using default\n");
- mxsfb->connector = &mxsfb->panel_connector;
- }
-
- pm_runtime_get_sync(drm->dev);
- drm_panel_prepare(mxsfb->panel);
- mxsfb_crtc_enable(mxsfb);
- drm_panel_enable(mxsfb->panel);
-}
+ struct drm_device *drm = mxsfb->drm;
+ struct drm_connector_list_iter iter;
+ struct drm_panel *panel;
+ struct drm_bridge *bridge;
+ int ret;
-static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
-{
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
- struct drm_device *drm = pipe->plane.dev;
- 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);
- pm_runtime_put_sync(drm->dev);
+ ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel,
+ &bridge);
+ if (ret)
+ return ret;
- spin_lock_irq(&drm->event_lock);
- event = crtc->state->event;
- if (event) {
- crtc->state->event = NULL;
- drm_crtc_send_vblank_event(crtc, event);
+ if (panel) {
+ bridge = devm_drm_panel_bridge_add_typed(drm->dev, panel,
+ DRM_MODE_CONNECTOR_DPI);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
}
- spin_unlock_irq(&drm->event_lock);
-
- if (mxsfb->connector != &mxsfb->panel_connector)
- mxsfb->connector = NULL;
-}
-static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state)
-{
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+ if (!bridge)
+ return -ENODEV;
- mxsfb_plane_atomic_update(mxsfb, plane_state);
-}
+ ret = drm_bridge_attach(&mxsfb->encoder, bridge, NULL, 0);
+ if (ret) {
+ DRM_DEV_ERROR(drm->dev,
+ "failed to attach bridge: %d\n", ret);
+ return ret;
+ }
-static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe)
-{
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+ mxsfb->bridge = bridge;
- /* Clear and enable VBLANK IRQ */
- mxsfb_enable_axi_clk(mxsfb);
- 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);
- mxsfb_disable_axi_clk(mxsfb);
+ /*
+ * Get hold of the connector. This is a bit of a hack, until the bridge
+ * API gives us bus flags and formats.
+ */
+ drm_connector_list_iter_begin(drm, &iter);
+ mxsfb->connector = drm_connector_list_iter_next(&iter);
+ drm_connector_list_iter_end(&iter);
return 0;
}
-static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe)
-{
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
-
- /* Disable and clear VBLANK IRQ */
- mxsfb_enable_axi_clk(mxsfb);
- 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);
- mxsfb_disable_axi_clk(mxsfb);
-}
-
-static struct drm_simple_display_pipe_funcs mxsfb_funcs = {
- .enable = mxsfb_pipe_enable,
- .disable = mxsfb_pipe_disable,
- .update = mxsfb_pipe_update,
- .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
- .enable_vblank = mxsfb_pipe_enable_vblank,
- .disable_vblank = mxsfb_pipe_disable_vblank,
-};
-
-static int mxsfb_load(struct drm_device *drm)
+static int mxsfb_load(struct drm_device *drm,
+ const struct mxsfb_devdata *devdata)
{
struct platform_device *pdev = to_platform_device(drm->dev);
struct mxsfb_drm_private *mxsfb;
@@ -207,8 +165,9 @@ static int mxsfb_load(struct drm_device *drm)
if (!mxsfb)
return -ENOMEM;
+ mxsfb->drm = drm;
drm->dev_private = mxsfb;
- mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+ mxsfb->devdata = devdata;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mxsfb->base = devm_ioremap_resource(drm->dev, res);
@@ -233,50 +192,28 @@ static int mxsfb_load(struct drm_device *drm)
pm_runtime_enable(drm->dev);
- ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
- if (ret < 0) {
- dev_err(drm->dev, "Failed to initialise vblank\n");
- goto err_vblank;
- }
-
/* Modeset init */
drm_mode_config_init(drm);
- ret = mxsfb_create_output(drm);
+ ret = mxsfb_kms_init(mxsfb);
if (ret < 0) {
- dev_err(drm->dev, "Failed to create outputs\n");
+ dev_err(drm->dev, "Failed to initialize KMS pipeline\n");
goto err_vblank;
}
- ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
- mxsfb_formats, ARRAY_SIZE(mxsfb_formats),
- mxsfb_modifiers, mxsfb->connector);
+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (ret < 0) {
- dev_err(drm->dev, "Cannot setup simple display pipe\n");
+ dev_err(drm->dev, "Failed to initialise vblank\n");
goto err_vblank;
}
- /*
- * Attach panel only if there is one.
- * If there is no panel attach, it must be a bridge. In this case, we
- * need a reference to its connector for a proper initialization.
- * We will do this check in pipe->enable(), since the connector won't
- * be attached to an encoder until then.
- */
+ /* Start with vertical blanking interrupt reporting disabled. */
+ drm_crtc_vblank_off(&mxsfb->crtc);
- if (mxsfb->panel) {
- ret = drm_panel_attach(mxsfb->panel, mxsfb->connector);
- if (ret) {
- dev_err(drm->dev, "Cannot connect panel: %d\n", ret);
- goto err_vblank;
- }
- } else if (mxsfb->bridge) {
- ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe,
- mxsfb->bridge);
- if (ret) {
- dev_err(drm->dev, "Cannot connect bridge: %d\n", ret);
- goto err_vblank;
- }
+ ret = mxsfb_attach_bridge(mxsfb);
+ if (ret) {
+ dev_err(drm->dev, "Cannot connect bridge: %d\n", ret);
+ goto err_vblank;
}
drm->mode_config.min_width = MXSFB_MIN_XRES;
@@ -294,7 +231,7 @@ static int mxsfb_load(struct drm_device *drm)
if (ret < 0) {
dev_err(drm->dev, "Failed to install IRQ handler\n");
- goto err_irq;
+ goto err_vblank;
}
drm_kms_helper_poll_init(drm);
@@ -305,8 +242,6 @@ static int mxsfb_load(struct drm_device *drm)
return 0;
-err_irq:
- drm_panel_detach(mxsfb->panel);
err_vblank:
pm_runtime_disable(drm->dev);
@@ -327,11 +262,13 @@ static void mxsfb_unload(struct drm_device *drm)
pm_runtime_disable(drm->dev);
}
-static void mxsfb_irq_preinstall(struct drm_device *drm)
+static void mxsfb_irq_disable(struct drm_device *drm)
{
struct mxsfb_drm_private *mxsfb = drm->dev_private;
- mxsfb_pipe_disable_vblank(&mxsfb->pipe);
+ mxsfb_enable_axi_clk(mxsfb);
+ mxsfb->crtc.funcs->disable_vblank(&mxsfb->crtc);
+ mxsfb_disable_axi_clk(mxsfb);
}
static irqreturn_t mxsfb_irq_handler(int irq, void *data)
@@ -340,17 +277,13 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *data)
struct mxsfb_drm_private *mxsfb = drm->dev_private;
u32 reg;
- mxsfb_enable_axi_clk(mxsfb);
-
reg = readl(mxsfb->base + LCDC_CTRL1);
if (reg & CTRL1_CUR_FRAME_DONE_IRQ)
- drm_crtc_handle_vblank(&mxsfb->pipe.crtc);
+ drm_crtc_handle_vblank(&mxsfb->crtc);
writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
- mxsfb_disable_axi_clk(mxsfb);
-
return IRQ_HANDLED;
}
@@ -359,8 +292,8 @@ DEFINE_DRM_GEM_CMA_FOPS(fops);
static struct drm_driver mxsfb_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
.irq_handler = mxsfb_irq_handler,
- .irq_preinstall = mxsfb_irq_preinstall,
- .irq_uninstall = mxsfb_irq_preinstall,
+ .irq_preinstall = mxsfb_irq_disable,
+ .irq_uninstall = mxsfb_irq_disable,
DRM_GEM_CMA_DRIVER_OPS,
.fops = &fops,
.name = "mxsfb-drm",
@@ -370,18 +303,10 @@ static struct drm_driver mxsfb_driver = {
.minor = 0,
};
-static const struct platform_device_id mxsfb_devtype[] = {
- { .name = "imx23-fb", .driver_data = MXSFB_V3, },
- { .name = "imx28-fb", .driver_data = MXSFB_V4, },
- { .name = "imx6sx-fb", .driver_data = MXSFB_V4, },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
-
static const struct of_device_id mxsfb_dt_ids[] = {
- { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
- { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
- { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devtype[2], },
+ { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devdata[MXSFB_V3], },
+ { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devdata[MXSFB_V4], },
+ { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devdata[MXSFB_V6], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
@@ -396,14 +321,11 @@ static int mxsfb_probe(struct platform_device *pdev)
if (!pdev->dev.of_node)
return -ENODEV;
- if (of_id)
- pdev->id_entry = of_id->data;
-
drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev);
if (IS_ERR(drm))
return PTR_ERR(drm);
- ret = mxsfb_load(drm);
+ ret = mxsfb_load(drm, of_id->data);
if (ret)
goto err_free;
@@ -457,7 +379,6 @@ static const struct dev_pm_ops mxsfb_pm_ops = {
static struct platform_driver mxsfb_platform_driver = {
.probe = mxsfb_probe,
.remove = mxsfb_remove,
- .id_table = mxsfb_devtype,
.driver = {
.name = "mxsfb",
.of_match_table = mxsfb_dt_ids,
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
index 0b65b5194a9c..399d23e91ed1 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
@@ -8,14 +8,20 @@
#ifndef __MXSFB_DRV_H__
#define __MXSFB_DRV_H__
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_plane.h>
+
+struct clk;
+
struct mxsfb_devdata {
- unsigned int transfer_count;
- unsigned int cur_buf;
- unsigned int next_buf;
- unsigned int debug0;
- unsigned int hs_wdth_mask;
- unsigned int hs_wdth_shift;
- unsigned int ipversion;
+ unsigned int transfer_count;
+ unsigned int cur_buf;
+ unsigned int next_buf;
+ unsigned int hs_wdth_mask;
+ unsigned int hs_wdth_shift;
+ bool has_overlay;
};
struct mxsfb_drm_private {
@@ -26,22 +32,26 @@ struct mxsfb_drm_private {
struct clk *clk_axi;
struct clk *clk_disp_axi;
- struct drm_simple_display_pipe pipe;
- struct drm_connector panel_connector;
+ struct drm_device *drm;
+ struct {
+ struct drm_plane primary;
+ struct drm_plane overlay;
+ } planes;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
struct drm_connector *connector;
- struct drm_panel *panel;
struct drm_bridge *bridge;
};
-int mxsfb_setup_crtc(struct drm_device *dev);
-int mxsfb_create_output(struct drm_device *dev);
+static inline struct mxsfb_drm_private *
+to_mxsfb_drm_private(struct drm_device *drm)
+{
+ return drm->dev_private;
+}
void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb);
void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb);
-void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb);
-void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb);
-void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
- struct drm_plane_state *state);
+int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb);
#endif /* __MXSFB_DRV_H__ */
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_kms.c b/drivers/gpu/drm/mxsfb/mxsfb_kms.c
new file mode 100644
index 000000000000..b721b8b262ce
--- /dev/null
+++ b/drivers/gpu/drm/mxsfb/mxsfb_kms.c
@@ -0,0 +1,571 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * This code is based on drivers/video/fbdev/mxsfb.c :
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "mxsfb_drv.h"
+#include "mxsfb_regs.h"
+
+/* 1 second delay should be plenty of time for block reset */
+#define RESET_TIMEOUT 1000000
+
+/* -----------------------------------------------------------------------------
+ * CRTC
+ */
+
+static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
+{
+ return (val & mxsfb->devdata->hs_wdth_mask) <<
+ mxsfb->devdata->hs_wdth_shift;
+}
+
+/*
+ * Setup the MXSFB registers for decoding the pixels out of the framebuffer and
+ * outputting them on the bus.
+ */
+static void mxsfb_set_formats(struct mxsfb_drm_private *mxsfb)
+{
+ struct drm_device *drm = mxsfb->drm;
+ const u32 format = mxsfb->crtc.primary->state->fb->format->format;
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ u32 ctrl, ctrl1;
+
+ if (mxsfb->connector->display_info.num_bus_formats)
+ bus_format = mxsfb->connector->display_info.bus_formats[0];
+
+ DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
+ bus_format);
+
+ ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
+
+ /* CTRL1 contains IRQ config and status bits, preserve those. */
+ ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
+ ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
+
+ switch (format) {
+ case DRM_FORMAT_RGB565:
+ dev_dbg(drm->dev, "Setting up RGB565 mode\n");
+ ctrl |= CTRL_WORD_LENGTH_16;
+ ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
+ break;
+ case DRM_FORMAT_XRGB8888:
+ dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
+ ctrl |= CTRL_WORD_LENGTH_24;
+ /* Do not use packed pixels = one pixel per word instead. */
+ ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
+ break;
+ }
+
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ ctrl |= CTRL_BUS_WIDTH_16;
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ ctrl |= CTRL_BUS_WIDTH_18;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ ctrl |= CTRL_BUS_WIDTH_24;
+ break;
+ default:
+ dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
+ break;
+ }
+
+ writel(ctrl1, mxsfb->base + LCDC_CTRL1);
+ writel(ctrl, mxsfb->base + LCDC_CTRL);
+}
+
+static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
+{
+ u32 reg;
+
+ if (mxsfb->clk_disp_axi)
+ clk_prepare_enable(mxsfb->clk_disp_axi);
+ clk_prepare_enable(mxsfb->clk);
+
+ /* If it was disabled, re-enable the mode again */
+ writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
+
+ /* Enable the SYNC signals first, then the DMA engine */
+ reg = readl(mxsfb->base + LCDC_VDCTRL4);
+ reg |= VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+ writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
+}
+
+static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
+{
+ u32 reg;
+
+ /*
+ * Even if we disable the controller here, it will still continue
+ * until its FIFOs are running out of data
+ */
+ writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+ readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
+ 0, 1000);
+
+ reg = readl(mxsfb->base + LCDC_VDCTRL4);
+ reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+ clk_disable_unprepare(mxsfb->clk);
+ if (mxsfb->clk_disp_axi)
+ clk_disable_unprepare(mxsfb->clk_disp_axi);
+}
+
+/*
+ * Clear the bit and poll it cleared. This is usually called with
+ * a reset address and mask being either SFTRST(bit 31) or CLKGATE
+ * (bit 30).
+ */
+static int clear_poll_bit(void __iomem *addr, u32 mask)
+{
+ u32 reg;
+
+ writel(mask, addr + REG_CLR);
+ return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
+}
+
+static int mxsfb_reset_block(struct mxsfb_drm_private *mxsfb)
+{
+ int ret;
+
+ ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
+ if (ret)
+ return ret;
+
+ writel(CTRL_CLKGATE, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+ ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
+ if (ret)
+ return ret;
+
+ return clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_CLKGATE);
+}
+
+static dma_addr_t mxsfb_get_fb_paddr(struct drm_plane *plane)
+{
+ struct drm_framebuffer *fb = plane->state->fb;
+ struct drm_gem_cma_object *gem;
+
+ if (!fb)
+ return 0;
+
+ gem = drm_fb_cma_get_gem_obj(fb, 0);
+ if (!gem)
+ return 0;
+
+ return gem->paddr;
+}
+
+static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
+{
+ struct drm_device *drm = mxsfb->crtc.dev;
+ struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode;
+ u32 bus_flags = mxsfb->connector->display_info.bus_flags;
+ u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
+ int err;
+
+ /*
+ * It seems, you can't re-program the controller if it is still
+ * running. This may lead to shifted pictures (FIFO issue?), so
+ * first stop the controller and drain its FIFOs.
+ */
+
+ /* Mandatory eLCDIF reset as per the Reference Manual */
+ err = mxsfb_reset_block(mxsfb);
+ if (err)
+ return;
+
+ /* Clear the FIFOs */
+ writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
+
+ if (mxsfb->devdata->has_overlay)
+ writel(0, mxsfb->base + LCDC_AS_CTRL);
+
+ mxsfb_set_formats(mxsfb);
+
+ clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
+
+ if (mxsfb->bridge && mxsfb->bridge->timings)
+ bus_flags = mxsfb->bridge->timings->input_bus_flags;
+
+ DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
+ m->crtc_clock,
+ (int)(clk_get_rate(mxsfb->clk) / 1000));
+ DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
+ bus_flags);
+ DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
+
+ writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
+ TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
+ mxsfb->base + mxsfb->devdata->transfer_count);
+
+ vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
+
+ vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */
+ VDCTRL0_VSYNC_PERIOD_UNIT |
+ VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
+ VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
+ if (m->flags & DRM_MODE_FLAG_PHSYNC)
+ vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+ if (m->flags & DRM_MODE_FLAG_PVSYNC)
+ vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+ /* Make sure Data Enable is high active by default */
+ if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
+ vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+ /*
+ * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric,
+ * controllers VDCTRL0_DOTCLK is display centric.
+ * Drive on positive edge -> display samples on falling edge
+ * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
+ */
+ if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
+ vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
+
+ writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
+
+ /* Frame length in lines. */
+ writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
+
+ /* Line length in units of clocks or pixels. */
+ hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
+ writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
+ VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
+ mxsfb->base + LCDC_VDCTRL2);
+
+ writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
+ SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
+ mxsfb->base + LCDC_VDCTRL3);
+
+ writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
+ mxsfb->base + LCDC_VDCTRL4);
+}
+
+static int mxsfb_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ bool has_primary = state->plane_mask &
+ drm_plane_mask(crtc->primary);
+
+ /* The primary plane has to be enabled when the CRTC is active. */
+ if (state->active && !has_primary)
+ return -EINVAL;
+
+ /* TODO: Is this needed ? */
+ return drm_atomic_add_affected_planes(state->state, crtc);
+}
+
+static void mxsfb_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct drm_pending_vblank_event *event;
+
+ event = crtc->state->event;
+ crtc->state->event = NULL;
+
+ if (!event)
+ return;
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (drm_crtc_vblank_get(crtc) == 0)
+ drm_crtc_arm_vblank_event(crtc, event);
+ else
+ drm_crtc_send_vblank_event(crtc, event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+ struct drm_device *drm = mxsfb->drm;
+ dma_addr_t paddr;
+
+ pm_runtime_get_sync(drm->dev);
+ mxsfb_enable_axi_clk(mxsfb);
+
+ drm_crtc_vblank_on(crtc);
+
+ mxsfb_crtc_mode_set_nofb(mxsfb);
+
+ /* Write cur_buf as well to avoid an initial corrupt frame */
+ paddr = mxsfb_get_fb_paddr(crtc->primary);
+ if (paddr) {
+ writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
+ writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
+ }
+
+ mxsfb_enable_controller(mxsfb);
+}
+
+static void mxsfb_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+ struct drm_device *drm = mxsfb->drm;
+ struct drm_pending_vblank_event *event;
+
+ mxsfb_disable_controller(mxsfb);
+
+ spin_lock_irq(&drm->event_lock);
+ event = crtc->state->event;
+ if (event) {
+ crtc->state->event = NULL;
+ drm_crtc_send_vblank_event(crtc, event);
+ }
+ spin_unlock_irq(&drm->event_lock);
+
+ drm_crtc_vblank_off(crtc);
+
+ mxsfb_disable_axi_clk(mxsfb);
+ pm_runtime_put_sync(drm->dev);
+}
+
+static int mxsfb_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+
+ /* 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);
+
+ return 0;
+}
+
+static void mxsfb_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
+
+ /* 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);
+}
+
+static const struct drm_crtc_helper_funcs mxsfb_crtc_helper_funcs = {
+ .atomic_check = mxsfb_crtc_atomic_check,
+ .atomic_flush = mxsfb_crtc_atomic_flush,
+ .atomic_enable = mxsfb_crtc_atomic_enable,
+ .atomic_disable = mxsfb_crtc_atomic_disable,
+};
+
+static const struct drm_crtc_funcs mxsfb_crtc_funcs = {
+ .reset = drm_atomic_helper_crtc_reset,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = mxsfb_crtc_enable_vblank,
+ .disable_vblank = mxsfb_crtc_disable_vblank,
+};
+
+/* -----------------------------------------------------------------------------
+ * Encoder
+ */
+
+static const struct drm_encoder_funcs mxsfb_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+/* -----------------------------------------------------------------------------
+ * Planes
+ */
+
+static int mxsfb_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *plane_state)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
+ struct drm_crtc_state *crtc_state;
+
+ crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
+ &mxsfb->crtc);
+
+ return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ false, true);
+}
+
+static void mxsfb_plane_primary_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_pstate)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
+ dma_addr_t paddr;
+
+ paddr = mxsfb_get_fb_paddr(plane);
+ if (paddr)
+ writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
+}
+
+static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_pstate)
+{
+ struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
+ struct drm_plane_state *state = plane->state;
+ dma_addr_t paddr;
+ u32 ctrl;
+
+ paddr = mxsfb_get_fb_paddr(plane);
+ if (!paddr) {
+ writel(0, mxsfb->base + LCDC_AS_CTRL);
+ return;
+ }
+
+ /*
+ * HACK: The hardware seems to output 64 bytes of data of unknown
+ * origin, and then to proceed with the framebuffer. Until the reason
+ * is understood, live with the 16 initial invalid pixels on the first
+ * line and start 64 bytes within the framebuffer.
+ */
+ paddr += 64;
+
+ writel(paddr, mxsfb->base + LCDC_AS_NEXT_BUF);
+
+ /*
+ * If the plane was previously disabled, write LCDC_AS_BUF as well to
+ * provide the first buffer.
+ */
+ if (!old_pstate->fb)
+ writel(paddr, mxsfb->base + LCDC_AS_BUF);
+
+ ctrl = AS_CTRL_AS_ENABLE | AS_CTRL_ALPHA(255);
+
+ switch (state->fb->format->format) {
+ case DRM_FORMAT_XRGB4444:
+ ctrl |= AS_CTRL_FORMAT_RGB444 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+ break;
+ case DRM_FORMAT_ARGB4444:
+ ctrl |= AS_CTRL_FORMAT_ARGB4444 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
+ break;
+ case DRM_FORMAT_XRGB1555:
+ ctrl |= AS_CTRL_FORMAT_RGB555 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+ break;
+ case DRM_FORMAT_ARGB1555:
+ ctrl |= AS_CTRL_FORMAT_ARGB1555 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
+ break;
+ case DRM_FORMAT_RGB565:
+ ctrl |= AS_CTRL_FORMAT_RGB565 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+ break;
+ case DRM_FORMAT_XRGB8888:
+ ctrl |= AS_CTRL_FORMAT_RGB888 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
+ break;
+ case DRM_FORMAT_ARGB8888:
+ ctrl |= AS_CTRL_FORMAT_ARGB8888 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
+ break;
+ }
+
+ writel(ctrl, mxsfb->base + LCDC_AS_CTRL);
+}
+
+static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = {
+ .atomic_check = mxsfb_plane_atomic_check,
+ .atomic_update = mxsfb_plane_primary_atomic_update,
+};
+
+static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = {
+ .atomic_check = mxsfb_plane_atomic_check,
+ .atomic_update = mxsfb_plane_overlay_atomic_update,
+};
+
+static const struct drm_plane_funcs mxsfb_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_plane_cleanup,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static const uint32_t mxsfb_primary_plane_formats[] = {
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XRGB8888,
+};
+
+static const uint32_t mxsfb_overlay_plane_formats[] = {
+ DRM_FORMAT_XRGB4444,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+};
+
+static const uint64_t mxsfb_modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb)
+{
+ struct drm_encoder *encoder = &mxsfb->encoder;
+ struct drm_crtc *crtc = &mxsfb->crtc;
+ int ret;
+
+ drm_plane_helper_add(&mxsfb->planes.primary,
+ &mxsfb_plane_primary_helper_funcs);
+ ret = drm_universal_plane_init(mxsfb->drm, &mxsfb->planes.primary, 1,
+ &mxsfb_plane_funcs,
+ mxsfb_primary_plane_formats,
+ ARRAY_SIZE(mxsfb_primary_plane_formats),
+ mxsfb_modifiers, DRM_PLANE_TYPE_PRIMARY,
+ NULL);
+ if (ret)
+ return ret;
+
+ if (mxsfb->devdata->has_overlay) {
+ drm_plane_helper_add(&mxsfb->planes.overlay,
+ &mxsfb_plane_overlay_helper_funcs);
+ ret = drm_universal_plane_init(mxsfb->drm,
+ &mxsfb->planes.overlay, 1,
+ &mxsfb_plane_funcs,
+ mxsfb_overlay_plane_formats,
+ ARRAY_SIZE(mxsfb_overlay_plane_formats),
+ mxsfb_modifiers, DRM_PLANE_TYPE_OVERLAY,
+ NULL);
+ if (ret)
+ return ret;
+ }
+
+ drm_crtc_helper_add(crtc, &mxsfb_crtc_helper_funcs);
+ ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
+ &mxsfb->planes.primary, NULL,
+ &mxsfb_crtc_funcs, NULL);
+ if (ret)
+ return ret;
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ return drm_encoder_init(mxsfb->drm, encoder, &mxsfb_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
+}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c
deleted file mode 100644
index 9eca1605d11d..000000000000
--- a/drivers/gpu/drm/mxsfb/mxsfb_out.c
+++ /dev/null
@@ -1,99 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Marek Vasut <marex@denx.de>
- */
-
-#include <linux/of_graph.h>
-
-#include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
-
-#include "mxsfb_drv.h"
-
-static struct mxsfb_drm_private *
-drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
-{
- return container_of(connector, struct mxsfb_drm_private,
- panel_connector);
-}
-
-static int mxsfb_panel_get_modes(struct drm_connector *connector)
-{
- struct mxsfb_drm_private *mxsfb =
- drm_connector_to_mxsfb_drm_private(connector);
-
- if (mxsfb->panel)
- return drm_panel_get_modes(mxsfb->panel, connector);
-
- return 0;
-}
-
-static const struct
-drm_connector_helper_funcs mxsfb_panel_connector_helper_funcs = {
- .get_modes = mxsfb_panel_get_modes,
-};
-
-static enum drm_connector_status
-mxsfb_panel_connector_detect(struct drm_connector *connector, bool force)
-{
- struct mxsfb_drm_private *mxsfb =
- drm_connector_to_mxsfb_drm_private(connector);
-
- if (mxsfb->panel)
- return connector_status_connected;
-
- return connector_status_disconnected;
-}
-
-static void mxsfb_panel_connector_destroy(struct drm_connector *connector)
-{
- struct mxsfb_drm_private *mxsfb =
- drm_connector_to_mxsfb_drm_private(connector);
-
- if (mxsfb->panel)
- drm_panel_detach(mxsfb->panel);
-
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
-}
-
-static const struct drm_connector_funcs mxsfb_panel_connector_funcs = {
- .detect = mxsfb_panel_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = mxsfb_panel_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-int mxsfb_create_output(struct drm_device *drm)
-{
- struct mxsfb_drm_private *mxsfb = drm->dev_private;
- int ret;
-
- ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0,
- &mxsfb->panel, &mxsfb->bridge);
- if (ret)
- return ret;
-
- if (mxsfb->panel) {
- mxsfb->connector = &mxsfb->panel_connector;
- mxsfb->connector->dpms = DRM_MODE_DPMS_OFF;
- mxsfb->connector->polled = 0;
- drm_connector_helper_add(mxsfb->connector,
- &mxsfb_panel_connector_helper_funcs);
- ret = drm_connector_init(drm, mxsfb->connector,
- &mxsfb_panel_connector_funcs,
- DRM_MODE_CONNECTOR_Unknown);
- }
-
- return ret;
-}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_regs.h b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
index 932d7ea08fd5..55d28a27f912 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_regs.h
+++ b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
@@ -27,52 +27,61 @@
#define LCDC_VDCTRL4 0xb0
#define LCDC_V4_DEBUG0 0x1d0
#define LCDC_V3_DEBUG0 0x1f0
-
-#define CTRL_SFTRST (1 << 31)
-#define CTRL_CLKGATE (1 << 30)
-#define CTRL_BYPASS_COUNT (1 << 19)
-#define CTRL_VSYNC_MODE (1 << 18)
-#define CTRL_DOTCLK_MODE (1 << 17)
-#define CTRL_DATA_SELECT (1 << 16)
-#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10)
-#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3)
+#define LCDC_AS_CTRL 0x210
+#define LCDC_AS_BUF 0x220
+#define LCDC_AS_NEXT_BUF 0x230
+#define LCDC_AS_CLRKEYLOW 0x240
+#define LCDC_AS_CLRKEYHIGH 0x250
+
+#define CTRL_SFTRST BIT(31)
+#define CTRL_CLKGATE BIT(30)
+#define CTRL_BYPASS_COUNT BIT(19)
+#define CTRL_VSYNC_MODE BIT(18)
+#define CTRL_DOTCLK_MODE BIT(17)
+#define CTRL_DATA_SELECT BIT(16)
+#define CTRL_BUS_WIDTH_16 (0 << 10)
+#define CTRL_BUS_WIDTH_8 (1 << 10)
+#define CTRL_BUS_WIDTH_18 (2 << 10)
+#define CTRL_BUS_WIDTH_24 (3 << 10)
#define CTRL_BUS_WIDTH_MASK (0x3 << 10)
-#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8)
-#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3)
-#define CTRL_MASTER (1 << 5)
-#define CTRL_DF16 (1 << 3)
-#define CTRL_DF18 (1 << 2)
-#define CTRL_DF24 (1 << 1)
-#define CTRL_RUN (1 << 0)
-
-#define CTRL1_FIFO_CLEAR (1 << 21)
+#define CTRL_WORD_LENGTH_16 (0 << 8)
+#define CTRL_WORD_LENGTH_8 (1 << 8)
+#define CTRL_WORD_LENGTH_18 (2 << 8)
+#define CTRL_WORD_LENGTH_24 (3 << 8)
+#define CTRL_MASTER BIT(5)
+#define CTRL_DF16 BIT(3)
+#define CTRL_DF18 BIT(2)
+#define CTRL_DF24 BIT(1)
+#define CTRL_RUN BIT(0)
+
+#define CTRL1_FIFO_CLEAR BIT(21)
#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
-#define CTRL1_CUR_FRAME_DONE_IRQ_EN (1 << 13)
-#define CTRL1_CUR_FRAME_DONE_IRQ (1 << 9)
+#define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13)
+#define CTRL1_CUR_FRAME_DONE_IRQ BIT(9)
#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff)
#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff)
-#define VDCTRL0_ENABLE_PRESENT (1 << 28)
-#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27)
-#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26)
-#define VDCTRL0_DOTCLK_ACT_FALLING (1 << 25)
-#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24)
-#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21)
-#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20)
-#define VDCTRL0_HALF_LINE (1 << 19)
-#define VDCTRL0_HALF_LINE_MODE (1 << 18)
+#define VDCTRL0_ENABLE_PRESENT BIT(28)
+#define VDCTRL0_VSYNC_ACT_HIGH BIT(27)
+#define VDCTRL0_HSYNC_ACT_HIGH BIT(26)
+#define VDCTRL0_DOTCLK_ACT_FALLING BIT(25)
+#define VDCTRL0_ENABLE_ACT_HIGH BIT(24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT BIT(21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT BIT(20)
+#define VDCTRL0_HALF_LINE BIT(19)
+#define VDCTRL0_HALF_LINE_MODE BIT(18)
#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
-#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29)
-#define VDCTRL3_VSYNC_ONLY (1 << 28)
+#define VDCTRL3_MUX_SYNC_SIGNALS BIT(29)
+#define VDCTRL3_VSYNC_ONLY BIT(28)
#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16)
#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff)
#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff)
@@ -80,28 +89,32 @@
#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */
#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */
-#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18)
+#define VDCTRL4_SYNC_SIGNALS_ON BIT(18)
#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
-#define DEBUG0_HSYNC (1 < 26)
-#define DEBUG0_VSYNC (1 < 25)
+#define DEBUG0_HSYNC BIT(26)
+#define DEBUG0_VSYNC BIT(25)
+
+#define AS_CTRL_PS_DISABLE BIT(23)
+#define AS_CTRL_ALPHA_INVERT BIT(20)
+#define AS_CTRL_ALPHA(a) (((a) & 0xff) << 8)
+#define AS_CTRL_FORMAT_RGB565 (0xe << 4)
+#define AS_CTRL_FORMAT_RGB444 (0xd << 4)
+#define AS_CTRL_FORMAT_RGB555 (0xc << 4)
+#define AS_CTRL_FORMAT_ARGB4444 (0x9 << 4)
+#define AS_CTRL_FORMAT_ARGB1555 (0x8 << 4)
+#define AS_CTRL_FORMAT_RGB888 (0x4 << 4)
+#define AS_CTRL_FORMAT_ARGB8888 (0x0 << 4)
+#define AS_CTRL_ENABLE_COLORKEY BIT(3)
+#define AS_CTRL_ALPHA_CTRL_ROP (3 << 1)
+#define AS_CTRL_ALPHA_CTRL_MULTIPLY (2 << 1)
+#define AS_CTRL_ALPHA_CTRL_OVERRIDE (1 << 1)
+#define AS_CTRL_ALPHA_CTRL_EMBEDDED (0 << 1)
+#define AS_CTRL_AS_ENABLE BIT(0)
#define MXSFB_MIN_XRES 120
#define MXSFB_MIN_YRES 120
#define MXSFB_MAX_XRES 0xffff
#define MXSFB_MAX_YRES 0xffff
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define TRANSP 3
-
-#define STMLCDIF_8BIT 1 /* pixel data bus to the display is of 8 bit width */
-#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */
-#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
-#define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */
-
-#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6)
-#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negative edge sampling */
-
#endif /* __MXSFB_REGS_H__ */