rockbox/utils/atj2137/adfuload/test_binary/lcm/test_lcm.c
Marcin Bukat c626fe7004 atj213x: e100/150 lcd test binary
Change-Id: I3f9fa21dcb33d1cd3081d0c995adfb44e085dd7a
2014-10-18 20:18:01 +02:00

316 lines
8.9 KiB
C

#include "mips.h"
#include "atj213x.h"
extern const unsigned short rockboxlogo[];
unsigned short framebuffer[320*240] __attribute__((aligned(32))) = {[0 ... 76799] = 0};
static void backlight_init(void)
{
/* backlight clock enable, select backlight clock as 32kHz */
CMU_FMCLK = (CMU_FMCLK & ~(CMU_FMCLK_BCLK_MASK)) | CMU_FMCLK_BCKE | CMU_FMCLK_BCLK_32K;
/* baclight enable */
PMU_CTL |= PMU_CTL_BL_EN;
/* pwm output, phase high, some initial duty cycle set as 24/32 */
PMU_CHG = ((PMU_CHG & ~PMU_CHG_PDOUT_MASK)| PMU_CHG_PBLS_PWM | PMU_CHG_PPHS_HIGH | PMU_CHG_PDUT(24));
}
static void backlight_set(int level)
{
/* set duty cycle in 1/32 units */
PMU_CHG = ((PMU_CHG & ~PMU_CHG_PDOUT_MASK) | PMU_CHG_PDUT(level));
}
static void wdt_feed(void)
{
RTC_WDCTL |= RTC_WDCTL_CLR;
}
void set_sw_interrupt0(void)
{
unsigned int val;
asm volatile("mfc0 %0,$13" : "=r" (val));
val |= 0x100;
asm volatile("mtc0 %0,$13" : "+r" (val));
}
int lcm_wait_fifo_empty(void)
{
volatile int timeout = 100000;
while (--timeout)
if (YUV2RGB_CTL & 0x04)
return 0;
return -1;
}
static inline void lcm_rs_command(void)
{
lcm_wait_fifo_empty();
YUV2RGB_CTL = 0x802ae;
}
static inline void lcm_rs_data(void)
{
lcm_wait_fifo_empty();
YUV2RGB_CTL = 0x902ae;
}
static inline void lcm_fb_data(void)
{
lcm_rs_command();
YUV2RGB_FIFODATA = 0x22; /* write GRAM command */
YUV2RGB_CTL = 0xa02ae; /* AHB bus write fifo */
}
static inline lcd_reg_write(int reg, int val)
{
lcm_rs_command();
YUV2RGB_FIFODATA = reg;
lcm_rs_data();
YUV2RGB_FIFODATA = val;
}
/* strips off MIPS segment coding */
#define PHYADDR(x) ((x) & 0x1fffffff)
/* rb compat defines */
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define FBADDR(x,y) ((short *)framebuffer + LCD_WIDTH*y + x)
static void lcd_set_gram_area(int x_start, int y_start,
int x_end, int y_end)
{
/* here we exploit the fact that width fits in LSB only */
lcd_reg_write(0x02, 0x00); /* column start MSB */
lcd_reg_write(0x03, x_start); /* column start LSB */
lcd_reg_write(0x04, 0x00); /* column end MSB */
lcd_reg_write(0x05, x_end); /* column end LSB */
lcd_reg_write(0x06, y_start>>8); /* row start MSB */
lcd_reg_write(0x07, y_start&0xff); /* row start LSB */
lcd_reg_write(0x08, y_end>>8); /* row end MSB */
lcd_reg_write(0x09, y_end&0xff); /* row end LSB */
}
void lcd_update_rect(int x, int y, int width, int height)
{
unsigned int end_x, end_y, row, col, *fbptr;
x &= ~1; /* we transfer 2px at once */
width = (width + 1) & ~1; /* adjust the width */
end_x = x + width - 1;
end_y = y + height - 1;
lcd_set_gram_area(x, y, end_x, end_y); /* set GRAM window */
lcm_fb_data(); /* prepare for AHB write to fifo */
for (row=y; row<=end_y; row++)
{
fbptr = (uint32_t *)FBADDR(x,row);
for (col=x; col<end_x; col+=2)
YUV2RGB_FIFODATA = *fbptr++;
}
}
/* for reference
* When in act213x_fb_data()
* YUV2RGB_CTL = 0xa02ae; -> DMA0-3 (AHB bus)
* YUV2RGB_CTL = 0xa00ae; -> DMA4-7 (special bus)
*/
static void lcd_update_dma(void)
{
lcd_set_gram_area(0, 0, LCD_WIDTH-1, LCD_HEIGHT-1);
/* AHB bus DMA channels are 0-3 */
DMA_MODE(0) = (0x00<<29) | /* dst burst length = single */
(0x00<<28) | /* DMA no reload */
(0x00<<27) | /* dst DSP mode disable */
(0x00<<26) | /* dst row mode */
(0x00<<25) | /* dst address count dir - don't care */
(0x01<<24) | /* dst fixed address */
(0x18<<19) | /* dst DRQ trig source LCM */
(0x02<<17) | /* dst transfer width 32bits */
(0x01<<16) | /* dst transfer fixed size chunks */
(0x05<<13) | /* src burst length = incr8 */
(0x00<<12) | /* reserved */
(0x00<<11) | /* src DSP mode disable */
(0x00<<10) | /* src row mode */
(0x00<<9) | /* src address count dir - increase */
(0x00<<8) | /* src address not fixed */
(0x10<<3) | /* src DRQ trig source SDRAM */
(0x02<<1) | /* src transfer width 32bit */
(0x00<<0); /* src transfer not in fixed chunks */
DMA_SRC(0) = PHYADDR((uint32_t)framebuffer);
DMA_DST(0) = PHYADDR((uint32_t)&YUV2RGB_FIFODATA);
DMA_CNT(0) = 240*320*2; /* in bytes */
DMA_CMD(0) = 1; /* start dma operation */
}
static lcm_init(void)
{
CMU_DEVCLKEN |= (1<<8)|(1<<1); /* dma clk, lcm clk */
CMU_DMACLK = 1; /* DMA4 clock enable */
/* reset DMA4 */
DMAC_CTL |= (1<<20);
udelay(1);
DMAC_CTL &= ~(1<<20);
GPIO_MFCTL1 = (1<<31); // enable multifunction
GPIO_MFCTL0 = (GPIO_MFCTL0 & ~(0x07<<22 | 0x03<<14 | 0x03<<6 | 0x07<<3 | 0x07)) | // 0xfe3f3f00
0x02<<22 | 0x02<<14 | 0x02<<6 | 0x02<<3|0x02; // 0x808092
udelay(1);
lcm_rs_command(); /* this has side effect of enabling whole block */
YUV2RGB_CLKCTL = 0x102; /* lcm clock divider */
}
/* google says COG-IZT2298 is 2.8" lcd module */
static lcd_init(void)
{
int x,y;
/* lcd reset pin GPIOA16 */
GPIO_AOUTEN |= (1<<16);
GPIO_ADAT |= (1<<16);
mdelay(10);
GPIO_ADAT &= ~(1<<16);
mdelay(10);
GPIO_ADAT |= (1<<16);
mdelay(10);
/* lcd controller init sequence matching HX8347-D */
lcd_reg_write(0xea, 0x00);
lcd_reg_write(0xeb, 0x20);
lcd_reg_write(0xec, 0x0f);
lcd_reg_write(0xed, 0xc4);
lcd_reg_write(0xe8, 0xc4);
lcd_reg_write(0xe9, 0xc4);
lcd_reg_write(0xf1, 0xc4);
lcd_reg_write(0xf2, 0xc4);
lcd_reg_write(0x27, 0xc4);
lcd_reg_write(0x40, 0x00); /* gamma block start */
lcd_reg_write(0x41, 0x00);
lcd_reg_write(0x42, 0x01);
lcd_reg_write(0x43, 0x13);
lcd_reg_write(0x44, 0x10);
lcd_reg_write(0x45, 0x26);
lcd_reg_write(0x46, 0x08);
lcd_reg_write(0x47, 0x51);
lcd_reg_write(0x48, 0x02);
lcd_reg_write(0x49, 0x12);
lcd_reg_write(0x4a, 0x18);
lcd_reg_write(0x4b, 0x19);
lcd_reg_write(0x4c, 0x14);
lcd_reg_write(0x50, 0x19);
lcd_reg_write(0x51, 0x2f);
lcd_reg_write(0x52, 0x2c);
lcd_reg_write(0x53, 0x3e);
lcd_reg_write(0x54, 0x3f);
lcd_reg_write(0x55, 0x3f);
lcd_reg_write(0x56, 0x2e);
lcd_reg_write(0x57, 0x77);
lcd_reg_write(0x58, 0x0b);
lcd_reg_write(0x59, 0x06);
lcd_reg_write(0x5a, 0x07);
lcd_reg_write(0x5b, 0x0d);
lcd_reg_write(0x5c, 0x1d);
lcd_reg_write(0x5d, 0xcc); /* gamma block end */
lcd_reg_write(0x1b, 0x1b);
lcd_reg_write(0x1a, 0x01);
lcd_reg_write(0x24, 0x2f);
lcd_reg_write(0x25, 0x57);
lcd_reg_write(0x23, 0x86);
lcd_reg_write(0x18, 0x36); /* 70Hz framerate */
lcd_reg_write(0x19, 0x01); /* osc enable */
lcd_reg_write(0x01, 0x00);
lcd_reg_write(0x1f, 0x88);
mdelay(5);
lcd_reg_write(0x1f, 0x80);
mdelay(5);
lcd_reg_write(0x1f, 0x90);
mdelay(5);
lcd_reg_write(0x1f, 0xd0);
mdelay(5);
lcd_reg_write(0x17, 0x05); /* 16bpp */
lcd_reg_write(0x36, 0x00);
lcd_reg_write(0x28, 0x38);
mdelay(40);
lcd_reg_write(0x28, 0x3c);
lcd_reg_write(0x02, 0x00); /* column start MSB */
lcd_reg_write(0x03, 0x00); /* column start LSB */
lcd_reg_write(0x04, 0x00); /* column end MSB */
lcd_reg_write(0x05, 0xef); /* column end LSB */
lcd_reg_write(0x06, 0x00); /* row start MSB */
lcd_reg_write(0x07, 0x00); /* row start LSB */
lcd_reg_write(0x08, 0x01); /* row end MSB */
lcd_reg_write(0x09, 0x3f); /* row end LSB */
lcm_fb_data(); /* prepare for DMA write to fifo */
/* clear lcd gram */
for (y=0; y<LCD_HEIGHT; y++)
for (x=0; x<(LCD_WIDTH>>1); x++)
YUV2RGB_FIFODATA = 0;
}
int main(void)
{
int i;
RTC_WDCTL &= ~(1<<4); /* disable WDT */
/* Configure T0 interrupt as IP6. IP6 is unmasked in crt0.S */
INTC_CFG0 = 0;
INTC_CFG1 = 0;
INTC_CFG2 = (1<<10);
/* unmask T0 source in INTC */
INTC_MSK |= (1<<10);
backlight_init();
/* copy rb logo image */
for (i=0; i<240*74; i++)
framebuffer[i] = rockboxlogo[i];
lcm_init();
lcd_init();
lcd_update_rect(0,0,240,74);
/* ADEC_N63.BIN seems to setup P_CLK as 7.5MHz which is timer clk */
RTC_T0 = (7500000*10/32); /* with this we should see transition every ~0.3125s and 'black' every ~10s */
RTC_T0CTL = (1<<5) | (1<<2) | (1<<1) | (1<<0); /* timer enable, timer reload, timer irq, clear irq pending bit */
while(1)
{
/* otherwise wdt will trigger reset */
//wdt_feed();
}
return 0;
}
/* Timer T0 interrupt service routine */
INT_T0()
{
static int j = 0;
/* clear pending bit in timer module */
RTC_T0CTL |= 1;
/* change backligh */
backlight_set(++j);
}