diff options
author | Dong Aisheng <aisheng.dong@nxp.com> | 2019-12-02 18:01:09 +0800 |
---|---|---|
committer | Dong Aisheng <aisheng.dong@nxp.com> | 2019-12-02 18:01:09 +0800 |
commit | 34ac946b631c67b53ef70aaf8b3856fe5d3a3b43 (patch) | |
tree | d60361cf052915e49582b8daa7f5d2c5daec7877 | |
parent | ce491fc5a6384f447770b2dee096f5b69f174f36 (diff) | |
parent | 327e1daa6e313c60d978a07ce18d32e75860f523 (diff) |
Merge remote-tracking branch 'origin/display/mxsfb' into display/next
* origin/display/mxsfb: (14 commits)
drm/mxsfb: Add support for live pixel format change
drm/mxsfb: Add support for horizontal stride
drm/mxsfb: Clear OUTSTANDING_REQS bits
drm/mxsfb: Improve the axi clock usage
drm/mxsfb: Update mxsfb to support LCD reset
...
-rw-r--r-- | Documentation/devicetree/bindings/display/mxsfb.txt | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 287 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_drv.c | 194 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_drv.h | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_out.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_regs.h | 193 |
6 files changed, 581 insertions, 136 deletions
diff --git a/Documentation/devicetree/bindings/display/mxsfb.txt b/Documentation/devicetree/bindings/display/mxsfb.txt index 472e1ea6c591..c8dca5051066 100644 --- a/Documentation/devicetree/bindings/display/mxsfb.txt +++ b/Documentation/devicetree/bindings/display/mxsfb.txt @@ -14,6 +14,11 @@ Required properties: - "pix" for the LCDIF block clock - (MX6SX-only) "axi", "disp_axi" for the bus interface clock +Optional properties: +- max-memory-bandwidth: maximum bandwidth in bytes per second that the + controller can handle; if not present, the memory + interface is fast enough to handle all possible video modes + Required sub-nodes: - port: The connection to an encoder chip. diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c index 12421567af89..5607fc0d61a6 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c @@ -15,6 +15,7 @@ #include <video/videomode.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_fb_cma_helper.h> @@ -43,14 +44,17 @@ static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) } /* Setup the MXSFB registers for decoding the pixels out of the framebuffer */ -static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb) +static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb, bool update) { 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; + u32 ctrl = 0, ctrl1 = 0; + bool bgr_format = true; + struct drm_format_name_buf format_name_buf; - ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER; + if (!update) + ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER; /* * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to @@ -59,61 +63,158 @@ static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb) * 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; + if (!update) { + /* 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; + } + + DRM_DEV_DEBUG_DRIVER(drm->dev, "Setting up %s mode\n", + drm_get_format_name(format, &format_name_buf)); + + /* Do some clean-up that we might have from a previous mode */ + ctrl &= ~CTRL_SHIFT_DIR(1); + ctrl &= ~CTRL_SHIFT_NUM(0x3f); + if (mxsfb->devdata->ipversion >= 4) + writel(CTRL2_ODD_LINE_PATTERN(CTRL2_LINE_PATTERN_CLR) | + CTRL2_EVEN_LINE_PATTERN(CTRL2_LINE_PATTERN_CLR), + mxsfb->base + LCDC_V4_CTRL2 + REG_CLR); switch (format) { - case DRM_FORMAT_RGB565: - dev_dbg(drm->dev, "Setting up RGB565 mode\n"); + case DRM_FORMAT_BGR565: /* BG16 */ + if (mxsfb->devdata->ipversion < 4) + goto err; + writel(CTRL2_ODD_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR) | + CTRL2_EVEN_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR), + mxsfb->base + LCDC_V4_CTRL2 + REG_SET); + /* Fall through */ + case DRM_FORMAT_RGB565: /* RG16 */ + ctrl |= CTRL_SET_WORD_LENGTH(0); + ctrl &= ~CTRL_DF16; + ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf); + break; + case DRM_FORMAT_XBGR1555: /* XB15 */ + case DRM_FORMAT_ABGR1555: /* AB15 */ + if (mxsfb->devdata->ipversion < 4) + goto err; + writel(CTRL2_ODD_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR) | + CTRL2_EVEN_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR), + mxsfb->base + LCDC_V4_CTRL2 + REG_SET); + /* Fall through */ + case DRM_FORMAT_XRGB1555: /* XR15 */ + case DRM_FORMAT_ARGB1555: /* AR15 */ ctrl |= CTRL_SET_WORD_LENGTH(0); + ctrl |= CTRL_DF16; ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf); break; - case DRM_FORMAT_XRGB8888: - dev_dbg(drm->dev, "Setting up XRGB8888 mode\n"); + case DRM_FORMAT_RGBX8888: /* RX24 */ + case DRM_FORMAT_RGBA8888: /* RA24 */ + /* RGBX - > 0RGB */ + ctrl |= CTRL_SHIFT_DIR(1); + ctrl |= CTRL_SHIFT_NUM(8); + bgr_format = false; + /* Fall through */ + case DRM_FORMAT_XBGR8888: /* XB24 */ + case DRM_FORMAT_ABGR8888: /* AB24 */ + if (bgr_format) { + if (mxsfb->devdata->ipversion < 4) + goto err; + writel(CTRL2_ODD_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR) | + CTRL2_EVEN_LINE_PATTERN(CTRL2_LINE_PATTERN_BGR), + mxsfb->base + LCDC_V4_CTRL2 + REG_SET); + } + /* Fall through */ + case DRM_FORMAT_XRGB8888: /* XR24 */ + case DRM_FORMAT_ARGB8888: /* AR24 */ 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; + goto err; } - writel(ctrl1, mxsfb->base + LCDC_CTRL1); - writel(ctrl, mxsfb->base + LCDC_CTRL); + if (update) { + writel(ctrl, mxsfb->base + LCDC_CTRL + REG_SET); + writel(ctrl1, mxsfb->base + LCDC_CTRL1 + REG_SET); + } else { + writel(ctrl, mxsfb->base + LCDC_CTRL); + writel(ctrl1, mxsfb->base + LCDC_CTRL1); + } return 0; + +err: + DRM_DEV_ERROR(drm->dev, "Unhandled pixel format: %s\n", + drm_get_format_name(format, &format_name_buf)); + + return -EINVAL; +} + +static u32 get_bus_format_from_bpp(u32 bpp) +{ + switch (bpp) { + case 16: + return MEDIA_BUS_FMT_RGB565_1X16; + case 18: + return MEDIA_BUS_FMT_RGB666_1X18; + case 24: + return MEDIA_BUS_FMT_RGB888_1X24; + default: + return MEDIA_BUS_FMT_RGB888_1X24; + } } 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 reg; + int num_bus_formats = mxsfb->connector->display_info.num_bus_formats; + const u32 *bus_formats = mxsfb->connector->display_info.bus_formats; + u32 reg = 0; + int i = 0; + + /* 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); + + bus_format = bus_formats[0]; + for (i = 0; i < num_bus_formats; i++) { + if (user_bus_format == bus_formats[i]) { + bus_format = user_bus_format; + break; + } + } + } - reg = readl(mxsfb->base + LCDC_CTRL); + /* + * CRTC will dictate the bus format via private_flags[16:1] + * and private_flags[0] will signal a bus format change + */ + crtc->mode.private_flags &= ~0x1FFFF; /* clear bus format */ + crtc->mode.private_flags |= (bus_format << 1); /* set bus format */ + crtc->mode.private_flags |= 0x1; /* bus format change indication*/ - 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); + reg = CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT); break; case MEDIA_BUS_FMT_RGB666_1X18: - reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT); + reg = CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT); break; case MEDIA_BUS_FMT_RGB888_1X24: - reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT); + 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); + writel(reg, mxsfb->base + LCDC_CTRL + REG_SET); } static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) @@ -124,6 +225,20 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) clk_prepare_enable(mxsfb->clk_disp_axi); clk_prepare_enable(mxsfb->clk); + if (mxsfb->devdata->ipversion >= 4) { + /* + * On some platforms, bit 21 is defaulted to 1, which may alter + * the below setting. So, to make sure we have the right setting + * clear all the bits for CTRL2_OUTSTANDING_REQS. + */ + writel(CTRL2_OUTSTANDING_REQS(0x7), + mxsfb->base + LCDC_V4_CTRL2 + REG_CLR); + writel(CTRL2_OUTSTANDING_REQS(REQ_16), + mxsfb->base + LCDC_V4_CTRL2 + REG_SET); + /* Assert LCD Reset bit */ + writel(CTRL2_LCD_RESET, mxsfb->base + LCDC_V4_CTRL2 + REG_SET); + } + /* If it was disabled, re-enable the mode again */ writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET); @@ -133,12 +248,22 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) writel(reg, mxsfb->base + LCDC_VDCTRL4); writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET); + writel(CTRL1_RECOVERY_ON_UNDERFLOW, mxsfb->base + LCDC_CTRL1 + REG_SET); } static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb) { u32 reg; + writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_CLR); + + if (mxsfb->devdata->ipversion >= 4) { + writel(CTRL2_OUTSTANDING_REQS(0x7), + mxsfb->base + LCDC_V4_CTRL2 + REG_CLR); + /* De-assert LCD Reset bit */ + writel(CTRL2_LCD_RESET, mxsfb->base + LCDC_V4_CTRL2 + REG_CLR); + } + /* * Even if we disable the controller here, it will still continue * until its FIFOs are running out of data @@ -204,8 +329,9 @@ static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb) 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; - const u32 bus_flags = mxsfb->connector.display_info.bus_flags; + u32 bus_flags = mxsfb->connector->display_info.bus_flags; u32 vdctrl0, vsync_pulse_len, hsync_pulse_len; int err; @@ -223,12 +349,22 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) /* Clear the FIFOs */ writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); - err = mxsfb_set_pixel_fmt(mxsfb); + err = mxsfb_set_pixel_fmt(mxsfb, false); 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); @@ -280,7 +416,8 @@ void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb) { dma_addr_t paddr; - mxsfb_enable_axi_clk(mxsfb); + clk_prepare_enable(mxsfb->clk_axi); + writel(0, mxsfb->base + LCDC_CTRL); mxsfb_crtc_mode_set_nofb(mxsfb); /* Write cur_buf as well to avoid an initial corrupt frame */ @@ -296,7 +433,58 @@ void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb) void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb) { mxsfb_disable_controller(mxsfb); - mxsfb_disable_axi_clk(mxsfb); + clk_disable_unprepare(mxsfb->clk_axi); +} + +void mxsfb_set_fb_hcrop(struct mxsfb_drm_private *mxsfb, u32 src_w, u32 fb_w) +{ + u32 mask_cnt, htotal, hcount; + u32 vdctrl2, vdctrl3, vdctrl4, transfer_count; + u32 pigeon_12_0, pigeon_12_1, pigeon_12_2; + + if (src_w == fb_w) { + writel(0x0, mxsfb->base + HW_EPDC_PIGEON_12_0); + writel(0x0, mxsfb->base + HW_EPDC_PIGEON_12_1); + + return; + } + + transfer_count = readl(mxsfb->base + LCDC_V4_TRANSFER_COUNT); + hcount = TRANSFER_COUNT_GET_HCOUNT(transfer_count); + + transfer_count &= ~TRANSFER_COUNT_SET_HCOUNT(0xffff); + transfer_count |= TRANSFER_COUNT_SET_HCOUNT(fb_w); + writel(transfer_count, mxsfb->base + LCDC_V4_TRANSFER_COUNT); + + vdctrl2 = readl(mxsfb->base + LCDC_VDCTRL2); + htotal = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2); + htotal += fb_w - hcount; + vdctrl2 &= ~VDCTRL2_SET_HSYNC_PERIOD(0x3ffff); + vdctrl2 |= VDCTRL2_SET_HSYNC_PERIOD(htotal); + writel(vdctrl2, mxsfb->base + LCDC_VDCTRL2); + + vdctrl4 = readl(mxsfb->base + LCDC_VDCTRL4); + vdctrl4 &= ~SET_DOTCLK_H_VALID_DATA_CNT(0x3ffff); + vdctrl4 |= SET_DOTCLK_H_VALID_DATA_CNT(fb_w); + writel(vdctrl4, mxsfb->base + LCDC_VDCTRL4); + + /* configure related pigeon registers */ + vdctrl3 = readl(mxsfb->base + LCDC_VDCTRL3); + mask_cnt = GET_HOR_WAIT_CNT(vdctrl3) - 5; + + pigeon_12_0 = PIGEON_12_0_SET_STATE_MASK(0x24) | + PIGEON_12_0_SET_MASK_CNT(mask_cnt) | + PIGEON_12_0_SET_MASK_CNT_SEL(0x6) | + PIGEON_12_0_POL_ACTIVE_LOW | + PIGEON_12_0_EN; + writel(pigeon_12_0, mxsfb->base + HW_EPDC_PIGEON_12_0); + + pigeon_12_1 = PIGEON_12_1_SET_CLR_CNT(src_w) | + PIGEON_12_1_SET_SET_CNT(0x0); + writel(pigeon_12_1, mxsfb->base + HW_EPDC_PIGEON_12_1); + + pigeon_12_2 = 0x0; + writel(pigeon_12_2, mxsfb->base + HW_EPDC_PIGEON_12_2); } void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, @@ -304,8 +492,11 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, { struct drm_simple_display_pipe *pipe = &mxsfb->pipe; struct drm_crtc *crtc = &pipe->crtc; + struct drm_plane_state *new_state = pipe->plane.state; + struct drm_framebuffer *fb = pipe->plane.state->fb; + struct drm_framebuffer *old_fb = state->fb; struct drm_pending_vblank_event *event; - dma_addr_t paddr; + u32 fb_addr, src_off, src_w, stride, cpp = 0; spin_lock_irq(&crtc->dev->event_lock); event = crtc->state->event; @@ -320,10 +511,40 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, } 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); + if (!fb || !old_fb) + return; + + fb_addr = mxsfb_get_fb_paddr(mxsfb); + if (mxsfb->devdata->ipversion >= 4) { + cpp = fb->format->cpp[0]; + src_off = (new_state->src_y >> 16) * fb->pitches[0] + + (new_state->src_x >> 16) * cpp; + fb_addr += fb->offsets[0] + src_off; + } + + if (fb_addr) { + clk_prepare_enable(mxsfb->clk_axi); + writel(fb_addr, mxsfb->base + mxsfb->devdata->next_buf); + clk_disable_unprepare(mxsfb->clk_axi); + } + + if (mxsfb->devdata->ipversion >= 4 && + unlikely(drm_atomic_crtc_needs_modeset(new_state->crtc->state))) { + stride = DIV_ROUND_UP(fb->pitches[0], cpp); + src_w = new_state->src_w >> 16; + mxsfb_set_fb_hcrop(mxsfb, src_w, stride); + } + + if (old_fb->format->format != fb->format->format) { + struct drm_format_name_buf old_fmt_buf; + struct drm_format_name_buf new_fmt_buf; + + DRM_DEV_DEBUG_DRIVER(crtc->dev->dev, + "Switching pixel format: %s -> %s\n", + drm_get_format_name(old_fb->format->format, + &old_fmt_buf), + drm_get_format_name(fb->format->format, + &new_fmt_buf)); + mxsfb_set_pixel_fmt(mxsfb, true); } } diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index e8506335cd15..06d3bf0d7ae7 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -26,6 +26,7 @@ #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> @@ -43,6 +44,27 @@ enum mxsfb_devtype { MXSFB_V4, }; +/* + * When adding new formats, make sure to update the num_formats from + * mxsfb_devdata below. + */ +static const u32 mxsfb_formats[] = { + /* MXSFB_V3 */ + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_RGB565, + /* MXSFB_V4 */ + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_BGR565 +}; + static const struct mxsfb_devdata mxsfb_devdata[] = { [MXSFB_V3] = { .transfer_count = LCDC_V3_TRANSFER_COUNT, @@ -52,6 +74,7 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { .hs_wdth_mask = 0xff, .hs_wdth_shift = 24, .ipversion = 3, + .num_formats = 3, }, [MXSFB_V4] = { .transfer_count = LCDC_V4_TRANSFER_COUNT, @@ -61,35 +84,62 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { .hs_wdth_mask = 0x3fff, .hs_wdth_shift = 18, .ipversion = 4, + .num_formats = ARRAY_SIZE(mxsfb_formats), }, }; -static const uint32_t mxsfb_formats[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_RGB565 -}; - 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) +/** + * mxsfb_atomic_helper_check - validate state object + * @dev: DRM device + * @state: the driver state object + * + * On top of the drm imlementation drm_atomic_helper_check, + * check if the bpp is changed, if so, signal mode_changed, + * this will trigger disable/enable + * + * RETURNS: + * Zero for success or -errno + */ +static int mxsfb_atomic_helper_check(struct drm_device *dev, + struct drm_atomic_state *state) { - if (mxsfb->clk_axi) - clk_prepare_enable(mxsfb->clk_axi); -} + struct drm_crtc *crtc; + struct drm_crtc_state *new_state; + int i, ret; -void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb) -{ - if (mxsfb->clk_axi) - clk_disable_unprepare(mxsfb->clk_axi); + ret = drm_atomic_helper_check(dev, state); + if (ret) + return ret; + + for_each_new_crtc_in_state(state, crtc, new_state, i) { + struct drm_plane_state *primary_state; + int old_bpp = 0; + int new_bpp = 0; + + if (!crtc->primary || !crtc->primary->old_fb) + continue; + primary_state = + drm_atomic_get_plane_state(state, crtc->primary); + if (!primary_state || !primary_state->fb) + continue; + old_bpp = crtc->primary->old_fb->format->depth; + new_bpp = primary_state->fb->format->depth; + if (old_bpp != new_bpp) + new_state->mode_changed = true; + } + + return ret; } static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = { .fb_create = drm_gem_fb_create, - .atomic_check = drm_atomic_helper_check, + .atomic_check = mxsfb_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -97,13 +147,72 @@ static const struct drm_mode_config_helper_funcs mxsfb_mode_config_helpers = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; +enum drm_mode_status mxsfb_pipe_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) +{ + struct drm_simple_display_pipe *pipe = + container_of(crtc, struct drm_simple_display_pipe, crtc); + struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); + u32 bpp; + u64 bw; + + if (!pipe->plane.state->fb) + bpp = 32; + else + bpp = pipe->plane.state->fb->format->depth; + + bw = mode->crtc_clock * 1000; + bw = bw * mode->hdisplay * mode->vdisplay * (bpp / 8); + bw = div_u64(bw, mode->htotal * mode->vtotal); + + if (mxsfb->max_bw && (bw > mxsfb->max_bw)) + return MODE_BAD; + + return MODE_OK; +} + +static int mxsfb_pipe_check(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state, + struct drm_crtc_state *crtc_state) +{ + struct drm_framebuffer *fb = plane_state->fb; + struct drm_framebuffer *old_fb = pipe->plane.state->fb; + + /* force 'mode_changed' when fb pitches changed, since + * the pitch related registers configuration of LCDIF + * can not be done when LCDIF is running. + */ + if (old_fb && likely(!crtc_state->mode_changed)) { + if (old_fb->pitches[0] != fb->pitches[0]) + crtc_state->mode_changed = true; + } + + return 0; +} + static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state, struct drm_plane_state *plane_state) { + 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); @@ -129,6 +238,9 @@ static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) drm_crtc_send_vblank_event(crtc, event); } 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, @@ -142,28 +254,36 @@ static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe, 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); + if (ret) + return ret; /* 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); + clk_disable_unprepare(mxsfb->clk_axi); - return 0; + return ret; } 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)) + return; + /* 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); + clk_disable_unprepare(mxsfb->clk_axi); } static struct drm_simple_display_pipe_funcs mxsfb_funcs = { + .mode_valid = mxsfb_pipe_mode_valid, + .check = mxsfb_pipe_check, .enable = mxsfb_pipe_enable, .disable = mxsfb_pipe_disable, .update = mxsfb_pipe_update, @@ -203,6 +323,9 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) if (IS_ERR(mxsfb->clk_disp_axi)) mxsfb->clk_disp_axi = NULL; + of_property_read_u32(drm->dev->of_node, "max-memory-bandwidth", + &mxsfb->max_bw); + ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32)); if (ret) return ret; @@ -225,17 +348,34 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) } ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs, - mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL, - &mxsfb->connector); + mxsfb_formats, mxsfb->devdata->num_formats, NULL, + mxsfb->connector); if (ret < 0) { dev_err(drm->dev, "Cannot setup simple display pipe\n"); goto err_vblank; } - ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector); - if (ret) { - dev_err(drm->dev, "Cannot connect panel\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. + */ + + 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; + } } drm->mode_config.min_width = MXSFB_MIN_XRES; @@ -299,7 +439,7 @@ 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); + clk_prepare_enable(mxsfb->clk_axi); reg = readl(mxsfb->base + LCDC_CTRL1); @@ -308,7 +448,7 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *data) writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); - mxsfb_disable_axi_clk(mxsfb); + clk_disable_unprepare(mxsfb->clk_axi); return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h index d975300dca05..54c06445be96 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h @@ -16,6 +16,7 @@ struct mxsfb_devdata { unsigned int hs_wdth_mask; unsigned int hs_wdth_shift; unsigned int ipversion; + unsigned int num_formats; }; struct mxsfb_drm_private { @@ -27,19 +28,20 @@ struct mxsfb_drm_private { struct clk *clk_disp_axi; struct drm_simple_display_pipe pipe; - struct drm_connector connector; + struct drm_connector panel_connector; + struct drm_connector *connector; struct drm_panel *panel; + struct drm_bridge *bridge; + + u32 max_bw; }; int mxsfb_setup_crtc(struct drm_device *dev); int mxsfb_create_output(struct drm_device *dev); -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); + struct drm_plane_state *old_state); #endif /* __MXSFB_DRV_H__ */ diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c index be36f4d6cc96..4eb94744c526 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_out.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c @@ -21,7 +21,8 @@ static struct mxsfb_drm_private * drm_connector_to_mxsfb_drm_private(struct drm_connector *connector) { - return container_of(connector, struct mxsfb_drm_private, connector); + return container_of(connector, struct mxsfb_drm_private, + panel_connector); } static int mxsfb_panel_get_modes(struct drm_connector *connector) @@ -76,22 +77,23 @@ static const struct drm_connector_funcs mxsfb_panel_connector_funcs = { int mxsfb_create_output(struct drm_device *drm) { struct mxsfb_drm_private *mxsfb = drm->dev_private; - struct drm_panel *panel; int ret; - ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, NULL); + ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, + &mxsfb->panel, &mxsfb->bridge); if (ret) return ret; - 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); - if (!ret) - mxsfb->panel = panel; + 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..df3279bf6118 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_regs.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_regs.h @@ -14,77 +14,152 @@ #define LCDC_CTRL 0x00 #define LCDC_CTRL1 0x10 +#define LCDC_V4_CTRL2 0x20 #define LCDC_V3_TRANSFER_COUNT 0x20 #define LCDC_V4_TRANSFER_COUNT 0x30 #define LCDC_V4_CUR_BUF 0x40 #define LCDC_V4_NEXT_BUF 0x50 #define LCDC_V3_CUR_BUF 0x30 #define LCDC_V3_NEXT_BUF 0x40 +#define LCDC_TIMING 0x60 #define LCDC_VDCTRL0 0x70 #define LCDC_VDCTRL1 0x80 #define LCDC_VDCTRL2 0x90 #define LCDC_VDCTRL3 0xa0 #define LCDC_VDCTRL4 0xb0 +#define LCDC_DVICTRL0 0xc0 +#define LCDC_DVICTRL1 0xd0 +#define LCDC_DVICTRL2 0xe0 +#define LCDC_DVICTRL3 0xf0 +#define LCDC_DVICTRL4 0x100 +#define LCDC_V4_DATA 0x180 +#define LCDC_V3_DATA 0x1b0 #define LCDC_V4_DEBUG0 0x1d0 #define LCDC_V3_DEBUG0 0x1f0 +#define LCDC_AS_CTRL 0x210 +#define LCDC_AS_BUF 0x220 +#define LCDC_AS_NEXT_BUF 0x230 + +/* reg bit manipulation */ +#define REG_PUT(x, h, l) (((x) << (l)) & GENMASK(h, l)) +#define REG_GET(x, h, l) (((x) & GENMASK(h, l)) >> (l)) + +#define SWIZZLE_LE 0 /* Little-Endian or No swap */ +#define SWIZZLE_BE 1 /* Big-Endian or swap all */ +#define SWIZZLE_HWD 2 /* Swap half-words */ +#define SWIZZLE_HWD_BYTE 3 /* Swap bytes within each half-word */ + +#define CTRL_SFTRST BIT(31) +#define CTRL_CLKGATE BIT(30) +#define CTRL_SHIFT_DIR(x) REG_PUT((x), 26, 26) +#define CTRL_SHIFT_NUM(x) REG_PUT((x), 25, 21) +#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_INPUT_SWIZZLE(x) REG_PUT((x), 15, 14) +#define CTRL_CSC_SWIZZLE(x) REG_PUT((x), 13, 12) +#define CTRL_SET_BUS_WIDTH(x) REG_PUT((x), 11, 10) +#define CTRL_GET_BUS_WIDTH(x) REG_GET((x), 11, 10) +#define CTRL_BUS_WIDTH_MASK REG_PUT((0x3), 11, 10) +#define CTRL_SET_WORD_LENGTH(x) REG_PUT((x), 9, 8) +#define CTRL_GET_WORD_LENGTH(x) REG_GET((x), 9, 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_RECOVERY_ON_UNDERFLOW BIT(24) +#define CTRL1_FIFO_CLEAR BIT(21) -#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 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 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 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_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 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) -#define GET_VERT_WAIT_CNT(x) ((x) & 0xffff) - -#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 SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff) - -#define DEBUG0_HSYNC (1 < 26) -#define DEBUG0_VSYNC (1 < 25) +/* + * BYTE_PACKAGING + * + * This bitfield is used to show which data bytes in a 32-bit word area valid. + * Default value 0xf indicates that all bytes are valid. For 8-bit transfers, + * any combination in this bitfield will mean valid data is present in the + * corresponding bytes. In the 16-bit mode, a 16-bit half-word is valid only if + * adjacent bits [1:0] or [3:2] or both are 1. A value of 0x0 will mean that + * none of the bytes are valid and should not be used. For example, set the bit + * field value to 0x7 if the display data is arranged in the 24-bit unpacked + * format (A-R-G-B where A value does not have be transmitted). + */ +#define CTRL1_SET_BYTE_PACKAGING(x) REG_PUT((x), 19, 16) +#define CTRL1_GET_BYTE_PACKAGING(x) REG_GET((x), 19, 16) + +#define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13) +#define CTRL1_CUR_FRAME_DONE_IRQ BIT(9) + +#define CTRL2_OUTSTANDING_REQS(x) REG_PUT((x), 23, 21) +#define REQ_1 0 +#define REQ_2 1 +#define REQ_4 2 +#define REQ_8 3 +#define REQ_16 4 + +#define CTRL2_ODD_LINE_PATTERN(x) REG_PUT((x), 18, 16) +#define CTRL2_EVEN_LINE_PATTERN(x) REG_PUT((x), 14, 12) +#define CTRL2_LINE_PATTERN_RGB 0 +#define CTRL2_LINE_PATTERN_RBG 1 +#define CTRL2_LINE_PATTERN_GBR 2 +#define CTRL2_LINE_PATTERN_GRB 3 +#define CTRL2_LINE_PATTERN_BRG 4 +#define CTRL2_LINE_PATTERN_BGR 5 +#define CTRL2_LINE_PATTERN_CLR 7 + +#define CTRL2_LCD_RESET BIT(0) + +#define TRANSFER_COUNT_SET_VCOUNT(x) REG_PUT((x), 31, 16) +#define TRANSFER_COUNT_GET_VCOUNT(x) REG_GET((x), 31, 16) +#define TRANSFER_COUNT_SET_HCOUNT(x) REG_PUT((x), 15, 0) +#define TRANSFER_COUNT_GET_HCOUNT(x) REG_GET((x), 15, 0) + +#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) REG_PUT((x), 17, 0) +#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) REG_GET((x), 17, 0) + +#define VDCTRL2_SET_HSYNC_PERIOD(x) REG_PUT((x), 15, 0) +#define VDCTRL2_GET_HSYNC_PERIOD(x) REG_GET((x), 15, 0) + +#define VDCTRL3_MUX_SYNC_SIGNALS BIT(29) +#define VDCTRL3_VSYNC_ONLY BIT(28) +#define SET_HOR_WAIT_CNT(x) REG_PUT((x), 27, 16) +#define GET_HOR_WAIT_CNT(x) REG_GET((x), 27, 16) +#define SET_VERT_WAIT_CNT(x) REG_PUT((x), 15, 0) +#define GET_VERT_WAIT_CNT(x) REG_GET((x), 15, 0) + +#define VDCTRL4_SET_DOTCLK_DLY(x) REG_PUT((x), 31, 29) /* v4 only */ +#define VDCTRL4_GET_DOTCLK_DLY(x) REG_GET((x), 31, 29) /* v4 only */ +#define VDCTRL4_SYNC_SIGNALS_ON BIT(18) +#define SET_DOTCLK_H_VALID_DATA_CNT(x) REG_PUT((x), 17, 0) + +#define DEBUG0_HSYNC BIT(26) +#define DEBUG0_VSYNC BIT(25) + +/* pigeon registers for crop */ +#define HW_EPDC_PIGEON_12_0 0xb00 +#define HW_EPDC_PIGEON_12_1 0xb10 +#define HW_EPDC_PIGEON_12_2 0xb20 + +#define PIGEON_12_0_SET_STATE_MASK(x) REG_PUT((x), 31, 24) +#define PIGEON_12_0_SET_MASK_CNT(x) REG_PUT((x), 23, 12) +#define PIGEON_12_0_SET_MASK_CNT_SEL(x) REG_PUT((x), 11, 8) +#define PIGEON_12_0_SET_OFFSET(x) REG_PUT((x), 7, 4) +#define PIGEON_12_0_SET_INC_SEL(x) REG_PUT((x), 3, 2) +#define PIGEON_12_0_POL_ACTIVE_LOW BIT(1) +#define PIGEON_12_0_EN BIT(0) + +#define PIGEON_12_1_SET_CLR_CNT(x) REG_PUT((x), 31, 16) +#define PIGEON_12_1_SET_SET_CNT(x) REG_PUT((x), 15, 0) #define MXSFB_MIN_XRES 120 #define MXSFB_MIN_YRES 120 @@ -101,7 +176,7 @@ #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 */ +#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT BIT(6) +#define MXSFB_SYNC_DOTCLK_FALLING_ACT BIT(7) /* negative edge sampling */ #endif /* __MXSFB_REGS_H__ */ |