Initial commit

This commit is contained in:
Bahadir Balban
2008-01-13 13:53:52 +00:00
commit e2b791a3d8
789 changed files with 95825 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['pl190_vic.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -0,0 +1,104 @@
/*
* PL190 Vectored irq controller support.
*
* This is more pb926 specific as it also touches the SIC, a partial irq
* controller.Normally, irq controller must be independent and singular. Later
* other generic code should make thlongwork in cascaded setup.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/lib/bit.h>
#include <l4/drivers/irq/pl190/pl190_vic.h>
/* FIXME: Fix the stupid uart driver and change to single definition of this! */
#if defined(read)
#undef read
#endif
#if defined(write)
#undef write
#endif
#define read(a) *((volatile unsigned int *)(a))
#define write(v, a) (*((volatile unsigned int *)(a)) = v)
#define setbit(bitvect, a) write(read(a) | (bitvect), a)
#define clrbit(bitvect, a) write(read(a) & ~(bitvect), a)
#define devio(base, reg, bitvect, setclr) \
((setclr) ? setbit(bitvect, (base + reg)) \
: clrbit(bitvect, (base + reg)))
/* Returns the irq number on this chip converting the irq bitvector */
int pl190_read_irq(void)
{
/* This also correctly returns a negative value for a spurious irq. */
return 31 - __clz(read(PL190_VIC_IRQSTATUS));
}
void pl190_mask_irq(int irq)
{
/* Reading WO registers blows QEMU/PB926.
* setbit((1 << irq), PL190_VIC_INTENCLEAR); */
write(1 << irq, PL190_VIC_INTENCLEAR);
}
/* Ack is same as mask */
void pl190_ack_irq(int irq)
{
pl190_mask_irq(irq);
}
void pl190_unmask_irq(int irq)
{
setbit(1 << irq, PL190_VIC_INTENABLE);
}
int pl190_sic_read_irq(void)
{
return 32 - __clz(read(PL190_SIC_STATUS));
}
void pl190_sic_mask_irq(int irq)
{
write(1 << irq, PL190_SIC_ENCLR);
}
void pl190_sic_ack_irq(int irq)
{
pl190_sic_mask_irq(irq);
}
void pl190_sic_unmask_irq(int irq)
{
setbit(1 << irq, PL190_SIC_ENSET);
}
/* Initialises the primary and secondary interrupt controllers */
void pl190_vic_init(void)
{
/* Clear all interrupts */
write(0, PL190_VIC_INTENABLE);
write(0xFFFFFFFF, PL190_VIC_INTENCLEAR);
/* Set all irqs as normal IRQs (i.e. not FIQ) */
write(0, PL190_VIC_INTSELECT);
/* TODO: Is there a SIC_IRQ_SELECT for irq/fiq ??? */
/* Disable user-mode access to VIC registers */
write(1, PL190_VIC_PROTECTION);
/* Clear software interrupts */
write(0xFFFFFFFF, PL190_VIC_SOFTINTCLEAR);
/* At this point, all interrupts are cleared and disabled.
* the controllers are ready to receive interrupts, if enabled. */
return;
}
void pl190_sic_init(void)
{
write(0, PL190_SIC_ENABLE);
write(0xFFFFFFFF, PL190_SIC_ENCLR);
/* Disable SIC-to-PIC direct routing of individual irq lines on SIC */
write(0xFFFFFFFF, PL190_SIC_PICENCLR);
}

View File

@@ -0,0 +1,10 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['sp804_timer.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -0,0 +1,107 @@
/*
* SP804 Primecell Timer driver
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/drivers/timer/sp804/sp804_timer.h>
/* FIXME: Fix the shameful uart driver and change to single definition of this! */
#if defined(read)
#undef read
#endif
#if defined(write)
#undef write
#endif
#define read(a) *((volatile unsigned int *)(a))
#define write(v, a) (*((volatile unsigned int *)(a)) = v)
#define setbit(bit, a) write(read(a) | bit, a)
#define clrbit(bit, a) write(read(a) & ~bit, a)
#define devio(base, reg, bit, setclr) \
((setclr) ? setbit(bit, base + reg) \
: clrbit(bit, base + reg))
void sp804_irq_handler(void)
{
/* Timer enabled as Periodic/Wrapper only needs irq clearing
* as it automatically reloads and wraps. */
write(1, SP804_TIMER1INTCLR);
}
static inline void sp804_control(int timer, int bit, int setclr)
{
unsigned long addr = SP804_TIMER1CONTROL + (timer ? SP804_TIMER2OFFSET : 0);
setclr ? setbit(bit, addr) : clrbit(bit, addr);
}
/* Sets timer's run mode:
* @periodic: periodic mode = 1, free-running = 0.
*/
#define SP804_PEREN (1 << 6)
static inline void sp804_set_runmode(int timer, int periodic)
{
sp804_control(timer, SP804_PEREN, periodic);
}
/* Sets timer's wrapping mode:
* @oneshot: oneshot = 1, wrapping = 0.
*/
#define SP804_ONESHOT (1 << 0)
static inline void sp804_set_wrapmode(int timer, int oneshot)
{
sp804_control(timer, SP804_ONESHOT, oneshot);
}
/* Sets the operational width of timers.
* In 16bit mode, top halfword is ignored.
* @width: 32bit mode = 1; 16bit mode = 0
*/
#define SP804_32BIT (1 << 1)
static inline void sp804_set_widthmode(int timer, int width)
{
sp804_control(timer, SP804_32BIT, width);
}
/* Enable/disable timer:
* @enable: enable = 1, disable = 0;
*/
#define SP804_ENABLE (1 << 7)
void sp804_enable(int timer, int enable)
{
sp804_control(timer, SP804_ENABLE, enable);
}
/* Enable/disable local irq register:
* @enable: enable = 1, disable = 0
*/
#define SP804_IRQEN (1 << 5)
void sp804_set_irq(int timer, int enable)
{
sp804_control(timer, SP804_IRQEN, enable);
}
/* Loads timer with value in val */
static inline void sp804_load_value(int timer, u32 val)
{
write(val, SP804_TIMER1LOAD + (timer ? SP804_TIMER2OFFSET : 0));
}
/* Returns current timer value */
static inline u32 sp804_read_value(int timer)
{
return read(SP804_TIMER1VALUE + (timer ? SP804_TIMER2OFFSET : 0));
}
/* TODO: These are default settings! The values must be passed as arguments */
void sp804_init(void)
{
/* 1 tick per usec */
const int duration = 250;
sp804_set_runmode(0, 1); /* Periodic */
sp804_set_wrapmode(0, 0); /* Wrapping */
sp804_set_widthmode(0, 1); /* 32 bit */
sp804_set_irq(0, 1); /* Enable */
sp804_load_value(0, duration);
}

View File

@@ -0,0 +1,10 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['pl011_uart.c']
obj = env.Object(src_local)
Return('obj')

View File

@@ -0,0 +1,278 @@
/*
* PL011 Primecell UART driver
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/drivers/uart/pl011/pl011_uart.h>
#include <l4/lib/bit.h>
struct pl011_uart uart = {
.base = PL011_BASE,
.ops = {
.initialise = pl011_initialise_device,
.tx_char = pl011_tx_char,
.rx_char = pl011_rx_char,
.set_baudrate = pl011_set_baudrate,
.set_irq_mask = pl011_set_irq_mask,
.clr_irq_mask = pl011_clr_irq_mask,
},
.frame_errors = 0,
.parity_errors = 0,
.break_errors = 0,
.rx_timeout_errors = 0,
};
/* UART-specific internal error codes.
* TODO: Replace them when generic error codes are in place */
#define PL011_ERROR 1
#define PL011_EAGAIN 2
/* Error status bits in receive status register */
#define PL011_FE (1 << 0)
#define PL011_PE (1 << 1)
#define PL011_BE (1 << 2)
#define PL011_OE (1 << 3)
/* Status bits in flag register */
#define PL011_TXFE (1 << 7)
#define PL011_RXFF (1 << 6)
#define PL011_TXFF (1 << 5)
#define PL011_RXFE (1 << 4)
#define PL011_BUSY (1 << 3)
#define PL011_DCD (1 << 2)
#define PL011_DSR (1 << 1)
#define PL011_CTS (1 << 0)
int pl011_tx_char(char c)
{
unsigned int val;
val = 0;
read(val, PL011_UARTFR);
if(val & PL011_TXFF) { /* TX FIFO Full */
return -PL011_EAGAIN;
}
write(c, PL011_UARTDR);
return 0;
}
int pl011_rx_char(char * c)
{
unsigned int data;
unsigned int val;
val = 0;
read(val, PL011_UARTFR);
if(val & PL011_RXFE) { /* RX FIFO Empty */
return -PL011_EAGAIN;
}
read(data, PL011_UARTDR);
*c = (char) data;
if((data >> 8) & 0xF) { /* There were errors */
return -1; /* Signal error in xfer */
}
return 0; /* No error return */
}
/*
* Sets the baud rate in kbps. It is recommended to use
* standard rates such as: 1200, 2400, 3600, 4800, 7200,
* 9600, 14400, 19200, 28800, 38400, 57600 76800, 115200.
*/
void pl011_set_baudrate(unsigned int baud, unsigned int clkrate)
{
const unsigned int uartclk = 24000000; /* 24Mhz clock fixed on pb926 */
unsigned int val;
unsigned int ipart, fpart;
unsigned int remainder;
remainder = 0;
ipart = 0;
fpart = 0;
val = 0;
/* Use default pb926 rate if no rate is supplied */
if(clkrate == 0)
clkrate = uartclk;
if(baud > 115200 || baud < 1200)
baud = 38400; /* Default rate. */
/* 24000000 / (16 * 38400) */
ipart = 39;
write(ipart, PL011_UARTIBRD);
write(fpart, PL011_UARTFBRD);
/* For the IBAUD and FBAUD to update, we need to
* write to UARTLCR_H because the 3 registers are
* actually part of a single register in hardware
* which only updates by a write to UARTLCR_H */
read(val, PL011_UARTLCR_H);
write(val, PL011_UARTLCR_H);
return;
}
/* Masks the irqs given in the flags bitvector. */
void pl011_set_irq_mask(unsigned int flags)
{
unsigned int val;
val = 0;
if(flags > 0x3FF) { /* Invalid irqmask bitvector */
return;
}
read(val, PL011_UARTIMSC);
val |= flags;
write(val, PL011_UARTIMSC);
return;
}
/* Clears the irqs given in flags from masking */
void pl011_clr_irq_mask(unsigned int flags)
{
unsigned int val;
val = 0;
if(flags > 0x3FF) { /* Invalid irqmask bitvector */
return;
}
read(val, PL011_UARTIMSC);
val &= ~flags;
write(val, PL011_UARTIMSC);
return;
}
/* Produces 1 character from data register and appends it into
* rx buffer keeps record of timeout errors if one occurs. */
void pl011_rx_irq_handler(struct pl011_uart * uart, unsigned int flags)
{
/*
* Currently we do nothing for uart irqs, because there's no external
* client to send/receive data (e.g. userspace processes kernel threads).
*/
return;
}
/* Consumes 1 character from tx buffer and attempts to transmit it */
void pl011_tx_irq_handler(struct pl011_uart * uart, unsigned int flags)
{
/*
* Currently we do nothing for uart irqs, because there's no external
* client to send/receive data (e.g. userspace processes kernel threads).
*/
return;
}
/* Updates error counts and exits. Does nothing to recover errors */
void pl011_error_irq_handler(struct pl011_uart * uart, unsigned int flags)
{
if(flags & PL011_FEIRQ) {
uart->frame_errors++;
}
if(flags & PL011_PEIRQ) {
uart->parity_errors++;
}
if(flags & PL011_BEIRQ) {
uart->break_errors++;
}
if(flags & PL011_OEIRQ) {
uart->overrun_errors++;
}
return;
}
void (* pl011_handlers[]) (struct pl011_uart *, unsigned int) = {
0, /* Modem RI */
0, /* Modem CTS */
0, /* Modem DCD */
0, /* Modem DSR */
&pl011_rx_irq_handler, /* Rx */
&pl011_tx_irq_handler, /* Tx */
&pl011_rx_irq_handler, /* Rx timeout */
&pl011_error_irq_handler, /* Framing error */
&pl011_error_irq_handler, /* Parity error */
&pl011_error_irq_handler, /* Break error */
&pl011_error_irq_handler /* Overrun error */
};
/* UART main entry for irq handling. It redirects actual
* handling to handlers relevant to the irq that has occured.
*/
void pl011_irq_handler(struct pl011_uart * uart)
{
unsigned int val;
int handler_index;
void (* handler)(struct pl011_uart *, unsigned int);
val = pl011_read_irqstat();
handler_index = 32 - __clz(val);
if(!handler_index) { /* No irq */
return;
}
/* Jump to right handler */
handler = (void (*) (struct pl011_uart *, unsigned int))
pl011_handlers[handler_index];
if(handler) { /* If a handler is available */
(*handler)(uart, val); /* Call it */
}
return;
}
void pl011_initialise_driver(void)
{
uart.ops.initialise(&uart);
}
/* Initialises the uart class data structures, and the device.
* Terminal-like operation is assumed for default settings.
*/
int pl011_initialise_device(struct pl011_uart * uart)
{
uart->frame_errors = 0;
uart->parity_errors = 0;
uart->break_errors = 0;
uart->overrun_errors = 0;
/* Initialise data register for 8 bit data read/writes */
pl011_set_word_width(8);
/* Fifos are disabled because by default it is assumed the port
* will be used as a user terminal, and in that case the typed
* characters will only show up when fifos are flushed, rather than
* when each character is typed. We avoid this by not using fifos.
*/
pl011_disable_fifos();
/* Set default baud rate of 38400 */
pl011_set_baudrate(38400, 24000000);
/* Set default settings of 1 stop bit, no parity, no hw flow ctrl */
pl011_set_stopbits(1);
pl011_parity_disable();
/* Install the irq handler */
/* TODO: INSTALL IT HERE */
/* Enable all irqs */
pl011_clr_irq_mask(0x3FF);
/* Enable rx, tx, and uart chip */
pl011_tx_enable();
pl011_rx_enable();
pl011_uart_enable();
return 0;
}