From 4abcbeba4cf2192e04e117f613f7ed8c92140639 Mon Sep 17 00:00:00 2001 From: YinhuaChen-cloud <229676342@qq.com> Date: Fri, 6 Mar 2026 18:15:37 +0800 Subject: [PATCH 1/2] Merge the driver of NS16650 and NS16550 Merge the driver of NS16650 and NS16550 Now the name of driver code is ns16x50.rs x means it can be 5, 6, 7 or other digits --- driver/src/uart/mod.rs | 3 +- driver/src/uart/ns16550a.rs | 101 ------------------ driver/src/uart/{ns16650.rs => ns16x50.rs} | 113 ++++++++++++--------- kernel/src/boards/qemu_riscv32/config.rs | 4 +- kernel/src/boards/qemu_riscv32/mod.rs | 10 +- kernel/src/boards/qemu_riscv64/config.rs | 4 +- kernel/src/boards/qemu_riscv64/mod.rs | 10 +- kernel/src/boards/rk3568/mod.rs | 4 +- 8 files changed, 83 insertions(+), 166 deletions(-) delete mode 100644 driver/src/uart/ns16550a.rs rename driver/src/uart/{ns16650.rs => ns16x50.rs} (59%) diff --git a/driver/src/uart/mod.rs b/driver/src/uart/mod.rs index 6a7e6b0a..78b77074 100644 --- a/driver/src/uart/mod.rs +++ b/driver/src/uart/mod.rs @@ -19,8 +19,7 @@ pub mod dumb; pub mod gd32e5x_uart; #[cfg(target_chip = "gd32vw55x")] pub mod gd32vw55x; -pub mod ns16550a; -pub mod ns16650; +pub mod ns16x50; #[derive(Debug, Clone, PartialEq, Eq)] #[repr(C)] diff --git a/driver/src/uart/ns16550a.rs b/driver/src/uart/ns16550a.rs deleted file mode 100644 index 75c9d440..00000000 --- a/driver/src/uart/ns16550a.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use blueos_hal::{ - uart::Uart, Configuration, Has8bitDataReg, HasFifo, HasInterruptReg, HasLineStatusReg, PlatPeri, -}; -use core::{cell::UnsafeCell, fmt, ptr::NonNull}; -use safe_mmio::{ - field, - fields::{ReadOnly, ReadPure, ReadPureWrite, ReadWrite, WriteOnly}, - UniqueMmioPointer, -}; - -// Register description -// see: https://uart16550.readthedocs.io/en/latest/uart16550doc.html - -// NS16550A resigter map(not complete) -#[repr(C)] -pub struct NS16550ARegisters { - /// 0x000: Transmit Holding Register - pub uartthr: WriteOnly, - /// 0x001 - 0x004 - reserved_01: [u8; 4], - /// 0x005: Line Status Register - pub uartlsr: ReadOnly, -} - -pub struct Ns16550a<'a> { - pub regs: UnsafeCell>, -} - -impl Ns16550a<'_> { - pub const fn new(base_addr: usize) -> Self { - Ns16550a { - regs: UnsafeCell::new(unsafe { - UniqueMmioPointer::new(NonNull::new(base_addr as *mut NS16550ARegisters).unwrap()) - }), - } - } -} - -macro_rules! field_used_by_inner { - ($mmio_pointer:expr, $field:ident) => {{ - // Make sure $mmio_pointer is the right type. - let mmio_pointer: &mut UniqueMmioPointer<_> = $mmio_pointer; - // SAFETY: ptr_mut is guaranteed to return a valid pointer for MMIO, so the pointer to the - // field must also be valid. MmioPointer::child gives it the same lifetime as the original - // pointer. - unsafe { - let child_pointer = - core::ptr::NonNull::new(&raw mut (*mmio_pointer.ptr_mut()).$field).unwrap(); - mmio_pointer.child(child_pointer) - } - }}; -} - -impl Configuration for Ns16550a<'static> { - type Target = (); - fn configure(&self, _config: &super::UartConfig) -> blueos_hal::err::Result<()> { - Ok(()) - } -} - -impl Uart - for Ns16550a<'static> -{ -} - -impl Has8bitDataReg for Ns16550a<'static> { - fn write_data8(&self, data: u8) { - let unsafe_mut_ref = unsafe { &mut *self.regs.get() }; - field_used_by_inner!(unsafe_mut_ref, uartthr).write(data as u8); - } -} - -impl HasLineStatusReg for Ns16550a<'static> {} - -impl HasFifo for Ns16550a<'static> {} - -impl HasInterruptReg for Ns16550a<'static> { - type InterruptType = super::InterruptType; - fn get_interrupt(&self) -> Self::InterruptType { - Self::InterruptType::Unknown - } -} - -unsafe impl Send for Ns16550a<'static> {} -unsafe impl Sync for Ns16550a<'static> {} - -impl PlatPeri for Ns16550a<'static> {} diff --git a/driver/src/uart/ns16650.rs b/driver/src/uart/ns16x50.rs similarity index 59% rename from driver/src/uart/ns16650.rs rename to driver/src/uart/ns16x50.rs index a21aa3d6..11555102 100644 --- a/driver/src/uart/ns16650.rs +++ b/driver/src/uart/ns16x50.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2025 vivo Mobile Communication Co., Ltd. +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,6 +24,26 @@ use tock_registers::{ use crate::static_ref::StaticRef; +#[cfg(any(target_board = "qemu_riscv32", target_board = "qemu_riscv64"))] +// qemu virt platform uses NS16550 UART +// NS16550 uses 8-bit registers, and the register offset is 1 byte. +register_structs! { + UartRegisters { + /// Get or Put Register. + (0x00 => rbr: ReadWrite), + (0x01 => ier: ReadWrite), + (0x02 => fcr: ReadWrite), + (0x03 => lcr: ReadWrite), + (0x04 => mcr: ReadWrite), + (0x05 => lsr: ReadOnly), + (0x06 => msr: ReadOnly), + (0x07 => @END), + } +} + +#[cfg(target_board = "rk3568")] +// rk3568 uses NS16650 UART +// NS16650 uses 32-bit registers, and the register offset is 4 bytes. register_structs! { UartRegisters { /// Get or Put Register. @@ -47,32 +67,42 @@ register_structs! { } } -register_bitfields! [u32, - LSR [ - DATA_READY OFFSET(0) NUMBITS(1) [], - OVERRUN_ERROR OFFSET(1) NUMBITS(1) [], - PARITY_ERROR OFFSET(2) NUMBITS(1) [], - FRAMING_ERROR OFFSET(3) NUMBITS(1) [], - BREAK_INTERRUPT OFFSET(4) NUMBITS(1) [], - TRANS_HOLD_REG_EMPTY OFFSET(5) NUMBITS(1) [], - TRANS_EMPTY OFFSET(6) NUMBITS(1) [], - RECV_FIFO_ERROR OFFSET(7) NUMBITS(1) [], - ], - - IER [ - RECV_DATA_AVAILABLE OFFSET(0) NUMBITS(1) [], - TRANS_HOLD_EMPTY OFFSET(1) NUMBITS(1) [], - RECV_LINE_STATUS OFFSET(2) NUMBITS(1) [], - MODEM_STATUS OFFSET(3) NUMBITS(1) [], - PROG_THRE OFFSET(5) NUMBITS(1) [], - ] -]; - -pub struct Ns16650 { +macro_rules! define_ns16x50_registers { + ($base:ident) => { + register_bitfields! [$base, + LSR [ + DATA_READY OFFSET(0) NUMBITS(1) [], + OVERRUN_ERROR OFFSET(1) NUMBITS(1) [], + PARITY_ERROR OFFSET(2) NUMBITS(1) [], + FRAMING_ERROR OFFSET(3) NUMBITS(1) [], + BREAK_INTERRUPT OFFSET(4) NUMBITS(1) [], + TRANS_HOLD_REG_EMPTY OFFSET(5) NUMBITS(1) [], + TRANS_EMPTY OFFSET(6) NUMBITS(1) [], + RECV_FIFO_ERROR OFFSET(7) NUMBITS(1) [], + ], + + IER [ + RECV_DATA_AVAILABLE OFFSET(0) NUMBITS(1) [], + TRANS_HOLD_EMPTY OFFSET(1) NUMBITS(1) [], + RECV_LINE_STATUS OFFSET(2) NUMBITS(1) [], + MODEM_STATUS OFFSET(3) NUMBITS(1) [], + PROG_THRE OFFSET(5) NUMBITS(1) [], + ] + ]; + } +} + +#[cfg(not(target_board = "rk3568"))] +define_ns16x50_registers!(u8); + +#[cfg(target_board = "rk3568")] +define_ns16x50_registers!(u32); + +pub struct Ns16x50 { registers: StaticRef, } -impl Ns16650 { +impl Ns16x50 { pub const fn new(base: usize) -> Self { Self { registers: unsafe { StaticRef::new(base as *const UartRegisters) }, @@ -80,16 +110,16 @@ impl Ns16650 { } } -impl Configuration for Ns16650 { +impl Configuration for Ns16x50 { type Target = (); fn configure(&self, para: &super::UartConfig) -> blueos_hal::err::Result<()> { Ok(()) } } -impl Uart for Ns16650 {} +impl Uart for Ns16x50 {} -impl Has8bitDataReg for Ns16650 { +impl Has8bitDataReg for Ns16x50 { fn read_data8(&self) -> Result { let er_bits = self.registers.ier.get(); if LSR::FRAMING_ERROR.is_set(er_bits) @@ -104,6 +134,9 @@ impl Has8bitDataReg for Ns16650 { } fn write_data8(&self, data: u8) { + #[cfg(any(target_board = "qemu_riscv32", target_board = "qemu_riscv64"))] + self.registers.rbr.set(data as u8); + #[cfg(target_board = "rk3568")] self.registers.rbr.set(data as u32); } @@ -112,13 +145,13 @@ impl Has8bitDataReg for Ns16650 { } } -impl HasLineStatusReg for Ns16650 { +impl HasLineStatusReg for Ns16x50 { fn is_bus_busy(&self) -> bool { !self.registers.lsr.is_set(LSR::TRANS_EMPTY) } } -impl HasFifo for Ns16650 { +impl HasFifo for Ns16x50 { fn enable_fifo(&self, num: u8) -> blueos_hal::err::Result<()> { todo!() } @@ -132,13 +165,9 @@ impl HasFifo for Ns16650 { } } -impl HasInterruptReg for Ns16650 { +impl HasInterruptReg for Ns16x50 { type InterruptType = super::InterruptType; - fn enable_interrupt(&self, int_type: Self::InterruptType) {} - - fn disable_interrupt(&self, int_type: Self::InterruptType) {} - fn clear_interrupt(&self, int_type: Self::InterruptType) { match int_type { super::InterruptType::Rx => {} @@ -150,19 +179,9 @@ impl HasInterruptReg for Ns16650 { fn get_interrupt(&self) -> Self::InterruptType { todo!() } - - fn set_interrupt_handler(&self, handler: &'static dyn Fn()) {} - - fn get_irq_nums(&self) -> &[u32] { - &[] - } } -unsafe impl Sync for Ns16650 {} -unsafe impl Send for Ns16650 {} +unsafe impl Sync for Ns16x50 {} +unsafe impl Send for Ns16x50 {} -impl PlatPeri for Ns16650 { - fn enable(&self) {} - - fn disable(&self) {} -} +impl PlatPeri for Ns16x50 {} diff --git a/kernel/src/boards/qemu_riscv32/config.rs b/kernel/src/boards/qemu_riscv32/config.rs index b45efa0b..037ad9f1 100644 --- a/kernel/src/boards/qemu_riscv32/config.rs +++ b/kernel/src/boards/qemu_riscv32/config.rs @@ -17,5 +17,5 @@ use crate::arch::irq::IrqNumber; pub const PLIC_BASE: usize = 0x0c00_0000; -pub const NS16550A_UART0_BASE: u32 = 0x1000_0000; -pub const NS16550A_UART0_IRQNUM: IrqNumber = IrqNumber::new(10); +pub const NS16550_UART0_BASE: u32 = 0x1000_0000; +pub const NS16550_UART0_IRQNUM: IrqNumber = IrqNumber::new(10); diff --git a/kernel/src/boards/qemu_riscv32/mod.rs b/kernel/src/boards/qemu_riscv32/mod.rs index a023e40c..b755b88b 100644 --- a/kernel/src/boards/qemu_riscv32/mod.rs +++ b/kernel/src/boards/qemu_riscv32/mod.rs @@ -67,21 +67,21 @@ pub(crate) fn init() { // Enable UART0 in PLIC. PLIC.enable( arch::current_cpu_id(), - u32::try_from(usize::from(config::NS16550A_UART0_IRQNUM)) + u32::try_from(usize::from(config::NS16550_UART0_IRQNUM)) .expect("usize(64 bits) converts to u32 failed"), ); // Set UART0 priority in PLIC. PLIC.set_priority( - u32::try_from(usize::from(config::NS16550A_UART0_IRQNUM)) + u32::try_from(usize::from(config::NS16550_UART0_IRQNUM)) .expect("usize(64 bits) converts to u32 failed"), 1, ); } crate::define_peripheral! { - (console_uart, blueos_driver::uart::ns16550a::Ns16550a<'static>, - blueos_driver::uart::ns16550a::Ns16550a::<'static>::new( - config::NS16550A_UART0_BASE as _, + (console_uart, blueos_driver::uart::ns16x50::Ns16x50, + blueos_driver::uart::ns16x50::Ns16x50::new( + config::NS16550_UART0_BASE as _, )), } diff --git a/kernel/src/boards/qemu_riscv64/config.rs b/kernel/src/boards/qemu_riscv64/config.rs index b45efa0b..037ad9f1 100644 --- a/kernel/src/boards/qemu_riscv64/config.rs +++ b/kernel/src/boards/qemu_riscv64/config.rs @@ -17,5 +17,5 @@ use crate::arch::irq::IrqNumber; pub const PLIC_BASE: usize = 0x0c00_0000; -pub const NS16550A_UART0_BASE: u32 = 0x1000_0000; -pub const NS16550A_UART0_IRQNUM: IrqNumber = IrqNumber::new(10); +pub const NS16550_UART0_BASE: u32 = 0x1000_0000; +pub const NS16550_UART0_IRQNUM: IrqNumber = IrqNumber::new(10); diff --git a/kernel/src/boards/qemu_riscv64/mod.rs b/kernel/src/boards/qemu_riscv64/mod.rs index a023e40c..b755b88b 100644 --- a/kernel/src/boards/qemu_riscv64/mod.rs +++ b/kernel/src/boards/qemu_riscv64/mod.rs @@ -67,21 +67,21 @@ pub(crate) fn init() { // Enable UART0 in PLIC. PLIC.enable( arch::current_cpu_id(), - u32::try_from(usize::from(config::NS16550A_UART0_IRQNUM)) + u32::try_from(usize::from(config::NS16550_UART0_IRQNUM)) .expect("usize(64 bits) converts to u32 failed"), ); // Set UART0 priority in PLIC. PLIC.set_priority( - u32::try_from(usize::from(config::NS16550A_UART0_IRQNUM)) + u32::try_from(usize::from(config::NS16550_UART0_IRQNUM)) .expect("usize(64 bits) converts to u32 failed"), 1, ); } crate::define_peripheral! { - (console_uart, blueos_driver::uart::ns16550a::Ns16550a<'static>, - blueos_driver::uart::ns16550a::Ns16550a::<'static>::new( - config::NS16550A_UART0_BASE as _, + (console_uart, blueos_driver::uart::ns16x50::Ns16x50, + blueos_driver::uart::ns16x50::Ns16x50::new( + config::NS16550_UART0_BASE as _, )), } diff --git a/kernel/src/boards/rk3568/mod.rs b/kernel/src/boards/rk3568/mod.rs index bda38345..209d3cce 100644 --- a/kernel/src/boards/rk3568/mod.rs +++ b/kernel/src/boards/rk3568/mod.rs @@ -38,8 +38,8 @@ pub(crate) fn init() { } crate::define_peripheral! { - (console_uart, blueos_driver::uart::ns16650::Ns16650, - blueos_driver::uart::ns16650::Ns16650::new( + (console_uart, blueos_driver::uart::ns16x50::Ns16x50, + blueos_driver::uart::ns16x50::Ns16x50::new( 0xFE660000, )), } From 82dbe76d6d764349b96b63f5a8918e956239710e Mon Sep 17 00:00:00 2001 From: YinhuaChen-cloud <229676342@qq.com> Date: Fri, 6 Mar 2026 18:35:49 +0800 Subject: [PATCH 2/2] fix compilation error --- driver/src/uart/ns16x50.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver/src/uart/ns16x50.rs b/driver/src/uart/ns16x50.rs index 11555102..0a64798b 100644 --- a/driver/src/uart/ns16x50.rs +++ b/driver/src/uart/ns16x50.rs @@ -24,7 +24,7 @@ use tock_registers::{ use crate::static_ref::StaticRef; -#[cfg(any(target_board = "qemu_riscv32", target_board = "qemu_riscv64"))] +#[cfg(not(target_board = "rk3568"))] // qemu virt platform uses NS16550 UART // NS16550 uses 8-bit registers, and the register offset is 1 byte. register_structs! { @@ -134,7 +134,7 @@ impl Has8bitDataReg for Ns16x50 { } fn write_data8(&self, data: u8) { - #[cfg(any(target_board = "qemu_riscv32", target_board = "qemu_riscv64"))] + #[cfg(not(target_board = "rk3568"))] self.registers.rbr.set(data as u8); #[cfg(target_board = "rk3568")] self.registers.rbr.set(data as u32);