summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-mvf/board-twr_vf600.c29
-rw-r--r--arch/arm/mach-mvf/clock.c6
-rw-r--r--arch/arm/mach-mvf/devices-mvf.h7
-rwxr-xr-xarch/arm/plat-mxc/devices/Kconfig4
-rwxr-xr-xarch/arm/plat-mxc/devices/Makefile1
-rw-r--r--arch/arm/plat-mxc/devices/platform-mvf_dcuv4.c136
-rw-r--r--arch/arm/plat-mxc/include/mach/dcu-v4.h241
-rwxr-xr-xarch/arm/plat-mxc/include/mach/devices-common.h17
-rwxr-xr-xarch/arm/plat-mxc/include/mach/iomux-vf6xx.h8
-rw-r--r--arch/arm/plat-mxc/include/mach/mvf.h4
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/mvf/Kconfig19
-rw-r--r--drivers/mvf/Makefile1
-rw-r--r--drivers/mvf/dcu4/Kconfig2
-rw-r--r--drivers/mvf/dcu4/Makefile4
-rw-r--r--drivers/mvf/dcu4/dcu.h79
-rw-r--r--drivers/mvf/dcu4/dcu4_driver.c1942
-rw-r--r--drivers/mvf/dcu4/dcu4_regs.h722
-rw-r--r--drivers/video/Kconfig3
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/mvf/Kconfig20
-rw-r--r--drivers/video/mvf/Makefile1
-rw-r--r--drivers/video/mvf/mvf_dcu4_fb.c1411
-rw-r--r--drivers/video/mvf/mvf_dispdrv.c144
-rw-r--r--drivers/video/mvf/mvf_dispdrv.h51
-rw-r--r--drivers/video/mvf/mvffb_nec_wqvga.c145
-rw-r--r--include/linux/fsl_devices.h10
-rw-r--r--include/linux/mvffb.h64
29 files changed, 5066 insertions, 9 deletions
diff --git a/arch/arm/mach-mvf/board-twr_vf600.c b/arch/arm/mach-mvf/board-twr_vf600.c
index 5f956e458f21..6c7ac64b3470 100644
--- a/arch/arm/mach-mvf/board-twr_vf600.c
+++ b/arch/arm/mach-mvf/board-twr_vf600.c
@@ -354,6 +354,28 @@ static struct platform_device lpt_device = {
.resource = lpt_resources,
};
+static struct mvf_dcuv4_platform_data dcuv4_data[] = {
+ {
+ .rev = 1,
+ }, {
+ .rev = 1,
+ },
+};
+
+static struct dcuv4_fb_platform_data mvf_fb_data[] = {
+ {
+ .disp_dev = "lcd",
+ .interface_pix_fmt = V4L2_PIX_FMT_RGB32,
+ .mode_str = "NEC-WQVGA",
+ .default_bpp = 32,
+ },
+};
+
+static struct fsl_mvf_lcd_platform_data lcdif_data = {
+ .dcu_id = 0,
+ .default_ifmt = V4L2_PIX_FMT_RGB32,
+};
+
static void twr_vf600_suspend_enter(void)
{
/* suspend preparation */
@@ -397,6 +419,13 @@ static void __init twr_vf600_init(void)
vf6xx_add_imx_snvs_rtc();
mvf_init_fec(fec_data);
+ printk("TWR_VF600: Adding dcuv4 \n");
+ vf600_add_dcuv4(0, &dcuv4_data[0]);
+ printk("TWR_VF600: Adding dcuv4-fb\n");
+ mvf_add_dcuv4_fb(0, &mvf_fb_data[0]);
+ printk("TWR_VF600: Adding lcdif\n");
+ mvf_add_lcdif(&lcdif_data);
+
platform_device_register(&edma_device0);
platform_device_register(&edma_device1);
platform_device_register(&pit_device);
diff --git a/arch/arm/mach-mvf/clock.c b/arch/arm/mach-mvf/clock.c
index 3ea6961df483..cd7e95fc749a 100644
--- a/arch/arm/mach-mvf/clock.c
+++ b/arch/arm/mach-mvf/clock.c
@@ -2559,10 +2559,10 @@ static unsigned long _clk_dcu_get_rate(struct clk *clk)
reg = __raw_readl(MXC_CCM_CSCDR3);
if (clk == &dcu0_clk_root)
- div = ((reg & ~MXC_CCM_CSCDR3_DCU0_DIV_MASK) >>
+ div = ((reg & MXC_CCM_CSCDR3_DCU0_DIV_MASK) >>
MXC_CCM_CSCDR3_DCU0_DIV_OFFSET) + 1;
else
- div = ((reg & ~MXC_CCM_CSCDR3_DCU1_DIV_MASK) >>
+ div = ((reg & MXC_CCM_CSCDR3_DCU1_DIV_MASK) >>
MXC_CCM_CSCDR3_DCU1_DIV_OFFSET) + 1;
return clk_get_rate(clk->parent) / div;
@@ -2617,7 +2617,7 @@ static int _clk_dcu_set_parent(struct clk *clk, struct clk *parent)
static struct clk dcu0_clk_root = {
__INIT_CLK_DEBUG(dcu0_clk_root)
- .parent = &pll1_pfd2, //FIXME
+ .parent = &pll3_480_usb1_main_clk,
.enable_shift = MXC_CCM_CSCDR3_DCU0_EN_OFFSET,
.enable = _clk_dcu_enable,
.disable = _clk_dcu_disable,
diff --git a/arch/arm/mach-mvf/devices-mvf.h b/arch/arm/mach-mvf/devices-mvf.h
index 7fa46ca9c8fa..00ea16ec6147 100644
--- a/arch/arm/mach-mvf/devices-mvf.h
+++ b/arch/arm/mach-mvf/devices-mvf.h
@@ -21,6 +21,9 @@
#include <mach/mvf.h>
#include <mach/devices-common.h>
+extern const struct mvf_dcuv4_data vf600_dcuv4_data[] __initconst;
+#define vf600_add_dcuv4(id, pdata) mvf_add_dcuv4(id, &vf600_dcuv4_data[id], pdata)
+
extern const struct imx_imx_uart_1irq_data mvf_imx_uart_data[] __initconst;
#define mvf_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&mvf_imx_uart_data[id], pdata)
@@ -29,6 +32,10 @@ extern const struct imx_snvs_rtc_data vf6xx_imx_snvs_rtc_data __initconst;
#define vf6xx_add_imx_snvs_rtc() \
imx_add_snvs_rtc(&vf6xx_imx_snvs_rtc_data)
+#define mvf_add_lcdif(pdata) \
+ platform_device_register_resndata(NULL, "mvf_lcdif",\
+ 0, NULL, 0, pdata, sizeof(*pdata));
+
#if 0
extern const struct imx_dma_data vf6xx_dma_data __initconst;
#define vf6xx_add_dma() imx_add_dma(&vf6xx_dma_data);
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index 3eead8ebda92..500e3267dc19 100755
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -169,3 +169,7 @@ config IMX_HAVE_PLATFORM_IMX_MIPI_DSI
config IMX_HAVE_PLATFORM_IMX_MIPI_CSI2
bool
+
+config MVF_HAVE_PLATFORM_DCUV4
+ bool
+ default y if ARCH_MVF
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
index 71cfefa7cccb..64a57a1f7e36 100755
--- a/arch/arm/plat-mxc/devices/Makefile
+++ b/arch/arm/plat-mxc/devices/Makefile
@@ -61,3 +61,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_HDMI) += platform-imx-hdmi-soc-dai.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_ASRC) += platform-imx-asrc.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_DSI) += platform-imx-mipi_dsi.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_MIPI_CSI2) += platform-imx-mipi_csi2.o
+obj-$(CONFIG_MVF_HAVE_PLATFORM_DCUV4) += platform-mvf_dcuv4.o
diff --git a/arch/arm/plat-mxc/devices/platform-mvf_dcuv4.c b/arch/arm/plat-mxc/devices/platform-mvf_dcuv4.c
new file mode 100644
index 000000000000..8f53c0e5e983
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-mvf_dcuv4.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#include <linux/clk.h>
+
+#define mvf_dcu4_data_entry_single(soc, id, size, dcu_pg, dcu_blank) \
+ { \
+ .iobase = soc ## _DCU ## id ## _BASE_ADDR, \
+ .irq = soc ## _INT_DCU ## id, \
+ .iosize = size, \
+ .pg = dcu_pg, \
+ .blank = dcu_blank, \
+ }
+
+#ifdef CONFIG_SOC_VF6XX
+#include <mach/iomux-vmvf.h>
+#include <mach/iomux-vf6xx.h>
+void vf600_dcuv4_pg(int id, int enable)
+{
+ /*TODO; get rid of this and use clock enable?*/
+ //if(enable)
+ //val = readl(MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
+ //writel(MXC_PGCR_PCR, MX51_PGC_IPU_PGCR);
+
+}
+
+void vf600_dcuv4_blank(int id, int enable)
+{
+ /*TODO: Add check for which DCU*/
+ /*TODO: Get rid of the backlight enable and use PWM module */
+ if(enable)
+ {
+ if(id == 0)
+ {
+ //disable pclk
+ mxc_iomux_vmvf_setup_pad(VF6XX_PAD_PAD_110__RGPIOC_GPIO110);
+ //disable backlight
+ mxc_iomux_vmvf_setup_pad((_VF6XX_PAD_PAD_30__RGPIOC_GPIO30 | MUX_CTRL_PAD(VF6XX_PAD_CTRL_OBE)));
+ }
+
+ }
+ else
+ {
+ if(id == 0)
+ {
+ //enable pclk
+ mxc_iomux_vmvf_setup_pad(VF6XX_PAD_PAD_110__TCON0_DATA_OUT18);
+ //enable backlight
+ mxc_iomux_vmvf_setup_pad((_VF6XX_PAD_PAD_30__RGPIOC_GPIO30 | MUX_CTRL_PAD(NO_PAD_CTRL)));
+ }
+ }
+}
+
+const struct mvf_dcuv4_data vf600_dcuv4_data[] __initconst = {
+ mvf_dcu4_data_entry_single(MVF, 0, SZ_4M,
+ vf600_dcuv4_pg, vf600_dcuv4_blank),
+ mvf_dcu4_data_entry_single(MVF, 1, SZ_4M,
+ vf600_dcuv4_pg, vf600_dcuv4_blank),
+};
+#endif
+
+struct platform_device *__init mvf_add_dcuv4(
+ const int id,
+ const struct mvf_dcuv4_data *data,
+ struct mvf_dcuv4_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + data->iosize - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->irq,
+ .end = data->irq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+ pdata->pg = data->pg;
+ pdata->blank = data->blank;
+
+ return imx_add_platform_device_dmamask("mvf-dcuv4", id,
+ res, ARRAY_SIZE(res), pdata, sizeof(*pdata),
+ DMA_BIT_MASK(32));
+}
+
+struct platform_device *__init mvf_add_dcuv4_fb(
+ const int id,
+ const struct dcuv4_fb_platform_data *pdata)
+{
+ if (pdata->res_size[0] > 0) {
+ struct resource res[] = {
+ {
+ .start = pdata->res_base[0],
+ .end = pdata->res_base[0] + pdata->res_size[0] - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_MEM,
+ },
+ };
+
+ if (pdata->res_size[1] > 0) {
+ res[1].start = pdata->res_base[1];
+ res[1].end = pdata->res_base[1] +
+ pdata->res_size[1] - 1;
+ }
+
+ return imx_add_platform_device_dmamask("mvf_dcu4_fb",
+ id, res, ARRAY_SIZE(res), pdata,
+ sizeof(*pdata), DMA_BIT_MASK(32));
+ } else
+ return imx_add_platform_device_dmamask("mvf_dcu4_fb", id,
+ NULL, 0, pdata, sizeof(*pdata),
+ DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/plat-mxc/include/mach/dcu-v4.h b/arch/arm/plat-mxc/include/mach/dcu-v4.h
new file mode 100644
index 000000000000..b1e04c09f983
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/dcu-v4.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef __MACH_DCU_V4_H_
+#define __MACH_DCU_V4_H_
+
+#include <linux/ipu.h>
+
+
+typedef struct
+{
+ unsigned enable:1;
+ unsigned tile_en:1;
+ unsigned data_sel:1;
+ unsigned saftey_en:1;
+ unsigned trans:8;
+ unsigned bpp:4;
+ unsigned rle_en:1;
+ unsigned luoffs:11;
+ unsigned bb:1;
+ unsigned ab:2;
+}dcu_layer_cfg_t;
+
+typedef struct
+{
+ unsigned color_r:8;
+ unsigned color_g:8;
+ unsigned color_b:8;
+}dcu_color_t;
+
+/*!
+ * Union of initialization parameters for a logical layer.
+ */
+typedef union {
+
+ struct {
+ uint32_t width;
+ uint32_t height;
+ uint32_t pos_x;
+ uint32_t pos_y;
+ uint32_t addr;
+ dcu_layer_cfg_t layer_cfg;
+ dcu_color_t ckmax;
+ dcu_color_t ckmin;
+ uint32_t tile_ver_size;
+ uint32_t tile_hor_size;
+ uint32_t fg_fcolor;
+ uint32_t fg_bcolor;
+ }layer_mem;
+}dcu_layer_params_t;
+
+/*!
+ * Enumeration of DCU interrupt sources.
+ */
+enum dcu_irq_line {
+ DCU_IRQ_VSYNC = 0,
+ DCU_IRQ_UNDRUN = DCU_IRQ_VSYNC + 1,
+ DCU_IRQ_LS_BF_VS = DCU_IRQ_VSYNC + 2,
+ DCU_IRQ_VS_BLANK = DCU_IRQ_VSYNC + 3,
+ DCU_IRQ_CRC_READY = DCU_IRQ_VSYNC + 4,
+ DCU_IRQ_CRC_OVERFLOW = DCU_IRQ_VSYNC + 5,
+ DCU_IRQ_P1_FIFO_LO_FLAG = DCU_IRQ_VSYNC + 6,
+ DCU_IRQ_P1_FIFO_HI_FLAG = DCU_IRQ_VSYNC + 7,
+ DCU_IRQ_P2_FIFO_LO_FLAG = DCU_IRQ_VSYNC + 8,
+ DCU_IRQ_P2_FIFO_HI_FLAG = DCU_IRQ_VSYNC + 9,
+ DCU_IRQ_PROG_END = DCU_IRQ_VSYNC + 10,
+ /* DCU_IRQ_IPM_ERROR = DCU_IRQ_VSYNC + 11, */
+ DCU_IRQ_LYR_TRANS_FINISH = DCU_IRQ_VSYNC + 12,
+ DCU_IRQ_DMA_TRANS_FINISH = DCU_IRQ_VSYNC + 14,
+ DCU_IRQ_P3_FIFO_LO_FLAG = DCU_IRQ_VSYNC + 16,
+ DCU_IRQ_P3_FIFO_HI_FLAG = DCU_IRQ_VSYNC + 17,
+ DCU_IRQ_P4_FIFO_LO_FLAG = DCU_IRQ_VSYNC + 18,
+ DCU_IRQ_P4_FIFO_HI_FLAG = DCU_IRQ_VSYNC + 19,
+ DCU_IRQ_P5_FIFO_LO_FLAG = DCU_IRQ_VSYNC + 20,
+ DCU_IRQ_P5_FIFO_HI_FLAG = DCU_IRQ_VSYNC + 21,
+ DCU_IRQ_P6_FIFO_LO_FLAG = DCU_IRQ_VSYNC + 22,
+ DCU_IRQ_P6_FIFO_HI_FLAG = DCU_IRQ_VSYNC + 23,
+ DCU_IRQ_P1_EMPTY = DCU_IRQ_VSYNC + 26,
+ DCU_IRQ_P2_EMPTY = DCU_IRQ_VSYNC + 27,
+ DCU_IRQ_P3_EMPTY = DCU_IRQ_VSYNC + 28,
+ DCU_IRQ_P4_EMPTY = DCU_IRQ_VSYNC + 29,
+ DCU_IRQ_P5_EMPTY = DCU_IRQ_VSYNC + 30,
+ DCU_IRQ_P6_EMPTY = DCU_IRQ_VSYNC + 31,
+ DCU_IRQ_COUNT
+};
+
+enum dcu_mode
+{
+ DCU_OFF = 0,
+ DCU_NORMAL_MODE,
+ DCU_TEST_MODE,
+ DCU_COLOR_BAR_MODE
+};
+
+typedef enum
+{
+ BPP1_CLUT = 0,
+ BPP2_CLUT,
+ BPP4_CLUT,
+ BPP8_CLUT,
+ BPP16_RGB565,
+ BPP24_RGB888,
+ BPP32_ARGB8888,
+ BPP4_TRANSPARENCY_MODE,
+ BPP8_TRANSPARENCY_MODE,
+ BPP4_LUMINANCE_OFFSET_MODE,
+ BPP8_LUMINANCE_OFFSET_MODE,
+ BPP16_ARGB1555,
+ BPP16_ARGB4444,
+ BPP16_APAL8,
+ YCbCr422,
+ BPP_INVALID
+}dcu_bpp_format;
+
+/* TODO: Give users more options */
+typedef enum
+{
+ ALPHA_BLEND_DISABLED = 0,
+ ALPHA_BLEND_ENABLED = 2
+}alpha_aa_config;
+
+/*!
+ * Bitfield of Display Interface signal polarities.
+ */
+typedef struct {
+ unsigned interlaced:1;
+ unsigned data_pol:1; /* true = inverted */
+ unsigned clk_pol:1; /* true = rising edge */
+ unsigned Hsync_pol:1; /* true = active high */
+ unsigned Vsync_pol:1;
+} dcu_di_signal_cfg_t;
+
+
+struct dcu_soc;
+struct dcu_soc *dcu_get_soc(int id);
+
+/* DCU Layer support */
+int32_t dcu_init_layer(struct dcu_soc *dcu, uint8_t layer,
+ uint32_t pixel_fmt,
+ uint16_t width, uint16_t height,
+ dma_addr_t phyaddr_0,
+ int16_t x_pos, int16_t y_pos);
+void dcu_uninit_layer(struct dcu_soc *dcu, uint8_t layer);
+
+int32_t dcu_update_layer_buffer(struct dcu_soc *dcu, uint8_t layer,
+ dma_addr_t phyaddr);
+
+int32_t dcu_set_layer_position(struct dcu_soc *dcu, uint8_t layer, int16_t x_pos,
+ int16_t y_pos);
+
+int32_t dcu_get_layer_position(struct dcu_soc *dcu, uint8_t layer, int16_t *x_pos,
+ int16_t *y_pos);
+
+int32_t dcu_is_layer_enabled(struct dcu_soc *dcu, uint8_t layer);
+
+int32_t dcu_enable_layer(struct dcu_soc *dcu, uint8_t layer);
+
+int32_t dcu_disable_layer(struct dcu_soc *dcu, uint8_t layer, bool wait_for_stop);
+
+int32_t dcu_config_layer_alpha(struct dcu_soc *dcu, uint8_t layer,
+ uint8_t alpha_value, alpha_aa_config aa);
+
+int32_t dcu_set_chroma_keying(struct dcu_soc *dcu, uint8_t layer,
+ dcu_color_t color_max, dcu_color_t color_min, bool enable);
+
+/* DCU IRQ Support */
+void dcu_enable_irq(struct dcu_soc *dcu, uint32_t irq);
+
+void dcu_disable_irq(struct dcu_soc *dcu, uint32_t irq);
+
+void dcu_clear_irq(struct dcu_soc *dcu, uint32_t irq);
+
+bool dcu_get_irq_status(struct dcu_soc *dcu, uint32_t irq);
+
+int dcu_request_irq(struct dcu_soc *dcu, uint32_t irq,
+ irqreturn_t(*handler) (int, void *),
+ uint32_t irq_flags, const char *devname, void *dev_id);
+
+void dcu_free_irq(struct dcu_soc *dcu, uint32_t irq, void *dev_id);
+
+/* DCU device driver support */
+int register_dcu_device(struct dcu_soc *dcu, int id);
+
+void unregister_dcu_device(struct dcu_soc *dcu, int id);
+
+/* Display API */
+int32_t dcu_init_panel(struct dcu_soc *dcu, uint32_t pixel_clk,
+ uint16_t width, uint16_t height,
+ uint16_t h_start_width, uint16_t h_sync_width,
+ uint16_t h_end_width, uint16_t v_start_width,
+ uint16_t v_sync_width, uint16_t v_end_width,
+ uint32_t v_to_h_sync, dcu_di_signal_cfg_t sig);
+
+void dcu_uninit_panel(struct dcu_soc *dcu);
+
+void dcu_enable(struct dcu_soc *dcu);
+
+void dcu_disable(struct dcu_soc *dcu);
+
+/* DCU global feature support */
+void dcu_set_bgnd_color(struct dcu_soc *dcu, dcu_color_t color);
+
+
+
+/* Later releases of DCU should support these
+ *
+int32_t dcu_disp_set_gamma_correction(struct dcu_soc *dcu, uint8_t layer, bool enable,
+ int constk[], int slopek[]);
+*/
+
+struct dcuv4_fb_platform_data {
+ char disp_dev[32];
+ u32 interface_pix_fmt;
+ char *mode_str;
+ int default_bpp;
+ int dcu_id;
+
+ /* reserved mem */
+ resource_size_t res_base[2];
+ resource_size_t res_size[2];
+};
+
+struct mvf_dcuv4_platform_data {
+ int rev;
+ void (*pg) (int, int);
+ void (*blank) (int, int);
+};
+
+#endif /* __MACH_DCU_V4_H_ */
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index 2f5f04c39638..b98db656f8f9 100755
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -352,6 +352,23 @@ struct platform_device *__init imx_add_ipuv3_fb(
const int id,
const struct ipuv3_fb_platform_data *pdata);
+#include <mach/dcu-v4.h>
+struct mvf_dcuv4_data {
+ resource_size_t iobase;
+ resource_size_t iosize;
+ resource_size_t irq;
+ void (*pg) (int, int);
+ void (*blank) (int, int);
+};
+struct platform_device *__init mvf_add_dcuv4(
+ const int id,
+ const struct mvf_dcuv4_data *data,
+ struct mvf_dcuv4_platform_data *pdata);
+
+struct platform_device *__init mvf_add_dcuv4_fb(
+ const int id,
+ const struct dcuv4_fb_platform_data *pdata);
+
#include <mach/mxc_vpu.h>
struct imx_vpu_data {
resource_size_t iobase;
diff --git a/arch/arm/plat-mxc/include/mach/iomux-vf6xx.h b/arch/arm/plat-mxc/include/mach/iomux-vf6xx.h
index f7c5c7620ae2..e1ab00606fcc 100755
--- a/arch/arm/plat-mxc/include/mach/iomux-vf6xx.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-vf6xx.h
@@ -3293,7 +3293,7 @@
#define VF6XX_PAD_PAD_105__RGPIOC_GPIO105 \
(_VF6XX_PAD_PAD_105__RGPIOC_GPIO105 | MUX_CTRL_PAD(NO_PAD_CTRL))
#define VF6XX_PAD_PAD_105__TCON0_TCON1 \
- (_VF6XX_PAD_PAD_105__TCON0_TCON1 | MUX_CTRL_PAD(VF6XX_PAD_CTRL_IOBE)) /* FIXME */
+ (_VF6XX_PAD_PAD_105__TCON0_TCON1 | MUX_CTRL_PAD(VF6XX_PAD_CTRL_OBE))
#define VF6XX_PAD_PAD_105__SRC_BMODE1 \
(_VF6XX_PAD_PAD_105__SRC_BMODE1 | MUX_CTRL_PAD(NO_PAD_CTRL))
#define VF6XX_PAD_PAD_105__LCD_64F6B_LCD0 \
@@ -3304,7 +3304,7 @@
#define VF6XX_PAD_PAD_106__RGPIOC_GPIO106 \
(_VF6XX_PAD_PAD_106__RGPIOC_GPIO106 | MUX_CTRL_PAD(NO_PAD_CTRL))
#define VF6XX_PAD_PAD_106__TCON0_TCON2 \
- (_VF6XX_PAD_PAD_106__TCON0_TCON2 | MUX_CTRL_PAD(VF6XX_PAD_CTRL_IOBE)) /* FIXME */
+ (_VF6XX_PAD_PAD_106__TCON0_TCON2 | MUX_CTRL_PAD(VF6XX_PAD_CTRL_OBE))
#define VF6XX_PAD_PAD_106__SRC_BMODE0 \
(_VF6XX_PAD_PAD_106__SRC_BMODE0 | MUX_CTRL_PAD(NO_PAD_CTRL))
#define VF6XX_PAD_PAD_106__LCD_64F6B_LCD1 \
@@ -3315,7 +3315,7 @@
#define VF6XX_PAD_PAD_107__RGPIOC_GPIO107 \
(_VF6XX_PAD_PAD_107__RGPIOC_GPIO107 | MUX_CTRL_PAD(NO_PAD_CTRL))
#define VF6XX_PAD_PAD_107__TCON0_DATA_OUT1 \
- (_VF6XX_PAD_PAD_107__TCON0_DATA_OUT1 | MUX_CTRL_PAD(VF6XX_PAD_CTRL_IOBE))
+ (_VF6XX_PAD_PAD_107__TCON0_DATA_OUT1 | MUX_CTRL_PAD(VF6XX_PAD_CTRL_OBE))
#define VF6XX_PAD_PAD_107__LCD_64F6B_LCD2 \
(_VF6XX_PAD_PAD_107__LCD_64F6B_LCD2 | MUX_CTRL_PAD(NO_PAD_CTRL))
#define VF6XX_PAD_PAD_107__VIU_MUX_DEBUG_OUT31 \
@@ -3333,7 +3333,7 @@
#define VF6XX_PAD_PAD_109__RGPIOC_GPIO109 \
(_VF6XX_PAD_PAD_109__RGPIOC_GPIO109 | MUX_CTRL_PAD(NO_PAD_CTRL))
#define VF6XX_PAD_PAD_109__TCON0_TCON3 \
- (_VF6XX_PAD_PAD_109__TCON0_TCON3 | MUX_CTRL_PAD(VF6XX_PAD_CTRL_IOBE))
+ (_VF6XX_PAD_PAD_109__TCON0_TCON3 | MUX_CTRL_PAD(VF6XX_PAD_CTRL_OBE))
#define VF6XX_PAD_PAD_109__LCD_64F6B_LCD4 \
(_VF6XX_PAD_PAD_109__LCD_64F6B_LCD4 | MUX_CTRL_PAD(NO_PAD_CTRL))
#define VF6XX_PAD_PAD_109__VIU_MUX_DEBUG_OUT33 \
diff --git a/arch/arm/plat-mxc/include/mach/mvf.h b/arch/arm/plat-mxc/include/mach/mvf.h
index 6cbea664b6e5..8c5aaad02d70 100644
--- a/arch/arm/plat-mxc/include/mach/mvf.h
+++ b/arch/arm/plat-mxc/include/mach/mvf.h
@@ -329,8 +329,8 @@
#define MXC_INT_DDRMC 58
#define MXC_INT_SDHC0 59
#define MXC_INT_SDHC1 60
-#define MXC_INT_DCU0 62
-#define MXC_INT_DCU1 63
+#define MVF_INT_DCU0 62
+#define MVF_INT_DCU1 63
#define MXC_INT_VIU 64
#define MXC_INT_GPU 66
#define MXC_INT_RLE 67
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 65f7142817a6..2eb96886b19e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -128,4 +128,6 @@ source "drivers/clocksource/Kconfig"
source "drivers/mxc/Kconfig"
+source "drivers/mvf/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 3c66d7069ec7..d62002a0fce8 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_CPU_IDLE) += cpuidle/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_ARCH_MXC) += mxc/
+obj-$(CONFIG_ARCH_MVF) += mvf/
obj-$(CONFIG_MEMSTICK) += memstick/
obj-y += leds/
obj-$(CONFIG_INFINIBAND) += infiniband/
diff --git a/drivers/mvf/Kconfig b/drivers/mvf/Kconfig
new file mode 100644
index 000000000000..babb8a1f2839
--- /dev/null
+++ b/drivers/mvf/Kconfig
@@ -0,0 +1,19 @@
+#drivers/video/mvf/Kconfig
+
+if ARCH_MVF
+
+menu "MVF support drivers"
+
+config MVF_DCU
+ bool "Display Controller Unit Driver"
+ depends on ARCH_VF6XX
+ select MVF_DCU_V4 if ARCH_VF6XX
+ help
+ If you plan to use the Display Controller unit, say
+ Y here. DCU is needed by Framebuffer and V4L2 drivers.
+
+source "drivers/mvf/dcu4/Kconfig"
+
+endmenu
+
+endif
diff --git a/drivers/mvf/Makefile b/drivers/mvf/Makefile
new file mode 100644
index 000000000000..c346ef61a446
--- /dev/null
+++ b/drivers/mvf/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MVF_DCU) += dcu4/
diff --git a/drivers/mvf/dcu4/Kconfig b/drivers/mvf/dcu4/Kconfig
new file mode 100644
index 000000000000..b935b261531b
--- /dev/null
+++ b/drivers/mvf/dcu4/Kconfig
@@ -0,0 +1,2 @@
+config MVF_DCU_V4
+ bool
diff --git a/drivers/mvf/dcu4/Makefile b/drivers/mvf/dcu4/Makefile
new file mode 100644
index 000000000000..690add975de8
--- /dev/null
+++ b/drivers/mvf/dcu4/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_MVF_DCU) = mvf_dcu.o
+
+mvf_dcu-objs := dcu4_driver.o
+
diff --git a/drivers/mvf/dcu4/dcu.h b/drivers/mvf/dcu4/dcu.h
new file mode 100644
index 000000000000..4792ab4d68ee
--- /dev/null
+++ b/drivers/mvf/dcu4/dcu.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __INCLUDE_DCU_H__
+#define __INCLUDE_DCU_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <mach/clock.h>
+#include <linux/clkdev.h>
+#include <linux/interrupt.h>
+#include <linux/fsl_devices.h>
+
+
+#define MVF_DCU_MAX_NUM 1
+
+/* Globals */
+struct dcu_irq_node {
+ irqreturn_t(*handler) (int, void *); /*!< the ISR */
+ const char *name; /*!< device associated with the interrupt */
+ void *dev_id; /*!< some unique information for the ISR */
+ __u32 flags; /*!< not used */
+};
+
+struct dcu_soc {
+ bool online;
+ bool display_configured;
+
+ /*clk*/
+ struct clk *dcu_clk;
+ struct clk pixel_clk;
+
+ /*irq*/
+ int irq_generic;
+ struct dcu_irq_node irq_list[DCU_IRQ_COUNT];
+
+ /*reg*/
+ u32 *dcu_base_reg;
+ u32 *clut_tile_mem_base;
+ u32 *gamma_r_mem_base;
+ u32 *gamma_g_mem_base;
+ u32 *gamma_b_mem_base;
+ u32 *cursor_mem_base;
+
+ struct device *platform_dev;
+ struct device *dcu_cdev;
+
+ uint32_t dcu_layer_transfer_complete_irq;
+ struct completion layer_transfer_complete;
+
+ /*use count*/
+ atomic_t dcu_use_count;
+ atomic_t layer_use_count;
+
+ struct mutex mutex_lock;
+ spinlock_t spin_lock;
+};
+
+static inline u32 dcu_read(struct dcu_soc *dcu, unsigned offset)
+{
+ return readl(dcu->dcu_base_reg + offset);
+}
+
+static inline void dcu_write(struct dcu_soc *dcu,
+ u32 value, unsigned offset)
+{
+ writel(value, dcu->dcu_base_reg + offset);
+}
+
+#endif /* __INCLUDE_DCU_H__ */
diff --git a/drivers/mvf/dcu4/dcu4_driver.c b/drivers/mvf/dcu4/dcu4_driver.c
new file mode 100644
index 000000000000..e6a637cf5f95
--- /dev/null
+++ b/drivers/mvf/dcu4/dcu4_driver.c
@@ -0,0 +1,1942 @@
+/*
+ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file dcu4_driver.c
+ *
+ * @brief This file contains the DCU driver common API functions.
+ *
+ * @ingroup DCU
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/clk.h>
+#include <mach/clock.h>
+#include <mach/hardware.h>
+#include <mach/dcu-v4.h>
+#include <mach/devices-common.h>
+#include <asm/cacheflush.h>
+#include <linux/delay.h>
+
+#include "dcu.h"
+#include "dcu4_regs.h"
+
+/*
+ * DCU Driver name
+ */
+#define MVF_DCU "mvf-dcuv4"
+
+/*
+ * DCU V4 limitations
+ */
+#define MAX_DISP_WIDTH 2048
+#define MAX_DISP_HEIGHT 2048
+#define MAX_DCU_LAYERS 64
+#define DCU_UNBLANK 0
+#define DCU_BLANK 1
+
+#define DCU_UNIT_TEST
+
+static struct dcu_soc dcu_array[MVF_DCU_MAX_NUM];
+static int g_dcu_hw_rev;
+static int major;
+static struct class *dcu_class;
+static uint32_t *tcon0_ctrl1;
+
+/* Static functions */
+static irqreturn_t dcu_irq_handler(int irq, void *desc);
+void dcu_enable_colorbar_mode(struct dcu_soc *dcu);
+void dcu_disable_colorbar_mode(struct dcu_soc *dcu);
+
+static dcu_bpp_format format_to_layerencoding(uint32_t fmt)
+{
+ switch (fmt){
+ case V4L2_PIX_FMT_RGB565:
+ return BPP16_RGB565;
+ case V4L2_PIX_FMT_RGB24:
+ return BPP24_RGB888;
+ case V4L2_PIX_FMT_RGB32:
+ return BPP32_ARGB8888;
+ default:
+ return BPP_INVALID;
+ }
+}
+
+static uint8_t layerencoding_to_min_width(dcu_bpp_format layerencoding)
+{
+ switch (layerencoding){
+ case BPP1_CLUT:
+ case BPP2_CLUT:
+ return 16;
+ case BPP4_CLUT:
+ case BPP4_LUMINANCE_OFFSET_MODE:
+ case BPP4_TRANSPARENCY_MODE:
+ return 8;
+ case BPP8_CLUT:
+ case BPP8_TRANSPARENCY_MODE:
+ case BPP8_LUMINANCE_OFFSET_MODE:
+ case YCbCr422:
+ case BPP24_RGB888:
+ return 4;
+ case BPP16_RGB565:
+ case BPP16_ARGB1555:
+ case BPP16_ARGB4444:
+ case BPP16_APAL8:
+ return 2;
+ case BPP32_ARGB8888:
+ return 1;
+ default:
+ return BPP_INVALID;
+ }
+}
+
+static void _dcu_lock(struct dcu_soc *dcu)
+{
+ /*TODO:Do we need the irq check?? See the flow of operations
+ * from V4L2 and FB*/
+ if (!in_irq() && !in_softirq())
+ {
+ mutex_lock(&dcu->mutex_lock);
+
+ if(dcu_read(dcu, DCU_UPDATE_MODE_OFFSET) & DCU_UPDATE_MODE_READREG_MASK)
+ {
+ int retval;
+ retval = wait_for_completion_interruptible_timeout(
+ &dcu->layer_transfer_complete, 1 * HZ);
+ if (retval == 0) {
+ dev_err(dcu->platform_dev, "MVF DCU lock: timeout\n");
+ }
+ }
+ }
+}
+
+static void _dcu_unlock(struct dcu_soc *dcu)
+{
+ uint32_t reg;
+ /* TODO: Make this more efficient? */
+ reg = dcu_read(dcu, DCU_UPDATE_MODE_OFFSET);
+ if(reg & DCU_UPDATE_MODE_MODE_MASK)
+ dev_err(dcu->platform_dev, "MVF DCU configured for unsupported automatic DCU update mode\n");
+ else
+ reg |= DCU_UPDATE_MODE_READREG_MASK;
+ dcu_write(dcu, reg, DCU_UPDATE_MODE_OFFSET);
+
+ init_completion(&dcu->layer_transfer_complete);
+ dcu_clear_irq(dcu, dcu->dcu_layer_transfer_complete_irq);
+ dcu_enable_irq(dcu, dcu->dcu_layer_transfer_complete_irq);
+
+ /*TODO:Do we need the irq check?? See the flow of operations
+ * from V4L2 and FB*/
+ if (!in_irq() && !in_softirq())
+ mutex_unlock(&dcu->mutex_lock);
+}
+
+static void _dcu_get(struct dcu_soc *dcu)
+{
+ if (atomic_inc_return(&dcu->dcu_use_count) == 1)
+ clk_enable(dcu->dcu_clk);
+}
+
+static void _dcu_put(struct dcu_soc *dcu)
+{
+ if (atomic_dec_return(&dcu->dcu_use_count) == 0)
+ clk_disable(dcu->dcu_clk);
+}
+#if 0
+static void dcu_reset(struct dcu_soc *dcu)
+{
+ u32 reg;
+ reg = dcu_read(dcu, DCU_DCU_MODE_OFFSET);
+ dcu_write(dcu, reg | DCU_DCU_MODE_DCU_SW_RESET_MASK, DCU_DCU_MODE_OFFSET);
+}
+#endif
+
+static inline struct dcu_soc *pixelclk2dcu(struct clk *clk)
+{
+ struct dcu_soc *dcu;
+ struct clk *base = clk - clk->id;
+
+ dcu = container_of(base, struct dcu_soc, pixel_clk);
+
+ return dcu;
+}
+
+static unsigned long _dcu_pixel_clk_get_rate(struct clk *clk)
+{
+ struct dcu_soc *dcu = pixelclk2dcu(clk);
+ u32 div;
+ u64 final_rate = clk_get_rate(clk->parent);
+
+ _dcu_get(dcu);
+ div = dcu_read(dcu, DCU_DIV_RATIO_OFFSET);
+ _dcu_put(dcu);
+ /* Actual value in register is div-1, so add 1 to get the real divider */
+ div++;
+ do_div(final_rate, div);
+ return (unsigned long)final_rate;
+}
+
+static unsigned long _dcu_pixel_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ u64 div, final_rate;
+ u32 remainder;
+ u64 parent_rate = (unsigned long long)clk_get_rate(clk->parent);
+
+ div = parent_rate;
+ remainder = do_div(div, rate);
+ /* Round the divider value */
+ if (remainder > (rate/2))
+ div++;
+ if (div == 0) /* Min DI disp clock divider is 1 */
+ div = 1;
+ else if (div > (DCU_DIV_RATIO_DIV_RATIO_MASK+1))
+ div = DCU_DIV_RATIO_DIV_RATIO_MASK+1;
+
+ final_rate = parent_rate;
+ do_div(final_rate, div);
+ return final_rate;
+}
+
+static int _dcu_pixel_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ u64 div, parent_rate;
+ u32 remainder;
+ struct dcu_soc *dcu = pixelclk2dcu(clk);
+
+ parent_rate = (unsigned long long)clk_get_rate(clk->parent);
+ div = parent_rate;
+ remainder = do_div(div, rate);
+ /* Round the divider value */
+ if (remainder > (rate/2))
+ div++;
+ if (div == 0) /* Min DI disp clock divider is 1 */
+ div = 1;
+ if (div > (DCU_DIV_RATIO_DIV_RATIO_MASK+1))
+ return -EINVAL;
+
+ /* While writing to the DIV_RATIO we need to subtract 1 */
+ div--;
+ dcu_write(dcu, (u32)div, DCU_DIV_RATIO_OFFSET);
+
+ return 0;
+}
+
+static int _dcu_pixel_clk_enable(struct clk *clk)
+{
+ /* We do not have an option to enable or disable this clock */
+ /* TODO: Do we need to look at the IOMUX settings to enable the clock
+ * to the pin/
+ */
+ return 0;
+}
+
+static void _dcu_pixel_clk_disable(struct clk *clk)
+{
+ /* We do not have an option to enable or disable this clock */
+ /* TODO: Do we need to look at the IOMUX settings to enable the clock
+ * to the pin/
+ */
+}
+
+static int _dcu_pixel_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ /* The parent for the pixel clock is always DCU clock */
+ /* However even though we cannot change this we do not have a good way
+ * of tell which DCU is the parent of this clock. So for now we will go
+ * ahead and implement this stub just for registering the parent
+ */
+ /* TODO: Get rid of this function and setup the parent of this clock in
+ * a more elegant fashion
+ */
+ return 0;
+}
+
+#ifdef CONFIG_CLK_DEBUG
+#define __INIT_CLK_DEBUG(n) .name = #n,
+#else
+#define __INIT_CLK_DEBUG(n)
+#endif
+struct clk dcu_pixel_clk = {
+ __INIT_CLK_DEBUG(pixel_clk)
+ .id = 0,
+ .get_rate = _dcu_pixel_clk_get_rate,
+ .set_rate = _dcu_pixel_clk_set_rate,
+ .round_rate = _dcu_pixel_clk_round_rate,
+ .set_parent = _dcu_pixel_clk_set_parent,
+ .enable = _dcu_pixel_clk_enable,
+ .disable = _dcu_pixel_clk_disable,
+};
+
+struct clk_lookup dcu_lookups[MVF_DCU_MAX_NUM] = {
+ {
+ .con_id = "pixel_clk",
+ },
+#if(MVF_DCU_MAX_NUM > 1)
+ {
+ .con_id = "pixel_clk",
+ },
+#endif
+};
+
+
+static int __devinit dcu_clk_setup_enable(struct dcu_soc *dcu,
+ struct platform_device *pdev)
+{
+ char dcu_clk[] = "dcu0_clk_root";
+ char dcu_clk_pg[] = "dcu0_clk";
+ struct clk *dcu_clk_pg_base;
+
+ dcu_clk[3] += pdev->id;
+
+ dcu_clk_pg_base = clk_get(dcu->platform_dev, dcu_clk_pg);
+ if (IS_ERR(dcu_clk_pg_base)) {
+ dev_err(dcu->platform_dev, "dcu_pg_clk_get failed");
+ return PTR_ERR(dcu_clk_pg_base);
+ }
+ clk_enable(dcu_clk_pg_base);
+
+ dcu->dcu_clk = clk_get(dcu->platform_dev, dcu_clk);
+ if (IS_ERR(dcu->dcu_clk)) {
+ dev_err(dcu->platform_dev, "dcu_clk_get failed");
+ return PTR_ERR(dcu->dcu_clk);
+ }
+ clk_set_rate(dcu->dcu_clk,120000000);
+ dev_dbg(dcu->platform_dev, "dcu_clk = %lu\n", clk_get_rate(dcu->dcu_clk));
+
+ dcu->pixel_clk = dcu_pixel_clk;
+
+ dcu_lookups[pdev->id].clk = &dcu->pixel_clk;
+ dcu_lookups[pdev->id].dev_id = dev_name(dcu->platform_dev);
+
+ clkdev_add(&dcu_lookups[pdev->id]);
+ clk_debug_register(&dcu->pixel_clk);
+ clk_enable(dcu->dcu_clk);
+ clk_set_parent(&dcu->pixel_clk, dcu->dcu_clk);
+
+ return 0;
+}
+
+
+/*!
+ * This function is called to initialize a LCD panel. It is called by the FB driver
+ * when any display related FB parameters changes or on init.
+ * Currently applies only to FB0 or FB1 and not for overlay FB's
+ *
+ * @param dcu dcu handler
+ *
+ * @param pixel_clk Desired pixel clock frequency in Hz.
+ *
+ * @param width The width of panel in pixels.
+ *
+ * @param height The height of panel in pixels.
+ *
+ * @param hStartWidth The number of pixel clocks between the HSYNC
+ * signal pulse and the start of valid data.
+ *
+ * @param hSyncWidth The width of the HSYNC signal in units of pixel
+ * clocks.
+ *
+ * @param hEndWidth The number of pixel clocks between the end of
+ * valid data and the HSYNC signal for next line.
+ *
+ * @param vStartWidth The number of lines between the VSYNC
+ * signal pulse and the start of valid data.
+ *
+ * @param vSyncWidth The width of the VSYNC signal in units of lines
+ *
+ * @param vEndWidth The number of lines between the end of valid
+ * data and the VSYNC signal for next frame.
+ *
+ * @param sig Bitfield of signal polarities for LCD interface.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t dcu_init_panel(struct dcu_soc *dcu, uint32_t pixel_clk,
+ uint16_t width, uint16_t height,
+ uint16_t h_start_width, uint16_t h_sync_width,
+ uint16_t h_end_width, uint16_t v_start_width,
+ uint16_t v_sync_width, uint16_t v_end_width,
+ uint32_t v_to_h_sync, dcu_di_signal_cfg_t sig)
+{
+ uint32_t reg;
+ uint32_t rounded_pixel_clk;
+
+ /* Setup panel resolution and timings*/
+ dev_dbg(dcu->platform_dev, "panel size = %d x %d\n", width, height);
+
+ if ((h_sync_width == 0) || (v_sync_width == 0) ||
+ (h_start_width == 0) || (v_start_width == 0) ||
+ (h_end_width == 0) || (v_end_width == 0))
+ {
+ dev_dbg(dcu->platform_dev, "HSYNC, VSYNC width and front/back porch width should be a minimum of 1\n");
+ return -EINVAL;
+ }
+
+ if((width % 16) != 0)
+ {
+ dev_dbg(dcu->platform_dev, "Display width needs to be a multiple of 16\n");
+ return -EINVAL;
+ }
+
+ if((width > MAX_DISP_WIDTH) || (height > MAX_DISP_HEIGHT))
+ {
+ dev_dbg(dcu->platform_dev, "Max width supported is %d, max height supported is %d\n",
+ MAX_DISP_WIDTH, MAX_DISP_HEIGHT);
+ return -EINVAL;
+ }
+
+ if (sig.interlaced) {
+ dev_dbg(dcu->platform_dev, "DCU does not support interlaced format\n");
+ _dcu_unlock(dcu);
+ return -EINVAL;
+ }
+
+ _dcu_lock(dcu);
+ reg = (uint32_t)((width/16) << DCU_DISP_SIZE_DELTA_X_SHIFT) |
+ (uint32_t)(height << DCU_DISP_SIZE_DELTA_Y_SHIFT);
+
+ dcu_write(dcu, reg, DCU_DISP_SIZE_OFFSET);
+
+ reg = (uint32_t)(h_sync_width << DCU_HSYN_PARA_PW_H_SHIFT) |
+ (uint32_t)(h_start_width << DCU_HSYN_PARA_BP_H_SHIFT) |
+ (uint32_t)(h_end_width << DCU_HSYN_PARA_FP_H_SHIFT);
+
+ dcu_write(dcu, reg, DCU_HSYN_PARA_OFFSET);
+
+ reg = (uint32_t)(v_sync_width << DCU_VSYN_PARA_PW_V_SHIFT) |
+ (uint32_t)(v_start_width << DCU_VSYN_PARA_BP_V_SHIFT) |
+ (uint32_t)(v_end_width << DCU_VSYN_PARA_FP_V_SHIFT);
+
+ dcu_write(dcu, reg, DCU_VSYN_PARA_OFFSET);
+
+ /* Setup signal polarity data*/
+ /* Read the signal polarity register first since its tied in with the PDI*/
+ reg = dcu_read(dcu, DCU_SYNPOL_OFFSET);
+ reg &= ~(DCU_SYNPOL_INV_HS_MASK | DCU_SYNPOL_INV_VS_MASK |
+ DCU_SYNPOL_NEG_MASK | DCU_SYNPOL_INV_PXCK_MASK);
+
+ if (!sig.Hsync_pol)
+ reg |= DCU_SYNPOL_INV_HS_MASK;
+ if (!sig.Vsync_pol)
+ reg |= DCU_SYNPOL_INV_VS_MASK;
+ if (sig.data_pol)
+ reg |= DCU_SYNPOL_NEG_MASK;
+ if (sig.clk_pol)
+ reg |= DCU_SYNPOL_INV_PXCK_MASK;
+
+ dcu_write(dcu, reg, DCU_SYNPOL_OFFSET);
+ _dcu_unlock(dcu);
+
+ /* Init clocking */
+ dev_dbg(dcu->platform_dev, "pixel clk = %d\n", pixel_clk);
+
+ clk_set_parent(&dcu->pixel_clk, dcu->dcu_clk);
+ rounded_pixel_clk = clk_round_rate(&dcu->pixel_clk, pixel_clk);
+ clk_set_rate(&dcu->pixel_clk, rounded_pixel_clk);
+ dcu->display_configured = true;
+
+ return 0;
+}
+EXPORT_SYMBOL(dcu_init_panel);
+
+static void dcu_blank(struct dcu_soc *dcu, int blank)
+{
+ struct mvf_dcuv4_platform_data *plat_data = dcu->platform_dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dcu->platform_dev);
+ if (plat_data->blank)
+ plat_data->blank(pdev->id, blank);
+}
+
+void dcu_enable(struct dcu_soc *dcu)
+{
+ u32 reg;
+ dcu_blank(dcu, DCU_UNBLANK);
+ /* TODO: Use count and clock */
+ _dcu_lock(dcu);
+ /* Enable the VSYNC and HSYNC */
+ reg = dcu_read(dcu, DCU_DCU_MODE_OFFSET);
+ reg |= DCU_DCU_MODE_RASTER_EN_MASK;
+ reg &= ~DCU_DCU_MODE_DCU_MODE_MASK;
+ reg |= (DCU_NORMAL_MODE << DCU_DCU_MODE_DCU_MODE_SHIFT);
+ dcu_write(dcu, reg, DCU_DCU_MODE_OFFSET);
+ _dcu_unlock(dcu);
+}
+EXPORT_SYMBOL(dcu_enable);
+
+void dcu_disable(struct dcu_soc *dcu)
+{
+ u32 reg;
+ /* TODO: Use count and clock */
+ _dcu_lock(dcu);
+ /* Disable the VSYNC and HSYNC */
+ reg = dcu_read(dcu, DCU_DCU_MODE_OFFSET);
+ reg &= ~DCU_DCU_MODE_RASTER_EN_MASK;
+ reg &= ~DCU_DCU_MODE_DCU_MODE_MASK;
+ dcu_write(dcu, reg, DCU_DCU_MODE_OFFSET);
+ _dcu_unlock(dcu);
+ dcu_blank(dcu, DCU_BLANK);
+}
+EXPORT_SYMBOL(dcu_disable);
+
+void dcu_uninit_panel(struct dcu_soc *dcu)
+{
+ _dcu_lock(dcu);
+
+ /* TODO: Support blanking the display??? */
+
+ _dcu_unlock(dcu);
+
+}
+EXPORT_SYMBOL(dcu_uninit_panel);
+
+struct dcu_soc *dcu_get_soc(int id)
+{
+ if (id >= MVF_DCU_MAX_NUM)
+ return ERR_PTR(-ENODEV);
+ else if (!dcu_array[id].online)
+ return ERR_PTR(-ENODEV);
+ else
+ return &(dcu_array[id]);
+}
+EXPORT_SYMBOL_GPL(dcu_get_soc);
+
+static irqreturn_t dcu_layer_transfer_complete_irq_handler(int irq, void *dev_id)
+{
+ struct dcu_soc *dcu = dev_id;
+ complete(&dcu->layer_transfer_complete);
+ dcu_disable_irq(dcu, irq);
+ return IRQ_HANDLED;
+}
+
+/*!
+ * This function is called by the driver framework to initialize the DCU
+ * hardware. This function performs the following operations:
+ * 1. Initialize software DCU module
+ * - Setup use count,
+* 2. Register the IRQ handler
+* 3. Remap the IO memory
+* 4. Initialize DCU clock ??
+* 5. Reset the DCU internal state and critical registers
+* 6. Registering the DCU device driver
+ *
+ * @param pdev The device structure for the DCU passed in by the
+ * driver framework.
+ *
+ * @return Returns 0 on success or negative error code on error
+ */
+static int __devinit dcu_probe(struct platform_device *pdev)
+{
+ struct mvf_dcuv4_platform_data *plat_data = pdev->dev.platform_data;
+ struct dcu_soc *dcu;
+ struct resource *res;
+ unsigned long dcu_base;
+ unsigned int layer_count;
+ int ret = 0;
+
+ if (pdev->id >= MVF_DCU_MAX_NUM)
+ return -ENODEV;
+
+ dcu = &dcu_array[pdev->id];
+ memset(dcu, 0, sizeof(struct dcu_soc));
+
+ spin_lock_init(&dcu->spin_lock);
+ mutex_init(&dcu->mutex_lock);
+ atomic_set(&dcu->dcu_use_count, 1);
+ atomic_set(&dcu->layer_use_count, 1);
+
+ /* Only one rev of DCU4, do not have any variants yet
+ * so store and forget */
+ g_dcu_hw_rev = plat_data->rev;
+
+ dcu->platform_dev = &pdev->dev;
+
+ dcu->irq_generic = platform_get_irq(pdev, 0);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res || dcu->irq_generic < 0) {
+ ret = -ENODEV;
+ goto failed_get_res;
+ }
+
+ if (request_irq(dcu->irq_generic, dcu_irq_handler, 0, pdev->name, dcu) != 0) {
+ dev_err(dcu->platform_dev, "request DCU generic interrupt failed\n");
+ ret = -EBUSY;
+ goto failed_req_irq_generic;
+ }
+
+ dcu_base = res->start;
+
+ dcu->dcu_base_reg = ioremap(dcu_base, SZ_8K);
+ dcu->clut_tile_mem_base = ioremap(dcu_base + DCU_CLUT_OFFSET, SZ_8K);
+ dcu->gamma_r_mem_base = ioremap(dcu_base + DCU_GAMMARED_OFFSET, PAGE_SIZE);
+ dcu->gamma_g_mem_base = ioremap(dcu_base + DCU_GAMMAGREEN_OFFSET, PAGE_SIZE);
+ dcu->gamma_b_mem_base = ioremap(dcu_base + DCU_GAMMABLUE_OFFSET, PAGE_SIZE);
+ dcu->cursor_mem_base = ioremap(dcu_base + DCU_CURSOR_OFFSET, PAGE_SIZE);
+
+ if (!dcu->dcu_base_reg || !dcu->clut_tile_mem_base || !dcu->gamma_r_mem_base ||
+ !dcu->gamma_g_mem_base || !dcu->gamma_b_mem_base || !dcu->cursor_mem_base) {
+ ret = -ENOMEM;
+ goto failed_ioremap;
+ }
+
+ dev_dbg(dcu->platform_dev, "DCU Base Regs = %p\n", dcu->dcu_base_reg);
+ dev_dbg(dcu->platform_dev, "DCU CLUT mem = %p\n", dcu->clut_tile_mem_base);
+ dev_dbg(dcu->platform_dev, "DCU Gamma R mem = %p\n", dcu->gamma_r_mem_base);
+ dev_dbg(dcu->platform_dev, "DCU Gamma G mem = %p\n", dcu->gamma_g_mem_base);
+ dev_dbg(dcu->platform_dev, "DCU Gamma B mem = %p\n", dcu->gamma_b_mem_base);
+ dev_dbg(dcu->platform_dev, "DCU Cursor mem = %p\n", dcu->cursor_mem_base);
+
+ ret = dcu_clk_setup_enable(dcu, pdev);
+ if (ret < 0) {
+ dev_err(dcu->platform_dev, "dcu clk setup failed\n");
+ goto failed_clk_setup;
+ }
+
+ platform_set_drvdata(pdev, dcu);
+
+ /* dcu_reset(dcu); */
+
+ /* Layer config registers are RAM with unknown values.
+ * Initialize layers to be off, this is a must since reset value is unknown */
+ for(layer_count=0;layer_count<MAX_DCU_LAYERS;layer_count++)
+ {
+ dcu_write(dcu, 0, DCU_CTRLDESCLx_y_OFFSET(layer_count,DCU_CTRLDESCL_OFFSET4));
+ }
+ register_dcu_device(dcu, pdev->id);
+ /* TODO: Cleanup and move to TCON header file/driver */
+ tcon0_ctrl1 = ioremap(TCON0_BASE + TCON_CTRL1_OFFSET, PAGE_SIZE);
+ writel(TCON_CTRL1_TCON_BYPASS_MASK, tcon0_ctrl1);
+
+ /*Setup the layer transfer IRQ */
+ dcu->dcu_layer_transfer_complete_irq = DCU_IRQ_LYR_TRANS_FINISH;
+ if (dcu_request_irq(dcu, dcu->dcu_layer_transfer_complete_irq, dcu_layer_transfer_complete_irq_handler, 0,
+ MVF_DCU, dcu) != 0) {
+ dev_err(dcu->platform_dev, "Error registering DCU irq %d\n",
+ dcu->dcu_layer_transfer_complete_irq);
+ goto failed_clk_setup;
+ }
+ dcu_disable_irq(dcu, dcu->dcu_layer_transfer_complete_irq);
+
+
+ /* TODO: Why is the clock being disabled? */
+ //clk_disable(dcu->dcu_clk);
+ dcu->online = true;
+ dcu->display_configured = false;
+
+ return ret;
+
+failed_clk_setup:
+ iounmap(dcu->dcu_base_reg);
+ iounmap(dcu->clut_tile_mem_base);
+ iounmap(dcu->gamma_r_mem_base);
+ iounmap(dcu->gamma_g_mem_base);
+ iounmap(dcu->gamma_b_mem_base);
+ iounmap(dcu->cursor_mem_base);
+failed_ioremap:
+ if (dcu->irq_generic)
+ free_irq(dcu->irq_generic, dcu);
+failed_req_irq_generic:
+failed_get_res:
+ return ret;
+}
+
+int __devexit dcu_remove(struct platform_device *pdev)
+{
+ struct dcu_soc *dcu = platform_get_drvdata(pdev);
+
+ unregister_dcu_device(dcu, pdev->id);
+
+ if (dcu->irq_generic)
+ free_irq(dcu->irq_generic, dcu);
+
+ clk_put(dcu->dcu_clk);
+
+ iounmap(dcu->dcu_base_reg);
+ iounmap(dcu->clut_tile_mem_base);
+ iounmap(dcu->gamma_r_mem_base);
+ iounmap(dcu->gamma_g_mem_base);
+ iounmap(dcu->gamma_b_mem_base);
+ iounmap(dcu->cursor_mem_base);
+ return 0;
+}
+
+#ifdef DCU_UNIT_TEST
+static const uint32_t white_color[]= {
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+static const uint32_t black_color[]= {
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
+ 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0
+};
+
+void dcu_unit_test_config_display(struct dcu_soc *dcu)
+{
+ dcu_di_signal_cfg_t sig;
+ sig.Hsync_pol = 0;
+ sig.Vsync_pol = 0;
+ dcu_init_panel(dcu, 11000000, 480, 272, 2, 41, 2, 1,
+ 2, 1, 0, sig);
+}
+
+void dcu_unit_test(struct dcu_soc *dcu)
+{
+ dcu_color_t color;
+ color.color_r = 0xFF;
+
+ //Color bar mode test
+ dcu_enable_colorbar_mode(dcu);
+ printk("Colorbar mode enabled\n");
+ msleep(5000);
+ dcu_disable_colorbar_mode(dcu);
+ printk("Colorbar mode disabled\n");
+ msleep(5000);
+
+ //Background color test
+ dcu_set_bgnd_color(dcu, color);
+ printk("Background color set to red\n");
+ dcu_enable(dcu);
+ msleep(5000);
+ color.color_r = 0x00;
+ color.color_g = 0xFF;
+ dcu_set_bgnd_color(dcu, color);
+ printk("Background color set to green\n");
+ msleep(5000);
+
+ //Layer test
+ dcu_init_layer(dcu, 0,
+ V4L2_PIX_FMT_RGB32, 16, 16,
+ (dma_addr_t)black_color,
+ 0, 0);
+ dcu_enable_layer(dcu,0);
+ printk("Layer 0 enabled, 16x16 Black square @top left corner\n");
+ msleep(5000);
+ dcu_init_layer(dcu, 1,
+ V4L2_PIX_FMT_RGB32, 16, 16,
+ (dma_addr_t)black_color,
+ 16, 16);
+ dcu_enable_layer(dcu,1);
+ printk("Layer 1 enabled, 16x16 Black square @offset 16x16 from top left corner\n");
+ msleep(5000);
+ dcu_set_layer_position(dcu, 1, 32,32);
+ printk("Layer 1 position now @offset 32x32 from top left corner\n");
+ dcu_update_layer_buffer(dcu, 1, (dma_addr_t)white_color);
+ printk("Layer 1 image updated to white color\n");
+ msleep(5000);
+ dcu_config_layer_alpha(dcu, 1, 0x3F, ALPHA_BLEND_ENABLED);
+ printk("Layer 1 alpha set to 0x3F\n");
+ msleep(5000);
+
+ //Test enable disable of DCU and layer
+ dcu_disable(dcu);
+ printk("DCU disabled\n");
+ msleep(5000);
+ printk("DCU enabled\n");
+ dcu_enable(dcu);
+ msleep(5000);
+ dcu_disable_layer(dcu, 1, 0);
+ dcu_uninit_layer(dcu, 1);
+ printk("Layer 1 disabled and uninit\n");
+ msleep(5000);
+ dcu_disable_layer(dcu, 0, 0);
+ dcu_uninit_layer(dcu, 0);
+ printk("Layer 0 disabled and uninit\n");
+ dcu_disable(dcu);
+ printk("DCU disabled\n");
+}
+#endif
+
+void dcu_dump_registers(struct dcu_soc *dcu)
+{
+ /* Display related */
+ dev_dbg(dcu->platform_dev, "DCU_DISP_SIZE = \t0x%08X\n", dcu_read(dcu, DCU_DISP_SIZE_OFFSET));
+ dev_dbg(dcu->platform_dev, "DCU_HSYN_PARA = \t0x%08X\n", dcu_read(dcu, DCU_HSYN_PARA_OFFSET));
+ dev_dbg(dcu->platform_dev, "DCU_VSYN_PARA = \t0x%08X\n", dcu_read(dcu, DCU_VSYN_PARA_OFFSET));
+ dev_dbg(dcu->platform_dev, "DCU_SYNPOL = \t0x%08X\n", dcu_read(dcu, DCU_SYNPOL_OFFSET));
+ dev_dbg(dcu->platform_dev, "DCU_DIV_RATIO = \t0x%08X\n", dcu_read(dcu, DCU_DIV_RATIO_OFFSET));
+
+ /* Global DCU related */
+ dev_dbg(dcu->platform_dev, "DCU_DCU_MODE = \t0x%08X\n", dcu_read(dcu, DCU_DCU_MODE_OFFSET));
+ dev_dbg(dcu->platform_dev, "DCU_BGND = \t0x%08X\n", dcu_read(dcu, DCU_BGND_OFFSET));
+
+ /* Interrupt status */
+ dev_dbg(dcu->platform_dev, "DCU_PARR_ERR_STATUS1 = \t0x%08X\n", dcu_read(dcu, DCU_PARR_ERR_STATUS1_OFFSET));
+ dev_dbg(dcu->platform_dev, "DCU_PARR_ERR_STATUS2 = \t0x%08X\n", dcu_read(dcu, DCU_PARR_ERR_STATUS2_OFFSET));
+ dev_dbg(dcu->platform_dev, "DCU_PARR_ERR_STATUS3 = \t0x%08X\n", dcu_read(dcu, DCU_PARR_ERR_STATUS3_OFFSET));
+
+ /* Layer 0 info*/
+ dev_dbg(dcu->platform_dev, "DCU_CTRLDESCL0_OFFSET1 = \t0x%08X\n",
+ dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(0,DCU_CTRLDESCL_OFFSET1)));
+ dev_dbg(dcu->platform_dev, "DCU_CTRLDESCL0_OFFSET2 = \t0x%08X\n",
+ dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(0,DCU_CTRLDESCL_OFFSET2)));
+ dev_dbg(dcu->platform_dev, "DCU_CTRLDESCL0_OFFSET3 = \t0x%08X\n",
+ dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(0,DCU_CTRLDESCL_OFFSET3)));
+ dev_dbg(dcu->platform_dev, "DCU_CTRLDESCL0_OFFSET4 = \t0x%08X\n",
+ dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(0,DCU_CTRLDESCL_OFFSET4)));
+
+}
+
+
+/*!
+ * This function is called to initialize buffer(s) for logical DCU layer.
+ *
+ * @param dcu dcu handler
+ *
+ * @param layer Input parameter for the logical layer ID.
+ *
+ * @param pixel_fmt Input parameter for pixel format of buffer.
+ * Pixel format is a FOURCC ASCII code.
+ *
+ * @param width Input parameter for width of buffer in pixels.
+ *
+ * @param height Input parameter for height of buffer in pixels.
+ *
+ * @param phyaddr Input parameter buffer physical address.
+ *
+ * @param u private u offset for additional cropping,
+ * zero if not used.
+ *
+ * @param v private v offset for additional cropping,
+ * zero if not used.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t dcu_init_layer(struct dcu_soc *dcu, uint8_t layer,
+ uint32_t pixel_fmt,
+ uint16_t width, uint16_t height,
+ dma_addr_t phyaddr_0,
+ int16_t x_pos, int16_t y_pos)
+{
+ int ret = 0;
+ uint32_t reg;
+ uint8_t layer_encoding_format;
+ uint8_t min_width;
+
+ dev_dbg(dcu->platform_dev, "init layer = %d\n", layer);
+
+ /* Check for valid layer number and resolution as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if((width > MAX_DISP_WIDTH) || (height > MAX_DISP_HEIGHT))
+ {
+ dev_err(dcu->platform_dev, "Max width supported is %d, max height supported is %d\n",
+ MAX_DISP_WIDTH, MAX_DISP_HEIGHT);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if((x_pos > (MAX_DISP_WIDTH-1) ) || (x_pos < -MAX_DISP_WIDTH) ||
+ (y_pos > (MAX_DISP_HEIGHT-1)) || (y_pos < -MAX_DISP_HEIGHT))
+ {
+ dev_err(dcu->platform_dev, "Offset is out of range. Range for x offset is %d to %d\n \
+ y offset is %d to %d\n", (MAX_DISP_WIDTH-1), -MAX_DISP_WIDTH,
+ (MAX_DISP_HEIGHT-1), -MAX_DISP_HEIGHT);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Check if the DCU supports the pixel format provided by the user */
+ layer_encoding_format = format_to_layerencoding(pixel_fmt);
+
+ if(layer_encoding_format == BPP_INVALID)
+ {
+ dev_err(dcu->platform_dev, "Image format %d is not supported by hardware\n", pixel_fmt);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ min_width = layerencoding_to_min_width(layer_encoding_format);
+ if(width % min_width)
+ {
+ dev_err(dcu->platform_dev, "Width must be multiple integer multiple of the number of\
+ pixels that are represented by a 32-bit word: %d\n", min_width);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ _dcu_get(dcu);
+ _dcu_lock(dcu);
+
+ /* Check if layer is already being used */
+ reg = dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+ if (reg & DCU_CTRLDESCLn_4_EN_MASK) {
+ dev_warn(dcu->platform_dev, "Warning: layer already initialized %d\n", layer);
+ }
+
+ /* Write all the parameters passed in */
+ reg = (uint32_t)(layer_encoding_format << DCU_CTRLDESCLn_4_BPP_SHIFT);
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+
+ reg = (uint32_t)(width << DCU_CTRLDESCLn_1_WIDTH_SHIFT) |
+ (uint32_t)(height << DCU_CTRLDESCLn_1_HEIGHT_SHIFT);
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET1));
+
+ dcu_write(dcu, phyaddr_0, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET3));
+
+ /* Default offset from display is 0,0. User will can change this using IOCTL */
+ /* TODO: Check if 2's complement format will cause any issues */
+ reg = (uint32_t)(y_pos << DCU_CTRLDESCLn_2_POSY_SHIFT) |
+ (uint32_t)(x_pos << DCU_CTRLDESCLn_2_POSX_SHIFT);
+
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET2));
+
+ _dcu_unlock(dcu);
+
+err:
+ return ret;
+}
+EXPORT_SYMBOL(dcu_init_layer);
+
+/*!
+ * This function is called to uninitialize a DCU layer.
+ *
+ * @param dcu dcu handler
+ * @param layer Input parameter for the logical layer ID to uninit.
+ */
+void dcu_uninit_layer(struct dcu_soc *dcu, uint8_t layer)
+{
+ uint32_t reg;
+ uint32_t reg_offset_count;
+
+ /* Check for valid layer numbe as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ return;
+ }
+
+ _dcu_lock(dcu);
+ reg = dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+ if (reg & DCU_CTRLDESCLn_4_EN_MASK) {
+ dev_err(dcu->platform_dev, "Disable layer first %d\n", layer);
+ _dcu_unlock(dcu);
+ return;
+ }
+
+ /* Clear out all layer data */
+ for(reg_offset_count=0; reg_offset_count <= DCU_CTRLDESCL_OFFSET_MAX; reg_offset_count++)
+ dcu_write(dcu, 0, DCU_CTRLDESCLx_y_OFFSET(layer, reg_offset_count));
+
+ /* TODO: Do we need to decrement the usecount for each layer
+ * after we uninit it?
+ */
+
+ /* TODO: Do we need to disable any interrupts here? */
+
+ /* TODO: Do we need to disable the DCU/clocks once all the layers are disabled */
+
+ /* TODO: Do we need to clear any status registers associated with this layer? */
+
+ /* Sample code for waiting from IPU
+
+ if(wait_for_stop)
+ {
+ int timeout = 50;
+
+ dcu_write(dcu, IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF),
+ IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF));
+ while ((dcu_read(dcu, IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF)) &
+ IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF)) == 0) {
+ msleep(10);
+ timeout -= 10;
+ if (timeout <= 0) {
+ dev_err(dcu->platform_dev, "warning: wait for bg sync eof timeout\n");
+ break;
+ }
+ }
+ }
+ */
+ _dcu_unlock(dcu);
+ _dcu_put(dcu);
+
+ //WARN_ON(dcu->dcu_use_count < 0);
+}
+EXPORT_SYMBOL(dcu_uninit_layer);
+
+/*!
+ * This function is called to update the physical address of a buffer for
+ * a logical DCU layer.
+ *
+ * @param dcu dcu handler
+ * @param layer Input parameter for the logical layer ID.
+ * @param phyaddr Input parameter buffer physical address
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t dcu_update_layer_buffer(struct dcu_soc *dcu, uint8_t layer,
+ dma_addr_t phyaddr)
+{
+ /* Check for valid layer numbe as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ return -EINVAL;
+ }
+
+ _dcu_lock(dcu);
+
+ dcu_write(dcu, phyaddr, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET3));
+
+ _dcu_unlock(dcu);
+
+ return 0;
+}
+EXPORT_SYMBOL(dcu_update_layer_buffer);
+
+
+/*!
+ * This function is called to initialize a buffer for logical DCU layer.
+ *
+ * @param dcu dcu handler
+ * @param layer Input parameter for the logical layer ID.
+ * @param x_pos x offset from display start, can be positive or negative
+ * @param y_pos y offset from display start, can be positive or negative
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t dcu_set_layer_position(struct dcu_soc *dcu, uint8_t layer, int16_t x_pos,
+ int16_t y_pos)
+{
+ uint32_t reg;
+ /* Check for valid layer number as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ return -EINVAL;
+ }
+
+ if((x_pos > (MAX_DISP_WIDTH-1) ) || (x_pos < -MAX_DISP_WIDTH) ||
+ (y_pos > (MAX_DISP_HEIGHT-1)) || (y_pos < -MAX_DISP_HEIGHT))
+ {
+ dev_err(dcu->platform_dev, "Offset is out of range. Range for x offset is %d to %d\n \
+ y offset is %d to %d\n", (MAX_DISP_WIDTH-1), -MAX_DISP_WIDTH,
+ (MAX_DISP_HEIGHT-1), -MAX_DISP_HEIGHT);
+ return -EINVAL;
+ }
+
+ _dcu_lock(dcu);
+
+ /* TODO: Do we need to check 2's complement format for negative position */
+ reg = (uint32_t)(y_pos << DCU_CTRLDESCLn_2_POSY_SHIFT) |
+ (uint32_t)(x_pos << DCU_CTRLDESCLn_2_POSX_SHIFT);
+
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET2));
+
+ _dcu_unlock(dcu);
+ return 0;
+}
+EXPORT_SYMBOL(dcu_set_layer_position);
+
+
+int32_t dcu_get_layer_position(struct dcu_soc *dcu, uint8_t layer, int16_t *x_pos,
+ int16_t *y_pos)
+{
+ uint32_t reg;
+ /* Check for valid layer number as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ return -EINVAL;
+ }
+
+ _dcu_lock(dcu);
+ reg = dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET2));
+ _dcu_unlock(dcu);
+
+ *y_pos = (reg & DCU_CTRLDESCLn_2_POSY_MASK) >> DCU_CTRLDESCLn_2_POSY_SHIFT;
+ *x_pos = (reg & DCU_CTRLDESCLn_2_POSX_MASK) >> DCU_CTRLDESCLn_2_POSX_SHIFT;
+
+ return 0;
+}
+EXPORT_SYMBOL(dcu_get_layer_position);
+
+/*!
+ * This function check whether a logical layer was enabled.
+ *
+ * @param dcu dcu handler
+ * @param layer Input parameter for the logical layer ID.
+ *
+ * @return This function returns 1 while request layer is enabled or
+ * 0 for not enabled.
+ */
+int32_t dcu_is_layer_enabled(struct dcu_soc *dcu, uint8_t layer)
+{
+ uint32_t reg;
+ /* Check for valid layer number as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ return -EINVAL;
+ }
+
+ reg = dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+ if (reg & DCU_CTRLDESCLn_4_EN_MASK)
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(dcu_is_layer_enabled);
+
+/*!
+ * This function enables a logical layer.
+ *
+ * @param dcu dcu handler
+ * @param layer Input parameter for the logical layer ID.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t dcu_enable_layer(struct dcu_soc *dcu, uint8_t layer)
+{
+ u32 reg;
+ /* Check for valid layer number as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ return -EINVAL;
+ }
+
+ _dcu_lock(dcu);
+ reg = dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+ if (reg & DCU_CTRLDESCLn_4_EN_MASK)
+ {
+ dev_err(dcu->platform_dev, "Warning: layer already enabled %d\n", layer);
+ _dcu_unlock(dcu);
+ return -EACCES;
+ }
+
+ /* TODO: Do we need to check the usecount for each layer
+ * to ensure it is initialized before it is enabled?
+ */
+ reg |= DCU_CTRLDESCLn_4_EN_MASK;
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+
+ _dcu_unlock(dcu);
+ return 0;
+}
+EXPORT_SYMBOL(dcu_enable_layer);
+
+/*!
+ * This function disables a logical layer.
+ *
+ * @param dcu dcu handler
+ * @param layer Input parameter for the logical layer ID.
+ *
+ * @param wait_for_stop Flag to set whether to wait for layer end
+ * of frame or return immediately.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t dcu_disable_layer(struct dcu_soc *dcu, uint8_t layer, bool wait_for_stop)
+{
+ uint32_t reg;
+
+ /* Check for valid layer number as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ return -EINVAL;
+ }
+
+ _dcu_lock(dcu);
+
+ reg = dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+ if (!(reg & DCU_CTRLDESCLn_4_EN_MASK))
+ {
+ dev_err(dcu->platform_dev, "Warning: layer already disabled %d\n", layer);
+ _dcu_unlock(dcu);
+ return -EACCES;
+ }
+
+ reg &= ~DCU_CTRLDESCLn_4_EN_MASK;
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+
+ _dcu_unlock(dcu);
+
+ return 0;
+}
+EXPORT_SYMBOL(dcu_disable_layer);
+
+/*!
+ * This function sets the DCU Background color.
+ *
+ * @param dcu dcu handler
+ * @param color desired rgb color for background
+ *
+ */
+void dcu_set_bgnd_color(struct dcu_soc *dcu, dcu_color_t color)
+{
+ uint32_t reg;
+
+ _dcu_lock(dcu);
+
+ reg = (uint32_t)(color.color_r << DCU_BGND_BGND_R_SHIFT) |
+ (uint32_t)(color.color_g << DCU_BGND_BGND_G_SHIFT) |
+ (uint32_t)(color.color_b << DCU_BGND_BGND_B_SHIFT);
+ dcu_write(dcu, reg, DCU_BGND_OFFSET);
+
+ _dcu_unlock(dcu);
+}
+EXPORT_SYMBOL(dcu_set_bgnd_color);
+
+/*!
+ * This function configures alpha .
+ *
+ * @param dcu dcu handler
+ * @param layer layer id
+ * @param alpha_value desired layer transparency value
+ * @param aa mode of alpha blending
+ *
+ */
+int32_t dcu_config_layer_alpha(struct dcu_soc *dcu, uint8_t layer,
+ uint8_t alpha_value, alpha_aa_config aa)
+{
+ uint32_t reg;
+ /* Check for valid layer number as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ return -EINVAL;
+ }
+
+ _dcu_lock(dcu);
+ reg = dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+ reg |= (uint32_t)(alpha_value << DCU_CTRLDESCLn_4_TRANS_SHIFT);
+ reg |= (uint32_t)(aa << DCU_CTRLDESCLn_4_AB_SHIFT);
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+ _dcu_unlock(dcu);
+
+ return 0;
+}
+EXPORT_SYMBOL(dcu_config_layer_alpha);
+
+/*!
+ * This function sets chroma keying RGB color values
+ *
+ * @param dcu dcu handler
+ * @param layer layer id
+ * @param color_max max color value
+ * @param color_min min color value
+ * @param enable enable or disable chroma keying
+ */
+int32_t dcu_set_chroma_keying(struct dcu_soc *dcu, uint8_t layer,
+ dcu_color_t color_max, dcu_color_t color_min, bool enable)
+{
+ uint32_t reg;
+ /* Check for valid layer number as supported by DCU */
+ if(layer >= MAX_DCU_LAYERS)
+ {
+ dev_err(dcu->platform_dev, "Invalid layer number %d\n", layer);
+ return -EINVAL;
+ }
+
+ _dcu_lock(dcu);
+ reg = (uint32_t)(color_max.color_r << DCU_BGND_BGND_R_SHIFT) |
+ (uint32_t)(color_max.color_g << DCU_BGND_BGND_G_SHIFT) |
+ (uint32_t)(color_max.color_b << DCU_BGND_BGND_B_SHIFT);
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET5));
+
+ reg = (uint32_t)(color_min.color_r << DCU_BGND_BGND_R_SHIFT) |
+ (uint32_t)(color_min.color_g << DCU_BGND_BGND_G_SHIFT) |
+ (uint32_t)(color_min.color_b << DCU_BGND_BGND_B_SHIFT);
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET6));
+
+ reg = dcu_read(dcu, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+ if(enable)
+ reg |= DCU_CTRLDESCLn_4_BB_MASK;
+ else
+ reg &= ~DCU_CTRLDESCLn_4_BB_MASK;
+ dcu_write(dcu, reg, DCU_CTRLDESCLx_y_OFFSET(layer,DCU_CTRLDESCL_OFFSET4));
+ _dcu_unlock(dcu);
+
+ return 0;
+}
+EXPORT_SYMBOL(dcu_set_chroma_keying);
+
+static irqreturn_t dcu_irq_handler(int irq, void *desc)
+{
+ struct dcu_soc *dcu = desc;
+ uint32_t line;
+ irqreturn_t result = IRQ_NONE;
+ uint32_t int_stat;
+ unsigned long lock_flags = 0;
+
+ //Param 1 interrupts
+ spin_lock_irqsave(&dcu->spin_lock, lock_flags);
+ int_stat = dcu_read(dcu, DCU_PARR_ERR_STATUS1_OFFSET);
+ int_stat &= ~(dcu_read(dcu, DCU_MASK_PARR_ERR_STATUS1_OFFSET));
+
+ if (int_stat) {
+ dcu_write(dcu, int_stat, DCU_PARR_ERR_STATUS1_OFFSET);
+ dev_err(dcu->platform_dev,
+ "DCU Error - DCU_PARR_ERR_STATUS1 = 0x%08X\n", int_stat);
+ /* Disable interrupts so we only get error once */
+ int_stat |=
+ dcu_read(dcu, DCU_PARR_ERR_STATUS1_OFFSET);
+ dcu_write(dcu, int_stat, DCU_MASK_PARR_ERR_STATUS1_OFFSET);
+ }
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+
+ //Param 2 interrupts
+ spin_lock_irqsave(&dcu->spin_lock, lock_flags);
+ int_stat = dcu_read(dcu, DCU_PARR_ERR_STATUS2_OFFSET);
+ int_stat &= ~(dcu_read(dcu, DCU_MASK_PARR_ERR_STATUS2_OFFSET));
+
+ if (int_stat) {
+ dcu_write(dcu, int_stat, DCU_PARR_ERR_STATUS2_OFFSET);
+ dev_err(dcu->platform_dev,
+ "DCU Error - DCU_PARR_ERR_STATUS2 = 0x%08X\n", int_stat);
+ /* Disable interrupts so we only get error once */
+ int_stat |=
+ dcu_read(dcu, DCU_PARR_ERR_STATUS2_OFFSET);
+ dcu_write(dcu, int_stat, DCU_MASK_PARR_ERR_STATUS2_OFFSET);
+ }
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+
+ //Param 3 interrupts
+ spin_lock_irqsave(&dcu->spin_lock, lock_flags);
+ int_stat = dcu_read(dcu, DCU_PARR_ERR_STATUS3_OFFSET);
+ int_stat &= ~(dcu_read(dcu, DCU_MASK_PARR_ERR_STATUS3_OFFSET));
+
+ if (int_stat) {
+ dcu_write(dcu, int_stat, DCU_PARR_ERR_STATUS3_OFFSET);
+ dev_err(dcu->platform_dev,
+ "DCU Error - DCU_PARR_ERR_STATUS3 = 0x%08X\n", int_stat);
+ /* Disable interrupts so we only get error once */
+ int_stat |=
+ dcu_read(dcu, DCU_PARR_ERR_STATUS3_OFFSET);
+ dcu_write(dcu, int_stat, DCU_MASK_PARR_ERR_STATUS3_OFFSET);
+ }
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+
+ spin_lock_irqsave(&dcu->spin_lock, lock_flags);
+ int_stat = dcu_read(dcu, DCU_INT_STATUS_OFFSET);
+ int_stat &= ~(dcu_read(dcu, DCU_INT_MASK_OFFSET));
+ dcu_write(dcu, int_stat, DCU_INT_STATUS_OFFSET);
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+ while ((line = ffs(int_stat)) != 0) {
+ line--;
+ int_stat &= ~(1UL << line);
+ result |=
+ dcu->irq_list[line].handler(line,
+ dcu->irq_list[line].
+ dev_id);
+ }
+
+ return result;
+}
+
+/*!
+ * This function enables the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b dcu_irq_line enum.
+ *
+ * @param dcu dcu handler
+ * @param irq Interrupt line to enable interrupt for.
+ *
+ */
+void dcu_enable_irq(struct dcu_soc *dcu, uint32_t irq)
+{
+ uint32_t reg;
+ unsigned long lock_flags;
+
+ _dcu_get(dcu);
+
+ spin_lock_irqsave(&dcu->spin_lock, lock_flags);
+
+ /* TODO: Make this code more flexible to handle PDI and Error IRQ */
+ reg = dcu_read(dcu, DCU_INT_MASK_OFFSET);
+ reg &= ~DCU_IRQ_MASK(irq);
+ dcu_write(dcu, reg, DCU_INT_MASK_OFFSET);
+
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+
+ _dcu_put(dcu);
+}
+EXPORT_SYMBOL(dcu_enable_irq);
+
+/*!
+ * This function disables the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b dcu_irq_line enum.
+ *
+ * @param dcu dcu handler
+ * @param irq Interrupt line to disable interrupt for.
+ *
+ */
+void dcu_disable_irq(struct dcu_soc *dcu, uint32_t irq)
+{
+ uint32_t reg;
+ unsigned long lock_flags;
+
+ _dcu_get(dcu);
+
+ spin_lock_irqsave(&dcu->spin_lock, lock_flags);
+
+ /* TODO: Make this code more flexible to handle PDI and Error IRQ */
+ reg = dcu_read(dcu, DCU_INT_MASK_OFFSET);
+ reg |= DCU_IRQ_MASK(irq);
+ dcu_write(dcu, reg, DCU_INT_MASK_OFFSET);
+
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+
+ _dcu_put(dcu);
+}
+EXPORT_SYMBOL(dcu_disable_irq);
+
+/*!
+ * This function clears the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b dcu_irq_line enum.
+ *
+ * @param dcu dcu handler
+ * @param irq Interrupt line to clear interrupt for.
+ *
+ */
+void dcu_clear_irq(struct dcu_soc *dcu, uint32_t irq)
+{
+ unsigned long lock_flags;
+
+ _dcu_get(dcu);
+
+ spin_lock_irqsave(&dcu->spin_lock, lock_flags);
+
+ /* TODO: Make this code more flexible to handle PDI and Error IRQ */
+ dcu_write(dcu, DCU_IRQ_MASK(irq), DCU_INT_STATUS_OFFSET);
+
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+
+ _dcu_put(dcu);
+}
+EXPORT_SYMBOL(dcu_clear_irq);
+
+/*!
+ * This function returns the current interrupt status for the specified
+ * interrupt line. The interrupt lines are defined in \b dcu_irq_line enum.
+ *
+ * @param dcu dcu handler
+ * @param irq Interrupt line to get status for.
+ *
+ * @return Returns true if the interrupt is pending/asserted or false if
+ * the interrupt is not pending.
+ */
+bool dcu_get_irq_status(struct dcu_soc *dcu, uint32_t irq)
+{
+ uint32_t reg;
+
+ _dcu_get(dcu);
+
+ /* TODO: Make this code more flexible to handle PDI and Error IRQ */
+ /* TODO: Why does this code not have irq save? */
+ reg = dcu_read(dcu, DCU_INT_STATUS_OFFSET);
+
+ _dcu_put(dcu);
+
+ if (reg & DCU_IRQ_MASK(irq))
+ return true;
+ else
+ return false;
+}
+EXPORT_SYMBOL(dcu_get_irq_status);
+
+/*!
+ * This function registers an interrupt handler function for the specified
+ * interrupt line. The interrupt lines are defined in \b dcu_irq_line enum.
+ *
+ * @param dcu dcu handler
+ * @param irq Interrupt line to get status for.
+ *
+ * @param handler Input parameter for address of the handler
+ * function.
+ *
+ * @param irq_flags Flags for interrupt mode. Currently not used.
+ *
+ * @param devname Input parameter for string name of driver
+ * registering the handler.
+ *
+ * @param dev_id Input parameter for pointer of data to be
+ * passed to the handler.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int dcu_request_irq(struct dcu_soc *dcu, uint32_t irq,
+ irqreturn_t(*handler) (int, void *),
+ uint32_t irq_flags, const char *devname, void *dev_id)
+{
+ unsigned long lock_flags;
+
+ BUG_ON(irq >= DCU_IRQ_COUNT);
+
+ _dcu_get(dcu);
+
+ spin_lock_irqsave(&dcu->spin_lock, lock_flags);
+
+ if (dcu->irq_list[irq].handler != NULL) {
+ dev_err(dcu->platform_dev,
+ "handler already installed on irq %d\n", irq);
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+ return -EINVAL;
+ }
+
+ dcu->irq_list[irq].handler = handler;
+ dcu->irq_list[irq].flags = irq_flags;
+ dcu->irq_list[irq].dev_id = dev_id;
+ dcu->irq_list[irq].name = devname;
+
+ /* TODO: Make this code more flexible to handle PDI and Error IRQ */
+ /* clear irq stat for previous use */
+ dcu_write(dcu, DCU_IRQ_MASK(irq), DCU_INT_STATUS_OFFSET);
+
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+
+ _dcu_put(dcu);
+
+ dcu_enable_irq(dcu, irq); /* enable the interrupt */
+
+ return 0;
+}
+EXPORT_SYMBOL(dcu_request_irq);
+
+/*!
+ * This function unregisters an interrupt handler for the specified interrupt
+ * line. The interrupt lines are defined in \b dcu_irq_line enum.
+ *
+ * @param dcu dcu handler
+ * @param irq Interrupt line to get status for.
+ *
+ * @param dev_id Input parameter for pointer of data to be passed
+ * to the handler. This must match value passed to
+ * dcu_request_irq().
+ *
+ */
+void dcu_free_irq(struct dcu_soc *dcu, uint32_t irq, void *dev_id)
+{
+ unsigned long lock_flags;
+
+ dcu_disable_irq(dcu, irq); /* disable the interrupt */
+
+ spin_lock_irqsave(&dcu->spin_lock, lock_flags);
+ if (dcu->irq_list[irq].dev_id == dev_id)
+ dcu->irq_list[irq].handler = NULL;
+ spin_unlock_irqrestore(&dcu->spin_lock, lock_flags);
+}
+EXPORT_SYMBOL(dcu_free_irq);
+
+static int dcu_suspend_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mvf_dcuv4_platform_data *plat_data = pdev->dev.platform_data;
+ struct dcu_soc *dcu = platform_get_drvdata(pdev);
+
+ if (atomic_read(&dcu->dcu_use_count)) {
+ /* save and disable enabled layers*/
+
+ /* save sub-modules status and disable all */
+
+
+ clk_disable(dcu->dcu_clk);
+ }
+
+ if (plat_data->pg)
+ plat_data->pg(pdev->id, 1);
+
+ return 0;
+}
+
+static int dcu_resume_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mvf_dcuv4_platform_data *plat_data = pdev->dev.platform_data;
+ struct dcu_soc *dcu = platform_get_drvdata(pdev);
+
+ if (plat_data->pg)
+ plat_data->pg(pdev->id, 0);
+
+ if (atomic_read(&dcu->dcu_use_count)) {
+ clk_enable(dcu->dcu_clk);
+
+ /* restore buf ready regs */
+
+ /* re-enable sub-modules*/
+
+ /* restore idamc sub addr regs */
+
+ /* restart idma layer*/
+ } else {
+ _dcu_get(dcu);
+// _dcu_dmfc_init(dcu, dmfc_type_setup, 1);
+// _dcu_init_dc_mappings(dcu);
+ /* Set sync refresh layers as high priority */
+// dcu_idmac_write(dcu, 0x18800001L, IDMAC_CHA_PRI(0));
+ _dcu_put(dcu);
+ }
+
+ return 0;
+}
+
+static int mvf_dcu_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static long mvf_dcu_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ //int __user *argp = (void __user *)arg;
+ int ret = 0;
+
+ switch (cmd) {
+
+ default:
+ break;
+ }
+ return ret;
+}
+
+static int mvf_dcu_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static struct file_operations mvf_dcu_fops = {
+ .owner = THIS_MODULE,
+ .open = mvf_dcu_open,
+ .release = mvf_dcu_release,
+ .unlocked_ioctl = mvf_dcu_ioctl,
+};
+
+/*!
+ * This function enables the DCU colorbar mode
+ *
+ * @param dcu dcu handler
+ *
+ */
+void dcu_enable_colorbar_mode(struct dcu_soc *dcu)
+{
+ uint32_t reg;
+ /* TODO: ensure clock is enabled */
+ /* TODO: Do we need to check usecount? */
+ dcu_blank(dcu, DCU_UNBLANK);
+ _dcu_lock(dcu);
+ /* Enable the VSYNC and HSYNC */
+ reg = dcu_read(dcu, DCU_DCU_MODE_OFFSET);
+ reg |= DCU_DCU_MODE_RASTER_EN_MASK;
+ reg &= ~DCU_DCU_MODE_DCU_MODE_MASK;
+ reg |= (DCU_COLOR_BAR_MODE << DCU_DCU_MODE_DCU_MODE_SHIFT);
+ dcu_write(dcu, reg, DCU_DCU_MODE_OFFSET);
+ _dcu_unlock(dcu);
+}
+EXPORT_SYMBOL(dcu_enable_colorbar_mode);
+
+/*!
+ * This function disables the DCU colorbar mode
+ *
+ * @param dcu dcu handler
+ *
+ */
+void dcu_disable_colorbar_mode(struct dcu_soc *dcu)
+{
+ uint32_t reg;
+
+ _dcu_lock(dcu);
+ reg = dcu_read(dcu, DCU_DCU_MODE_OFFSET);
+ reg &= ~DCU_DCU_MODE_RASTER_EN_MASK;
+ reg &= ~DCU_DCU_MODE_DCU_MODE_MASK;
+ reg |= (DCU_OFF << DCU_DCU_MODE_DCU_MODE_SHIFT);
+ /* TODO: Do we need to check usecount? */
+ dcu_write(dcu, reg, DCU_DCU_MODE_OFFSET);
+ _dcu_unlock(dcu);
+ dcu_blank(dcu, DCU_BLANK);
+
+}
+EXPORT_SYMBOL(dcu_disable_colorbar_mode);
+
+static ssize_t get_dcu_colorbar_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint32_t reg;
+ struct dcu_soc *dcu = &dcu_array[0];
+ int i;
+
+ if(dcu->display_configured == false)
+ {
+ return sprintf(buf, "Display currently not configured\n");
+ }
+
+ for(i=0; i<MVF_DCU_MAX_NUM; i++)
+ {
+ if(dcu_array[i].dcu_cdev == dev)
+ {
+ dcu = &dcu_array[i];
+ break;
+ }
+ }
+
+ _dcu_lock(dcu);
+ reg = dcu_read(dcu, DCU_DCU_MODE_OFFSET);
+ reg &= DCU_DCU_MODE_DCU_MODE_MASK;
+ _dcu_unlock(dcu);
+
+ reg = reg >> DCU_DCU_MODE_DCU_MODE_SHIFT;
+ if(reg == DCU_COLOR_BAR_MODE)
+ return sprintf(buf, "Colorbar mode enabled\n");
+ else
+ return sprintf(buf, "Colorbar mode not enabled\n");
+}
+
+static ssize_t set_dcu_colorbar_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dcu_soc *dcu = &dcu_array[0];
+ int colorbarmode, r,i;
+
+ for(i=0; i<MVF_DCU_MAX_NUM; i++)
+ {
+ if(dcu_array[i].dcu_cdev == dev)
+ {
+ dcu = &dcu_array[i];
+ break;
+ }
+ }
+
+ if(dcu->display_configured == false)
+ {
+#ifdef DCU_UNIT_TEST
+ dcu_unit_test_config_display(dcu);
+#else
+ printk("Display currently not configured\n");
+ return count;
+#endif
+ }
+
+ r = kstrtoint(buf, 0, &colorbarmode);
+ if (r)
+ return r;
+
+ /* TODO: Do we need to ensure DCU, display, clocks. TCON etc is enabled? */
+ if(colorbarmode)
+ dcu_enable_colorbar_mode(dcu);
+ else
+ dcu_disable_colorbar_mode(dcu);
+
+ return count;
+}
+DEVICE_ATTR(dcu_colorbar_mode, 0644, get_dcu_colorbar_state, set_dcu_colorbar_state);
+
+#ifdef DCU_UNIT_TEST
+static ssize_t perform_dcu_unit_test(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dcu_soc *dcu = &dcu_array[0];
+ int i;
+
+ for(i=0; i<MVF_DCU_MAX_NUM; i++)
+ {
+ if(dcu_array[i].dcu_cdev == dev)
+ {
+ dcu = &dcu_array[i];
+ break;
+ }
+ }
+
+ if(dcu->display_configured == false)
+ {
+ dcu_unit_test_config_display(dcu);
+ }
+ dcu_unit_test(dcu);
+ return count;
+}
+DEVICE_ATTR(dcu_unit_test, 0644, NULL, perform_dcu_unit_test);
+#endif
+
+static struct device_attribute *dcu_sysfs_attrs[] = {
+ &dev_attr_dcu_colorbar_mode,
+#ifdef DCU_UNIT_TEST
+ &dev_attr_dcu_unit_test,
+#endif
+ NULL
+};
+
+/*!
+ * This function performs the following operations:
+ * 1. Register DCU as char device
+ * 2. Creates a DCU class
+ * 3. Setups up the device attributes *
+ */
+int register_dcu_device(struct dcu_soc *dcu, int id)
+{
+ int ret = 0;
+ int i;
+ struct device_attribute *attr;
+
+ if (!major) {
+ major = register_chrdev(0, "mvf_dcu", &mvf_dcu_fops);
+ if (major < 0) {
+ printk(KERN_ERR "Unable to register mvf_dcu as a char device\n");
+ ret = major;
+ goto register_cdev_fail;
+ }
+
+ dcu_class = class_create(THIS_MODULE, "mvf_dcu");
+ if (IS_ERR(dcu_class)) {
+ ret = PTR_ERR(dcu_class);
+ goto dcu_class_fail;
+ }
+
+ dcu->dcu_cdev = device_create(dcu_class, NULL, MKDEV(major, 0),
+ NULL, "mvf_dcu");
+ if (IS_ERR(dcu->dcu_cdev)) {
+ ret = PTR_ERR(dcu->dcu_cdev);
+ goto dev_create_fail;
+ }
+
+ /* create device sysfs files */
+ i = 0;
+ while ((attr = dcu_sysfs_attrs[i++]) != NULL) {
+ ret = device_create_file(dcu->dcu_cdev, attr);
+ if (ret)
+ dev_err(dcu->dcu_cdev, "Error %d on creating file\n", ret);
+ }
+ /*
+ ret = device_create_file(dcu->dcu_cdev, &dcu_colorbar_mode);
+ if (ret){
+ dev_err(dcu->dcu_cdev, "Error %d on creating file\n", ret);
+ }
+ */
+ dcu->dcu_cdev->dma_mask = kmalloc(sizeof(*dcu->dcu_cdev->dma_mask), GFP_KERNEL);
+ *dcu->dcu_cdev->dma_mask = DMA_BIT_MASK(32);
+ dcu->dcu_cdev->coherent_dma_mask = DMA_BIT_MASK(32);
+ }
+
+ return ret;
+
+dev_create_fail:
+ if (id == 0) {
+ class_destroy(dcu_class);
+ unregister_chrdev(major, "mvf_dcu");
+ }
+dcu_class_fail:
+ if (id == 0)
+ unregister_chrdev(major, "mvf_dcu");
+register_cdev_fail:
+ return ret;
+}
+
+void unregister_dcu_device(struct dcu_soc *dcu, int id)
+{
+ int i;
+ struct device_attribute *attr;
+
+ if (major) {
+ i = 0;
+ while ((attr = dcu_sysfs_attrs[i++]) != NULL) {
+ device_remove_file(dcu->dcu_cdev, attr);
+ }
+ device_destroy(dcu_class, MKDEV(major, 0));
+ class_destroy(dcu_class);
+ unregister_chrdev(major, "mvf_dcu");
+ major = 0;
+ }
+}
+
+static const struct dev_pm_ops mvfdcu_pm_ops = {
+ .suspend_noirq = dcu_suspend_noirq,
+ .resume_noirq = dcu_resume_noirq,
+};
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mvfdcu_driver = {
+ .driver = {
+ .name = MVF_DCU,
+ .pm = &mvfdcu_pm_ops,
+ },
+ .probe = dcu_probe,
+ .remove = dcu_remove,
+};
+
+static int32_t __init dcu_gen_init(void)
+{
+ int32_t ret;
+
+ ret = platform_driver_register(&mvfdcu_driver);
+ return 0;
+}
+
+subsys_initcall(dcu_gen_init);
+
+static void __exit dcu_gen_uninit(void)
+{
+ platform_driver_unregister(&mvfdcu_driver);
+}
+
+module_exit(dcu_gen_uninit);
diff --git a/drivers/mvf/dcu4/dcu4_regs.h b/drivers/mvf/dcu4/dcu4_regs.h
new file mode 100644
index 000000000000..f638096f9187
--- /dev/null
+++ b/drivers/mvf/dcu4/dcu4_regs.h
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * @file dcu4_regs.h
+ *
+ * @brief DCU Register definitions
+ *
+ * @ingroup DCU
+ */
+#ifndef __DCU4_REGS_INCLUDED__
+#define __DCU4_REGS_INCLUDED__
+
+/* DCU - Internal RAM Offsets */
+#define DCU_CLUT_OFFSET 0x00002000
+#define DCU_GAMMARED_OFFSET 0x00004000
+#define DCU_GAMMAGREEN_OFFSET 0x00004400
+#define DCU_GAMMABLUE_OFFSET 0x00004800
+#define DCU_CURSOR_OFFSET 0x00004C00
+
+/* DCU - Register offsets */
+#define DCU_CTRLDESCCURSOR1_OFFSET (0x00000000/4)
+#define DCU_CTRLDESCCURSOR2_OFFSET (0x00000004/4)
+#define DCU_CTRLDESCCURSOR3_OFFSET (0x00000008/4)
+#define DCU_CTRLDESCCURSOR4_OFFSET (0x0000000C/4)
+#define DCU_DCU_MODE_OFFSET (0x00000010/4)
+#define DCU_BGND_OFFSET (0x00000014/4)
+#define DCU_DISP_SIZE_OFFSET (0x00000018/4)
+#define DCU_HSYN_PARA_OFFSET (0x0000001C/4)
+#define DCU_VSYN_PARA_OFFSET (0x00000020/4)
+#define DCU_SYNPOL_OFFSET (0x00000024/4)
+#define DCU_THRESHOLD_OFFSET (0x00000028/4)
+#define DCU_INT_STATUS_OFFSET (0x0000002C/4)
+#define DCU_INT_MASK_OFFSET (0x00000030/4)
+#define DCU_COLBAR_1_OFFSET (0x00000034/4)
+#define DCU_COLBAR_2_OFFSET (0x00000038/4)
+#define DCU_COLBAR_3_OFFSET (0x0000003C/4)
+#define DCU_COLBAR_4_OFFSET (0x00000040/4)
+#define DCU_COLBAR_5_OFFSET (0x00000044/4)
+#define DCU_COLBAR_6_OFFSET (0x00000048/4)
+#define DCU_COLBAR_7_OFFSET (0x0000004C/4)
+#define DCU_COLBAR_8_OFFSET (0x00000050/4)
+#define DCU_DIV_RATIO_OFFSET (0x00000054/4)
+#define DCU_SIGN_CALC_1_OFFSET (0x00000058/4)
+#define DCU_SIGN_CALC_2_OFFSET (0x0000005C/4)
+#define DCU_CRC_VAL_OFFSET (0x00000060/4)
+#define DCU_PARR_ERR_STATUS1_OFFSET (0x0000006C/4)
+#define DCU_PARR_ERR_STATUS2_OFFSET (0x00000070/4)
+#define DCU_PARR_ERR_STATUS3_OFFSET (0x0000007C/4)
+#define DCU_MASK_PARR_ERR_STATUS1_OFFSET (0x00000080/4)
+#define DCU_MASK_PARR_ERR_STATUS2_OFFSET (0x00000084/4)
+#define DCU_MASK_PARR_ERR_STATUS3_OFFSET (0x00000090/4)
+#define DCU_THRESHOLD_INP_BUF_1_OFFSET (0x00000094/4)
+#define DCU_THRESHOLD_INP_BUF_2_OFFSET (0x00000098/4)
+#define DCU_THRESHOLD_INP_BUF_3_OFFSET (0x0000009C/4)
+#define DCU_LUMA_COMP_OFFSET (0x000000A0/4)
+#define DCU_CHROMA_RED_OFFSET (0x000000A4/4)
+#define DCU_CHROMA_GREEN_OFFSET (0x000000A8/4)
+#define DCU_CHROMA_BLUE_OFFSET (0x000000AC/4)
+#define DCU_CRC_POS_OFFSET (0x000000B0/4)
+#define DCU_LYR_INTPOL_EN_OFFSET (0x000000B4/4)
+#define DCU_LYR_LUMA_COMP_OFFSET (0x000000B8/4)
+#define DCU_LYR_CHROMA_RED_OFFSET (0x000000BC/4)
+#define DCU_LYR_CHROMA_GREEN_OFFSET (0x000000C0/4)
+#define DCU_LYR_CHROMA_BLUE_OFFSET (0x000000C4/4)
+#define DCU_COMP_IMSIZE_OFFSET (0x000000C8/4)
+#define DCU_UPDATE_MODE_OFFSET (0x000000CC/4)
+#define DCU_UNDERRUN_OFFSET (0x000000D0/4)
+
+#define DCU_LAYER_CTRLDESC_BASE (0x00000200/4)
+#define DCU_CTRLDESCLx_OFFSET(LayerNum) (DCU_LAYER_CTRLDESC_BASE + LayerNum*16)
+#define DCU_CTRLDESCLx_y_OFFSET(LayerNum,RegisterOffset) (DCU_CTRLDESCLx_OFFSET(LayerNum) + RegisterOffset)
+#define DCU_CTRLDESCL_OFFSET1 (0)
+#define DCU_CTRLDESCL_OFFSET2 (1)
+#define DCU_CTRLDESCL_OFFSET3 (2)
+#define DCU_CTRLDESCL_OFFSET4 (3)
+#define DCU_CTRLDESCL_OFFSET5 (4)
+#define DCU_CTRLDESCL_OFFSET6 (5)
+#define DCU_CTRLDESCL_OFFSET7 (6)
+#define DCU_CTRLDESCL_OFFSET8 (7)
+#define DCU_CTRLDESCL_OFFSET9 (8)
+#define DCU_CTRLDESCL_OFFSET_MAX (8)
+
+/* Field definitions for CTRLDESCCURSOR4 */
+#define DCU_CTRLDESCCURSOR4_HWC_BLINK_OFF_SHIFT (16)
+#define DCU_CTRLDESCCURSOR4_HWC_BLINK_OFF_MASK ((0x000000FF) << (DCU_CTRLDESCCURSOR4_HWC_BLINK_OFF_SHIFT))
+
+#define DCU_CTRLDESCCURSOR4_EN_BLINK_SHIFT (8)
+#define DCU_CTRLDESCCURSOR4_EN_BLINK_MASK ((1) << (DCU_CTRLDESCCURSOR4_EN_BLINK_SHIFT))
+
+#define DCU_CTRLDESCCURSOR4_HWC_BLINK_ON_SHIFT (0)
+#define DCU_CTRLDESCCURSOR4_HWC_BLINK_ON_MASK ((0x000000FF) << (DCU_CTRLDESCCURSOR4_HWC_BLINK_ON_SHIFT))
+
+
+
+/* Field definitions for DCU_MODE */
+#define DCU_DCU_MODE_DCU_SW_RESET_SHIFT (31)
+#define DCU_DCU_MODE_DCU_SW_RESET_MASK ((1) << (DCU_DCU_MODE_DCU_SW_RESET_SHIFT))
+
+#define DCU_DCU_MODE_EN_DITHER_SHIFT (30)
+#define DCU_DCU_MODE_EN_DITHER_MASK ((1) << (DCU_DCU_MODE_EN_DITHER_SHIFT))
+
+#define DCU_DCU_MODE_ADDB_SHIFT (28)
+#define DCU_DCU_MODE_ADDB_MASK ((0x00000003) << (DCU_DCU_MODE_ADDB_SHIFT))
+
+#define DCU_DCU_MODE_ADDG_SHIFT (26)
+#define DCU_DCU_MODE_ADDG_MASK ((0x00000003) << (DCU_DCU_MODE_ADDG_SHIFT))
+
+#define DCU_DCU_MODE_ADDR_SHIFT (24)
+#define DCU_DCU_MODE_ADDR_MASK ((0x00000003) << (DCU_DCU_MODE_ADDR_SHIFT))
+
+#define DCU_DCU_MODE_DDR_MODE_SHIFT (23)
+#define DCU_DCU_MODE_DDR_MODE_MASK ((1) << (DCU_DCU_MODE_DDR_MODE_SHIFT))
+
+#define DCU_DCU_MODE_BLEND_ITER_SHIFT (20)
+#define DCU_DCU_MODE_BLEND_ITER_MASK ((0x00000007) << (DCU_DCU_MODE_BLEND_ITER_SHIFT))
+
+#define DCU_DCU_MODE_RASTER_EN_SHIFT (14)
+#define DCU_DCU_MODE_RASTER_EN_MASK ((1) << (DCU_DCU_MODE_RASTER_EN_SHIFT))
+
+#define DCU_DCU_MODE_TAG_EN_SHIFT (6)
+#define DCU_DCU_MODE_TAG_EN_MASK ((1) << (DCU_DCU_MODE_TAG_EN_SHIFT))
+
+#define DCU_DCU_MODE_SIG_EN_SHIFT (5)
+#define DCU_DCU_MODE_SIG_EN_MASK ((1) << (DCU_DCU_MODE_SIG_EN_SHIFT))
+
+#define DCU_DCU_MODE_EN_GAMMA_SHIFT (2)
+#define DCU_DCU_MODE_EN_GAMMA_MASK ((1) << (DCU_DCU_MODE_EN_GAMMA_SHIFT))
+
+#define DCU_DCU_MODE_DCU_MODE_SHIFT (0)
+#define DCU_DCU_MODE_DCU_MODE_MASK ((0x00000003) << (DCU_DCU_MODE_DCU_MODE_SHIFT))
+
+
+
+/* Field definitions for BGND */
+#define DCU_BGND_BGND_R_SHIFT (16)
+#define DCU_BGND_BGND_R_MASK ((0x000000FF) << (DCU_BGND_BGND_R_SHIFT))
+
+#define DCU_BGND_BGND_G_SHIFT (8)
+#define DCU_BGND_BGND_G_MASK ((0x000000FF) << (DCU_BGND_BGND_G_SHIFT))
+
+#define DCU_BGND_BGND_B_SHIFT (0)
+#define DCU_BGND_BGND_B_MASK ((0x000000FF) << (DCU_BGND_BGND_B_SHIFT))
+
+
+
+/* Field definitions for DISP_SIZE */
+#define DCU_DISP_SIZE_DELTA_Y_SHIFT (16)
+#define DCU_DISP_SIZE_DELTA_Y_MASK ((0x000007FF) << (DCU_DISP_SIZE_DELTA_Y_SHIFT))
+
+#define DCU_DISP_SIZE_DELTA_X_SHIFT (0)
+#define DCU_DISP_SIZE_DELTA_X_MASK ((0x0000007F) << (DCU_DISP_SIZE_DELTA_X_SHIFT))
+
+
+
+/* Field definitions for HSYN_PARA */
+#define DCU_HSYN_PARA_BP_H_SHIFT (22)
+#define DCU_HSYN_PARA_BP_H_MASK ((0x000001FF) << (DCU_HSYN_PARA_BP_H_SHIFT))
+
+#define DCU_HSYN_PARA_PW_H_SHIFT (11)
+#define DCU_HSYN_PARA_PW_H_MASK ((0x000001FF) << (DCU_HSYN_PARA_PW_H_SHIFT))
+
+#define DCU_HSYN_PARA_FP_H_SHIFT (0)
+#define DCU_HSYN_PARA_FP_H_MASK ((0x000001FF) << (DCU_HSYN_PARA_FP_H_SHIFT))
+
+
+
+/* Field definitions for VSYN_PARA */
+#define DCU_VSYN_PARA_BP_V_SHIFT (22)
+#define DCU_VSYN_PARA_BP_V_MASK ((0x000001FF) << (DCU_VSYN_PARA_BP_V_SHIFT))
+
+#define DCU_VSYN_PARA_PW_V_SHIFT (11)
+#define DCU_VSYN_PARA_PW_V_MASK ((0x000001FF) << (DCU_VSYN_PARA_PW_V_SHIFT))
+
+#define DCU_VSYN_PARA_FP_V_SHIFT (0)
+#define DCU_VSYN_PARA_FP_V_MASK ((0x000001FF) << (DCU_VSYN_PARA_FP_V_SHIFT))
+
+
+
+/* Field definitions for SYNPOL */
+#define DCU_SYNPOL_INV_PXCK_SHIFT (6)
+#define DCU_SYNPOL_INV_PXCK_MASK ((1) << (DCU_SYNPOL_INV_PXCK_SHIFT))
+
+#define DCU_SYNPOL_NEG_SHIFT (5)
+#define DCU_SYNPOL_NEG_MASK ((1) << (DCU_SYNPOL_NEG_SHIFT))
+
+#define DCU_SYNPOL_INV_VS_SHIFT (1)
+#define DCU_SYNPOL_INV_VS_MASK ((1) << (DCU_SYNPOL_INV_VS_SHIFT))
+
+#define DCU_SYNPOL_INV_HS_SHIFT (0)
+#define DCU_SYNPOL_INV_HS_MASK ((1) << (DCU_SYNPOL_INV_HS_SHIFT))
+
+
+
+/* Field definitions for THRESHOLD */
+#define DCU_THRESHOLD_LS_BF_VS_SHIFT (16)
+#define DCU_THRESHOLD_LS_BF_VS_MASK ((0x000003FF) << (DCU_THRESHOLD_LS_BF_VS_SHIFT))
+
+#define DCU_THRESHOLD_OUT_BUF_HIGH_SHIFT (8)
+#define DCU_THRESHOLD_OUT_BUF_HIGH_MASK ((0x000000FF) << (DCU_THRESHOLD_OUT_BUF_HIGH_SHIFT))
+
+#define DCU_THRESHOLD_OUT_BUF_LOW_SHIFT (0)
+#define DCU_THRESHOLD_OUT_BUF_LOW_MASK ((0x000000FF) << (DCU_THRESHOLD_OUT_BUF_LOW_SHIFT))
+
+
+
+/* Field definitions for INT_STATUS */
+#define DCU_INT_STATUS_P6_EMPTY_SHIFT (31)
+#define DCU_INT_STATUS_P6_EMPTY_MASK ((1) << (DCU_INT_STATUS_P6_EMPTY_SHIFT))
+
+#define DCU_INT_STATUS_P5_EMPTY_SHIFT (30)
+#define DCU_INT_STATUS_P5_EMPTY_MASK ((1) << (DCU_INT_STATUS_P5_EMPTY_SHIFT))
+
+#define DCU_INT_STATUS_P4_EMPTY_SHIFT (29)
+#define DCU_INT_STATUS_P4_EMPTY_MASK ((1) << (DCU_INT_STATUS_P4_EMPTY_SHIFT))
+
+#define DCU_INT_STATUS_P3_EMPTY_SHIFT (28)
+#define DCU_INT_STATUS_P3_EMPTY_MASK ((1) << (DCU_INT_STATUS_P3_EMPTY_SHIFT))
+
+#define DCU_INT_STATUS_P2_EMPTY_SHIFT (27)
+#define DCU_INT_STATUS_P2_EMPTY_MASK ((1) << (DCU_INT_STATUS_P2_EMPTY_SHIFT))
+
+#define DCU_INT_STATUS_P1_EMPTY_SHIFT (26)
+#define DCU_INT_STATUS_P1_EMPTY_MASK ((1) << (DCU_INT_STATUS_P1_EMPTY_SHIFT))
+
+#define DCU_INT_STATUS_P6_FIFO_HI_FLAG_SHIFT (23)
+#define DCU_INT_STATUS_P6_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_STATUS_P6_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P6_FIFO_LO_FLAG_SHIFT (22)
+#define DCU_INT_STATUS_P6_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_STATUS_P6_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P5_FIFO_HI_FLAG_SHIFT (21)
+#define DCU_INT_STATUS_P5_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_STATUS_P5_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P5_FIFO_LO_FLAG_SHIFT (20)
+#define DCU_INT_STATUS_P5_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_STATUS_P5_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P4_FIFO_HI_FLAG_SHIFT (19)
+#define DCU_INT_STATUS_P4_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_STATUS_P4_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P4_FIFO_LO_FLAG_SHIFT (18)
+#define DCU_INT_STATUS_P4_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_STATUS_P4_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P3_FIFO_HI_FLAG_SHIFT (17)
+#define DCU_INT_STATUS_P3_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_STATUS_P3_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P3_FIFO_LO_FLAG_SHIFT (16)
+#define DCU_INT_STATUS_P3_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_STATUS_P3_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_DMA_TRANS_FINISH_SHIFT (14)
+#define DCU_INT_STATUS_DMA_TRANS_FINISH_MASK ((1) << (DCU_INT_STATUS_DMA_TRANS_FINISH_SHIFT))
+
+#define DCU_INT_STATUS_LYR_TRANS_FINISH_SHIFT (12)
+#define DCU_INT_STATUS_LYR_TRANS_FINISH_MASK ((1) << (DCU_INT_STATUS_LYR_TRANS_FINISH_SHIFT))
+#define DCU_INT_STATUS_IPM_ERROR_SHIFT (11)
+#define DCU_INT_STATUS_IPM_ERROR_MASK ((1) << (DCU_INT_STATUS_IPM_ERROR_SHIFT))
+
+#define DCU_INT_STATUS_PROG_END_SHIFT (10)
+#define DCU_INT_STATUS_PROG_END_MASK ((1) << (DCU_INT_STATUS_PROG_END_SHIFT))
+
+#define DCU_INT_STATUS_P2_FIFO_HI_FLAG_SHIFT (9)
+#define DCU_INT_STATUS_P2_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_STATUS_P2_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P2_FIFO_LO_FLAG_SHIFT (8)
+#define DCU_INT_STATUS_P2_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_STATUS_P2_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P1_FIFO_HI_FLAG_SHIFT (7)
+#define DCU_INT_STATUS_P1_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_STATUS_P1_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_P1_FIFO_LO_FLAG_SHIFT (6)
+#define DCU_INT_STATUS_P1_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_STATUS_P1_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_STATUS_CRC_OVERFLOW_SHIFT (5)
+#define DCU_INT_STATUS_CRC_OVERFLOW_MASK ((1) << (DCU_INT_STATUS_CRC_OVERFLOW_SHIFT))
+
+#define DCU_INT_STATUS_CRC_READY_SHIFT (4)
+#define DCU_INT_STATUS_CRC_READY_MASK ((1) << (DCU_INT_STATUS_CRC_READY_SHIFT))
+
+#define DCU_INT_STATUS_VS_BLANK_SHIFT (3)
+#define DCU_INT_STATUS_VS_BLANK_MASK ((1) << (DCU_INT_STATUS_VS_BLANK_SHIFT))
+
+#define DCU_INT_STATUS_LS_BF_VS_SHIFT (2)
+#define DCU_INT_STATUS_LS_BF_VS_MASK ((1) << (DCU_INT_STATUS_LS_BF_VS_SHIFT))
+
+#define DCU_INT_STATUS_UNDRUN_SHIFT (1)
+#define DCU_INT_STATUS_UNDRUN_MASK ((1) << (DCU_INT_STATUS_UNDRUN_SHIFT))
+
+#define DCU_INT_STATUS_VSYNC_SHIFT (0)
+#define DCU_INT_STATUS_VSYNC_MASK ((1) << (DCU_INT_STATUS_VSYNC_SHIFT))
+
+
+
+/* Field definitions for INT_MASK */
+#define DCU_INT_MASK_M_P6_EMPTY_SHIFT (31)
+#define DCU_INT_MASK_M_P6_EMPTY_MASK ((1) << (DCU_INT_MASK_M_P6_EMPTY_SHIFT))
+
+#define DCU_INT_MASK_M_P5_EMPTY_SHIFT (30)
+#define DCU_INT_MASK_M_P5_EMPTY_MASK ((1) << (DCU_INT_MASK_M_P5_EMPTY_SHIFT))
+
+#define DCU_INT_MASK_M_P4_EMPTY_SHIFT (29)
+#define DCU_INT_MASK_M_P4_EMPTY_MASK ((1) << (DCU_INT_MASK_M_P4_EMPTY_SHIFT))
+
+#define DCU_INT_MASK_M_P3_EMPTY_SHIFT (28)
+#define DCU_INT_MASK_M_P3_EMPTY_MASK ((1) << (DCU_INT_MASK_M_P3_EMPTY_SHIFT))
+
+#define DCU_INT_MASK_M_P2_EMPTY_SHIFT (27)
+#define DCU_INT_MASK_M_P2_EMPTY_MASK ((1) << (DCU_INT_MASK_M_P2_EMPTY_SHIFT))
+
+#define DCU_INT_MASK_M_P1_EMPTY_SHIFT (26)
+#define DCU_INT_MASK_M_P1_EMPTY_MASK ((1) << (DCU_INT_MASK_M_P1_EMPTY_SHIFT))
+
+#define DCU_INT_MASK_M_P6_FIFO_HI_FLAG_SHIFT (23)
+#define DCU_INT_MASK_M_P6_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_MASK_M_P6_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P6_FIFO_LO_FLAG_SHIFT (22)
+#define DCU_INT_MASK_M_P6_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_MASK_M_P6_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P5_FIFO_HI_FLAG_SHIFT (21)
+#define DCU_INT_MASK_M_P5_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_MASK_M_P5_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P5_FIFO_LO_FLAG_SHIFT (20)
+#define DCU_INT_MASK_M_P5_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_MASK_M_P5_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P4_FIFO_HI_FLAG_SHIFT (19)
+#define DCU_INT_MASK_M_P4_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_MASK_M_P4_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P4_FIFO_LO_FLAG_SHIFT (18)
+#define DCU_INT_MASK_M_P4_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_MASK_M_P4_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P3_FIFO_HI_FLAG_SHIFT (17)
+#define DCU_INT_MASK_M_P3_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_MASK_M_P3_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P3_FIFO_LO_FLAG_SHIFT (16)
+#define DCU_INT_MASK_M_P3_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_MASK_M_P3_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_DMA_TRANS_FINISH_SHIFT (14)
+#define DCU_INT_MASK_M_DMA_TRANS_FINISH_MASK ((1) << (DCU_INT_MASK_M_DMA_TRANS_FINISH_SHIFT))
+
+#define DCU_INT_MASK_M_LYR_TRANS_FINISH_SHIFT (12)
+#define DCU_INT_MASK_M_LYR_TRANS_FINISH_MASK ((1) << (DCU_INT_MASK_M_LYR_TRANS_FINISH_SHIFT))
+
+#define DCU_INT_MASK_M_IPM_ERROR_SHIFT (11)
+#define DCU_INT_MASK_M_IPM_ERROR_MASK ((1) << (DCU_INT_MASK_M_IPM_ERROR_SHIFT))
+
+#define DCU_INT_MASK_M_PROG_END_SHIFT (10)
+#define DCU_INT_MASK_M_PROG_END_MASK ((1) << (DCU_INT_MASK_M_PROG_END_SHIFT))
+
+#define DCU_INT_MASK_M_P2_FIFO_HI_FLAG_SHIFT (9)
+#define DCU_INT_MASK_M_P2_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_MASK_M_P2_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P2_FIFO_LO_FLAG_SHIFT (8)
+#define DCU_INT_MASK_M_P2_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_MASK_M_P2_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P1_FIFO_HI_FLAG_SHIFT (7)
+#define DCU_INT_MASK_M_P1_FIFO_HI_FLAG_MASK ((1) << (DCU_INT_MASK_M_P1_FIFO_HI_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_P1_FIFO_LO_FLAG_SHIFT (6)
+#define DCU_INT_MASK_M_P1_FIFO_LO_FLAG_MASK ((1) << (DCU_INT_MASK_M_P1_FIFO_LO_FLAG_SHIFT))
+
+#define DCU_INT_MASK_M_CRC_OVERFLOW_SHIFT (5)
+#define DCU_INT_MASK_M_CRC_OVERFLOW_MASK ((1) << (DCU_INT_MASK_M_CRC_OVERFLOW_SHIFT))
+
+#define DCU_INT_MASK_M_CRC_READY_SHIFT (4)
+#define DCU_INT_MASK_M_CRC_READY_MASK ((1) << (DCU_INT_MASK_M_CRC_READY_SHIFT))
+
+#define DCU_INT_MASK_M_VS_BLANK_SHIFT (3)
+#define DCU_INT_MASK_M_VS_BLANK_MASK ((1) << (DCU_INT_MASK_M_VS_BLANK_SHIFT))
+
+#define DCU_INT_MASK_M_LS_BF_VS_SHIFT (2)
+#define DCU_INT_MASK_M_LS_BF_VS_MASK ((1) << (DCU_INT_MASK_M_LS_BF_VS_SHIFT))
+
+#define DCU_INT_MASK_M_UNDRUN_SHIFT (1)
+#define DCU_INT_MASK_M_UNDRUN_MASK ((1) << (DCU_INT_MASK_M_UNDRUN_SHIFT))
+
+#define DCU_INT_MASK_M_VSYNC_SHIFT (0)
+#define DCU_INT_MASK_M_VSYNC_MASK ((1) << (DCU_INT_MASK_M_VSYNC_SHIFT))
+
+#define DCU_IRQ_MASK(irq) (1UL << (irq & 0x1F))
+
+/* Field definitions for COLBAR_n */
+#define DCU_COLBAR_n_R_SHIFT (16)
+#define DCU_COLBAR_n_R_MASK ((0x000000FF) << (DCU_COLBAR_n_R_SHIFT))
+
+#define DCU_COLBAR_n_G_SHIFT (8)
+#define DCU_COLBAR_n_G_MASK ((0x000000FF) << (DCU_COLBAR_n_G_SHIFT))
+
+#define DCU_COLBAR_n_B_SHIFT (0)
+#define DCU_COLBAR_n_B_MASK ((0x000000FF) << (DCU_COLBAR_n_B_SHIFT))
+
+
+
+
+/* Field definitions for DIV_RATIO */
+#define DCU_DIV_RATIO_DIV_RATIO_SHIFT (0)
+#define DCU_DIV_RATIO_DIV_RATIO_MASK ((0x000000FF) << (DCU_DIV_RATIO_DIV_RATIO_SHIFT))
+
+
+
+/* Field definitions for SIGN_CALC_1 */
+#define DCU_SIGN_CALC_1_SIG_VER_SIZE_SHIFT (16)
+#define DCU_SIGN_CALC_1_SIG_VER_SIZE_MASK ((0x000007FF) << (DCU_SIGN_CALC_1_SIG_VER_SIZE_SHIFT))
+
+#define DCU_SIGN_CALC_1_SIG_HOR_SIZE_SHIFT (0)
+#define DCU_SIGN_CALC_1_SIG_HOR_SIZE_MASK ((0x000007FF) << (DCU_SIGN_CALC_1_SIG_HOR_SIZE_SHIFT))
+
+
+
+/* Field definitions for SIGN_CALC_2 */
+#define DCU_SIGN_CALC_2_SIG_VER_POS_SHIFT (16)
+#define DCU_SIGN_CALC_2_SIG_VER_POS_MASK ((0x000007FF) << (DCU_SIGN_CALC_2_SIG_VER_POS_SHIFT))
+
+#define DCU_SIGN_CALC_2_SIG_HOR_POS_SHIFT (0)
+#define DCU_SIGN_CALC_2_SIG_HOR_POS_MASK ((0x000007FF) << (DCU_SIGN_CALC_2_SIG_HOR_POS_SHIFT))
+
+
+
+/* Field definitions for CRC_VAL */
+#define DCU_CRC_VAL_CRC_VAL_SHIFT (0)
+#define DCU_CRC_VAL_CRC_VAL_MASK ((0xFFFFFFFF) << (DCU_CRC_VAL_CRC_VAL_SHIFT))
+
+
+
+/* Field definitions for PARR_ERR_STATUS1/2 */
+#define DCU_PARR_ERR_STATUS_Lx_MASK(Layer) ((1) << (Layer % 32))
+
+/* Field definitions for MASK_PARR_ERR_STATUS1/2 */
+#define DCU_MASK_PARR_ERR_STATUS_Lx_MASK(Layer) ((1) << (Layer % 32))
+
+
+/* Field definitions for MASK_PARR_ERR_STATUS3 */
+#define DCU_MASK_PARR_ERR_STATUS3_M_RLE_ERR_SHIFT (3)
+#define DCU_MASK_PARR_ERR_STATUS3_M_RLE_ERR_MASK ((1) << (DCU_MASK_PARR_ERR_STATUS3_M_RLE_ERR_SHIFT))
+
+#define DCU_MASK_PARR_ERR_STATUS3_M_HWC_ERR_SHIFT (2)
+#define DCU_MASK_PARR_ERR_STATUS3_M_HWC_ERR_MASK ((1) << (DCU_MASK_PARR_ERR_STATUS3_M_HWC_ERR_SHIFT))
+
+#define DCU_MASK_PARR_ERR_STATUS3_M_SIG_ERR_SHIFT (1)
+#define DCU_MASK_PARR_ERR_STATUS3_M_SIG_ERR_MASK ((1) << (DCU_MASK_PARR_ERR_STATUS3_M_SIG_ERR_SHIFT))
+
+#define DCU_MASK_PARR_ERR_STATUS3_M_DISP_ERR_SHIFT (0)
+#define DCU_MASK_PARR_ERR_STATUS3_M_DISP_ERR_MASK ((1) << (DCU_MASK_PARR_ERR_STATUS3_M_DISP_ERR_SHIFT))
+
+
+
+/* Field definitions for THRESHOLD_INP_BUF_1 */
+#define DCU_THRESHOLD_INP_BUF_1_INP_BUF_P2_HI_SHIFT (24)
+#define DCU_THRESHOLD_INP_BUF_1_INP_BUF_P2_HI_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_1_INP_BUF_P2_HI_SHIFT))
+
+#define DCU_THRESHOLD_INP_BUF_1_INP_BUF_P2_LO_SHIFT (16)
+#define DCU_THRESHOLD_INP_BUF_1_INP_BUF_P2_LO_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_1_INP_BUF_P2_LO_SHIFT))
+
+#define DCU_THRESHOLD_INP_BUF_1_INP_BUF_P1_HI_SHIFT (8)
+#define DCU_THRESHOLD_INP_BUF_1_INP_BUF_P1_HI_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_1_INP_BUF_P1_HI_SHIFT))
+
+#define DCU_THRESHOLD_INP_BUF_1_INP_BUF_P1_LO_SHIFT (0)
+#define DCU_THRESHOLD_INP_BUF_1_INP_BUF_P1_LO_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_1_INP_BUF_P1_LO_SHIFT))
+
+
+
+/* Field definitions for THRESHOLD_INP_BUF_2 */
+#define DCU_THRESHOLD_INP_BUF_2_INP_BUF_P4_HI_SHIFT (24)
+#define DCU_THRESHOLD_INP_BUF_2_INP_BUF_P4_HI_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_2_INP_BUF_P4_HI_SHIFT))
+
+#define DCU_THRESHOLD_INP_BUF_2_INP_BUF_P4_LO_SHIFT (16)
+#define DCU_THRESHOLD_INP_BUF_2_INP_BUF_P4_LO_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_2_INP_BUF_P4_LO_SHIFT))
+
+#define DCU_THRESHOLD_INP_BUF_2_INP_BUF_P3_HI_SHIFT (8)
+#define DCU_THRESHOLD_INP_BUF_2_INP_BUF_P3_HI_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_2_INP_BUF_P3_HI_SHIFT))
+
+#define DCU_THRESHOLD_INP_BUF_2_INP_BUF_P3_LO_SHIFT (0)
+#define DCU_THRESHOLD_INP_BUF_2_INP_BUF_P3_LO_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_2_INP_BUF_P3_LO_SHIFT))
+
+
+
+/* Field definitions for THRESHOLD_INP_BUF_3 */
+#define DCU_THRESHOLD_INP_BUF_3_INP_BUF_P6_HI_SHIFT (24)
+#define DCU_THRESHOLD_INP_BUF_3_INP_BUF_P6_HI_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_3_INP_BUF_P6_HI_SHIFT))
+
+#define DCU_THRESHOLD_INP_BUF_3_INP_BUF_P6_LO_SHIFT (16)
+#define DCU_THRESHOLD_INP_BUF_3_INP_BUF_P6_LO_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_3_INP_BUF_P6_LO_SHIFT))
+
+#define DCU_THRESHOLD_INP_BUF_3_INP_BUF_P5_HI_SHIFT (8)
+#define DCU_THRESHOLD_INP_BUF_3_INP_BUF_P5_HI_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_3_INP_BUF_P5_HI_SHIFT))
+
+#define DCU_THRESHOLD_INP_BUF_3_INP_BUF_P5_LO_SHIFT (0)
+#define DCU_THRESHOLD_INP_BUF_3_INP_BUF_P5_LO_MASK ((0x0000007F) << (DCU_THRESHOLD_INP_BUF_3_INP_BUF_P5_LO_SHIFT))
+
+
+
+/* Field definitions for LUMA_COMP */
+#define DCU_LUMA_COMP_Y_RED_SHIFT (22)
+#define DCU_LUMA_COMP_Y_RED_MASK ((0x000003FF) << (DCU_LUMA_COMP_Y_RED_SHIFT))
+
+#define DCU_LUMA_COMP_Y_GREEN_SHIFT (11)
+#define DCU_LUMA_COMP_Y_GREEN_MASK ((0x000003FF) << (DCU_LUMA_COMP_Y_GREEN_SHIFT))
+
+#define DCU_LUMA_COMP_Y_BLUE_SHIFT (0)
+#define DCU_LUMA_COMP_Y_BLUE_MASK ((0x000003FF) << (DCU_LUMA_COMP_Y_BLUE_SHIFT))
+
+
+
+/* Field definitions for CHROMA_RED */
+#define DCU_CHROMA_RED_CR_RED_SHIFT (16)
+#define DCU_CHROMA_RED_CR_RED_MASK ((0x000007FF) << (DCU_CHROMA_RED_CR_RED_SHIFT))
+
+#define DCU_CHROMA_RED_CB_GREEN_SHIFT (0)
+#define DCU_CHROMA_RED_CB_GREEN_MASK ((0x00000FFF) << (DCU_CHROMA_RED_CB_GREEN_SHIFT))
+
+
+
+/* Field definitions for CHROMA_GREEN */
+#define DCU_CHROMA_GREEN_CR_GREEN_SHIFT (16)
+#define DCU_CHROMA_GREEN_CR_GREEN_MASK ((0x000007FF) << (DCU_CHROMA_GREEN_CR_GREEN_SHIFT))
+
+#define DCU_CHROMA_GREEN_CB_GREEN_SHIFT (0)
+#define DCU_CHROMA_GREEN_CB_GREEN_MASK ((0x00000FFF) << (DCU_CHROMA_GREEN_CB_GREEN_SHIFT))
+
+
+
+/* Field definitions for CHROMA_BLUE */
+#define DCU_CHROMA_BLUE_CR_BLUE_SHIFT (16)
+#define DCU_CHROMA_BLUE_CR_BLUE_MASK ((0x000007FF) << (DCU_CHROMA_BLUE_CR_BLUE_SHIFT))
+
+#define DCU_CHROMA_BLUE_CB_BLUE_SHIFT (0)
+#define DCU_CHROMA_BLUE_CB_BLUE_MASK ((0x00000FFF) << (DCU_CHROMA_BLUE_CB_BLUE_SHIFT))
+
+
+
+/* Field definitions for CRC_POS */
+#define DCU_CRC_POS_CRC_POS_SHIFT (0)
+#define DCU_CRC_POS_CRC_POS_MASK ((0xFFFFFFFF) << (DCU_CRC_POS_CRC_POS_SHIFT))
+
+
+
+/* Field definitions for LYR_INTPOL_EN */
+#define DCU_LYR_INTPOL_EN_EN_SHIFT (0)
+#define DCU_LYR_INTPOL_EN_EN_MASK ((1) << (DCU_LYR_INTPOL_EN_EN_SHIFT))
+
+
+
+/* Field definitions for LYR_LUMA_COMP */
+#define DCU_LYR_LUMA_COMP_Y_RED_SHIFT (22)
+#define DCU_LYR_LUMA_COMP_Y_RED_MASK ((0x000003FF) << (DCU_LYR_LUMA_COMP_Y_RED_SHIFT))
+
+#define DCU_LYR_LUMA_COMP_Y_GREEN_SHIFT (11)
+#define DCU_LYR_LUMA_COMP_Y_GREEN_MASK ((0x000003FF) << (DCU_LYR_LUMA_COMP_Y_GREEN_SHIFT))
+
+#define DCU_LYR_LUMA_COMP_Y_BLUE_SHIFT (0)
+#define DCU_LYR_LUMA_COMP_Y_BLUE_MASK ((0x000003FF) << (DCU_LYR_LUMA_COMP_Y_BLUE_SHIFT))
+
+
+/* Field definitions for LYR_CHROMA_RED */
+#define DCU_LYR_CHROMA_RED_CR_RED_SHIFT (16)
+#define DCU_LYR_CHROMA_RED_CR_RED_MASK ((0x000007FF) << (DCU_LYR_CHROMA_RED_CR_RED_SHIFT))
+
+#define DCU_LYR_CHROMA_RED_CB_RED_SHIFT (0)
+#define DCU_LYR_CHROMA_RED_CB_RED_MASK ((0x00000FFF) << (DCU_LYR_CHROMA_RED_CB_RED_SHIFT))
+
+
+
+/* Field definitions for LYR_CHROMA_GREEN */
+#define DCU_LYR_CHROMA_GREEN_CR_GREEN_SHIFT (16)
+#define DCU_LYR_CHROMA_GREEN_CR_GREEN_MASK ((0x000007FF) << (DCU_LYR_CHROMA_GREEN_CR_GREEN_SHIFT))
+
+#define DCU_LYR_CHROMA_GREEN_CB_GREEN_SHIFT (0)
+#define DCU_LYR_CHROMA_GREEN_CB_GREEN_MASK ((0x00000FFF) << (DCU_LYR_CHROMA_GREEN_CB_GREEN_SHIFT))
+
+
+/* Field definitions for LYR_CHROMA_BLUE */
+#define DCU_LYR_CHROMA_BLUE_CR_BLUE_SHIFT (16)
+#define DCU_LYR_CHROMA_BLUE_CR_BLUE_MASK ((0x000007FF) << (DCU_LYR_CHROMA_BLUE_CR_BLUE_SHIFT))
+
+#define DCU_LYR_CHROMA_BLUE_CB_BLUE_SHIFT (0)
+#define DCU_LYR_CHROMA_BLUE_CB_BLUE_MASK ((0x00000FFF) << (DCU_LYR_CHROMA_BLUE_CB_BLUE_SHIFT))
+
+/* Field definitions for COMP_IMSIZE */
+#define DCU_COMP_IMSIZE_SIZE_SHIFT (0)
+#define DCU_COMP_IMSIZE_SIZE_MASK ((0x003FFFFF) << (DCU_COMP_IMSIZE_SIZE_SHIFT))
+
+
+
+/* Field definitions for UPDATE_MODE */
+#define DCU_UPDATE_MODE_MODE_SHIFT (31)
+#define DCU_UPDATE_MODE_MODE_MASK ((1) << (DCU_UPDATE_MODE_MODE_SHIFT))
+
+#define DCU_UPDATE_MODE_READREG_SHIFT (30)
+#define DCU_UPDATE_MODE_READREG_MASK ((1) << (DCU_UPDATE_MODE_READREG_SHIFT))
+
+
+
+/* Field definitions for UNDERRUN */
+#define DCU_UNDERRUN_LINE_SHIFT (16)
+#define DCU_UNDERRUN_LINE_MASK ((0x000007FF) << (DCU_UNDERRUN_LINE_SHIFT))
+
+#define DCU_UNDERRUN_PIXEL_SHIFT (0)
+#define DCU_UNDERRUN_PIXEL_MASK ((0x000007FF) << (DCU_UNDERRUN_PIXEL_SHIFT))
+
+
+/* Field definitions for CTRLDESCLn_1 */
+#define DCU_CTRLDESCLn_1_HEIGHT_SHIFT (16)
+#define DCU_CTRLDESCLn_1_HEIGHT_MASK ((0x000007FF) << (DCU_CTRLDESCLn_1_HEIGHT_SHIFT))
+
+#define DCU_CTRLDESCLn_1_WIDTH_SHIFT (0)
+#define DCU_CTRLDESCLn_1_WIDTH_MASK ((0x000007FF) << (DCU_CTRLDESCLn_1_WIDTH_SHIFT))
+
+
+
+/* Field definitions for CTRLDESCLn_2 */
+#define DCU_CTRLDESCLn_2_POSY_SHIFT (16)
+#define DCU_CTRLDESCLn_2_POSY_MASK ((0x000007FF) << (DCU_CTRLDESCLn_2_POSY_SHIFT))
+
+#define DCU_CTRLDESCLn_2_POSX_SHIFT (0)
+#define DCU_CTRLDESCLn_2_POSX_MASK ((0x000007FF) << (DCU_CTRLDESCLn_2_POSX_SHIFT))
+
+
+
+/* Field definitions for CTRLDESCLn_3 */
+#define DCU_CTRLDESCLn_3_ADDR_SHIFT (0)
+#define DCU_CTRLDESCLn_3_ADDR_MASK ((0xFFFFFFFF) << (DCU_CTRLDESCLn_3_ADDR_SHIFT))
+
+
+/* Field definitions for CTRLDESCLn_4 */
+#define DCU_CTRLDESCLn_4_EN_SHIFT (31)
+#define DCU_CTRLDESCLn_4_EN_MASK ((1) << (DCU_CTRLDESCLn_4_EN_SHIFT))
+
+#define DCU_CTRLDESCLn_4_TILE_EN_SHIFT (30)
+#define DCU_CTRLDESCLn_4_TILE_EN_MASK ((1) << (DCU_CTRLDESCLn_4_TILE_EN_SHIFT))
+
+#define DCU_CTRLDESCLn_4_DATA_SEL_SHIFT (29)
+#define DCU_CTRLDESCLn_4_DATA_SEL_MASK ((1) << (DCU_CTRLDESCLn_4_DATA_SEL_SHIFT))
+
+#define DCU_CTRLDESCLn_4_SAFETY_EN_SHIFT (28)
+#define DCU_CTRLDESCLn_4_SAFETY_EN_MASK ((1) << (DCU_CTRLDESCLn_4_SAFETY_EN_SHIFT))
+
+#define DCU_CTRLDESCLn_4_TRANS_SHIFT (20)
+#define DCU_CTRLDESCLn_4_TRANS_MASK ((0x000000FF) << (DCU_CTRLDESCLn_4_TRANS_SHIFT))
+
+#define DCU_CTRLDESCLn_4_BPP_SHIFT (16)
+#define DCU_CTRLDESCLn_4_BPP_MASK ((0x0000000F) << (DCU_CTRLDESCLn_4_BPP_SHIFT))
+
+#define DCU_CTRLDESCLn_4_EN_RLE_SHIFT (15)
+#define DCU_CTRLDESCLn_4_EN_RLE_MASK ((1) << (DCU_CTRLDESCLn_4_EN_RLE_SHIFT))
+
+#define DCU_CTRLDESCLn_4_LUOFFS_SHIFT (4)
+#define DCU_CTRLDESCLn_4_LUOFFS_MASK ((0x000007FF) << (DCU_CTRLDESCLn_4_LUOFFS_SHIFT))
+
+#define DCU_CTRLDESCLn_4_BB_SHIFT (2)
+#define DCU_CTRLDESCLn_4_BB_MASK ((1) << (DCU_CTRLDESCLn_4_BB_SHIFT))
+
+#define DCU_CTRLDESCLn_4_AB_SHIFT (0)
+#define DCU_CTRLDESCLn_4_AB_MASK ((0x00000003) << (DCU_CTRLDESCLn_4_AB_SHIFT))
+
+
+
+/* Field definitions for CTRLDESCLn_5 */
+#define DCU_CTRLDESCLn_5_CKMAX_R_SHIFT (16)
+#define DCU_CTRLDESCLn_5_CKMAX_R_MASK ((0x000000FF) << (DCU_CTRLDESCLn_5_CKMAX_R_SHIFT))
+
+#define DCU_CTRLDESCLn_5_CKMAX_G_SHIFT (8)
+#define DCU_CTRLDESCLn_5_CKMAX_G_MASK ((0x000000FF) << (DCU_CTRLDESCLn_5_CKMAX_G_SHIFT))
+
+#define DCU_CTRLDESCLn_5_CKMAX_B_SHIFT (0)
+#define DCU_CTRLDESCLn_5_CKMAX_B_MASK ((0x000000FF) << (DCU_CTRLDESCLn_5_CKMAX_B_SHIFT))
+
+
+
+/* Field definitions for CTRLDESCLn_6 */
+#define DCU_CTRLDESCLn_6_CKMIN_R_SHIFT (16)
+#define DCU_CTRLDESCLn_6_CKMIN_R_MASK ((0x000000FF) << (DCU_CTRLDESCLn_6_CKMIN_R_SHIFT))
+
+#define DCU_CTRLDESCLn_6_CKMIN_G_SHIFT (8)
+#define DCU_CTRLDESCLn_6_CKMIN_G_MASK ((0x000000FF) << (DCU_CTRLDESCLn_6_CKMIN_G_SHIFT))
+
+#define DCU_CTRLDESCLn_6_CKMIN_B_SHIFT (0)
+#define DCU_CTRLDESCLn_6_CKMIN_B_MASK ((0x000000FF) << (DCU_CTRLDESCLn_6_CKMIN_B_SHIFT))
+
+
+
+/* Field definitions for CTRLDESCLn_7 */
+#define DCU_CTRLDESCLn_7_TILE_VER_SIZE_SHIFT (16)
+#define DCU_CTRLDESCLn_7_TILE_VER_SIZE_MASK ((0x000007FF) << (DCU_CTRLDESCLn_7_TILE_VER_SIZE_SHIFT))
+
+#define DCU_CTRLDESCLn_7_TILE_HOR_SIZE_SHIFT (0)
+#define DCU_CTRLDESCLn_7_TILE_HOR_SIZE_MASK ((0x0000007F) << (DCU_CTRLDESCLn_7_TILE_HOR_SIZE_SHIFT))
+
+
+
+/* Field definitions for CTRLDESCLn_8 */
+#define DCU_CTRLDESCLn_8_COLOR_SHIFT (0)
+#define DCU_CTRLDESCLn_8_COLOR_MASK ((0x00FFFFFF) << (DCU_CTRLDESCLn_8_COLOR_SHIFT))
+
+
+
+/* Field definitions for CTRLDESCLn_9 */
+#define DCU_CTRLDESCLn_9_COLOR_SHIFT (0)
+#define DCU_CTRLDESCLn_9_COLOR_MASK ((0x00FFFFFF) << (DCU_CTRLDESCLn_9_COLOR_SHIFT))
+
+
+/*** End of bit definitions ***/
+
+/*** define base address ***/
+#define DCU0_BASE 0x40058000
+#define DCU1_BASE 0x400D8000
+
+/* TODO: Cleanup and move to TCON header file/driver */
+#define TCON0_BASE 0x4003D000
+#define TCON_CTRL1_OFFSET (0x00000000/4)
+#define TCON_CTRL1_TCON_BYPASS_SHIFT (29)
+#define TCON_CTRL1_TCON_BYPASS_MASK ((1) << (TCON_CTRL1_TCON_BYPASS_SHIFT))
+
+
+#endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 7ca56f93cf53..7b61c433f265 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2400,6 +2400,9 @@ config FB_MXC_HDMI
help
Driver for the on-chip MXC HDMI controller.
+if ARCH_MVF
+source "drivers/video/mvf/Kconfig"
+endif
if VT
source "drivers/video/console/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 0ebfeecca8db..3b9db9e573d7 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_FB_GEODE) += geode/
obj-$(CONFIG_FB_MBX) += mbx/
obj-$(CONFIG_FB_MXC_HDMI) += mxc_hdmi.o
obj-$(CONFIG_FB_MXC) += mxc/
+obj-$(CONFIG_FB_MVF) += mvf/
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
obj-$(CONFIG_FB_CONTROL) += controlfb.o
diff --git a/drivers/video/mvf/Kconfig b/drivers/video/mvf/Kconfig
new file mode 100644
index 000000000000..2c928a5c9147
--- /dev/null
+++ b/drivers/video/mvf/Kconfig
@@ -0,0 +1,20 @@
+config FB_MVF
+ tristate "MVF Framebuffer support"
+ depends on FB && (MVF_DCU || ARCH_VF6XX)
+ default y
+ help
+ This is a framebuffer device for the MVF LCD Controller.
+ See <http://www.linux-fbdev.org/> for information on framebuffer
+ devices.
+
+ If you plan to use the LCD display with your MVF system, say
+ Y here.
+
+config FB_MVF_NUM_FBS
+ int "Number of Framebuffers"
+ range 1 32
+ default 1
+ depends on FB_MVF
+ help
+ Select the number of framebuffers corresponding to layers
+ desired.
diff --git a/drivers/video/mvf/Makefile b/drivers/video/mvf/Makefile
new file mode 100644
index 000000000000..2f5dbde80084
--- /dev/null
+++ b/drivers/video/mvf/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_FB_MVF) += mvf_dispdrv.o mvffb_nec_wqvga.o mvf_dcu4_fb.o
diff --git a/drivers/video/mvf/mvf_dcu4_fb.c b/drivers/video/mvf/mvf_dcu4_fb.c
new file mode 100644
index 000000000000..956bd3e29a55
--- /dev/null
+++ b/drivers/video/mvf/mvf_dcu4_fb.c
@@ -0,0 +1,1411 @@
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @defgroup Framebuffer Driver for DCU4
+ */
+
+/*!
+ * @file mvf_dcu4_fb.c
+ *
+ * @brief MVF Frame buffer driver for DCU4
+ *
+ * @ingroup Framebuffer
+ */
+
+/*!
+ * Include files
+ */
+#include "mvf_dispdrv.h"
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/mvffb.h>
+#include <linux/uaccess.h>
+#include <linux/fsl_devices.h>
+#include <asm/mach-types.h>
+#include <mach/dcu-v4.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+
+/*
+ * Driver name
+ */
+#define MVFFB_NAME "mvf_dcu4_fb"
+
+/*!
+ * Structure containing the MVF specific framebuffer information.
+ */
+//TODO: How are multiple overlays handled?
+struct mvffb_info {
+ int default_bpp;
+ int cur_blank;
+ int next_blank;
+ int dcu_id;
+ u32 dcu_pix_fmt;
+ bool layer;
+ uint32_t dcu_layer_transfer_finish;
+ struct fb_info *ovfbi[32];
+ void *dcu;
+ struct mvf_dispdrv_handle *dispdrv;
+
+ bool alpha_en;
+ dma_addr_t alpha_phy_addr0;
+ dma_addr_t alpha_phy_addr1;
+ void *alpha_virt_addr0;
+ void *alpha_virt_addr1;
+ uint32_t alpha_mem_len;
+ uint32_t cur_dcu_buf;
+ uint32_t cur_dcu_alpha_buf;
+ u32 pseudo_palette[16];
+ struct semaphore flip_sem;
+ struct semaphore alpha_flip_sem;
+};
+
+struct mvffb_alloc_list {
+ struct list_head list;
+ dma_addr_t phy_addr;
+ void *cpu_addr;
+ u32 size;
+};
+
+static bool g_dp_in_use[2];
+LIST_HEAD(fb_alloc_list);
+
+static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
+{
+ //FIXME: For now Supporting 3 formats as given below
+ uint32_t pixfmt = 0;
+
+ if (fbi->var.nonstd)
+ return fbi->var.nonstd;
+
+ switch (fbi->var.bits_per_pixel) {
+ case 24:
+ pixfmt = V4L2_PIX_FMT_RGB24;
+ break;
+ case 32:
+ pixfmt = V4L2_PIX_FMT_RGB32;
+ break;
+ case 16:
+ pixfmt = V4L2_PIX_FMT_RGB565;
+ break;
+ }
+ return pixfmt;
+}
+
+static bool dcu_usage[2];
+static int dcu_set_usage(int dcu)
+{
+ if (dcu_usage[dcu])
+ return -EBUSY;
+ else
+ dcu_usage[dcu] = true;
+ return 0;
+}
+
+static void dcu_clear_usage(int dcu)
+{
+ dcu_usage[dcu] = false;
+}
+
+static struct fb_info *found_registered_fb(int layer_id, int dcu_id)
+{
+ int i;
+ struct mvffb_info *mvf_fbi;
+ struct fb_info *fbi = NULL;
+
+ for (i = 0; i < num_registered_fb; i++) {
+ mvf_fbi =
+ ((struct mvffb_info *)(registered_fb[i]->par));
+
+ if ((mvf_fbi->dcu_id == dcu_id) && (registered_fb[i]->node == layer_id)) {
+ fbi = registered_fb[i];
+ break;
+ }
+ }
+ return fbi;
+}
+
+static int mvffb_blank(int blank, struct fb_info *info);
+static int mvffb_map_video_memory(struct fb_info *fbi);
+static int mvffb_unmap_video_memory(struct fb_info *fbi);
+
+/*
+ * Set fixed framebuffer parameters based on variable settings.
+ *
+ * @param info framebuffer information pointer
+ */
+static int mvffb_set_fix(struct fb_info *info)
+{
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct fb_var_screeninfo *var = &info->var;
+
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->accel = FB_ACCEL_NONE;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 0;
+ fix->ywrapstep = 0;
+ fix->ypanstep = 0;
+
+ return 0;
+}
+
+/*
+ * Set framebuffer parameters and change the operating mode.
+ *
+ * @param info framebuffer information pointer
+ */
+static int mvffb_set_par(struct fb_info *fbi)
+{
+ int retval = 0;
+ u32 mem_len;
+ dcu_di_signal_cfg_t sig_cfg;
+ struct mvffb_info *mvf_fbi = (struct mvffb_info *)fbi->par;
+
+ dev_dbg(fbi->device, "Reconfiguring framebuffer\n");
+
+ if (mvf_fbi->dispdrv && mvf_fbi->dispdrv->drv->setup) {
+ retval = mvf_fbi->dispdrv->drv->setup(mvf_fbi->dispdrv, fbi);
+ if (retval < 0) {
+ dev_err(fbi->device, "setup error, dispdrv:%s.\n",
+ mvf_fbi->dispdrv->drv->name);
+ return -EINVAL;
+ }
+ }
+
+ if(dcu_is_layer_enabled(mvf_fbi->dcu, fbi->node))
+ {
+ retval = dcu_disable_layer(mvf_fbi->dcu, fbi->node, true);
+ if (retval < 0) {
+ dev_err(fbi->device, "Error disabling layer, %d\n", fbi->node);
+ return -EINVAL;
+ }
+ dcu_uninit_layer(mvf_fbi->dcu, fbi->node);
+ }
+
+ mvffb_set_fix(fbi);
+
+ mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
+ if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
+ if (fbi->fix.smem_start)
+ mvffb_unmap_video_memory(fbi);
+
+ if (mvffb_map_video_memory(fbi) < 0)
+ return -ENOMEM;
+ }
+
+ if (mvf_fbi->next_blank != FB_BLANK_UNBLANK)
+ return retval;
+
+ if (!mvf_fbi->layer) {
+ printk("Framebuffer: Configuring layer in set_par");
+
+ memset(&sig_cfg, 0, sizeof(sig_cfg));
+ if (fbi->var.vmode & FB_VMODE_INTERLACED)
+ sig_cfg.interlaced = true;
+ else
+ sig_cfg.interlaced = false;
+ if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ sig_cfg.Hsync_pol = true;
+ else
+ sig_cfg.Hsync_pol = false;
+ if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ sig_cfg.Vsync_pol = true;
+ else
+ sig_cfg.Vsync_pol = false;
+ if (fbi->var.sync & FB_SYNC_INV_PIX_CLK)
+ sig_cfg.clk_pol = true;
+ else
+ sig_cfg.clk_pol = false;
+ if (fbi->var.sync & FB_SYNC_DATA_INVERT)
+ sig_cfg.data_pol = true;
+ else
+ sig_cfg.data_pol = false;
+
+ printk("Framebuffer: FB Params are Resolution x = %d, y = %d, left_margin = %d, hsync_len= %d, right_margin = %d, upper_margin = %d, vsync_len = %d lower_margin = %d bpp = %d\n", \
+ fbi->var.xres, fbi->var.yres, fbi->var.left_margin, fbi->var.hsync_len, fbi->var.right_margin, \
+ fbi->var.upper_margin, fbi->var.vsync_len, fbi->var.lower_margin, fbi->var.bits_per_pixel);
+
+ dev_dbg(fbi->device, "pixclock = %ul Hz\n",
+ (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
+
+ if (dcu_init_panel(mvf_fbi->dcu,
+ (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
+ fbi->var.xres, fbi->var.yres,
+ fbi->var.left_margin,
+ fbi->var.hsync_len,
+ fbi->var.right_margin,
+ fbi->var.upper_margin,
+ fbi->var.vsync_len,
+ fbi->var.lower_margin,
+ 0, sig_cfg) != 0) {
+ dev_err(fbi->device,
+ "mvffb: Error initializing panel.\n");
+ return -EINVAL;
+ }
+ dcu_enable(mvf_fbi->dcu);
+ }
+
+ fbi->mode =
+ (struct fb_videomode *)fb_match_mode(&fbi->var,
+ &fbi->modelist);
+
+ dcu_init_layer(mvf_fbi->dcu, fbi->node, bpp_to_pixfmt(fbi), fbi->var.xres, fbi->var.yres, fbi->fix.smem_start, 0, 0);
+ dcu_update_layer_buffer(mvf_fbi->dcu, fbi->node, fbi->fix.smem_start);
+ dcu_enable_layer(mvf_fbi->dcu, fbi->node);
+ dcu_set_layer_position(mvf_fbi->dcu, fbi->node, 0,0);
+
+ if (mvf_fbi->dispdrv && mvf_fbi->dispdrv->drv->enable) {
+ retval = mvf_fbi->dispdrv->drv->enable(mvf_fbi->dispdrv);
+ if (retval < 0) {
+ dev_err(fbi->device, "enable error, dispdrv:%s.\n",
+ mvf_fbi->dispdrv->drv->name);
+ return -EINVAL;
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * Check framebuffer variable parameters and adjust to valid values.
+ *
+ * @param var framebuffer variable parameters
+ *
+ * @param info framebuffer information pointer
+ */
+static int mvffb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ u32 vtotal;
+ u32 htotal;
+
+/* DCU does not support rotation, TODO: add software implementation?
+ if (var->rotate > IPU_ROTATE_VERT_FLIP)
+ var->rotate = IPU_ROTATE_NONE;
+*/
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+
+/* TODO: Remove magic number 2 and replace with double buffer or not */
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres * 2;
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+ (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
+ var->bits_per_pixel = 16;
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.length = 3;
+ var->red.offset = 5;
+ var->red.msb_right = 0;
+
+ var->green.length = 3;
+ var->green.offset = 2;
+ var->green.msb_right = 0;
+
+ var->blue.length = 2;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 16:
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 24:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 32:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ var->transp.msb_right = 0;
+ break;
+ }
+
+ if (var->pixclock < 1000) {
+ htotal = var->xres + var->right_margin + var->hsync_len +
+ var->left_margin;
+ vtotal = var->yres + var->lower_margin + var->vsync_len +
+ var->upper_margin;
+ var->pixclock = (vtotal * htotal * 6UL) / 100UL;
+ var->pixclock = KHZ2PICOS(var->pixclock);
+ dev_dbg(info->device,
+ "pixclock set for 60Hz refresh = %u ps\n",
+ var->pixclock);
+ }
+
+ var->height = -1;
+ var->width = -1;
+ var->grayscale = 0;
+
+ return 0;
+}
+
+/*
+ * Function to handle custom ioctls for MVF framebuffer.
+ *
+ * @param inode inode struct
+ *
+ * @param file file struct
+ *
+ * @param cmd Ioctl command to handle
+ *
+ * @param arg User pointer to command arguments
+ *
+ * @param fbi framebuffer information pointer
+ */
+static int mvffb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ int __user *argp = (void __user *)arg;
+ struct mvffb_info *mvf_fbi = (struct mvffb_info *)fbi->par;
+
+ switch (cmd) {
+ case MVFFB_SET_LAYER_ALPHA:
+ {
+ struct mvffb_layer_alpha ga;
+
+ if (copy_from_user(&ga, (void *)arg, sizeof(ga))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if(dcu_config_layer_alpha(mvf_fbi->dcu,
+ fbi->node,
+ ga.alpha,
+ ga.blend_enable)) {
+ retval = -EINVAL;
+ break;
+ }
+
+ printk("Framebuffer: Set Layer Alpha of %s to %d\n", fbi->fix.id, ga.alpha);
+ dev_dbg(fbi->device, "Set Layer Alpha of %s to %d\n", fbi->fix.id, ga.alpha);
+
+ break;
+ }
+ case FBIO_ALLOC:
+ {
+ int size;
+ struct mvffb_alloc_list *mem;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (mem == NULL)
+ return -ENOMEM;
+
+ if (get_user(size, argp))
+ return -EFAULT;
+
+ mem->size = PAGE_ALIGN(size);
+
+ mem->cpu_addr = dma_alloc_coherent(fbi->device, size,
+ &mem->phy_addr,
+ GFP_DMA);
+ if (mem->cpu_addr == NULL) {
+ kfree(mem);
+ return -ENOMEM;
+ }
+
+ list_add(&mem->list, &fb_alloc_list);
+
+ dev_dbg(fbi->device, "allocated %d bytes @ 0x%08X\n",
+ mem->size, mem->phy_addr);
+
+ if (put_user(mem->phy_addr, argp))
+ return -EFAULT;
+
+ break;
+ }
+ case FBIO_FREE:
+ {
+ unsigned long offset;
+ struct mvffb_alloc_list *mem;
+
+ if (get_user(offset, argp))
+ return -EFAULT;
+
+ retval = -EINVAL;
+ list_for_each_entry(mem, &fb_alloc_list, list) {
+ if (mem->phy_addr == offset) {
+ list_del(&mem->list);
+ dma_free_coherent(fbi->device,
+ mem->size,
+ mem->cpu_addr,
+ mem->phy_addr);
+ kfree(mem);
+ retval = 0;
+ break;
+ }
+ }
+
+ break;
+ }
+ case MVFFB_GET_FB_BLANK:
+ {
+ struct mvffb_info *mvf_fbi =
+ (struct mvffb_info *)fbi->par;
+
+ if (put_user(mvf_fbi->cur_blank, argp))
+ return -EFAULT;
+ break;
+ }
+ case MVFFB_SETUP_LAYER:
+ {
+ struct mvffb_layer_pos pos;
+ struct fb_info *bg_fbi = NULL;
+ struct mvffb_info *bg_mvffbi = NULL;
+
+ if (copy_from_user(&pos, (void *)arg, sizeof(pos))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ bg_fbi = found_registered_fb(0, mvf_fbi->dcu_id);
+ if (bg_fbi)
+ bg_mvffbi = ((struct mvffb_info *)(bg_fbi->par));
+
+ if (bg_fbi == NULL) {
+ printk("Framebuffer: Cannot find the background framebuffer\n");
+ dev_err(fbi->device, "Cannot find the "
+ "background framebuffer \n");
+ retval = -ENOENT;
+ break;
+ }
+
+ // if fb is unblank, check if the pos fit the display
+ if (mvf_fbi->cur_blank == FB_BLANK_UNBLANK) {
+ if (fbi->var.xres + pos.x > bg_fbi->var.xres) {
+ if (bg_fbi->var.xres < fbi->var.xres)
+ pos.x = 0;
+ else
+ pos.x = bg_fbi->var.xres - fbi->var.xres;
+ }
+ if (fbi->var.yres + pos.y > bg_fbi->var.yres) {
+ if (bg_fbi->var.yres < fbi->var.yres)
+ pos.y = 0;
+ else
+ pos.y = bg_fbi->var.yres - fbi->var.yres;
+ }
+ }
+
+ retval = dcu_set_layer_position(mvf_fbi->dcu, fbi->node, pos.x, pos.y);
+ if(retval != 0)
+ {
+ break;
+ }
+
+ if (copy_to_user((void *)arg, &pos, sizeof(pos))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ break;
+ }
+ default:
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+/*
+ * mvffb_blank():
+ * Blank the display.
+ */
+static int mvffb_blank(int blank, struct fb_info *info)
+{
+ struct mvffb_info *mvf_fbi = (struct mvffb_info *)info->par;
+ int ret = 0;
+
+ dev_dbg(info->device, "blank = %d\n", blank);
+
+ if (mvf_fbi->cur_blank == blank)
+ return 0;
+
+ mvf_fbi->next_blank = blank;
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ if (mvf_fbi->dispdrv && mvf_fbi->dispdrv->drv->disable)
+ mvf_fbi->dispdrv->drv->disable(mvf_fbi->dispdrv);
+ //TODO: Remove / understand true. Not used in dcu driver.
+ dcu_disable_layer(mvf_fbi->dcu, info->node, true);
+ dcu_uninit_layer(mvf_fbi->dcu, info->node);
+ dcu_uninit_panel(mvf_fbi->dcu);
+ break;
+ case FB_BLANK_UNBLANK:
+ ret = mvffb_set_par(info);
+ break;
+ }
+ if (!ret)
+ mvf_fbi->cur_blank = blank;
+ return ret;
+}
+
+/*
+ * Pan or Wrap the Display
+ *
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+ *
+ * @param var Variable screen buffer information
+ * @param info Framebuffer information pointer
+ */
+static int
+mvffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ /*
+ struct mvffb_info *mvf_fbi = (struct mvffb_info *)info->par,
+ *mvf_graphic_fbi = NULL;
+ u_int y_bottom;
+ unsigned int fr_xoff, fr_yoff, fr_w, fr_h;
+ unsigned long base, active_alpha_phy_addr = 0;
+ bool loc_alpha_en = false;
+ int fb_stride;
+ int i;
+
+ if (info->var.yoffset == var->yoffset)
+ return 0; // No change, do nothing
+
+ // no pan display during fb blank
+ if (mvf_fbi->cur_blank != FB_BLANK_UNBLANK)
+ return -EINVAL;
+
+ y_bottom = var->yoffset;
+
+ if (y_bottom > info->var.yres_virtual)
+ return -EINVAL;
+
+ fb_stride = info->fix.line_length;
+
+ base = info->fix.smem_start;
+ fr_xoff = var->xoffset;
+ fr_w = info->var.xres_virtual;
+ if (!(var->vmode & FB_VMODE_YWRAP)) {
+ dev_dbg(info->device, "Y wrap disabled\n");
+ fr_yoff = var->yoffset % info->var.yres;
+ fr_h = info->var.yres;
+ base += info->fix.line_length * info->var.yres *
+ (var->yoffset / info->var.yres);
+ } else {
+ dev_dbg(info->device, "Y wrap enabled\n");
+ fr_yoff = var->yoffset;
+ fr_h = info->var.yres_virtual;
+ }
+ base += fr_yoff * fb_stride + fr_xoff;
+
+ // Check if DP local alpha is enabled and find the graphic fb
+ for (i = 0; i < num_registered_fb; i++) {
+ char *bg_id = "DISP3 BG";
+ char *fg_id = "DISP3 FG";
+ char *idstr = registered_fb[i]->fix.id;
+ bg_id[4] += mvf_fbi->dcu_id;
+ fg_id[4] += mvf_fbi->dcu_id;
+ if ((strcmp(idstr, bg_id) == 0 ||
+ strcmp(idstr, fg_id) == 0) &&
+ ((struct mvffb_info *)
+ (registered_fb[i]->par))->alpha_chan_en) {
+ loc_alpha_en = true;
+ mvf_graphic_fbi = (struct mvffb_info *)
+ (registered_fb[i]->par);
+ active_alpha_phy_addr =
+ mvf_fbi->cur_dcu_alpha_buf ?
+ mvf_graphic_fbi->alpha_phy_addr1 :
+ mvf_graphic_fbi->alpha_phy_addr0;
+ dev_dbg(info->device, "Updating SDC alpha "
+ "buf %d address=0x%08lX\n",
+ !mvf_fbi->cur_dcu_alpha_buf,
+ active_alpha_phy_addr);
+ break;
+ }
+ }
+
+ if (down_timeout(&mvf_fbi->flip_sem, HZ/2)) {
+ dev_err(info->device, "timeout when waiting for flip irq\n");
+ return -ETIMEDOUT;
+ }
+
+ ++mvf_fbi->cur_dcu_buf;
+ mvf_fbi->cur_dcu_buf %= 3;
+ mvf_fbi->cur_dcu_alpha_buf = !mvf_fbi->cur_dcu_alpha_buf;
+
+ dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n",
+ info->fix.id, mvf_fbi->cur_dcu_buf, base);
+
+ if (dcu_update_layer_buffer(mvf_fbi->dcu, mvf_fbi->dcu_ch, IPU_INPUT_BUFFER,
+ mvf_fbi->cur_dcu_buf, base) == 0) {
+ // Update the DP local alpha buffer only for graphic plane
+ if (loc_alpha_en && mvf_graphic_fbi == mvf_fbi &&
+ dcu_update_layer_buffer(mvf_graphic_fbi->dcu, mvf_graphic_fbi->dcu_ch,
+ IPU_ALPHA_IN_BUFFER,
+ mvf_fbi->cur_dcu_alpha_buf,
+ active_alpha_phy_addr) == 0) {
+ dcu_select_buffer(mvf_graphic_fbi->dcu, mvf_graphic_fbi->dcu_ch,
+ IPU_ALPHA_IN_BUFFER,
+ mvf_fbi->cur_dcu_alpha_buf);
+ }
+
+ // update u/v offset
+ dcu_update_layer_offset(mvf_fbi->dcu, mvf_fbi->dcu_ch,
+ IPU_INPUT_BUFFER,
+ bpp_to_pixfmt(info),
+ fr_w,
+ fr_h,
+ fr_w,
+ 0, 0,
+ fr_yoff,
+ fr_xoff);
+
+ dcu_select_buffer(mvf_fbi->dcu, mvf_fbi->dcu_ch, IPU_INPUT_BUFFER,
+ mvf_fbi->cur_dcu_buf);
+ dcu_clear_irq(mvf_fbi->dcu, mvf_fbi->dcu_ch_irq);
+ dcu_enable_irq(mvf_fbi->dcu, mvf_fbi->dcu_ch_irq);
+ } else {
+ dev_err(info->device,
+ "Error updating SDC buf %d to address=0x%08lX, "
+ "current buf %d, buf0 ready %d, buf1 ready %d, "
+ "buf2 ready %d\n", mvf_fbi->cur_dcu_buf, base,
+ dcu_get_cur_buffer_idx(mvf_fbi->dcu, mvf_fbi->dcu_ch,
+ IPU_INPUT_BUFFER),
+ dcu_check_buffer_ready(mvf_fbi->dcu, mvf_fbi->dcu_ch,
+ IPU_INPUT_BUFFER, 0),
+ dcu_check_buffer_ready(mvf_fbi->dcu, mvf_fbi->dcu_ch,
+ IPU_INPUT_BUFFER, 1),
+ dcu_check_buffer_ready(mvf_fbi->dcu, mvf_fbi->dcu_ch,
+ IPU_INPUT_BUFFER, 2));
+ ++mvf_fbi->cur_dcu_buf;
+ mvf_fbi->cur_dcu_buf %= 3;
+ ++mvf_fbi->cur_dcu_buf;
+ mvf_fbi->cur_dcu_buf %= 3;
+ mvf_fbi->cur_dcu_alpha_buf = !mvf_fbi->cur_dcu_alpha_buf;
+ dcu_clear_irq(mvf_fbi->dcu, mvf_fbi->dcu_ch_irq);
+ dcu_enable_irq(mvf_fbi->dcu, mvf_fbi->dcu_ch_irq);
+ return -EBUSY;
+ }
+
+ dev_dbg(info->device, "Update complete\n");
+
+ info->var.yoffset = var->yoffset;
+ */
+ return 0;
+}
+
+/*
+ * Function to handle custom mmap for MVF framebuffer.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @param vma Pointer to vm_area_struct
+ */
+static int mvffb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
+{
+ bool found = false;
+ u32 len;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ struct mvffb_alloc_list *mem;
+ struct mvffb_info *mvf_fbi = (struct mvffb_info *)fbi->par;
+
+ if (offset < fbi->fix.smem_len) {
+ /* mapping framebuffer memory */
+ len = fbi->fix.smem_len - offset;
+ vma->vm_pgoff = (fbi->fix.smem_start + offset) >> PAGE_SHIFT;
+ } else if ((vma->vm_pgoff ==
+ (mvf_fbi->alpha_phy_addr0 >> PAGE_SHIFT)) ||
+ (vma->vm_pgoff ==
+ (mvf_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) {
+ len = mvf_fbi->alpha_mem_len;
+ } else {
+ list_for_each_entry(mem, &fb_alloc_list, list) {
+ if (offset == mem->phy_addr) {
+ found = true;
+ len = mem->size;
+ break;
+ }
+ }
+ if (!found)
+ return -EINVAL;
+ }
+
+ len = PAGE_ALIGN(len);
+ if (vma->vm_end - vma->vm_start > len)
+ return -EINVAL;
+
+ /* make buffers bufferable */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ dev_dbg(fbi->device, "mmap remap_pfn_range failed\n");
+ return -ENOBUFS;
+ }
+
+ return 0;
+}
+
+/*!
+ * This structure contains the pointers to the control functions that are
+ * invoked by the core framebuffer driver to perform operations like
+ * blitting, rectangle filling, copy regions and cursor definition.
+ */
+static struct fb_ops mvffb_ops = {
+ .owner = THIS_MODULE,
+ .fb_set_par = mvffb_set_par,
+ .fb_check_var = mvffb_check_var,
+ .fb_pan_display = mvffb_pan_display,
+ .fb_ioctl = mvffb_ioctl,
+ .fb_mmap = mvffb_mmap,
+ //.fb_fillrect = cfb_fillrect,
+ //.fb_copyarea = cfb_copyarea,
+ //.fb_imageblit = cfb_imageblit,
+ .fb_blank = mvffb_blank,
+};
+
+/*
+ * Suspends the framebuffer and blanks the screen. Power management support
+ */
+static int mvffb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct fb_info *fbi = platform_get_drvdata(pdev);
+ struct mvffb_info *mvf_fbi = (struct mvffb_info *)fbi->par;
+ int saved_blank;
+
+ console_lock();
+ fb_set_suspend(fbi, 1);
+ saved_blank = mvf_fbi->cur_blank;
+ mvffb_blank(FB_BLANK_POWERDOWN, fbi);
+ mvf_fbi->next_blank = saved_blank;
+ console_unlock();
+
+ return 0;
+}
+
+/*
+ * Resumes the framebuffer and unblanks the screen. Power management support
+ */
+static int mvffb_resume(struct platform_device *pdev)
+{
+ struct fb_info *fbi = platform_get_drvdata(pdev);
+ struct mvffb_info *mvf_fbi = (struct mvffb_info *)fbi->par;
+
+ console_lock();
+ mvffb_blank(mvf_fbi->next_blank, fbi);
+ fb_set_suspend(fbi, 0);
+ console_unlock();
+
+ return 0;
+}
+
+/*
+ * Main framebuffer functions
+ */
+
+/*!
+ * Allocates the DRAM memory for the frame buffer. This buffer is remapped
+ * into a non-cached, non-buffered, memory region to allow palette and pixel
+ * writes to occur without flushing the cache. Once this area is remapped,
+ * all virtual memory access to the video memory should occur at the new region.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @return Error code indicating success or failure
+ */
+static int mvffb_map_video_memory(struct fb_info *fbi)
+{
+ if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length)
+ fbi->fix.smem_len = fbi->var.yres_virtual *
+ fbi->fix.line_length;
+
+ fbi->screen_base = dma_alloc_writecombine(fbi->device,
+ fbi->fix.smem_len,
+ (dma_addr_t *)&fbi->fix.smem_start,
+ GFP_DMA);
+ if (fbi->screen_base == 0) {
+ dev_err(fbi->device, "Unable to allocate framebuffer memory\n");
+ fbi->fix.smem_len = 0;
+ fbi->fix.smem_start = 0;
+ return -EBUSY;
+ }
+
+ dev_dbg(fbi->device, "allocated fb @ paddr=0x%08X, size=%d.\n",
+ (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
+
+ fbi->screen_size = fbi->fix.smem_len;
+
+ /* Clear the screen */
+ memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+ return 0;
+}
+
+/*!
+ * De-allocates the DRAM memory for the frame buffer.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @return Error code indicating success or failure
+ */
+static int mvffb_unmap_video_memory(struct fb_info *fbi)
+{
+ dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+ fbi->screen_base, fbi->fix.smem_start);
+ fbi->screen_base = 0;
+ fbi->fix.smem_start = 0;
+ fbi->fix.smem_len = 0;
+ return 0;
+}
+
+/*!
+ * Initializes the framebuffer information pointer. After allocating
+ * sufficient memory for the framebuffer structure, the fields are
+ * filled with custom information passed in from the configurable
+ * structures. This includes information such as bits per pixel,
+ * color maps, screen width/height and RGBA offsets.
+ *
+ * @return Framebuffer structure initialized with our information
+ */
+static struct fb_info *mvffb_init_fbinfo(struct device *dev, struct fb_ops *ops)
+{
+ struct fb_info *fbi;
+ struct mvffb_info *mvffbi;
+
+ /*
+ * Allocate sufficient memory for the fb structure
+ */
+ fbi = framebuffer_alloc(sizeof(struct mvffb_info), dev);
+ if (!fbi)
+ return NULL;
+
+ mvffbi = (struct mvffb_info *)fbi->par;
+
+ fbi->var.activate = FB_ACTIVATE_NOW;
+
+ fbi->fbops = ops;
+ fbi->flags = FBINFO_MODULE;
+ fbi->pseudo_palette = mvffbi->pseudo_palette;
+
+ /*
+ * Allocate colormap
+ */
+ fb_alloc_cmap(&fbi->cmap, 16, 0);
+
+ return fbi;
+}
+
+static int mvffb_dispdrv_init(struct platform_device *pdev,
+ struct fb_info *fbi)
+{
+ struct dcuv4_fb_platform_data *plat_data = pdev->dev.platform_data;
+ struct mvffb_info *mvffbi = (struct mvffb_info *)fbi->par;
+ struct mvf_dispdrv_setting setting;
+ char disp_dev[32], *default_dev = "lcd";
+ int ret = 0;
+
+ setting.if_fmt = plat_data->interface_pix_fmt;
+ setting.dft_mode_str = plat_data->mode_str;
+ setting.default_bpp = plat_data->default_bpp;
+
+ //TODO: What should be our default bpp?
+ if (!setting.default_bpp)
+ setting.default_bpp = 16;
+ setting.fbi = fbi;
+ if (!strlen(plat_data->disp_dev)) {
+ memcpy(disp_dev, default_dev, strlen(default_dev));
+ disp_dev[strlen(default_dev)] = '\0';
+ } else {
+ memcpy(disp_dev, plat_data->disp_dev,
+ strlen(plat_data->disp_dev));
+ disp_dev[strlen(plat_data->disp_dev)] = '\0';
+ }
+
+ dev_info(&pdev->dev, "Register mvf display driver %s\n", disp_dev);
+
+ mvffbi->dispdrv = mvf_dispdrv_gethandle(disp_dev, &setting);
+ if (IS_ERR(mvffbi->dispdrv)) {
+ ret = PTR_ERR(mvffbi->dispdrv);
+ dev_err(&pdev->dev, "NO mvf display driver found!\n");
+ return ret;
+ } else {
+ // fix-up
+ mvffbi->dcu_pix_fmt = setting.if_fmt;
+ mvffbi->default_bpp = setting.default_bpp;
+
+ // setting - set default setting of dev_id if plat_data dcu_id is DCU0
+ if(!plat_data->dcu_id)
+ mvffbi->dcu_id = setting.dev_id;
+ }
+
+ return ret;
+}
+
+/*
+ * Parse user specified options (`video=trident:')
+ * example:
+ * orig - video=mvffb0:dev=lcd,800x480M-16@55,if=RGB565,bpp=16,noaccel
+ * TODO: video=mvffb0:dev=lcd,if=BGRA8888,dcu=0,NEC-WQVGA,primary video=mvffb1:dev=lcd,if=BGRA8888,dcu=1,NEC-WQVGA
+ * Proposed: video=mvfdcu0fb:BGRA8888,NEC-WQVGA dcu0_primary
+ * Supported Below: video=mvffb0:dev=lcd,if=BGRA8888,dcu=0,NEC-WQVGA
+ * TODO: re-visit the supported formats below to enhance the list
+ */
+static int mvffb_option_setup(struct platform_device *pdev)
+{
+ struct dcuv4_fb_platform_data *pdata = pdev->dev.platform_data;
+ char *options, *opt, *fb_mode_str = NULL;
+ char name[] = "mvffb0";
+
+ name[5] += pdev->id;
+ fb_get_options(name, &options);
+
+ if (!options || !*options)
+ return 0;
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+
+ if (!strncmp(opt, "dev=", 4)) {
+ memcpy(pdata->disp_dev, opt + 4, strlen(opt) - 4);
+ pdata->disp_dev[strlen(opt) - 4] = '\0';
+ continue;
+ }
+ if (!strncmp(opt, "if=", 3)) {
+ if (!strncmp(opt+3, "RGB24", 5)) {
+ pdata->interface_pix_fmt = V4L2_PIX_FMT_RGB24;
+ continue;
+ }
+ if (!strncmp(opt+3, "RGB565", 6)) {
+ pdata->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
+ continue;
+ }
+ if (!strncmp(opt+3, "RGB32", 5)) {
+ pdata->interface_pix_fmt = V4L2_PIX_FMT_RGB32;
+ continue;
+ }
+
+ /*if (!strncmp(opt+6, "BGR24", 5)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_BGR24;
+ continue;
+ }
+ if (!strncmp(opt+3, "GBR24", 5)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_GBR24;
+ continue;
+ }
+ if (!strncmp(opt+3, "RGB666", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_RGB666;
+ continue;
+ }
+ if (!strncmp(opt+3, "YUV444", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_YUV444;
+ continue;
+ }
+ if (!strncmp(opt+3, "LVDS666", 7)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_LVDS666;
+ continue;
+ }
+ if (!strncmp(opt+3, "YUYV16", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_YUYV;
+ continue;
+ }
+ if (!strncmp(opt+3, "UYVY16", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_UYVY;
+ continue;
+ }
+ if (!strncmp(opt+3, "YVYU16", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_YVYU;
+ continue;
+ }
+ if (!strncmp(opt+3, "VYUY16", 6)) {
+ pdata->interface_pix_fmt = IPU_PIX_FMT_VYUY;
+ continue;
+ }
+ */
+ }
+
+ if(!strncmp(opt,"dcu=", 4))
+ pdata->dcu_id =
+ simple_strtoul(opt + 4, NULL, 0);
+ if (!strncmp(opt, "bpp=", 4))
+ pdata->default_bpp =
+ simple_strtoul(opt + 4, NULL, 0);
+ else
+ fb_mode_str = opt;
+ }
+
+ if (fb_mode_str)
+ pdata->mode_str = fb_mode_str;
+
+ return 0;
+}
+
+static int mvffb_register(struct fb_info *fbi)
+{
+ struct mvffb_info *mvffbi = (struct mvffb_info *)fbi->par;
+ struct fb_videomode m;
+ int ret = 0;
+
+ char disp_id[] = "DCU0 BG LAYER";
+ char layer_id[] = "DCU0 FG LAYER";
+
+ if(!mvffbi->layer)
+ {
+ disp_id[3] += mvffbi->dcu_id;
+ strcpy(fbi->fix.id, disp_id);
+ }
+ else
+ {
+ layer_id[3] += mvffbi->dcu_id;
+ strcpy(fbi->fix.id, layer_id);
+ }
+
+ mvffb_check_var(&fbi->var, fbi);
+
+ mvffb_set_fix(fbi);
+
+ /*added first mode to fbi modelist*/
+ if (!fbi->modelist.next || !fbi->modelist.prev)
+ INIT_LIST_HEAD(&fbi->modelist);
+ fb_var_to_videomode(&m, &fbi->var);
+ fb_add_videomode(&m, &fbi->modelist);
+
+ fbi->var.activate |= FB_ACTIVATE_FORCE;
+ console_lock();
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ ret = fb_set_var(fbi, &fbi->var);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+
+ if (mvffbi->next_blank == FB_BLANK_UNBLANK) {
+ console_lock();
+ fb_blank(fbi, FB_BLANK_UNBLANK);
+ console_unlock();
+ }
+
+ ret = register_framebuffer(fbi);
+
+ return ret;
+}
+
+static void mvffb_unregister(struct fb_info *fbi)
+{
+ unregister_framebuffer(fbi);
+}
+
+//Setting up the overlay frame buffer and registering the same.
+static int mvffb_setup_overlay(struct platform_device *pdev,
+ struct fb_info *fbi_bg, struct resource *res)
+{
+ struct fb_info *ovfbi;
+ struct mvffb_info *mvffbi_bg = (struct mvffb_info *)fbi_bg->par;
+ struct mvffb_info *mvffbi_fg;
+ int ret = 0;
+
+ ovfbi = mvffb_init_fbinfo(&pdev->dev, &mvffb_ops);
+ if (!ovfbi) {
+ ret = -ENOMEM;
+ goto init_ovfbinfo_failed;
+ }
+ mvffbi_fg = (struct mvffb_info *)ovfbi->par;
+
+ mvffbi_fg->dcu = dcu_get_soc(mvffbi_bg->dcu_id);
+ if (IS_ERR(mvffbi_fg->dcu)) {
+ ret = -ENODEV;
+ goto get_dcu_failed;
+ }
+ mvffbi_fg->dcu_id = mvffbi_bg->dcu_id;
+ mvffbi_fg->dcu_pix_fmt = mvffbi_bg->dcu_pix_fmt;
+ mvffbi_fg->layer = true;
+ mvffbi_fg->cur_blank = mvffbi_fg->next_blank = FB_BLANK_POWERDOWN;
+
+ // Need dummy values until real panel is configured
+ ovfbi->var.xres = 240;
+ ovfbi->var.yres = 320;
+
+ if (res && res->start && res->end) {
+ ovfbi->fix.smem_len = res->end - res->start + 1;
+ ovfbi->fix.smem_start = res->start;
+ ovfbi->screen_base = ioremap(
+ ovfbi->fix.smem_start,
+ ovfbi->fix.smem_len);
+ }
+
+ ret = mvffb_register(ovfbi);
+ if (ret < 0)
+ goto register_ov_failed;
+
+ mvffbi_bg->ovfbi[ovfbi->node] = ovfbi;
+
+ return ret;
+
+register_ov_failed:
+get_dcu_failed:
+ fb_dealloc_cmap(&ovfbi->cmap);
+ framebuffer_release(ovfbi);
+init_ovfbinfo_failed:
+ return ret;
+}
+
+static void mvffb_unsetup_overlay(struct fb_info *fbi_bg, int layer_num)
+{
+ struct mvffb_info *mvffbi_bg = (struct mvffb_info *)fbi_bg->par;
+ struct fb_info *ovfbi = mvffbi_bg->ovfbi[layer_num];
+
+ mvffb_unregister(ovfbi);
+
+ if (&ovfbi->cmap)
+ fb_dealloc_cmap(&ovfbi->cmap);
+ framebuffer_release(ovfbi);
+}
+
+/*!
+ * Probe routine for the framebuffer driver. It is called during the
+ * driver binding process. The following functions are performed in
+ * this routine: Framebuffer initialization, Memory allocation and
+ * mapping, Framebuffer registration, DCU initialization.
+ *
+ * @return Appropriate error code to the kernel common code
+ */
+static int mvffb_probe(struct platform_device *pdev)
+{
+ //struct dcuv4_fb_platform_data *plat_data = pdev->dev.platform_data;
+ struct fb_info *fbi;
+ struct mvffb_info *mvffbi;
+ struct resource *res;
+ int ret = 0, i = 0;
+
+ printk("Framebuffer: Probe Entered!!!!\n");
+ /*
+ * Initialize FB structures
+ */
+ fbi = mvffb_init_fbinfo(&pdev->dev, &mvffb_ops);
+ if (!fbi) {
+ ret = -ENOMEM;
+ goto init_fbinfo_failed;
+ }
+ printk("Framebuffer: init complete!!!!\n");
+
+ mvffb_option_setup(pdev);
+
+ printk("Framebuffer: option setup complete!!!!\n");
+
+ mvffbi = (struct mvffb_info *)fbi->par;
+ ret = mvffb_dispdrv_init(pdev, fbi);
+ if (ret < 0)
+ goto init_dispdrv_failed;
+
+ ret = dcu_set_usage(mvffbi->dcu_id);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "dcu%d already in use\n",
+ mvffbi->dcu_id);
+ goto dcu_in_busy;
+ }
+
+ printk("Framebuffer: disp drv init complete!!!!\n");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res && res->start && res->end) {
+ fbi->fix.smem_len = res->end - res->start + 1;
+ fbi->fix.smem_start = res->start;
+ fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len);
+ memset(fbi->screen_base, 0, fbi->fix.smem_len);
+ }
+
+ mvffbi->dcu = dcu_get_soc(mvffbi->dcu_id);
+ if (IS_ERR(mvffbi->dcu)) {
+ ret = -ENODEV;
+ goto get_dcu_failed;
+ }
+
+ printk("Framebuffer: got dcu soc handle!!!!\n");
+
+ /* first user uses DP(display processor) with alpha feature */
+ if (!g_dp_in_use[mvffbi->dcu_id]) {
+ mvffbi->cur_blank = mvffbi->next_blank = FB_BLANK_UNBLANK;
+
+ if(dcu_config_layer_alpha(mvffbi->dcu, fbi->node, 0x80, ALPHA_BLEND_ENABLED)) {
+ ret = -EINVAL;
+ goto mvffb_register_failed;
+ }
+ //dcu_disp_set_color_key(mvffbi->dcu, mvffbi->dcu_ch, false, 0);
+
+ ret = mvffb_register(fbi);
+ if (ret < 0)
+ goto mvffb_register_failed;
+
+ printk("Framebuffer: registered fb with alpha complete!!!!\n");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ for(i = 1; i <= (CONFIG_FB_MVF_NUM_FBS-1); i++)
+ {
+ printk("Framebuffer: Registering Layer %d\n", i);
+ ret = mvffb_setup_overlay(pdev, fbi, res);
+
+ if (ret < 0) {
+ mvffb_unregister(fbi);
+ goto mvffb_setupoverlay_failed;
+ }
+ }
+
+ g_dp_in_use[mvffbi->dcu_id] = true;
+ } else {
+ mvffbi->cur_blank = mvffbi->next_blank = FB_BLANK_POWERDOWN;
+
+ ret = mvffb_register(fbi);
+ if (ret < 0)
+ goto mvffb_register_failed;
+ printk("Framebuffer: registred fb complete!!!!\n");
+
+ }
+
+ platform_set_drvdata(pdev, fbi);
+
+#ifdef CONFIG_LOGO
+ printk("Framebuffer: showing logo...!!!!\n");
+ fb_prepare_logo(fbi, 0);
+ fb_show_logo(fbi, 0);
+#endif
+
+ return 0;
+
+mvffb_setupoverlay_failed:
+mvffb_register_failed:
+get_dcu_failed:
+ dcu_clear_usage(mvffbi->dcu_id);
+dcu_in_busy:
+init_dispdrv_failed:
+ fb_dealloc_cmap(&fbi->cmap);
+ framebuffer_release(fbi);
+init_fbinfo_failed:
+ return ret;
+}
+
+static int mvffb_remove(struct platform_device *pdev)
+{
+ struct fb_info *fbi = platform_get_drvdata(pdev);
+ struct mvffb_info *mvf_fbi = fbi->par;
+ int i = 0;
+
+ if (!fbi)
+ return 0;
+
+ mvffb_blank(FB_BLANK_POWERDOWN, fbi);
+ mvffb_unregister(fbi);
+ mvffb_unmap_video_memory(fbi);
+
+ for(i = 1; i <= (CONFIG_FB_MVF_NUM_FBS-1); i++)
+ {
+ if (mvf_fbi->ovfbi[i]) {
+ mvffb_blank(FB_BLANK_POWERDOWN, mvf_fbi->ovfbi[i]);
+ mvffb_unsetup_overlay(fbi, i);
+ mvffb_unmap_video_memory(mvf_fbi->ovfbi[i]);
+ }
+ }
+
+ dcu_clear_usage(mvf_fbi->dcu_id);
+ if (&fbi->cmap)
+ fb_dealloc_cmap(&fbi->cmap);
+ framebuffer_release(fbi);
+ return 0;
+}
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mvffb_driver = {
+ .driver = {
+ .name = MVFFB_NAME,
+ },
+ .probe = mvffb_probe,
+ .remove = mvffb_remove,
+ .suspend = mvffb_suspend,
+ .resume = mvffb_resume,
+};
+
+/*!
+ * Main entry function for the framebuffer. The function registers the power
+ * management callback functions with the kernel and also registers the MVFFB
+ * callback functions with the core Linux framebuffer driver \b fbmem.c
+ *
+ * @return Error code indicating success or failure
+ */
+int __init mvffb_init(void)
+{
+ return platform_driver_register(&mvffb_driver);
+}
+
+void mvffb_exit(void)
+{
+ platform_driver_unregister(&mvffb_driver);
+}
+
+module_init(mvffb_init);
+module_exit(mvffb_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MVF frame buffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
diff --git a/drivers/video/mvf/mvf_dispdrv.c b/drivers/video/mvf/mvf_dispdrv.c
new file mode 100644
index 000000000000..84aed84bb6d9
--- /dev/null
+++ b/drivers/video/mvf/mvf_dispdrv.c
@@ -0,0 +1,144 @@
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mvf_dispdrv.c
+ * @brief mvf display driver framework.
+ *
+ * A display device driver could call mvf_dispdrv_register(drv) in its dev_probe() function.
+ * Move all dev_probe() things into mvf_dispdrv_driver->init(), init() function should init
+ * and feedback setting;
+ * Move all dev_remove() things into mvf_dispdrv_driver->deinit();
+ * Move all dev_suspend() things into fb_notifier for SUSPEND, if there is;
+ * Move all dev_resume() things into fb_notifier for RESUME, if there is;
+ *
+ * DCU4 fb driver could call mvf_dispdrv_gethandle(name, setting) before a fb
+ * need be added, with fbi param passing by setting, after
+ * mvf_dispdrv_gethandle() return, FB driver should get the basic setting
+ * about fbi info and dcuv4-hw.
+ *
+ * @ingroup Framebuffer
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include "mvf_dispdrv.h"
+
+static LIST_HEAD(dispdrv_list);
+static DEFINE_MUTEX(dispdrv_lock);
+
+struct mvf_dispdrv_entry {
+ /* Note: drv always the first element */
+ struct mvf_dispdrv_driver *drv;
+ bool active;
+ void *priv;
+ struct list_head list;
+};
+
+struct mvf_dispdrv_handle *mvf_dispdrv_register(struct mvf_dispdrv_driver *drv)
+{
+ struct mvf_dispdrv_entry *new;
+
+ mutex_lock(&dispdrv_lock);
+
+ new = kzalloc(sizeof(struct mvf_dispdrv_entry), GFP_KERNEL);
+ if (!new) {
+ mutex_unlock(&dispdrv_lock);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ new->drv = drv;
+ list_add_tail(&new->list, &dispdrv_list);
+
+ mutex_unlock(&dispdrv_lock);
+
+ return (struct mvf_dispdrv_handle *)new;
+}
+EXPORT_SYMBOL_GPL(mvf_dispdrv_register);
+
+int mvf_dispdrv_unregister(struct mvf_dispdrv_handle *handle)
+{
+ struct mvf_dispdrv_entry *entry = (struct mvf_dispdrv_entry *)handle;
+
+ if (entry) {
+ mutex_lock(&dispdrv_lock);
+ list_del(&entry->list);
+ mutex_unlock(&dispdrv_lock);
+ kfree(entry);
+ return 0;
+ } else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mvf_dispdrv_unregister);
+
+struct mvf_dispdrv_handle *mvf_dispdrv_gethandle(char *name,
+ struct mvf_dispdrv_setting *setting)
+{
+ int ret, found = 0;
+ struct mvf_dispdrv_entry *entry;
+
+ mutex_lock(&dispdrv_lock);
+ list_for_each_entry(entry, &dispdrv_list, list) {
+ if (!strcmp(entry->drv->name, name) && (entry->drv->init)) {
+ ret = entry->drv->init((struct mvf_dispdrv_handle *)
+ entry, setting);
+ if (ret >= 0) {
+ entry->active = true;
+ found = 1;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&dispdrv_lock);
+
+ return found ? (struct mvf_dispdrv_handle *)entry:ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(mvf_dispdrv_gethandle);
+
+void mvf_dispdrv_puthandle(struct mvf_dispdrv_handle *handle)
+{
+ struct mvf_dispdrv_entry *entry = (struct mvf_dispdrv_entry *)handle;
+
+ mutex_lock(&dispdrv_lock);
+ if (entry && entry->active && entry->drv->deinit) {
+ entry->drv->deinit(handle);
+ entry->active = false;
+ }
+ mutex_unlock(&dispdrv_lock);
+
+}
+EXPORT_SYMBOL_GPL(mvf_dispdrv_puthandle);
+
+int mvf_dispdrv_setdata(struct mvf_dispdrv_handle *handle, void *data)
+{
+ struct mvf_dispdrv_entry *entry = (struct mvf_dispdrv_entry *)handle;
+
+ if (entry) {
+ entry->priv = data;
+ return 0;
+ } else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mvf_dispdrv_setdata);
+
+void *mvf_dispdrv_getdata(struct mvf_dispdrv_handle *handle)
+{
+ struct mvf_dispdrv_entry *entry = (struct mvf_dispdrv_entry *)handle;
+
+ if (entry) {
+ return entry->priv;
+ } else
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(mvf_dispdrv_getdata);
diff --git a/drivers/video/mvf/mvf_dispdrv.h b/drivers/video/mvf/mvf_dispdrv.h
new file mode 100644
index 000000000000..5de389cb91a4
--- /dev/null
+++ b/drivers/video/mvf/mvf_dispdrv.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __MVF_DISPDRV_H__
+#define __MVF_DISPDRV_H__
+#include <linux/fb.h>
+
+struct mvf_dispdrv_handle {
+ struct mvf_dispdrv_driver *drv;
+};
+
+struct mvf_dispdrv_setting {
+ /*input-feedback parameter*/
+ struct fb_info *fbi;
+ int if_fmt;
+ int default_bpp;
+ char *dft_mode_str;
+
+ /*feedback parameter*/
+ int dev_id;
+};
+
+struct mvf_dispdrv_driver {
+ const char *name;
+ int (*init) (struct mvf_dispdrv_handle *, struct mvf_dispdrv_setting *);
+ void (*deinit) (struct mvf_dispdrv_handle *);
+ /* display driver enable function for extension */
+ int (*enable) (struct mvf_dispdrv_handle *);
+ /* display driver disable function, called at early part of fb_blank */
+ void (*disable) (struct mvf_dispdrv_handle *);
+ /* display driver setup function, called at early part of fb_set_par */
+ int (*setup) (struct mvf_dispdrv_handle *, struct fb_info *fbi);
+};
+
+struct mvf_dispdrv_handle *mvf_dispdrv_register(struct mvf_dispdrv_driver *drv);
+int mvf_dispdrv_unregister(struct mvf_dispdrv_handle *handle);
+struct mvf_dispdrv_handle *mvf_dispdrv_gethandle(char *name,
+ struct mvf_dispdrv_setting *setting);
+void mvf_dispdrv_puthandle(struct mvf_dispdrv_handle *handle);
+int mvf_dispdrv_setdata(struct mvf_dispdrv_handle *handle, void *data);
+void *mvf_dispdrv_getdata(struct mvf_dispdrv_handle *handle);
+#endif
diff --git a/drivers/video/mvf/mvffb_nec_wqvga.c b/drivers/video/mvf/mvffb_nec_wqvga.c
new file mode 100644
index 000000000000..82d8ff371aa5
--- /dev/null
+++ b/drivers/video/mvf/mvffb_nec_wqvga.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mvffb.h>
+#include <linux/fsl_devices.h>
+#include "mvf_dispdrv.h"
+
+struct mvf_lcdif_data {
+ struct platform_device *pdev;
+ struct mvf_dispdrv_handle *disp_lcdif;
+};
+
+#define DISPDRV_LCD "lcd"
+
+static struct fb_videomode lcdif_modedb[] = {
+ {
+ /* 480x272 @ 75 Hz pixel clock - typical - 10.87Mhz*/
+ "NEC-WQVGA", 75, 480, 272, KHZ2PICOS(10870), 2, 2, 1, 1, 41, 2,
+ /*Active low HSYC/VSYNC, Sample on falling edge of pxl clk, output not negated*/
+ 0,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+};
+
+static int lcdif_modedb_sz = ARRAY_SIZE(lcdif_modedb);
+
+static int lcdif_init(struct mvf_dispdrv_handle *disp,
+ struct mvf_dispdrv_setting *setting)
+{
+ int ret, i;
+ struct mvf_lcdif_data *lcdif = mvf_dispdrv_getdata(disp);
+ struct fsl_mvf_lcd_platform_data *plat_data
+ = lcdif->pdev->dev.platform_data;
+ struct fb_videomode *modedb = lcdif_modedb;
+ int modedb_sz = lcdif_modedb_sz;
+
+ printk("lcd-if: init called with dcu = %d!!\n", plat_data->dcu_id);
+ printk("The pixel clock in modedb, picosecs = %ld, HZ = %ld\n", KHZ2PICOS(10870), ((PICOS2KHZ(91996)) * 1000UL));
+
+ /* use platform defined dcu */
+ setting->dev_id = plat_data->dcu_id;
+
+ ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
+ modedb, modedb_sz, NULL, setting->default_bpp);
+ if (!ret) {
+ fb_videomode_to_var(&setting->fbi->var, &modedb[0]);
+ setting->if_fmt = plat_data->default_ifmt;
+ }
+
+ INIT_LIST_HEAD(&setting->fbi->modelist);
+ for (i = 0; i < modedb_sz; i++) {
+ struct fb_videomode m;
+ fb_var_to_videomode(&m, &setting->fbi->var);
+ if (fb_mode_is_equal(&m, &modedb[i])) {
+ fb_add_videomode(&modedb[i],
+ &setting->fbi->modelist);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void lcdif_deinit(struct mvf_dispdrv_handle *disp)
+{
+ /*TODO*/
+}
+
+static struct mvf_dispdrv_driver lcdif_drv = {
+ .name = DISPDRV_LCD,
+ .init = lcdif_init,
+ .deinit = lcdif_deinit,
+};
+
+static int mvf_lcdif_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mvf_lcdif_data *lcdif;
+ printk("lcdif: probe called!!!\n");
+
+ lcdif = kzalloc(sizeof(struct mvf_lcdif_data), GFP_KERNEL);
+ if (!lcdif) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ lcdif->pdev = pdev;
+ lcdif->disp_lcdif = mvf_dispdrv_register(&lcdif_drv);
+ mvf_dispdrv_setdata(lcdif->disp_lcdif, lcdif);
+
+ dev_set_drvdata(&pdev->dev, lcdif);
+
+ printk("lcdif: registeration and setdata complete\n");
+alloc_failed:
+ return ret;
+}
+
+static int mvf_lcdif_remove(struct platform_device *pdev)
+{
+ struct mvf_lcdif_data *lcdif = dev_get_drvdata(&pdev->dev);
+
+ mvf_dispdrv_puthandle(lcdif->disp_lcdif);
+ mvf_dispdrv_unregister(lcdif->disp_lcdif);
+ kfree(lcdif);
+ return 0;
+}
+
+static struct platform_driver mvf_lcdif_driver = {
+ .driver = {
+ .name = "mvf_lcdif",
+ },
+ .probe = mvf_lcdif_probe,
+ .remove = mvf_lcdif_remove,
+};
+
+static int __init mvf_lcdif_init(void)
+{
+ return platform_driver_register(&mvf_lcdif_driver);
+}
+
+static void __exit mvf_lcdif_exit(void)
+{
+ platform_driver_unregister(&mvf_lcdif_driver);
+}
+
+module_init(mvf_lcdif_init);
+module_exit(mvf_lcdif_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MVF DCUV4 LCD driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 8ebf770c3af9..7a1a770532d0 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -303,6 +303,16 @@ struct fsl_mxc_tvin_platform_data {
bool cvbs;
};
+struct fsl_mvf_lcd_platform_data {
+ void (*reset) (void);
+ int (*get_pins) (void);
+ void (*put_pins) (void);
+ void (*enable_pins) (void);
+ void (*disable_pins) (void);
+ int default_ifmt;
+ int dcu_id;
+};
+
struct mpc8xx_pcmcia_ops {
void(*hw_ctrl)(int slot, int enable);
int(*voltage_set)(int slot, int vcc, int vpp);
diff --git a/include/linux/mvffb.h b/include/linux/mvffb.h
new file mode 100644
index 000000000000..436ba9a1238b
--- /dev/null
+++ b/include/linux/mvffb.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License. You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+/*
+ * @file arch-mvf/ mvffb.h
+ *
+ * @brief Global header file for the MVF Frame buffer
+ *
+ * @ingroup Framebuffer
+ */
+#ifndef __ASM_ARCH_MVFFB_H__
+#define __ASM_ARCH_MVFFB_H__
+
+#include <linux/fb.h>
+
+#define FB_SYNC_INV_PIX_CLK 0x80000000 /* If set Display samples data on the rising edge */
+#define FB_SYNC_DATA_INVERT 0x20000000 /* If set Output to display to be negated */
+
+enum {
+
+ DISABLE_ALPHA_BLEND = 0,
+ ENABLE_ALPHA_BLEND = 2,
+};
+
+struct mvffb_layer_alpha {
+ int blend_enable;
+ int alpha;
+};
+
+struct mvffb_layer_pos {
+ __u16 x; //position
+ __u16 y;
+};
+
+/* Custom IOCTL's to support advanced FB operations */
+#define MVFFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t)
+#define MVFFB_SET_LAYER_ALPHA _IOW('F', 0x21, struct mvffb_layer_alpha)
+#define MVFFB_GET_FB_BLANK _IOR('F', 0x22, u_int32_t)
+#define MVFFB_SETUP_LAYER _IOW('F', 0x23, struct mvffb_layer_pos)
+//#define MVFFB_SET_CLR_KEY _IOW('F', 0x22, struct mvffb_color_key)
+//#define MVFFB_SET_OVERLAY_POS _IOWR('F', 0x24, struct mvffb_pos)
+//#define MVFFB_SET_LOC_ALPHA _IOWR('F', 0x26, struct mvffb_loc_alpha)
+//#define MVFFB_SET_LOC_ALP_BUF _IOW('F', 0x27, unsigned long)
+//#define MVFFB_SET_GAMMA _IOW('F', 0x28, struct mvffb_gamma)
+
+//#define MVFFB_ENABLE_OVERLAY_DOUBLE_BUFFER _IOW('F',0x2d, u_int32_t)
+
+#ifdef __KERNEL__
+
+extern struct fb_videomode mvffb_modedb[];
+extern int mvffb_modedb_sz;
+
+#endif /* __KERNEL__ */
+#endif