RustForge

rust-kernel

Rustbelt: a hobby x86_64 kernel written in Rust

rust-kernel / src / arch / aarch64 / board / pl011.rs
1452 bytes ยท raw
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
//! The Arm PL011 UART: QEMU virt's serial port, and the Pi 3's "UART0"
//! (which the Pi wires to Bluetooth by default; the mini-UART is the other
//! one). QEMU needs no setup at all; on real hardware the firmware has set
//! the baud rate, so `init` only makes sure it's on, 8 bits, FIFOs on.

use super::Uart;
use crate::arch::aarch64::mmio;
use core::sync::atomic::{AtomicUsize, Ordering};

const DR: usize = 0x00; // data register
const FR: usize = 0x18; // flags
const FR_TXFF: u32 = 1 << 5; // transmit FIFO full
const LCRH: usize = 0x2c; // line control
const CR: usize = 0x30; // control

pub struct Pl011 {
    base: AtomicUsize, // physical address
}

impl Pl011 {
    pub const fn new(base: usize) -> Self {
        Pl011 { base: AtomicUsize::new(base) }
    }
    pub fn base(&self) -> usize {
        self.base.load(Ordering::Relaxed)
    }
    pub fn set_base(&self, base: usize) {
        self.base.store(base, Ordering::Relaxed);
    }
    /// 8N1 with FIFOs; transmit + receive + UART enable.
    pub fn init(&self) {
        let b = self.base();
        mmio::write32(b + CR, 0);
        mmio::write32(b + LCRH, (3 << 5) | (1 << 4));
        mmio::write32(b + CR, (1 << 9) | (1 << 8) | 1);
    }
}

impl Uart for Pl011 {
    fn putc(&self, byte: u8) {
        let b = self.base();
        while mmio::read32(b + FR) & FR_TXFF != 0 {
            core::hint::spin_loop();
        }
        mmio::write32(b + DR, byte as u32);
    }
}