11// SPDX-License-Identifier: MIT OR Apache-2.0
22//
3- // Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
3+ // Copyright (c) 2018-2025 Andre Richter <andre.o.richter@gmail.com>
44
55//! PL011 UART driver.
66//!
@@ -201,22 +201,6 @@ impl PL011UartInner {
201201 }
202202
203203 /// Set up baud rate and characteristics.
204- ///
205- /// This results in 8N1 and 921_600 baud.
206- ///
207- /// The calculation for the BRD is (we set the clock to 48 MHz in config.txt):
208- /// `(48_000_000 / 16) / 921_600 = 3.2552083`.
209- ///
210- /// This means the integer part is `3` and goes into the `IBRD`.
211- /// The fractional part is `0.2552083`.
212- ///
213- /// `FBRD` calculation according to the PL011 Technical Reference Manual:
214- /// `INTEGER((0.2552083 * 64) + 0.5) = 16`.
215- ///
216- /// Therefore, the generated baud rate divider is: `3 + 16/64 = 3.25`. Which results in a
217- /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`.
218- ///
219- /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`.
220204 pub fn init ( & mut self ) {
221205 // Execution can arrive here while there are still characters queued in the TX FIFO and
222206 // actively being sent out by the UART hardware. If the UART is turned off in this case,
@@ -240,9 +224,26 @@ impl PL011UartInner {
240224 // updated on a single write strobe generated by a LCR_H write. So, to internally update the
241225 // contents of IBRD or FBRD, a LCR_H write must always be performed at the end.
242226 //
243- // Set the baud rate, 8N1 and FIFO enabled.
244- self . registers . IBRD . write ( IBRD :: BAUD_DIVINT . val ( 3 ) ) ;
245- self . registers . FBRD . write ( FBRD :: BAUD_DIVFRAC . val ( 16 ) ) ;
227+ // Set the baud rate.
228+ #[ cfg( feature = "bsp_rpi5" ) ]
229+ {
230+ // For Pi 5, use the known-good 115200 baud configuration.
231+ // This is proven to work with the default 48MHz UART clock.
232+ // BAUDDIV = 48,000,000 / (16 * 115200) = 26.0416...
233+ // IBRD = 26, FBRD = 3
234+ self . registers . IBRD . write ( IBRD :: BAUD_DIVINT . val ( 26 ) ) ;
235+ self . registers . FBRD . write ( FBRD :: BAUD_DIVFRAC . val ( 3 ) ) ;
236+ }
237+ #[ cfg( not( feature = "bsp_rpi5" ) ) ]
238+ {
239+ // Original configuration for RPi3/4 at 921600 baud.
240+ // BAUDDIV = 48_000,000 / (16 * 921_600) = 3.2552...
241+ // IBRD = 3, FBRD = 16
242+ self . registers . IBRD . write ( IBRD :: BAUD_DIVINT . val ( 3 ) ) ;
243+ self . registers . FBRD . write ( FBRD :: BAUD_DIVFRAC . val ( 16 ) ) ;
244+ }
245+
246+ // Set 8N1 and FIFO enabled.
246247 self . registers
247248 . LCR_H
248249 . write ( LCR_H :: WLEN :: EightBit + LCR_H :: FEN :: FifosEnabled ) ;
@@ -255,7 +256,18 @@ impl PL011UartInner {
255256
256257 /// Send a character.
257258 fn write_char ( & mut self , c : char ) {
258- // Spin while TX FIFO full is set, waiting for an empty slot.
259+ // If the character is a newline, prepend a carriage return.
260+ if c == '\n' {
261+ // Spin while TX FIFO full is set.
262+ while self . registers . FR . matches_all ( FR :: TXFF :: SET ) {
263+ cpu:: nop ( ) ;
264+ }
265+ // Write the carriage return character.
266+ self . registers . DR . set ( '\r' as u32 ) ;
267+ }
268+
269+ // Now, send the original character.
270+ // Spin while TX FIFO full is set.
259271 while self . registers . FR . matches_all ( FR :: TXFF :: SET ) {
260272 cpu:: nop ( ) ;
261273 }
@@ -292,7 +304,8 @@ impl PL011UartInner {
292304 // Read one character.
293305 let mut ret = self . registers . DR . get ( ) as u8 as char ;
294306
295- // Convert carrige return to newline.
307+ // Convert carriage return to newline. This is a standard behavior
308+ // for console input.
296309 if ret == '\r' {
297310 ret = '\n'
298311 }
@@ -316,6 +329,7 @@ impl PL011UartInner {
316329impl fmt:: Write for PL011UartInner {
317330 fn write_str ( & mut self , s : & str ) -> fmt:: Result {
318331 for c in s. chars ( ) {
332+ // The `write_char` function now correctly handles `\n` -> `\r\n` conversion.
319333 self . write_char ( c) ;
320334 }
321335
0 commit comments