diff options
Diffstat (limited to 'kernel/drivers')
-rw-r--r-- | kernel/drivers/uart.S | 53 | ||||
-rw-r--r-- | kernel/drivers/uart.c | 83 |
2 files changed, 136 insertions, 0 deletions
diff --git a/kernel/drivers/uart.S b/kernel/drivers/uart.S new file mode 100644 index 0000000..38957c2 --- /dev/null +++ b/kernel/drivers/uart.S @@ -0,0 +1,53 @@ +.section ".text" + +.globl uart_char +uart_char: + mov r2, #0x1000 + movt r2, #0x3f20 +1: + ldr r3, [r2, #24] + tst r3, #0b100000 + bne 1b + str r0, [r2] + bx lr + +.globl uart_string +uart_string: + push {r4, lr} + mov r4, r0 + ldrb r0, [r0] + cmp r0, #0 + popeq {r4, pc} +1: + bl uart_char + ldrb r0, [r4, #1]! + cmp r0, #0 + bne 1b + pop {r4, pc} + +.globl uart_hex +uart_hex: + push {r4, lr} + mov r2, #0x1000 + movt r2, #0x3f20 +1: + ldr r3, [r2, #24] + tst r3, #0b100000 + bne 1b + mov r3, #7 +2: + mov r1, r0 + asr r1, r3 + asr r1, r3 + asr r1, r3 + asr r1, r3 + and r1, #0xf + add r1, #0x30 + cmp r1, #0x3A + blt 3f + add r1, #7 +3: + str r1, [r2] + subs r3, #1 + bge 2b // Jump back to wait for availablilty + pop {r4, pc} diff --git a/kernel/drivers/uart.c b/kernel/drivers/uart.c new file mode 100644 index 0000000..68c70d6 --- /dev/null +++ b/kernel/drivers/uart.c @@ -0,0 +1,83 @@ +#include <drivers/uart.h> +#include <lib/kmem.h> +#include <lib/strings.h> +#include <sys/core.h> +#include <sys/schedule.h> +#include <symbols.h> +#include <util/lock.h> + +#define UART_BUFFER_SIZE 0x400 +struct UartBuffer { + char buffer[UART_BUFFER_SIZE]; + unsigned long roffset; + unsigned long woffset; + struct Lock l; +} ubuffer; + +void uart_init(void) +{ + ubuffer.roffset = 0; + ubuffer.woffset = 0; + ubuffer.l.pid = 0; + + // Disable UART0 + store32(0x0, UART0_CR); + // Setup GPIO on pin 14 and 15 + store32(0x0, (unsigned long)GPPUD); + delay(150); + store32((1 << 14) | (1 << 15), (unsigned long)GPPUDCLK0); + delay(150); + store32(0x0, (unsigned long)GPPUDCLK0); + // Clear pending interrupts + store32(0x7FF, UART0_ICR); + // Set to 3Mhz + store32(1, UART0_IBRD); + store32(40, UART0_FBRD); + // Enable FIFO and 8 bit transmission + store32((1<<4)|(1<<5)|(1<<6), UART0_LCRH); + // Mask all interrupts + store32((1<<1)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10), UART0_IMSC); + // Enable UART0 + store32((1<<0)|(1<<8)|(1<<9), UART0_CR); +} + +// s = zero-terminated string +void* uart_print(char* s) +{ + lock(&ubuffer.l); + char* ptr = s; + while (1) { + if (*ptr == 0) + break; + ubuffer.buffer[ubuffer.woffset] = *ptr; + if ((ubuffer.woffset+1)%UART_BUFFER_SIZE == ubuffer.roffset) + return ptr; + ubuffer.woffset++; + ubuffer.woffset %= UART_BUFFER_SIZE; + ptr += 1; + } + // Low priority flush run whenever + add_thread_without_duplicate(uart_flush, 0, PRIORITIES-1); + unlock(&ubuffer.l); + return 0; +} + +void uart_flush(void) +{ + while (ubuffer.roffset != ubuffer.woffset) { + uart_char(ubuffer.buffer[ubuffer.roffset++]); + ubuffer.roffset %= UART_BUFFER_SIZE; + } +} + +void uart_10(unsigned long val) +{ + char* dptr = u32_to_str(val); + uart_string(dptr); +} + +void uart_hexn(unsigned long c_val) +{ + uart_hex(c_val); + uart_char('\n'); +} |