mirror of
https://github.com/drasko/codezero.git
synced 2026-01-13 03:13:15 +01:00
Initial commit
This commit is contained in:
10
src/drivers/irq/pl190/SConscript
Normal file
10
src/drivers/irq/pl190/SConscript
Normal 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')
|
||||
104
src/drivers/irq/pl190/pl190_vic.c
Normal file
104
src/drivers/irq/pl190/pl190_vic.c
Normal 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);
|
||||
}
|
||||
|
||||
10
src/drivers/timer/sp804/SConscript
Normal file
10
src/drivers/timer/sp804/SConscript
Normal 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')
|
||||
107
src/drivers/timer/sp804/sp804_timer.c
Normal file
107
src/drivers/timer/sp804/sp804_timer.c
Normal 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);
|
||||
}
|
||||
|
||||
10
src/drivers/uart/pl011/SConscript
Normal file
10
src/drivers/uart/pl011/SConscript
Normal 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')
|
||||
278
src/drivers/uart/pl011/pl011_uart.c
Normal file
278
src/drivers/uart/pl011/pl011_uart.c
Normal 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user