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 ...5.4-rM2-2.2.x-imx-squashed
commit
34ac946b63
|
@ -14,6 +14,11 @@ Required properties:
|
||||||
- "pix" for the LCDIF block clock
|
- "pix" for the LCDIF block clock
|
||||||
- (MX6SX-only) "axi", "disp_axi" for the bus interface 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:
|
Required sub-nodes:
|
||||||
- port: The connection to an encoder chip.
|
- port: The connection to an encoder chip.
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include <video/videomode.h>
|
#include <video/videomode.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_atomic_helper.h>
|
#include <drm/drm_atomic_helper.h>
|
||||||
#include <drm/drm_crtc.h>
|
#include <drm/drm_crtc.h>
|
||||||
#include <drm/drm_fb_cma_helper.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 */
|
/* 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_crtc *crtc = &mxsfb->pipe.crtc;
|
||||||
struct drm_device *drm = crtc->dev;
|
struct drm_device *drm = crtc->dev;
|
||||||
const u32 format = crtc->primary->state->fb->format->format;
|
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
|
* 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.
|
* to arbitrary value. This limitation should not pose an issue.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* CTRL1 contains IRQ config and status bits, preserve those. */
|
if (!update) {
|
||||||
ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
|
/* CTRL1 contains IRQ config and status bits, preserve those. */
|
||||||
ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
|
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) {
|
switch (format) {
|
||||||
case DRM_FORMAT_RGB565:
|
case DRM_FORMAT_BGR565: /* BG16 */
|
||||||
dev_dbg(drm->dev, "Setting up RGB565 mode\n");
|
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_SET_WORD_LENGTH(0);
|
||||||
|
ctrl &= ~CTRL_DF16;
|
||||||
ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
|
ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
|
||||||
break;
|
break;
|
||||||
case DRM_FORMAT_XRGB8888:
|
case DRM_FORMAT_XBGR1555: /* XB15 */
|
||||||
dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
|
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_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);
|
ctrl |= CTRL_SET_WORD_LENGTH(3);
|
||||||
/* Do not use packed pixels = one pixel per word instead. */
|
/* Do not use packed pixels = one pixel per word instead. */
|
||||||
ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
|
ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
|
goto err;
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writel(ctrl1, mxsfb->base + LCDC_CTRL1);
|
if (update) {
|
||||||
writel(ctrl, mxsfb->base + LCDC_CTRL);
|
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;
|
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)
|
static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
|
||||||
{
|
{
|
||||||
struct drm_crtc *crtc = &mxsfb->pipe.crtc;
|
struct drm_crtc *crtc = &mxsfb->pipe.crtc;
|
||||||
|
unsigned int bits_per_pixel = crtc->primary->state->fb->format->depth;
|
||||||
struct drm_device *drm = crtc->dev;
|
struct drm_device *drm = crtc->dev;
|
||||||
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
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;
|
||||||
|
|
||||||
reg = readl(mxsfb->base + LCDC_CTRL);
|
/* 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);
|
||||||
|
|
||||||
if (mxsfb->connector.display_info.num_bus_formats)
|
bus_format = bus_formats[0];
|
||||||
bus_format = mxsfb->connector.display_info.bus_formats[0];
|
for (i = 0; i < num_bus_formats; i++) {
|
||||||
|
if (user_bus_format == bus_formats[i]) {
|
||||||
|
bus_format = user_bus_format;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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*/
|
||||||
|
|
||||||
|
DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
|
||||||
|
bus_format);
|
||||||
|
|
||||||
reg &= ~CTRL_BUS_WIDTH_MASK;
|
|
||||||
switch (bus_format) {
|
switch (bus_format) {
|
||||||
case MEDIA_BUS_FMT_RGB565_1X16:
|
case MEDIA_BUS_FMT_RGB565_1X16:
|
||||||
reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
|
reg = CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
|
||||||
break;
|
break;
|
||||||
case MEDIA_BUS_FMT_RGB666_1X18:
|
case MEDIA_BUS_FMT_RGB666_1X18:
|
||||||
reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
|
reg = CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
|
||||||
break;
|
break;
|
||||||
case MEDIA_BUS_FMT_RGB888_1X24:
|
case MEDIA_BUS_FMT_RGB888_1X24:
|
||||||
reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
|
reg = CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
|
dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
|
||||||
break;
|
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)
|
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_disp_axi);
|
||||||
clk_prepare_enable(mxsfb->clk);
|
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 */
|
/* If it was disabled, re-enable the mode again */
|
||||||
writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
|
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(reg, mxsfb->base + LCDC_VDCTRL4);
|
||||||
|
|
||||||
writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
|
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)
|
static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
|
||||||
{
|
{
|
||||||
u32 reg;
|
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
|
* Even if we disable the controller here, it will still continue
|
||||||
* until its FIFOs are running out of data
|
* 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)
|
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;
|
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;
|
u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -223,12 +349,22 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
|
||||||
/* Clear the FIFOs */
|
/* Clear the FIFOs */
|
||||||
writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
|
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)
|
if (err)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
|
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) |
|
writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
|
||||||
TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
|
TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
|
||||||
mxsfb->base + mxsfb->devdata->transfer_count);
|
mxsfb->base + mxsfb->devdata->transfer_count);
|
||||||
|
@ -280,7 +416,8 @@ void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
|
||||||
{
|
{
|
||||||
dma_addr_t paddr;
|
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);
|
mxsfb_crtc_mode_set_nofb(mxsfb);
|
||||||
|
|
||||||
/* Write cur_buf as well to avoid an initial corrupt frame */
|
/* 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)
|
void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
|
||||||
{
|
{
|
||||||
mxsfb_disable_controller(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,
|
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_simple_display_pipe *pipe = &mxsfb->pipe;
|
||||||
struct drm_crtc *crtc = &pipe->crtc;
|
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;
|
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);
|
spin_lock_irq(&crtc->dev->event_lock);
|
||||||
event = crtc->state->event;
|
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);
|
spin_unlock_irq(&crtc->dev->event_lock);
|
||||||
|
|
||||||
paddr = mxsfb_get_fb_paddr(mxsfb);
|
if (!fb || !old_fb)
|
||||||
if (paddr) {
|
return;
|
||||||
mxsfb_enable_axi_clk(mxsfb);
|
|
||||||
writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
|
fb_addr = mxsfb_get_fb_paddr(mxsfb);
|
||||||
mxsfb_disable_axi_clk(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
#include <drm/drm_fb_cma_helper.h>
|
#include <drm/drm_fb_cma_helper.h>
|
||||||
#include <drm/drm_fb_helper.h>
|
#include <drm/drm_fb_helper.h>
|
||||||
|
#include <drm/drm_fourcc.h>
|
||||||
#include <drm/drm_gem_cma_helper.h>
|
#include <drm/drm_gem_cma_helper.h>
|
||||||
#include <drm/drm_gem_framebuffer_helper.h>
|
#include <drm/drm_gem_framebuffer_helper.h>
|
||||||
#include <drm/drm_irq.h>
|
#include <drm/drm_irq.h>
|
||||||
|
@ -43,6 +44,27 @@ enum mxsfb_devtype {
|
||||||
MXSFB_V4,
|
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[] = {
|
static const struct mxsfb_devdata mxsfb_devdata[] = {
|
||||||
[MXSFB_V3] = {
|
[MXSFB_V3] = {
|
||||||
.transfer_count = LCDC_V3_TRANSFER_COUNT,
|
.transfer_count = LCDC_V3_TRANSFER_COUNT,
|
||||||
|
@ -52,6 +74,7 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
|
||||||
.hs_wdth_mask = 0xff,
|
.hs_wdth_mask = 0xff,
|
||||||
.hs_wdth_shift = 24,
|
.hs_wdth_shift = 24,
|
||||||
.ipversion = 3,
|
.ipversion = 3,
|
||||||
|
.num_formats = 3,
|
||||||
},
|
},
|
||||||
[MXSFB_V4] = {
|
[MXSFB_V4] = {
|
||||||
.transfer_count = LCDC_V4_TRANSFER_COUNT,
|
.transfer_count = LCDC_V4_TRANSFER_COUNT,
|
||||||
|
@ -61,35 +84,62 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
|
||||||
.hs_wdth_mask = 0x3fff,
|
.hs_wdth_mask = 0x3fff,
|
||||||
.hs_wdth_shift = 18,
|
.hs_wdth_shift = 18,
|
||||||
.ipversion = 4,
|
.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 *
|
static struct mxsfb_drm_private *
|
||||||
drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
|
drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
|
||||||
{
|
{
|
||||||
return container_of(pipe, struct mxsfb_drm_private, 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)
|
struct drm_crtc *crtc;
|
||||||
clk_prepare_enable(mxsfb->clk_axi);
|
struct drm_crtc_state *new_state;
|
||||||
}
|
int i, ret;
|
||||||
|
|
||||||
void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb)
|
ret = drm_atomic_helper_check(dev, state);
|
||||||
{
|
if (ret)
|
||||||
if (mxsfb->clk_axi)
|
return ret;
|
||||||
clk_disable_unprepare(mxsfb->clk_axi);
|
|
||||||
|
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 = {
|
static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = {
|
||||||
.fb_create = drm_gem_fb_create,
|
.fb_create = drm_gem_fb_create,
|
||||||
.atomic_check = drm_atomic_helper_check,
|
.atomic_check = mxsfb_atomic_helper_check,
|
||||||
.atomic_commit = drm_atomic_helper_commit,
|
.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,
|
.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,
|
static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||||
struct drm_crtc_state *crtc_state,
|
struct drm_crtc_state *crtc_state,
|
||||||
struct drm_plane_state *plane_state)
|
struct drm_plane_state *plane_state)
|
||||||
{
|
{
|
||||||
|
struct drm_connector *connector;
|
||||||
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
|
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
|
||||||
struct drm_device *drm = pipe->plane.dev;
|
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);
|
pm_runtime_get_sync(drm->dev);
|
||||||
drm_panel_prepare(mxsfb->panel);
|
drm_panel_prepare(mxsfb->panel);
|
||||||
mxsfb_crtc_enable(mxsfb);
|
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);
|
drm_crtc_send_vblank_event(crtc, event);
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&drm->event_lock);
|
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,
|
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)
|
static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe)
|
||||||
{
|
{
|
||||||
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(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 */
|
/* 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, mxsfb->base + LCDC_CTRL1 + REG_CLR);
|
||||||
writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
|
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)
|
static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe)
|
||||||
{
|
{
|
||||||
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(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 */
|
/* 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_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
|
||||||
writel(CTRL1_CUR_FRAME_DONE_IRQ, 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 = {
|
static struct drm_simple_display_pipe_funcs mxsfb_funcs = {
|
||||||
|
.mode_valid = mxsfb_pipe_mode_valid,
|
||||||
|
.check = mxsfb_pipe_check,
|
||||||
.enable = mxsfb_pipe_enable,
|
.enable = mxsfb_pipe_enable,
|
||||||
.disable = mxsfb_pipe_disable,
|
.disable = mxsfb_pipe_disable,
|
||||||
.update = mxsfb_pipe_update,
|
.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))
|
if (IS_ERR(mxsfb->clk_disp_axi))
|
||||||
mxsfb->clk_disp_axi = NULL;
|
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));
|
ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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,
|
ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
|
||||||
mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL,
|
mxsfb_formats, mxsfb->devdata->num_formats, NULL,
|
||||||
&mxsfb->connector);
|
mxsfb->connector);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(drm->dev, "Cannot setup simple display pipe\n");
|
dev_err(drm->dev, "Cannot setup simple display pipe\n");
|
||||||
goto err_vblank;
|
goto err_vblank;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector);
|
/*
|
||||||
if (ret) {
|
* Attach panel only if there is one.
|
||||||
dev_err(drm->dev, "Cannot connect panel\n");
|
* If there is no panel attach, it must be a bridge. In this case, we
|
||||||
goto err_vblank;
|
* 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;
|
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;
|
struct mxsfb_drm_private *mxsfb = drm->dev_private;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
mxsfb_enable_axi_clk(mxsfb);
|
clk_prepare_enable(mxsfb->clk_axi);
|
||||||
|
|
||||||
reg = readl(mxsfb->base + LCDC_CTRL1);
|
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);
|
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;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ struct mxsfb_devdata {
|
||||||
unsigned int hs_wdth_mask;
|
unsigned int hs_wdth_mask;
|
||||||
unsigned int hs_wdth_shift;
|
unsigned int hs_wdth_shift;
|
||||||
unsigned int ipversion;
|
unsigned int ipversion;
|
||||||
|
unsigned int num_formats;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mxsfb_drm_private {
|
struct mxsfb_drm_private {
|
||||||
|
@ -27,19 +28,20 @@ struct mxsfb_drm_private {
|
||||||
struct clk *clk_disp_axi;
|
struct clk *clk_disp_axi;
|
||||||
|
|
||||||
struct drm_simple_display_pipe pipe;
|
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_panel *panel;
|
||||||
|
struct drm_bridge *bridge;
|
||||||
|
|
||||||
|
u32 max_bw;
|
||||||
};
|
};
|
||||||
|
|
||||||
int mxsfb_setup_crtc(struct drm_device *dev);
|
int mxsfb_setup_crtc(struct drm_device *dev);
|
||||||
int mxsfb_create_output(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_enable(struct mxsfb_drm_private *mxsfb);
|
||||||
void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb);
|
void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb);
|
||||||
void mxsfb_plane_atomic_update(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__ */
|
#endif /* __MXSFB_DRV_H__ */
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
static struct mxsfb_drm_private *
|
static struct mxsfb_drm_private *
|
||||||
drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
|
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)
|
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)
|
int mxsfb_create_output(struct drm_device *drm)
|
||||||
{
|
{
|
||||||
struct mxsfb_drm_private *mxsfb = drm->dev_private;
|
struct mxsfb_drm_private *mxsfb = drm->dev_private;
|
||||||
struct drm_panel *panel;
|
|
||||||
int ret;
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
mxsfb->connector.dpms = DRM_MODE_DPMS_OFF;
|
if (mxsfb->panel) {
|
||||||
mxsfb->connector.polled = 0;
|
mxsfb->connector = &mxsfb->panel_connector;
|
||||||
drm_connector_helper_add(&mxsfb->connector,
|
mxsfb->connector->dpms = DRM_MODE_DPMS_OFF;
|
||||||
&mxsfb_panel_connector_helper_funcs);
|
mxsfb->connector->polled = 0;
|
||||||
ret = drm_connector_init(drm, &mxsfb->connector,
|
drm_connector_helper_add(mxsfb->connector,
|
||||||
&mxsfb_panel_connector_funcs,
|
&mxsfb_panel_connector_helper_funcs);
|
||||||
DRM_MODE_CONNECTOR_Unknown);
|
ret = drm_connector_init(drm, mxsfb->connector,
|
||||||
if (!ret)
|
&mxsfb_panel_connector_funcs,
|
||||||
mxsfb->panel = panel;
|
DRM_MODE_CONNECTOR_Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,77 +14,152 @@
|
||||||
|
|
||||||
#define LCDC_CTRL 0x00
|
#define LCDC_CTRL 0x00
|
||||||
#define LCDC_CTRL1 0x10
|
#define LCDC_CTRL1 0x10
|
||||||
|
#define LCDC_V4_CTRL2 0x20
|
||||||
#define LCDC_V3_TRANSFER_COUNT 0x20
|
#define LCDC_V3_TRANSFER_COUNT 0x20
|
||||||
#define LCDC_V4_TRANSFER_COUNT 0x30
|
#define LCDC_V4_TRANSFER_COUNT 0x30
|
||||||
#define LCDC_V4_CUR_BUF 0x40
|
#define LCDC_V4_CUR_BUF 0x40
|
||||||
#define LCDC_V4_NEXT_BUF 0x50
|
#define LCDC_V4_NEXT_BUF 0x50
|
||||||
#define LCDC_V3_CUR_BUF 0x30
|
#define LCDC_V3_CUR_BUF 0x30
|
||||||
#define LCDC_V3_NEXT_BUF 0x40
|
#define LCDC_V3_NEXT_BUF 0x40
|
||||||
|
#define LCDC_TIMING 0x60
|
||||||
#define LCDC_VDCTRL0 0x70
|
#define LCDC_VDCTRL0 0x70
|
||||||
#define LCDC_VDCTRL1 0x80
|
#define LCDC_VDCTRL1 0x80
|
||||||
#define LCDC_VDCTRL2 0x90
|
#define LCDC_VDCTRL2 0x90
|
||||||
#define LCDC_VDCTRL3 0xa0
|
#define LCDC_VDCTRL3 0xa0
|
||||||
#define LCDC_VDCTRL4 0xb0
|
#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_V4_DEBUG0 0x1d0
|
||||||
#define LCDC_V3_DEBUG0 0x1f0
|
#define LCDC_V3_DEBUG0 0x1f0
|
||||||
|
#define LCDC_AS_CTRL 0x210
|
||||||
|
#define LCDC_AS_BUF 0x220
|
||||||
|
#define LCDC_AS_NEXT_BUF 0x230
|
||||||
|
|
||||||
#define CTRL_SFTRST (1 << 31)
|
/* reg bit manipulation */
|
||||||
#define CTRL_CLKGATE (1 << 30)
|
#define REG_PUT(x, h, l) (((x) << (l)) & GENMASK(h, l))
|
||||||
#define CTRL_BYPASS_COUNT (1 << 19)
|
#define REG_GET(x, h, l) (((x) & GENMASK(h, l)) >> (l))
|
||||||
#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 SWIZZLE_LE 0 /* Little-Endian or No swap */
|
||||||
#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
|
#define SWIZZLE_BE 1 /* Big-Endian or swap all */
|
||||||
#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
|
#define SWIZZLE_HWD 2 /* Swap half-words */
|
||||||
#define CTRL1_CUR_FRAME_DONE_IRQ_EN (1 << 13)
|
#define SWIZZLE_HWD_BYTE 3 /* Swap bytes within each half-word */
|
||||||
#define CTRL1_CUR_FRAME_DONE_IRQ (1 << 9)
|
|
||||||
|
|
||||||
#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
|
#define CTRL_SFTRST BIT(31)
|
||||||
#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
|
#define CTRL_CLKGATE BIT(30)
|
||||||
#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff)
|
#define CTRL_SHIFT_DIR(x) REG_PUT((x), 26, 26)
|
||||||
#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff)
|
#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 VDCTRL0_ENABLE_PRESENT (1 << 28)
|
#define CTRL1_RECOVERY_ON_UNDERFLOW BIT(24)
|
||||||
#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27)
|
#define CTRL1_FIFO_CLEAR BIT(21)
|
||||||
#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)
|
* 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 VDCTRL3_MUX_SYNC_SIGNALS (1 << 29)
|
#define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13)
|
||||||
#define VDCTRL3_VSYNC_ONLY (1 << 28)
|
#define CTRL1_CUR_FRAME_DONE_IRQ BIT(9)
|
||||||
#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 CTRL2_OUTSTANDING_REQS(x) REG_PUT((x), 23, 21)
|
||||||
#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */
|
#define REQ_1 0
|
||||||
#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18)
|
#define REQ_2 1
|
||||||
#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
|
#define REQ_4 2
|
||||||
|
#define REQ_8 3
|
||||||
|
#define REQ_16 4
|
||||||
|
|
||||||
#define DEBUG0_HSYNC (1 < 26)
|
#define CTRL2_ODD_LINE_PATTERN(x) REG_PUT((x), 18, 16)
|
||||||
#define DEBUG0_VSYNC (1 < 25)
|
#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_XRES 120
|
||||||
#define MXSFB_MIN_YRES 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_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 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_DATA_ENABLE_HIGH_ACT BIT(6)
|
||||||
#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negative edge sampling */
|
#define MXSFB_SYNC_DOTCLK_FALLING_ACT BIT(7) /* negative edge sampling */
|
||||||
|
|
||||||
#endif /* __MXSFB_REGS_H__ */
|
#endif /* __MXSFB_REGS_H__ */
|
||||||
|
|
Loading…
Reference in New Issue