96 lines
3.4 KiB
C
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]);
|
|
}
|
|
}
|