summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s5l8702/ipod6g
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/s5l8702/ipod6g')
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c78
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
51int lcd_type; /* also needed in debug-s5l8702.c */ 52int lcd_type; /* also needed in debug-s5l8702.c */
52static struct dma_lli lcd_lli[(LCD_WIDTH * LCD_HEIGHT - 1) / 0xfff] CACHEALIGN_ATTR;
53static struct semaphore lcd_wakeup;
54static struct mutex lcd_mutex; 53static struct mutex lcd_mutex;
55static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH]; 54static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH] CACHEALIGN_ATTR;
56static bool lcd_ispowered; 55static 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
208static struct dmac_tsk lcd_dma_tskbuf[LCD_DMA_TSKBUF_SZ];
209static struct dmac_lli volatile \
210 lcd_dma_llibuf[LCD_DMA_LLIBUF_SZ] CACHEALIGN_ATTR;
211
212static 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
226static 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
200static inline void s5l_lcd_write_reg(int cmd, unsigned int data) 241static 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)
328void lcd_init_device(void) 369void 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,
362static void displaylcd_setup(int x, int y, int width, int height) ICODE_ATTR; 405static void displaylcd_setup(int x, int y, int width, int height) ICODE_ATTR;
363static void displaylcd_setup(int x, int y, int width, int height) 406static 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)
398static void displaylcd_dma(int pixels) ICODE_ATTR; 443static void displaylcd_dma(int pixels) ICODE_ATTR;
399static void displaylcd_dma(int pixels) 444static 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
419void INT_DMAC0C4(void) ICODE_ATTR;
420void 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. */
427void lcd_update_rect(int, int, int, int) ICODE_ATTR; 453void lcd_update_rect(int, int, int, int) ICODE_ATTR;
428void lcd_update_rect(int x, int y, int width, int height) 454void lcd_update_rect(int x, int y, int width, int height)