aboutsummaryrefslogtreecommitdiff
path: root/src/uart.rs
blob: 0f66116af4b531c27319af01e352fbe7b8fd2338 (plain)
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
//! # UART Console Definition
use crate::cpu::*;
use crate::sync::NullLock;
use core::fmt;
use crate::sync::interface::Mutex;

/// # Data Register
const UART0_DR: u32    = 0x3F201000;
/// # Flag Register
const UART0_FR: u32    = 0x3F201018;
/// # Fractional Baud Rate Register
const UART0_FBRD: u32  = 0x3F201028;
/// # Line Control Register
const UART0_LCRH: u32  = 0x3F20102C;
/// # Control Register
const UART0_CR: u32    = 0x3F201030;
/// # Interrupt Mask Set/ Clear Register
const UART0_IMSC: u32  = 0x3F201038;
/// # Interrupt Control Register
const UART0_ICR: u32   = 0x3F201044;
/// # Integer Baud Rate Register
const UART0_IBRD: u32  = 0x3F201024;

/// GPIO Register
const GPPUD: u32       = 0x3F200094;
/// GPIO Clock 0 Register
const GPPUDCLK0: u32   = 0x3F200098;

/// # UART Inner Structure
///
/// Keeps record of the console statistics.
struct UartInner {
	chars_written: usize,
}

/// # UART Structure
///
/// Wraps the UART writer in a sharable lock.
pub struct Uart {
	inner: NullLock<UartInner>,
}

impl UartInner {
	/// # Clear statistics
	///
	/// Create the writer with cleared statistics
	pub const fn new() -> Self {
		Self {
			chars_written: 0,
		}
	}

	/// # Initialize the UART setup
	///
	/// Set baud rate and timings
	pub fn init(&mut self) {
		store32(UART0_CR, 0);
		store32(GPPUD, 0);
		spin_for_n_cycles(150);
		store32(GPPUDCLK0, (1 << 14) | (1 << 15));
		spin_for_n_cycles(150);
		store32(GPPUDCLK0, 0);
		store32(UART0_ICR, 0x7FF);
		store32(UART0_IBRD, 9);
		store32(UART0_FBRD, 49);
		store32(UART0_LCRH, (1<<4) | (1<<5) | (1<<6));
		store32(UART0_IMSC, (1<<1) | (1<<4) | (1<<5) | (1<<6) | (1<<7) | (1<<8) | (1<<9) | (1<<10));
		store32(UART0_CR, (1<<0) | (1<<8) | (1<<9));
	}

	/// # Write `char` to UART
	fn write_char(&mut self, ch: char) {
		while load32(UART0_FR) & 0x20 != 0 {
			nop();
		}
		store32(UART0_DR, ch as u32);
		self.chars_written += 1;
	}

	/// # Flush UART
	fn flush(&self) {
		while load32(UART0_FR) & 0x08 != 0 {
			nop();
		}
	}
}

impl fmt::Write for UartInner {
	/// # Write string to UART console
	fn write_str(&mut self, s: &str) -> fmt::Result {
		for c in s.chars() {
			self.write_char(c);
		}
		Ok(())
	}
}


impl Uart {
	/// # Create sharable UART wrapper
	pub const fn new() -> Self {
		Self {
			inner: NullLock::new(UartInner::new()),
		}
	}

	/// # Call UART initialization
	pub fn init(&self) -> Result<(), &'static str> {
		self.inner.lock(|inner| inner.init());
		Ok(())
	}
}

impl super::console::interface::Write for Uart {
	/// # Write `char` to UART
	fn write_char(&self, c: char) {
		self.inner.lock(|inner| inner.write_char(c));
	}

	/// # Write formatted string to UART
	fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result {
		self.inner.lock(|inner| fmt::Write::write_fmt(inner, args))
	}

	/// # Flush UART
	fn flush(&self) {
		self.inner.lock(|inner| inner.flush());
	}
}

impl super::console::interface::Statistics for Uart {
	/// # Get `char` written stats
	fn chars_written(&self) -> usize {
		self.inner.lock(|inner| inner.chars_written)
	}
}

/// # UART Writer + Stats
impl super::console::interface::All for Uart {}

/// # Public reference to console.
pub static UART_WRITER: Uart = Uart::new();