aboutsummaryrefslogtreecommitdiff
path: root/src/arm
diff options
context:
space:
mode:
authorWojtek Kosior <kwojtus@protonmail.com>2020-01-18 21:03:06 +0100
committerWojtek Kosior <kwojtus@protonmail.com>2020-01-18 21:03:06 +0100
commitad15edc4b3a3901812c823422f415b4ec9cc1177 (patch)
treeec69c105e0b9fd862d95e9daf4e1a755d0492aae /src/arm
parent5c8308c7ef5f4e528389ef7787dfc5e87d0a16d2 (diff)
downloadrpi-MMU-example-ad15edc4b3a3901812c823422f415b4ec9cc1177.tar.gz
rpi-MMU-example-ad15edc4b3a3901812c823422f415b4ec9cc1177.zip
make UART our own
Diffstat (limited to 'src/arm')
-rw-r--r--src/arm/PL1/PL1_common/uart.c57
-rw-r--r--src/arm/PL1/PL1_common/uart.h18
-rw-r--r--src/arm/PL1/kernel/setup.c2
3 files changed, 43 insertions, 34 deletions
diff --git a/src/arm/PL1/PL1_common/uart.c b/src/arm/PL1/PL1_common/uart.c
index 4dd1c2b..94aae46 100644
--- a/src/arm/PL1/PL1_common/uart.c
+++ b/src/arm/PL1/PL1_common/uart.c
@@ -3,53 +3,48 @@
#include "uart.h"
#include "global.h"
-// Loop <delay> times in a way that the compiler won't optimize away
-static inline void delay(int32_t count)
+void uart_init(uint32_t baud, uint32_t config)
{
- asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n"
- : "=r"(count): [count]"0"(count) : "cc");
-}
-
-void uart_init()
-{
- // Disable PL011_UART.
+ // PL011 UART must be disabled before configuring
wr32(PL011_UART_CR, 0);
-
- // Setup the GPIO pin 14 && 15.
- // Disable pull up/down for all GPIO pins & delay for 150 cycles.
+ // GPIO pins used for UART should have pull up/down disabled
+ // Procedure as described in BCM2835 ARM Peripherals
wr32(GPPUD, 0);
- delay(150);
- // Disable pull up/down for pin 14,15 & delay for 150 cycles.
+ for (int i = 0; i < 150; i++) // delay for at least 150 cycles
+ asm volatile("nop");
+
wr32(GPPUDCLK0, (1 << 14) | (1 << 15));
- delay(150);
- // Write 0 to GPPUDCLK0 to make it take effect.
- wr32(GPPUDCLK0, 0);
+ for (int i = 0; i < 150; i++)
+ asm volatile("nop");
- // Set integer & fractional part of baud rate.
- // Divider = UART_CLOCK/(16 * Baud)
- // Fraction part register = (Fractional part * 64) + 0.5
- // UART_CLOCK = 3000000; Baud = 115200.
+ wr32(GPPUDCLK0, 0);
+
+ wr32(GPPUD, 0);
- // Divider = 3000000 / (16 * 115200) = 1.627 = ~1.
- wr32(PL011_UART_IBRD, 1);
- // Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40.
- wr32(PL011_UART_FBRD, 40);
+ // Setting clock rate
+ // As described in UART (PL011) Technical Reference Manual
+ uint32_t int_part = DEFAULT_UART_CLOCK_RATE / (16 * baud);
+ uint32_t rest = DEFAULT_UART_CLOCK_RATE % (16 * baud);
+ uint32_t fract_part = (rest * 64 * 2 + 1) / (2 * 16 * baud);
+
+ wr32(PL011_UART_IBRD, int_part);
+ wr32(PL011_UART_FBRD, fract_part);
- // Set 8 bit data transmission (1 stop bit, no parity)
- // and disable FIFO to be able to receive interrupt every received
+ // Set data transmission specified by caller
+ // Don't enable FIFO to be able to receive interrupt every received
// char, not every 2 chars
- wr32(PL011_UART_LCRH, (1 << 5) | (1 << 6));
+ wr32(PL011_UART_LCRH, config);
- // set interrupt to come when transmit FIFO becomes ≤ 1/8 full
+ // Set interrupt to come when transmit FIFO becomes ≤ 1/8 full
// or receive FIFO becomes ≥ 1/8 full
// (not really matters, since we disabled FIFOs)
wr32(PL011_UART_IFLS, 0);
- // Enable PL011_UART, receive & transfer part of UART.2
- wr32(PL011_UART_CR, (1 << 0) | (1 << 8) | (1 << 9));
+ // Enable UART receiving and transmitting, as well as UART itself
+ wr32(PL011_UART_CR, (1 << 9) | (1 << 8) | 1);
// At first, it's probably safer to disable interrupts :)
uart_irq_disable();
diff --git a/src/arm/PL1/PL1_common/uart.h b/src/arm/PL1/PL1_common/uart.h
index 96f3634..e02b3c8 100644
--- a/src/arm/PL1/PL1_common/uart.h
+++ b/src/arm/PL1/PL1_common/uart.h
@@ -5,12 +5,26 @@
#include "global.h"
#include "interrupts.h"
+#define DEFAULT_UART_CLOCK_RATE 3000000
+
+#define UART_WLEN_8_BITS (0b11 << 5)
+#define UART_WLEN_7_BITS (0b10 << 5)
+#define UART_WLEN_6_BITS (0b01 << 5)
+#define UART_WLEN_5_BITS 0b00
+
+#define UART_2_STOP (1 << 3)
+#define UART_1_STOP 0
+
+#define UART_ODD_PAR (1 << 1)
+#define UART_EVEN_PAR ((1 << 1) | (1 << 2))
+#define UART_NO_PAR 0
+
// The offsets for reach register.
-// Controls actuation of pull up/down to ALL GPIO pins.
+// GPIO Pin Pull-up/down Enable
#define GPPUD (GPIO_BASE + 0x94)
-// Controls actuation of pull up/down for specific GPIO pin.
+// GPIO Pin Pull-up/down Enable Clock 0
#define GPPUDCLK0 (GPIO_BASE + 0x98)
// The base address for UART.
diff --git a/src/arm/PL1/kernel/setup.c b/src/arm/PL1/kernel/setup.c
index bf7c9a1..865a719 100644
--- a/src/arm/PL1/kernel/setup.c
+++ b/src/arm/PL1/kernel/setup.c
@@ -11,7 +11,7 @@
void setup(uint32_t r0, uint32_t machine_type,
struct atag_header *atags)
{
- uart_init();
+ uart_init(115200, UART_1_STOP | UART_NO_PAR | UART_WLEN_8_BITS);
// When we attach screen session after loading kernel with socat
// we miss kernel's greeting... So we'll make the kernel wait for