From a54e0b6dba1b79b6a449395ffdbfc7220bbbe80c Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Sat, 18 Apr 2009 17:38:55 +0000 Subject: Onda VX747: * Add YUV support * Clean up LCD driver a bit and speed it up git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20730 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/jz4740.h | 102 +++++++++++++++----- firmware/export/r61509.h | 1 + firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c | 71 +++++++++++--- firmware/target/mips/ingenic_jz47xx/lcd-target.h | 2 +- .../ingenic_jz47xx/onda_vx747/lcd-onda_vx747.c | 106 ++++++++------------- 5 files changed, 177 insertions(+), 105 deletions(-) diff --git a/firmware/export/jz4740.h b/firmware/export/jz4740.h index cacdd1e488..b0f3f538a3 100644 --- a/firmware/export/jz4740.h +++ b/firmware/export/jz4740.h @@ -1305,10 +1305,10 @@ #define ICDC_CDCCR1_SUSPD (1 << 1) #define ICDC_CDCCR1_RST (1 << 0) -#define ICDC_CDCCR2_AINVOL(n) ((n & 5) << 16) -#define ICDC_CDCCR2_SMPR(n) ((n & 4) << 8) -#define ICDC_CDCCR2_MICBG(n) ((n & 2) << 4) -#define ICDC_CDCCR2_HPVOL(n) ((n & 2) << 0) +#define ICDC_CDCCR2_AINVOL(n) ((n & 0x1F) << 16) +#define ICDC_CDCCR2_SMPR(n) ((n & 0xF) << 8) +#define ICDC_CDCCR2_MICBG(n) ((n & 0x3) << 4) +#define ICDC_CDCCR2_HPVOL(n) ((n & 0x3) << 0) #define ICDC_CDCCR2_AINVOL_DB(n) ((n+34.5)/1.5) @@ -1423,7 +1423,7 @@ #define SSI_CR1_MULTS (1 << 22) #define SSI_CR1_FMAT_BIT 20 #define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) - #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ + #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ @@ -4984,7 +4984,7 @@ do{ \ // IPU_REG_BASE #define IPU_P_BASE 0x13080000 -#define IPU__OFFSET 0x13080000 +#define IPU_V_BASE 0xB3080000 #define IPU__SIZE 0x00001000 struct ipu_module @@ -5069,10 +5069,12 @@ struct Ration2m #define INFMT_YCbCr422 (5 << 0) #define INFMT_YCbCr444 (6 << 0) #define INFMT_YCbCr411 (7 << 0) +#define INFMT_MASK (7) #define OUTFMT_RGB555 (0 << 16) #define OUTFMT_RGB565 (1 << 16) #define OUTFMT_RGB888 (2 << 16) +#define OUTFMT_MASK (3 << 16) // REG_IN_FM_GS field define #define IN_FM_W(val) ((val) << 16) @@ -5086,7 +5088,6 @@ struct Ration2m #define U_STRIDE(val) ((val) << 16) #define V_STRIDE(val) ((val) << 0) - #define VE_IDX_SFT 0 #define HE_IDX_SFT 16 @@ -5099,53 +5100,106 @@ struct Ration2m #define W_COEF_MSK 0xFF // function about REG_CTRL -#define IPU_STOP_IPU(IPU_V_BASE) \ +#define IPU_STOP_IPU() \ REG32(IPU_V_BASE + REG_CTRL) &= ~IPU_EN; -#define IPU_RUN_IPU(IPU_V_BASE) \ +#define IPU_RUN_IPU() \ REG32(IPU_V_BASE + REG_CTRL) |= IPU_EN; -#define IPU_RESET_IPU(IPU_V_BASE) \ +#define IPU_RESET_IPU() \ REG32(IPU_V_BASE + REG_CTRL) |= IPU_RESET; -#define IPU_DISABLE_IRQ(IPU_V_BASE) \ +#define IPU_DISABLE_IRQ() \ REG32(IPU_V_BASE + REG_CTRL) &= ~FM_IRQ_EN; -#define IPU_DISABLE_RSIZE(IPU_V_BASE) \ +#define IPU_DISABLE_RSIZE() \ REG32(IPU_V_BASE + REG_CTRL) &= ~RSZ_EN; -#define IPU_ENABLE_RSIZE(IPU_V_BASE) \ +#define IPU_ENABLE_RSIZE() \ REG32(IPU_V_BASE + REG_CTRL) |= RSZ_EN; -#define IPU_IS_ENABLED(IPU_V_BASE) \ +#define IPU_IS_ENABLED() \ (REG32(IPU_V_BASE + REG_CTRL) & IPU_EN) // function about REG_STATUS -#define IPU_CLEAR_END_FLAG(IPU_V_BASE) \ +#define IPU_CLEAR_END_FLAG() \ REG32(IPU_V_BASE + REG_STATUS) &= ~OUT_END; -#define IPU_POLLING_END_FLAG(IPU_V_BASE) \ +#define IPU_POLLING_END_FLAG() \ (REG32(IPU_V_BASE + REG_STATUS) & OUT_END) +#define IPU_SET_INFMT(fmt) \ + REG32(IPU_V_BASE + REG_D_FMT) = (REG32(IPU_V_BASE + REG_D_FMT) & ~INFMT_MASK) | (fmt); + +#define IPU_SET_OUTFMT(fmt) \ + REG32(IPU_V_BASE + REG_D_FMT) = (REG32(IPU_V_BASE + REG_D_FMT) & ~OUTFMT_MASK) | (fmt); + +#define IPU_SET_IN_FM(w, h) \ + REG32(IPU_V_BASE + REG_IN_FM_GS) = IN_FM_W(w) | IN_FM_H(h); + +#define IPU_SET_Y_STRIDE(stride) \ + REG32(IPU_V_BASE + REG_Y_STRIDE) = (stride); + +#define IPU_SET_UV_STRIDE(u, v) \ + REG32(IPU_V_BASE + REG_UV_STRIDE) = U_STRIDE(u) | V_STRIDE(v); + +#define IPU_SET_Y_ADDR(addr) \ + REG32(IPU_V_BASE + REG_Y_ADDR) = (addr); + +#define IPU_SET_U_ADDR(addr) \ + REG32(IPU_V_BASE + REG_U_ADDR) = (addr); + +#define IPU_SET_V_ADDR(addr) \ + REG32(IPU_V_BASE + REG_V_ADDR) = (addr); + +#define IPU_SET_OUT_ADDR(addr) \ + REG32(IPU_V_BASE + REG_OUT_ADDR) = (addr); + +#define IPU_SET_OUT_FM(w, h) \ + REG32(IPU_V_BASE + REG_OUT_GS) = OUT_FM_W(w) | OUT_FM_H(h); + +#define IPU_SET_OUT_STRIDE(stride) \ + REG32(IPU_V_BASE + REG_OUT_STRIDE) = (stride); + +#define IPU_SET_CSC_C0_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C0_COEF) = (coef); + +#define IPU_SET_CSC_C1_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C1_COEF) = (coef); + +#define IPU_SET_CSC_C2_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C2_COEF) = (coef); + +#define IPU_SET_CSC_C3_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C3_COEF) = (coef); + +#define IPU_SET_CSC_C4_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C4_COEF) = (coef); + +/* YCbCr */ /* parameter R = 1.164 * (Y - 16) + 1.596 * (cr - 128) {C0, C1} G = 1.164 * (Y - 16) - 0.392 * (cb -128) - 0.813 * (cr - 128) {C0, C2, C3} B = 1.164 * (Y - 16) + 2.017 * (cb - 128) {C0, C4} */ +#define YCBCR_CSC_C0 0x4A8 /* 1.164 * 1024 */ +#define YCBCR_CSC_C1 0x662 /* 1.596 * 1024 */ +#define YCBCR_CSC_C2 0x191 /* 0.392 * 1024 */ +#define YCBCR_CSC_C3 0x341 /* 0.813 * 1024 */ +#define YCBCR_CSC_C4 0x811 /* 2.017 * 1024 */ -#if 1 -#define YUV_CSC_C0 0x4A8 /* 1.164 * 1024 */ -#define YUV_CSC_C1 0x662 /* 1.596 * 1024 */ -#define YUV_CSC_C2 0x191 /* 0.392 * 1024 */ -#define YUV_CSC_C3 0x341 /* 0.813 * 1024 */ -#define YUV_CSC_C4 0x811 /* 2.017 * 1024 */ -#else + +/* YUV */ +/* parameter + R = 1 * (Y – 0) + 1.4026 * (V - 128) {C0, C1} + G = 1 * (Y – 0) – 0.3444 * (U - 128) – 0.7144 * (V - 128) {C0, C2, C3} + B = 1 * (Y – 0) + 1.7730 * (U - 128) {C0, C4} +*/ #define YUV_CSC_C0 0x400 #define YUV_CSC_C1 0x59C #define YUV_CSC_C2 0x161 #define YUV_CSC_C3 0x2DC #define YUV_CSC_C4 0x718 -#endif #endif /* _IPU_H_ */ diff --git a/firmware/export/r61509.h b/firmware/export/r61509.h index 53f0440742..f61b620084 100644 --- a/firmware/export/r61509.h +++ b/firmware/export/r61509.h @@ -26,6 +26,7 @@ #define __R61509_H /* Register list */ +#define REG_DEVICE_CODE 0x000 #define REG_DRIVER_OUTPUT 0x001 #define REG_LCD_DR_WAVE_CTRL 0x002 #define REG_ENTRY_MODE 0x003 diff --git a/firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c b/firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c index 783621c88b..25265395b2 100644 --- a/firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c @@ -71,7 +71,14 @@ bool lcd_active(void) /* Update a fraction of the display. */ void lcd_update_rect(int x, int y, int width, int height) { -x=0;y=0;width=LCD_WIDTH;height=LCD_HEIGHT; /* HACK! */ + /* Currently only do full updates. + * DMA can't handle partial updates and CPU is too slow compared + * to full DMA updates */ + x = 0; + y = 0; + width = LCD_WIDTH; + height = LCD_HEIGHT; + mutex_lock(&lcd_mtx); __cpm_start_lcd(); @@ -82,12 +89,12 @@ x=0;y=0;width=LCD_WIDTH;height=LCD_HEIGHT; /* HACK! */ REG_DMAC_DCCSR(DMA_LCD_CHANNEL) = DMAC_DCCSR_NDES; REG_DMAC_DSAR(DMA_LCD_CHANNEL) = PHYSADDR((unsigned long)&lcd_framebuffer[y][x]); - REG_DMAC_DRSR(DMA_LCD_CHANNEL) = DMAC_DRSR_RS_SLCD; /* source = SLCD */ + REG_DMAC_DRSR(DMA_LCD_CHANNEL) = DMAC_DRSR_RS_SLCD; REG_DMAC_DTAR(DMA_LCD_CHANNEL) = PHYSADDR(SLCD_FIFO); - REG_DMAC_DTCR(DMA_LCD_CHANNEL) = width*height; + REG_DMAC_DTCR(DMA_LCD_CHANNEL) = (width * height) >> 3; REG_DMAC_DCMD(DMA_LCD_CHANNEL) = ( DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 - | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BIT ); + | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE ); __dcache_writeback_all(); /* Size of framebuffer is way bigger than cache size. We need to find a way to make the framebuffer uncached, so this statement can get removed. */ @@ -101,7 +108,6 @@ x=0;y=0;width=LCD_WIDTH;height=LCD_HEIGHT; /* HACK! */ wakeup_wait(&lcd_wkup, TIMEOUT_BLOCK); /* Sleeping in lcd_update() should be safe */ REG_DMAC_DCCSR(DMA_LCD_CHANNEL) &= ~DMAC_DCCSR_EN; /* Disable DMA channel */ - dma_disable(); while(REG_SLCD_STATE & SLCD_STATE_BUSY); @@ -139,17 +145,54 @@ void lcd_update(void) lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); } -/* TODO: use IPU */ +/* (Mis)use LCD framebuffer as a temporary buffer */ void lcd_blit_yuv(unsigned char * const src[3], int src_x, int src_y, int stride, int x, int y, int width, int height) { - (void)src; - (void)src_x; - (void)src_y; - (void)stride; - (void)x; - (void)y; - (void)width; - (void)height; + __dcache_writeback_all(); + + __cpm_start_ipu(); + + IPU_STOP_IPU(); + IPU_RESET_IPU() + IPU_CLEAR_END_FLAG(); + + IPU_DISABLE_RSIZE(); + IPU_DISABLE_IRQ(); + + IPU_SET_INFMT(INFMT_YUV420); + IPU_SET_OUTFMT(OUTFMT_RGB565); + + IPU_SET_IN_FM(width, height); + IPU_SET_Y_STRIDE(stride); + IPU_SET_UV_STRIDE(stride, stride); + + IPU_SET_Y_ADDR((unsigned long)src[0]); + IPU_SET_U_ADDR((unsigned long)src[2]); + IPU_SET_V_ADDR((unsigned long)src[3]); + IPU_SET_OUT_ADDR(PHYSADDR((unsigned long)&lcd_framebuffer[y][x])); + + IPU_SET_OUT_FM(width, height); + IPU_SET_OUT_STRIDE(stride); + + IPU_SET_CSC_C0_COEF(YUV_CSC_C0); + IPU_SET_CSC_C1_COEF(YUV_CSC_C1); + IPU_SET_CSC_C2_COEF(YUV_CSC_C2); + IPU_SET_CSC_C2_COEF(YUV_CSC_C3); + IPU_SET_CSC_C4_COEF(YUV_CSC_C4); + + IPU_RUN_IPU(); + + while(!(IPU_POLLING_END_FLAG()) && IPU_IS_ENABLED()); + + IPU_CLEAR_END_FLAG(); + IPU_STOP_IPU(); + + //__cpm_stop_ipu(); + + __dcache_invalidate_all(); + + /* YUV speed is limited by LCD speed */ + lcd_update_rect(x, y, width, height); } diff --git a/firmware/target/mips/ingenic_jz47xx/lcd-target.h b/firmware/target/mips/ingenic_jz47xx/lcd-target.h index 95eecf7823..95ce7acbb5 100644 --- a/firmware/target/mips/ingenic_jz47xx/lcd-target.h +++ b/firmware/target/mips/ingenic_jz47xx/lcd-target.h @@ -29,7 +29,7 @@ void lcd_init_device(void); void lcd_init_controller(void); -void lcd_set_target(short x, short y, short width, short height); +void lcd_set_target(int x, int y, int width, int height); void lcd_on(void); void lcd_off(void); diff --git a/firmware/target/mips/ingenic_jz47xx/onda_vx747/lcd-onda_vx747.c b/firmware/target/mips/ingenic_jz47xx/onda_vx747/lcd-onda_vx747.c index 85947eb66c..a2240e0f7d 100644 --- a/firmware/target/mips/ingenic_jz47xx/onda_vx747/lcd-onda_vx747.c +++ b/firmware/target/mips/ingenic_jz47xx/onda_vx747/lcd-onda_vx747.c @@ -25,23 +25,22 @@ #include "lcd.h" #include "lcd-target.h" -#define PIN_CS_N (32*1+17) /* Chip select */ -#define PIN_RESET_N (32*1+18) /* Reset */ -#define LCD_PCLK (20000000) /* LCD PCLK */ +#define PIN_CS_N (32*1+17) /* Chip select */ +#define PIN_RESET_N (32*1+18) /* Reset */ +#define LCD_PCLK (20000000) /* LCD PCLK */ #define my__gpio_as_lcd_16bit() \ do { \ REG_GPIO_PXFUNS(2) = 0x001cffff; \ REG_GPIO_PXSELC(2) = 0x001cffff; \ - REG_GPIO_PXPES(2) = 0x001cffff; \ + REG_GPIO_PXPES(2) = 0x001cffff; \ } while (0) -#define SLEEP(x) for(i=0; i 0x1ff ) val = 0x1ff; /* CPM_LPCDR is too large, set it to 0x1ff */ __cpm_set_pixdiv(val); @@ -215,7 +190,6 @@ static void _set_lcd_clock(void) void lcd_init_controller(void) { - int i; _display_pin_init(); _set_lcd_bus(); _set_lcd_clock(); @@ -223,37 +197,37 @@ void lcd_init_controller(void) _display_init(); } -void lcd_set_target(short x, short y, short width, short height) +void lcd_set_target(int x, int y, int width, int height) { #if CONFIG_ORIENTATION == SCREEN_PORTRAIT - SLCD_SEND_COMMAND(REG_RAM_HADDR_START, y); /* y_start */ - SLCD_SEND_COMMAND(REG_RAM_HADDR_END, y+width-1); /* y_end */ - SLCD_SEND_COMMAND(REG_RAM_VADDR_START, x); /* x_start */ - SLCD_SEND_COMMAND(REG_RAM_VADDR_END, x+height-1); /* x_end */ + SLCD_SEND_COMMAND(REG_RAM_HADDR_START, x); + SLCD_SEND_COMMAND(REG_RAM_HADDR_END, x + width - 1); + SLCD_SEND_COMMAND(REG_RAM_VADDR_START, y); + SLCD_SEND_COMMAND(REG_RAM_VADDR_END, y + height - 1); + SLCD_SEND_COMMAND(REG_RAM_HADDR_SET, x); + SLCD_SEND_COMMAND(REG_RAM_VADDR_SET, y); #else - SLCD_SEND_COMMAND(REG_RAM_HADDR_START, y); /* y_start */ - SLCD_SEND_COMMAND(REG_RAM_HADDR_END, y+height-1); /* y_end */ - SLCD_SEND_COMMAND(REG_RAM_VADDR_START, x); /* x_start */ - SLCD_SEND_COMMAND(REG_RAM_VADDR_END, x+width-1); /* x_end */ + SLCD_SEND_COMMAND(REG_RAM_HADDR_START, y); + SLCD_SEND_COMMAND(REG_RAM_HADDR_END, y + height - 1); + SLCD_SEND_COMMAND(REG_RAM_VADDR_START, x); + SLCD_SEND_COMMAND(REG_RAM_VADDR_END, x + width - 1); + SLCD_SEND_COMMAND(REG_RAM_HADDR_SET, y); + SLCD_SEND_COMMAND(REG_RAM_VADDR_SET, x); #endif - SLCD_SEND_COMMAND(REG_RAM_HADDR_SET, y); /* set cursor at x_start */ - SLCD_SEND_COMMAND(REG_RAM_VADDR_SET, x); /* set cursor at y_start */ SLCD_SET_COMMAND(REG_RW_GRAM); /* write data to GRAM */ } void lcd_set_flip(bool yesno) { - int i; - __cpm_start_lcd(); #if CONFIG_ORIENTATION == SCREEN_PORTRAIT if(yesno) { - SLCD_SEND_COMMAND(REG_ENTRY_MODE, (ENTRY_MODE_BGR | ENTRY_MODE_HWM)); + SLCD_SEND_COMMAND(REG_ENTRY_MODE, ENTRY_MODE_BGR); } else { - SLCD_SEND_COMMAND(REG_ENTRY_MODE, (ENTRY_MODE_BGR | ENTRY_MODE_VID | ENTRY_MODE_HID | ENTRY_MODE_HWM)); + SLCD_SEND_COMMAND(REG_ENTRY_MODE, (ENTRY_MODE_BGR | ENTRY_MODE_VID | ENTRY_MODE_HID)); } #else if(yesno) -- cgit v1.2.3