From 1af7591e37d09ddcd734ea07d0e999cf61c8bc5e Mon Sep 17 00:00:00 2001 From: vetch Date: Mon, 13 Jan 2020 12:40:38 +0100 Subject: Great Reorganisation, modify structure and makefile --- src/arm/PL1/PL1_common/global.h | 38 ++++++++++++++ src/arm/PL1/PL1_common/uart.c | 103 ++++++++++++++++++++++++++++++++++++++ src/arm/PL1/PL1_common/uart.h | 106 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 src/arm/PL1/PL1_common/global.h create mode 100644 src/arm/PL1/PL1_common/uart.c create mode 100644 src/arm/PL1/PL1_common/uart.h (limited to 'src/arm/PL1/PL1_common') diff --git a/src/arm/PL1/PL1_common/global.h b/src/arm/PL1/PL1_common/global.h new file mode 100644 index 0000000..4e17b44 --- /dev/null +++ b/src/arm/PL1/PL1_common/global.h @@ -0,0 +1,38 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#include + +// board type, raspi2 +#define RASPI 2 + +// conditionally #define PERIF_BASE +#if RASPI == 4 + +#define PERIF_BASE 0xFE000000 + +#elif RASPI == 3 || RASPI == 2 + +#define PERIF_BASE 0x3F000000 + +#else // if RASPI == 1 + +#define PERIF_BASE 0x20000000 + +#endif + +// GPIO_BASE is #define'd in terms of PERIF_BASE +// (as in sane kernels - like linux, not like in wiki.osdev codes...) +#define GPIO_BASE (PERIF_BASE + 0x200000) + +inline static uint32_t rd32(uint32_t addr) +{ + return *(uint32_t volatile*) addr; +} + +inline static void wr32(uint32_t addr, uint32_t value) +{ + *(uint32_t volatile*) addr = value; +} + +#endif // GLOBAL_H diff --git a/src/arm/PL1/PL1_common/uart.c b/src/arm/PL1/PL1_common/uart.c new file mode 100644 index 0000000..4dd1c2b --- /dev/null +++ b/src/arm/PL1/PL1_common/uart.c @@ -0,0 +1,103 @@ +#include +#include +#include "uart.h" +#include "global.h" + +// Loop times in a way that the compiler won't optimize away +static inline void delay(int32_t count) +{ + asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n" + : "=r"(count): [count]"0"(count) : "cc"); +} + +void uart_init() +{ + // Disable PL011_UART. + wr32(PL011_UART_CR, 0); + + // Setup the GPIO pin 14 && 15. + + // Disable pull up/down for all GPIO pins & delay for 150 cycles. + wr32(GPPUD, 0); + delay(150); + + // Disable pull up/down for pin 14,15 & delay for 150 cycles. + wr32(GPPUDCLK0, (1 << 14) | (1 << 15)); + delay(150); + + // Write 0 to GPPUDCLK0 to make it take effect. + wr32(GPPUDCLK0, 0); + + // 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. + + // 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); + + // Set 8 bit data transmission (1 stop bit, no parity) + // and disable FIFO to be able to receive interrupt every received + // char, not every 2 chars + wr32(PL011_UART_LCRH, (1 << 5) | (1 << 6)); + + // 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)); + + // At first, it's probably safer to disable interrupts :) + uart_irq_disable(); + + // The above disables the entire uart irq; + // Also disable single sources within it + wr32(PL011_UART_IMSC, 0); +} + +inline static _Bool can_transmit(void) +{ + return !(rd32(PL011_UART_FR) & (1 << 5)); +} + +inline static _Bool can_receive(void) +{ + return !(rd32(PL011_UART_FR) & (1 << 4)); +} + +void putchar(char c) +{ + while (!can_transmit()); + + wr32(PL011_UART_DR, c); +} + +char getchar(void) +{ + while (!can_receive()); + + return rd32(PL011_UART_DR); +} + +_Bool putchar_non_blocking(char c) +{ + if (can_transmit()) + { + wr32(PL011_UART_DR, c); + return 0; + } + + return 1; +} + +int getchar_non_blocking(void) +{ + if (can_receive()) + return rd32(PL011_UART_DR); + + return -1; +} diff --git a/src/arm/PL1/PL1_common/uart.h b/src/arm/PL1/PL1_common/uart.h new file mode 100644 index 0000000..96f3634 --- /dev/null +++ b/src/arm/PL1/PL1_common/uart.h @@ -0,0 +1,106 @@ +#ifndef UART_H +#define UART_H + +#include +#include "global.h" +#include "interrupts.h" + +// The offsets for reach register. + +// Controls actuation of pull up/down to ALL GPIO pins. +#define GPPUD (GPIO_BASE + 0x94) + +// Controls actuation of pull up/down for specific GPIO pin. +#define GPPUDCLK0 (GPIO_BASE + 0x98) + +// The base address for UART. +#define PL011_UART_BASE (GPIO_BASE + 0x1000) + +// The offsets for reach register for the UART. +#define PL011_UART_DR (PL011_UART_BASE + 0x00) +#define PL011_UART_RSRECR (PL011_UART_BASE + 0x04) +#define PL011_UART_FR (PL011_UART_BASE + 0x18) +#define PL011_UART_ILPR (PL011_UART_BASE + 0x20) +#define PL011_UART_IBRD (PL011_UART_BASE + 0x24) +#define PL011_UART_FBRD (PL011_UART_BASE + 0x28) +#define PL011_UART_LCRH (PL011_UART_BASE + 0x2C) +#define PL011_UART_CR (PL011_UART_BASE + 0x30) +#define PL011_UART_IFLS (PL011_UART_BASE + 0x34) +#define PL011_UART_IMSC (PL011_UART_BASE + 0x38) +#define PL011_UART_RIS (PL011_UART_BASE + 0x3C) +#define PL011_UART_MIS (PL011_UART_BASE + 0x40) +#define PL011_UART_ICR (PL011_UART_BASE + 0x44) +#define PL011_UART_DMACR (PL011_UART_BASE + 0x48) +#define PL011_UART_ITCR (PL011_UART_BASE + 0x80) +#define PL011_UART_ITIP (PL011_UART_BASE + 0x84) +#define PL011_UART_ITOP (PL011_UART_BASE + 0x88) +#define PL011_UART_TDR (PL011_UART_BASE + 0x8C) + +void uart_init(); +void putchar(char c); +char getchar(void); +_Bool putchar_non_blocking(char c); +int getchar_non_blocking(void); + +// TODO experiment to see if this gives us raw uart irq or the uart +// irq bit or'd with it's enable bit (not crucial for now, sice in our +// code this function only gets called when this irq is enabled) +static inline _Bool uart_irq_pending(void) +{ + return + ((uint32_t) 1 << 25) & rd32(ARM_IRQ_PENDING_2); +} + +static inline void uart_irq_disable(void) +{ + // Mask uart in arm peripheral interrupts + wr32(ARM_DISABLE_IRQS_2, ((uint32_t) 1) << 25); +} + +static inline void uart_irq_enable(void) +{ + // Unmask uart in arm peripheral interrupts + wr32(ARM_ENABLE_IRQS_2, ((uint32_t) 1) << 25); +} + +static inline _Bool uart_recv_irq_pending(void) +{ + return (1 << 4) & rd32(PL011_UART_MIS); +} + +static inline void uart_recv_irq_disable(void) +{ + wr32(PL011_UART_IMSC, rd32(PL011_UART_IMSC) & ~(1 << 4)); +} + +static inline void uart_recv_irq_enable(void) +{ + wr32(PL011_UART_IMSC, rd32(PL011_UART_IMSC) | (1 << 4)); +} + +static inline void uart_clear_recv_irq(void) +{ + wr32(PL011_UART_ICR, (1 << 4)); +} + +static inline _Bool uart_send_irq_pending(void) +{ + return (1 << 5) & rd32(PL011_UART_MIS); +} + +static inline void uart_send_irq_disable(void) +{ + wr32(PL011_UART_IMSC, rd32(PL011_UART_IMSC) & ~(1 << 5)); +} + +static inline void uart_send_irq_enable(void) +{ + wr32(PL011_UART_IMSC, rd32(PL011_UART_IMSC) | (1 << 5)); +} + +static inline void uart_clear_send_irq(void) +{ + wr32(PL011_UART_ICR, (1 << 5)); +} + +#endif // UART_H -- cgit v1.2.3