~increscent/rk3128-brom

ref: fa29de59579d123e2d47f6938bb41cb818e548f3 rk3128-brom/uart/uart.rs -rw-r--r-- 3.4 KiB
fa29de59 — Robert Williams Created DRAM version 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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#![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;

const DRAM_BASE: u32 = 0x6000_0000;
const DRAM_TEST_BASE: u32 = DRAM_BASE + 0x0000_2000; // So we don't overwrite our DRAM code

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

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

    const WORDS: u32 = 0x1_0000;
    const VALUE: u32 = 0x5C5C5C5C;

    for i in 0..WORDS {
        bits::write((DRAM_TEST_BASE + i * 4) as *mut u32, VALUE);
    }

    busy_wait();

    for i in 0..WORDS {
        let val = bits::read((DRAM_TEST_BASE + i * 4) as *mut u32);
        if val != VALUE {
            uart_putsx("Oh No! ", val);
        }
    }

    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 uart_putx(x: u32) {
    uart_putc('0');
    uart_putc('x');
    for i in 0..8 {
        let b: u8 = ((x >> ((7 - i) * 4)) & 0xF) as u8;
        let c: char = if b < 0xA {
            (b + '0' as u8) as char
        } else {
            ((b - 0xA) + 'A' as u8) as char
        };
        uart_putc(c);
    }
}

fn uart_putsx(s: &str, x: u32) {
    uart_puts(s);
    uart_putx(x);
    uart_puts("\n");
}

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