Skip to content

Instantly share code, notes, and snippets.

@bb33bb
Forked from NyanSatan/uart.c
Created May 8, 2025 06:07
Show Gist options
  • Save bb33bb/865959ec1f37b98bc32fb0a5bf7a2653 to your computer and use it in GitHub Desktop.
Save bb33bb/865959ec1f37b98bc32fb0a5bf7a2653 to your computer and use it in GitHub Desktop.
UART write-only driver for A6 SecureROM
/*
* The algorithm is mostly stolen from iBoot source,
* cleaned up for the purpose
*
* TODO: analyze S5L8700X datasheet in order
* to understand if UART peripherial is the same,
* and if so - clean up this mess
*/
#include <stdint.h>
#include <securerom.h>
#include <target/offsets.h>
#define rULCON (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x00))
#define rUCON (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x04))
#define rUFCON (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x08))
#define rUMCON (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x0C))
#define rUTRSTAT (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x10))
#define rUERSTAT (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x14))
#define rUFSTAT (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x18))
#define rUMSTAT (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x1C))
#define rUBRDIV (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x28))
#define rUABRCNT (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x2C))
#define rUTXH (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x20))
#define rURXH (*(volatile uint32_t *)(TARGET_DEBUG_UART_BASEADDR + 0x24))
static void uart_gpio_init() {
*(volatile uint32_t *)(TARGET_GPIO_BASEADDR + sizeof(uint32_t) * (TARGET_GPIO_DEBUG_UART_PORT * 8 + TARGET_GPIO_DEBUG_UART_PIN)) = \
TARGET_GPIO_DEBUG_UART_CONFIG;
}
#define SAMPLE_RATE 16
#define BAUD_RATE 115200
int uart_init() {
/* configuring UART TX line GPIO */
uart_gpio_init();
/* enabling UART clocking */
clock_gate(TARGET_DEBUG_UART_CLK_GATE, true);
/* setting data sizes */
rULCON = 0x03; // 81N, not IR
rUCON = 0x05;
/* setting NCLK */
rUCON |= (1 << 10);
/* setting sample rate */
rUBRDIV = (rUBRDIV & ~(0xF << 16)) | ((16 - SAMPLE_RATE) << 16);
/* setting baud rate */
uint32_t freq = clock_get_frequency(TARGET_NCLK_CLK_GATE);
uint16_t div = freq / (BAUD_RATE * SAMPLE_RATE);
uint32_t baud_low, actual_baud;
actual_baud = freq / ((div + 0) * SAMPLE_RATE);
baud_low = freq / ((div + 1) * SAMPLE_RATE);
if ((BAUD_RATE - baud_low) < (actual_baud - BAUD_RATE)) {
div++;
}
rUBRDIV = (rUBRDIV & ~0xFFFF) | (div - 1);
/* setting flow control */
rUMCON = 0x01; // no flow control - assert RTS
/* setting FIFO */
rUFCON = 0; // no FIFO
/*
* setting mode:
* TX and RX (GPIO is disabled for RX, so we should be OK),
* no interrupts
*/
rUCON &= ~((0xf << 11) | (1 << 7));
rUCON = (rUCON & ~0xf) | 0x5;
return 0;
}
int uart_putc(char c) {
/* wait */
while (!((rUTRSTAT) & 0x04));
/* write! */
rUTXH = c;
return 1;
}
int uart_puts(const char *s) {
char c;
size_t size = 0;
while ((c = *s++)) {
uart_putc(c);
size++;
}
return size;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment