Created
April 10, 2023 12:05
-
-
Save NyanSatan/c669e3daff983f086401c9d3f1a832ea to your computer and use it in GitHub Desktop.
UART write-only driver for A6 SecureROM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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