96 lines
3.4 KiB
C

/**
* UART board initialization of Asagiri
* Copyright (C) 2023 Asagiri contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <bits/alltypes.h>
#include <device.h>
#include <fdt.h>
#include <hal.h>
#include <string.h>
#include <uart.h>
void uart_init() {
/* Get MMIO, UART and MBOX addresses from FDT */
fdt_prop ranges = fdt_get_prop(fdt_get_addr("/soc/ranges"));
MMIO_BASE = SWAP_UINT32(*ranges.data) - SWAP_UINT32(*(ranges.data + 1));
fdt_prop gpio_path = fdt_get_prop(fdt_get_addr("/__symbols__/gpio"));
fdt_prop gpio_reg = fdt_get_prop(fdt_get_addr(strcat((char *)gpio_path.data, "/reg")));
GPIO_BASE = SWAP_UINT32(*gpio_reg.data) - MMIO_BASE;
fdt_prop uart_path = fdt_get_prop(fdt_get_addr("/__symbols__/uart1"));
fdt_prop uart_reg = fdt_get_prop(fdt_get_addr(strcat((char *)uart_path.data, "/reg")));
UART_BASE = SWAP_UINT32(*uart_reg.data) - MMIO_BASE;
GPPUD = GPIO_BASE + 0x94;
GPPUDCLK0 = GPIO_BASE + 0x98;
UART_DR = UART_BASE + 0x00;
UART_FR = UART_BASE + 0x18;
UART_IBRD = UART_BASE + 0x24;
UART_FBRD = UART_BASE + 0x28;
UART_LCRH = UART_BASE + 0x2C;
UART_CR = UART_BASE + 0x30;
UART_IMSC = UART_BASE + 0x38;
UART_ICR = UART_BASE + 0x44;
/* Disable UART0. */
mmio_write(UART_CR, 0);
/* Setup the GPIO pin 14 && 15.
* Disable pull up/down for all GPIO pins & delay for 150 cycles. */
mmio_write(GPPUD, 0);
delay(150);
/* Disable pull up/down for pin 14,15 & delay for 150 cycles. */
mmio_write(GPPUDCLK0, (1 << 14) | (1 << 15));
delay(150);
/* Write 0 to GPPUDCLK0 to make it take effect. */
mmio_write(GPPUDCLK0, 0);
/* Clear pending interrupts. */
mmio_write(UART_ICR, 0x7FF);
/* Set integer & fractional part of baud rate.
* Divider = UART_CLOCK/(16 * Baud) */
mmio_write(UART_IBRD, 1);
/* Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40. */
mmio_write(UART_FBRD, 40);
/* Enable FIFO & 8 bit data transmission (1 stop bit, no parity). */
mmio_write(UART_LCRH, (1 << 4) | (1 << 5) | (1 << 6));
/* Mask all interrupts. */
mmio_write(UART_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10));
/* Enable UART0, receive & transfer part of UART. */
mmio_write(UART_CR, 1 | (1 << 8) | (1 << 9));
}
void uart_putc(unsigned char c) {
/* Wait for UART to become ready to transmit. */
while (mmio_read(UART_FR) & (1 << 5))
;
mmio_write(UART_DR, c);
}
unsigned char uart_getc() {
/* Wait for UART to have received something. */
while (mmio_read(UART_FR) & (1 << 4))
;
return mmio_read(UART_DR);
}
void uart_puts(const char *str) {
for (size_t i = 0; str[i] != '\0'; i++) {
uart_putc((unsigned char)str[i]);
}
}