1
0
mirror of git://projects.qi-hardware.com/ben-blinkenlights.git synced 2024-07-01 02:44:32 +03:00

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
This commit is contained in:
Werner Almesberger 2011-05-01 12:22:23 -03:00
parent 64f3047144
commit a8a0cfa22f

View File

@ -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();