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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#![no_std]

use processor::cpu_relax;
use simink_serial::{self, Serial, SerialInstance};
use simink_spinlock::{self, SpinLock};
use tock_registers::{
    interfaces::{Readable, Writeable},
    register_bitfields, register_structs,
    registers::{ReadOnly, ReadWrite, WriteOnly},
};

register_bitfields! {
    u32,

    Data [
        IO OFFSET(0) NUMBITS(32) []
    ],

    Flags [
        FR OFFSET(0) NUMBITS(32) [
            TXFE = 0x80,
            RXFF = 0x40,
            TXFF = 0x20,
            RXFE = 0x10,
            BUSY = 0x08,
        ]
    ],

    Baud [
        BAUD OFFSET(0) NUMBITS(32) []
    ],

    LineControl [
        BRK OFFSET(0) NUMBITS(1) [],
        PEN OFFSET(1) NUMBITS(1) [],
        EPS OFFSET(2) NUMBITS(1) [],
        STP2 OFFSET(3) NUMBITS(1) [],
        FEN OFFSET(4) NUMBITS(1) [],

        WLEN OFFSET(5) NUMBITS(2) [
            WLEN_5 = 0,
            WLEN_6 = 1,
            WLEN_7 = 2,
            WLEN_8 = 3,
        ],

        SPS OFFSET(7) NUMBITS(1) [],
    ],

    Control [
        UARTEN OFFSET(0) NUMBITS(1) [],
        SIREN OFFSET(1) NUMBITS(1) [],
        IIRLP OFFSET(2) NUMBITS(1) [],
        LPE OFFSET(7) NUMBITS(1) [],
        TXE OFFSET(8) NUMBITS(1) [],
        RXE OFFSET(9) NUMBITS(1) [],
        DTR OFFSET(10) NUMBITS(1) [],
        RTS OFFSET(11) NUMBITS(1) [],
        OUT1 OFFSET(12) NUMBITS(1) [],
        OUT2 OFFSET(13) NUMBITS(1) [],
        RTSEN OFFSET(14) NUMBITS(1) [],
        CTSEN OFFSET(15) NUMBITS(1) [],
    ]
}

register_structs! {
    Pl011Registers {
        // Data register
        (0x00 => dr: WriteOnly<u32, Data::Register>),
        // ecr - 0x04 Error clear register (Write)
        // pl010_lcrh - 0x08 Line control register, high byte
        // pl010_lcrm - 0x0C Line control register, middle byte
        // pl010_lcrl - 0x10 Line control register, low byte
        // pl010_cr - 0x14 Control register
        (0x04 => _reserved),
        // Flag register (Read only)
        (0x18 => fr: ReadOnly<u32, Flags::Register>),
        // pl011_rlcr - 0x1c Receive line control register
        // lpr - 0x20 IrDA low-power counter register
        (0x1c => _reserved2),
        // Integer baud rate register
        (0x24 => ibrd: ReadWrite<u32, Baud::Register>),
        // Fractional baud rate register
        (0x28 => fbrd: ReadWrite<u32, Baud::Register>),
        // Line control register
        (0x2c => lcrh: ReadWrite<u32, LineControl::Register>),
        // Control register
        (0x30 => cr: ReadWrite<u32, Control::Register>),
        (0x34 => @END),
    }
}

pub struct Pl011State {
    val: SpinLock<*mut Pl011Registers>,
}

impl Default for Pl011State {
    fn default() -> Self {
        Self::new()
    }
}

impl Pl011State {
    pub fn new() -> Self {
        Self::default()
    }

    #[inline]
    fn putc(reg: &Pl011Registers, c: u8) {
        while reg.fr.matches_any(Flags::FR::TXFF) {
            cpu_relax();
        }

        reg.dr.set(c as u32);

        while reg.fr.matches_any(Flags::FR::BUSY) {
            cpu_relax();
        }
    }
}

impl<S> SerialInstance<S> for Pl011State {
    fn init(&self, serial: &Serial<S>) {
        let reg;
        unsafe {
            let mut val = self.val.lock();
            *val = serial.virtbase as *mut Pl011Registers;
            reg = val.as_ref().unwrap();
        }
        reg.cr.set(0);

        let mut temp = 16 * serial.baud;
        let divider = serial.clk / temp;
        let remainder = serial.clk % temp;
        temp = (8 * remainder) / serial.baud;
        let fraction = (temp >> 1) + (temp & 1);

        reg.ibrd.set(divider);
        reg.fbrd.set(fraction);

        reg.lcrh
            .write(LineControl::WLEN::WLEN_8 + LineControl::FEN::SET);

        reg.cr.write(
            Control::UARTEN::SET + Control::TXE::SET + Control::RXE::SET + Control::RTS::SET,
        );
    }

    fn write(&self, s: &str) {
        let reg;
        unsafe {
            reg = self.val.lock().as_ref().unwrap();
        }
        for c in s.bytes() {
            if c == b'\n' {
                Pl011State::putc(reg, b'\r');
            }
            Pl011State::putc(reg, c);
        }
    }
}