From 89f83291537366fec7e9a984569037758077ec55 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=92=9F=E5=8B=87=E6=B1=AA?= Date: Fri, 14 May 2010 12:44:56 +0000 Subject: [PATCH] add fb --- arch/arm/mach-rk2818/board-midsdk.c | 23 + arch/arm/mach-rk2818/devices.c | 26 + arch/arm/mach-rk2818/devices.h | 2 +- arch/arm/mach-rk2818/include/mach/board.h | 21 + drivers/video/Kconfig | 9 + drivers/video/Makefile | 1 + drivers/video/display/Kconfig | 1 + drivers/video/display/Makefile | 2 +- drivers/video/rk2818_fb.c | 2449 +++++++++++++++++++++ drivers/video/rk2818_fb.h | 413 ++++ 10 files changed, 2945 insertions(+), 2 deletions(-) create mode 100644 drivers/video/rk2818_fb.c create mode 100644 drivers/video/rk2818_fb.h diff --git a/arch/arm/mach-rk2818/board-midsdk.c b/arch/arm/mach-rk2818/board-midsdk.c index 851770d25d69..07d127be01a5 100644 --- a/arch/arm/mach-rk2818/board-midsdk.c +++ b/arch/arm/mach-rk2818/board-midsdk.c @@ -245,6 +245,28 @@ static struct spi_board_info board_spi_devices[] = { }, }; +/*rk2818_fb gpio information*/ +static struct rk2818_fb_gpio rk2818_fb_gpio_info = { + .lcd_cs = 0, + .display_on = (GPIO_LOW<<16)|RK2818_PIN_PA2, + .lcd_standby = 0, + .mcu_fmk_pin = 0, +}; + +/*rk2818_fb iomux information*/ +static struct rk2818_fb_iomux rk2818_fb_iomux_info = { + .data16 = GPIOC_LCDC16BIT_SEL_NAME, + .data18 = GPIOC_LCDC18BIT_SEL_NAME, + .data24 = GPIOC_LCDC24BIT_SEL_NAME, + .den = CXGPIO_LCDDEN_SEL_NAME, + .vsync = CXGPIO_LCDVSYNC_SEL_NAME, + .mcu_fmk = 0, +}; +/*rk2818_fb*/ +struct rk2818_fb_mach_info rk2818_fb_mach_info = { + .gpio = &rk2818_fb_gpio_info, + .iomux = &rk2818_fb_iomux_info, +}; static struct platform_device *devices[] __initdata = { &rk2818_device_uart1, @@ -256,6 +278,7 @@ static struct platform_device *devices[] __initdata = { &rk2818_device_i2c1, #endif &rk2818_device_spim, + &rk2818_device_fb, }; extern struct sys_timer rk2818_timer; diff --git a/arch/arm/mach-rk2818/devices.c b/arch/arm/mach-rk2818/devices.c index 8b27b4c5ccde..65d1ed19279b 100644 --- a/arch/arm/mach-rk2818/devices.c +++ b/arch/arm/mach-rk2818/devices.c @@ -168,6 +168,32 @@ struct platform_device rk2818_device_spim = { .resource = resources_spim, }; +/* rk2818 fb resource */ +static struct resource rk2818_fb_resource[] = { + [0] = { + .start = RK2818_LCDC_PHYS, + .end = RK2818_LCDC_PHYS + RK2818_LCDC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_NR_LCDC, + .end = IRQ_NR_LCDC, + .flags = IORESOURCE_IRQ, + }, +}; + +/*platform_device*/ +extern struct rk2818_fb_mach_info rk2818_fb_mach_info; + +struct platform_device rk2818_device_fb = { + .name = "rk2818-fb", + .id = 4, + .num_resources = ARRAY_SIZE(rk2818_fb_resource), + .resource = rk2818_fb_resource, + .dev = { + .platform_data = &rk2818_fb_mach_info, + } +}; //net device /* DM9000 */ static struct resource dm9k_resource[] = { diff --git a/arch/arm/mach-rk2818/devices.h b/arch/arm/mach-rk2818/devices.h index b3cc29876210..505fdff65bce 100644 --- a/arch/arm/mach-rk2818/devices.h +++ b/arch/arm/mach-rk2818/devices.h @@ -26,5 +26,5 @@ extern struct platform_device rk2818_device_i2c1; extern struct rk2818_i2c_platform_data default_i2c0_data; extern struct rk2818_i2c_platform_data default_i2c1_data; extern struct platform_device rk2818_device_dm9k; - +extern struct platform_device rk2818_device_fb; #endif diff --git a/arch/arm/mach-rk2818/include/mach/board.h b/arch/arm/mach-rk2818/include/mach/board.h index f013efb72561..244280e7f56c 100644 --- a/arch/arm/mach-rk2818/include/mach/board.h +++ b/arch/arm/mach-rk2818/include/mach/board.h @@ -35,6 +35,27 @@ struct rk2818_i2c_platform_data { void (*cfg_gpio)(struct platform_device *dev); }; +struct rk2818_fb_gpio{ + u32 display_on; + u32 lcd_cs; + u32 lcd_standby; + u32 mcu_fmk_pin; +}; + +struct rk2818_fb_iomux{ + char *data16; + char *data18; + char *data24; + char *den; + char *vsync; + char *mcu_fmk; +}; + +struct rk2818_fb_mach_info { + struct rk2818_fb_gpio *gpio; + struct rk2818_fb_iomux *iomux; +}; + /* common init routines for use by arch/arm/mach-msm/board-*.c */ void __init rk2818_add_devices(void); void __init rk2818_map_common_io(void); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 188e1ba3b69f..b2837066ee0d 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1927,6 +1927,15 @@ config FB_S3C2410_DEBUG Turn on debugging messages. Note that you can set/unset at run time through sysfs +config FB_RK2818 + tristate "RK2818 lcd control" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Framebuffer driver for RK2818 Platform,select it if you using rk2818 + config FB_SM501 tristate "Silicon Motion SM501 framebuffer support" depends on FB && MFD_SM501 diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 80232e124889..6777b5a36243 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -120,6 +120,7 @@ obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o +obj-$(CONFIG_FB_RK2818) += rk2818_fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig index f99af931d4f8..19e534aca13b 100644 --- a/drivers/video/display/Kconfig +++ b/drivers/video/display/Kconfig @@ -20,5 +20,6 @@ config DISPLAY_SUPPORT comment "Display hardware drivers" depends on DISPLAY_SUPPORT +source "drivers/video/display/screen/Kconfig" endmenu diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile index c0ea832bf171..c7d6d8b6b696 100644 --- a/drivers/video/display/Makefile +++ b/drivers/video/display/Makefile @@ -3,4 +3,4 @@ display-objs := display-sysfs.o obj-$(CONFIG_DISPLAY_SUPPORT) += display.o - +obj-$(CONFIG_DISPLAY_SUPPORT) += screen/ diff --git a/drivers/video/rk2818_fb.c b/drivers/video/rk2818_fb.c new file mode 100644 index 000000000000..324484e56ed8 --- /dev/null +++ b/drivers/video/rk2818_fb.c @@ -0,0 +1,2449 @@ +/* + * drivers/video/rk2818_fb.c + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + +#include "rk2818_fb.h" + +#ifdef CONFIG_PM +#include +#endif + +#include +#include +#include +#include +//#include + +#ifdef CONFIG_ANDROID_POWER +#include +#endif + +#include "./display/screen/screen.h" + + +#define FMK_USE_HARDTIMER 1 //frame mark use hard timer replace high timer +#define WIN1_USE_DOUBLE_BUF 1 //win1 use double buf to accelerate display +#define LANDSCAPE_USE_ROTATE 1 //rotate win1 in landscape with mcu panel + +#if 1 + #define fbprintk(msg...) printk(msg); +#else + #define fbprintk(msg...) +#endif + + +#if 1 + #define fbprintk2(msg...) printk(msg); +#else + #define fbprintk2(msg...) +#endif +/* +#define LcdReadBit(inf, addr, msk) ((inf->regbak.addr=__raw_readl(inf->preg->addr))&(msk)) +#define LcdWrReg(inf, addr, val) __raw_writel(val, inf->regbak.addr); inf->preg->addr = (val) +#define LcdRdReg(inf, addr) __raw_readl(inf->preg->addr) +#define LcdSetBit(inf, addr, msk) __raw_writel((inf->regbak.addr |= (msk)), inf->preg->addr) +#define LcdClrBit(inf, addr, msk) __raw_writel((inf->regbak.addr &= ~(msk)), inf->preg->addr) +#define LcdMskReg(inf, addr, msk, val) (inf->regbak.addr)&=~(msk); __raw_writel((inf->regbak.addr|=(val)), inf->preg->addr) +*/ +#define LcdReadBit(inf, addr, msk) ((inf->regbak.addr=inf->preg->addr)&(msk)) +#define LcdWrReg(inf, addr, val) inf->preg->addr=inf->regbak.addr=(val) +#define LcdRdReg(inf, addr) (inf->preg->addr) +#define LcdSetBit(inf, addr, msk) inf->preg->addr=((inf->regbak.addr) |= (msk)) +#define LcdClrBit(inf, addr, msk) inf->preg->addr=((inf->regbak.addr) &= ~(msk)) +#define LcdMskReg(inf, addr, msk, val) (inf->regbak.addr)&=~(msk); inf->preg->addr=(inf->regbak.addr|=(val)) + + +#define IsMcuLandscape() ((SCREEN_MCU==inf->cur_screen->type) && ((90==inf->mcu_scandir)||(270==inf->mcu_scandir))) +#define IsMcuUseFmk() ( (2==inf->cur_screen->mcu_usefmk) || ((1==inf->cur_screen->mcu_usefmk)&&IsMcuLandscape()) ) + +#define CalScaleW1(x, y) (u32)( ((u32)x*0x1000)/y) +#define CalScaleDownW0(x, y) (u32)( (x>=y) ? ( ((u32)x*0x1000)/y) : (0x1000) ) +#define CalScaleUpW0(x, y) (u32)( (x<=y) ? ( ((u32)x*0x1000)/y) : (0x1000) ) + +struct rk28fb_rgb { + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; +}; + +static struct rk28fb_rgb def_rgb_16 = { + red: { offset: 11, length: 5, }, + green: { offset: 5, length: 6, }, + blue: { offset: 0, length: 5, }, + transp: { offset: 0, length: 0, }, +}; + +struct win0_fmk { + u8 completed; + u8 enable; + u8 format; + u32 addr_y[2]; + u32 addr_uv[2]; + u16 act_w[2]; + u16 win_w[2]; + u16 win_stx[2]; + u32 addr_y2offset; + u32 addr_uv2offset; +}; + +struct win0_par { + u32 refcount; + u32 pseudo_pal[16]; + u32 y_offset; + u32 uv_offset; + + struct win0_fmk fmktmp; + struct win0_fmk fmk; + + u8 par_seted; + u8 addr_seted; +}; + + +struct win1_fmk { + u8 completed; + u8 enable; + u32 addr[2]; + u16 win_stx[2]; + u16 act_w[2]; + u32 addr2_offset; +}; + +struct win1_par { + u32 refcount; + u32 pseudo_pal[16]; + int lstblank; + struct win1_fmk fmktmp; + struct win1_fmk fmk; +}; + +struct rk2818fb_inf { + struct fb_info *win0fb; + struct fb_info *win1fb; + + void __iomem *reg_vir_base; // virtual basic address of lcdc register + u32 reg_phy_base; // physical basic address of lcdc register + u32 len; // physical map length of lcdc register + + struct clk *clk; + struct clk *dclk; //lcdc dclk + struct clk *dclk_parent; //lcdc dclk divider frequency source + struct clk *dclk_divider; //lcdc demodulator divider frequency + unsigned long dclk_rate; + + /* lcdc reg base address and backup reg */ + LCDC_REG *preg; + LCDC_REG regbak; + + int in_suspend; + + /* variable used in mcu panel */ + int mcu_needflush; + int mcu_isrcnt; + u16 mcu_scandir; + struct timer_list mcutimer; + int mcu_status; + int mcu_ebooknew; + int mcu_usetimer; + int mcu_stopflush; + struct hrtimer htimer; + int mcu_fmkstate; + + /* external memery */ + char __iomem *screen_base2; + __u32 smem_len2; + unsigned long smem_start2; + + struct rk28fb_screen lcd_info; + struct rk28fb_screen tv_info[5]; + struct rk28fb_screen hdmi_info[2]; + struct rk28fb_screen *cur_screen; + +#ifdef CONFIG_ANDROID_POWER + android_early_suspend_t early_suspend; +#endif +}; + +typedef enum _TRSP_MODE +{ + TRSP_CLOSE = 0, + TRSP_FMREG, + TRSP_FMREGEX, + TRSP_FMRAM, + TRSP_FMRAMEX, + TRSP_MASK, + TRSP_INVAL +} TRSP_MODE; + +typedef enum _FMK_STATE +{ + FMK_IDLE = 0, + FMK_INT, + FMK_PRELEFT, + FMK_PREUP, + FMK_LEFT, + FMK_UP, + FMK_ENDING + +} FMK_STATE; + + +struct platform_device *g_pdev = NULL; +static int rk2818fb_suspend(struct platform_device *pdev, pm_message_t msg); +static int win1fb_set_par(struct fb_info *info); + +#if FMK_USE_HARDTIMER +int rk2818fb_dohardtimer(void); +#endif + +#ifdef CONFIG_ANDROID_POWER +static void rk2818fb_early_suspend(android_early_suspend_t *h); +static void rk2818fb_early_resume(android_early_suspend_t *h); +#endif + + +#if 0 +#define CHK_SUSPEND(inf) \ + if(inf->in_suspend) { \ + fbprintk(">>>>>> fb is in suspend! return! \n"); \ + return -EPERM; \ + } +#else +#define CHK_SUSPEND(inf) +#endif + +static DECLARE_WAIT_QUEUE_HEAD(wq); +static int wq_condition = 0; + +void set_lcd_pin(struct platform_device *pdev, int enable) +{ + int ret =0; + struct rk2818_fb_mach_info *mach_info = pdev->dev.platform_data; + + unsigned lcd_cs = mach_info->gpio->lcd_cs&0xffff; + unsigned display_on = mach_info->gpio->display_on&0xffff; + unsigned lcd_standby = mach_info->gpio->lcd_standby&0xffff; + + int lcd_cs_pol = (mach_info->gpio->lcd_cs>>16)&0xffff; + int display_on_pol = (mach_info->gpio->display_on>>16)&0xffff; + int lcd_standby_pol = (mach_info->gpio->lcd_standby>>16)&0xffff; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + fbprintk(">>>>>> lcd_cs(%d) = %d \n", lcd_cs, enable ? lcd_cs_pol : !lcd_cs_pol); + fbprintk(">>>>>> display_on(%d) = %d \n", display_on, enable ? display_on_pol : !display_on_pol); + fbprintk(">>>>>> lcd_standby(%d) = %d \n", lcd_standby, enable ? lcd_standby_pol : !lcd_standby_pol); + + // set cs and display_on + if(mach_info->gpio->lcd_cs) + { + ret = gpio_request(lcd_cs, NULL); + if(ret != 0) + { + gpio_free(lcd_cs); + printk(KERN_ERR ">>>>>> lcd_cs gpio_request err \n "); + goto pin_err; + } + gpio_direction_output(lcd_cs, 0); + gpio_set_value(lcd_cs, enable ? lcd_cs_pol : !lcd_cs_pol); + } + if(mach_info->gpio->display_on) + { + ret = gpio_request(display_on, NULL); + if(ret != 0) + { + gpio_free(display_on); + printk(KERN_ERR ">>>>>> display_on gpio_request err \n "); + goto pin_err; + } + gpio_direction_output(display_on, 0); + gpio_set_value(display_on, enable ? display_on_pol : !display_on_pol); + } + if(mach_info->gpio->lcd_standby) + { + ret = gpio_request(lcd_standby, NULL); + if(ret != 0) + { + gpio_free(lcd_standby); + printk(KERN_ERR ">>>>>> lcd_standby gpio_request err \n "); + goto pin_err; + } + gpio_direction_output(lcd_standby, 0); + gpio_set_value(lcd_standby, enable ? lcd_standby_pol : !lcd_standby_pol); + } + + return; +pin_err: + return; +} + +int mcu_do_refresh(struct rk2818fb_inf *inf) +{ + if(inf->mcu_stopflush) return 0; + + if(SCREEN_MCU!=inf->cur_screen->type) return 0; + + // use frame mark + if(IsMcuUseFmk()) { + if(FMK_IDLE==inf->mcu_fmkstate) { + inf->mcu_fmkstate = FMK_INT; + } else { + inf->mcu_needflush = 1; + return (1); + } + return 0; + } + + // not use frame mark + if(LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) { + if(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) { + inf->mcu_needflush = 1; + } else { + if(inf->cur_screen->refresh) inf->cur_screen->refresh(REFRESH_PRE); + inf->mcu_needflush = 0; + inf->mcu_isrcnt = 0; + LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST); + } + } + return 0; +} + + +void mcutimer_callback(unsigned long arg) +{ + struct rk2818fb_inf *inf = platform_get_drvdata(g_pdev); + static int waitcnt = 0; + static int newcnt = 0; + + mod_timer(&inf->mcutimer, jiffies + HZ/10); + + switch(inf->mcu_status) + { + case MS_IDLE: + if(OUT_P16BPP4==inf->cur_screen->face) { + inf->mcu_status = MS_EBOOK; + } else { + inf->mcu_status = MS_MCU; + } + break; + case MS_MCU: + if(inf->mcu_usetimer) mcu_do_refresh(inf); + break; + case MS_EBOOK: + if(inf->mcu_ebooknew) { + inf->mcu_ebooknew = 0; + inf->mcu_status = MS_EWAITSTART; + newcnt = 0; + } + break; + case MS_EWAITSTART: + if(inf->mcu_ebooknew) { + inf->mcu_ebooknew = 0; + if(newcnt++>10) { + inf->mcu_status = MS_EWAITEND; + waitcnt = 0; + } + } else { + inf->mcu_status = MS_EWAITEND; + waitcnt = 0; + } + break; + case MS_EWAITEND: + if(0==waitcnt) { + mcu_do_refresh(inf); + } + if(waitcnt++>14) { + inf->mcu_status = MS_EEND; + } + break; + case MS_EEND: + inf->mcu_status = MS_MCU; + break; + default: + inf->mcu_status = MS_MCU; + break; + } +} + +int mcu_refresh(struct rk2818fb_inf *inf) +{ + static int mcutimer_inited = 0; + + if(SCREEN_MCU!=inf->cur_screen->type) return 0; + + if(!mcutimer_inited) { + mcutimer_inited = 1; + init_timer(&inf->mcutimer); + inf->mcutimer.function = mcutimer_callback; + inf->mcutimer.expires = jiffies + HZ/5; + inf->mcu_status = 0; + add_timer(&inf->mcutimer); + } + + inf->mcu_ebooknew = 1; + if(MS_MCU==inf->mcu_status) mcu_do_refresh(inf); + + return 0; +} + +int init_lcdc(struct fb_info *info) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + u32 reg1=0, reg2=0, msk=0, clr=0; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + fbprintk(">>>>>> inf %x ; inf->regbak%x ; inf->preg %x \n", inf, &inf->regbak, inf->preg); + fbprintk(">>>>>> %x ; %x \n", &(inf->regbak.SYS_CONFIG), &(inf->preg->SYS_CONFIG)); + // set AHB access rule and disable all windows + LcdMskReg(inf, SYS_CONFIG, + m_W1_ROLLER | m_W0_ROLLER | m_INTERIACE_EN | m_MPEG2_I2P_EN | m_W0_ROTATE | + m_W1_ENABLE |m_W0_ENABLE | m_HWC_ENABLE | m_HWC_RELOAD_EN |m_W1_INTERLACE_READ | + m_W0_INTERLACE_READ | m_STANDBY | m_W1_HWC_INCR| + m_W1_HWC_BURST | m_W0_INCR | m_W0_BURST , + v_W1_ROLLER(0) | v_W0_ROLLER(0) | v_INTERIACE_EN(0) | + v_MPEG2_I2P_EN(0) | v_W0_ROTATE(0) |v_W1_ENABLE(0) | + v_W0_ENABLE(0) | v_HWC_ENABLE(0) | v_HWC_RELOAD_EN(0) | v_W1_INTERLACE_READ(0) | + v_W0_INTERLACE_READ(0) | v_STANDBY(0) | v_W1_HWC_INCR(31) | v_W1_HWC_BURST(1) | + v_W0_INCR(31) | v_W0_BURST(1) + ); // use ahb burst32 + + // set all swap rule for every window and set water mark + reg1 = v_W0_565_RB_SWAP(0) | v_W0_YRGB_M8_SWAP(0) | + v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_CBR_R_SHIFT_SWAP(0) | v_W0_YRGB_16_SWAP(0) | + v_W0_YRGB_8_SWAP(0) | v_W0_CBR_16_SWAP(0) | v_W0_CBR_8_SWAP(0) | v_W0_YRGB_HL8_SWAP(0); + + reg2 = v_W1_565_RB_SWAP(0) | v_W1_16_SWAP(0) | v_W1_8_SWAP(0) | + v_W1_R_SHIFT_SWAP(0) | v_OUTPUT_BG_SWAP(0) | v_OUTPUT_RB_SWAP(0) | v_OUTPUT_RG_SWAP(0) | + v_DELTA_SWAP(0) | v_DUMMY_SWAP(0); + + LcdWrReg(inf, SWAP_CTRL, reg1 | reg2); + + // and mcu holdmode; and set win1 top. + LcdMskReg(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_SELECT | m_MCU_HOLDMODE_FRAME_ST | m_MCU_BYPASSMODE_SELECT , + v_MCU_HOLDMODE_SELECT(0)| v_MCU_HOLDMODE_FRAME_ST(0) |v_MCU_BYPASSMODE_SELECT(0)); + + // disable blank out, black out, tristate out, yuv2rgb bypass + LcdMskReg(inf, BLEND_CTRL, m_W1_BLEND_EN | m_W0_BLEND_EN | m_HWC_BLEND_EN | m_W1_BLEND_FACTOR_SELECT | + m_W0_BLEND_FACTOR_SELECT | m_W0W1_OVERLAY | m_HWC_BLEND_FACTOR | m_W1_BLEND_FACTOR | m_W0_BLEND_FACTOR, + v_W1_BLEND_EN(0) | v_W0_BLEND_EN(0) | v_HWC_BLEND_EN(0) | v_W1_BLEND_FACTOR_SELECT(0) | + v_W0_BLEND_FACTOR_SELECT(0) | v_W0W1_OVERLAY(0) | v_HWC_BLEND_FACTOR(0) | v_W1_BLEND_FACTOR(0) | v_W0_BLEND_FACTOR(0) + ); + + LcdMskReg(inf, WIN0_COLOR_KEY_CTRL, m_COLORKEY_EN, v_COLORKEY_EN(0)); + LcdMskReg(inf, WIN1_COLOR_KEY_CTRL, m_COLORKEY_EN, v_COLORKEY_EN(0)); + + LcdMskReg(inf, DSP_CTRL0, m_HSYNC_POLARITY | m_VSYNC_POLARITY | m_DEN_POLARITY | m_DCLK_POLARITY | + m_COLOR_SPACE_CONVERSION | m_DITHERING_EN | m_INTERLACE_FIELD_POLARITY | + m_YUV_CLIP_MODE | m_I2P_FILTER_EN , + v_HSYNC_POLARITY(0) | v_VSYNC_POLARITY(0) | v_DEN_POLARITY(0) | v_DCLK_POLARITY(0) | v_COLOR_SPACE_CONVERSION(0) | + v_DITHERING_EN(0) | v_INTERLACE_FIELD_POLARITY(0) | v_YUV_CLIP_MODE(0) | v_I2P_FILTER_EN(0)); + + LcdMskReg(inf, DSP_CTRL1, m_BG_COLOR | m_BLANK_MODE | m_BLACK_MODE | m_W1_SD_DEFLICKER_EN | m_W1_SP_DEFLICKER_EN | + m_W0CR_SD_DEFLICKER_EN | m_W0CR_SP_DEFLICKER_EN | m_W0YRGB_SD_DEFLICKER_EN | m_W0YRGB_SP_DEFLICKER_EN, + v_BG_COLOR(0) | v_BLANK_MODE(0) | v_BLACK_MODE(0) | v_W1_SD_DEFLICKER_EN(0) | v_W1_SP_DEFLICKER_EN(0) | + v_W0CR_SD_DEFLICKER_EN(0) | v_W0CR_SP_DEFLICKER_EN(0) | v_W0YRGB_SD_DEFLICKER_EN(0) | v_W0YRGB_SP_DEFLICKER_EN(0)); + + // initialize all interrupt + clr = v_HOR_STARTCLEAR(1) | v_FRM_STARTCLEAR(1) | v_SCANNING_CLEAR(1); + + msk = v_HOR_STARTMASK(1) | v_FRM_STARTMASK(0) | v_SCANNING_MASK(1); + + LcdWrReg(inf, INT_STATUS, clr | msk); + + // let above to take effect + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + return 0; +} + +void load_screen(struct fb_info *info, bool initscreen) +{ + int ret = -EINVAL; + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct rk28fb_screen *screen = inf->cur_screen; + u16 face = screen->face; + u16 mcu_total, mcu_rwstart, mcu_csstart, mcu_rwend, mcu_csend; + u16 right_margin = screen->right_margin, lower_margin = screen->lower_margin; + u16 x_res = screen->x_res, y_res = screen->y_res; + u32 clk_rate = 0; + u32 dclk_rate = 0; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + +// if(OUT_P16BPP4==face) face = OUT_P565; + + // set the rgb or mcu + LcdMskReg(inf, MCU_TIMING_CTRL, m_MCU_OUTPUT_SELECT, v_MCU_OUTPUT_SELECT((SCREEN_MCU==screen->type)?(1):(0))); + /* + + // set out format and mcu timing + mcu_total = (screen->mcu_wrperiod*150*1000)/1000000; + if(mcu_total>31) mcu_total = 31; + if(mcu_total<3) mcu_total = 3; + mcu_rwstart = (mcu_total+1)/4 - 1; + mcu_rwend = ((mcu_total+1)*3)/4 - 1; + mcu_csstart = (mcu_rwstart>2) ? (mcu_rwstart-3) : (0); + mcu_csend = (mcu_rwend>15) ? (mcu_rwend-1) : (mcu_rwend); + + fbprintk(">> mcu_total=%d, mcu_rwstart=%d, mcu_csstart=%d, mcu_rwend=%d, mcu_csend=%d \n", + mcu_total, mcu_rwstart, mcu_csstart, mcu_rwend, mcu_csend); + + LcdMskReg(inf, MCU_TIMING_CTRL, + m_MCU_CS_ST | m_MCU_CS_END| m_MCU_RW_ST | m_MCU_RW_END | + m_MCU_WRITE_PERIOD | m_MCU_HOLDMODE_SELECT | m_MCU_HOLDMODE_FRAME_ST, + v_MCU_CS_ST(mcu_csstart) | v_MCU_CS_END(mcu_csend) | v_MCU_RW_ST(mcu_rwstart) | + v_MCU_RW_END(mcu_rwend) | v_MCU_WRITE_PERIOD(mcu_total) | + v_MCU_HOLDMODE_SELECT((SCREEN_MCU==screen->type)?(1):(0)) | v_MCU_HOLDMODE_FRAME_ST(0) + ); +*/ + // set synchronous pin polarity and data pin swap rule + LcdMskReg(inf, DSP_CTRL0, + m_DISPLAY_FORMAT | m_HSYNC_POLARITY | m_VSYNC_POLARITY | m_DEN_POLARITY | + m_DCLK_POLARITY | m_COLOR_SPACE_CONVERSION, + v_DISPLAY_FORMAT(face) | v_HSYNC_POLARITY(screen->pin_hsync) | v_VSYNC_POLARITY(screen->pin_vsync) | + v_DEN_POLARITY(screen->pin_den) | v_DCLK_POLARITY(screen->pin_dclk) | v_COLOR_SPACE_CONVERSION(0) + ); + + LcdMskReg(inf, DSP_CTRL1, m_BG_COLOR, v_BG_COLOR(0xff0000) ); + + LcdMskReg(inf, SWAP_CTRL, m_OUTPUT_RB_SWAP | m_OUTPUT_RG_SWAP | m_DELTA_SWAP | m_DUMMY_SWAP, + v_OUTPUT_RB_SWAP(screen->swap_rb) | v_OUTPUT_RG_SWAP(screen->swap_rg) | v_DELTA_SWAP(screen->swap_delta) | v_DUMMY_SWAP(screen->swap_dumy)); + + // set horizontal & vertical out timing + if(IsMcuLandscape()) + { + x_res = (screen->mcu_usefmk) ? (screen->y_res/2) : (screen->y_res); + y_res = screen->x_res; + } + if(SCREEN_MCU==inf->cur_screen->type) + { + right_margin = x_res/6; + } + + LcdMskReg(inf, DSP_HTOTAL_HS_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->hsync_len) | + v_BIT11HI(screen->hsync_len + screen->left_margin + x_res + right_margin)); + LcdMskReg(inf, DSP_HACT_ST_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->hsync_len + screen->left_margin + x_res) | + v_BIT11HI(screen->hsync_len + screen->left_margin)); + + + LcdMskReg(inf, DSP_VTOTAL_VS_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->vsync_len) | + v_BIT11HI(screen->vsync_len + screen->upper_margin + y_res + lower_margin)); + LcdMskReg(inf, DSP_VACT_ST_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->vsync_len + screen->upper_margin+y_res)| + v_BIT11HI(screen->vsync_len + screen->upper_margin)); + + LcdMskReg(inf, DSP_VS_ST_END_F1, m_BIT11LO | m_BIT11HI, v_BIT11LO(0) | v_BIT11HI(0)); + LcdMskReg(inf, DSP_VACT_ST_END_F1, m_BIT11LO | m_BIT11HI, v_BIT11LO(0) | v_BIT11HI(0)); + + // let above to take effect + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + // set lcdc clk + if(SCREEN_MCU==screen->type) screen->pixclock = 150; //mcu fix to 150 MHz + + clk_set_parent(inf->dclk_divider, inf->dclk_parent); + clk_set_parent(inf->dclk, inf->dclk_divider); + + //clk_set_parent(inf->dclk, inf->dclk_parent); + + clk_rate = clk_get_rate(inf->dclk_parent); + + dclk_rate = screen->pixclock * 1000000; + + printk(">>>>>> set lcdc dclk need %d HZ, clk_parent = %d hz \n ", screen->pixclock, clk_rate); + + if(clk_rate < dclk_rate) + { + clk_rate = dclk_rate; + ret = clk_set_rate(inf->dclk_parent, clk_rate); + if(ret) + { + printk(KERN_ERR ">>>>>> set lcdc dclk_parent faild clk_rate = %d \n ", clk_rate); + } + } + else if((clk_rate > dclk_rate) && (clk_rate % dclk_rate)) + { + clk_rate = clk_rate/dclk_rate * dclk_rate; + ret = clk_set_rate(inf->dclk_parent, clk_rate); + if(ret) + { + printk(KERN_ERR ">>>>>> set lcdc dclk_parent faild clk_rate = %d \n ", clk_rate); + } + } + + ret = clk_set_rate(inf->dclk_divider, dclk_rate); + + if(ret) + { + printk(KERN_ERR ">>>>>> set lcdc dclk_divider faild \n "); + } + + clk_enable(inf->dclk); + // clk_enable(inf->clk); + + // init screen panel + if(screen->init && initscreen) + screen->init(); +} + +static inline unsigned int chan_to_field(unsigned int chan, + struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int fb_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + unsigned int val; +// fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* true-colour, use pseudo-palette */ + if (regno < 16) { + u32 *pal = info->pseudo_palette; + val = chan_to_field(red, &info->var.red); + val |= chan_to_field(green, &info->var.green); + val |= chan_to_field(blue, &info->var.blue); + pal[regno] = val; + } + break; + default: + return -1; /* unknown type */ + } + + return 0; +} + +static int win0fb_blank(int blank_mode, struct fb_info *info) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct win0_par *par = info->par; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(blank_mode) + { + case FB_BLANK_UNBLANK: + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(1)); + par->fmktmp.enable = 1; + par->fmktmp.completed = 1; + break; + default: + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0)); + par->fmktmp.enable = 0; + par->fmktmp.completed = 1; + break; + } + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + mcu_refresh(inf); + return 0; +} + +static int win0fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct rk28fb_screen *screen = inf->cur_screen; + + u32 ScaleYUpY=0x1000, ScaleYDnY=0x1000; + u16 xpos = (var->nonstd>>8) & 0xfff; //offset in panel + u16 ypos = (var->nonstd>>20) & 0xfff; + u16 xsize = (var->grayscale>>8) & 0xfff; //visiable size in panel + u16 ysize = (var->grayscale>>20) & 0xfff; + u16 xlcd = screen->x_res; //size of panel + u16 ylcd = screen->y_res; + + if(IsMcuLandscape()) + { + xlcd = screen->y_res; + ylcd = screen->x_res; + } + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + if( 0==var->xres_virtual || 0==var->yres_virtual || + 0==var->xres || 0==var->yres || var->xres<16 || + 0==xsize || 0==ysize || xsize<16 || + ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) ) + { + printk(">>>>>> win0fb_check_var fail 1!!! \n"); + printk("0==%d || 0==%d || 0==%d || 0==%d || %d<16 \n ||0==%d || 0==%d || %d<16 ||((16!=%d)&&(32!=%d)) \n", + var->xres_virtual, var->yres_virtual, var->xres, var->yres, var->xres, xsize, ysize, xsize, + var->bits_per_pixel, var->bits_per_pixel); + return -EINVAL; + } + + if( (var->xoffset+var->xres)>var->xres_virtual || + (var->yoffset+var->yres)>var->yres_virtual || + (xpos+xsize)>xlcd || (ypos+ysize)>ylcd ) + { + printk(">>>>>> win0fb_check_var fail 2!!! \n"); + printk("(%d+%d)>%d || (%d+%d)>%d || (%d+%d)>%d || (%d+%d)>%d \n ", + var->xoffset, var->xres, var->xres_virtual, var->yoffset, var->yres, + var->yres_virtual, xpos, xsize, xlcd, ypos, ysize, ylcd); + return -EINVAL; + } + + switch(var->nonstd&0xff) + { + case 0: // rgb + switch(var->bits_per_pixel) + { + case 16: // rgb565 + var->xres_virtual = (var->xres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x1); + break; + default: // rgb888 + var->bits_per_pixel = 32; + break; + } + break; + case 1: // yuv422 + var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3); + var->xres = (var->xres + 0x3) & (~0x3); + var->xoffset = (var->xoffset) & (~0x3); + break; + case 2: // yuv4200 + var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3); + var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x3) & (~0x3); + var->yres = (var->yres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x3); + var->yoffset = (var->yoffset) & (~0x1); + break; + case 3: // yuv4201 + var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3); + var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x3) & (~0x3); + var->yres = (var->yres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x3); + var->yoffset = (var->yoffset) & (~0x1); + break; + case 4: // yuv420m + var->xres_virtual = (var->xres_virtual + 0x7) & (~0x7); + var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x7) & (~0x7); + var->yres = (var->yres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x7); + var->yoffset = (var->yoffset) & (~0x1); + break; + case 5: // yuv444 + var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3); + var->xres = (var->xres + 0x3) & (~0x3); + var->xoffset = (var->xoffset) & (~0x3); + break; + default: + printk(">>>>>> win0fb var->nonstd=%d is invalid! \n", var->nonstd); + return -EINVAL; + } + + ScaleYDnY = CalScaleDownW0(var->yres, ysize); + ScaleYUpY = CalScaleUpW0(var->yres, ysize); + + if((ScaleYDnY>0x8000) || (ScaleYUpY<=0x200)) + { + return -EINVAL; // multiple of scale down or scale up can't exceed 8 + } + + return 0; +} + +static int win0fb_set_par(struct fb_info *info) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct rk28fb_screen *screen = inf->cur_screen; + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + struct win0_par *par = info->par; + + u8 format = 0; + dma_addr_t map_dma; + u32 y_offset=0, uv_offset=0, cblen=0, crlen=0, map_size=0, smem_len=0; + u16 xres=var->xres; + u16 xpos = (var->nonstd>>8) & 0xfff; + u16 ypos = (var->nonstd>>20) & 0xfff; + u16 xsize = (var->grayscale>>8) & 0xfff; + u16 ysize = (var->grayscale>>20) & 0xfff; + u32 win0_en = var->reserved[2]; + u32 y_addr = var->reserved[3]; + u32 uv_addr = var->reserved[4]; + + u32 ScaleYUpX=0x1000, ScaleYDnX=0x1000, ScaleYUpY=0x1000, ScaleYDnY=0x1000; + u32 ScaleCbrUpX=0x1000, ScaleCbrDnX=0x1000, ScaleCbrUpY=0x1000, ScaleCbrDnY=0x1000; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + /* calculate y_offset,uv_offset,line_length,cblen and crlen */ + switch(var->nonstd&0xff) + { + case 0: // rgb + switch(var->bits_per_pixel) + { + case 16: // rgb565 + format = 1; + fix->line_length = 2 * var->xres_virtual; + y_offset = (var->yoffset*var->xres_virtual + var->xoffset)*2; + break; + case 32: // rgb888 + format = 0; + fix->line_length = 4 * var->xres_virtual; + y_offset = (var->yoffset*var->xres_virtual + var->xoffset)*4; + break; + default: + return -EINVAL; + } + break; + case 1: // yuv422 + format = 2; + fix->line_length = var->xres_virtual; + y_offset = var->yoffset*var->xres_virtual + var->xoffset; + uv_offset = var->yoffset*var->xres_virtual + var->xoffset; + cblen = crlen = (var->xres_virtual*var->yres_virtual)/2; + break; + case 2: // yuv4200 + format = 3; + fix->line_length = var->xres_virtual; + y_offset = var->yoffset*var->xres_virtual + var->xoffset; + uv_offset = (var->yoffset/2)*var->xres_virtual + var->xoffset; + cblen = crlen = (var->xres_virtual*var->yres_virtual)/4; + break; + case 3: // yuv4201 + format = 4; + fix->line_length = var->xres_virtual; + y_offset = (var->yoffset/2)*2*var->xres_virtual + (var->xoffset)*2; + uv_offset = (var->yoffset/2)*var->xres_virtual + var->xoffset; + cblen = crlen = (var->xres_virtual*var->yres_virtual)/4; + break; + case 4: // yuv420m + format = 5; + fix->line_length = var->xres_virtual; + y_offset = (var->yoffset/2)*3*var->xres_virtual + (var->xoffset)*3; + cblen = crlen = (var->xres_virtual*var->yres_virtual)/4; + break; + case 5: // yuv444 + format = 6; + fix->line_length = var->xres_virtual; + y_offset = var->yoffset*var->xres_virtual + var->xoffset; + uv_offset = var->yoffset*2*var->xres_virtual + var->xoffset*2; + cblen = crlen = (var->xres_virtual*var->yres_virtual); + break; + default: + return -EINVAL; + } + + smem_len = fix->line_length * var->yres_virtual + cblen + crlen; + map_size = PAGE_ALIGN(smem_len); + + if(y_addr && uv_addr) // buffer alloced by user + { + if (info->screen_base) { + printk(">>>>>> win0fb unmap memory(%d)! \n", info->fix.smem_len); + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start); + info->screen_base = 0; + } + fix->smem_start = y_addr; + fix->smem_len = smem_len; + fix->mmio_start = uv_addr; + + par->addr_seted = ((-1==(int)y_addr)&&(-1==(int)uv_addr)) ? 0 : 1; + } + else // driver alloce buffer + { + if ( (smem_len != fix->smem_len) || !info->screen_base ) // buffer need realloc + { + fbprintk(">>>>>> win0 buffer size is change! remap memory!\n"); + fbprintk(">>>>>> smem_len %d = %d * %d + %d + %d\n", smem_len, fix->line_length, var->yres_virtual, cblen, crlen); + fbprintk(">>>>>> map_size = %d\n", map_size); + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + msleep(50); + if (info->screen_base) { + fbprintk(">>>>>> win0fb unmap memory(%d)! \n", info->fix.smem_len); + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start); + info->screen_base = 0; + fix->smem_start = 0; + fix->smem_len = 0; + } + + info->screen_base = dma_alloc_writecombine(NULL, map_size, &map_dma, GFP_KERNEL); + if(!info->screen_base) { + printk(">>>>>> win0fb dma_alloc_writecombine fail!\n"); + return -ENOMEM; + } + memset(info->screen_base, 0x00, map_size); + fix->smem_start = map_dma; + fix->smem_len = smem_len; + fix->mmio_start = fix->smem_start + fix->line_length * var->yres_virtual; + fbprintk(">>>>>> alloc succ, smem_start=%08x, smem_len=%d, mmio_start=%d!\n", + (u32)fix->smem_start, fix->smem_len, (u32)fix->mmio_start); + } + } + + par->y_offset = y_offset; + par->uv_offset = uv_offset; + + // calculate the display phy address + y_addr = fix->smem_start + y_offset; + uv_addr = fix->mmio_start + uv_offset; + fbprintk("y_addr 0x%08x = 0x%08x + %d\n", y_addr, (u32)fix->smem_start, y_offset); + fbprintk("uv_addr 0x%08x = 0x%08x + %d\n", uv_addr, (u32)fix->mmio_start , uv_offset); + + if((var->xres>1280) && (xsize>1280)) + { + ScaleYDnX = CalScaleDownW0(var->xres, 1280); + ScaleYUpX = CalScaleUpW0(1280, xsize); + } + else + { + ScaleYDnX = CalScaleDownW0(var->xres, xsize); + ScaleYUpX = CalScaleUpW0(var->xres, xsize); + } + + ScaleYDnY = CalScaleDownW0(var->yres, ysize); + ScaleYUpY = CalScaleUpW0(var->yres, ysize); + + switch(var->nonstd&0xff) + { + case 0: // rgb + case 1:// yuv422 + if((var->xres>1280) && (xsize>1280)) + { + ScaleCbrDnX= CalScaleDownW0((var->xres/2), 1280); + ScaleCbrUpX = CalScaleUpW0((640), xsize); + } + else + { + if(var->rotate) + { + ScaleCbrDnX= CalScaleDownW0(var->xres, xsize); + ScaleCbrUpX = CalScaleUpW0(var->xres, xsize); + } + else + { + ScaleCbrDnX= CalScaleDownW0((var->xres/2), xsize); + ScaleCbrUpX = CalScaleUpW0((var->xres/2), xsize); + } + } + + ScaleCbrDnY = CalScaleDownW0(var->yres, ysize); + ScaleCbrUpY = CalScaleUpW0(var->yres, ysize); + break; + case 2: // yuv4200 + case 3: // yuv4201 + case 4: // yuv420m + if((var->xres>1280) && (xsize>1280)) + { + ScaleCbrDnX= CalScaleDownW0(var->xres/2, 1280); + ScaleCbrUpX = CalScaleUpW0(640, xsize); + } + else + { + ScaleCbrDnX= CalScaleDownW0(var->xres/2, xsize); + ScaleCbrUpX = CalScaleUpW0(var->xres/2, xsize); + } + + ScaleCbrDnY = CalScaleDownW0(var->yres/2, ysize); + ScaleCbrUpY = CalScaleUpW0(var->yres/2, ysize); + break; + case 5:// yuv444 + if((var->xres>1280) && (xsize>1280)) + { + ScaleCbrDnX= CalScaleDownW0(var->xres, 1280); + ScaleCbrUpX = CalScaleUpW0(1280, xsize); + } + else + { + ScaleCbrDnX= CalScaleDownW0(var->xres, xsize); + ScaleCbrUpX = CalScaleUpW0(var->xres, xsize); + } + ScaleCbrDnY = CalScaleDownW0(var->yres, ysize); + ScaleCbrUpY = CalScaleUpW0(var->yres, ysize); + break; + } + + xpos += LcdReadBit(inf, DSP_HACT_ST_END, m_BIT11HI); + ypos += LcdReadBit(inf, DSP_VACT_ST_END, m_BIT11HI); + + LcdWrReg(inf, WIN0_YRGB_MST, y_addr); + LcdWrReg(inf, WIN0_CBR_MST, uv_addr); + + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE | m_W0_FORMAT, + v_W0_ENABLE(win0_en) | v_W0_FORMAT(format)); + + LcdMskReg(inf, WIN0_VIR, m_WORDLO | m_WORDHI, v_VIRWIDTH(var->xres_virtual) | v_VIRHEIGHT((var->yres_virtual)) ); + LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO | m_WORDHI, v_WORDLO(xres) | v_WORDHI(var->yres)); + LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO | m_BIT11HI, v_BIT11LO(xpos) | v_BIT11HI(ypos)); + LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI, v_BIT11LO(xsize) | v_BIT11HI(ysize)); + LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleYDnX) | v_WORDHI(ScaleYDnY)); + LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleYUpX) | v_WORDHI(ScaleYUpY)); + LcdMskReg(inf, WIN0_SD_FACTOR_CBR, m_WORDLO | m_WORDHI, v_WORDLO(ScaleCbrDnX) | v_WORDHI(ScaleCbrDnY)); + LcdMskReg(inf, WIN0_SP_FACTOR_CBR, m_WORDLO | m_WORDHI, v_WORDLO(ScaleCbrUpX) | v_WORDHI(ScaleCbrUpY)); + + LcdMskReg(inf, DSP_CTRL0, m_I2P_THRESHOLD_Y | m_I2P_THRESHOLD_CBR | m_I2P_CUR_POLARITY | m_DROP_LINE_W0, + v_I2P_THRESHOLD_Y(0) | v_I2P_THRESHOLD_CBR(0)| v_I2P_CUR_POLARITY(0) | v_DROP_LINE_W0(0)); + + switch(format) + { + case 0: + LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP | m_W0_YRGB_HL8_SWAP, + v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(0)| v_W0_YRGB_M8_SWAP(0)| v_W0_CBR_8_SWAP(0) | v_W0_YRGB_HL8_SWAP(0) ); + break; + case 1: + LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP | m_W0_YRGB_HL8_SWAP, + v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(1) | v_W0_YRGB_M8_SWAP(0) | v_W0_CBR_8_SWAP(0) | v_W0_YRGB_HL8_SWAP(0) ); + break; + + case 4: + LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP | m_W0_YRGB_HL8_SWAP, + v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(0) | + v_W0_YRGB_M8_SWAP((var->rotate==0)) | v_W0_CBR_8_SWAP(0) | v_W0_YRGB_HL8_SWAP(var->rotate!=0)); + break; + default: + LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP | m_W0_YRGB_HL8_SWAP, + v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(0) | v_W0_YRGB_M8_SWAP(0) | v_W0_CBR_8_SWAP(0)| v_W0_YRGB_HL8_SWAP(0) ); + } + + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + return 0; +} + +static int win0fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct fb_var_screeninfo *var0 = &info->var; + struct fb_fix_screeninfo *fix0 = &info->fix; + struct win0_par *par = info->par; + u32 y_offset=0, uv_offset=0, y_addr=0, uv_addr=0; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(var0->nonstd&0xff) + { + case 0: // rgb + switch(var0->bits_per_pixel) + { + case 16: // rgb565 + var->xoffset = (var->xoffset) & (~0x1); + y_offset = (var->yoffset*var0->xres_virtual + var->xoffset)*2; + break; + default: // rgb888 + y_offset = (var->yoffset*var0->xres_virtual + var->xoffset)*4; + break; + } + break; + case 1: // yuv422 + var->xoffset = (var->xoffset) & (~0x3); + y_offset = var->yoffset*var0->xres_virtual + var->xoffset; + uv_offset = var->yoffset*var0->xres_virtual + var->xoffset; + break; + case 2: // yuv4200 + var->xoffset = (var->xoffset) & (~0x3); + var->yoffset = (var->yoffset) & (~0x1); + y_offset = var->yoffset*var0->xres_virtual + var->xoffset; + uv_offset = (var->yoffset/2)*var0->xres_virtual + var->xoffset; + break; + case 3: // yuv4201 + var->xoffset = (var->xoffset) & (~0x3); + var->yoffset = (var->yoffset) & (~0x1); + y_offset = (var->yoffset/2)*2*var0->xres_virtual + (var->xoffset)*2; + uv_offset = (var->yoffset/2)*var0->xres_virtual + var->xoffset; + break; + case 4: // yuv420m + var->xoffset = (var->xoffset) & (~0x7); + var->yoffset = (var->yoffset) & (~0x1); + y_offset = (var->yoffset/2)*3*var0->xres_virtual + (var->xoffset)*3; + break; + case 5: // yuv444 + var->xoffset = (var->xoffset) & (~0x3); + y_offset = var->yoffset*var0->xres_virtual + var->xoffset; + uv_offset = var->yoffset*2*var0->xres_virtual + var->xoffset*2; + break; + default: + return -EINVAL; + } + + par->y_offset = y_offset; + par->uv_offset = uv_offset; + + y_addr = fix0->smem_start + y_offset; + uv_addr = fix0->mmio_start + uv_offset; + + LcdWrReg(inf, WIN0_YRGB_MST, y_addr); + LcdWrReg(inf, WIN0_CBR_MST, uv_addr); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + // enable win0 after the win0 addr is seted + par->par_seted = 1; + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE((1==par->addr_seted)?(1):(0))); + mcu_refresh(inf); + + return 0; +} + +int win0fb_open(struct fb_info *info, int user) +{ + struct win0_par *par = info->par; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + par->par_seted = 0; + par->addr_seted = 0; + + if(par->refcount) { + printk(">>>>>> win0fb has opened! \n"); + return -EACCES; + } else { + par->refcount++; + return 0; + } +} + +int win0fb_release(struct fb_info *info, int user) +{ + struct win0_par *par = info->par; + struct fb_var_screeninfo *var0 = &info->var; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + if(par->refcount) { + par->refcount--; + + win0fb_blank(FB_BLANK_POWERDOWN, info); + // wait for lcdc stop access memory + msleep(50); + + // unmap memory + if (info->screen_base) { + printk(">>>>>> win0fb unmap memory(%d)! \n", info->fix.smem_len); + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start); + info->screen_base = 0; + info->fix.smem_start = 0; + info->fix.smem_len = 0; + } + + // clean the var param + memset(var0, 0, sizeof(struct fb_var_screeninfo)); + } + + return 0; +} + +static int win0fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct win0_par *par = info->par; + void __user *argp = (void __user *)arg; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(cmd) + { + case FB1_IOCTL_GET_PANEL_SIZE: //get panel size + { + u32 panel_size[2]; + if(IsMcuLandscape()) { + panel_size[0] = inf->cur_screen->y_res; + panel_size[1] = inf->cur_screen->x_res; + } else { + panel_size[0] = inf->cur_screen->x_res; + panel_size[1] = inf->cur_screen->y_res; + } + if(copy_to_user(argp, panel_size, 8)) return -EFAULT; + } + break; + + case FB1_IOCTL_SET_YUV_ADDR: //set y&uv address to register direct + { + u32 yuv_phy[2]; + if (copy_from_user(yuv_phy, argp, 8)) + return -EFAULT; + + yuv_phy[0] += par->y_offset; + yuv_phy[1] += par->uv_offset; + + //printk("new y_addr=%08x, new uv_addr=%08x \n", yuv_phy[0], yuv_phy[1]); + LcdWrReg(inf, WIN0_YRGB_MST, yuv_phy[0]); + LcdWrReg(inf, WIN0_CBR_MST, yuv_phy[1]); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + // enable win0 after the win0 par is seted + par->addr_seted = 1; + if(par->par_seted) { + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(1)); + mcu_refresh(inf); + } + } + break; + + case FB1_TOCTL_SET_MCU_DIR: //change MCU panel scan direction + { + fbprintk(">>>>>> change MCU panel scan direction(%d) \n", (int)arg); + + if(SCREEN_MCU!=inf->cur_screen->type) return -1; + + switch(arg) + { + case 0: + case 90: + case 180: + case 270: + { + if(inf->cur_screen->scandir) { + inf->mcu_stopflush = 1; + inf->mcu_needflush = 0; + inf->mcu_status = FMK_IDLE; + while(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) { + msleep(10); + } + msleep(10); + while(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) { + msleep(10); + } + msleep(10); + + inf->cur_screen->scandir(arg); + } + inf->mcu_scandir = arg; + load_screen(info, 0); + msleep(10); + inf->mcu_stopflush = 0; + win1fb_set_par(inf->win1fb); + } + break; + + default: + return -1; + } + } + break; + default: + break; + } + return 0; +} + +static struct fb_ops win0fb_ops = { + .owner = THIS_MODULE, + .fb_open = win0fb_open, + .fb_release = win0fb_release, + .fb_check_var = win0fb_check_var, + .fb_set_par = win0fb_set_par, + .fb_blank = win0fb_blank, + .fb_pan_display = win0fb_pan_display, + .fb_ioctl = win0fb_ioctl, + .fb_setcolreg = fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_rotate = NULL,//win0fb_rotate, +}; + +static int win1fb_blank(int blank_mode, struct fb_info *info) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct win1_par *par = info->par; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(blank_mode) + { + case FB_BLANK_UNBLANK: + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(1)); + par->fmktmp.enable = 1; + par->fmktmp.completed = 1; + break; + default: + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0)); + par->fmktmp.enable = 0; + par->fmktmp.completed = 1; + break; + } + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + mcu_refresh(inf); + return 0; +} + +static int win1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct rk28fb_screen *screen = inf->cur_screen; + u32 ScaleY = 0x1000; + u16 xpos = (var->nonstd>>8) & 0xfff; + u16 ypos = (var->nonstd>>20) & 0xfff; + u16 xlcd = screen->x_res; + u16 ylcd = screen->y_res; + u8 trspmode = (var->grayscale>>8) & 0xff; + u8 trspval = (var->grayscale) & 0xff; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + +#if (0==WIN1_USE_DOUBLE_BUF) + if(var->yres_virtual>ylcd) + var->yres_virtual = ylcd; +#endif + + if( 0==var->xres_virtual || 0==var->yres_virtual || + 0==var->xres || 0==var->yres || var->xres<16 || + trspmode>5 || trspval>16 || + ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) ) + { + printk(">>>>>> win1fb_check_var fail 1!!! \n"); + printk(">>>>>> 0==%d || 0==%d ", var->xres_virtual,var->yres_virtual); + printk("0==%d || 0==%d || %d<16 || ", var->xres,var->yres,var->xres<16); + printk("%d>5 || %d>16 \n", trspmode,trspval); + printk("bits_per_pixel=%d \n", var->bits_per_pixel); + return -EINVAL; + } + + if( (var->xoffset+var->xres)>var->xres_virtual || + (var->yoffset+var->yres)>var->yres_virtual || + (xpos+var->xres)>xlcd || (ypos+var->yres)>ylcd ) + { + printk(">>>>>> win1fb_check_var fail 2!!! \n"); + printk(">>>>>> (%d+%d)>%d || ", var->xoffset,var->xres,var->xres_virtual); + printk("(%d+%d)>%d || ", var->yoffset,var->yres,var->yres_virtual); + printk("(%d+%d)>%d || (%d+%d)>%d \n", xpos,var->xres,xlcd,ypos,var->yres,ylcd); + return -EINVAL; + } + + switch(var->bits_per_pixel) + { + case 16: // rgb565 + var->xres_virtual = (var->xres_virtual + 0x1) & (~0x1); + var->xres = (var->xres + 0x1) & (~0x1); + var->xoffset = (var->xoffset) & (~0x1); + break; + default: // rgb888 + var->bits_per_pixel = 32; + break; + } + + // ScaleY = CalScaleW1(var->yres, ysize); + + if((ScaleY>0x8000) ||(ScaleY<0x200)) + { + return (-EINVAL); // multiple of scale down or scale up can't exceed 8 + } + + return 0; +} + +static int win1fb_set_par(struct fb_info *info) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + struct rk28fb_screen *screen = inf->cur_screen; + struct win1_par *par = info->par; + + u8 format = 0; + dma_addr_t map_dma; + u32 offset=0, addr=0, map_size=0, smem_len=0; + u16 xpos = (var->nonstd>>8) & 0xfff; + u16 ypos = (var->nonstd>>20) & 0xfff; + u16 xres = var->xres, yres = var->yres, xres_virtual = var->xres_virtual; + // u8 trspmode = TRSP_FMREG; //(var->grayscale>>8) & 0xff; + // u8 trspmode = TRSP_CLOSE; // ²»Ê¹ÓÃÓ²¼þµÄ°ë͸²Ù×÷. + u8 trspmode = TRSP_CLOSE; // ½«Ö¸¶¨µÄ ÏñËØ value (ȱʡÊÇ ºÚÉ«(0, 0, 0) ), ÉèÖÃΪ ȫ͸. + u8 trspval = 1; //(var->grayscale) & 0xff; + u32 i; + + //the below code is not correct, make we can't see alpha picture. + //u8 trspmode = (var->grayscale>>8) & 0xff; + //u8 trspval = (var->grayscale) & 0xff; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(var->bits_per_pixel) + { + case 16: // rgb565 + format = 1; + fix->line_length = 2 * var->xres_virtual; + offset = (var->yoffset*var->xres_virtual + var->xoffset)*2; + break; + case 32: // rgb888 + default: + format = 0; + fix->line_length = 4 * var->xres_virtual; + offset = (var->yoffset*var->xres_virtual + var->xoffset)*4; + break; + } + + smem_len = fix->line_length * var->yres_virtual; + map_size = PAGE_ALIGN(smem_len); + +#if WIN1_USE_DOUBLE_BUF + if( var->yres_virtual == 2*screen->y_res ) { + inf->mcu_usetimer = 0; + } + if(0==fix->smem_len) { + smem_len = smem_len*2; + map_size = PAGE_ALIGN(smem_len); + fbprintk(">>>>>> first alloc, alloc double!!! \n "); + } +#endif + +#if WIN1_USE_DOUBLE_BUF + if (smem_len > fix->smem_len) // buffer need realloc +#else + if (smem_len != fix->smem_len) // buffer need realloc +#endif + { + fbprintk(">>>>>> win1 buffer size is change(%d->%d)! remap memory!\n",fix->smem_len, smem_len); + fbprintk(">>>>>> smem_len %d = %d * %d \n", smem_len, fix->line_length, var->yres_virtual); + fbprintk(">>>>>> map_size = %d\n", map_size); + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + msleep(50); + if (info->screen_base) { + printk(">>>>>> win1fb unmap memory(%d)! \n", info->fix.smem_len); + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len), info->screen_base, info->fix.smem_start); + info->screen_base = 0; + fix->smem_start = 0; + fix->smem_len = 0; + } + + info->screen_base = dma_alloc_writecombine(NULL, map_size, &map_dma, GFP_KERNEL); + if(!info->screen_base) { + printk(">>>>>> win1fb dma_alloc_writecombine fail!\n"); + return -ENOMEM; + } + memset(info->screen_base, 0, map_size); + fix->smem_start = map_dma; + fix->smem_len = smem_len; + fbprintk(">>>>>> alloc succ, mem=%08x, len=%d!\n", (u32)fix->smem_start, fix->smem_len); + } + + addr = fix->smem_start + offset; + + if(TRSP_FMREGEX==trspmode) trspmode = TRSP_FMREG; + if(TRSP_FMRAMEX==trspmode) trspmode = TRSP_FMRAM; + + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE|m_W1_FORMAT, v_W1_ENABLE(1)|v_W1_FORMAT(format)); + + xpos += (screen->left_margin + screen->hsync_len); + ypos += (screen->upper_margin + screen->vsync_len); + + LcdWrReg(inf, WIN1_YRGB_MST, addr); + LcdWrReg(inf, WIN1_VIR_MST, fix->smem_start); + + LcdMskReg(inf, WIN1_DSP_ST, m_BIT11LO|m_BIT11HI, v_BIT11LO(xpos) | v_BIT11HI(ypos)); + LcdMskReg(inf, WIN1_DSP_INFO, m_BIT11LO|m_BIT11HI, v_BIT11LO(xres) | v_BIT11HI(yres)); + + LcdMskReg(inf, WIN1_VIR, m_WORDLO | m_WORDHI , v_WORDLO(xres_virtual) | v_WORDHI(var->yres_virtual)); + LcdMskReg(inf, WIN1_ACT_INFO, m_WORDLO | m_WORDHI, v_WORDLO(xres) | v_WORDHI(yres)); + + LcdMskReg(inf, BLEND_CTRL, m_W1_BLEND_EN | m_W1_BLEND_FACTOR_SELECT | m_W1_BLEND_FACTOR, + v_W1_BLEND_EN((TRSP_FMREG==trspmode) || (TRSP_MASK==trspmode)) | + v_W1_BLEND_FACTOR_SELECT(TRSP_FMRAM==trspmode) | v_W1_BLEND_FACTOR(trspval)); //͸Ã÷¶È + + if(1==format) //rgb565 + { + LcdMskReg(inf, SWAP_CTRL, m_W1_8_SWAP | m_W1_16_SWAP | m_W1_R_SHIFT_SWAP | m_W1_565_RB_SWAP, + v_W1_8_SWAP(0) | v_W1_16_SWAP(0) | v_W1_R_SHIFT_SWAP(0) | v_W1_565_RB_SWAP(0) ); + } + else + { + LcdMskReg(inf, SWAP_CTRL, m_W1_8_SWAP | m_W1_16_SWAP | m_W1_R_SHIFT_SWAP | m_W1_565_RB_SWAP, + v_W1_8_SWAP(0) | v_W1_16_SWAP(0) | v_W1_R_SHIFT_SWAP(0) | v_W1_565_RB_SWAP(0) ); + } + + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + return 0; +} + +static int win1fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct rk28fb_screen *screen = inf->cur_screen; + struct fb_var_screeninfo *var1 = &info->var; + struct fb_fix_screeninfo *fix1 = &info->fix; + struct win1_par *par = info->par; + u32 offset = 0, addr = 0; + u32 i=0; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(var1->bits_per_pixel) + { + case 16: // rgb565 + var->xoffset = (var->xoffset) & (~0x1); + offset = (var->yoffset*var1->xres_virtual + var->xoffset)*2; + break; + case 32: // rgb888 + offset = (var->yoffset*var1->xres_virtual + var->xoffset)*4; + break; + default: + return -EINVAL; + } + + addr = fix1->smem_start + offset; + + fbprintk("info->screen_base = %8x ; fix1->smem_len = %d , addr = %8x\n",info->screen_base, fix1->smem_len, addr); + + LcdWrReg(inf, WIN1_YRGB_MST, addr); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + mcu_refresh(inf); + + // flush end when wq_condition=1 in mcu panel, but not in rgb panel + if(SCREEN_MCU == inf->cur_screen->type) { + wait_event_interruptible_timeout(wq, wq_condition, HZ/20); + wq_condition = 0; + } else { + wq_condition = 0; + wait_event_interruptible_timeout(wq, wq_condition, HZ/20); + } + + return 0; +} + + +static int win1fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + struct rk2818fb_inf *inf = dev_get_drvdata(info->device); + struct rk2818_fb_mach_info *mach_info = info->device->platform_data; + unsigned display_on; + int display_on_pol; + + fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + CHK_SUSPEND(inf); + + switch(cmd) + { + case FB0_IOCTL_STOP_TIMER_FLUSH: //stop timer flush mcu panel after android is runing + if(1==arg) + { + inf->mcu_usetimer = 0; + } + break; + + case FB0_IOCTL_SET_PANEL: + if(arg>7) return -1; + + /* Black out, because some display device need clock to standby */ + //LcdMskReg(inf, DSP_CTRL_REG1, m_BLACK_OUT, v_BLACK_OUT(1)); + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0)); + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0)); + LcdMskReg(inf, DSP_CTRL1, m_BLACK_MODE, v_BLACK_MODE(1)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + if(inf->cur_screen) + { + if(inf->cur_screen->standby) inf->cur_screen->standby(1); + // operate the display_on pin to power down the lcd + if(SCREEN_RGB==inf->cur_screen->type || SCREEN_MCU==inf->cur_screen->type) + { + if(mach_info && mach_info->gpio && mach_info->gpio->display_on) + { + display_on = mach_info->gpio->display_on&0xffff; + display_on_pol = (mach_info->gpio->display_on>>16)&0xffff; + gpio_direction_output(display_on, 0); + gpio_set_value(display_on, !display_on_pol); + } + } + } + + /* Load the new device's param */ + switch(arg) + { + case 0: inf->cur_screen = &inf->lcd_info; break; //lcd + case 1: inf->cur_screen = &inf->tv_info[0]; break; //tv ntsc cvbs + case 2: inf->cur_screen = &inf->tv_info[1]; break; //tv pal cvbs + case 3: inf->cur_screen = &inf->tv_info[2]; break; //tv 480 ypbpr + case 4: inf->cur_screen = &inf->tv_info[3]; break; //tv 576 ypbpr + case 5: inf->cur_screen = &inf->tv_info[4]; break; //tv 720 ypbpr + case 6: inf->cur_screen = &inf->hdmi_info[0]; break; //hdmi 576 + case 7: inf->cur_screen = &inf->hdmi_info[1]; break; //hdmi 720 + default: break; + } + load_screen(info, 1); + mcu_refresh(inf); + break; + default: + break; + } + return 0; +} + + +static struct fb_ops win1fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = win1fb_check_var, + .fb_set_par = win1fb_set_par, + .fb_blank = win1fb_blank, + .fb_pan_display = win1fb_pan_display, + .fb_ioctl = win1fb_ioctl, + .fb_setcolreg = fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL,//fb_set_cursor, +}; + + +static irqreturn_t rk2818fb_irq(int irq, void *dev_id) +{ + struct platform_device *pdev = (struct platform_device*)dev_id; + struct rk2818fb_inf *inf = platform_get_drvdata(pdev); + if(!inf) + return IRQ_HANDLED; + + //fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__); + + LcdMskReg(inf, INT_STATUS, m_FRM_STARTCLEAR, v_FRM_STARTCLEAR(1)); + + if(SCREEN_MCU == inf->cur_screen->type) + { + inf->mcu_isrcnt = !inf->mcu_isrcnt; + if(inf->mcu_isrcnt) + return IRQ_HANDLED; + + if(IsMcuUseFmk()) + { + if(inf->mcu_needflush) { + if(FMK_IDLE==inf->mcu_fmkstate || FMK_ENDING==inf->mcu_fmkstate) { + inf->mcu_fmkstate = FMK_INT; + inf->mcu_needflush = 0; + fbprintk2("A "); + } else { + return IRQ_HANDLED; + } + } else { + if(FMK_ENDING==inf->mcu_fmkstate) { + if(inf->cur_screen->refresh) + inf->cur_screen->refresh(REFRESH_END); + inf->mcu_fmkstate = FMK_IDLE; + } else { + return IRQ_HANDLED; + } + } + } + else + { + if(inf->mcu_needflush) { + if(inf->cur_screen->refresh) + inf->cur_screen->refresh(REFRESH_PRE); + inf->mcu_needflush = 0; + LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST); + } else { + if(inf->cur_screen->refresh) + inf->cur_screen->refresh(REFRESH_END); + } + } + } + + wq_condition = 1; + wake_up_interruptible(&wq); + + return IRQ_HANDLED; +} + + +static irqreturn_t rk2818fb_irqfmk(int irq, void *dev_id) +{ + struct platform_device *pdev = (struct platform_device*)dev_id; + struct rk2818fb_inf *inf = platform_get_drvdata(pdev); + struct rk28fb_screen *screen; + struct win0_par *w0par; + struct win1_par *w1par; + u16 hact_st = 0; + static u8 leap_cnt = 0; + u16 tmp = 1; + + if(!inf) return IRQ_HANDLED; + + screen = inf->cur_screen; + w0par = inf->win0fb->par; + w1par = inf->win1fb->par; + + if(0==screen->mcu_usefmk) { + inf->mcu_fmkstate = FMK_IDLE; + return IRQ_HANDLED; + } + + hact_st = LcdReadBit(inf, DSP_HACT_ST_END, m_BIT11HI); + + switch(inf->mcu_fmkstate) + { + case FMK_INT: // ¿ª¶¨Ê±Æ÷(FMKµ½) + if(0==irq) return IRQ_HANDLED; + if(screen->mcu_usefmk && IsMcuLandscape()) + { + if(leap_cnt) { leap_cnt--; return IRQ_HANDLED; } //ÊúÆÁתºáÆÁ¶ªµô2¸öÖжÏÒÔͬ²½ + if(w0par->fmktmp.completed) { w0par->fmk = w0par->fmktmp; w0par->fmktmp.completed = 0; } + if(w1par->fmktmp.completed) { w1par->fmk = w1par->fmktmp; w1par->fmktmp.completed = 0; } + inf->mcu_fmkstate = FMK_PRELEFT; + } else if ( (2==screen->mcu_usefmk) && (!IsMcuLandscape()) ) { + leap_cnt = 2; + inf->mcu_fmkstate = FMK_PREUP; + } else { + leap_cnt = 0; + inf->mcu_fmkstate = FMK_IDLE; + break; + } +#if FMK_USE_HARDTIMER + // rockchip_usertimer_start(500000/screen->mcu_frmrate, rk28fb_dohardtimer); +#else + // hrtimer_start(&inf->htimer,ktime_set(0,(450000000/screen->mcu_frmrate)),HRTIMER_MODE_REL); +#endif + break; + + case FMK_PRELEFT: // ËÍ×ó°ëÆÁ(¶¨Ê±Æ÷µ½) + if(0!=irq) return IRQ_HANDLED; + if(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) { + inf->mcu_fmkstate = FMK_IDLE; + printk("L failed! \n"); + return IRQ_HANDLED; + } + if (screen->disparea) screen->disparea(0); + + if (w0par->fmk.enable && w0par->fmk.addr_y[0]) + { + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE|m_W0_FORMAT, v_W0_ENABLE(1)|v_W0_FORMAT(w0par->fmk.format)); + LcdWrReg(inf, WIN0_YRGB_MST, w0par->fmk.addr_y[0]); + LcdWrReg(inf, WIN0_CBR_MST, w0par->fmk.addr_uv[0]); + LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO, v_WORDLO(w0par->fmk.act_w[0])); + LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO, v_BIT11LO(w0par->fmk.win_stx[0]+hact_st)); + LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO, v_BIT11LO(w0par->fmk.win_w[0])); + w0par->fmk.addr_y[1] = w0par->fmk.addr_y[0] + w0par->fmk.addr_y2offset; + w0par->fmk.addr_uv[1] = w0par->fmk.addr_uv[0] + w0par->fmk.addr_uv2offset; + } + else + { + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0)); + } + + if (w1par->fmk.enable && w1par->fmk.addr[0]) // Win1 + { + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(1)); + LcdWrReg(inf, WIN1_YRGB_MST, w1par->fmk.addr[0]); + LcdMskReg(inf, WIN1_DSP_ST, m_BIT11LO, v_BIT11LO(w1par->fmk.win_stx[0]+hact_st)); + LcdMskReg(inf, WIN1_ACT_INFO, m_BIT11LO, v_BIT11LO(w1par->fmk.act_w[0])); + w1par->fmk.addr[1] = w1par->fmk.addr[0] + w1par->fmk.addr2_offset; + } + else + { + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0)); + } + + LcdSetBit(inf,MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + inf->mcu_fmkstate = FMK_LEFT; + fbprintk2("L "); + break; + + case FMK_LEFT: // ËÍÓÒ°ëÆÁ(FMKµ½) + if(0==irq) return IRQ_HANDLED; + while(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) { + udelay(25); + if(tmp) printk("X "); + tmp = 0; + } + if(screen->disparea) screen->disparea(1); + + if (w0par->fmk.enable && w0par->fmk.addr_y[1]) // win0 + { + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE|m_W0_FORMAT, v_W0_ENABLE(1)|v_W0_FORMAT(w0par->fmk.format)); + LcdWrReg(inf, WIN0_YRGB_MST, w0par->fmk.addr_y[1]); + LcdWrReg(inf, WIN0_CBR_MST, w0par->fmk.addr_uv[1]); + LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO, v_WORDLO(w0par->fmk.act_w[1])); + LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO, v_BIT11LO(w0par->fmk.win_stx[1]+hact_st)); + LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO, v_BIT11LO(w0par->fmk.win_w[1])); + } + else + { + LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0)); + } + + if (w1par->fmk.enable && w1par->fmk.addr[1]) // win1 + { + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(1)); + LcdWrReg(inf, WIN1_YRGB_MST, w1par->fmk.addr[1]); + LcdMskReg(inf, WIN1_DSP_ST, m_BIT11LO, v_BIT11LO(w1par->fmk.win_stx[1]+hact_st)); + LcdMskReg(inf, WIN1_ACT_INFO, m_BIT11LO, v_BIT11LO(w1par->fmk.act_w[1])); + } + else + { + LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0)); + } + + inf->mcu_isrcnt = 0; + inf->mcu_fmkstate = FMK_ENDING; + LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + fbprintk2("R "); + break; + + case FMK_PREUP: // ËÍÉϰëÆÁ(¶¨Ê±Æ÷µ½) + if(0!=irq) return IRQ_HANDLED; + if(screen->disparea) screen->disparea(2); + inf->mcu_isrcnt = 0; + inf->mcu_fmkstate = FMK_UP; + LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + fbprintk2("U "); + break; + + case FMK_UP: // ËÍϰëÆÁ(FMKµ½) + if(0==irq) return IRQ_HANDLED; + fbprintk2("D "); + inf->mcu_fmkstate = FMK_ENDING; + break; + + case FMK_ENDING: + default: + inf->mcu_fmkstate = FMK_IDLE; + break; + } + + return IRQ_HANDLED; +} + +static int __init rk2818fb_probe (struct platform_device *pdev) +{ + struct rk2818fb_inf *inf = NULL; + struct resource *res = NULL; + struct resource *mem = NULL; + struct rk2818_fb_mach_info *mach_info = NULL; + struct rk28fb_screen *screen = NULL; + int irq = 0; + int ret = 0; + +//------------------back light----------------------- + rk2818_mux_api_set(GPIOF2_APWM0_SEL_NAME, 0); + ret = gpio_request(RK2818_PIN_PF2, NULL); + if(ret != 0) + { + gpio_free(RK2818_PIN_PF2); + printk(KERN_ERR ">>>>>> back light gpio_request err \n "); + return 1; + } + gpio_direction_output(RK2818_PIN_PF2, 0); + gpio_set_value(RK2818_PIN_PF2, 0); + +//----------------------------------------- + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + /* Malloc rk2818fb_inf and set it to pdev for drvdata */ + fbprintk(">> Malloc rk2818fb_inf and set it to pdev for drvdata \n"); + inf = kmalloc(sizeof(struct rk2818fb_inf), GFP_KERNEL); + if(!inf) + { + dev_err(&pdev->dev, ">> inf kmalloc fail!"); + ret = -ENOMEM; + goto release_drvdata; + } + fbprintk(">> rk2818fb_inf addr = 0x%x \n", inf); + memset(inf, 0, sizeof(struct rk2818fb_inf)); + platform_set_drvdata(pdev, inf); + + /* Fill screen info and set current screen */ + fbprintk(">> Fill screen info and set current screen \n"); + set_lcd_info(&inf->lcd_info); + set_tv_info(&inf->tv_info[0]); + set_hdmi_info(&inf->hdmi_info[0]); + inf->cur_screen = &inf->lcd_info; + screen = inf->cur_screen; + if(SCREEN_NULL==screen->type) + { + dev_err(&pdev->dev, ">> Please select a display device! \n"); + ret = -EINVAL; + goto release_drvdata; + } + + /* get virtual basic address of lcdc register */ + fbprintk(">> get virtual basic address of lcdc register \n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + { + dev_err(&pdev->dev, "failed to get memory registers\n"); + ret = -ENOENT; + goto release_drvdata; + } + inf->reg_phy_base = res->start; + inf->len = (res->end - res->start) + 1; + mem = request_mem_region(inf->reg_phy_base, inf->len, pdev->name); + if (mem == NULL) + { + dev_err(&pdev->dev, "failed to get memory region\n"); + ret = -ENOENT; + goto release_drvdata; + } + fbprintk("inf->reg_phy_base = 0x%08x, inf->len = %d \n", inf->reg_phy_base, inf->len); + inf->reg_vir_base = ioremap(inf->reg_phy_base, inf->len); + if (inf->reg_vir_base == NULL) + { + dev_err(&pdev->dev, "ioremap() of registers failed\n"); + ret = -ENXIO; + goto release_drvdata; + } + inf->preg = (LCDC_REG*)inf->reg_vir_base; + + /* Prepare win1 info */ + fbprintk(">> Prepare win1 info \n"); + inf->win1fb = framebuffer_alloc(sizeof(struct win1_par), &pdev->dev); + if(!inf->win1fb) + { + dev_err(&pdev->dev, ">> win1fb framebuffer_alloc fail!"); + inf->win1fb = NULL; + ret = -ENOMEM; + goto release_win1fb; + } + + strcpy(inf->win1fb->fix.id, "win1fb"); + inf->win1fb->fix.type = FB_TYPE_PACKED_PIXELS; + inf->win1fb->fix.type_aux = 0; + inf->win1fb->fix.xpanstep = 1; + inf->win1fb->fix.ypanstep = 1; + inf->win1fb->fix.ywrapstep = 0; + inf->win1fb->fix.accel = FB_ACCEL_NONE; + inf->win1fb->fix.visual = FB_VISUAL_TRUECOLOR; + inf->win1fb->fix.smem_len = 0; + inf->win1fb->fix.line_length = 0; + inf->win1fb->fix.smem_start = 0; + + inf->win1fb->var.xres = screen->x_res; + inf->win1fb->var.yres = screen->y_res; + inf->win1fb->var.bits_per_pixel = 16; + inf->win1fb->var.xres_virtual = screen->x_res; + inf->win1fb->var.yres_virtual = screen->y_res; + inf->win1fb->var.width = screen->x_res; + inf->win1fb->var.height = screen->y_res; + inf->win1fb->var.pixclock = screen->pixclock; + inf->win1fb->var.left_margin = screen->left_margin; + inf->win1fb->var.right_margin = screen->right_margin; + inf->win1fb->var.upper_margin = screen->upper_margin; + inf->win1fb->var.lower_margin = screen->lower_margin; + inf->win1fb->var.vsync_len = screen->vsync_len; + inf->win1fb->var.hsync_len = screen->hsync_len; + inf->win1fb->var.red = def_rgb_16.red; + inf->win1fb->var.green = def_rgb_16.green; + inf->win1fb->var.blue = def_rgb_16.blue; + inf->win1fb->var.transp = def_rgb_16.transp; + + inf->win1fb->var.nonstd = 0; //win1 format & ypos & xpos (ypos<<20 + xpos<<8 + format) + inf->win1fb->var.grayscale = 0; //win1 transprent mode & value(mode<<8 + value) + inf->win1fb->var.activate = FB_ACTIVATE_NOW; + inf->win1fb->var.accel_flags = 0; + inf->win1fb->var.vmode = FB_VMODE_NONINTERLACED; + + inf->win1fb->fbops = &win1fb_ops; + inf->win1fb->flags = FBINFO_FLAG_DEFAULT; + inf->win1fb->pseudo_palette = ((struct win1_par*)inf->win1fb->par)->pseudo_pal; + inf->win1fb->screen_base = 0; + + memset(inf->win1fb->par, 0, sizeof(struct win1_par)); + + /* Prepare win0 info */ + fbprintk(">> Prepare win0 info \n"); + inf->win0fb = framebuffer_alloc(sizeof(struct win0_par), &pdev->dev); + if(!inf->win0fb) + { + dev_err(&pdev->dev, ">> win0fb framebuffer_alloc fail!"); + inf->win0fb = NULL; + ret = -ENOMEM; + goto release_win0fb; + } + + strcpy(inf->win0fb->fix.id, "win0fb"); + inf->win0fb->fix.type = FB_TYPE_PACKED_PIXELS; + inf->win0fb->fix.type_aux = 0; + inf->win0fb->fix.xpanstep = 1; + inf->win0fb->fix.ypanstep = 1; + inf->win0fb->fix.ywrapstep = 0; + inf->win0fb->fix.accel = FB_ACCEL_NONE; + inf->win0fb->fix.visual = FB_VISUAL_TRUECOLOR; + inf->win0fb->fix.smem_len = 0; + inf->win0fb->fix.line_length = 0; + inf->win0fb->fix.smem_start = 0; + + inf->win0fb->var.xres = screen->x_res; + inf->win0fb->var.yres = screen->y_res; + inf->win0fb->var.bits_per_pixel = 16; + inf->win0fb->var.xres_virtual = screen->x_res; + inf->win0fb->var.yres_virtual = screen->y_res; + inf->win0fb->var.width = screen->x_res; + inf->win0fb->var.height = screen->y_res; + inf->win0fb->var.pixclock = screen->pixclock; + inf->win0fb->var.left_margin = screen->left_margin; + inf->win0fb->var.right_margin = screen->right_margin; + inf->win0fb->var.upper_margin = screen->upper_margin; + inf->win0fb->var.lower_margin = screen->lower_margin; + inf->win0fb->var.vsync_len = screen->vsync_len; + inf->win0fb->var.hsync_len = screen->hsync_len; + inf->win0fb->var.red = def_rgb_16.red; + inf->win0fb->var.green = def_rgb_16.green; + inf->win0fb->var.blue = def_rgb_16.blue; + inf->win0fb->var.transp = def_rgb_16.transp; + + inf->win0fb->var.nonstd = 0; //win0 format & ypos & xpos (ypos<<20 + xpos<<8 + format) + inf->win0fb->var.grayscale = ((inf->win0fb->var.yres<<20)&0xfff00000) + ((inf->win0fb->var.xres<<8)&0xfff00);//win0 xsize & ysize + inf->win0fb->var.activate = FB_ACTIVATE_NOW; + inf->win0fb->var.accel_flags = 0; + inf->win0fb->var.vmode = FB_VMODE_NONINTERLACED; + + inf->win0fb->fbops = &win0fb_ops; + inf->win0fb->flags = FBINFO_FLAG_DEFAULT; + inf->win0fb->pseudo_palette = ((struct win0_par*)inf->win0fb->par)->pseudo_pal; + inf->win0fb->screen_base = 0; + + memset(inf->win0fb->par, 0, sizeof(struct win0_par)); + + /* Init all lcdc and lcd before register_framebuffer. */ + /* because after register_framebuffer, the win1fb_check_par and winfb_set_par execute immediately */ + fbprintk(">> Init all lcdc and lcd before register_framebuffer \n"); + init_lcdc(inf->win1fb); + inf->clk = clk_get(&pdev->dev, "lcdc_hclk"); + if (!inf->clk || IS_ERR(inf->clk)) + { + printk(KERN_ERR "failed to get lcdc_hclk source\n"); + ret = -ENOENT; + goto unregister_win1fb; + } + + clk_enable(inf->clk ); + + inf->dclk = clk_get(&pdev->dev, "lcdc"); + if (!inf->dclk || IS_ERR(inf->dclk)) + { + printk(KERN_ERR "failed to get lcd dclock source\n"); + ret = -ENOENT; + goto unregister_win1fb; + } + inf->dclk_parent = clk_get(&pdev->dev, "codec_pll"); + if (!inf->dclk_parent || IS_ERR(inf->dclk_parent)) + { + printk(KERN_ERR "failed to get lcd dclock parent source\n"); + ret = -ENOENT; + goto unregister_win1fb; + } + inf->dclk_divider= clk_get(&pdev->dev, "lcdc_divider"); + if (!inf->dclk_divider || IS_ERR(inf->dclk_divider)) + { + printk(KERN_ERR "failed to get lcd clock lcdc_divider source \n"); + ret = -ENOENT; + goto unregister_win1fb; + } + + printk("got and enabled clock\n"); + + mach_info = pdev->dev.platform_data; + if(mach_info) + { + if( OUT_P888==inf->lcd_info.face || + OUT_P888==inf->tv_info[0].face || + OUT_P888==inf->hdmi_info[0].face ) // set lcdc iomux + { + printk("set iomux\n"); + rk2818_mux_api_set(mach_info->iomux->data24, 1); + } + else + { + rk2818_mux_api_set(mach_info->iomux->data18, 1); + } + rk2818_mux_api_set(mach_info->iomux->den, 1); + rk2818_mux_api_set(mach_info->iomux->vsync, 1); + } + + set_lcd_pin(pdev, 1); + mdelay(10); + g_pdev = pdev; + inf->mcu_usetimer = 1; + load_screen(inf->win1fb, 1); + + /* Register framebuffer(win1fb & win0fb) */ + fbprintk(">> Register framebuffer(win1fb & win0fb) \n"); + ret = register_framebuffer(inf->win1fb); + if(ret<0) + { + printk(">> win1fb register_framebuffer fail!\n"); + ret = -EINVAL; + goto release_win0fb; + } + +// ret = register_framebuffer(inf->win0fb); + if(ret<0) + { + printk(">> win0fb register_framebuffer fail!\n"); + ret = -EINVAL; + goto unregister_win1fb; + } + +#ifdef CONFIG_ANDROID_POWER + inf->early_suspend.suspend = rk2818fb_early_suspend; + inf->early_suspend.resume = rk2818fb_early_resume; + inf->early_suspend.level= 0x0; + android_register_early_suspend(&inf->early_suspend); +#endif + + /* get and request irq */ + fbprintk(">> get and request irq \n"); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq for device\n"); + ret = -ENOENT; + goto release_irq; + } + ret = request_irq(irq, rk2818fb_irq, IRQF_DISABLED, pdev->name, pdev); + if (ret) { + dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret); + ret = -EBUSY; + goto release_irq; + } + + if((mach_info->iomux->mcu_fmk) && (mach_info->gpio->mcu_fmk_pin)) + { + rk2818_mux_api_set(mach_info->iomux->mcu_fmk, mach_info->gpio->mcu_fmk_pin); + ret = request_irq(gpio_to_irq(mach_info->gpio->mcu_fmk_pin), rk2818fb_irqfmk, GPIOEdgelFalling, pdev->name, pdev); + if (ret) + { + dev_err(&pdev->dev, "cannot get fmk irq %d - err %d\n", irq, ret); + ret = -EBUSY; + goto release_irq; + } + } + +#if (0==FMK_USE_HARDTIMER) + hrtimer_init(&inf->htimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + inf->htimer.function = rk2818_fb_dohtimer; +#endif + + return ret; + +release_fmkirq: + if(mach_info->gpio->mcu_fmk_pin) + free_irq(gpio_to_irq(mach_info->gpio->mcu_fmk_pin), pdev); +release_irq: + if(irq>=0) + free_irq(irq, pdev); +unregister_win1fb: + unregister_framebuffer(inf->win1fb); +release_win0fb: + if(inf->win0fb) + framebuffer_release(inf->win0fb); + inf->win0fb = NULL; +release_win1fb: + if(inf->win1fb) + framebuffer_release(inf->win1fb); + inf->win1fb = NULL; +release_drvdata: + if(inf && inf->reg_vir_base) + iounmap(inf->reg_vir_base); + if(inf && mem) + release_mem_region(inf->reg_phy_base, inf->len); + if(inf) + kfree(inf); + platform_set_drvdata(pdev, NULL); + return ret; +} + +static int rk2818fb_remove(struct platform_device *pdev) +{ + struct rk2818fb_inf *inf = platform_get_drvdata(pdev); + struct fb_info *info = NULL; + pm_message_t msg; + struct rk2818_fb_mach_info *mach_info = NULL; + int irq = 0; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + if(!inf) { + printk("inf==0, rk2818_fb_remove fail! \n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq >0) + { + free_irq(irq, pdev); + } + + mach_info = pdev->dev.platform_data; + if(mach_info->gpio->mcu_fmk_pin) + { + free_irq(gpio_to_irq(mach_info->gpio->mcu_fmk_pin), pdev); + } + +#ifdef CONFIG_ANDROID_POWER + android_unregister_early_suspend(&inf->early_suspend); +#endif + + set_lcd_pin(pdev, 0); + + // blank the lcdc + if(inf->win0fb) + win0fb_blank(FB_BLANK_POWERDOWN, inf->win0fb); + if(inf->win1fb) + win1fb_blank(FB_BLANK_POWERDOWN, inf->win1fb); + + // suspend the lcdc + rk2818fb_suspend(pdev, msg); + + // unmap memory and release framebuffer + if(inf->win0fb) { + info = inf->win0fb; + if (info->screen_base) { + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start); + info->screen_base = 0; + info->fix.smem_start = 0; + info->fix.smem_len = 0; + } + unregister_framebuffer(inf->win0fb); + framebuffer_release(inf->win0fb); + inf->win0fb = NULL; + } + if(inf->win1fb) { + info = inf->win1fb; + if (info->screen_base) { + dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start); + info->screen_base = 0; + info->fix.smem_start = 0; + info->fix.smem_len = 0; + } + unregister_framebuffer(inf->win1fb); + framebuffer_release(inf->win1fb); + inf->win1fb = NULL; + } + + if (inf->clk) + { + clk_disable(inf->clk); + clk_put(inf->clk); + inf->clk = NULL; + } + if (inf->dclk) + { + clk_disable(inf->dclk); + clk_put(inf->dclk); + inf->dclk = NULL; + } + + kfree(inf); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static int rk2818fb_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct rk2818fb_inf *inf = platform_get_drvdata(pdev); + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + if(!inf) { + printk("inf==0, rk2818fb_suspend fail! \n"); + return -EINVAL; + } + + if(inf->cur_screen->standby) + { + fbprintk(">>>>>> power down the screen! \n"); + inf->cur_screen->standby(1); + } + + LcdMskReg(inf, DSP_CTRL1, m_BLANK_MODE , v_BLANK_MODE(1)); + LcdMskReg(inf, SYS_CONFIG, m_STANDBY, v_STANDBY(1)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + if(!inf->in_suspend) + { + fbprintk(">>>>>> diable the lcdc clk! \n"); + msleep(100); + if (inf->dclk) + { + clk_disable(inf->dclk); + } + inf->in_suspend = 1; + } + + set_lcd_pin(pdev, 0); + + return 0; +} + + +static int rk2818fb_resume(struct platform_device *pdev) +{ + struct rk2818fb_inf *inf = platform_get_drvdata(pdev); + struct rk28fb_screen *screen = inf->cur_screen; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + if(!inf) { + printk("inf==0, rk2818fb_resume fail! \n"); + return -EINVAL; + } + + set_lcd_pin(pdev, 1); + + if(inf->in_suspend) + { + inf->in_suspend = 0; + fbprintk(">>>>>> eable the lcdc clk! \n"); + if (inf->dclk) + { + clk_enable(inf->dclk); + clk_set_rate(inf->dclk, screen->pixclock); + } + msleep(100); + } + + LcdMskReg(inf, DSP_CTRL1, m_BLANK_MODE , v_BLANK_MODE(0)); + LcdMskReg(inf, SYS_CONFIG, m_STANDBY, v_STANDBY(0)); + LcdWrReg(inf, REG_CFG_DONE, 0x01); + + if(inf->cur_screen->standby) + { + fbprintk(">>>>>> power on the screen! \n"); + inf->cur_screen->standby(0); + } + msleep(100); + + return 0; +} + + +#ifdef CONFIG_ANDROID_POWER +static void rk2818fb_early_suspend(android_early_suspend_t *h) +{ + pm_message_t msg; + + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + if(g_pdev) + { + rk2818fb_suspend(g_pdev, msg); + } + else + { + printk("g_pdev==0, rk2818fb_early_suspend fail! \n"); + return; + } +} +static void rk2818fb_early_resume(android_early_suspend_t *h) +{ + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + + if(g_pdev) + { + rk2818fb_resume(g_pdev); + } + else + { + printk("g_pdev==0, rk2818fb_early_resume fail! \n"); + return; + } +} +#endif +static void rk2818fb_shutdown(struct platform_device *pdev) +{ + struct rk2818fb_inf *inf = platform_get_drvdata(pdev); + mdelay(300); + //printk("----------------------------rk2818fb_shutdown----------------------------\n"); + set_lcd_pin(pdev, 0); + if (inf->dclk) + { + clk_disable(inf->dclk); + } + if (inf->clk) + { + clk_disable(inf->clk); + } +} + +static struct platform_driver rk2818fb_driver = { + .probe = rk2818fb_probe, + .remove = rk2818fb_remove, + .driver = { + .name = "rk2818-fb", + .owner = THIS_MODULE, + }, + .shutdown = rk2818fb_shutdown, +}; + +static int __init rk2818fb_init(void) +{ + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + return platform_driver_register(&rk2818fb_driver); +} + +static void __exit rk2818fb_exit(void) +{ + fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__); + platform_driver_unregister(&rk2818fb_driver); +} + +//subsys_initcall(rk2818fb_init); + +module_init(rk2818fb_init); +module_exit(rk2818fb_exit); + + +MODULE_AUTHOR(" zyw@rock-chips.com"); +MODULE_DESCRIPTION("Driver for rk2818 fb device"); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/video/rk2818_fb.h b/drivers/video/rk2818_fb.h new file mode 100644 index 000000000000..62d855636011 --- /dev/null +++ b/drivers/video/rk2818_fb.h @@ -0,0 +1,413 @@ +/* drivers/video/rk2818_fb.h + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 __ARCH_ARM_MACH_RK2818_FB_H +#define __ARCH_ARM_MACH_RK2818_FB_H + +/******************************************************************** +** ºê¶¨Òå * +********************************************************************/ +/* ÊäÍùÆÁµÄÊý¾Ý¸ñʽ */ +#define OUT_P888 0 +#define OUT_P666 1 +#define OUT_P565 2 +#define OUT_S888x 4 +#define OUT_CCIR656 6 +#define OUT_S888 8 +#define OUT_S888DUMY 12 +#define OUT_P16BPP4 24 //Ä£Äⷽʽ,¿ØÖÆÆ÷²¢²»Ö§³Ö + +/* Low Bits Mask */ +#define m_WORDLO (0xffff<<0) +#define m_WORDHI (0xffff<<16) +#define v_WORDLO(x) (((x)&0xffff)<<0) +#define v_WORDHI(x) (((x)&0xffff)<<16) + +#define m_BIT11LO (0x7ff<<0) +#define m_BIT11HI (0x7ff<<16) +#define v_BIT11LO(x) (((x)&0x7ff)<<0) +#define v_BIT11HI(x) (((x)&0x7ff)<<16) + + +/* SYS_CONFIG */ +#define m_W1_FORMAT (1<<0) +#define m_W0_FORMAT (7<<1) +#define m_W1_ROLLER (1<<4) +#define m_W0_ROLLER (1<<5) +#define m_INTERIACE_EN (1<<6) +#define m_MPEG2_I2P_EN (1<<7) +#define m_W0_ROTATE (1<<8) +#define m_W1_ENABLE (1<<9) +#define m_W0_ENABLE (1<<10) +#define m_HWC_ENABLE (1<<11) +#define m_HWC_RELOAD_EN (1<<12) +#define m_W1_INTERLACE_READ (1<<13) +#define m_W0_INTERLACE_READ (1<<14) +#define m_STANDBY (1<<15) +#define m_W1_HWC_INCR (31<<16) +#define m_W1_HWC_BURST (7<<21) +#define m_W0_INCR (31<<24) +#define m_W0_BURST (7<<29) +#define v_W1_FORMAT(x) (((x)&1)<<0) +#define v_W0_FORMAT(x) (((x)&7)<<1) +#define v_W1_ROLLER(x) (((x)&1)<<4) +#define v_W0_ROLLER(x) (((x)&1)<<5) +#define v_INTERIACE_EN(x) (((x)&1)<<6) +#define v_MPEG2_I2P_EN(x) (((x)&1)<<7) +#define v_W0_ROTATE(x) (((x)&1)<<8) +#define v_W1_ENABLE(x) (((x)&1)<<9) +#define v_W0_ENABLE(x) (((x)&1)<<10) +#define v_HWC_ENABLE(x) (((x)&1)<<11) +#define v_HWC_RELOAD_EN(x) (((x)&1)<<12) +#define v_W1_INTERLACE_READ(x) (((x)&1)<<13) +#define v_W0_INTERLACE_READ(x) (((x)&1)<<14) +#define v_STANDBY(x) (((x)&1)<<15) +#define v_W1_HWC_INCR(x) (((x)&31)<<16) +#define v_W1_HWC_BURST(x) (((x)&7)<<21) +#define v_W0_INCR(x) (((x)&31)<<24) +#define v_W0_BURST(x) (((x)&7)<<29) + +//LCDC_SWAP_CTRL +#define m_W1_565_RB_SWAP (1<<0) +#define m_W0_565_RB_SWAP (1<<1) +#define m_W0_YRGB_M8_SWAP (1<<2) +#define m_W0_YRGB_R_SHIFT_SWAP (1<<3) +#define m_W0_CBR_R_SHIFT_SWAP (1<<4) +#define m_W0_YRGB_16_SWAP (1<<5) +#define m_W0_YRGB_8_SWAP (1<<6) +#define m_W0_CBR_16_SWAP (1<<7) +#define m_W0_CBR_8_SWAP (1<<8) +#define m_W1_16_SWAP (1<<9) +#define m_W1_8_SWAP (1<<10) +#define m_W1_R_SHIFT_SWAP (1<<11) +#define m_OUTPUT_BG_SWAP (1<<12) +#define m_OUTPUT_RB_SWAP (1<<13) +#define m_OUTPUT_RG_SWAP (1<<14) +#define m_DELTA_SWAP (1<<15) +#define m_DUMMY_SWAP (1<<16) +#define m_W0_YRGB_HL8_SWAP (1<<17) +#define v_W1_565_RB_SWAP(x) (((x)&1)<<0) +#define v_W0_565_RB_SWAP(x) (((x)&1)<<1) +#define v_W0_YRGB_M8_SWAP(x) (((x)&1)<<2) +#define v_W0_YRGB_R_SHIFT_SWAP(x) (((x)&1)<<3) +#define v_W0_CBR_R_SHIFT_SWAP(x) (((x)&1)<<4) +#define v_W0_YRGB_16_SWAP(x) (((x)&1)<<5) +#define v_W0_YRGB_8_SWAP(x) (((x)&1)<<6) +#define v_W0_CBR_16_SWAP(x) (((x)&1)<<7) +#define v_W0_CBR_8_SWAP(x) (((x)&1)<<8) +#define v_W1_16_SWAP(x) (((x)&1)<<9) +#define v_W1_8_SWAP(x) (((x)&1)<<10) +#define v_W1_R_SHIFT_SWAP(x) (((x)&1)<<11) +#define v_OUTPUT_BG_SWAP(x) (((x)&1)<<12) +#define v_OUTPUT_RB_SWAP(x) (((x)&1)<<13) +#define v_OUTPUT_RG_SWAP(x) (((x)&1)<<14) +#define v_DELTA_SWAP(x) (((x)&1)<<15) +#define v_DUMMY_SWAP(x) (((x)&1)<<16) +#define v_W0_YRGB_HL8_SWAP(x) (((x)&1)<<17) + +//LCDC_MCU_TIMING_CTRL +#define m_MCU_WRITE_PERIOD (31<<0) +#define m_MCU_CS_ST (31<<5) +#define m_MCU_CS_END (31<<10) +#define m_MCU_RW_ST (31<<15) +#define m_MCU_RW_END (31<<20) +#define m_MCU_HOLD_STATUS (1<<26) +#define m_MCU_HOLDMODE_SELECT (1<<27) +#define m_MCU_HOLDMODE_FRAME_ST (1<<28) +#define m_MCU_RS_SELECT (1<<29) +#define m_MCU_BYPASSMODE_SELECT (1<<30) +#define m_MCU_OUTPUT_SELECT (1<<31) +#define v_MCU_WRITE_PERIOD(x) (((x)&31)<<0) +#define v_MCU_CS_ST(x) (((x)&31)<<5) +#define v_MCU_CS_END(x) (((x)&31)<<10) +#define v_MCU_RW_ST(x) (((x)&31)<<15) +#define v_MCU_RW_END(x) (((x)&31)<<20) +#define v_MCU_HOLD_STATUS(x) (((x)&1)<<26) +#define v_MCU_HOLDMODE_SELECT(x) (((x)&1)<<27) +#define v_MCU_HOLDMODE_FRAME_ST(x) (((x)&1)<<28) +#define v_MCU_RS_SELECT(x) (((x)&1)<<29) +#define v_MCU_BYPASSMODE_SELECT(x) (((x)&1)<<30) +#define v_MCU_OUTPUT_SELECT(x) (((x)&1)<<31) + +//LCDC_ BLEND_CTRL +#define m_W1_BLEND_EN (1<<0) +#define m_W0_BLEND_EN (1<<1) +#define m_HWC_BLEND_EN (1<<2) +#define m_W1_BLEND_FACTOR_SELECT (1<<3) +#define m_W0_BLEND_FACTOR_SELECT (1<<4) +#define m_W0W1_OVERLAY (1<<5) +#define m_HWC_BLEND_FACTOR (15<<12) +#define m_W1_BLEND_FACTOR (0xff<<16) +#define m_W0_BLEND_FACTOR (0xff<<24) +#define v_W1_BLEND_EN(x) (((x)&1)<<0) +#define v_W0_BLEND_EN(x) (((x)&1)<<1) +#define v_HWC_BLEND_EN(x) (((x)&1)<<2) +#define v_W1_BLEND_FACTOR_SELECT(x) (((x)&1)<<3) +#define v_W0_BLEND_FACTOR_SELECT(x) (((x)&1)<<4) +#define v_W0W1_OVERLAY(x) (((x)&1)<<5) +#define v_HWC_BLEND_FACTOR(x) (((x)&15)<<12) +#define v_W1_BLEND_FACTOR(x) (((x)&0xff)<<16) +#define v_W0_BLEND_FACTOR(x) (((x)&0xff)<<24) + +//LCDC_WIN0_COLOR_KEY_CTRL / LCDC_WIN1_COLOR_KEY_CTRL +#define m_KEYCOLOR (0xffffff<<0) +#define m_KEYCOLOR_B (0xff<<0) +#define m_KEYCOLOR_G (0xff<<8) +#define m_KEYCOLOR_R (0xff<<16) +#define m_COLORKEY_EN (1<<24) +#define v_KEYCOLOR(x) (((x)&0xffffff)<<0) +#define v_KEYCOLOR_B(x) (((x)&0xff)<<0) +#define v_KEYCOLOR_G(x) (((x)&0xff)<<8) +#define v_KEYCOLOR_R(x) (((x)&0xff)<<16) +#define v_COLORKEY_EN(x) (((x)&1)<<24) + +//LCDC_DEFLICKER_SCL_OFFSET +#define m_W0_YRGB_VSD_OFFSET (0xff<<0) +#define m_W0_YRGB_VSP_OFFSET (0xff<<8) +#define m_W1_VSD_OFFSET (0xff<<16) +#define m_W1_VSP_OFFSET (0xff<<24) +#define v_W0_YRGB_VSD_OFFSET(x) (((x)&0xff)<<0) +#define v_W0_YRGB_VSP_OFFSET(x) (((x)&0xff)<<8) +#define v_W1_VSD_OFFSET(x) (((x)&0xff)<<16) +#define v_W1_VSP_OFFSET(x) (((x)&0xff)<<24) + +//LCDC_DSP_CTRL_REG0 +#define m_DISPLAY_FORMAT (0xf<<0) +#define m_HSYNC_POLARITY (1<<4) +#define m_VSYNC_POLARITY (1<<5) +#define m_DEN_POLARITY (1<<6) +#define m_DCLK_POLARITY (1<<7) +#define m_COLOR_SPACE_CONVERSION (3<<8) +#define m_I2P_THRESHOLD_Y (0x3f<<10) +#define m_I2P_THRESHOLD_CBR (0x3f<<16) +#define m_565_TO_888_REPLICATION_EN (1<<22) +#define m_DITHERING_MODE (1<<23) +#define m_DITHERING_EN (1<<24) +#define m_DROP_LINE_W1 (1<<25) +#define m_DROP_LINE_W0 (1<<26) +#define m_I2P_CUR_POLARITY (1<<27) +#define m_INTERLACE_FIELD_POLARITY (1<<28) +#define m_YUV_CLIP_MODE (1<<29) +#define m_I2P_FILTER_EN (1<<30) +#define m_I2P_FILTER_PARAM (1<<31) +#define v_DISPLAY_FORMAT(x) (((x)&0xf)<<0) +#define v_HSYNC_POLARITY(x) (((x)&1)<<4) +#define v_VSYNC_POLARITY(x) (((x)&1)<<5) +#define v_DEN_POLARITY(x) (((x)&1)<<6) +#define v_DCLK_POLARITY(x) (((x)&1)<<7) +#define v_COLOR_SPACE_CONVERSION(x) (((x)&3)<<8) +#define v_I2P_THRESHOLD_Y(x) (((x)&0x3f)<<10) +#define v_I2P_THRESHOLD_CBR(x) (((x)&0x3f)<<16) +#define v_565_TO_888_REPLICATION_EN(x) (((x)&1)<<22) +#define v_DITHERING_MODE(x) (((x)&1)<<23) +#define v_DITHERING_EN(x) (((x)&1)<<24) +#define v_DROP_LINE_W1(x) (((x)&1)<<25) +#define v_DROP_LINE_W0(x) (((x)&1)<<26) +#define v_I2P_CUR_POLARITY(x) (((x)&1)<<27) +#define v_INTERLACE_FIELD_POLARITY(x) (((x)&1)<<28) +#define v_YUV_CLIP_MODE(x) (((x)&1)<<29) +#define v_I2P_FILTER_EN(x) (((x)&1)<<30) +#define v_I2P_FILTER_PARAM(x) (((x)&1)<<31) + +//LCDC_DSP_CTRL_REG1 +#define m_BG_COLOR (0xffffff<<0) +#define m_BG_B (0xff<<0) +#define m_BG_G (0xff<<8) +#define m_BG_R (0xff<<16) +#define m_BLANK_MODE (1<<24) +#define m_BLACK_MODE (1<<25) +#define m_W1_SD_DEFLICKER_EN (1<<26) +#define m_W1_SP_DEFLICKER_EN (1<<27) +#define m_W0CR_SD_DEFLICKER_EN (1<<28) +#define m_W0CR_SP_DEFLICKER_EN (1<<29) +#define m_W0YRGB_SD_DEFLICKER_EN (1<<30) +#define m_W0YRGB_SP_DEFLICKER_EN (1<<31) +#define v_BG_COLOR(x) (((x)&0xffffff)<<0) +#define v_BG_B(x) (((x)&0xff)<<0) +#define v_BG_G(x) (((x)&0xff)<<8) +#define v_BG_R(x) (((x)&0xff)<<16) +#define v_BLANK_MODE(x) (((x)&1)<<24) +#define v_BLACK_MODE(x) (((x)&1)<<25) +#define v_W1_SD_DEFLICKER_EN(x) (((x)&1)<<26) +#define v_W1_SP_DEFLICKER_EN(x) (((x)&1)<<27) +#define v_W0CR_SD_DEFLICKER_EN(x) (((x)&1)<<28) +#define v_W0CR_SP_DEFLICKER_EN(x) (((x)&1)<<29) +#define v_W0YRGB_SD_DEFLICKER_EN(x) (((x)&1)<<30) +#define v_W0YRGB_SP_DEFLICKER_EN(x) (((x)&1)<<31) + +//LCDC_INT_STATUS +#define m_HOR_START (1<<0) +#define m_FRM_START (1<<1) +#define m_SCANNING_FLAG (1<<2) +#define m_HOR_STARTMASK (1<<3) +#define m_FRM_STARTMASK (1<<4) +#define m_SCANNING_MASK (1<<5) +#define m_HOR_STARTCLEAR (1<<6) +#define m_FRM_STARTCLEAR (1<<7) +#define m_SCANNING_CLEAR (1<<8) +#define m_SCAN_LINE_NUM (0x7ff<<9) +#define v_HOR_START(x) (((x)&1)<<0) +#define v_FRM_START(x) (((x)&1)<<1) +#define v_SCANNING_FLAG(x) (((x)&1)<<2) +#define v_HOR_STARTMASK(x) (((x)&1)<<3) +#define v_FRM_STARTMASK(x) (((x)&1)<<4) +#define v_SCANNING_MASK(x) (((x)&1)<<5) +#define v_HOR_STARTCLEAR(x) (((x)&1)<<6) +#define v_FRM_STARTCLEAR(x) (((x)&1)<<7) +#define v_SCANNING_CLEAR(x) (((x)&1)<<8) +#define v_SCAN_LINE_NUM(x) (((x)&0x7ff)<<9) + +#define m_VIRWIDTH (0xffff<<0) +#define m_VIRHEIGHT (0xffff<<16) +#define v_VIRWIDTH(x) (((x)&0xffff)<<0) +#define v_VIRHEIGHT(x) (((x)&0xffff)<<16) + +#define m_ACTWIDTH (0xffff<<0) +#define m_ACTHEIGHT (0xffff<<16) +#define v_ACTWIDTH(x) (((x)&0xffff)<<0) +#define v_ACTHEIGHT(x) (((x)&0xffff)<<16) + +#define m_VIRST_X (0xffff<<0) +#define m_VIRST_Y (0xffff<<16) +#define v_VIRST_X(x) (((x)&0xffff)<<0) +#define v_VIRST_Y(x) (((x)&0xffff)<<16) + +#define m_PANELST_X (0x3ff<<0) +#define m_PANELST_Y (0x3ff<<16) +#define v_PANELST_X(x) (((x)&0x3ff)<<0) +#define v_PANELST_Y(x) (((x)&0x3ff)<<16) + +#define m_PANELWIDTH (0x3ff<<0) +#define m_PANELHEIGHT (0x3ff<<16) +#define v_PANELWIDTH(x) (((x)&0x3ff)<<0) +#define v_PANELHEIGHT(x) (((x)&0x3ff)<<16) + +#define m_HWC_B (0xff<<0) +#define m_HWC_G (0xff<<8) +#define m_HWC_R (0xff<<16) +#define m_W0_YRGB_HSP_OFFSET (0xff<<24) +#define m_W0_YRGB_HSD_OFFSET (0xff<<24) +#define v_HWC_B(x) (((x)&0xff)<<0) +#define v_HWC_G(x) (((x)&0xff)<<8) +#define v_HWC_R(x) (((x)&0xff)<<16) +#define v_W0_YRGB_HSP_OFFSET(x) (((x)&0xff)<<24) +#define v_W0_YRGB_HSD_OFFSET(x) (((x)&0xff)<<24) + + +//Panel display scanning +#define m_PANEL_HSYNC_WIDTH (0x3ff<<0) +#define m_PANEL_HORIZONTAL_PERIOD (0x3ff<<16) +#define v_PANEL_HSYNC_WIDTH(x) (((x)&0x3ff)<<0) +#define v_PANEL_HORIZONTAL_PERIOD(x) (((x)&0x3ff)<<16) + +#define m_PANEL_END (0x3ff<<0) +#define m_PANEL_START (0x3ff<<16) +#define v_PANEL_END(x) (((x)&0x3ff)<<0) +#define v_PANEL_START(x) (((x)&0x3ff)<<16) + +#define m_PANEL_VSYNC_WIDTH (0x3ff<<0) +#define m_PANEL_VERTICAL_PERIOD (0x3ff<<16) +#define v_PANEL_VSYNC_WIDTH(x) (((x)&0x3ff)<<0) +#define v_PANEL_VERTICAL_PERIOD(x) (((x)&0x3ff)<<16) +//----------- + +#define m_HSCALE_FACTOR (0xffff<<0) +#define m_VSCALE_FACTOR (0xffff<<16) +#define v_HSCALE_FACTOR(x) (((x)&0xffff)<<0) +#define v_VSCALE_FACTOR(x) (((x)&0xffff)<<16) + +#define m_W0_CBR_HSD_OFFSET (0xff<<0) +#define m_W0_CBR_HSP_OFFSET (0xff<<8) +#define m_W0_CBR_VSD_OFFSET (0xff<<16) +#define m_W0_CBR_VSP_OFFSET (0xff<<24) +#define v_W0_CBR_HSD_OFFSET(x) (((x)&0xff)<<0) +#define v_W0_CBR_HSP_OFFSET(x) (((x)&0xff)<<8) +#define v_W0_CBR_VSD_OFFSET(x) (((x)&0xff)<<16) +#define v_W0_CBR_VSP_OFFSET(x) (((x)&0xff)<<24) + + +#define FB0_IOCTL_STOP_TIMER_FLUSH 0x6001 +#define FB0_IOCTL_SET_PANEL 0x6002 + +#define FB1_IOCTL_GET_PANEL_SIZE 0x5001 +#define FB1_IOCTL_SET_YUV_ADDR 0x5002 +#define FB1_TOCTL_SET_MCU_DIR 0x5003 + + +/******************************************************************** +** ½á¹¹¶¨Òå * +********************************************************************/ +/* LCDCµÄ¼Ä´æÆ÷½á¹¹ */ +typedef volatile struct tagLCDC_REG +{ + /* offset 0x00~0xc0 */ + unsigned int SYS_CONFIG; //SYSTEM configure register + unsigned int SWAP_CTRL; //Data SWAP control + unsigned int MCU_TIMING_CTRL; //MCU TIMING control register + unsigned int BLEND_CTRL; //Blending control register + unsigned int WIN0_COLOR_KEY_CTRL; //Win0 blending control register + unsigned int WIN1_COLOR_KEY_CTRL; //Win1 blending control register + unsigned int DEFLICKER_SCL_OFFSET; //Deflick scaling start point offset + unsigned int DSP_CTRL0; //Display control register0 + unsigned int DSP_CTRL1; //Display control register1 + unsigned int INT_STATUS; //Interrupt status register + unsigned int WIN0_VIR; //WIN0 virtual display width/height + unsigned int WIN0_YRGB_MST; //Win0 active YRGB memory start address + unsigned int WIN0_CBR_MST; //Win0 active Cbr memory start address + unsigned int WIN0_ACT_INFO; //Win0 active window width/height + unsigned int WIN0_ROLLER_INFO; //Win0 x and y value of start point in roller mode + unsigned int WIN0_DSP_ST; //Win0 display start point on panel + unsigned int WIN0_DSP_INFO; //Win0 display width/height on panel + unsigned int WIN1_VIR; //Win1 virtual display width/height + unsigned int WIN1_YRGB_MST; //Win1 active memory start address + unsigned int WIN1_ACT_INFO; //Win1 active width /height + unsigned int WIN1_ROLLER_INFO; //Win1 x and y value of start point in roller mode + unsigned int WIN1_DSP_ST; //Win1 display start point on panel + unsigned int WIN1_DSP_INFO; //Win1 display width/height on panel + unsigned int HWC_MST; //HWC memory start address + unsigned int HWC_DSP_ST; //HWC display start point on panel + unsigned int HWC_COLOR_LUT0; //Hardware cursor color 2¡¯b01 look up table 0 + unsigned int HWC_COLOR_LUT1; //Hardware cursor color 2¡¯b10 look up table 1 + unsigned int HWC_COLOR_LUT2; //Hardware cursor color 2¡¯b11 look up table 2 + unsigned int DSP_HTOTAL_HS_END; //Panel scanning horizontal width and hsync pulse end point + unsigned int DSP_HACT_ST_END; //Panel active horizontal scanning start/end point + unsigned int DSP_VTOTAL_VS_END; //Panel scanning vertical height and vsync pulse end point + unsigned int DSP_VACT_ST_END; //Panel active vertical scanning start/end point + unsigned int DSP_VS_ST_END_F1; //Vertical scanning start point and vsync pulse end point of even filed in interlace mode + unsigned int DSP_VACT_ST_END_F1; //Vertical scanning active start/end point of even filed in interlace mode + unsigned int WIN0_SD_FACTOR_Y; //Win0 YRGB scaling down factor setting + unsigned int WIN0_SP_FACTOR_Y; //Win0 YRGB scaling up factor setting + unsigned int WIN0_CBR_SCL_OFFSET; //Win0 Cbr scaling start point offset + unsigned int WIN1_SCL_FACTOR; //Win1 scaling factor setting + unsigned int I2P_REF0_MST_Y; //I2P field 0 memory start address + unsigned int I2P_REF0_MST_CBR; //I2P field 0 memory start address + unsigned int I2P_REF1_MST_Y; //I2P field 2 memory start address + unsigned int I2P_REF1_MST_CBR; //I2P field 2 memory start address + unsigned int WIN0_YRGB_VIR_MST; //Win0 virtual memory start address + unsigned int WIN0_CBR_VIR_MST; //Win0 virtual memory start address + unsigned int WIN1_VIR_MST; //Win1 virtual memory start address + unsigned int WIN0_SD_FACTOR_CBR; //Win0 CBR scaling down factor setting + unsigned int WIN0_SP_FACTOR_CBR; //Win0 CBR scaling up factor setting + unsigned int reserved0; + unsigned int REG_CFG_DONE; //REGISTER CONFIG FINISH + unsigned int reserved1[(0x500-0xc4)/4]; + unsigned int MCU_BYPASS_WPORT; //MCU BYPASS MODE, DATA Write Port +} LCDC_REG, *pLCDC_REG; + + +extern void __init rk2818_add_device_lcdc(void); +extern int mcu_ioctl(unsigned int cmd, unsigned long arg); + +#endif -- 2.34.1