~increscent/rk3128-brom

ref: 73661af99c04bf720df79e92c2ff3c3ec2759363 rk3128-brom/uart/uart.rs -rw-r--r-- 2.5 KiB
73661af9 — Robert Williams Custom UART is working! 4 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#![no_main]
#![no_std]
#![no_builtins]

mod bits;

#[panic_handler]
fn panic_handler(_panic_info: &core::panic::PanicInfo) -> ! {
    loop {}
}

// Assume GPIO is already setup by ddr program

const UART_BASE: u32 = 0x2006_8000;

const UART_RBR: *mut u32 = (UART_BASE + 0x00) as *mut u32;
const UART_THR: *mut u32 = (UART_BASE + 0x00) as *mut u32;
const UART_DLL: *mut u32 = (UART_BASE + 0x00) as *mut u32;
const UART_DLH: *mut u32 = (UART_BASE + 0x04) as *mut u32;
const UART_IER: *mut u32 = (UART_BASE + 0x04) as *mut u32;
const UART_FCR: *mut u32 = (UART_BASE + 0x08) as *mut u32;
const UART_LCR: *mut u32 = (UART_BASE + 0x0C) as *mut u32;
const UART_LSR: *mut u32 = (UART_BASE + 0x14) as *mut u32;
const UART_USR: *mut u32 = (UART_BASE + 0x7C) as *mut u32;

#[no_mangle]
pub extern "C" fn main() {
    uart_init();

    uart_puts("Hello, world!\n");

    loop {
        let c = uart_getc();
        if c == '\r' {
            uart_putc('\n');
        }
        uart_putc(c);

        if c == 'Q' {
            // quit
            return;
        }
    }
}

fn uart_init() {
    // Disable UART interrupts
    bits::write(UART_IER, 0);

    // Enable FIFO (and reset FIFOs)
    bits::write(UART_FCR, 0x7);

//    // No FIFO
//    bits::write(UART_FCR, 0);

    // Wait until UART is not busy
    while (bits::read(UART_USR) & 0x1) != 0 {}
    const LCR_DIVISOR_LATCH: u32 = 0x80;
    const LCR_8_BIT_DATA: u32 = 0x03;
    // Set line control
    bits::write(UART_LCR, LCR_DIVISOR_LATCH | LCR_8_BIT_DATA);

    // Setup baud rate
    // 24,000,000 / (16 * divisor) = 115,200
    // divisor = 13
    bits::write(UART_DLH, 0);
    bits::write(UART_DLL, 13);
    
    bits::write(UART_LCR, LCR_8_BIT_DATA);
}

fn uart_puts(s: &str) {
    for b in s.as_bytes() {
        let c = *b as char;
        if c == '\n' { uart_putc('\r'); }
        uart_putc(c);
    }
}

fn uart_putc(c: char) {
    const LSR_THRE: u32 = 0x20;
    const USR_TX_FIFO_NOT_FULL: u32 = 0x02;

    // Wait until there's space in the TX FIFO
    while (bits::read(UART_USR) & USR_TX_FIFO_NOT_FULL) == 0 {}
    // Wait until the Transmit Holding Register is empty
    while (bits::read(UART_LSR) & LSR_THRE) == 0 {}
    bits::write(UART_THR, c as u32);
}

fn uart_getc() -> char {
    const LSR_DATA_READY: u32 = 0x01;

    // Wait until there's data in the RX FIFO
    while (bits::read(UART_LSR) & LSR_DATA_READY) == 0 {}

    return ((bits::read(UART_RBR) & 0xFF) as u8) as char;
}

//fn busy_wait() {
//    for _ in 0..0x00FF {
//        unsafe {
//            core::arch::asm!("nop");
//        }
//    }
//}