aboutsummaryrefslogtreecommitdiff
path: root/kernel/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers')
-rw-r--r--kernel/drivers/uart.S53
-rw-r--r--kernel/drivers/uart.c83
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');
+}