diff options
author | Liu Ying <b17645@freescale.com> | 2010-07-13 17:39:46 +0800 |
---|---|---|
committer | Justin Waters <justin.waters@timesys.com> | 2010-12-17 12:10:50 -0500 |
commit | 27072bc84de2fb24f3382f7b10d48d4fc20bffb7 (patch) | |
tree | efee6e86fb9626aec6f9f558554459ddf63d7ee7 | |
parent | affb65ad818251ca22acb10b4f79307ed60602f0 (diff) |
ENGR00124989-3 ELCDIF:Support ELCDIF framebuffer driver
1) Support ELCDIF framebuffer driver.
2) Change CLAA WVGA LCD driver to make it co-work with ELCDIF driver.
Signed-off-by: Liu Ying <b17645@freescale.com>
-rw-r--r-- | drivers/video/mxc/Kconfig | 4 | ||||
-rw-r--r-- | drivers/video/mxc/Makefile | 3 | ||||
-rw-r--r-- | drivers/video/mxc/elcdif_regs.h | 678 | ||||
-rw-r--r-- | drivers/video/mxc/mxc_elcdif_fb.c | 1438 | ||||
-rw-r--r-- | drivers/video/mxc/mxcfb_claa_wvga.c | 12 |
5 files changed, 2129 insertions, 6 deletions
diff --git a/drivers/video/mxc/Kconfig b/drivers/video/mxc/Kconfig index e7d93d164a9d..66a7f84c5656 100644 --- a/drivers/video/mxc/Kconfig +++ b/drivers/video/mxc/Kconfig @@ -82,6 +82,10 @@ config FB_MXC_EINK_AUTO_UPDATE_MODE default n depends on FB_MXC_EINK_PANEL +config FB_MXC_ELCDIF_FB + depends on FB && ARCH_MXC + tristate "Support MXC ELCDIF framebuffer" + choice prompt "Async Panel Interface Type" depends on FB_MXC_ASYNC_PANEL && FB_MXC diff --git a/drivers/video/mxc/Makefile b/drivers/video/mxc/Makefile index 1985ee4ac0b4..c428bb95a948 100644 --- a/drivers/video/mxc/Makefile +++ b/drivers/video/mxc/Makefile @@ -20,4 +20,5 @@ obj-$(CONFIG_FB_MXC_TVOUT_TVE) += tve.o obj-$(CONFIG_FB_MXC_LDB) += ldb.o obj-$(CONFIG_FB_MXC_CH7026) += mxcfb_ch7026.o #obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o -obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o
\ No newline at end of file +obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o +obj-$(CONFIG_FB_MXC_ELCDIF_FB) += mxc_elcdif_fb.o diff --git a/drivers/video/mxc/elcdif_regs.h b/drivers/video/mxc/elcdif_regs.h new file mode 100644 index 000000000000..2eceba5864e0 --- /dev/null +++ b/drivers/video/mxc/elcdif_regs.h @@ -0,0 +1,678 @@ +/* + * Copyright (C) 2010 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. + */ +/* + * Based on arch/arm/mach-mx28/include/mach/regs-lcdif.h. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +#ifndef __ELCDIF_REGS_INCLUDED_ +#define __ELCDIF_REGS_INCLUDED_ + +#define HW_ELCDIF_CTRL (0x00000000) +#define HW_ELCDIF_CTRL_SET (0x00000004) +#define HW_ELCDIF_CTRL_CLR (0x00000008) +#define HW_ELCDIF_CTRL_TOG (0x0000000c) + +#define BM_ELCDIF_CTRL_SFTRST 0x80000000 +#define BM_ELCDIF_CTRL_CLKGATE 0x40000000 +#define BM_ELCDIF_CTRL_YCBCR422_INPUT 0x20000000 +#define BM_ELCDIF_CTRL_READ_WRITEB 0x10000000 +#define BM_ELCDIF_CTRL_WAIT_FOR_VSYNC_EDGE 0x08000000 +#define BM_ELCDIF_CTRL_DATA_SHIFT_DIR 0x04000000 +#define BV_ELCDIF_CTRL_DATA_SHIFT_DIR__TXDATA_SHIFT_LEFT 0x0 +#define BV_ELCDIF_CTRL_DATA_SHIFT_DIR__TXDATA_SHIFT_RIGHT 0x1 +#define BP_ELCDIF_CTRL_SHIFT_NUM_BITS 21 +#define BM_ELCDIF_CTRL_SHIFT_NUM_BITS 0x03E00000 +#define BF_ELCDIF_CTRL_SHIFT_NUM_BITS(v) \ + (((v) << 21) & BM_ELCDIF_CTRL_SHIFT_NUM_BITS) +#define BM_ELCDIF_CTRL_DVI_MODE 0x00100000 +#define BM_ELCDIF_CTRL_BYPASS_COUNT 0x00080000 +#define BM_ELCDIF_CTRL_VSYNC_MODE 0x00040000 +#define BM_ELCDIF_CTRL_DOTCLK_MODE 0x00020000 +#define BM_ELCDIF_CTRL_DATA_SELECT 0x00010000 +#define BV_ELCDIF_CTRL_DATA_SELECT__CMD_MODE 0x0 +#define BV_ELCDIF_CTRL_DATA_SELECT__DATA_MODE 0x1 +#define BP_ELCDIF_CTRL_INPUT_DATA_SWIZZLE 14 +#define BM_ELCDIF_CTRL_INPUT_DATA_SWIZZLE 0x0000C000 +#define BF_ELCDIF_CTRL_INPUT_DATA_SWIZZLE(v) \ + (((v) << 14) & BM_ELCDIF_CTRL_INPUT_DATA_SWIZZLE) +#define BV_ELCDIF_CTRL_INPUT_DATA_SWIZZLE__NO_SWAP 0x0 +#define BV_ELCDIF_CTRL_INPUT_DATA_SWIZZLE__LITTLE_ENDIAN 0x0 +#define BV_ELCDIF_CTRL_INPUT_DATA_SWIZZLE__BIG_ENDIAN_SWAP 0x1 +#define BV_ELCDIF_CTRL_INPUT_DATA_SWIZZLE__SWAP_ALL_BYTES 0x1 +#define BV_ELCDIF_CTRL_INPUT_DATA_SWIZZLE__HWD_SWAP 0x2 +#define BV_ELCDIF_CTRL_INPUT_DATA_SWIZZLE__HWD_BYTE_SWAP 0x3 +#define BP_ELCDIF_CTRL_CSC_DATA_SWIZZLE 12 +#define BM_ELCDIF_CTRL_CSC_DATA_SWIZZLE 0x00003000 +#define BF_ELCDIF_CTRL_CSC_DATA_SWIZZLE(v) \ + (((v) << 12) & BM_ELCDIF_CTRL_CSC_DATA_SWIZZLE) +#define BV_ELCDIF_CTRL_CSC_DATA_SWIZZLE__NO_SWAP 0x0 +#define BV_ELCDIF_CTRL_CSC_DATA_SWIZZLE__LITTLE_ENDIAN 0x0 +#define BV_ELCDIF_CTRL_CSC_DATA_SWIZZLE__BIG_ENDIAN_SWAP 0x1 +#define BV_ELCDIF_CTRL_CSC_DATA_SWIZZLE__SWAP_ALL_BYTES 0x1 +#define BV_ELCDIF_CTRL_CSC_DATA_SWIZZLE__HWD_SWAP 0x2 +#define BV_ELCDIF_CTRL_CSC_DATA_SWIZZLE__HWD_BYTE_SWAP 0x3 +#define BP_ELCDIF_CTRL_LCD_DATABUS_WIDTH 10 +#define BM_ELCDIF_CTRL_LCD_DATABUS_WIDTH 0x00000C00 +#define BF_ELCDIF_CTRL_LCD_DATABUS_WIDTH(v) \ + (((v) << 10) & BM_ELCDIF_CTRL_LCD_DATABUS_WIDTH) +#define BV_ELCDIF_CTRL_LCD_DATABUS_WIDTH__16_BIT 0x0 +#define BV_ELCDIF_CTRL_LCD_DATABUS_WIDTH__8_BIT 0x1 +#define BV_ELCDIF_CTRL_LCD_DATABUS_WIDTH__18_BIT 0x2 +#define BV_ELCDIF_CTRL_LCD_DATABUS_WIDTH__24_BIT 0x3 +#define BP_ELCDIF_CTRL_WORD_LENGTH 8 +#define BM_ELCDIF_CTRL_WORD_LENGTH 0x00000300 +#define BF_ELCDIF_CTRL_WORD_LENGTH(v) \ + (((v) << 8) & BM_ELCDIF_CTRL_WORD_LENGTH) +#define BV_ELCDIF_CTRL_WORD_LENGTH__16_BIT 0x0 +#define BV_ELCDIF_CTRL_WORD_LENGTH__8_BIT 0x1 +#define BV_ELCDIF_CTRL_WORD_LENGTH__18_BIT 0x2 +#define BV_ELCDIF_CTRL_WORD_LENGTH__24_BIT 0x3 +#define BM_ELCDIF_CTRL_RGB_TO_YCBCR422_CSC 0x00000080 +#define BM_ELCDIF_CTRL_ENABLE_PXP_HANDSHAKE 0x00000040 +#define BM_ELCDIF_CTRL_ELCDIF_MASTER 0x00000020 +#define BM_ELCDIF_CTRL_RSRVD0 0x00000010 +#define BM_ELCDIF_CTRL_DATA_FORMAT_16_BIT 0x00000008 +#define BM_ELCDIF_CTRL_DATA_FORMAT_18_BIT 0x00000004 +#define BV_ELCDIF_CTRL_DATA_FORMAT_18_BIT__LOWER_18_BITS_VALID 0x0 +#define BV_ELCDIF_CTRL_DATA_FORMAT_18_BIT__UPPER_18_BITS_VALID 0x1 +#define BM_ELCDIF_CTRL_DATA_FORMAT_24_BIT 0x00000002 +#define BV_ELCDIF_CTRL_DATA_FORMAT_24_BIT__ALL_24_BITS_VALID 0x0 +#define BV_ELCDIF_CTRL_DATA_FORMAT_24_BIT__DROP_UPPER_2_BITS_PER_BYTE 0x1 +#define BM_ELCDIF_CTRL_RUN 0x00000001 + +#define HW_ELCDIF_CTRL1 (0x00000010) +#define HW_ELCDIF_CTRL1_SET (0x00000014) +#define HW_ELCDIF_CTRL1_CLR (0x00000018) +#define HW_ELCDIF_CTRL1_TOG (0x0000001c) + +#define BP_ELCDIF_CTRL1_RSRVD1 28 +#define BM_ELCDIF_CTRL1_RSRVD1 0xF0000000 +#define BF_ELCDIF_CTRL1_RSRVD1(v) \ + (((v) << 28) & BM_ELCDIF_CTRL1_RSRVD1) +#define BM_ELCDIF_CTRL1_COMBINE_MPU_WR_STRB 0x08000000 +#define BM_ELCDIF_CTRL1_BM_ERROR_IRQ_EN 0x04000000 +#define BM_ELCDIF_CTRL1_BM_ERROR_IRQ 0x02000000 +#define BV_ELCDIF_CTRL1_BM_ERROR_IRQ__NO_REQUEST 0x0 +#define BV_ELCDIF_CTRL1_BM_ERROR_IRQ__REQUEST 0x1 +#define BM_ELCDIF_CTRL1_RECOVER_ON_UNDERFLOW 0x01000000 +#define BM_ELCDIF_CTRL1_INTERLACE_FIELDS 0x00800000 +#define BM_ELCDIF_CTRL1_START_INTERLACE_FROM_SECOND_FIELD 0x00400000 +#define BM_ELCDIF_CTRL1_FIFO_CLEAR 0x00200000 +#define BM_ELCDIF_CTRL1_IRQ_ON_ALTERNATE_FIELDS 0x00100000 +#define BP_ELCDIF_CTRL1_BYTE_PACKING_FORMAT 16 +#define BM_ELCDIF_CTRL1_BYTE_PACKING_FORMAT 0x000F0000 +#define BF_ELCDIF_CTRL1_BYTE_PACKING_FORMAT(v) \ + (((v) << 16) & BM_ELCDIF_CTRL1_BYTE_PACKING_FORMAT) +#define BM_ELCDIF_CTRL1_OVERFLOW_IRQ_EN 0x00008000 +#define BM_ELCDIF_CTRL1_UNDERFLOW_IRQ_EN 0x00004000 +#define BM_ELCDIF_CTRL1_CUR_FRAME_DONE_IRQ_EN 0x00002000 +#define BM_ELCDIF_CTRL1_VSYNC_EDGE_IRQ_EN 0x00001000 +#define BM_ELCDIF_CTRL1_OVERFLOW_IRQ 0x00000800 +#define BV_ELCDIF_CTRL1_OVERFLOW_IRQ__NO_REQUEST 0x0 +#define BV_ELCDIF_CTRL1_OVERFLOW_IRQ__REQUEST 0x1 +#define BM_ELCDIF_CTRL1_UNDERFLOW_IRQ 0x00000400 +#define BV_ELCDIF_CTRL1_UNDERFLOW_IRQ__NO_REQUEST 0x0 +#define BV_ELCDIF_CTRL1_UNDERFLOW_IRQ__REQUEST 0x1 +#define BM_ELCDIF_CTRL1_CUR_FRAME_DONE_IRQ 0x00000200 +#define BV_ELCDIF_CTRL1_CUR_FRAME_DONE_IRQ__NO_REQUEST 0x0 +#define BV_ELCDIF_CTRL1_CUR_FRAME_DONE_IRQ__REQUEST 0x1 +#define BM_ELCDIF_CTRL1_VSYNC_EDGE_IRQ 0x00000100 +#define BV_ELCDIF_CTRL1_VSYNC_EDGE_IRQ__NO_REQUEST 0x0 +#define BV_ELCDIF_CTRL1_VSYNC_EDGE_IRQ__REQUEST 0x1 +#define BP_ELCDIF_CTRL1_RSRVD0 3 +#define BM_ELCDIF_CTRL1_RSRVD0 0x000000F8 +#define BF_ELCDIF_CTRL1_RSRVD0(v) \ + (((v) << 3) & BM_ELCDIF_CTRL1_RSRVD0) +#define BM_ELCDIF_CTRL1_BUSY_ENABLE 0x00000004 +#define BV_ELCDIF_CTRL1_BUSY_ENABLE__BUSY_DISABLED 0x0 +#define BV_ELCDIF_CTRL1_BUSY_ENABLE__BUSY_ENABLED 0x1 +#define BM_ELCDIF_CTRL1_MODE86 0x00000002 +#define BV_ELCDIF_CTRL1_MODE86__8080_MODE 0x0 +#define BV_ELCDIF_CTRL1_MODE86__6800_MODE 0x1 +#define BM_ELCDIF_CTRL1_RESET 0x00000001 +#define BV_ELCDIF_CTRL1_RESET__LCDRESET_LOW 0x0 +#define BV_ELCDIF_CTRL1_RESET__LCDRESET_HIGH 0x1 + +#define HW_ELCDIF_CTRL2 (0x00000020) +#define HW_ELCDIF_CTRL2_SET (0x00000024) +#define HW_ELCDIF_CTRL2_CLR (0x00000028) +#define HW_ELCDIF_CTRL2_TOG (0x0000002c) + +#define BP_ELCDIF_CTRL2_RSRVD5 24 +#define BM_ELCDIF_CTRL2_RSRVD5 0xFF000000 +#define BF_ELCDIF_CTRL2_RSRVD5(v) \ + (((v) << 24) & BM_ELCDIF_CTRL2_RSRVD5) +#define BP_ELCDIF_CTRL2_OUTSTANDING_REQS 21 +#define BM_ELCDIF_CTRL2_OUTSTANDING_REQS 0x00E00000 +#define BF_ELCDIF_CTRL2_OUTSTANDING_REQS(v) \ + (((v) << 21) & BM_ELCDIF_CTRL2_OUTSTANDING_REQS) +#define BV_ELCDIF_CTRL2_OUTSTANDING_REQS__REQ_1 0x0 +#define BV_ELCDIF_CTRL2_OUTSTANDING_REQS__REQ_2 0x1 +#define BV_ELCDIF_CTRL2_OUTSTANDING_REQS__REQ_4 0x2 +#define BV_ELCDIF_CTRL2_OUTSTANDING_REQS__REQ_8 0x3 +#define BV_ELCDIF_CTRL2_OUTSTANDING_REQS__REQ_16 0x4 +#define BM_ELCDIF_CTRL2_BURST_LEN_8 0x00100000 +#define BM_ELCDIF_CTRL2_RSRVD4 0x00080000 +#define BP_ELCDIF_CTRL2_ODD_LINE_PATTERN 16 +#define BM_ELCDIF_CTRL2_ODD_LINE_PATTERN 0x00070000 +#define BF_ELCDIF_CTRL2_ODD_LINE_PATTERN(v) \ + (((v) << 16) & BM_ELCDIF_CTRL2_ODD_LINE_PATTERN) +#define BV_ELCDIF_CTRL2_ODD_LINE_PATTERN__RGB 0x0 +#define BV_ELCDIF_CTRL2_ODD_LINE_PATTERN__RBG 0x1 +#define BV_ELCDIF_CTRL2_ODD_LINE_PATTERN__GBR 0x2 +#define BV_ELCDIF_CTRL2_ODD_LINE_PATTERN__GRB 0x3 +#define BV_ELCDIF_CTRL2_ODD_LINE_PATTERN__BRG 0x4 +#define BV_ELCDIF_CTRL2_ODD_LINE_PATTERN__BGR 0x5 +#define BM_ELCDIF_CTRL2_RSRVD3 0x00008000 +#define BP_ELCDIF_CTRL2_EVEN_LINE_PATTERN 12 +#define BM_ELCDIF_CTRL2_EVEN_LINE_PATTERN 0x00007000 +#define BF_ELCDIF_CTRL2_EVEN_LINE_PATTERN(v) \ + (((v) << 12) & BM_ELCDIF_CTRL2_EVEN_LINE_PATTERN) +#define BV_ELCDIF_CTRL2_EVEN_LINE_PATTERN__RGB 0x0 +#define BV_ELCDIF_CTRL2_EVEN_LINE_PATTERN__RBG 0x1 +#define BV_ELCDIF_CTRL2_EVEN_LINE_PATTERN__GBR 0x2 +#define BV_ELCDIF_CTRL2_EVEN_LINE_PATTERN__GRB 0x3 +#define BV_ELCDIF_CTRL2_EVEN_LINE_PATTERN__BRG 0x4 +#define BV_ELCDIF_CTRL2_EVEN_LINE_PATTERN__BGR 0x5 +#define BM_ELCDIF_CTRL2_RSRVD2 0x00000800 +#define BM_ELCDIF_CTRL2_READ_PACK_DIR 0x00000400 +#define BM_ELCDIF_CTRL2_READ_MODE_OUTPUT_IN_RGB_FORMAT 0x00000200 +#define BM_ELCDIF_CTRL2_READ_MODE_6_BIT_INPUT 0x00000100 +#define BM_ELCDIF_CTRL2_RSRVD1 0x00000080 +#define BP_ELCDIF_CTRL2_READ_MODE_NUM_PACKED_SUBWORDS 4 +#define BM_ELCDIF_CTRL2_READ_MODE_NUM_PACKED_SUBWORDS 0x00000070 +#define BF_ELCDIF_CTRL2_READ_MODE_NUM_PACKED_SUBWORDS(v) \ + (((v) << 4) & BM_ELCDIF_CTRL2_READ_MODE_NUM_PACKED_SUBWORDS) +#define BP_ELCDIF_CTRL2_INITIAL_DUMMY_READ 1 +#define BM_ELCDIF_CTRL2_INITIAL_DUMMY_READ 0x0000000E +#define BF_ELCDIF_CTRL2_INITIAL_DUMMY_READ(v) \ + (((v) << 1) & BM_ELCDIF_CTRL2_INITIAL_DUMMY_READ) +#define BM_ELCDIF_CTRL2_RSRVD0 0x00000001 + +#define HW_ELCDIF_TRANSFER_COUNT (0x00000030) + +#define BP_ELCDIF_TRANSFER_COUNT_V_COUNT 16 +#define BM_ELCDIF_TRANSFER_COUNT_V_COUNT 0xFFFF0000 +#define BF_ELCDIF_TRANSFER_COUNT_V_COUNT(v) \ + (((v) << 16) & BM_ELCDIF_TRANSFER_COUNT_V_COUNT) +#define BP_ELCDIF_TRANSFER_COUNT_H_COUNT 0 +#define BM_ELCDIF_TRANSFER_COUNT_H_COUNT 0x0000FFFF +#define BF_ELCDIF_TRANSFER_COUNT_H_COUNT(v) \ + (((v) << 0) & BM_ELCDIF_TRANSFER_COUNT_H_COUNT) + +#define HW_ELCDIF_CUR_BUF (0x00000040) + +#define BP_ELCDIF_CUR_BUF_ADDR 0 +#define BM_ELCDIF_CUR_BUF_ADDR 0xFFFFFFFF +#define BF_ELCDIF_CUR_BUF_ADDR(v) (v) + +#define HW_ELCDIF_NEXT_BUF (0x00000050) + +#define BP_ELCDIF_NEXT_BUF_ADDR 0 +#define BM_ELCDIF_NEXT_BUF_ADDR 0xFFFFFFFF +#define BF_ELCDIF_NEXT_BUF_ADDR(v) (v) + +#define HW_ELCDIF_TIMING (0x00000060) + +#define BP_ELCDIF_TIMING_CMD_HOLD 24 +#define BM_ELCDIF_TIMING_CMD_HOLD 0xFF000000 +#define BF_ELCDIF_TIMING_CMD_HOLD(v) \ + (((v) << 24) & BM_ELCDIF_TIMING_CMD_HOLD) +#define BP_ELCDIF_TIMING_CMD_SETUP 16 +#define BM_ELCDIF_TIMING_CMD_SETUP 0x00FF0000 +#define BF_ELCDIF_TIMING_CMD_SETUP(v) \ + (((v) << 16) & BM_ELCDIF_TIMING_CMD_SETUP) +#define BP_ELCDIF_TIMING_DATA_HOLD 8 +#define BM_ELCDIF_TIMING_DATA_HOLD 0x0000FF00 +#define BF_ELCDIF_TIMING_DATA_HOLD(v) \ + (((v) << 8) & BM_ELCDIF_TIMING_DATA_HOLD) +#define BP_ELCDIF_TIMING_DATA_SETUP 0 +#define BM_ELCDIF_TIMING_DATA_SETUP 0x000000FF +#define BF_ELCDIF_TIMING_DATA_SETUP(v) \ + (((v) << 0) & BM_ELCDIF_TIMING_DATA_SETUP) + +#define HW_ELCDIF_VDCTRL0 (0x00000070) +#define HW_ELCDIF_VDCTRL0_SET (0x00000074) +#define HW_ELCDIF_VDCTRL0_CLR (0x00000078) +#define HW_ELCDIF_VDCTRL0_TOG (0x0000007c) + +#define BP_ELCDIF_VDCTRL0_RSRVD2 30 +#define BM_ELCDIF_VDCTRL0_RSRVD2 0xC0000000 +#define BF_ELCDIF_VDCTRL0_RSRVD2(v) \ + (((v) << 30) & BM_ELCDIF_VDCTRL0_RSRVD2) +#define BM_ELCDIF_VDCTRL0_VSYNC_OEB 0x20000000 +#define BV_ELCDIF_VDCTRL0_VSYNC_OEB__VSYNC_OUTPUT 0x0 +#define BV_ELCDIF_VDCTRL0_VSYNC_OEB__VSYNC_INPUT 0x1 +#define BM_ELCDIF_VDCTRL0_ENABLE_PRESENT 0x10000000 +#define BM_ELCDIF_VDCTRL0_VSYNC_POL 0x08000000 +#define BM_ELCDIF_VDCTRL0_HSYNC_POL 0x04000000 +#define BM_ELCDIF_VDCTRL0_DOTCLK_POL 0x02000000 +#define BM_ELCDIF_VDCTRL0_ENABLE_POL 0x01000000 +#define BP_ELCDIF_VDCTRL0_RSRVD1 22 +#define BM_ELCDIF_VDCTRL0_RSRVD1 0x00C00000 +#define BF_ELCDIF_VDCTRL0_RSRVD1(v) \ + (((v) << 22) & BM_ELCDIF_VDCTRL0_RSRVD1) +#define BM_ELCDIF_VDCTRL0_VSYNC_PERIOD_UNIT 0x00200000 +#define BM_ELCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT 0x00100000 +#define BM_ELCDIF_VDCTRL0_HALF_LINE 0x00080000 +#define BM_ELCDIF_VDCTRL0_HALF_LINE_MODE 0x00040000 +#define BP_ELCDIF_VDCTRL0_VSYNC_PULSE_WIDTH 0 +#define BM_ELCDIF_VDCTRL0_VSYNC_PULSE_WIDTH 0x0003FFFF +#define BF_ELCDIF_VDCTRL0_VSYNC_PULSE_WIDTH(v) \ + (((v) << 0) & BM_ELCDIF_VDCTRL0_VSYNC_PULSE_WIDTH) + +#define HW_ELCDIF_VDCTRL1 (0x00000080) + +#define BP_ELCDIF_VDCTRL1_VSYNC_PERIOD 0 +#define BM_ELCDIF_VDCTRL1_VSYNC_PERIOD 0xFFFFFFFF +#define BF_ELCDIF_VDCTRL1_VSYNC_PERIOD(v) (v) + +#define HW_ELCDIF_VDCTRL2 (0x00000090) + +#define BP_ELCDIF_VDCTRL2_HSYNC_PULSE_WIDTH 18 +#define BM_ELCDIF_VDCTRL2_HSYNC_PULSE_WIDTH 0xFFFC0000 +#define BF_ELCDIF_VDCTRL2_HSYNC_PULSE_WIDTH(v) \ + (((v) << 18) & BM_ELCDIF_VDCTRL2_HSYNC_PULSE_WIDTH) +#define BP_ELCDIF_VDCTRL2_HSYNC_PERIOD 0 +#define BM_ELCDIF_VDCTRL2_HSYNC_PERIOD 0x0003FFFF +#define BF_ELCDIF_VDCTRL2_HSYNC_PERIOD(v) \ + (((v) << 0) & BM_ELCDIF_VDCTRL2_HSYNC_PERIOD) + +#define HW_ELCDIF_VDCTRL3 (0x000000a0) + +#define BP_ELCDIF_VDCTRL3_RSRVD0 30 +#define BM_ELCDIF_VDCTRL3_RSRVD0 0xC0000000 +#define BF_ELCDIF_VDCTRL3_RSRVD0(v) \ + (((v) << 30) & BM_ELCDIF_VDCTRL3_RSRVD0) +#define BM_ELCDIF_VDCTRL3_MUX_SYNC_SIGNALS 0x20000000 +#define BM_ELCDIF_VDCTRL3_VSYNC_ONLY 0x10000000 +#define BP_ELCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT 16 +#define BM_ELCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT 0x0FFF0000 +#define BF_ELCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT(v) \ + (((v) << 16) & BM_ELCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT) +#define BP_ELCDIF_VDCTRL3_VERTICAL_WAIT_CNT 0 +#define BM_ELCDIF_VDCTRL3_VERTICAL_WAIT_CNT 0x0000FFFF +#define BF_ELCDIF_VDCTRL3_VERTICAL_WAIT_CNT(v) \ + (((v) << 0) & BM_ELCDIF_VDCTRL3_VERTICAL_WAIT_CNT) + +#define HW_ELCDIF_VDCTRL4 (0x000000b0) + +#define BP_ELCDIF_VDCTRL4_DOTCLK_DLY_SEL 29 +#define BM_ELCDIF_VDCTRL4_DOTCLK_DLY_SEL 0xE0000000 +#define BF_ELCDIF_VDCTRL4_DOTCLK_DLY_SEL(v) \ + (((v) << 29) & BM_ELCDIF_VDCTRL4_DOTCLK_DLY_SEL) +#define BP_ELCDIF_VDCTRL4_RSRVD0 19 +#define BM_ELCDIF_VDCTRL4_RSRVD0 0x1FF80000 +#define BF_ELCDIF_VDCTRL4_RSRVD0(v) \ + (((v) << 19) & BM_ELCDIF_VDCTRL4_RSRVD0) +#define BM_ELCDIF_VDCTRL4_SYNC_SIGNALS_ON 0x00040000 +#define BP_ELCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT 0 +#define BM_ELCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT 0x0003FFFF +#define BF_ELCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT(v) \ + (((v) << 0) & BM_ELCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT) + +#define HW_ELCDIF_DVICTRL0 (0x000000c0) + +#define BP_ELCDIF_DVICTRL0_RSRVD1 28 +#define BM_ELCDIF_DVICTRL0_RSRVD1 0xF0000000 +#define BF_ELCDIF_DVICTRL0_RSRVD1(v) \ + (((v) << 28) & BM_ELCDIF_DVICTRL0_RSRVD1) +#define BP_ELCDIF_DVICTRL0_H_ACTIVE_CNT 16 +#define BM_ELCDIF_DVICTRL0_H_ACTIVE_CNT 0x0FFF0000 +#define BF_ELCDIF_DVICTRL0_H_ACTIVE_CNT(v) \ + (((v) << 16) & BM_ELCDIF_DVICTRL0_H_ACTIVE_CNT) +#define BP_ELCDIF_DVICTRL0_RSRVD0 12 +#define BM_ELCDIF_DVICTRL0_RSRVD0 0x0000F000 +#define BF_ELCDIF_DVICTRL0_RSRVD0(v) \ + (((v) << 12) & BM_ELCDIF_DVICTRL0_RSRVD0) +#define BP_ELCDIF_DVICTRL0_H_BLANKING_CNT 0 +#define BM_ELCDIF_DVICTRL0_H_BLANKING_CNT 0x00000FFF +#define BF_ELCDIF_DVICTRL0_H_BLANKING_CNT(v) \ + (((v) << 0) & BM_ELCDIF_DVICTRL0_H_BLANKING_CNT) + +#define HW_ELCDIF_DVICTRL1 (0x000000d0) + +#define BP_ELCDIF_DVICTRL1_RSRVD0 30 +#define BM_ELCDIF_DVICTRL1_RSRVD0 0xC0000000 +#define BF_ELCDIF_DVICTRL1_RSRVD0(v) \ + (((v) << 30) & BM_ELCDIF_DVICTRL1_RSRVD0) +#define BP_ELCDIF_DVICTRL1_F1_START_LINE 20 +#define BM_ELCDIF_DVICTRL1_F1_START_LINE 0x3FF00000 +#define BF_ELCDIF_DVICTRL1_F1_START_LINE(v) \ + (((v) << 20) & BM_ELCDIF_DVICTRL1_F1_START_LINE) +#define BP_ELCDIF_DVICTRL1_F1_END_LINE 10 +#define BM_ELCDIF_DVICTRL1_F1_END_LINE 0x000FFC00 +#define BF_ELCDIF_DVICTRL1_F1_END_LINE(v) \ + (((v) << 10) & BM_ELCDIF_DVICTRL1_F1_END_LINE) +#define BP_ELCDIF_DVICTRL1_F2_START_LINE 0 +#define BM_ELCDIF_DVICTRL1_F2_START_LINE 0x000003FF +#define BF_ELCDIF_DVICTRL1_F2_START_LINE(v) \ + (((v) << 0) & BM_ELCDIF_DVICTRL1_F2_START_LINE) + +#define HW_ELCDIF_DVICTRL2 (0x000000e0) + +#define BP_ELCDIF_DVICTRL2_RSRVD0 30 +#define BM_ELCDIF_DVICTRL2_RSRVD0 0xC0000000 +#define BF_ELCDIF_DVICTRL2_RSRVD0(v) \ + (((v) << 30) & BM_ELCDIF_DVICTRL2_RSRVD0) +#define BP_ELCDIF_DVICTRL2_F2_END_LINE 20 +#define BM_ELCDIF_DVICTRL2_F2_END_LINE 0x3FF00000 +#define BF_ELCDIF_DVICTRL2_F2_END_LINE(v) \ + (((v) << 20) & BM_ELCDIF_DVICTRL2_F2_END_LINE) +#define BP_ELCDIF_DVICTRL2_V1_BLANK_START_LINE 10 +#define BM_ELCDIF_DVICTRL2_V1_BLANK_START_LINE 0x000FFC00 +#define BF_ELCDIF_DVICTRL2_V1_BLANK_START_LINE(v) \ + (((v) << 10) & BM_ELCDIF_DVICTRL2_V1_BLANK_START_LINE) +#define BP_ELCDIF_DVICTRL2_V1_BLANK_END_LINE 0 +#define BM_ELCDIF_DVICTRL2_V1_BLANK_END_LINE 0x000003FF +#define BF_ELCDIF_DVICTRL2_V1_BLANK_END_LINE(v) \ + (((v) << 0) & BM_ELCDIF_DVICTRL2_V1_BLANK_END_LINE) + +#define HW_ELCDIF_DVICTRL3 (0x000000f0) + +#define BP_ELCDIF_DVICTRL3_RSRVD0 30 +#define BM_ELCDIF_DVICTRL3_RSRVD0 0xC0000000 +#define BF_ELCDIF_DVICTRL3_RSRVD0(v) \ + (((v) << 30) & BM_ELCDIF_DVICTRL3_RSRVD0) +#define BP_ELCDIF_DVICTRL3_V2_BLANK_START_LINE 20 +#define BM_ELCDIF_DVICTRL3_V2_BLANK_START_LINE 0x3FF00000 +#define BF_ELCDIF_DVICTRL3_V2_BLANK_START_LINE(v) \ + (((v) << 20) & BM_ELCDIF_DVICTRL3_V2_BLANK_START_LINE) +#define BP_ELCDIF_DVICTRL3_V2_BLANK_END_LINE 10 +#define BM_ELCDIF_DVICTRL3_V2_BLANK_END_LINE 0x000FFC00 +#define BF_ELCDIF_DVICTRL3_V2_BLANK_END_LINE(v) \ + (((v) << 10) & BM_ELCDIF_DVICTRL3_V2_BLANK_END_LINE) +#define BP_ELCDIF_DVICTRL3_V_LINES_CNT 0 +#define BM_ELCDIF_DVICTRL3_V_LINES_CNT 0x000003FF +#define BF_ELCDIF_DVICTRL3_V_LINES_CNT(v) \ + (((v) << 0) & BM_ELCDIF_DVICTRL3_V_LINES_CNT) + +#define HW_ELCDIF_DVICTRL4 (0x00000100) + +#define BP_ELCDIF_DVICTRL4_Y_FILL_VALUE 24 +#define BM_ELCDIF_DVICTRL4_Y_FILL_VALUE 0xFF000000 +#define BF_ELCDIF_DVICTRL4_Y_FILL_VALUE(v) \ + (((v) << 24) & BM_ELCDIF_DVICTRL4_Y_FILL_VALUE) +#define BP_ELCDIF_DVICTRL4_CB_FILL_VALUE 16 +#define BM_ELCDIF_DVICTRL4_CB_FILL_VALUE 0x00FF0000 +#define BF_ELCDIF_DVICTRL4_CB_FILL_VALUE(v) \ + (((v) << 16) & BM_ELCDIF_DVICTRL4_CB_FILL_VALUE) +#define BP_ELCDIF_DVICTRL4_CR_FILL_VALUE 8 +#define BM_ELCDIF_DVICTRL4_CR_FILL_VALUE 0x0000FF00 +#define BF_ELCDIF_DVICTRL4_CR_FILL_VALUE(v) \ + (((v) << 8) & BM_ELCDIF_DVICTRL4_CR_FILL_VALUE) +#define BP_ELCDIF_DVICTRL4_H_FILL_CNT 0 +#define BM_ELCDIF_DVICTRL4_H_FILL_CNT 0x000000FF +#define BF_ELCDIF_DVICTRL4_H_FILL_CNT(v) \ + (((v) << 0) & BM_ELCDIF_DVICTRL4_H_FILL_CNT) + +#define HW_ELCDIF_CSC_COEFF0 (0x00000110) + +#define BP_ELCDIF_CSC_COEFF0_RSRVD1 26 +#define BM_ELCDIF_CSC_COEFF0_RSRVD1 0xFC000000 +#define BF_ELCDIF_CSC_COEFF0_RSRVD1(v) \ + (((v) << 26) & BM_ELCDIF_CSC_COEFF0_RSRVD1) +#define BP_ELCDIF_CSC_COEFF0_C0 16 +#define BM_ELCDIF_CSC_COEFF0_C0 0x03FF0000 +#define BF_ELCDIF_CSC_COEFF0_C0(v) \ + (((v) << 16) & BM_ELCDIF_CSC_COEFF0_C0) +#define BP_ELCDIF_CSC_COEFF0_RSRVD0 2 +#define BM_ELCDIF_CSC_COEFF0_RSRVD0 0x0000FFFC +#define BF_ELCDIF_CSC_COEFF0_RSRVD0(v) \ + (((v) << 2) & BM_ELCDIF_CSC_COEFF0_RSRVD0) +#define BP_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER 0 +#define BM_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER 0x00000003 +#define BF_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER(v) \ + (((v) << 0) & BM_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER) +#define BV_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER__SAMPLE_AND_HOLD 0x0 +#define BV_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER__RSRVD 0x1 +#define BV_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER__INTERSTITIAL 0x2 +#define BV_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER__COSITED 0x3 + +#define HW_ELCDIF_CSC_COEFF1 (0x00000120) + +#define BP_ELCDIF_CSC_COEFF1_RSRVD1 26 +#define BM_ELCDIF_CSC_COEFF1_RSRVD1 0xFC000000 +#define BF_ELCDIF_CSC_COEFF1_RSRVD1(v) \ + (((v) << 26) & BM_ELCDIF_CSC_COEFF1_RSRVD1) +#define BP_ELCDIF_CSC_COEFF1_C2 16 +#define BM_ELCDIF_CSC_COEFF1_C2 0x03FF0000 +#define BF_ELCDIF_CSC_COEFF1_C2(v) \ + (((v) << 16) & BM_ELCDIF_CSC_COEFF1_C2) +#define BP_ELCDIF_CSC_COEFF1_RSRVD0 10 +#define BM_ELCDIF_CSC_COEFF1_RSRVD0 0x0000FC00 +#define BF_ELCDIF_CSC_COEFF1_RSRVD0(v) \ + (((v) << 10) & BM_ELCDIF_CSC_COEFF1_RSRVD0) +#define BP_ELCDIF_CSC_COEFF1_C1 0 +#define BM_ELCDIF_CSC_COEFF1_C1 0x000003FF +#define BF_ELCDIF_CSC_COEFF1_C1(v) \ + (((v) << 0) & BM_ELCDIF_CSC_COEFF1_C1) + +#define HW_ELCDIF_CSC_COEFF2 (0x00000130) + +#define BP_ELCDIF_CSC_COEFF2_RSRVD1 26 +#define BM_ELCDIF_CSC_COEFF2_RSRVD1 0xFC000000 +#define BF_ELCDIF_CSC_COEFF2_RSRVD1(v) \ + (((v) << 26) & BM_ELCDIF_CSC_COEFF2_RSRVD1) +#define BP_ELCDIF_CSC_COEFF2_C4 16 +#define BM_ELCDIF_CSC_COEFF2_C4 0x03FF0000 +#define BF_ELCDIF_CSC_COEFF2_C4(v) \ + (((v) << 16) & BM_ELCDIF_CSC_COEFF2_C4) +#define BP_ELCDIF_CSC_COEFF2_RSRVD0 10 +#define BM_ELCDIF_CSC_COEFF2_RSRVD0 0x0000FC00 +#define BF_ELCDIF_CSC_COEFF2_RSRVD0(v) \ + (((v) << 10) & BM_ELCDIF_CSC_COEFF2_RSRVD0) +#define BP_ELCDIF_CSC_COEFF2_C3 0 +#define BM_ELCDIF_CSC_COEFF2_C3 0x000003FF +#define BF_ELCDIF_CSC_COEFF2_C3(v) \ + (((v) << 0) & BM_ELCDIF_CSC_COEFF2_C3) + +#define HW_ELCDIF_CSC_COEFF3 (0x00000140) + +#define BP_ELCDIF_CSC_COEFF3_RSRVD1 26 +#define BM_ELCDIF_CSC_COEFF3_RSRVD1 0xFC000000 +#define BF_ELCDIF_CSC_COEFF3_RSRVD1(v) \ + (((v) << 26) & BM_ELCDIF_CSC_COEFF3_RSRVD1) +#define BP_ELCDIF_CSC_COEFF3_C6 16 +#define BM_ELCDIF_CSC_COEFF3_C6 0x03FF0000 +#define BF_ELCDIF_CSC_COEFF3_C6(v) \ + (((v) << 16) & BM_ELCDIF_CSC_COEFF3_C6) +#define BP_ELCDIF_CSC_COEFF3_RSRVD0 10 +#define BM_ELCDIF_CSC_COEFF3_RSRVD0 0x0000FC00 +#define BF_ELCDIF_CSC_COEFF3_RSRVD0(v) \ + (((v) << 10) & BM_ELCDIF_CSC_COEFF3_RSRVD0) +#define BP_ELCDIF_CSC_COEFF3_C5 0 +#define BM_ELCDIF_CSC_COEFF3_C5 0x000003FF +#define BF_ELCDIF_CSC_COEFF3_C5(v) \ + (((v) << 0) & BM_ELCDIF_CSC_COEFF3_C5) + +#define HW_ELCDIF_CSC_COEFF4 (0x00000150) + +#define BP_ELCDIF_CSC_COEFF4_RSRVD1 26 +#define BM_ELCDIF_CSC_COEFF4_RSRVD1 0xFC000000 +#define BF_ELCDIF_CSC_COEFF4_RSRVD1(v) \ + (((v) << 26) & BM_ELCDIF_CSC_COEFF4_RSRVD1) +#define BP_ELCDIF_CSC_COEFF4_C8 16 +#define BM_ELCDIF_CSC_COEFF4_C8 0x03FF0000 +#define BF_ELCDIF_CSC_COEFF4_C8(v) \ + (((v) << 16) & BM_ELCDIF_CSC_COEFF4_C8) +#define BP_ELCDIF_CSC_COEFF4_RSRVD0 10 +#define BM_ELCDIF_CSC_COEFF4_RSRVD0 0x0000FC00 +#define BF_ELCDIF_CSC_COEFF4_RSRVD0(v) \ + (((v) << 10) & BM_ELCDIF_CSC_COEFF4_RSRVD0) +#define BP_ELCDIF_CSC_COEFF4_C7 0 +#define BM_ELCDIF_CSC_COEFF4_C7 0x000003FF +#define BF_ELCDIF_CSC_COEFF4_C7(v) \ + (((v) << 0) & BM_ELCDIF_CSC_COEFF4_C7) + +#define HW_ELCDIF_CSC_OFFSET (0x00000160) + +#define BP_ELCDIF_CSC_OFFSET_RSRVD1 25 +#define BM_ELCDIF_CSC_OFFSET_RSRVD1 0xFE000000 +#define BF_ELCDIF_CSC_OFFSET_RSRVD1(v) \ + (((v) << 25) & BM_ELCDIF_CSC_OFFSET_RSRVD1) +#define BP_ELCDIF_CSC_OFFSET_CBCR_OFFSET 16 +#define BM_ELCDIF_CSC_OFFSET_CBCR_OFFSET 0x01FF0000 +#define BF_ELCDIF_CSC_OFFSET_CBCR_OFFSET(v) \ + (((v) << 16) & BM_ELCDIF_CSC_OFFSET_CBCR_OFFSET) +#define BP_ELCDIF_CSC_OFFSET_RSRVD0 9 +#define BM_ELCDIF_CSC_OFFSET_RSRVD0 0x0000FE00 +#define BF_ELCDIF_CSC_OFFSET_RSRVD0(v) \ + (((v) << 9) & BM_ELCDIF_CSC_OFFSET_RSRVD0) +#define BP_ELCDIF_CSC_OFFSET_Y_OFFSET 0 +#define BM_ELCDIF_CSC_OFFSET_Y_OFFSET 0x000001FF +#define BF_ELCDIF_CSC_OFFSET_Y_OFFSET(v) \ + (((v) << 0) & BM_ELCDIF_CSC_OFFSET_Y_OFFSET) + +#define HW_ELCDIF_CSC_LIMIT (0x00000170) + +#define BP_ELCDIF_CSC_LIMIT_CBCR_MIN 24 +#define BM_ELCDIF_CSC_LIMIT_CBCR_MIN 0xFF000000 +#define BF_ELCDIF_CSC_LIMIT_CBCR_MIN(v) \ + (((v) << 24) & BM_ELCDIF_CSC_LIMIT_CBCR_MIN) +#define BP_ELCDIF_CSC_LIMIT_CBCR_MAX 16 +#define BM_ELCDIF_CSC_LIMIT_CBCR_MAX 0x00FF0000 +#define BF_ELCDIF_CSC_LIMIT_CBCR_MAX(v) \ + (((v) << 16) & BM_ELCDIF_CSC_LIMIT_CBCR_MAX) +#define BP_ELCDIF_CSC_LIMIT_Y_MIN 8 +#define BM_ELCDIF_CSC_LIMIT_Y_MIN 0x0000FF00 +#define BF_ELCDIF_CSC_LIMIT_Y_MIN(v) \ + (((v) << 8) & BM_ELCDIF_CSC_LIMIT_Y_MIN) +#define BP_ELCDIF_CSC_LIMIT_Y_MAX 0 +#define BM_ELCDIF_CSC_LIMIT_Y_MAX 0x000000FF +#define BF_ELCDIF_CSC_LIMIT_Y_MAX(v) \ + (((v) << 0) & BM_ELCDIF_CSC_LIMIT_Y_MAX) + +#define HW_ELCDIF_DATA (0x00000180) + +#define BP_ELCDIF_DATA_DATA_THREE 24 +#define BM_ELCDIF_DATA_DATA_THREE 0xFF000000 +#define BF_ELCDIF_DATA_DATA_THREE(v) \ + (((v) << 24) & BM_ELCDIF_DATA_DATA_THREE) +#define BP_ELCDIF_DATA_DATA_TWO 16 +#define BM_ELCDIF_DATA_DATA_TWO 0x00FF0000 +#define BF_ELCDIF_DATA_DATA_TWO(v) \ + (((v) << 16) & BM_ELCDIF_DATA_DATA_TWO) +#define BP_ELCDIF_DATA_DATA_ONE 8 +#define BM_ELCDIF_DATA_DATA_ONE 0x0000FF00 +#define BF_ELCDIF_DATA_DATA_ONE(v) \ + (((v) << 8) & BM_ELCDIF_DATA_DATA_ONE) +#define BP_ELCDIF_DATA_DATA_ZERO 0 +#define BM_ELCDIF_DATA_DATA_ZERO 0x000000FF +#define BF_ELCDIF_DATA_DATA_ZERO(v) \ + (((v) << 0) & BM_ELCDIF_DATA_DATA_ZERO) + +#define HW_ELCDIF_BM_ERROR_STAT (0x00000190) + +#define BP_ELCDIF_BM_ERROR_STAT_ADDR 0 +#define BM_ELCDIF_BM_ERROR_STAT_ADDR 0xFFFFFFFF +#define BF_ELCDIF_BM_ERROR_STAT_ADDR(v) (v) + +#define HW_ELCDIF_CRC_STAT (0x000001a0) + +#define BP_ELCDIF_CRC_STAT_CRC_VALUE 0 +#define BM_ELCDIF_CRC_STAT_CRC_VALUE 0xFFFFFFFF +#define BF_ELCDIF_CRC_STAT_CRC_VALUE(v) (v) + +#define HW_ELCDIF_STAT (0x000001b0) + +#define BM_ELCDIF_STAT_PRESENT 0x80000000 +#define BM_ELCDIF_STAT_DMA_REQ 0x40000000 +#define BM_ELCDIF_STAT_LFIFO_FULL 0x20000000 +#define BM_ELCDIF_STAT_LFIFO_EMPTY 0x10000000 +#define BM_ELCDIF_STAT_TXFIFO_FULL 0x08000000 +#define BM_ELCDIF_STAT_TXFIFO_EMPTY 0x04000000 +#define BM_ELCDIF_STAT_BUSY 0x02000000 +#define BM_ELCDIF_STAT_DVI_CURRENT_FIELD 0x01000000 +#define BP_ELCDIF_STAT_RSRVD0 9 +#define BM_ELCDIF_STAT_RSRVD0 0x00FFFE00 +#define BF_ELCDIF_STAT_RSRVD0(v) \ + (((v) << 9) & BM_ELCDIF_STAT_RSRVD0) +#define BP_ELCDIF_STAT_LFIFO_COUNT 0 +#define BM_ELCDIF_STAT_LFIFO_COUNT 0x000001FF +#define BF_ELCDIF_STAT_LFIFO_COUNT(v) \ + (((v) << 0) & BM_ELCDIF_STAT_LFIFO_COUNT) + +#define HW_ELCDIF_VERSION (0x000001c0) + +#define BP_ELCDIF_VERSION_MAJOR 24 +#define BM_ELCDIF_VERSION_MAJOR 0xFF000000 +#define BF_ELCDIF_VERSION_MAJOR(v) \ + (((v) << 24) & BM_ELCDIF_VERSION_MAJOR) +#define BP_ELCDIF_VERSION_MINOR 16 +#define BM_ELCDIF_VERSION_MINOR 0x00FF0000 +#define BF_ELCDIF_VERSION_MINOR(v) \ + (((v) << 16) & BM_ELCDIF_VERSION_MINOR) +#define BP_ELCDIF_VERSION_STEP 0 +#define BM_ELCDIF_VERSION_STEP 0x0000FFFF +#define BF_ELCDIF_VERSION_STEP(v) \ + (((v) << 0) & BM_ELCDIF_VERSION_STEP) + +#define HW_ELCDIF_DEBUG0 (0x000001d0) + +#define BM_ELCDIF_DEBUG0_STREAMING_END_DETECTED 0x80000000 +#define BM_ELCDIF_DEBUG0_WAIT_FOR_VSYNC_EDGE_OUT 0x40000000 +#define BM_ELCDIF_DEBUG0_SYNC_SIGNALS_ON_REG 0x20000000 +#define BM_ELCDIF_DEBUG0_DMACMDKICK 0x10000000 +#define BM_ELCDIF_DEBUG0_ENABLE 0x08000000 +#define BM_ELCDIF_DEBUG0_HSYNC 0x04000000 +#define BM_ELCDIF_DEBUG0_VSYNC 0x02000000 +#define BM_ELCDIF_DEBUG0_CUR_FRAME_TX 0x01000000 +#define BM_ELCDIF_DEBUG0_EMPTY_WORD 0x00800000 +#define BP_ELCDIF_DEBUG0_CUR_STATE 16 +#define BM_ELCDIF_DEBUG0_CUR_STATE 0x007F0000 +#define BF_ELCDIF_DEBUG0_CUR_STATE(v) \ + (((v) << 16) & BM_ELCDIF_DEBUG0_CUR_STATE) +#define BM_ELCDIF_DEBUG0_PXP_ELCDIF_B0_READY 0x00008000 +#define BM_ELCDIF_DEBUG0_ELCDIF_PXP_B0_DONE 0x00004000 +#define BM_ELCDIF_DEBUG0_PXP_ELCDIF_B1_READY 0x00002000 +#define BM_ELCDIF_DEBUG0_ELCDIF_PXP_B1_DONE 0x00001000 +#define BP_ELCDIF_DEBUG0_CUR_REQ_STATE 10 +#define BM_ELCDIF_DEBUG0_CUR_REQ_STATE 0x00000C00 +#define BF_ELCDIF_DEBUG0_CUR_REQ_STATE(v) \ + (((v) << 10) & BM_ELCDIF_DEBUG0_CUR_REQ_STATE) +#define BM_ELCDIF_DEBUG0_MST_AVALID 0x00000200 +#define BP_ELCDIF_DEBUG0_MST_OUTSTANDING_REQS 4 +#define BM_ELCDIF_DEBUG0_MST_OUTSTANDING_REQS 0x000001F0 +#define BF_ELCDIF_DEBUG0_MST_OUTSTANDING_REQS(v) \ + (((v) << 4) & BM_ELCDIF_DEBUG0_MST_OUTSTANDING_REQS) +#define BP_ELCDIF_DEBUG0_MST_WORDS 0 +#define BM_ELCDIF_DEBUG0_MST_WORDS 0x0000000F +#define BF_ELCDIF_DEBUG0_MST_WORDS(v) \ + (((v) << 0) & BM_ELCDIF_DEBUG0_MST_WORDS) + +#define HW_ELCDIF_DEBUG1 (0x000001e0) + +#define BP_ELCDIF_DEBUG1_H_DATA_COUNT 16 +#define BM_ELCDIF_DEBUG1_H_DATA_COUNT 0xFFFF0000 +#define BF_ELCDIF_DEBUG1_H_DATA_COUNT(v) \ + (((v) << 16) & BM_ELCDIF_DEBUG1_H_DATA_COUNT) +#define BP_ELCDIF_DEBUG1_V_DATA_COUNT 0 +#define BM_ELCDIF_DEBUG1_V_DATA_COUNT 0x0000FFFF +#define BF_ELCDIF_DEBUG1_V_DATA_COUNT(v) \ + (((v) << 0) & BM_ELCDIF_DEBUG1_V_DATA_COUNT) + +#define HW_ELCDIF_DEBUG2 (0x000001f0) + +#define BP_ELCDIF_DEBUG2_MST_ADDRESS 0 +#define BM_ELCDIF_DEBUG2_MST_ADDRESS 0xFFFFFFFF +#define BF_ELCDIF_DEBUG2_MST_ADDRESS(v) (v) +#endif /* __ELCDIF_REGS_INCLUDED_ */ diff --git a/drivers/video/mxc/mxc_elcdif_fb.c b/drivers/video/mxc/mxc_elcdif_fb.c new file mode 100644 index 000000000000..44587d28c7f9 --- /dev/null +++ b/drivers/video/mxc/mxc_elcdif_fb.c @@ -0,0 +1,1438 @@ +/* + * Copyright (C) 2010 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. + */ +/* + * Based on drivers/video/mxc/mxc_ipuv3_fb.c, drivers/video/mxs/lcdif.c + * and arch/arm/mach-mx28/include/mach/lcdif.h. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/mxcfb.h> +#include <linux/uaccess.h> + +#include <mach/hardware.h> + +#include "elcdif_regs.h" + +/* ELCDIF Pixel format definitions */ +/* Four-character-code (FOURCC) */ +#define fourcc(a, b, c, d) \ + (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) + +/* + * ELCDIF RGB Formats + */ +#define ELCDIF_PIX_FMT_RGB332 fourcc('R', 'G', 'B', '1') +#define ELCDIF_PIX_FMT_RGB555 fourcc('R', 'G', 'B', 'O') +#define ELCDIF_PIX_FMT_RGB565 fourcc('R', 'G', 'B', 'P') +#define ELCDIF_PIX_FMT_RGB666 fourcc('R', 'G', 'B', '6') +#define ELCDIF_PIX_FMT_BGR666 fourcc('B', 'G', 'R', '6') +#define ELCDIF_PIX_FMT_BGR24 fourcc('B', 'G', 'R', '3') +#define ELCDIF_PIX_FMT_RGB24 fourcc('R', 'G', 'B', '3') +#define ELCDIF_PIX_FMT_BGR32 fourcc('B', 'G', 'R', '4') +#define ELCDIF_PIX_FMT_BGRA32 fourcc('B', 'G', 'R', 'A') +#define ELCDIF_PIX_FMT_RGB32 fourcc('R', 'G', 'B', '4') +#define ELCDIF_PIX_FMT_RGBA32 fourcc('R', 'G', 'B', 'A') +#define ELCDIF_PIX_FMT_ABGR32 fourcc('A', 'B', 'G', 'R') + +struct mxc_elcdif_fb_data { + int is_blank; + int output_pix_fmt; + int elcdif_mode; + ssize_t mem_size; + ssize_t map_size; + dma_addr_t phys_start; + dma_addr_t cur_phys; + int dma_irq; + int err_irq; + void *virt_start; + struct completion vsync_complete; + struct semaphore flip_sem; + u32 pseudo_palette[16]; +}; + +struct elcdif_signal_cfg { + unsigned clk_pol:1; /* true = falling edge */ + unsigned enable_pol:1; /* true = active high */ + unsigned Hsync_pol:1; /* true = active high */ + unsigned Vsync_pol:1; /* true = active high */ +}; + +static int mxc_elcdif_fb_blank(int blank, struct fb_info *info); +static int mxc_elcdif_fb_map_video_memory(struct fb_info *info); +static int mxc_elcdif_fb_unmap_video_memory(struct fb_info *info); +static char *fb_mode; +static unsigned long default_bpp = 16; +static void __iomem *elcdif_base; +static struct device *g_elcdif_dev; +static bool g_elcdif_axi_clk_enable; +static bool g_elcdif_pix_clk_enable; +static struct clk *g_elcdif_axi_clk; +static struct clk *g_elcdif_pix_clk; + +static inline void setup_dotclk_panel(u32 pixel_clk, + u16 v_pulse_width, + u16 v_period, + u16 v_wait_cnt, + u16 v_active, + u16 h_pulse_width, + u16 h_period, + u16 h_wait_cnt, + u16 h_active, + int in_pixel_format, + int out_pixel_format, + struct elcdif_signal_cfg sig_cfg, + int enable_present) +{ + u32 val, rounded_pixel_clk; + + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + dev_dbg(g_elcdif_dev, "pixel clk = %d\n", pixel_clk); + rounded_pixel_clk = clk_round_rate(g_elcdif_pix_clk, pixel_clk); + clk_set_rate(g_elcdif_pix_clk, rounded_pixel_clk); + + __raw_writel(BM_ELCDIF_CTRL_DATA_SHIFT_DIR, + elcdif_base + HW_ELCDIF_CTRL_CLR); + + __raw_writel(BM_ELCDIF_CTRL_SHIFT_NUM_BITS, + elcdif_base + HW_ELCDIF_CTRL_CLR); + + __raw_writel(BF_ELCDIF_CTRL2_OUTSTANDING_REQS + (BV_ELCDIF_CTRL2_OUTSTANDING_REQS__REQ_8), + elcdif_base + HW_ELCDIF_CTRL2_SET); + + /* Recover on underflow */ + __raw_writel(BM_ELCDIF_CTRL1_RECOVER_ON_UNDERFLOW, + elcdif_base + HW_ELCDIF_CTRL1_SET); + + /* Configure the input pixel format */ + __raw_writel(BM_ELCDIF_CTRL_WORD_LENGTH | + BM_ELCDIF_CTRL_INPUT_DATA_SWIZZLE | + BM_ELCDIF_CTRL_DATA_FORMAT_16_BIT | + BM_ELCDIF_CTRL_DATA_FORMAT_18_BIT | + BM_ELCDIF_CTRL_DATA_FORMAT_24_BIT, + elcdif_base + HW_ELCDIF_CTRL_CLR); + __raw_writel(BM_ELCDIF_CTRL1_BYTE_PACKING_FORMAT, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + switch (in_pixel_format) { + case ELCDIF_PIX_FMT_RGB565: + __raw_writel(BF_ELCDIF_CTRL1_BYTE_PACKING_FORMAT(0xF), + elcdif_base + HW_ELCDIF_CTRL1_SET); + __raw_writel(BF_ELCDIF_CTRL_WORD_LENGTH(0) | + BF_ELCDIF_CTRL_INPUT_DATA_SWIZZLE(0), + elcdif_base + HW_ELCDIF_CTRL_SET); + break; + case ELCDIF_PIX_FMT_RGB24: + __raw_writel(BF_ELCDIF_CTRL1_BYTE_PACKING_FORMAT(0xF), + elcdif_base + HW_ELCDIF_CTRL1_SET); + __raw_writel(BF_ELCDIF_CTRL_WORD_LENGTH(3) | + BF_ELCDIF_CTRL_INPUT_DATA_SWIZZLE(0), + elcdif_base + HW_ELCDIF_CTRL_SET); + break; + case ELCDIF_PIX_FMT_RGB32: + __raw_writel(BF_ELCDIF_CTRL1_BYTE_PACKING_FORMAT(0x7), + elcdif_base + HW_ELCDIF_CTRL1_SET); + __raw_writel(BF_ELCDIF_CTRL_WORD_LENGTH(3) | + BF_ELCDIF_CTRL_INPUT_DATA_SWIZZLE(0), + elcdif_base + HW_ELCDIF_CTRL_SET); + break; + default: + dev_err(g_elcdif_dev, "ELCDIF unsupported input pixel format " + "%d\n", in_pixel_format); + break; + } + + /* Configure the output pixel format */ + __raw_writel(BM_ELCDIF_CTRL_LCD_DATABUS_WIDTH, + elcdif_base + HW_ELCDIF_CTRL_CLR); + switch (out_pixel_format) { + case ELCDIF_PIX_FMT_RGB565: + __raw_writel(BF_ELCDIF_CTRL_LCD_DATABUS_WIDTH(0), + elcdif_base + HW_ELCDIF_CTRL_SET); + break; + case ELCDIF_PIX_FMT_RGB666: + __raw_writel(BF_ELCDIF_CTRL_LCD_DATABUS_WIDTH(2), + elcdif_base + HW_ELCDIF_CTRL_SET); + break; + case ELCDIF_PIX_FMT_RGB24: + __raw_writel(BF_ELCDIF_CTRL_LCD_DATABUS_WIDTH(3), + elcdif_base + HW_ELCDIF_CTRL_SET); + break; + default: + dev_err(g_elcdif_dev, "ELCDIF unsupported output pixel format " + "%d\n", out_pixel_format); + break; + } + + val = __raw_readl(elcdif_base + HW_ELCDIF_TRANSFER_COUNT); + val &= ~(BM_ELCDIF_TRANSFER_COUNT_V_COUNT | + BM_ELCDIF_TRANSFER_COUNT_H_COUNT); + val |= BF_ELCDIF_TRANSFER_COUNT_H_COUNT(h_active) | + BF_ELCDIF_TRANSFER_COUNT_V_COUNT(v_active); + __raw_writel(val, elcdif_base + HW_ELCDIF_TRANSFER_COUNT); + + __raw_writel(BM_ELCDIF_CTRL_VSYNC_MODE, + elcdif_base + HW_ELCDIF_CTRL_CLR); + __raw_writel(BM_ELCDIF_CTRL_WAIT_FOR_VSYNC_EDGE, + elcdif_base + HW_ELCDIF_CTRL_CLR); + __raw_writel(BM_ELCDIF_CTRL_DVI_MODE, + elcdif_base + HW_ELCDIF_CTRL_CLR); + __raw_writel(BM_ELCDIF_CTRL_DOTCLK_MODE, + elcdif_base + HW_ELCDIF_CTRL_SET); + __raw_writel(BM_ELCDIF_CTRL_BYPASS_COUNT, + elcdif_base + HW_ELCDIF_CTRL_SET); + + val = __raw_readl(elcdif_base + HW_ELCDIF_VDCTRL0); + val &= ~(BM_ELCDIF_VDCTRL0_VSYNC_POL | + BM_ELCDIF_VDCTRL0_HSYNC_POL | + BM_ELCDIF_VDCTRL0_ENABLE_POL | + BM_ELCDIF_VDCTRL0_DOTCLK_POL); + if (sig_cfg.Vsync_pol) + val |= BM_ELCDIF_VDCTRL0_VSYNC_POL; + if (sig_cfg.Hsync_pol) + val |= BM_ELCDIF_VDCTRL0_HSYNC_POL; + if (sig_cfg.clk_pol) + val |= BM_ELCDIF_VDCTRL0_DOTCLK_POL; + if (sig_cfg.enable_pol) + val |= BM_ELCDIF_VDCTRL0_ENABLE_POL; + __raw_writel(val, elcdif_base + HW_ELCDIF_VDCTRL0); + + /* vsync is output */ + val = __raw_readl(elcdif_base + HW_ELCDIF_VDCTRL0); + val &= ~(BM_ELCDIF_VDCTRL0_VSYNC_OEB); + __raw_writel(val, elcdif_base + HW_ELCDIF_VDCTRL0); + + /* + * need enable sig for true RGB i/f. Or, if not true RGB, leave it + * zero. + */ + if (enable_present) { + val = __raw_readl(elcdif_base + HW_ELCDIF_VDCTRL0); + val |= BM_ELCDIF_VDCTRL0_ENABLE_PRESENT; + __raw_writel(val, elcdif_base + HW_ELCDIF_VDCTRL0); + } + + /* + * For DOTCLK mode, count VSYNC_PERIOD in terms of complete hz lines + */ + val = __raw_readl(elcdif_base + HW_ELCDIF_VDCTRL0); + val &= ~(BM_ELCDIF_VDCTRL0_VSYNC_PERIOD_UNIT | + BM_ELCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT); + val |= BM_ELCDIF_VDCTRL0_VSYNC_PERIOD_UNIT | + BM_ELCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT; + __raw_writel(val, elcdif_base + HW_ELCDIF_VDCTRL0); + + __raw_writel(BM_ELCDIF_VDCTRL0_VSYNC_PULSE_WIDTH, + elcdif_base + HW_ELCDIF_VDCTRL0_CLR); + __raw_writel(v_pulse_width, elcdif_base + HW_ELCDIF_VDCTRL0_SET); + + __raw_writel(BF_ELCDIF_VDCTRL1_VSYNC_PERIOD(v_period), + elcdif_base + HW_ELCDIF_VDCTRL1); + + __raw_writel(BF_ELCDIF_VDCTRL2_HSYNC_PULSE_WIDTH(h_pulse_width) | + BF_ELCDIF_VDCTRL2_HSYNC_PERIOD(h_period), + elcdif_base + HW_ELCDIF_VDCTRL2); + + val = __raw_readl(elcdif_base + HW_ELCDIF_VDCTRL4); + val &= ~BM_ELCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT; + val |= BF_ELCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT(h_active); + __raw_writel(val, elcdif_base + HW_ELCDIF_VDCTRL4); + + val = __raw_readl(elcdif_base + HW_ELCDIF_VDCTRL3); + val &= ~(BM_ELCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT | + BM_ELCDIF_VDCTRL3_VERTICAL_WAIT_CNT); + val |= BF_ELCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT(h_wait_cnt) | + BF_ELCDIF_VDCTRL3_VERTICAL_WAIT_CNT(v_wait_cnt); + __raw_writel(val, elcdif_base + HW_ELCDIF_VDCTRL3); + + val = __raw_readl(elcdif_base + HW_ELCDIF_VDCTRL4); + val |= BM_ELCDIF_VDCTRL4_SYNC_SIGNALS_ON; + __raw_writel(val, elcdif_base + HW_ELCDIF_VDCTRL4); + + return; +} + +static inline void release_dotclk_panel(void) +{ + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + __raw_writel(BM_ELCDIF_CTRL_DOTCLK_MODE, + elcdif_base + HW_ELCDIF_CTRL_CLR); + __raw_writel(0, elcdif_base + HW_ELCDIF_VDCTRL0); + __raw_writel(0, elcdif_base + HW_ELCDIF_VDCTRL1); + __raw_writel(0, elcdif_base + HW_ELCDIF_VDCTRL2); + __raw_writel(0, elcdif_base + HW_ELCDIF_VDCTRL3); + + return; +} + +static inline void setup_dvi_panel(u16 h_active, u16 v_active, + u16 h_blanking, u16 v_lines, + u16 v1_blank_start, u16 v1_blank_end, + u16 v2_blank_start, u16 v2_blank_end, + u16 f1_start, u16 f1_end, + u16 f2_start, u16 f2_end) +{ + u32 val; + + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + /* 32bit packed format (RGB) */ + __raw_writel(BM_ELCDIF_CTRL1_BYTE_PACKING_FORMAT, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + __raw_writel(BF_ELCDIF_CTRL1_BYTE_PACKING_FORMAT(0x7) | + BM_ELCDIF_CTRL1_RECOVER_ON_UNDERFLOW, + elcdif_base + HW_ELCDIF_CTRL1_SET); + + val = __raw_readl(elcdif_base + HW_ELCDIF_TRANSFER_COUNT); + val &= ~(BM_ELCDIF_TRANSFER_COUNT_V_COUNT | + BM_ELCDIF_TRANSFER_COUNT_H_COUNT); + val |= BF_ELCDIF_TRANSFER_COUNT_H_COUNT(h_active) | + BF_ELCDIF_TRANSFER_COUNT_V_COUNT(v_active); + __raw_writel(val, elcdif_base + HW_ELCDIF_TRANSFER_COUNT); + + /* set elcdif to DVI mode */ + __raw_writel(BM_ELCDIF_CTRL_DVI_MODE, + elcdif_base + HW_ELCDIF_CTRL_SET); + __raw_writel(BM_ELCDIF_CTRL_VSYNC_MODE, + elcdif_base + HW_ELCDIF_CTRL_CLR); + __raw_writel(BM_ELCDIF_CTRL_DOTCLK_MODE, + elcdif_base + HW_ELCDIF_CTRL_CLR); + + __raw_writel(BM_ELCDIF_CTRL_BYPASS_COUNT, + elcdif_base + HW_ELCDIF_CTRL_SET); + /* convert input RGB -> YCbCr */ + __raw_writel(BM_ELCDIF_CTRL_RGB_TO_YCBCR422_CSC, + elcdif_base + HW_ELCDIF_CTRL_SET); + /* interlace odd and even fields */ + __raw_writel(BM_ELCDIF_CTRL1_INTERLACE_FIELDS, + elcdif_base + HW_ELCDIF_CTRL1_SET); + + __raw_writel(BM_ELCDIF_CTRL_WORD_LENGTH | + BM_ELCDIF_CTRL_INPUT_DATA_SWIZZLE | + BM_ELCDIF_CTRL_LCD_DATABUS_WIDTH, + elcdif_base + HW_ELCDIF_CTRL_CLR); + __raw_writel(BF_ELCDIF_CTRL_WORD_LENGTH(3) | /* 24 bit */ + BM_ELCDIF_CTRL_DATA_SELECT | /* data mode */ + BF_ELCDIF_CTRL_INPUT_DATA_SWIZZLE(0) | /* no swap */ + BF_ELCDIF_CTRL_LCD_DATABUS_WIDTH(1), /* 8 bit */ + elcdif_base + HW_ELCDIF_CTRL_SET); + + /* ELCDIF_DVI */ + /* set frame size */ + val = __raw_readl(elcdif_base + HW_ELCDIF_DVICTRL0); + __raw_writel(val, elcdif_base + HW_ELCDIF_DVICTRL0); + + /* set start/end of field-1 and start of field-2 */ + val = __raw_readl(elcdif_base + HW_ELCDIF_DVICTRL1); + val &= ~(BM_ELCDIF_DVICTRL1_F1_START_LINE | + BM_ELCDIF_DVICTRL1_F1_END_LINE | + BM_ELCDIF_DVICTRL1_F2_START_LINE); + val |= BF_ELCDIF_DVICTRL1_F1_START_LINE(f1_start) | + BF_ELCDIF_DVICTRL1_F1_END_LINE(f1_end) | + BF_ELCDIF_DVICTRL1_F2_START_LINE(f2_start); + __raw_writel(val, elcdif_base + HW_ELCDIF_DVICTRL1); + + /* set first vertical blanking interval and end of filed-2 */ + val = __raw_readl(elcdif_base + HW_ELCDIF_DVICTRL2); + val &= ~(BM_ELCDIF_DVICTRL2_F2_END_LINE | + BM_ELCDIF_DVICTRL2_V1_BLANK_START_LINE | + BM_ELCDIF_DVICTRL2_V1_BLANK_END_LINE); + val |= BF_ELCDIF_DVICTRL2_F2_END_LINE(f2_end) | + BF_ELCDIF_DVICTRL2_V1_BLANK_START_LINE(v1_blank_start) | + BF_ELCDIF_DVICTRL2_V1_BLANK_END_LINE(v1_blank_end); + __raw_writel(val, elcdif_base + HW_ELCDIF_DVICTRL2); + + /* set second vertical blanking interval */ + val = __raw_readl(elcdif_base + HW_ELCDIF_DVICTRL3); + val &= ~(BM_ELCDIF_DVICTRL3_V2_BLANK_START_LINE | + BM_ELCDIF_DVICTRL3_V2_BLANK_END_LINE); + val |= BF_ELCDIF_DVICTRL3_V2_BLANK_START_LINE(v2_blank_start) | + BF_ELCDIF_DVICTRL3_V2_BLANK_END_LINE(v2_blank_end); + __raw_writel(val, elcdif_base + HW_ELCDIF_DVICTRL3); + + /* fill the rest area black color if the input frame + * is not 720 pixels/line + */ + if (h_active != 720) { + /* the input frame can't be less then (720-256) pixels/line */ + if (720 - h_active > 0xff) + h_active = 720 - 0xff; + + val = __raw_readl(elcdif_base + HW_ELCDIF_DVICTRL4); + val &= ~(BM_ELCDIF_DVICTRL4_H_FILL_CNT | + BM_ELCDIF_DVICTRL4_Y_FILL_VALUE | + BM_ELCDIF_DVICTRL4_CB_FILL_VALUE | + BM_ELCDIF_DVICTRL4_CR_FILL_VALUE); + val |= BF_ELCDIF_DVICTRL4_H_FILL_CNT(720 - h_active) | + BF_ELCDIF_DVICTRL4_Y_FILL_VALUE(16) | + BF_ELCDIF_DVICTRL4_CB_FILL_VALUE(128) | + BF_ELCDIF_DVICTRL4_CR_FILL_VALUE(128); + __raw_writel(val, elcdif_base + HW_ELCDIF_DVICTRL4); + } + + /* Color Space Conversion RGB->YCbCr */ + val = __raw_readl(elcdif_base + HW_ELCDIF_CSC_COEFF0); + val &= ~(BM_ELCDIF_CSC_COEFF0_C0 | + BM_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER); + val |= BF_ELCDIF_CSC_COEFF0_C0(0x41) | + BF_ELCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER(3); + __raw_writel(val, elcdif_base + HW_ELCDIF_CSC_COEFF0); + + val = __raw_readl(elcdif_base + HW_ELCDIF_CSC_COEFF1); + val &= ~(BM_ELCDIF_CSC_COEFF1_C1 | BM_ELCDIF_CSC_COEFF1_C2); + val |= BF_ELCDIF_CSC_COEFF1_C1(0x81) | + BF_ELCDIF_CSC_COEFF1_C2(0x19); + __raw_writel(val, elcdif_base + HW_ELCDIF_CSC_COEFF1); + + val = __raw_readl(elcdif_base + HW_ELCDIF_CSC_COEFF2); + val &= ~(BM_ELCDIF_CSC_COEFF2_C3 | BM_ELCDIF_CSC_COEFF2_C4); + val |= BF_ELCDIF_CSC_COEFF2_C3(0x3DB) | + BF_ELCDIF_CSC_COEFF2_C4(0x3B6); + __raw_writel(val, elcdif_base + HW_ELCDIF_CSC_COEFF2); + + val = __raw_readl(elcdif_base + HW_ELCDIF_CSC_COEFF3); + val &= ~(BM_ELCDIF_CSC_COEFF3_C5 | BM_ELCDIF_CSC_COEFF3_C6); + val |= BF_ELCDIF_CSC_COEFF3_C5(0x70) | + BF_ELCDIF_CSC_COEFF3_C6(0x70); + __raw_writel(val, elcdif_base + HW_ELCDIF_CSC_COEFF3); + + val = __raw_readl(elcdif_base + HW_ELCDIF_CSC_COEFF4); + val &= ~(BM_ELCDIF_CSC_COEFF4_C7 | BM_ELCDIF_CSC_COEFF4_C8); + val |= BF_ELCDIF_CSC_COEFF4_C7(0x3A2) | + BF_ELCDIF_CSC_COEFF4_C8(0x3EE); + __raw_writel(val, elcdif_base + HW_ELCDIF_CSC_COEFF4); + + val = __raw_readl(elcdif_base + HW_ELCDIF_CSC_OFFSET); + val &= ~(BM_ELCDIF_CSC_OFFSET_CBCR_OFFSET | + BM_ELCDIF_CSC_OFFSET_Y_OFFSET); + val |= BF_ELCDIF_CSC_OFFSET_CBCR_OFFSET(0x80) | + BF_ELCDIF_CSC_OFFSET_Y_OFFSET(0x10); + __raw_writel(val, elcdif_base + HW_ELCDIF_CSC_OFFSET); + + val = __raw_readl(elcdif_base + HW_ELCDIF_CSC_LIMIT); + val &= ~(BM_ELCDIF_CSC_LIMIT_CBCR_MIN | + BM_ELCDIF_CSC_LIMIT_CBCR_MAX | + BM_ELCDIF_CSC_LIMIT_Y_MIN | + BM_ELCDIF_CSC_LIMIT_Y_MAX); + val |= BF_ELCDIF_CSC_LIMIT_CBCR_MIN(16) | + BF_ELCDIF_CSC_LIMIT_CBCR_MAX(240) | + BF_ELCDIF_CSC_LIMIT_Y_MIN(16) | + BF_ELCDIF_CSC_LIMIT_Y_MAX(235); + __raw_writel(val, elcdif_base + HW_ELCDIF_CSC_LIMIT); + + return; +} + +static inline void release_dvi_panel(void) +{ + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + __raw_writel(BM_ELCDIF_CTRL_DVI_MODE, + elcdif_base + HW_ELCDIF_CTRL_CLR); + return; +} + +static inline void mxc_init_elcdif(void) +{ + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + __raw_writel(BM_ELCDIF_CTRL_CLKGATE, + elcdif_base + HW_ELCDIF_CTRL_CLR); + /* Reset controller */ + __raw_writel(BM_ELCDIF_CTRL_SFTRST, + elcdif_base + HW_ELCDIF_CTRL_SET); + udelay(10); + + /* Take controller out of reset */ + __raw_writel(BM_ELCDIF_CTRL_SFTRST | BM_ELCDIF_CTRL_CLKGATE, + elcdif_base + HW_ELCDIF_CTRL_CLR); + + /* Setup the bus protocol */ + __raw_writel(BM_ELCDIF_CTRL1_MODE86, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + __raw_writel(BM_ELCDIF_CTRL1_BUSY_ENABLE, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + + /* Take display out of reset */ + __raw_writel(BM_ELCDIF_CTRL1_RESET, + elcdif_base + HW_ELCDIF_CTRL1_SET); + + /* VSYNC is an input by default */ + __raw_writel(BM_ELCDIF_VDCTRL0_VSYNC_OEB, + elcdif_base + HW_ELCDIF_VDCTRL0_SET); + + /* Reset display */ + __raw_writel(BM_ELCDIF_CTRL1_RESET, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + udelay(10); + __raw_writel(BM_ELCDIF_CTRL1_RESET, + elcdif_base + HW_ELCDIF_CTRL1_SET); + udelay(10); + + return; +} + +static inline int mxc_elcdif_dma_init(dma_addr_t phys) +{ + int ret = 0; + + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + __raw_writel(BM_ELCDIF_CTRL_ELCDIF_MASTER, + elcdif_base + HW_ELCDIF_CTRL_SET); + + __raw_writel(phys, elcdif_base + HW_ELCDIF_CUR_BUF); + __raw_writel(phys, elcdif_base + HW_ELCDIF_NEXT_BUF); + return ret; +} + +static inline void mxc_elcdif_dma_release(void) +{ + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + __raw_writel(BM_ELCDIF_CTRL_ELCDIF_MASTER, + elcdif_base + HW_ELCDIF_CTRL_CLR); + return; +} + +static inline void mxc_elcdif_run(void) +{ + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + __raw_writel(BM_ELCDIF_CTRL_ELCDIF_MASTER, + elcdif_base + HW_ELCDIF_CTRL_SET); + __raw_writel(BM_ELCDIF_CTRL_RUN, + elcdif_base + HW_ELCDIF_CTRL_SET); + return; +} + +static inline void mxc_elcdif_stop(void) +{ + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + __raw_writel(BM_ELCDIF_CTRL_RUN, + elcdif_base + HW_ELCDIF_CTRL_CLR); + __raw_writel(BM_ELCDIF_CTRL_ELCDIF_MASTER, + elcdif_base + HW_ELCDIF_CTRL_CLR); + msleep(1); + __raw_writel(BM_ELCDIF_CTRL_CLKGATE, elcdif_base + HW_ELCDIF_CTRL_SET); + return; +} + +static int mxc_elcdif_blank_panel(int blank) +{ + int ret = 0, count; + + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + switch (blank) { + case FB_BLANK_NORMAL: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + __raw_writel(BM_ELCDIF_CTRL_BYPASS_COUNT, + elcdif_base + HW_ELCDIF_CTRL_CLR); + for (count = 10000; count; count--) { + if (__raw_readl(elcdif_base + HW_ELCDIF_STAT) & + BM_ELCDIF_STAT_TXFIFO_EMPTY) + break; + msleep(1); + } + break; + + case FB_BLANK_UNBLANK: + __raw_writel(BM_ELCDIF_CTRL_BYPASS_COUNT, + elcdif_base + HW_ELCDIF_CTRL_SET); + break; + + default: + dev_err(g_elcdif_dev, "unknown blank parameter\n"); + ret = -EINVAL; + break; + } + return ret; +} + +static int mxc_elcdif_init_panel(void) +{ + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + + /* + * Make sure we do a high-to-low transition to reset the panel. + * First make it low for 100 msec, hi for 10 msec, low for 10 msec, + * then hi. + */ + __raw_writel(BM_ELCDIF_CTRL1_RESET, + elcdif_base + HW_ELCDIF_CTRL1_CLR); /* low */ + msleep(100); + __raw_writel(BM_ELCDIF_CTRL1_RESET, + elcdif_base + HW_ELCDIF_CTRL1_SET); /* high */ + msleep(10); + __raw_writel(BM_ELCDIF_CTRL1_RESET, + elcdif_base + HW_ELCDIF_CTRL1_CLR); /* low */ + + /* For the Samsung, Reset must be held low at least 30 uSec + * Therefore, we'll hold it low for about 10 mSec just to be sure. + * Then we'll wait 1 mSec afterwards. + */ + msleep(10); + __raw_writel(BM_ELCDIF_CTRL1_RESET, + elcdif_base + HW_ELCDIF_CTRL1_SET); /* high */ + msleep(1); + + return 0; +} + +static uint32_t bpp_to_pixfmt(struct fb_info *fbi) +{ + uint32_t pixfmt = 0; + + if (fbi->var.nonstd) + return fbi->var.nonstd; + + switch (fbi->var.bits_per_pixel) { + case 32: + pixfmt = ELCDIF_PIX_FMT_RGB32; + break; + case 24: + pixfmt = ELCDIF_PIX_FMT_RGB24; + break; + case 18: + pixfmt = ELCDIF_PIX_FMT_RGB666; + break; + case 16: + pixfmt = ELCDIF_PIX_FMT_RGB565; + break; + case 8: + pixfmt = ELCDIF_PIX_FMT_RGB332; + break; + } + return pixfmt; +} + +static int mxc_elcdif_fb_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 = 1; + fix->ypanstep = 1; + + return 0; +} + +static irqreturn_t lcd_irq_handler(int irq, void *dev_id) +{ + struct mxc_elcdif_fb_data *data = dev_id; + u32 status_lcd = __raw_readl(elcdif_base + HW_ELCDIF_CTRL1); + dev_dbg(g_elcdif_dev, "%s: irq %d\n", __func__, irq); + + if (status_lcd & BM_ELCDIF_CTRL1_VSYNC_EDGE_IRQ) { + dev_dbg(g_elcdif_dev, "%s: VSYNC irq\n", __func__); + __raw_writel(BM_ELCDIF_CTRL1_VSYNC_EDGE_IRQ, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + complete(&data->vsync_complete); + } + if (status_lcd & BM_ELCDIF_CTRL1_CUR_FRAME_DONE_IRQ) { + dev_dbg(g_elcdif_dev, "%s: frame done irq\n", __func__); + __raw_writel(BM_ELCDIF_CTRL1_CUR_FRAME_DONE_IRQ, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + up(&data->flip_sem); + } + if (status_lcd & BM_ELCDIF_CTRL1_UNDERFLOW_IRQ) { + dev_dbg(g_elcdif_dev, "%s: underflow irq\n", __func__); + __raw_writel(BM_ELCDIF_CTRL1_UNDERFLOW_IRQ, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + } + if (status_lcd & BM_ELCDIF_CTRL1_OVERFLOW_IRQ) { + dev_dbg(g_elcdif_dev, "%s: overflow irq\n", __func__); + __raw_writel(BM_ELCDIF_CTRL1_OVERFLOW_IRQ, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + } + return IRQ_HANDLED; +} + +static inline u_int _chan_to_field(u_int chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int mxc_elcdif_fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *fbi) +{ + unsigned int val; + int ret = 1; + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. + */ + if (fbi->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + switch (fbi->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* + * 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = fbi->pseudo_palette; + + val = _chan_to_field(red, &fbi->var.red); + val |= _chan_to_field(green, &fbi->var.green); + val |= _chan_to_field(blue, &fbi->var.blue); + + pal[regno] = val; + ret = 0; + } + break; + + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + break; + } + return ret; +} + +/* + * This routine actually sets the video mode. It's in here where we + * the hardware state info->par and fix which can be affected by the + * change in par. For this driver it doesn't do much. + * + */ +static int mxc_elcdif_fb_set_par(struct fb_info *fbi) +{ + struct mxc_elcdif_fb_data *data = (struct mxc_elcdif_fb_data *)fbi->par; + struct elcdif_signal_cfg sig_cfg; + int mem_len; + + dev_dbg(fbi->device, "Reconfiguring framebuffer\n"); + + sema_init(&data->flip_sem, 1); + + /* release prev panel */ + if (!g_elcdif_pix_clk_enable) { + clk_enable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = true; + } + mxc_elcdif_blank_panel(FB_BLANK_POWERDOWN); + mxc_elcdif_stop(); + release_dotclk_panel(); + mxc_elcdif_dma_release(); + mxc_elcdif_fb_set_fix(fbi); + if (g_elcdif_pix_clk_enable) { + clk_disable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = false; + } + + 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) + mxc_elcdif_fb_unmap_video_memory(fbi); + + if (mxc_elcdif_fb_map_video_memory(fbi) < 0) + return -ENOMEM; + } + + if (data->is_blank) + return 0; + + /* init next panel */ + if (!g_elcdif_pix_clk_enable) { + clk_enable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = true; + } + mxc_init_elcdif(); + mxc_elcdif_init_panel(); + + dev_dbg(fbi->device, "pixclock = %ul Hz\n", + (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL)); + + memset(&sig_cfg, 0, sizeof(sig_cfg)); + if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT) + sig_cfg.Hsync_pol = true; + if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) + sig_cfg.Vsync_pol = true; + if (fbi->var.sync & FB_SYNC_CLK_LAT_FALL) + sig_cfg.clk_pol = true; + if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT)) + sig_cfg.enable_pol = true; + + setup_dotclk_panel((PICOS2KHZ(fbi->var.pixclock)) * 1000UL, + fbi->var.vsync_len, + fbi->var.upper_margin + + fbi->var.yres + fbi->var.lower_margin, + fbi->var.upper_margin, + fbi->var.yres, + fbi->var.hsync_len, + fbi->var.left_margin + + fbi->var.xres + fbi->var.right_margin, + fbi->var.left_margin, + fbi->var.xres, + bpp_to_pixfmt(fbi), + data->output_pix_fmt, + sig_cfg, + 1); + mxc_elcdif_dma_init(fbi->fix.smem_start); + mxc_elcdif_run(); + mxc_elcdif_blank_panel(FB_BLANK_UNBLANK); + + fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var, + &fbi->modelist); + return 0; +} + +static int mxc_elcdif_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + 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 = default_bpp; + + 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; + } + + var->height = -1; + var->width = -1; + var->grayscale = 0; + + return 0; +} + +static int mxc_elcdif_fb_wait_for_vsync(u32 channel, struct fb_info *info) +{ + struct mxc_elcdif_fb_data *data = + (struct mxc_elcdif_fb_data *)info->par; + int ret = 0; + + if (data->is_blank) { + dev_err(info->device, "can't wait for VSYNC when fb " + "is blank\n"); + return -EINVAL; + } + + init_completion(&data->vsync_complete); + + __raw_writel(BM_ELCDIF_CTRL1_VSYNC_EDGE_IRQ_EN, + elcdif_base + HW_ELCDIF_CTRL1_SET); + ret = wait_for_completion_interruptible_timeout( + &data->vsync_complete, 1 * HZ); + if (ret == 0) { + dev_err(info->device, + "MXC ELCDIF wait for vsync: timeout %d\n", + ret); + ret = -ETIME; + } else if (ret > 0) { + ret = 0; + } + __raw_writel(BM_ELCDIF_CTRL1_VSYNC_EDGE_IRQ_EN, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + if (!ret) { + dev_err(info->device, "wait for vsync timed out\n"); + ret = -ETIMEDOUT; + } + return ret; +} + +static int mxc_elcdif_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + u32 channel = 0; + int ret = -EINVAL; + + switch (cmd) { + case MXCFB_WAIT_FOR_VSYNC: + if (!get_user(channel, (__u32 __user *) arg)) + ret = mxc_elcdif_fb_wait_for_vsync(channel, info); + break; + default: + break; + } + return ret; +} + +static int mxc_elcdif_fb_blank(int blank, struct fb_info *info) +{ + struct mxc_elcdif_fb_data *data = + (struct mxc_elcdif_fb_data *)info->par; + int ret = 0; + + if (data->is_blank == (blank != FB_BLANK_UNBLANK)) + return ret; + + if (blank == FB_BLANK_UNBLANK) { + if (!g_elcdif_pix_clk_enable) { + clk_enable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = true; + } + } + ret = mxc_elcdif_blank_panel(blank); + if (ret == 0) + data->is_blank = (blank != FB_BLANK_UNBLANK); + else + return ret; + + if (data->is_blank) { + if (g_elcdif_axi_clk_enable) { + clk_disable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = false; + } + if (g_elcdif_pix_clk_enable) { + clk_disable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = false; + } + } else { + if (!g_elcdif_axi_clk_enable) { + clk_enable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = true; + } + if (!g_elcdif_pix_clk_enable) { + clk_enable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = true; + } + } + + return ret; +} + +static int mxc_elcdif_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct mxc_elcdif_fb_data *data = + (struct mxc_elcdif_fb_data *)info->par; + int ret = 0; + unsigned long base; + + if (data->is_blank) { + dev_err(info->device, "can't do pan display when fb " + "is blank\n"); + return -EINVAL; + } + + if (var->xoffset > 0) { + dev_dbg(info->device, "x panning not supported\n"); + return -EINVAL; + } + + if ((var->yoffset + var->yres > var->yres_virtual)) { + dev_err(info->device, "y panning exceeds\n"); + return -EINVAL; + } + + /* update framebuffer visual */ + base = (var->yoffset * var->xres_virtual + var->xoffset); + base *= (var->bits_per_pixel) / 8; + base += info->fix.smem_start; + + __raw_writel(base, elcdif_base + HW_ELCDIF_NEXT_BUF); + + init_completion(&data->vsync_complete); + + /* + * Wait for an interrupt or we will lose frame + * if we call pan-dislay too fast. + */ + __raw_writel(BM_ELCDIF_CTRL1_CUR_FRAME_DONE_IRQ, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + __raw_writel(BM_ELCDIF_CTRL1_CUR_FRAME_DONE_IRQ_EN, + elcdif_base + HW_ELCDIF_CTRL1_SET); + down(&data->flip_sem); + __raw_writel(BM_ELCDIF_CTRL1_CUR_FRAME_DONE_IRQ_EN, + elcdif_base + HW_ELCDIF_CTRL1_CLR); + + return ret; +} + +static struct fb_ops mxc_elcdif_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = mxc_elcdif_fb_check_var, + .fb_set_par = mxc_elcdif_fb_set_par, + .fb_setcolreg = mxc_elcdif_fb_setcolreg, + .fb_ioctl = mxc_elcdif_fb_ioctl, + .fb_blank = mxc_elcdif_fb_blank, + .fb_pan_display = mxc_elcdif_fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +/*! + * 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 mxc_elcdif_fb_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 mxc_elcdif_fb_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; +} + +static int mxc_elcdif_fb_probe(struct platform_device *pdev) +{ + int ret = 0; + struct mxc_elcdif_fb_data *data; + struct resource *res; + struct fb_info *fbi; + struct mxc_fb_platform_data *pdata = pdev->dev.platform_data; + + fbi = framebuffer_alloc(sizeof(struct mxc_elcdif_fb_data), &pdev->dev); + if (fbi == NULL) { + ret = -ENOMEM; + goto out; + } + + data = (struct mxc_elcdif_fb_data *)fbi->par; + data->is_blank = false; + + fbi->var.activate = FB_ACTIVATE_NOW; + fbi->fbops = &mxc_elcdif_fb_ops; + fbi->flags = FBINFO_FLAG_DEFAULT; + fbi->pseudo_palette = data->pseudo_palette; + + ret = fb_alloc_cmap(&fbi->cmap, 16, 0); + if (ret) + goto out; + + g_elcdif_dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(&pdev->dev, "cannot get IRQ resource\n"); + ret = -ENODEV; + goto err0; + } + data->dma_irq = res->start; + + ret = request_irq(data->dma_irq, lcd_irq_handler, 0, + "mxc_elcdif_fb", data); + if (ret) { + dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n", + data->dma_irq, ret); + goto err0; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + ret = -ENODEV; + goto err1; + } + elcdif_base = ioremap(res->start, SZ_4K); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + 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); + } + + strcpy(fbi->fix.id, "mxc_elcdif_fb"); + + fbi->var.xres = 800; + fbi->var.yres = 480; + + if (pdata && !data->output_pix_fmt) + data->output_pix_fmt = pdata->interface_pix_fmt; + + if (pdata && pdata->mode && pdata->num_modes) + fb_videomode_to_modelist(pdata->mode, pdata->num_modes, + &fbi->modelist); + + if (!fb_mode && pdata && pdata->mode_str) + fb_mode = pdata->mode_str; + + if (fb_mode) { + ret = fb_find_mode(&fbi->var, fbi, fb_mode, NULL, 0, NULL, + default_bpp); + if ((!ret || (ret > 2)) && pdata && pdata->mode && + pdata->num_modes) + fb_find_mode(&fbi->var, fbi, fb_mode, pdata->mode, + pdata->num_modes, NULL, default_bpp); + } + + mxc_elcdif_fb_check_var(&fbi->var, fbi); + + fbi->var.xres_virtual = fbi->var.xres; + fbi->var.yres_virtual = fbi->var.yres * 3; + + mxc_elcdif_fb_set_fix(fbi); + + if (!res || !res->end) + if (mxc_elcdif_fb_map_video_memory(fbi) < 0) { + ret = -ENOMEM; + goto err2; + } + + g_elcdif_axi_clk = clk_get(g_elcdif_dev, "elcdif_axi"); + if (g_elcdif_axi_clk == NULL) { + dev_err(&pdev->dev, "can't get ELCDIF axi clk\n"); + ret = -ENODEV; + goto err3; + } + g_elcdif_pix_clk = clk_get(g_elcdif_dev, "elcdif_pix"); + if (g_elcdif_pix_clk == NULL) { + dev_err(&pdev->dev, "can't get ELCDIF pix clk\n"); + ret = -ENODEV; + goto err3; + } + /* + * Set an appropriate pixel clk rate first, so that we can + * access ELCDIF registers. + */ + clk_set_rate(g_elcdif_pix_clk, 25000000); + + ret = register_framebuffer(fbi); + if (ret) + goto err3; + + platform_set_drvdata(pdev, fbi); + + return 0; +err3: + mxc_elcdif_fb_unmap_video_memory(fbi); +err2: + iounmap(elcdif_base); +err1: + free_irq(data->dma_irq, data); +err0: + fb_dealloc_cmap(&fbi->cmap); + framebuffer_release(fbi); +out: + return ret; +} + +static int mxc_elcdif_fb_remove(struct platform_device *pdev) +{ + struct fb_info *fbi = platform_get_drvdata(pdev); + struct mxc_elcdif_fb_data *data = (struct mxc_elcdif_fb_data *)fbi->par; + + mxc_elcdif_fb_blank(FB_BLANK_POWERDOWN, fbi); + mxc_elcdif_stop(); + release_dotclk_panel(); + mxc_elcdif_dma_release(); + + if (g_elcdif_axi_clk_enable) { + clk_disable(g_elcdif_axi_clk); + g_elcdif_axi_clk_enable = false; + } + if (g_elcdif_pix_clk_enable) { + clk_disable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = false; + } + clk_put(g_elcdif_axi_clk); + clk_put(g_elcdif_pix_clk); + + free_irq(data->dma_irq, data); + mxc_elcdif_fb_unmap_video_memory(fbi); + + if (&fbi->cmap) + fb_dealloc_cmap(&fbi->cmap); + + unregister_framebuffer(fbi); + framebuffer_release(fbi); + + platform_set_drvdata(pdev, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int mxc_elcdif_fb_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct fb_info *fbi = platform_get_drvdata(pdev); + struct mxc_elcdif_fb_data *data = (struct mxc_elcdif_fb_data *)fbi->par; + int saved_blank; + + acquire_console_sem(); + fb_set_suspend(fbi, 1); + saved_blank = data->is_blank; + mxc_elcdif_fb_blank(FB_BLANK_POWERDOWN, fbi); + data->is_blank = saved_blank; + if (!g_elcdif_pix_clk_enable) { + clk_enable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = true; + } + mxc_elcdif_stop(); + mxc_elcdif_dma_release(); + if (g_elcdif_pix_clk_enable) { + clk_disable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = false; + } + + return 0; +} + +static int mxc_elcdif_fb_resume(struct platform_device *pdev) +{ + struct fb_info *fbi = platform_get_drvdata(pdev); + struct mxc_elcdif_fb_data *data = (struct mxc_elcdif_fb_data *)fbi->par; + + acquire_console_sem(); + if (!g_elcdif_pix_clk_enable) { + clk_enable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = true; + } + mxc_init_elcdif(); + mxc_elcdif_init_panel(); + mxc_elcdif_dma_init(fbi->fix.smem_start); + mxc_elcdif_run(); + if (g_elcdif_pix_clk_enable) { + clk_disable(g_elcdif_pix_clk); + g_elcdif_pix_clk_enable = false; + } + if (!data->is_blank) + mxc_elcdif_fb_blank(FB_BLANK_UNBLANK, fbi); + fb_set_suspend(fbi, 0); + release_console_sem(); + + return 0; +} +#else +#define mxc_elcdif_fb_suspend NULL +#define mxc_elcdif_fb_resume NULL +#endif + +static struct platform_driver mxc_elcdif_fb_driver = { + .probe = mxc_elcdif_fb_probe, + .remove = mxc_elcdif_fb_remove, + .suspend = mxc_elcdif_fb_suspend, + .resume = mxc_elcdif_fb_resume, + .driver = { + .name = "mxc_elcdif_fb", + .owner = THIS_MODULE, + }, +}; + +/* + * Parse user specified options (`video=trident:') + * example: + * video=trident:800x600,bpp=16,noaccel + */ +int mxc_elcdif_fb_setup(char *options) +{ + char *opt; + if (!options || !*options) + return 0; + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + + if (!strncmp(opt, "bpp=", 4)) + default_bpp = simple_strtoul(opt + 4, NULL, 0); + else + fb_mode = opt; + } + return 0; +} + +static int __init mxc_elcdif_fb_init(void) +{ + char *option = NULL; + + if (fb_get_options("mxc_elcdif_fb", &option)) + return -ENODEV; + mxc_elcdif_fb_setup(option); + + return platform_driver_register(&mxc_elcdif_fb_driver); +} + +static void __exit mxc_elcdif_fb_exit(void) +{ + platform_driver_unregister(&mxc_elcdif_fb_driver); +} + +module_init(mxc_elcdif_fb_init); +module_exit(mxc_elcdif_fb_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC ELCDIF Framebuffer Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/mxc/mxcfb_claa_wvga.c b/drivers/video/mxc/mxcfb_claa_wvga.c index bd5ff7b83f8c..8f696c19e7d9 100644 --- a/drivers/video/mxc/mxcfb_claa_wvga.c +++ b/drivers/video/mxc/mxcfb_claa_wvga.c @@ -48,8 +48,8 @@ static int lcd_on; static struct fb_videomode video_modes[] = { { - /* 800x480 @ 55 Hz , pixel clk @ 25MHz */ - "CLAA-WVGA", 55, 800, 480, 40000, 40, 40, 5, 5, 20, 10, + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, FB_SYNC_CLK_LAT_FALL, FB_VMODE_NONINTERLACED, 0,}, @@ -77,13 +77,14 @@ static int lcd_fb_event(struct notifier_block *nb, unsigned long val, void *v) { struct fb_event *event = v; - if (strcmp(event->info->fix.id, "DISP3 BG")) { + if (strcmp(event->info->fix.id, "DISP3 BG") && + strcmp(event->info->fix.id, "mxc_elcdif_fb")) return 0; - } switch (val) { case FB_EVENT_FB_REGISTERED: lcd_init_fb(event->info); + fb_show_logo(event->info, 0); lcd_poweron(); break; case FB_EVENT_BLANK: @@ -133,7 +134,8 @@ static int __devinit lcd_probe(struct platform_device *pdev) } for (i = 0; i < num_registered_fb; i++) { - if (strcmp(registered_fb[i]->fix.id, "DISP3 BG") == 0) { + if (strcmp(registered_fb[i]->fix.id, "DISP3 BG") == 0 || + strcmp(registered_fb[i]->fix.id, "mxc_elcdif_fb") == 0) { lcd_init_fb(registered_fb[i]); fb_show_logo(registered_fb[i], 0); lcd_poweron(); |