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

ubb-vga2: instead of pointers to registers, use pointer plus offset (via macros)

- regs4740.h: macros to access selected Jz4740 registers
- ubb-vga2.c: replaced all pointers to registers with access macros
- ubb-vga2.c (line_cycles): we now seem to be 0.1 us slower
This commit is contained in:
Werner Almesberger 2011-04-28 18:41:00 -03:00
parent cb5a6bd202
commit 957491d209
2 changed files with 114 additions and 97 deletions

63
ubb-vga/regs4740.h Normal file
View File

@ -0,0 +1,63 @@
/*
* regs4740.h - Jz4740 register definitions (subset)
*
* Written 2011 by Werner Almesberger
* Copyright 2011 Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef REGS4740_H
#define REGS4740_H
#include <stdint.h>
#define SOC_BASE 0x10000000
#define REG(n) (*(volatile uint32_t *) ((REG_BASE_PTR)+(n)))
#define CGU(n) REG(0x00000+(n))
#define INTC(n) REG(0x01000+(n))
#define TCU(n) REG(0x02000+(n))
#define GPIO(n) REG(0x10000+(n))
#define MSC(n) REG(0x21000+(n))
#define CLKGR CGU(0x0020) /* Clock Gate */
#define MSCCDR CGU(0x0068) /* MSC device clock divider */
#define PDPIN GPIO(0x300) /* port D pin level */
#define PDDATS GPIO(0x314) /* port D data set */
#define PDDATC GPIO(0x318) /* port D data clear */
#define PDFUNS GPIO(0x344) /* port D function set */
#define PDFUNC GPIO(0x348) /* port D function clear */
#define PDDIRS GPIO(0x364) /* port D direction set */
#define PDDIRC GPIO(0x368) /* port D direction clear */
#define ICMR INTC(0x04) /* Interrupt controller mask */
#define ICMSR INTC(0x08) /* Interrupt controller mask set */
#define ICMCR INTC(0x0c) /* Interrupt controller mask clear */
#define TSSR TCU(0x2c) /* Timer STOP set */
#define TSCR TCU(0x3c) /* Timer STOP clear */
#define TESR TCU(0x14) /* Timer counter enable set */
#define TECR TCU(0x18) /* Timer counter enable clear */
#define TCSR(n) TCU(0x4c+0x10*(n)) /* Timer control */
#define TDFR(n) TCU(0x40+0x10*(n)) /* Timer data full */
#define TCNT(n) TCU(0x48+0x10*(n)) /* Timer counter */
#define MSC_STRPCL MSC(0x00) /* Start/stop MMC/SD clock */
#define MSC_STAT MSC(0x04) /* MSC status */
#define MSC_CLKRT MSC(0x08) /* MSC clock rate */
#define MSC_CMDAT MSC(0x0c) /* MMC/SD command and data control */
#define MSC_RESTO MSC(0x10) /* MMC/SD response time out */
#define MSC_BLKLEN MSC(0x18) /* MMC/SD block length */
#define MSC_NOP MSC(0x1c) /* MMC/SD number of blocks */
#define MSC_CMD MSC(0x2c) /* MMC/SD command index */
#define MSC_ARG MSC(0x30) /* MMC/SD command argument */
#define MSC_TXFIFO MSC(0x3c) /* MMC/SD transmit data FIFO */
#endif /* !REGS4740_H */

View File

