Commit 4cbaf59b authored by Robert Chiras's avatar Robert Chiras Committed by Guido Gunther
Browse files

drm/mxsfb: Add support for horizontal stride



Besides the eLCDIF block, there is another IP block, used in the past
for EPDC panels. Since the iMX.8mq doesn't have an EPDC connector, this
block is not documented, but we can use it to do additional operations
on the frame buffer.
In this case, we can use the pigeon registers from this IP block in
order to do horizontal crop on the frame buffer processed by the eLCDIF
block.
Signed-off-by: default avatarRobert Chiras <robert.chiras@nxp.com>
parent 30cc1e31
......@@ -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>
......@@ -435,13 +436,66 @@ void mxsfb_crtc_disable(struct mxsfb_drm_private *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,
struct drm_plane_state *state)
{
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_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;
......@@ -456,10 +510,27 @@ 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) {
if (!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(paddr, mxsfb->base + mxsfb->devdata->next_buf);
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);
}
}
......@@ -136,6 +136,7 @@ static int mxsfb_atomic_helper_check(struct drm_device *dev,
if (old_bpp != new_bpp)
new_state->mode_changed = true;
}
return ret;
}
......
......@@ -145,6 +145,22 @@
#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
#define MXSFB_MAX_XRES 0xffff
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment