From fc00285eb664fda92852b5bd7b56cccf7b0881f4 Mon Sep 17 00:00:00 2001 From: yxj Date: Wed, 22 Feb 2012 14:37:53 +0800 Subject: [PATCH] rk30 fb:base version ,can show linux boot logo --- arch/arm/mach-rk29/include/mach/board.h | 27 - arch/arm/mach-rk30/board-rk30-sdk.c | 30 ++ arch/arm/mach-rk30/devices.c | 36 ++ arch/arm/plat-rk/include/plat/board.h | 28 + drivers/video/Kconfig | 1 + drivers/video/Makefile | 1 + drivers/video/display/Kconfig | 2 +- drivers/video/display/screen/screen.h | 6 +- drivers/video/rockchip/Kconfig | 13 + drivers/video/rockchip/Makefile | 2 + drivers/video/rockchip/chips/rk30_lcdc.c | 644 +++++++++++++++++++++++ drivers/video/rockchip/chips/rk30_lcdc.h | 503 ++++++++++++++++++ drivers/video/rockchip/rk_fb.c | 522 ++++++++++++++++++ drivers/video/rockchip/rk_fb.h | 113 ++++ 14 files changed, 1897 insertions(+), 31 deletions(-) create mode 100644 drivers/video/rockchip/Kconfig create mode 100644 drivers/video/rockchip/Makefile create mode 100644 drivers/video/rockchip/chips/rk30_lcdc.c create mode 100644 drivers/video/rockchip/chips/rk30_lcdc.h create mode 100644 drivers/video/rockchip/rk_fb.c create mode 100644 drivers/video/rockchip/rk_fb.h diff --git a/arch/arm/mach-rk29/include/mach/board.h b/arch/arm/mach-rk29/include/mach/board.h index 0773e2806b25..c63f3f6dfe1b 100755 --- a/arch/arm/mach-rk29/include/mach/board.h +++ b/arch/arm/mach-rk29/include/mach/board.h @@ -86,33 +86,6 @@ struct rk29_vmac_platform_data { #define INVALID_GPIO -1 -struct rk29lcd_info{ - u32 lcd_id; - u32 txd_pin; - u32 clk_pin; - u32 cs_pin; - int (*io_init)(void); - int (*io_deinit)(void); -}; - -struct rk29_fb_setting_info{ - u8 data_num; - u8 vsync_en; - u8 den_en; - u8 mcu_fmk_en; - u8 disp_on_en; - u8 standby_en; -}; - -struct rk29fb_info{ - u32 fb_id; - u32 mcu_fmk_pin; - struct rk29lcd_info *lcd_info; - int (*io_init)(struct rk29_fb_setting_info *fb_setting); - int (*io_deinit)(void); - int (*io_enable)(void); - int (*io_disable)(void); -}; #ifndef _LINUX_WLAN_PLAT_H_ struct wifi_platform_data { diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 98066f618d43..7e7307175e7e 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -49,6 +49,8 @@ #include "../../../drivers/spi/rk29_spim.h" #endif +#define RK30_FB0_MEM_SIZE 8*SZ_1M + /***************************************************************************************** * xpt2046 touch panel @@ -290,11 +292,37 @@ static struct mma8452_platform_data mma8452_info = { }; #endif +#ifdef CONFIG_FB_ROCKCHIP +/* rk30 fb resource */ + static struct resource resource_fb[] = { + [0] = { + .name = "fb0 buf", + .start = 0, + .end = 0,//RK30_FB0_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +/*platform_device*/ +struct platform_device device_fb = { + .name = "rk-fb", + .id = -1, + .num_resources = ARRAY_SIZE(resource_fb), + .resource = resource_fb, +}; +#endif +extern struct platform_device rk30_device_lcdc; static struct platform_device *devices[] __initdata = { #ifdef CONFIG_BACKLIGHT_RK29_BL &rk29_device_backlight, #endif +#ifdef CONFIG_FB_ROCKCHIP + &device_fb, +#endif +#ifdef CONFIG_LCDC_RK30 + &rk30_device_lcdc, +#endif }; @@ -363,6 +391,8 @@ static void __init machine_rk30_board_init(void) static void __init rk30_reserve(void) { + resource_fb[0].start = board_mem_reserve_add("fb0",RK30_FB0_MEM_SIZE); + resource_fb[0].end = resource_fb[0].start + RK30_FB0_MEM_SIZE - 1; board_mem_reserved(); } diff --git a/arch/arm/mach-rk30/devices.c b/arch/arm/mach-rk30/devices.c index 00ba803c04e0..538020fda41a 100755 --- a/arch/arm/mach-rk30/devices.c +++ b/arch/arm/mach-rk30/devices.c @@ -687,6 +687,42 @@ static struct platform_device device_nand = { }; #endif +static struct resource resource_lcdc[] = { + [0] = { + .name = "lcdc0 reg", + .start = RK30_LCDC0_PHYS, + .end = RK30_LCDC0_PHYS + RK30_LCDC0_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "lcdc1 reg", + .start = RK30_LCDC1_PHYS, + .end = RK30_LCDC1_PHYS + RK30_LCDC1_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .name = "lcdc0 irq", + .start = IRQ_LCDC0, + .end = IRQ_LCDC0, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .name = "lcdc1 irq", + .start = IRQ_LCDC1, + .end = IRQ_LCDC1, + .flags = IORESOURCE_IRQ, + }, +}; + +/*platform_device*/ +struct platform_device rk30_device_lcdc = { + .name = "rk30-lcdc", + .id = 4, + .num_resources = ARRAY_SIZE(resource_lcdc), + .resource = resource_lcdc, +}; + + #ifdef CONFIG_KEYS_RK29 extern struct rk29_keys_platform_data rk29_keys_pdata; static struct platform_device device_keys = { diff --git a/arch/arm/plat-rk/include/plat/board.h b/arch/arm/plat-rk/include/plat/board.h index c445738ea8cf..7a3b62e8cc16 100644 --- a/arch/arm/plat-rk/include/plat/board.h +++ b/arch/arm/plat-rk/include/plat/board.h @@ -40,6 +40,34 @@ struct rk29_bl_info { #define BOOT_MODE_REBOOT 6 #define BOOT_MODE_PANIC 7 +struct rk29lcd_info { + u32 lcd_id; + u32 txd_pin; + u32 clk_pin; + u32 cs_pin; + int (*io_init)(void); + int (*io_deinit)(void); +}; + +struct rk29_fb_setting_info { + u8 data_num; + u8 vsync_en; + u8 den_en; + u8 mcu_fmk_en; + u8 disp_on_en; + u8 standby_en; +}; + +struct rk29_fb_info { + u32 fb_id; + u32 mcu_fmk_pin; + struct rk29lcd_info *lcd_info; + int (*io_init)(struct rk_fb_setting_info *fb_setting); + int (*io_deinit)(void); + int (*io_enable)(void); + int (*io_disable)(void); +}; + int board_boot_mode(void); /* for USB detection */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index ce7ba837987f..b4117f636264 100755 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2439,6 +2439,7 @@ source "drivers/video/omap2/Kconfig" source "drivers/video/backlight/Kconfig" source "drivers/video/display/Kconfig" source "drivers/video/hdmi/Kconfig" +source "drivers/video/rockchip/Kconfig" if VT source "drivers/video/console/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 2ad17115b399..016839ca0b38 100755 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -126,6 +126,7 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_RK29) += rk29_fb.o +obj-$(CONFIG_FB_ROCKCHIP) += rockchip/ obj-$(CONFIG_FB_SM501) += sm501fb.o obj-$(CONFIG_FB_UDL) += udlfb.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig index 7faf10e5a2c6..1b497d4c64fb 100644 --- a/drivers/video/display/Kconfig +++ b/drivers/video/display/Kconfig @@ -6,7 +6,7 @@ menu "Display device support" config DISPLAY_SUPPORT tristate "Display panel/monitor support" - depends on FB_RK29 + depends on FB_RK29 || FB_ROCKCHIP ---help--- This framework adds support for low-level control of a display. This includes support for power. diff --git a/drivers/video/display/screen/screen.h b/drivers/video/display/screen/screen.h index 761992aa0769..d07ad0692e7c 100755 --- a/drivers/video/display/screen/screen.h +++ b/drivers/video/display/screen/screen.h @@ -34,8 +34,9 @@ typedef enum _MCU_STATUS { } MCU_STATUS; + /* Screen description */ -struct rk29fb_screen { +typedef struct rk29fb_screen { /* screen type & out face */ u16 type; u16 face; @@ -82,8 +83,7 @@ struct rk29fb_screen { int (*scandir)(u16 dir); int (*disparea)(u8 area); -}; - +} rk_screen; extern void set_lcd_info(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info); extern void set_tv_info(struct rk29fb_screen *screen); extern void set_hdmi_info(struct rk29fb_screen *screen); diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig new file mode 100644 index 000000000000..9198783073db --- /dev/null +++ b/drivers/video/rockchip/Kconfig @@ -0,0 +1,13 @@ +config FB_ROCKCHIP + tristate "Frame buffer support for Rockchip lcd controller" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Framebuffer driver for rochip based Platform +config LCDC_RK30 + tristate "Frame buffer driver support for rk30 lcdc " + depends on FB_ROCKCHIP + help + Frame buffer driver for rk30 lcdc based boards. diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile new file mode 100644 index 000000000000..184952bc7ab1 --- /dev/null +++ b/drivers/video/rockchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_FB_ROCKCHIP) += rk_fb.o +obj-$(CONFIG_LCDC_RK30) += chips/rk30_lcdc.o diff --git a/drivers/video/rockchip/chips/rk30_lcdc.c b/drivers/video/rockchip/chips/rk30_lcdc.c new file mode 100644 index 000000000000..a3407598eea9 --- /dev/null +++ b/drivers/video/rockchip/chips/rk30_lcdc.c @@ -0,0 +1,644 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "../../display/screen/screen.h" +#include "../rk_fb.h" +#include "rk30_lcdc.h" + + + + +static int dbg_thresd = 0; +#define DBG(x...) do { if(unlikely(dbg_thresd)) printk(KERN_INFO x); } while (0) + + +static struct platform_device * g_lcdc_pdev; +static rk_screen * to_screen(struct rk30_lcdc_device *lcdc_dev) +{ + return &(lcdc_dev->driver->screen); +} + + +static int init_rk30_lcdc(struct lcdc_info *info) +{ + struct rk30_lcdc_device * lcdc_dev = &info->lcdc0; + struct rk30_lcdc_device * lcdc_dev1 = &info->lcdc1; + info->lcdc0.hclk = clk_get(NULL,"hclk_lcdc0"); + info->lcdc0.aclk = clk_get(NULL,"aclk_lcdc0"); + info->lcdc0.dclk = clk_get(NULL,"dclk_lcdc0"); + + info->lcdc1.hclk = clk_get(NULL,"hclk_lcdc1"); + info->lcdc1.aclk = clk_get(NULL,"aclk_lcdc1"); + info->lcdc1.dclk = clk_get(NULL,"dclk_lcdc1"); + if ((IS_ERR(info->lcdc0.aclk)) ||(IS_ERR(info->lcdc0.dclk)) || (IS_ERR(info->lcdc0.hclk))|| + (IS_ERR(info->lcdc1.aclk)) ||(IS_ERR(info->lcdc1.dclk)) || (IS_ERR(info->lcdc1.hclk))) + { + printk(KERN_ERR "failed to get lcdc_hclk source\n"); + return PTR_ERR(info->lcdc0.aclk); + } + clk_enable(info->lcdc0.hclk); //enable aclk for register config + clk_enable(info->lcdc1.hclk); + + LcdSetBit(lcdc_dev,DSP_CTRL0, m_LCDC_AXICLK_AUTO_ENABLE);//eanble axi-clk auto gating for low power + LcdSetBit(lcdc_dev1,DSP_CTRL0, m_LCDC_AXICLK_AUTO_ENABLE); + return 0; +} + +int rk30_lcdc_deinit(void) +{ + return 0; +} + +void rk30_load_screen(struct rk30_lcdc_device*lcdc_dev, bool initscreen) +{ + int ret = -EINVAL; + rk_screen *screen = to_screen(lcdc_dev); + u16 face; + u16 mcu_total, mcu_rwstart, mcu_csstart, mcu_rwend, mcu_csend; + u16 right_margin = screen->right_margin; + u16 lower_margin = screen->lower_margin; + u16 x_res = screen->x_res, y_res = screen->y_res; + u32 aclk_rate = 150000000; + + // set the rgb or mcu + + if(screen->type==SCREEN_MCU) + { + LcdMskReg(lcdc_dev, MCU_CTRL, m_MCU_OUTPUT_SELECT,v_MCU_OUTPUT_SELECT(1)); + // 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); + + DBG(">> 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); + + // set horizontal & vertical out timing + + right_margin = x_res/6; + screen->pixclock = 150000000; //mcu fix to 150 MHz + + } + + + + // set synchronous pin polarity and data pin swap rule + switch (screen->face) + { + case OUT_P565: + face = OUT_P565; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0)); + break; + case OUT_P666: + face = OUT_P666; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1)); + break; + case OUT_D888_P565: + face = OUT_P888; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0)); + break; + case OUT_D888_P666: + face = OUT_P888; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1)); + break; + case OUT_P888: + face = OUT_P888; + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_UP_EN, v_DITHER_UP_EN(1)); + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(0) | v_DITHER_DOWN_MODE(0)); + break; + default: + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_UP_EN, v_DITHER_UP_EN(0)); + LcdMskReg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(0) | v_DITHER_DOWN_MODE(0)); + face = screen->face; + break; + } + + //use default overlay,set vsyn hsync den dclk polarity + LcdMskReg(lcdc_dev, DSP_CTRL0,m_DISPLAY_FORMAT | m_HSYNC_POLARITY | m_VSYNC_POLARITY + | m_DEN_POLARITY |m_DCLK_POLARITY, + 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)); + + //set background color to black,set swap according to the screen panel + LcdMskReg(lcdc_dev, DSP_CTRL1, m_BG_COLOR | m_OUTPUT_RB_SWAP | m_OUTPUT_RG_SWAP | m_DELTA_SWAP | + m_DUMMY_SWAP, v_BG_COLOR(0x000000) | 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) ); + + + LcdWrReg(lcdc_dev, DSP_HTOTAL_HS_END,v_HSYNC(screen->hsync_len) | + v_HORPRD(screen->hsync_len + screen->left_margin + x_res + right_margin)); + LcdWrReg(lcdc_dev, DSP_HACT_ST_END, v_HAEP(screen->hsync_len + screen->left_margin + x_res) | + v_HASP(screen->hsync_len + screen->left_margin)); + + LcdWrReg(lcdc_dev, DSP_VTOTAL_VS_END, v_VSYNC(screen->vsync_len) | + v_VERPRD(screen->vsync_len + screen->upper_margin + y_res + lower_margin)); + LcdWrReg(lcdc_dev, DSP_VACT_ST_END, v_VAEP(screen->vsync_len + screen->upper_margin+y_res)| + v_VASP(screen->vsync_len + screen->upper_margin)); + // let above to take effect + LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + + if(initscreen == 0) //not init + { + clk_disable(lcdc_dev->dclk); + // clk_disable(inf->aclk); + } + + + + // ret = clk_set_rate(lcdc_dev->dclk, screen->pixclock); + if(ret) + { + printk(KERN_ERR ">>>>>> set lcdc dclk failed\n"); + } + lcdc_dev->driver->pixclock = lcdc_dev->pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk)); + if(initscreen) + { + //ret = clk_set_parent(lcdc_dev->aclk, lcdc_dev->aclk_parent); + if(screen->lcdc_aclk){ + aclk_rate = screen->lcdc_aclk; + } + // ret = clk_set_rate(lcdc_dev->aclk, aclk_rate); + if(ret){ + printk(KERN_ERR ">>>>>> set lcdc aclk failed\n"); + } + clk_enable(lcdc_dev->aclk); + } + + clk_enable(lcdc_dev->dclk); + + if(screen->init) + { + screen->init(); + } + printk("%s>>>>>ok!\n",__func__); +} + +static int mcu_refresh(struct rk30_lcdc_device *lcdc_dev) +{ + + return 0; +} + +static int win0_blank(int blank_mode,struct rk30_lcdc_device *lcdc_dev) +{ + switch(blank_mode) + { + case FB_BLANK_UNBLANK: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W0_EN(1)); + break; + case FB_BLANK_NORMAL: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W0_EN(0)); + break; + default: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_EN, v_W1_EN(1)); + break; + } + mcu_refresh(lcdc_dev); + return 0; +} + +static int win1_blank(int blank_mode, struct rk30_lcdc_device *lcdc_dev) +{ + printk(KERN_INFO "%s>>>>>>>>>>mode:%d\n",__func__,blank_mode); + switch(blank_mode) + { + case FB_BLANK_UNBLANK: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(1)); + break; + case FB_BLANK_NORMAL: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(0)); + break; + default: + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN, v_W1_EN(0)); + break; + } + + //mcu_refresh(inf); + return 0; +} +static int rk30_lcdc_blank(struct rk_fb_device_driver*fb_drv,int layer_id,int blank_mode) +{ + struct rk30_lcdc_device * lcdc_dev = NULL; + struct lcdc_info * info = platform_get_drvdata(g_lcdc_pdev); + if(!strcmp(fb_drv->name,"lcdc0")) + { + lcdc_dev = &(info->lcdc0); + } + else if(!strcmp(fb_drv->name,"lcdc1")) + { + lcdc_dev = &(info->lcdc1); + } + if(layer_id==0) + { + win0_blank(blank_mode,lcdc_dev); + } + else if(layer_id==1) + { + win1_blank(blank_mode,lcdc_dev); + } + + LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + return 0; +} + +static int win0_set_par(struct rk30_lcdc_device *lcdc_dev,rk_screen *screen, + struct layer_par *par ) +{ + u32 xact, yact, xvir, yvir, xpos, ypos; + u32 ScaleYrgbX,ScaleYrgbY, ScaleCbrX, ScaleCbrY; + u32 y_addr,uv_addr; + + xact = par->xact; /*active (origin) picture window width/height */ + yact = par->yact; + xvir = par->xres_virtual; /* virtual resolution */ + yvir = par->yres_virtual; + xpos = par->xpos+screen->left_margin + screen->hsync_len; + ypos = par->ypos+screen->upper_margin + screen->vsync_len; + y_addr = par->smem_start + par->y_offset; + switch (par->format) + { + case RGB888: + case RGB565: + ScaleYrgbX = CalScale(xact, par->xsize); + ScaleYrgbY = CalScale(yact, par->ysize); + break; + case YUV422:// yuv422 + ScaleCbrX= CalScale((xact/2), par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + case YUV420: // yuv420 + ScaleCbrX= CalScale(xact/2, par->xsize); + ScaleCbrY = CalScale(yact/2, par->ysize); + break; + case YUV444:// yuv444 + ScaleCbrX= CalScale(xact, par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + default: + break; + } + + DBG("%s>>format:%d>>>xact:%d>>yact:%d>>xvir:%d>>yvir:%d>>ypos:%d>>y_addr:0x%x\n", + __func__,par->format,xact,yact,xvir,yvir,ypos,y_addr); + LcdWrReg(lcdc_dev, WIN0_YRGB_MST0, y_addr); + LcdMskReg(lcdc_dev,SYS_CTRL1, m_W0_FORMAT , v_W0_FORMAT(par->format)); //(inf->video_mode==0) + LcdWrReg(lcdc_dev, WIN0_ACT_INFO,v_ACT_WIDTH(xact) | v_ACT_HEIGHT(yact)); + LcdWrReg(lcdc_dev, WIN0_DSP_ST, v_DSP_STX(xpos) | v_DSP_STY(ypos)); + LcdWrReg(lcdc_dev, WIN0_DSP_INFO, v_DSP_WIDTH(par->xsize) | v_DSP_HEIGHT(par->ysize)); + LcdWrReg(lcdc_dev, WIN0_SCL_FACTOR_YRGB, v_X_SCL_FACTOR(ScaleYrgbX) | v_Y_SCL_FACTOR(ScaleYrgbY)); + LcdWrReg(lcdc_dev, WIN0_SCL_FACTOR_CBR, v_X_SCL_FACTOR(ScaleCbrX) | v_Y_SCL_FACTOR(ScaleCbrY)); + switch(par->format) + { + case RGB888: //rgb888 + LcdMskReg(lcdc_dev, WIN0_VIR, m_WORDLO, v_RGB888_VIRWIDTH(xvir)); + break; + case RGB565: //rgb565 + LcdMskReg(lcdc_dev, WIN0_VIR, m_WORDLO, v_YUV_VIRWIDTH(xvir)); + break; + case YUV420: + LcdMskReg(lcdc_dev, WIN0_VIR, m_WORDLO,v_RGB565_VIRWIDTH(xvir)); + break; + default: + LcdMskReg(lcdc_dev, WIN0_VIR, m_WORDLO, v_RGB888_VIRWIDTH(xvir)); + break; + } + + LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + printk(KERN_INFO "%s>>>>done!\n",__func__); + + return 0; + +} + +static int win1_set_par(struct rk30_lcdc_device *lcdc_dev,rk_screen *screen, + struct layer_par *par ) + +{ + u32 xact, yact, xvir, yvir, xpos, ypos,xres_virtual; + u32 ScaleYrgbX,ScaleYrgbY, ScaleCbrX, ScaleCbrY; + u32 addr; + xact = par->xact; /* visible resolution */ + yact = par->yact; + xvir = par->xres_virtual; /* virtual resolution */ + yvir = par->yres_virtual; + xpos = par->xpos+screen->left_margin + screen->hsync_len; + ypos = par->ypos+screen->upper_margin + screen->vsync_len; + addr = par->smem_start + par->y_offset; + + + switch (par->format) + { + case RGB888: + case RGB565: + ScaleYrgbX = CalScale(xact, par->xsize); + ScaleYrgbY = CalScale(yact, par->ysize); + break; + case YUV422:// yuv422 + ScaleCbrX= CalScale((xact/2), par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + case YUV420: // yuv420 + ScaleCbrX= CalScale(xact/2, par->xsize); + ScaleCbrY = CalScale(yact/2, par->ysize); + break; + case YUV444:// yuv444 + ScaleCbrX= CalScale(xact, par->xsize); + ScaleCbrY = CalScale(yact, par->ysize); + break; + default: + break; + } + + LcdWrReg(lcdc_dev, WIN1_SCL_FACTOR_YRGB, v_X_SCL_FACTOR(ScaleYrgbX) | v_Y_SCL_FACTOR(ScaleYrgbY)); + LcdWrReg(lcdc_dev, WIN1_SCL_FACTOR_CBR, v_X_SCL_FACTOR(ScaleCbrX) | v_Y_SCL_FACTOR(ScaleCbrY)); + LcdMskReg(lcdc_dev, SYS_CTRL1, m_W1_EN|m_W1_FORMAT, v_W1_EN(1)|v_W1_FORMAT(par->format)); + LcdWrReg(lcdc_dev, WIN1_YRGB_MST, addr); + LcdWrReg(lcdc_dev, WIN1_DSP_ST,v_DSP_STX(xpos) | v_DSP_STY(ypos)); + LcdWrReg(lcdc_dev, WIN1_DSP_INFO,v_DSP_WIDTH(par->xsize) | v_DSP_HEIGHT(par->ysize)); + // enable win1 color key and set the color to black(rgb=0) + LcdMskReg(lcdc_dev, WIN1_COLOR_KEY_CTRL, m_COLORKEY_EN | m_KEYCOLOR, v_COLORKEY_EN(1) | v_KEYCOLOR(0)); + switch(par->format) + { + case RGB888: //rgb888 + LcdMskReg(lcdc_dev, WIN1_VIR, m_WORDLO, v_RGB888_VIRWIDTH(xvir)); + break; + case RGB565: //rgb565 + LcdMskReg(lcdc_dev, WIN1_VIR, m_WORDLO, v_YUV_VIRWIDTH(xvir)); + break; + case YUV420: + LcdMskReg(lcdc_dev, WIN1_VIR, m_WORDLO,v_RGB565_VIRWIDTH(xvir)); + break; + default: + LcdMskReg(lcdc_dev, WIN1_VIR, m_WORDLO, v_RGB888_VIRWIDTH(xvir)); + break; + } + + LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); + + + return 0; +} + +static int rk30_lcdc_set_par(struct rk_fb_device_driver *fb_drv,int layer_id) +{ + struct rk30_lcdc_device *lcdc_dev=NULL; + struct layer_par *par = &fb_drv->layer_par[0]; + rk_screen *screen = &fb_drv->screen; + struct lcdc_info * info = platform_get_drvdata(g_lcdc_pdev); + if(!strcmp(fb_drv->name,"lcdc0")) + { + lcdc_dev = &(info->lcdc0); + } + else if(!strcmp(fb_drv->name,"lcdc1")) + { + lcdc_dev = &(info->lcdc1); + } + + if(!screen) + { + printk(KERN_ERR "screen is null!\n"); + } + if(layer_id==0) + { + win0_set_par(lcdc_dev,screen,par); + } + else if(layer_id==1) + { + win1_set_par(lcdc_dev,screen,&(fb_drv->layer_par[1])); + } + + return 0; +} + +int rk30_lcdc_pan(struct rk_fb_device_driver * dev_drv,int layer_id) +{ + + return 0; +} + +int rk30_lcdc_ioctl(unsigned int cmd, unsigned long arg,struct layer_par *layer_par) +{ + return 0; +} + +int rk30_lcdc_suspend(struct layer_par *layer_par) +{ + return 0; +} + + +int rk30_lcdc_resume(struct layer_par *layer_par) +{ + + return 0; +} + +static struct layer_par lcdc0_layer[] = { + [0] = { + .name = "win0", + .id = 0, + .support_3d = true, + }, + [1] = { + .name = "win1", + .id = 1, + .support_3d = false, + }, +}; +static struct layer_par lcdc1_layer[] = { + [0] = { + .name = "win0", + .id = 0, + .support_3d = true, + }, + [1] = { + .name = "win1", + .id = 1, + .support_3d = false, + }, +}; + +static struct rk_fb_device_driver lcdc0_driver = { + .name = "lcdc0", + .layer_par = lcdc0_layer, + .num_layer = ARRAY_SIZE(lcdc0_layer), + .ioctl = rk30_lcdc_ioctl, + .suspend = rk30_lcdc_suspend, + .resume = rk30_lcdc_resume, + .set_par = rk30_lcdc_set_par, + .blank = rk30_lcdc_blank, + .pan = rk30_lcdc_pan, +}; +static struct rk_fb_device_driver lcdc1_driver = { + .name = "lcdc1", + .layer_par = lcdc1_layer, + .num_layer = ARRAY_SIZE(lcdc1_layer), + .ioctl = rk30_lcdc_ioctl, + .suspend = rk30_lcdc_suspend, + .resume = rk30_lcdc_resume, + .set_par = rk30_lcdc_set_par, + .blank = rk30_lcdc_blank, + .pan = rk30_lcdc_pan, +}; + +static int __devinit rk30_lcdc_probe (struct platform_device *pdev) +{ + struct lcdc_info *inf = NULL; + struct resource *res = NULL; + struct resource *mem; + int ret = 0; + + g_lcdc_pdev = pdev; //set g_pdev + + /*************Malloc rk30lcdc_inf and set it to pdev for drvdata**********/ + inf = kmalloc(sizeof(struct lcdc_info), GFP_KERNEL); + if(!inf) + { + dev_err(&pdev->dev, ">>rk30 lcdc inf kmalloc fail!"); + ret = -ENOMEM; + } + memset(inf, 0, sizeof(struct lcdc_info)); + platform_set_drvdata(pdev, inf); + + /**************** get lcdc0 reg *************************/ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lcdc0 reg"); + if (res == NULL) + { + dev_err(&pdev->dev, "failed to get memory registers\n"); + ret = -ENOENT; + //goto release_drvdata; + } + inf->lcdc0.reg_phy_base = res->start; + inf->lcdc0.len = (res->end - res->start) + 1; + mem = request_mem_region(inf->lcdc0.reg_phy_base, inf->lcdc0.len, pdev->name); + if (mem == NULL) + { + dev_err(&pdev->dev, "failed to get memory region\n"); + ret = -ENOENT; + //goto release_drvdata; + } + inf->lcdc0.reg_vir_base = ioremap(inf->lcdc0.reg_phy_base, inf->lcdc0.len); + if (inf->lcdc0.reg_vir_base == NULL) + { + dev_err(&pdev->dev, "ioremap() of registers failed\n"); + ret = -ENXIO; + //goto release_drvdata; + } + inf->lcdc0.preg = (LCDC_REG*)inf->lcdc0.reg_vir_base; + printk("lcdc0 reg_phy_base = 0x%08x,reg_vir_base:0x%p\n", inf->lcdc0.reg_phy_base, inf->lcdc0.preg); + /**************** get lcdc1 reg *************************/ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lcdc1 reg"); + if (res == NULL) + { + dev_err(&pdev->dev, "failed to get memory registers\n"); + ret = -ENOENT; + //goto release_drvdata; + } + inf->lcdc1.reg_phy_base = res->start; + inf->lcdc1.len = (res->end - res->start) + 1; + mem = request_mem_region(inf->lcdc1.reg_phy_base, inf->lcdc1.len, pdev->name); + if (mem == NULL) + { + dev_err(&pdev->dev, "failed to get memory region\n"); + ret = -ENOENT; + //goto release_drvdata; + } + inf->lcdc1.reg_vir_base = ioremap(inf->lcdc1.reg_phy_base, inf->lcdc1.len); + if (inf->lcdc1.reg_vir_base == NULL) + { + dev_err(&pdev->dev, "ioremap() of registers failed\n"); + ret = -ENXIO; + //goto release_drvdata; + } + inf->lcdc1.preg = (LCDC_REG*)inf->lcdc1.reg_vir_base; + printk("lcdc1 reg_phy_base = 0x%08x,reg_vir_base:0x%p\n", inf->lcdc1.reg_phy_base, inf->lcdc1.preg); + /***************** LCDC driver ********/ + inf->lcdc0.driver = &lcdc0_driver; + inf->lcdc0.driver->dev=&pdev->dev; + inf->lcdc1.driver = &lcdc1_driver; + inf->lcdc1.driver->dev=&pdev->dev; + /***************** set lcdc screen ********/ + set_lcd_info(&inf->lcdc0.driver->screen, NULL); + set_lcd_info(&inf->lcdc1.driver->screen, NULL); + /***************** INIT LCDC ********/ + init_rk30_lcdc(inf); + rk30_load_screen(&inf->lcdc0,1); + //rk30_load_screen(&inf->lcdc1,1); + /***************** lcdc register ********/ + rk_fb_register(&lcdc0_driver); + //rk_fb_register(&lcdc1_driver); + + + printk("rk30 lcdc probe ok!\n"); + return 0; + +} +static int __devexit rk30_lcdc_remove(struct platform_device *pdev) +{ + return 0; +} + +static void rk30_lcdc_shutdown(struct platform_device *pdev) +{ + +} + + +static struct platform_driver rk30lcdc_driver = { + .probe = rk30_lcdc_probe, + .remove = __devexit_p(rk30_lcdc_remove), + .driver = { + .name = "rk30-lcdc", + .owner = THIS_MODULE, + }, + .shutdown = rk30_lcdc_shutdown, +}; + +static int __init rk30_lcdc_init(void) +{ + //wake_lock_init(&idlelock, WAKE_LOCK_IDLE, "fb"); + return platform_driver_register(&rk30lcdc_driver); +} + +static void __exit rk30_lcdc_exit(void) +{ + platform_driver_unregister(&rk30lcdc_driver); +} + + + +fs_initcall(rk30_lcdc_init); +module_exit(rk30_lcdc_exit); + + + diff --git a/drivers/video/rockchip/chips/rk30_lcdc.h b/drivers/video/rockchip/chips/rk30_lcdc.h new file mode 100644 index 000000000000..4e98c106211f --- /dev/null +++ b/drivers/video/rockchip/chips/rk30_lcdc.h @@ -0,0 +1,503 @@ +#ifndef RK30_LCDC_H_ +#define RK30_LCDC_H_ + +#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 LcdSetRegBit(inf, addr, msk) inf->preg->addr=((inf->preg->addr) |= (msk)) +#define LcdMskReg(inf, addr, msk, val) (inf->regbak.addr)&=~(msk); inf->preg->addr=(inf->regbak.addr|=(val)) + +/******************************************************************** +** ½á¹¹¶¨Òå * +********************************************************************/ +/* LCDCµÄ¼Ä´æÆ÷½á¹¹ */ + +typedef volatile struct tagLCDC_REG +{ + /* offset 0x00~0xc0 */ + unsigned int SYS_CTRL0; //0x00 system control register 0 + unsigned int SYS_CTRL1; //0x04 system control register 1 + unsigned int DSP_CTRL0; //0x08 display control register 0 + unsigned int DSP_CTRL1; //0x0c display control register 1 + unsigned int INT_STATUS; //0x10 Interrupt status register + unsigned int MCU_CTRL ; //0x14 MCU mode contol register + unsigned int BLEND_CTRL; //0x18 Blending control register + unsigned int WIN0_COLOR_KEY_CTRL; //0x1c Win0 blending control register + unsigned int WIN1_COLOR_KEY_CTRL; //0x20 Win1 blending control register + unsigned int WIN2_COLOR_KEY_CTRL; //0x24 Win2 blending control register + unsigned int WIN0_YRGB_MST0; //0x28 Win0 active YRGB memory start address0 + unsigned int WIN0_CBR_MST0; //0x2c Win0 active Cbr memory start address0 + unsigned int WIN0_YRGB_MST1; //0x30 Win0 active YRGB memory start address1 + unsigned int WIN0_CBR_MST1; //0x34 Win0 active Cbr memory start address1 + unsigned int WIN0_VIR; //0x38 WIN0 virtual display width/height + unsigned int WIN0_ACT_INFO; //0x3C Win0 active window width/height + unsigned int WIN0_DSP_INFO; //0x40 Win0 display width/height on panel + unsigned int WIN0_DSP_ST; //0x44 Win0 display start point on panel + unsigned int WIN0_SCL_FACTOR_YRGB; //0x48Win0 YRGB scaling factor setting + unsigned int WIN0_SCL_FACTOR_CBR; //0x4c Win0 YRGB scaling factor setting + unsigned int WIN0_SCL_OFFSET; //0x50 Win0 Cbr scaling start point offset + unsigned int WIN1_YRGB_MST; //0x54 Win1 active YRGB memory start address + unsigned int WIN1_CBR_MST; //0x58 Win1 active Cbr memory start address + unsigned int WIN1_VIR; //0x5c WIN1 virtual display width/height + unsigned int WIN1_ACT_INFO; //0x60 Win1 active window width/height + unsigned int WIN1_DSP_INFO; //0x64 Win1 display width/height on panel + unsigned int WIN1_DSP_ST; //0x68 Win1 display start point on panel + unsigned int WIN1_SCL_FACTOR_YRGB; //0x6c Win1 YRGB scaling factor setting + unsigned int WIN1_SCL_FACTOR_CBR; //0x70 Win1 YRGB scaling factor setting + unsigned int WIN1_SCL_OFFSET; //0x74 Win1 Cbr scaling start point offset + unsigned int WIN2_MST; //0x78 win2 memort start address + unsigned int WIM2_VIR; //0x7c win2 virtual stride + unsigned int WIN2_DSP_INFO; //0x80 Win2 display width/height on panel + unsigned int WIN2_DSP_ST; //0x84 Win2 display start point on panel + unsigned int HWC_MST; //0x88 HWC memory start address + unsigned int HWC_DSP_ST; //0x8C HWC display start point on panel + unsigned int HWC_COLOR_LUT0; //0x90 Hardware cursor color 2¡¯b01 look up table 0 + unsigned int HWC_COLOR_LUT1; //0x94 Hardware cursor color 2¡¯b10 look up table 1 + unsigned int HWC_COLOR_LUT2; //0x98 Hardware cursor color 2¡¯b11 look up table 2 + unsigned int DSP_HTOTAL_HS_END; //0x9c Panel scanning horizontal width and hsync pulse end point + unsigned int DSP_HACT_ST_END; //0xa0 Panel active horizontal scanning start/end point + unsigned int DSP_VTOTAL_VS_END; //0xa4 Panel scanning vertical height and vsync pulse end point + unsigned int DSP_VACT_ST_END; //0xa8 Panel active vertical scanning start/end point + unsigned int DSP_VS_ST_END_F1; //0xac Vertical scanning start point and vsync pulse end point of even filed in interlace mode + unsigned int DSP_VACT_ST_END_F1; //0xb0 Vertical scanning active start/end point of even filed in interlace mode + unsigned int reserved0[(0xc0-0xb4)/4]; + unsigned int REG_CFG_DONE; //0xc0 REGISTER CONFIG FINISH + unsigned int reserved1[(0x100-0xc4)/4]; + unsigned int MCU_BYPASS_WPORT; //0x100 MCU BYPASS MODE, DATA Write Only Port + unsigned int reserved2[(0x200-0x104)/4]; + unsigned int MCU_BYPASS_RPORT; //0x200 MCU BYPASS MODE, DATA Read Only Port + +} LCDC_REG, *pLCDC_REG; + + +/* SYS_CONFIG */ + +#define m_LCDC_DMA_STOP (1<<0) +#define m_LCDC_STANDBY (1<<1) +#define m_HWC_RELOAD_EN (1<<2) +#define m_W0_AXI_OUTSTANDING_DISABLE (1<<3) +#define m_W1_AXI_OUTSTANDING_DISABLE (1<<4) +#define m_W2_AXI_OUTSTANDING_DISABLE (1<<5) +#define m_DMA_BURST_LENGTH (3<<6) + +#define v_LCDC_DMA_STOP(x) (((x)&1)<<0) +#define v_LCDC_STANDBY(x) (((x)&1)<<1) +#define v_HWC_RELOAD_EN(x) (((x)&1)<<2) +#define v_W0_AXI_OUTSTANDING_DISABLE(x) (((x)&1)<<3) +#define v_W1_AXI_OUTSTANDING_DISABLE(x) (((x)&1)<<4) +#define v_W2_AXI_OUTSTANDING_DISABLE(x) (((x)&1)<<5) +#define v_DMA_BURST_LENGTH(x) (((x)&3)<<6) + + + +//LCDC_SYS_CTRL1 +#define m_W0_EN (1<<0) +#define m_W1_EN (1<<1) +#define m_W2_EN (1<<2) +#define m_HWC_EN (1<<3) +#define m_W0_FORMAT (7<<4) +#define m_W1_FORMAT (7<<7) +#define m_W2_FORMAT (7<<10) +#define m_HWC_COLOR_MODE (1<<13) +#define m_HWC_SIZE_SELET (1<<14) +#define m_W0_3D_MODE_EN (1<<15) +#define m_W0_3D_MODE_SELET (7<<16) +#define m_W0_RGB_RB_SWAP (1<<19) +#define m_W0_RGB_ALPHA_SWAP (1<<20) +#define m_W0_YRGB_M8_SWAP (1<<21) +#define m_W0_CBCR_SWAP (1<<22) +#define m_W1_RGB_RB_SWAP (1<<23) +#define m_W1_RGB_ALPHA_SWAP (1<<24) +#define m_W1_YRGB_M8_SWAP (1<<25) +#define m_W1_CBCR_SWAP (1<<26) +#define m_W2_RGB_RB_SWAP (1<<27) +#define m_W2_RGB_ALPHA_SWAP (1<<28) +#define m_W2_8pp_PALETTE_ENDIAN_SELECT (1<<29) +#define m_W2_LUT_RAM_EN (1<<30) +#define m_DSP_LUT_RAM_EN (1<<31) + +#define v_W0_EN(x) (((x)&1)<<0) +#define v_W1_EN(x) (((x)&1)<<1) +#define v_W2_EN(x) (((x)&1)<<2) +#define v_HWC_EN(x) (((x)&1)<<3) +#define v_W0_FORMAT(x) (((x)&7)<<4) +#define v_W1_FORMAT(x) (((x)&7)<<7) +#define v_W2_FORMAT(x) (((x)&7)<<10) +#define v_HWC_COLOR_MODE(x) (((x)&1)<<13) +#define v_HWC_SIZE_SELET(x) (((x)&1)<<14) +#define v_W0_3D_MODE_EN(x) (((x)&1)<<15) +#define v_W0_3D_MODE_SELET(x) (((x)&3)<<16) +#define v_W0_RGB_RB_SWAP(x) (((x)&1)<<19) +#define v_W0_RGB_ALPHA_SWAP(x) (((x)&1)<<20) +#define v_W0_YRGB_M8_SWAP(x) (((x)&1)<<21) +#define v_W0_CBCR_SWAP(x) (((x)&1)<<22) +#define v_W1_RGB_RB_SWAP(x) (((x)&1)<<23) +#define v_W1_RGB_ALPHA_SWAP(x) (((x)&1)<<24) +#define v_W1_YRGB_M8_SWAP(x) (((x)&1)<<25) +#define v_W1_CBCR_SWAP(x) (((x)&1)<<26) +#define v_W2_RGB_RB_SWAP(x) (((x)&1)<<27) +#define v_W2_RGB_ALPHA_SWAP(x) (((x)&1)<<28) +#define v_W2_8pp_PALETTE_ENDIAN_SELECT (((x)&1)<<29) +#define v_W2_LUT_RAM_EN(x) (((x)&1)<<30) +#define v_DSP_LUT_RAM_EN(x)¡¡¡¡¡¡(((x)&1)<<31) + + +//LCDC_DSP_CTRL_REG0 +#define m_DISPLAY_FORMAT (0x0f<<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_W0W1_POSITION_SWAP (1<<8) +#define m_DITHER_UP_EN (1<<9) +#define m_DITHER_DOWN_MODE (1<<10) +#define m_DITHER_DOWN_EN (1<<11) +#define m_INTERLACE_DSP_EN (1<<12) +#define m_INTERLACE_FIELD_POLARITY (1<<13) +#define m_W0_INTERLACE_READ_MODE (1<<14) +#define m_W1_INTERLACE_READ_MODE (1<<15) +#define m_W2_INTERLACE_READ_MODE (1<<16) +#define m_W0_YRGB_DEFLICK_MODE (1<<17) +#define m_W0_CBR_DEFLICK_MODE (1<<18) +#define m_W1_YRGB_DEFLICK_MODE (1<<19) +#define m_W1_CBR_DEFLICK_MODE (1<<20) +#define m_W0_ALPHA_MODE (1<<21) +#define m_W1_ALPHA_MODE (1<<22) +#define m_W2_ALPHA_MODE (1<<23) +#define m_W0_COLOR_SPACE_CONVERSION (3<<24) +#define m_W1_COLOR_SPACE_CONVERSION (3<<26) +#define m_W2_COLOR_SPACE_CONVERSION (1<<28) +#define m_YCRCB_CLIP_EN (1<<29) +#define m_CBR_FILTER_656 (1<<30) +#define m_LCDC_AXICLK_AUTO_ENABLE (1<<31) //eanble for low power + +#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_W0W1_POSITION_SWAP(x) (((x)&1)<<8) +#define v_DITHER_UP_EN(x) (((x)&1)<<9) +#define v_DITHER_DOWN_MODE(x) (((x)&1)<<10) +#define v_DITHER_DOWN_EN(x) (((x)&1)<<11) +#define v_INTERLACE_DSP_EN(x) (((x)&1)<<12) +#define v_INTERLACE_FIELD_POLARITY(x) (((x)&1)<<13) +#define v_W0_INTERLACE_READ_MODE(x) (((x)&1)<<14) +#define v_W1_INTERLACE_READ_MODE(x) (((x)&1)<<15) +#define v_W2_INTERLACE_READ_MODE(x) (((x)&1)<<16) +#define v_W0_YRGB_DEFLICK_MODE(x) (((x)&1)<<17) +#define v_W0_CBR_DEFLICK_MODE(x) (((x)&1)<<18) +#define v_W1_YRGB_DEFLICK_MODE(x) (((x)&1)<<19) +#define v_W1_CBR_DEFLICK_MODE(x) (((x)&1)<<20) +#define v_W0_ALPHA_MODE(x) (((x)&1)<<21) +#define v_W1_ALPHA_MODE(x) (((x)&1)<<22) +#define v_W2_ALPHA_MODE(x) (((x)&1)<<23) +#define v_W0_COLOR_SPACE_CONVERSION(x) (((x)&3)<<24) +#define v_W1_COLOR_SPACE_CONVERSION(x) (((x)&3)<<26) +#define v_W2_COLOR_SPACE_CONVERSION(x) (((x)&1)<<28) +#define v_YCRCB_CLIP_EN(x) (((x)&1)<<29) +#define v_CBR_FILTER_656(x) (((x)&1)<<30) +#define v_LCDC_AXICLK_AUTO_ENABLE(x) (((x)&1)<<31) //eanble for low power + +//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_OUTPUT_BG_SWAP (1<<26) +#define m_OUTPUT_RB_SWAP (1<<27) +#define m_OUTPUT_RG_SWAP (1<<28) +#define m_DELTA_SWAP (1<<29) +#define m_DUMMY_SWAP (1<<30) + +#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_OUTPUT_BG_SWAP(x) (((x)&1)<<26) +#define v_OUTPUT_RB_SWAP(x) (((x)&1)<<27) +#define v_OUTPUT_RG_SWAP(x) (((x)&1)<<28) +#define v_DELTA_SWAP(x) (((x)&1)<<29) +#define v_DUMMY_SWAP(x) (((x)&1)<<30) + + +//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) + + +//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_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_HWC_BLEND_EN (1<<0) +#define m_W2_BLEND_EN (1<<1) +#define m_W1_BLEND_EN (1<<2) +#define m_W0_BLEND_EN (1<<3) +#define m_HWC_BLEND_FACTOR (15<<4) +#define m_W2_BLEND_FACTOR (0xff<<8) +#define m_W1_BLEND_FACTOR (0xff<<16) +#define m_W0_BLEND_FACTOR (0xff<<24) + +#define v_HWC_BLEND_EN(x) (((x)&1)<<0) +#define v_W2_BLEND_EN(x) (((x)&1)<<1) +#define v_W1_BLEND_EN(x) (((x)&1)<<2) +#define v_W0_BLEND_EN(x) (((x)&1)<<3) +#define v_HWC_BLEND_FACTOR(x) (((x)&15)<<4) +#define v_W2_BLEND_FACTOR(x) (((x)&0xff)<<8) +#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) + + + + + +//AXI MS ID +#define m_W0_YRGB_CH_ID (0xF<<0) +#define m_W0_CBR_CH_ID (0xF<<4) +#define m_W1_YRGB_CH_ID (0xF<<8) +#define m_W2_CH_ID (0xF<<12) +#define m_HWC_CH_ID (0xF<<16) +#define v_W0_YRGB_CH_ID(x) (((x)&0xF)<<0) +#define v_W0_CBR_CH_ID(x) (((x)&0xF)<<4) +#define v_W1_YRGB_CH_ID(x) (((x)&0xF)<<8) +#define v_W2_CH_ID(x) (((x)&0xF)<<12) +#define v_HWC_CH_ID(x) (((x)&0xF)<<16) + + +/* 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) + + +//LCDC_WINx_SCL_FACTOR_Y/CBCR +#define v_X_SCL_FACTOR(x) ((x)<<0) +#define v_Y_SCL_FACTOR(x) ((x)<<16) + +//LCDC_DSP_HTOTAL_HS_END +#define v_HSYNC(x) ((x)<<0) //hsync pulse width +#define v_HORPRD(x) ((x)<<16) //horizontal period + + +//LCDC_DSP_HACT_ST_END +#define v_HAEP(x) ((x)<<0) //horizontal active end point +#define v_HASP(x) ((x)<<16) //horizontal active start point + +//LCDC_DSP_VTOTAL_VS_END +#define v_VSYNC(x) ((x)<<0) +#define v_VERPRD(x) ((x)<<16) + +//LCDC_DSP_VACT_ST_END +#define v_VAEP(x) ((x)<<0) +#define v_VASP(x) ((x)<<16) + + + +#define v_RGB888_VIRWIDTH(x) (((x*3)>>2)+((x)%3)) +#define v_RGB565_VIRWIDTH(x) ((x)>>1) +#define v_YUV_VIRWIDTH(x) ((x)>>1) + +#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) + +//LCDC_WIN0_ACT_INFO +#define v_ACT_WIDTH(x) ((x-1)<<0) +#define v_ACT_HEIGHT(x) ((x-1)<<16) + +//LCDC_WIN0_DSP_INFO +#define v_DSP_WIDTH(x) ((x-1)<<0) +#define v_DSP_HEIGHT(x) ((x-1)<<16) + +//LCDC_WIN0_DSP_ST //x,y start point of the panel scanning +#define v_DSP_STX(x) (x<<0) +#define v_DSP_STY(x) (x<<16) + +//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 CalScale(x, y) (((u32)x*0x1000)/y) +struct rk30_lcdc_device{ + struct rk_fb_device_driver *driver; + /* LCDC reg base address and backup reg */ + LCDC_REG *preg; + LCDC_REG regbak; + + 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 *hclk; //lcdc AHP clk + struct clk *dclk; //lcdc dclk + struct clk *aclk; //lcdc share memory frequency + struct clk *aclk_parent; //lcdc aclk divider frequency source + struct clk *aclk_ddr_lcdc; //DDR LCDC AXI clock disable. + struct clk *aclk_disp_matrix; //DISPLAY matrix AXI clock disable. + struct clk *hclk_cpu_display; //CPU DISPLAY AHB bus clock disable. + struct clk *pd_display; // display power domain + u32 pixclock; +}; + + +struct lcdc_info{ +/*LCD CLK*/ + struct rk30_lcdc_device lcdc0; + struct rk30_lcdc_device lcdc1; + +}; + + +struct win_set { + volatile u32 y_offset; + volatile u32 c_offset; +}; + +struct win0_par { + u32 refcount; + u32 pseudo_pal[16]; + u32 y_offset; + u32 c_offset; + u32 xpos; //size in panel + u32 ypos; + u32 xsize; //start point in panel + u32 ysize; + enum data_format format; + + wait_queue_head_t wait; + struct win_set mirror; + struct win_set displ; + struct win_set done; + + u8 par_seted; + u8 addr_seted; +}; + +#endif + + diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c new file mode 100644 index 000000000000..5c5a81716534 --- /dev/null +++ b/drivers/video/rockchip/rk_fb.c @@ -0,0 +1,522 @@ +/* + * drivers/video/rk30_fb.c + * + * Copyright (C) 2012 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 +#include +#include +#include + +#include +#include +#include +#include + +#include "../display/screen/screen.h" +#include "rk_fb.h" + +#if 0 + #define fbprintk(msg...) printk(msg); +#else + #define fbprintk(msg...) +#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 struct platform_device *g_fb_pdev; + +static struct rk_fb_rgb def_rgb_16 = { + red: { offset: 11, length: 5, }, + green: { offset: 5, length: 6, }, + blue: { offset: 0, length: 5, }, + transp: { offset: 0, length: 0, }, +}; + +static int fb0_blank(int blank_mode, struct fb_info *info) +{ + struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev); + struct rk_fb_device_driver *rk_fb_dev_drv = fb_inf->rk_lcdc_device[0]; + fb_inf->rk_lcdc_device[0]->blank(rk_fb_dev_drv,0,blank_mode); + + return 0; +} + +static int fb0_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + + struct rk_fb_inf *inf = dev_get_drvdata(info->device); + rk_screen *screen = &inf->rk_lcdc_device[0]->screen; + u16 xpos = (var->nonstd>>8) & 0xfff; + u16 ypos = (var->nonstd>>20) & 0xfff; + u16 xlcd = screen->x_res; + u16 ylcd = screen->y_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 || + ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) ) + { + printk(">>>>>> fb0_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("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*2 ) + { + printk(">>>>>> fb0_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; + } + return 0; +} + + +static int fb0_set_par(struct fb_info *info) +{ + struct rk_fb_inf *inf = platform_get_drvdata(g_fb_pdev); + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + struct rk_fb_device_driver *rk_fb_dev_drv = inf->rk_lcdc_device[0]; + struct layer_par *par = &rk_fb_dev_drv->layer_par[0]; + rk_screen *screen = &rk_fb_dev_drv->screen; + + u32 offset=0, smem_len=0; + u16 xres_virtual = var->xres_virtual; //virtual screen size + u16 xpos_virtual = var->xoffset; //visiable offset in virtual screen + u16 ypos_virtual = var->yoffset; + + switch(var->bits_per_pixel) + { + case 16: // rgb565 + par->format = RGB565; + fix->line_length = 2 * xres_virtual; + offset = (ypos_virtual*xres_virtual + xpos_virtual)*2; + break; + case 32: // rgb888 + default: + par->format = RGB888; + fix->line_length = 4 * xres_virtual; + offset = (ypos_virtual*xres_virtual + xpos_virtual)*4; + + if(ypos_virtual >= 2*var->yres) + { + par->format = RGB565; + if(ypos_virtual == 3*var->yres) + { + offset -= var->yres * var->xres *2; + } + } + break; + } + + smem_len = fix->line_length * var->yres_virtual; + if (smem_len > fix->smem_len) // buffer need realloc + { + printk("%s sorry!!! win0 buf is not enough\n",__FUNCTION__); + printk("line_length = %d, yres_virtual = %d, win0_buf only = %dB\n",fix->line_length,var->yres_virtual,fix->smem_len); + printk("you can change buf size MEM_FB_SIZE in board-xxx.c \n"); + return 0; + } + par->smem_start = fix->smem_start; + par->y_offset = offset; + par->xpos = 0; + par->ypos = 0; + par->xact = var->xres; + par->yact = var->yres; + par->xres_virtual = var->xres_virtual; /* virtual resolution */ + par->yres_virtual = var->yres_virtual; + par->xsize = screen->x_res; + par->ysize = screen->y_res; + inf->rk_lcdc_device[0]->set_par(rk_fb_dev_drv,0); + return 0; +} + +static int fb0_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev); + return 0; +} + +static int fb0_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev); + return 0; +} + +static int fb1_blank(int blank_mode, struct fb_info *info) +{ + struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev); + return 0; +} + +static int fb1_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + return 0; +} + +static int fb1_set_par(struct fb_info *info) +{ + struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev); + return 0; + return 0; +} + +static int fb1_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev); + return 0; +} + +static int fb1_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev); + return 0; +} +int fb1_open(struct fb_info *info, int user) +{ + return 0; +} + +int fb1_release(struct fb_info *info, int user) +{ + + return 0; +} + +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 struct fb_ops fb1_ops = { + .owner = THIS_MODULE, + .fb_open = fb1_open, + .fb_release = fb1_release, + .fb_check_var = fb1_check_var, + .fb_set_par = fb1_set_par, + .fb_blank = fb1_blank, + .fb_pan_display = fb1_pan_display, + .fb_ioctl = fb1_ioctl, + .fb_setcolreg = fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +static struct fb_ops fb0_ops = { + .owner = THIS_MODULE, + .fb_check_var = fb0_check_var, + .fb_set_par = fb0_set_par, + .fb_blank = fb0_blank, + .fb_pan_display = fb0_pan_display, + .fb_ioctl = fb0_ioctl, + .fb_setcolreg = fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + //.fb_cursor = rk29_set_cursor, +}; +int rk_fb_register(struct rk_fb_device_driver *fb_device_driver) +{ + struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev); + int i=0; + if(NULL==fb_device_driver){ + printk("rk_fb_register lcdc register fail"); + return -ENOENT; + } + for(i=0;irk_lcdc_device[i]){ + fb_inf->rk_lcdc_device[i] = fb_device_driver; + fb_inf->rk_lcdc_device[i]->id = i; + fb_inf->num_lcdc++; + break; + } + } + if(i==RK30_MAX_LCDC_SUPPORT){ + printk("rk_fb_register lcdc out of support %d",i); + return -ENOENT; + } + printk("%s>>>%s registered\n",__func__,fb_inf->rk_lcdc_device[i]->name); + /************fb0 set ***********/ + fb_inf->fb0->fix.type = FB_TYPE_PACKED_PIXELS; + fb_inf->fb0->fix.type_aux = 0; + fb_inf->fb0->fix.xpanstep = 1; + fb_inf->fb0->fix.ypanstep = 1; + fb_inf->fb0->fix.ywrapstep = 0; + fb_inf->fb0->fix.accel = FB_ACCEL_NONE; + fb_inf->fb0->fix.visual = FB_VISUAL_TRUECOLOR; + + fb_inf->fb0->var.xres = fb_inf->rk_lcdc_device[0]->screen.x_res; + fb_inf->fb0->var.yres = fb_inf->rk_lcdc_device[0]->screen.y_res; + fb_inf->fb0->var.bits_per_pixel = 16; + //fb_inf->fb0_color_deepth = 0; + fb_inf->fb0->var.xres_virtual = fb_inf->rk_lcdc_device[0]->screen.x_res; + fb_inf->fb0->var.yres_virtual = fb_inf->rk_lcdc_device[0]->screen.y_res; + fb_inf->fb0->var.width = fb_inf->rk_lcdc_device[0]->screen.width; + fb_inf->fb0->var.height = fb_inf->rk_lcdc_device[0]->screen.height; + fb_inf->fb0->var.pixclock =fb_inf->rk_lcdc_device[0]->pixclock; + fb_inf->fb0->var.left_margin = fb_inf->rk_lcdc_device[0]->screen.left_margin; + fb_inf->fb0->var.right_margin = fb_inf->rk_lcdc_device[0]->screen.right_margin; + fb_inf->fb0->var.upper_margin = fb_inf->rk_lcdc_device[0]->screen.upper_margin; + fb_inf->fb0->var.lower_margin = fb_inf->rk_lcdc_device[0]->screen.lower_margin; + fb_inf->fb0->var.vsync_len = fb_inf->rk_lcdc_device[0]->screen.vsync_len; + fb_inf->fb0->var.hsync_len = fb_inf->rk_lcdc_device[0]->screen.hsync_len; + fb_inf->fb0->var.red = def_rgb_16.red; + fb_inf->fb0->var.green = def_rgb_16.green; + fb_inf->fb0->var.blue = def_rgb_16.blue; + fb_inf->fb0->var.transp = def_rgb_16.transp; + + fb_inf->fb0->var.nonstd = 0; //win1 format & ypos & xpos (ypos<<20 + xpos<<8 + format) + fb_inf->fb0->var.grayscale = 0; //win1 transprent mode & value(mode<<8 + value) + fb_inf->fb0->var.activate = FB_ACTIVATE_NOW; + fb_inf->fb0->var.accel_flags = 0; + fb_inf->fb0->var.vmode = FB_VMODE_NONINTERLACED; + + fb_inf->fb0->fbops = &fb0_ops; + fb_inf->fb0->flags = FBINFO_FLAG_DEFAULT; + fb_inf->fb0->pseudo_palette = fb_inf->rk_lcdc_device[0]->layer_par[0].pseudo_pal; + + + /************fb1 set ****************/ + fb_inf->fb1->fix.type = FB_TYPE_PACKED_PIXELS; + fb_inf->fb1->fix.type_aux = 0; + fb_inf->fb1->fix.xpanstep = 1; + fb_inf->fb1->fix.ypanstep = 1; + fb_inf->fb1->fix.ywrapstep = 0; + fb_inf->fb1->fix.accel = FB_ACCEL_NONE; + fb_inf->fb1->fix.visual = FB_VISUAL_TRUECOLOR; + + fb_inf->fb1->var.xres = fb_inf->rk_lcdc_device[0]->screen.x_res; + fb_inf->fb1->var.yres = fb_inf->rk_lcdc_device[0]->screen.y_res; + fb_inf->fb1->var.bits_per_pixel = 16; + //fb_inf->fb1_color_deepth = 0; + fb_inf->fb1->var.xres_virtual = fb_inf->rk_lcdc_device[0]->screen.x_res; + fb_inf->fb1->var.yres_virtual = fb_inf->rk_lcdc_device[0]->screen.y_res; + fb_inf->fb1->var.width = fb_inf->rk_lcdc_device[0]->screen.width; + fb_inf->fb1->var.height = fb_inf->rk_lcdc_device[0]->screen.height; + //fb_inf->fb1->var.pixclock = div_u64(1000000000000llu, screen.pixclock); + fb_inf->fb1->var.left_margin = fb_inf->rk_lcdc_device[0]->screen.left_margin; + fb_inf->fb1->var.right_margin = fb_inf->rk_lcdc_device[0]->screen.right_margin; + fb_inf->fb1->var.upper_margin = fb_inf->rk_lcdc_device[0]->screen.upper_margin; + fb_inf->fb1->var.lower_margin = fb_inf->rk_lcdc_device[0]->screen.lower_margin; + fb_inf->fb1->var.vsync_len = fb_inf->rk_lcdc_device[0]->screen.vsync_len; + fb_inf->fb1->var.hsync_len = fb_inf->rk_lcdc_device[0]->screen.hsync_len; + fb_inf->fb1->var.red = def_rgb_16.red; + fb_inf->fb1->var.green = def_rgb_16.green; + fb_inf->fb1->var.blue = def_rgb_16.blue; + fb_inf->fb1->var.transp = def_rgb_16.transp; + + fb_inf->fb1->var.nonstd = 0; //win1 format & ypos & xpos (ypos<<20 + xpos<<8 + format) + fb_inf->fb1->var.grayscale = 0; //win1 transprent mode & value(mode<<8 + value) + fb_inf->fb1->var.activate = FB_ACTIVATE_NOW; + fb_inf->fb1->var.accel_flags = 0; + fb_inf->fb1->var.vmode = FB_VMODE_NONINTERLACED; + + fb_inf->fb1->fbops = &fb1_ops; + fb_inf->fb1->flags = FBINFO_FLAG_DEFAULT; + fb_inf->fb1->pseudo_palette = fb_inf->rk_lcdc_device[0]->layer_par[0].pseudo_pal; + fb_inf->fb1->screen_base = 0; + +#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) + fb0_set_par(fb_inf->fb0); + if (fb_prepare_logo(fb_inf->fb0, FB_ROTATE_UR)) { + /* Start display and show logo on boot */ + fb_set_cmap(&fb_inf->fb0->cmap, fb_inf->fb0); + fb_show_logo(fb_inf->fb0, FB_ROTATE_UR); + fb0_blank(FB_BLANK_UNBLANK, fb_inf->fb0); + } +#endif + return 0; + + +} +int rk_fb_unregister(struct rk_fb_device_driver *fb_device_driver) +{ + + struct rk_fb_inf *fb_inf = platform_get_drvdata(g_fb_pdev); + int i=0; + if(NULL==fb_device_driver){ + printk("rk_fb_register lcdc register fail"); + return -ENOENT; + } + for(i=0;irk_lcdc_device[i]->id == i ){ + fb_inf->rk_lcdc_device[i] = NULL; + fb_inf->num_lcdc--; + break; + } + } + if(i==RK30_MAX_LCDC_SUPPORT){ + printk("rk_fb_unregister lcdc out of support %d",i); + return -ENOENT; + } + + + return 0; +} + +static int __devinit rk_fb_probe (struct platform_device *pdev) +{ + struct resource *res = NULL; + struct rk_fb_inf *fb_inf = NULL; + int ret = 0; + g_fb_pdev=pdev; + /* Malloc rk29fb_inf and set it to pdev for drvdata */ + fb_inf = kmalloc(sizeof(struct rk_fb_inf), GFP_KERNEL); + if(!fb_inf) + { + dev_err(&pdev->dev, ">>fb inf kmalloc fail!"); + ret = -ENOMEM; + } + memset(fb_inf, 0, sizeof(struct rk_fb_inf)); + platform_set_drvdata(pdev, fb_inf); + fb_inf->fb0 = framebuffer_alloc(0, &pdev->dev); + if(!fb_inf->fb0){ + dev_err(&pdev->dev,">> fb0 framebuffer_alloc fail!"); + fb_inf->fb1 = NULL; + ret = -ENOMEM; + } + strcpy(fb_inf->fb0->fix.id, "fb0"); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fb0 buf"); + if (res == NULL) + { + dev_err(&pdev->dev, "failed to get win1 memory \n"); + ret = -ENOENT; + } + fb_inf->fb0->fix.smem_start = res->start; + fb_inf->fb0->fix.smem_len = res->end - res->start + 1; + fb_inf->fb0->screen_base = ioremap(res->start, fb_inf->fb0->fix.smem_len); + memset(fb_inf->fb0->screen_base, 0, fb_inf->fb0->fix.smem_len); + fb_inf->fb1= framebuffer_alloc(0, &pdev->dev); + if(!fb_inf->fb1){ + dev_err(&pdev->dev,">> fb1 framebuffer_alloc fail!"); + fb_inf->fb1 = NULL; + ret = -ENOMEM; + } + strcpy(fb_inf->fb1->fix.id, "fb1"); + printk("rk fb probe ok!\n"); + return 0; +} + +static int __devexit rk_fb_remove(struct platform_device *pdev) +{ + return 0; +} + +static void rk_fb_shutdown(struct platform_device *pdev) +{ + +} + +static struct platform_driver rk_fb_driver = { + .probe = rk_fb_probe, + .remove = __devexit_p(rk_fb_remove), + .driver = { + .name = "rk-fb", + .owner = THIS_MODULE, + }, + .shutdown = rk_fb_shutdown, +}; + +static int __init rk_fb_init(void) +{ + return platform_driver_register(&rk_fb_driver); +} + +static void __exit rk_fb_exit(void) +{ + platform_driver_unregister(&rk_fb_driver); +} + +fs_initcall(rk_fb_init); +module_exit(rk_fb_exit); + diff --git a/drivers/video/rockchip/rk_fb.h b/drivers/video/rockchip/rk_fb.h new file mode 100644 index 000000000000..1721f8558b31 --- /dev/null +++ b/drivers/video/rockchip/rk_fb.h @@ -0,0 +1,113 @@ +/* drivers/video/rk30_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_RK30_FB_H +#define __ARCH_ARM_MACH_RK30_FB_H + +#define RK30_MAX_LCDC_SUPPORT 4 +#define RK30_MAX_LAYER_SUPPORT 4 + + +/******************************************************************** +** ºê¶¨Òå * +********************************************************************/ +/* ÊäÍùÆÁµÄÊý¾Ý¸ñʽ */ +#define OUT_P888 0 +#define OUT_P666 1 //666µÄÆÁ, ½ÓDATA0-17 +#define OUT_P565 2 //565µÄÆÁ, ½ÓDATA0-15 +#define OUT_S888x 4 +#define OUT_CCIR656 6 +#define OUT_S888 8 +#define OUT_S888DUMY 12 +#define OUT_P16BPP4 24 //Ä£Äⷽʽ,¿ØÖÆÆ÷²¢²»Ö§³Ö +#define OUT_D888_P666 0x21 //666µÄÆÁ, ½ÓDATA2-7, DATA10-15, DATA18-23 +#define OUT_D888_P565 0x22 //565µÄÆÁ, ½ÓDATA3-7, DATA10-15, DATA19-23 + +enum data_format{ + ARGB888 = 0, + RGB888, + RGB565, + YUV422, + YUV420, + YUV444, +}; +struct rk_fb_rgb { + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; +}; + +typedef enum _TRSP_MODE +{ + TRSP_CLOSE = 0, + TRSP_FMREG, + TRSP_FMREGEX, + TRSP_FMRAM, + TRSP_FMRAMEX, + TRSP_MASK, + TRSP_INVAL +} TRSP_MODE; + +struct layer_par { + u32 pseudo_pal[16]; + u32 y_offset; + u32 c_offset; + u32 xpos; //start point in panel + u32 ypos; + u16 xsize; //size of panel + u16 ysize; + u16 xact; //act size + u16 yact; + u16 xres_virtual; + u16 yres_virtual; + unsigned long smem_start; + enum data_format format; + + bool support_3d; + const char *name; + int id; +}; + +struct rk_fb_device_driver{ + const char *name; + int id; + struct device *dev; + + struct layer_par *layer_par; + int num_layer; + rk_screen screen; + u32 pixclock; + int (*ioctl)(unsigned int cmd, unsigned long arg,struct layer_par *layer_par); + int (*suspend)(struct layer_par *layer_par); + int (*resume)(struct layer_par *layer_par); + int (*blank)(struct rk_fb_device_driver *rk_fb_dev_drv,int layer_id,int blank_mode); + int (*set_par)(struct rk_fb_device_driver *rk_fb_dev_drv,int layer_id); + int (*pan)(struct rk_fb_device_driver *rk_fb_dev_drv,int layer_id); + +}; + +struct rk_fb_inf { + struct fb_info *fb1; + struct fb_info *fb0; + + struct rk_fb_device_driver *rk_lcdc_device[RK30_MAX_LCDC_SUPPORT]; + + int num_lcdc; +}; +extern int rk_fb_register(struct rk_fb_device_driver *fb_device_driver); +extern int rk_fb_unregister(struct rk_fb_device_driver *fb_device_driver); + +#endif -- 2.34.1