diff options
Diffstat (limited to 'firmware/target/arm/s5l8702/ipod6g')
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c | 78 |
1 files changed, 52 insertions, 26 deletions
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c index f9dbab6180..bf6c1a1402 100644 --- a/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "pmu-target.h" | 28 | #include "pmu-target.h" |
29 | #include "power.h" | 29 | #include "power.h" |
30 | #include "string.h" | 30 | #include "string.h" |
31 | #include "dma-s5l8702.h" | ||
31 | 32 | ||
32 | 33 | ||
33 | #define R_HORIZ_GRAM_ADDR_SET 0x200 | 34 | #define R_HORIZ_GRAM_ADDR_SET 0x200 |
@@ -49,10 +50,8 @@ | |||
49 | /** globals **/ | 50 | /** globals **/ |
50 | 51 | ||
51 | int lcd_type; /* also needed in debug-s5l8702.c */ | 52 | int lcd_type; /* also needed in debug-s5l8702.c */ |
52 | static struct dma_lli lcd_lli[(LCD_WIDTH * LCD_HEIGHT - 1) / 0xfff] CACHEALIGN_ATTR; | ||
53 | static struct semaphore lcd_wakeup; | ||
54 | static struct mutex lcd_mutex; | 53 | static struct mutex lcd_mutex; |
55 | static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH]; | 54 | static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH] CACHEALIGN_ATTR; |
56 | static bool lcd_ispowered; | 55 | static bool lcd_ispowered; |
57 | 56 | ||
58 | #define SLEEP 0 | 57 | #define SLEEP 0 |
@@ -197,6 +196,48 @@ static const unsigned short lcd_init_sequence_23[] = | |||
197 | }; | 196 | }; |
198 | #endif | 197 | #endif |
199 | 198 | ||
199 | /* DMA configuration */ | ||
200 | |||
201 | /* one single transfer at once, needed LLIs: | ||
202 | * screen_size / (DMAC_LLI_MAX_COUNT << swidth) = | ||
203 | * (320*240*2) / (4095*2) = 19 | ||
204 | */ | ||
205 | #define LCD_DMA_TSKBUF_SZ 1 /* N tasks, MUST be pow2 */ | ||
206 | #define LCD_DMA_LLIBUF_SZ 32 /* N LLIs, MUST be pow2 */ | ||
207 | |||
208 | static struct dmac_tsk lcd_dma_tskbuf[LCD_DMA_TSKBUF_SZ]; | ||
209 | static struct dmac_lli volatile \ | ||
210 | lcd_dma_llibuf[LCD_DMA_LLIBUF_SZ] CACHEALIGN_ATTR; | ||
211 | |||
212 | static struct dmac_ch lcd_dma_ch = { | ||
213 | .dmac = &s5l8702_dmac0, | ||
214 | .prio = DMAC_CH_PRIO(4), | ||
215 | .cb_fn = NULL, | ||
216 | |||
217 | .tskbuf = lcd_dma_tskbuf, | ||
218 | .tskbuf_mask = LCD_DMA_TSKBUF_SZ - 1, | ||
219 | .queue_mode = QUEUE_NORMAL, | ||
220 | |||
221 | .llibuf = lcd_dma_llibuf, | ||
222 | .llibuf_mask = LCD_DMA_LLIBUF_SZ - 1, | ||
223 | .llibuf_bus = DMAC_MASTER_AHB1, | ||
224 | }; | ||
225 | |||
226 | static struct dmac_ch_cfg lcd_dma_ch_cfg = { | ||
227 | .srcperi = S5L8702_DMAC0_PERI_MEM, | ||
228 | .dstperi = S5L8702_DMAC0_PERI_LCD_WR, | ||
229 | .sbsize = DMACCxCONTROL_BSIZE_1, | ||
230 | .dbsize = DMACCxCONTROL_BSIZE_1, | ||
231 | .swidth = DMACCxCONTROL_WIDTH_16, | ||
232 | .dwidth = DMACCxCONTROL_WIDTH_16, | ||
233 | .sbus = DMAC_MASTER_AHB1, | ||
234 | .dbus = DMAC_MASTER_AHB1, | ||
235 | .sinc = DMACCxCONTROL_INC_ENABLE, | ||
236 | .dinc = DMACCxCONTROL_INC_DISABLE, | ||
237 | .prot = DMAC_PROT_CACH | DMAC_PROT_BUFF | DMAC_PROT_PRIV, | ||
238 | .lli_xfer_max_count = DMAC_LLI_MAX_COUNT, | ||
239 | }; | ||
240 | |||
200 | static inline void s5l_lcd_write_reg(int cmd, unsigned int data) | 241 | static inline void s5l_lcd_write_reg(int cmd, unsigned int data) |
201 | { | 242 | { |
202 | while (LCD_STATUS & 0x10); | 243 | while (LCD_STATUS & 0x10); |
@@ -328,12 +369,14 @@ void lcd_awake(void) | |||
328 | void lcd_init_device(void) | 369 | void lcd_init_device(void) |
329 | { | 370 | { |
330 | /* Detect lcd type */ | 371 | /* Detect lcd type */ |
331 | semaphore_init(&lcd_wakeup, 1, 0); | ||
332 | mutex_init(&lcd_mutex); | 372 | mutex_init(&lcd_mutex); |
333 | lcd_type = (PDAT6 & 0x30) >> 4; | 373 | lcd_type = (PDAT6 & 0x30) >> 4; |
334 | while (!(LCD_STATUS & 0x2)); | 374 | while (!(LCD_STATUS & 0x2)); |
335 | LCD_CONFIG = 0x80100db0; | 375 | LCD_CONFIG = 0x80100db0; |
336 | 376 | ||
377 | /* Configure DMA channel */ | ||
378 | dmac_ch_init(&lcd_dma_ch, &lcd_dma_ch_cfg); | ||
379 | |||
337 | lcd_ispowered = true; | 380 | lcd_ispowered = true; |
338 | } | 381 | } |
339 | 382 | ||
@@ -362,8 +405,10 @@ extern void lcd_write_line(const fb_data *addr, | |||
362 | static void displaylcd_setup(int x, int y, int width, int height) ICODE_ATTR; | 405 | static void displaylcd_setup(int x, int y, int width, int height) ICODE_ATTR; |
363 | static void displaylcd_setup(int x, int y, int width, int height) | 406 | static void displaylcd_setup(int x, int y, int width, int height) |
364 | { | 407 | { |
408 | /* TODO: ISR()->panicf()->lcd_update() blocks forever */ | ||
365 | mutex_lock(&lcd_mutex); | 409 | mutex_lock(&lcd_mutex); |
366 | while (DMAC0C4CONFIG & 1) semaphore_wait(&lcd_wakeup, HZ / 10); | 410 | while (dmac_ch_running(&lcd_dma_ch)) |
411 | yield(); | ||
367 | 412 | ||
368 | int xe = (x + width) - 1; /* max horiz */ | 413 | int xe = (x + width) - 1; /* max horiz */ |
369 | int ye = (y + height) - 1; /* max vert */ | 414 | int ye = (y + height) - 1; /* max vert */ |
@@ -398,31 +443,12 @@ static void displaylcd_setup(int x, int y, int width, int height) | |||
398 | static void displaylcd_dma(int pixels) ICODE_ATTR; | 443 | static void displaylcd_dma(int pixels) ICODE_ATTR; |
399 | static void displaylcd_dma(int pixels) | 444 | static void displaylcd_dma(int pixels) |
400 | { | 445 | { |
401 | int i; | ||
402 | void* data = lcd_dblbuf; | ||
403 | for (i = -1; i < (int)ARRAYLEN(lcd_lli) && pixels > 0; i++, pixels -= 0xfff) | ||
404 | { | ||
405 | bool last = i + 1 >= (int)ARRAYLEN(lcd_lli) || pixels <= 0xfff; | ||
406 | struct dma_lli* lli = i < 0 ? (struct dma_lli*)((int)&DMAC0C4LLI) : &lcd_lli[i]; | ||
407 | lli->srcaddr = data; | ||
408 | lli->dstaddr = (void*)((int)&LCD_WDATA); | ||
409 | lli->nextlli = last ? NULL : &lcd_lli[i + 1]; | ||
410 | lli->control = 0x70240000 | (last ? pixels : 0xfff) | ||
411 | | (last ? 0x80000000 : 0) | 0x4000000; | ||
412 | data += 0x1ffe; | ||
413 | } | ||
414 | commit_dcache(); | 446 | commit_dcache(); |
415 | DMAC0C4CONFIG = 0x88c1; | 447 | dmac_ch_queue(&lcd_dma_ch, lcd_dblbuf, |
448 | (void*)S5L8702_DADDR_PERI_LCD_WR, pixels*2, NULL); | ||
416 | mutex_unlock(&lcd_mutex); | 449 | mutex_unlock(&lcd_mutex); |
417 | } | 450 | } |
418 | 451 | ||
419 | void INT_DMAC0C4(void) ICODE_ATTR; | ||
420 | void INT_DMAC0C4(void) | ||
421 | { | ||
422 | DMAC0INTTCCLR = 0x10; | ||
423 | semaphore_release(&lcd_wakeup); | ||
424 | } | ||
425 | |||
426 | /* Update a fraction of the display. */ | 452 | /* Update a fraction of the display. */ |
427 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; | 453 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; |
428 | void lcd_update_rect(int x, int y, int width, int height) | 454 | void lcd_update_rect(int x, int y, int width, int height) |