diff --git a/ubb-vga/regs4740.h b/ubb-vga/regs4740.h index 808e26e..215f9b9 100644 --- a/ubb-vga/regs4740.h +++ b/ubb-vga/regs4740.h @@ -50,8 +50,12 @@ #define TSCR _TCU(0x3c) /* Timer STOP clear */ #define TESR _TCU(0x14) /* Timer counter enable set */ #define TECR _TCU(0x18) /* Timer counter enable clear */ +#define TFR _TCU(0x20) /* Timer flag */ +#define TFSR _TCU(0x24) /* Timer flag set */ +#define TFCR _TCU(0x28) /* Timer flag clear */ #define TCSR(n) _TCU(0x4c+0x10*(n)) /* Timer control */ #define TDFR(n) _TCU(0x40+0x10*(n)) /* Timer data full */ +#define TDHR(n) _TCU(0x44+0x10*(n)) /* Timer data half */ #define TCNT(n) _TCU(0x48+0x10*(n)) /* Timer counter */ #define MSC_STRPCL _MSC(0x00) /* Start/stop MMC/SD clock */ diff --git a/ubb-vga/ubb-vga.c b/ubb-vga/ubb-vga.c index 652f415..e9d063d 100644 --- a/ubb-vga/ubb-vga.c +++ b/ubb-vga/ubb-vga.c @@ -233,9 +233,14 @@ static void cleanup(void) /* ----- Delay logic ------------------------------------------------------- */ -static void until(uint16_t cycles) +static void delay(uint16_t cycles) { - while ((TCNT(TIMER) & 0xffff) < cycles); + static uint16_t next = 0; + + next += cycles; + TDHR(TIMER) = next; + TFCR = 1 << (TIMER+16); + while (!(TFR & (1 << (TIMER+16)))); } @@ -292,7 +297,7 @@ static void line(unsigned long line) DTA(DMA) = REG_PADDR(MSC_TXFIFO); /* MUST set this each time */ DTC(DMA) = (mode->xres+63) >> 6; - until(mode->hback_cycles); + delay(mode->hback_cycles); /* HSYNC */ @@ -313,7 +318,7 @@ static void line(unsigned long line) (1 << 31) | /* no descriptor */ 1; - until(mode->hback_cycles+mode->hsync_cycles); + delay(mode->hsync_cycles); // MSC_TXFIFO = 0xffffffff; @@ -323,7 +328,7 @@ static void line(unsigned long line) PDDATS = HSYNC; PDFUNC = CMD; - until(mode->line_cycles); + delay(mode->line_cycles-mode->hback_cycles-mode->hsync_cycles); MSC_TXFIFO = 0; if (MSC_STAT & 3) bad++; @@ -333,11 +338,10 @@ static void line(unsigned long line) static void hdelay(int cycles) { while (cycles--) { - TCNT(TIMER) = 0; PDDATC = HSYNC; - until(mode->hsync_cycles); + delay(mode->hsync_cycles); PDDATS = HSYNC; - until(mode->line_cycles); + delay(mode->line_cycles-mode->hsync_cycles); } } @@ -359,22 +363,15 @@ static void frame(const unsigned long *f) * The horizontal back porch of the previous line is handled inside * "line", so we have to wait for less than a full line here. */ - TCNT(TIMER) = 0; PDDATC = HSYNC; - until(mode->hsync_cycles); + delay(mode->hsync_cycles); PDDATS = HSYNC; - until(mode->line_cycles-mode->hback_cycles); + delay(mode->line_cycles-mode->hback_cycles-mode->hsync_cycles); - /* - * Note: resetting the timer just before calling "line" isn't enough. - * We have t reset it before the loop and right after returning from - * "line". - */ - TCNT(TIMER) = 0; - for (p = f; p != f+mode->yres; p++) { + for (p = f; p != f+mode->yres; p++) line(*p); - TCNT(TIMER) = 0; - } + + delay(mode->hback_cycles); /* Back porch */ hdelay(mode->vback_lines); @@ -401,6 +398,7 @@ static void session(void (*gen)(void **fb, int xres, int yres), int frames) setup_noirq(); + TCNT(TIMER) = 0; for (i = 0; !frames || i != frames; i++) { frame(f_phys); if (DTC(DMA)) {