rpi4-osdev/part3-helloworld/io.c
2020-07-12 15:34:23 +01:00

96 lines
3.1 KiB
C

// GPIO
enum {
PERIPHERAL_BASE = 0xFE000000,
GPFSEL0 = PERIPHERAL_BASE + 0x200000,
GPSET0 = PERIPHERAL_BASE + 0x20001C,
GPCLR0 = PERIPHERAL_BASE + 0x200028,
GPPUPPDN0 = PERIPHERAL_BASE + 0x2000E4
};
enum {
GPIO_MAX_PIN = 53,
GPIO_FUNCTION_ALT5 = 2,
};
enum {
Pull_None = 0,
};
void mmio_write(long reg, unsigned int val) { *(volatile unsigned int *)reg = val; }
unsigned int mmio_read(long reg) { return *(volatile unsigned int *)reg; }
unsigned int gpio_call(unsigned int pin_number, unsigned int value, unsigned int base, unsigned int field_size, unsigned int field_max) {
unsigned int field_mask = (1 << field_size) - 1;
if (pin_number > field_max) return 0;
if (value > field_mask) return 0;
unsigned int num_fields = 32 / field_size;
unsigned int reg = base + ((pin_number / num_fields) * 4);
unsigned int shift = (pin_number % num_fields) * field_size;
unsigned int curval = mmio_read(reg);
curval &= ~(field_mask << shift);
curval |= value << shift;
mmio_write(reg, curval);
return 1;
}
unsigned int gpio_set (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPSET0, 1, GPIO_MAX_PIN); }
unsigned int gpio_clear (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPCLR0, 1, GPIO_MAX_PIN); }
unsigned int gpio_pull (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPPUPPDN0, 2, GPIO_MAX_PIN); }
unsigned int gpio_function(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPFSEL0, 3, GPIO_MAX_PIN); }
void gpio_useAsAlt5(unsigned int pin_number) {
gpio_pull(pin_number, Pull_None);
gpio_function(pin_number, GPIO_FUNCTION_ALT5);
}
// UART
enum {
AUX_BASE = PERIPHERAL_BASE + 0x215000,
AUX_ENABLES = AUX_BASE + 4,
AUX_MU_IO_REG = AUX_BASE + 64,
AUX_MU_IER_REG = AUX_BASE + 68,
AUX_MU_IIR_REG = AUX_BASE + 72,
AUX_MU_LCR_REG = AUX_BASE + 76,
AUX_MU_MCR_REG = AUX_BASE + 80,
AUX_MU_LSR_REG = AUX_BASE + 84,
AUX_MU_CNTL_REG = AUX_BASE + 96,
AUX_MU_BAUD_REG = AUX_BASE + 104,
AUX_UART_CLOCK = 500000000,
UART_MAX_QUEUE = 16 * 1024
};
#define AUX_MU_BAUD(baud) ((AUX_UART_CLOCK/(baud*8))-1)
void uart_init() {
mmio_write(AUX_ENABLES, 1); //enable UART1
mmio_write(AUX_MU_IER_REG, 0);
mmio_write(AUX_MU_CNTL_REG, 0);
mmio_write(AUX_MU_LCR_REG, 3); //8 bits
mmio_write(AUX_MU_MCR_REG, 0);
mmio_write(AUX_MU_IER_REG, 0);
mmio_write(AUX_MU_IIR_REG, 0xC6); //disable interrupts
mmio_write(AUX_MU_BAUD_REG, AUX_MU_BAUD(115200));
gpio_useAsAlt5(14);
gpio_useAsAlt5(15);
mmio_write(AUX_MU_CNTL_REG, 3); //enable RX/TX
}
unsigned int uart_isWriteByteReady() { return mmio_read(AUX_MU_LSR_REG) & 0x20; }
void uart_writeByteBlockingActual(unsigned char ch) {
while (!uart_isWriteByteReady());
mmio_write(AUX_MU_IO_REG, (unsigned int)ch);
}
void uart_writeText(char *buffer) {
while (*buffer) {
if (*buffer == '\n') uart_writeByteBlockingActual('\r');
uart_writeByteBlockingActual(*buffer++);
}
}