From a8a0cfa22f31e638c19ae4471a30c31b93bae8bf Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Sun, 1 May 2011 12:22:23 -0300 Subject: [PATCH] ubb-vga.c: added (fragile) DMA support (locks up on anything but 800x600) Note that DMA is very sensitive to the video timing. At the moment, only 800x600 mode works without locking up the DMA controller. - ubb-vga.c (DMA, setup_noirq, cleanup_noirq, line): replaced MMC PIO with DMA - ubb-vga.c (frame): pass physical addresses to "line" - ubb-vga.c (frame): detect if the DMA controller is stuck --- ubb-vga/ubb-vga.c | 83 +++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/ubb-vga/ubb-vga.c b/ubb-vga/ubb-vga.c index 35a24fb..8c7369e 100644 --- a/ubb-vga/ubb-vga.c +++ b/ubb-vga/ubb-vga.c @@ -67,6 +67,7 @@ static int bad; #define TIMER 7 +#define DMA 0 static uint32_t old_icmr; @@ -245,25 +246,35 @@ static void setup(void) static void setup_noirq(void) { + DMAC = 1; + DCS(DMA) = (1 << 3) | (1 << 2); + DCS(DMA) = 0; } static void cleanup_noirq(void) { + DMAC = 0; + DCS(DMA) = (1 << 3) | (1 << 2); + DCS(DMA) = 0; } -static void line(const uint32_t *line) +static void line(unsigned long line) { - const uint32_t *p = line; - uint32_t first; - /* Back porch */ MSC_STRPCL = 1 << 3; /* reset the MSC */ -// while (MSC_STAT & (1 << 15)); - first = *p++; + DCS(DMA) = (1 << 31) | (1 << 3) | (1 << 2); + DCS(DMA) = 1 << 31; + DSA(DMA) = line; + DTA(DMA) = REG_PADDR(MSC_TXFIFO); + DTC(DMA) = mode->xres >> 5; + DCM(DMA) = + (1 << 23) | /* source address increment */ + (4 << 8); /* transfer size is 32 bytes */ + DRT(DMA) = 26; /* MSC transmit-fifo-empty transfer request */ until(US(0.79)); @@ -275,50 +286,30 @@ static void line(const uint32_t *line) MSC_CMDAT = (2 << 9) | /* 4 bit bus */ + (1 << 8) | /* DMA */ (1 << 4) | /* write */ (1 << 3) | /* with data transfer */ 1; /* R1 response */ MSC_STRPCL = 4; /* START_OP */ + DCS(DMA) = + (1 << 31) | /* no descriptor */ + 1; + until(mode->hsync_end); - /* Front porch */ +// MSC_TXFIFO = 0xffffffff; - MSC_TXFIFO = first; + /* Front porch */ PDFUNS = CMD; PDDATS = HSYNC; PDFUNC = CMD; - /* - * We don't wait for the end of the front porch because the beginning - * of pixel data is determined by the MSC. Instead, we make good use - * of the delay to shovel bits into the MSC's FIFO. - */ - -#if 1 /* quick load */ - MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; - MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; - MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; - MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; - MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; MSC_TXFIFO = *p++; -#endif - while (p != line+mode->line_words) { - uint8_t st; - do { - st = MSC_STAT; - if (st & 3) { - bad++; - goto fail; - } - } - while (st & (1 << 7)); - MSC_TXFIFO = *p++; - } - -fail: until(mode->line_cycles); + if (MSC_STAT & 3) + bad++; } @@ -334,9 +325,9 @@ static void hdelay(int cycles) } -static void frame(void *const *f) +static void frame(const unsigned long *f) { - void *const *p; + const unsigned long *p; /* VSYNC */ PDDATC = VSYNC; @@ -378,19 +369,27 @@ static void frame(void *const *f) static void session(void (*gen)(void **fb, int xres, int yres), int frames) { - void **f; + void **f_virt; + const unsigned long *f_phys; int i; ccube_init(); - f = calloc_phys_vec(mode->yres, mode->xres/2); - gen(f, mode->xres, mode->yres); + f_virt = calloc_phys_vec(mode->yres, mode->xres/2); + gen(f_virt, mode->xres, mode->yres); + f_phys = xlat_virt(f_virt, mode->yres); disable_interrupts(); setup_noirq(); - for (i = 0; i != frames; i++) - frame(f); + for (i = 0; i != frames; i++) { + frame(f_phys); + if (DTC(DMA)) { + fprintf(stderr, + "DMA locked up. Need hardware reset.\n"); + break; + } + } cleanup_noirq();