@ -34,6 +34,7 @@
#include <fcntl.h>
#include <sys/mman.h>
#include "regs4740.h"
#include "ubb-vga.h"
@ -41,6 +42,10 @@
#define YRES 480
#define REG_BASE_PTR base
static volatile void *base;
static int bad;
@ -69,27 +74,11 @@ static int bad;
#define PAGE_SIZE 4096
#define SOC_BASE 0x10000000
static volatile uint32_t *icmr, *icmsr, *icmcr;
static uint32_t old_icmr;
static volatile uint32_t *clkgr, *msccdr;
static uint32_t old_clkgr;
static volatile uint32_t *pddats, *pddatc;
static volatile uint32_t *pddirs, *pddirc;
static volatile uint32_t *pdfuns, *pdfunc;
static volatile uint32_t *tssr, *tscr;
static volatile uint32_t *tesr, *tecr;
static volatile uint32_t *tcsr, *tdfr, *tcnt;
static volatile uint32_t *msc_strpcl, *msc_stat, *msc_clkrt;
static volatile uint32_t *msc_cmdat, *msc_resto, *msc_blklen, *msc_nob;
static volatile uint32_t *msc_cmd, *msc_arg, *msc_txfifo;
static void disable_interrupts(void)
{
@ -100,14 +89,14 @@ static void disable_interrupts(void)
* incorrect mask when restoring interrupts, which may hang the system.
*/
old_icmr = *icmr;
*icmsr = 0xffffffff;
old_icmr = ICMR;
ICMSR = 0xffffffff;
}
static void enable_interrupts(void)
{
*icmcr = ~old_icmr;
ICMCR = ~old_icmr;
}
@ -118,30 +107,30 @@ static void enable_interrupts(void)
static void disable_lcd(void)
{
old_clkgr = *clkgr;
*clkgr = old_clkgr | 1 << 10;
old_clkgr = CLKGR;
CLKGR = old_clkgr | 1 << 10;
}
static void enable_lcd(void)
{
*clkgr = old_clkgr;
CLKGR = old_clkgr;
}
static void get_timer(void)
{
*tscr = 1 << TIMER; /* enable clock */
*tcsr = 1; /* count at PCLK/1 */
*tdfr = 0xffff; /* count to 0xffff */
*tesr = 1 << TIMER;
TSCR = 1 << TIMER; /* enable clock */
TCSR(TIMER) = 1; /* count at PCLK/1 */
TDFR(TIMER) = 0xffff; /* count to 0xffff */
TESR = 1 << TIMER;
}
static void release_timer(void)
{
*tecr = 1 << TIMER;
*tssr = 1 << TIMER;
TECR = 1 << TIMER;
TSSR = 1 << TIMER;
}
@ -167,43 +156,8 @@ void *map(off_t addr, size_t size)
static void ben_setup(void)
{
volatile void *base;
base = map(SOC_BASE, PAGE_SIZE*3*16);
clkgr = base+0x20;
msccdr = base+0x68;
icmr = base+0x1004;
icmsr = base+0x1008;
icmcr = base+0x100c;
pddats = base+0x10314;
pddatc = base+0x10318;
pdfuns = base+0x10344;
pdfunc = base+0x10348;
pddirs = base+0x10364;
pddirc = base+0x10368;
tssr = base+0x202c;
tscr = base+0x203c;
tesr = base+0x2014;
tecr = base+0x2018;
tcsr = base+0x204c+0x10*TIMER;
tdfr = base+0x2040+0x10*TIMER;
tcnt = base+0x2048+0x10*TIMER;
msc_strpcl = base+0x21000;
msc_stat = base+0x21004;
msc_clkrt = base+0x21008;
msc_cmdat = base+0x2100c;
msc_resto = base+0x21010;
msc_blklen = base+0x21018;
msc_nob = base+0x2101c;
msc_cmd = base+0x2102c;
msc_arg = base+0x21030;
msc_txfifo = base+0x2103c;
/*
* Ironically, switching the LCD clock on and off many times only
* increases the risk of a hang. Therefore, we leave stop it during
@ -229,7 +183,7 @@ static void cleanup(void)
static void until(uint16_t cycles)
{
while ((*tcnt & 0xffff) < cycles);
while ((TCNT(TIMER) & 0xffff) < cycles);
}
@ -239,9 +193,9 @@ static void until(uint16_t cycles)
static int line_words = XRES/8;
//static int line_cycles = US(36); /* nominally 31.77 us, but we're too slow */
//static int line_cycles = US(32); /* nominally 31.77 us, but we're too slow */
static int line_cycles = US(29.6); /* nominally 31.77 us, but we're too fast */
static int line_cycles = US(29.7); /* nominally 31.77 us, but we're too fast */
/*
* Note: 29.5 is already too short. Tricky timing.
* Note: 29.6 is already too short. Tricky timing.
*/
void setup(void)
@ -249,16 +203,16 @@ void setup(void)
mlockall(MCL_CURRENT | MCL_FUTURE);
ben_setup();
*pdfuns = R | G | B | Y;
*pdfunc = VSYNC | HSYNC;
*pddirs = VSYNC | HSYNC | R | G | B | Y;
*pddats = VSYNC | HSYNC;
*pddatc = R | G | B | Y;
PDFUNS = R | G | B | Y;
PDFUNC = VSYNC | HSYNC;
PDDIRS = VSYNC | HSYNC | R | G | B | Y;
PDDATS = VSYNC | HSYNC;
PDDATC = R | G | B | Y;
// *msccdr = 20; /* set the MSC clock to 336 MHz / 21 = 16 MHz */
*msccdr = 11; /* set the MSC clock to 336 MHz / 12 = 28 MHz */
*clkgr &= ~(1 << 7); /* enable MSC clock */
*msc_clkrt = 0; /* bus clock = MSC clock / 1 */
MSCCDR = 11; /* set the MSC clock to 336 MHz / 12 = 28 MHz */
CLKGR &= ~(1 << 7); /* enable MSC clock */
MSC_CLKRT = 0; /* bus clock = MSC clock / 1 */
}
@ -269,10 +223,10 @@ static void line(const uint32_t *line)
/* Back porch */
*tcnt = 0;
TCNT(TIMER) = 0;
*msc_strpcl = 1 << 3; /* reset the MSC */
// while (*msc_stat & (1 << 15));
MSC_STRPCL = 1 << 3; /* reset the MSC */
// while (MSC_STAT & (1 << 15));
first = *p++;
@ -280,16 +234,16 @@ static void line(const uint32_t *line)
/* HSYNC */
*pddatc = HSYNC;
*msc_strpcl = 2; /* start MMC clock output */
PDDATC = HSYNC;
MSC_STRPCL = 2; /* start MMC clock output */
*msc_cmdat =
MSC_CMDAT =
(1 << 10) | /* 4 bit bus */
(1 << 4) | /* write */
(1 << 3) | /* with data transfer */
1; /* R1 response */
*msc_strpcl = 4; /* START_OP */
MSC_STRPCL = 4; /* START_OP */
until(US(0.79+3.77-0.3));
/*
@ -317,11 +271,11 @@ static void line(const uint32_t *line)
/* Front porch */
*msc_txfifo = first;
MSC_TXFIFO = first;
*pdfuns = CMD;
*pddats = HSYNC;
*pdfunc = CMD;
PDFUNS = CMD;
PDDATS = HSYNC;
PDFUNC = CMD;
/*
* We don't wait for the end of the front porch because the beginning
@ -330,20 +284,20 @@ static void line(const uint32_t *line)
*/
#if 0 /* quick load */
*msc_txfifo = *p++;
*msc_txfifo = *p++;
MSC_TXFIFO = *p++;
MSC_TXFIFO = *p++;
#endif
while (p != line+line_words) {
uint8_t st;
do {
st = *msc_stat;
st = MSC_STAT;
if (st & 3) {
bad++;
goto fail;
}
}
while (st & (1 << 7));
*msc_txfifo = *p++;
MSC_TXFIFO = *p++;
}
fail:
@ -354,10 +308,10 @@ fail:
static void hdelay(int cycles)
{
while (cycles--) {
*tcnt = 0;
*pddatc = HSYNC;
TCNT(TIMER) = 0;
PDDATC = HSYNC;
until(US(3.77));
*pddats = HSYNC;
PDDATS = HSYNC;
until(line_cycles);
}
}
@ -368,9 +322,9 @@ static void frame(const uint32_t *f)
const uint32_t *p;
/* VSYNC */
*pddatc = VSYNC;
PDDATC = VSYNC;
hdelay(2);
*pddats = VSYNC;
PDDATS = VSYNC;
/* Front porch */
@ -380,10 +334,10 @@ static void frame(const uint32_t *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 = 0;
*pddatc = HSYNC;
TCNT(TIMER) = 0;
PDDATC = HSYNC;
until(US(3.77));
*pddats = HSYNC;
PDDATS = HSYNC;
until(line_cycles-US(0.79));
for (p = f; p != f+YRES*line_words; p += line_words)