sifive: initial support for hifive unleashed a00

This commit is contained in:
2026-02-04 17:34:37 +02:00
parent 0e979a9e09
commit 4f648142c8
16 changed files with 934 additions and 15 deletions
Generated
+17
View File
@@ -2723,6 +2723,22 @@ dependencies = [
"yggdrasil-abi",
]
[[package]]
name = "ygg_driver_bsp_sifive"
version = "0.1.0"
dependencies = [
"bytemuck",
"device-api",
"device-tree",
"futures-util",
"libk",
"libk-mm",
"libk-util",
"log",
"tock-registers",
"yggdrasil-abi",
]
[[package]]
name = "ygg_driver_fat32"
version = "0.1.0"
@@ -3053,6 +3069,7 @@ dependencies = [
"ygg_driver_bsp_bcm283x",
"ygg_driver_bsp_jh7110",
"ygg_driver_bsp_riscv",
"ygg_driver_bsp_sifive",
"ygg_driver_fat32",
"ygg_driver_input",
"ygg_driver_net_core",
@@ -0,0 +1,248 @@
/dts-v1/;
/ {
#address-cells = <0x02>;
#size-cells = <0x02>;
compatible = "sifive,hifive-unleashed-a00";
model = "SiFive HiFive Unleashed A00";
chosen {
linux,initrd-end = <0x00 0x87688400>;
linux,initrd-start = <0x00 0x84200000>;
stdout-path = "/soc/serial@10010000";
};
aliases {
serial0 = "/soc/serial@10010000";
serial1 = "/soc/serial@10011000";
ethernet0 = "/soc/ethernet@10090000";
};
gpio-restart {
compatible = "gpio-restart";
gpios = <0x07 0x0a 0x01>;
};
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
timebase-frequency = <0xf4240>;
cpu0: cpu@0 {
device_type = "cpu";
reg = <0x00>;
status = "okay";
compatible = "riscv";
riscv,isa-extensions = "i", "m", "a", "c", "zicntr", "zicsr", "zifencei", "zihpm", "sdtrig";
riscv,isa-base = "rv64i";
riscv,isa = "rv64imac_zicntr_zicsr_zifencei_zihpm_sdtrig";
cpu0_intc: interrupt-controller {
#interrupt-cells = <0x01>;
interrupt-controller;
compatible = "riscv,cpu-intc";
phandle = <0x04>;
};
};
cpu1: cpu@1 {
device_type = "cpu";
reg = <0x01>;
status = "okay";
compatible = "riscv";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", "zifencei", "zihpm", "sdtrig";
riscv,isa-base = "rv64i";
riscv,isa = "rv64imafdc_zicntr_zicsr_zifencei_zihpm_sdtrig";
mmu-type = "riscv,sv39";
cpu1_intc: interrupt-controller {
#interrupt-cells = <0x01>;
interrupt-controller;
compatible = "riscv,cpu-intc";
phandle = <0x03>;
};
};
};
memory@80000000 {
device_type = "memory";
reg = <0x00 0x80000000 0x00 0x8000000>;
};
rtcclk: rtcclk {
#clock-cells = <0x00>;
compatible = "fixed-clock";
clock-frequency = <0xf4240>;
clock-output-names = "rtcclk";
phandle = <0x02>;
};
hfclk: hfclk {
#clock-cells = <0x00>;
compatible = "fixed-clock";
clock-frequency = <0x1fca055>;
clock-output-names = "hfclk";
phandle = <0x01>;
};
soc {
#address-cells = <0x02>;
#size-cells = <0x02>;
compatible = "simple-bus";
ranges;
uart0: serial@10010000 {
interrupts = <0x04>;
interrupt-parent = <&plic>;
clocks = <&prci 0x03>;
reg = <0x00 0x10010000 0x00 0x1000>;
compatible = "sifive,uart0";
};
uart1: serial@10011000 {
interrupts = <0x05>;
interrupt-parent = <&plic>;
clocks = <&prci 0x03>;
reg = <0x00 0x10011000 0x00 0x1000>;
compatible = "sifive,uart0";
};
// pwm@10021000 {
// #pwm-cells = <0x00>;
// clocks = <0x05 0x03>;
// interrupts = <0x2e 0x2f 0x30 0x31>;
// interrupt-parent = <0x06>;
// reg = <0x00 0x10021000 0x00 0x1000>;
// compatible = "sifive,pwm0";
// };
// pwm@10020000 {
// #pwm-cells = <0x00>;
// clocks = <0x05 0x03>;
// interrupts = <0x2a 0x2b 0x2c 0x2d>;
// interrupt-parent = <0x06>;
// reg = <0x00 0x10020000 0x00 0x1000>;
// compatible = "sifive,pwm0";
// };
// ethernet@10090000 {
// #size-cells = <0x00>;
// #address-cells = <0x01>;
// local-mac-address = [52 54 00 12 34 56];
// clock-names = "pclk", "hclk";
// clocks = <0x05 0x02 0x05 0x02>;
// interrupts = <0x35>;
// interrupt-parent = <0x06>;
// phy-handle = <0x08>;
// phy-mode = "gmii";
// reg-names = "control";
// reg = <0x00 0x10090000 0x00 0x2000 0x00 0x100a0000 0x00 0x1000>;
// compatible = "sifive,fu540-c000-gem";
// ethernet-phy@0 {
// reg = <0x00>;
// phandle = <0x08>;
// };
// };
// spi@10040000 {
// compatible = "sifive,spi0";
// reg = <0x00 0x10040000 0x00 0x1000>;
// interrupt-parent = <0x06>;
// interrupts = <0x33>;
// clocks = <0x05 0x03>;
// #address-cells = <0x01>;
// #size-cells = <0x00>;
// flash@0 {
// compatible = "jedec,spi-nor";
// reg = <0x00>;
// spi-max-frequency = <0x2faf080>;
// m25p,fast-read;
// spi-tx-bus-width = <0x04>;
// spi-rx-bus-width = <0x04>;
// };
// };
// spi@10050000 {
// compatible = "sifive,spi0";
// reg = <0x00 0x10050000 0x00 0x1000>;
// interrupt-parent = <0x06>;
// interrupts = <0x06>;
// clocks = <0x05 0x03>;
// #address-cells = <0x01>;
// #size-cells = <0x00>;
// mmc@0 {
// compatible = "mmc-spi-slot";
// reg = <0x00>;
// spi-max-frequency = <0x1312d00>;
// voltage-ranges = <0xce4 0xce4>;
// disable-wp;
// };
// };
// cache-controller@2010000 {
// compatible = "sifive,fu540-c000-ccache";
// cache-block-size = <0x40>;
// cache-level = <0x02>;
// cache-sets = <0x400>;
// cache-size = <0x200000>;
// cache-unified;
// interrupt-parent = <0x06>;
// interrupts = <0x01 0x02 0x03>;
// reg = <0x00 0x2010000 0x00 0x1000>;
// };
// dma@3000000 {
// compatible = "sifive,fu540-c000-pdma";
// reg = <0x00 0x3000000 0x00 0x100000>;
// interrupt-parent = <0x06>;
// interrupts = <0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e>;
// #dma-cells = <0x01>;
// };
gpio: gpio@10060000 {
compatible = "sifive,gpio0";
interrupt-parent = <&plic>;
interrupts = <0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15 0x16>;
reg = <0x00 0x10060000 0x00 0x1000>;
gpio-controller;
#gpio-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x02>;
clocks = <0x05 0x03>;
phandle = <0x07>;
};
plic: interrupt-controller@c000000 {
phandle = <0x06>;
riscv,ndev = <0x35>;
reg = <0x00 0xc000000 0x00 0x4000000>;
interrupts-extended = <0x04 0x0b 0x03 0x0b 0x03 0x09>;
interrupt-controller;
compatible = "sifive,plic-1.0.0", "riscv,plic0";
#interrupt-cells = <0x01>;
};
prci: clock-controller@10000000 {
compatible = "sifive,fu540-c000-prci";
reg = <0x00 0x10000000 0x00 0x1000>;
clocks = <&hfclk>, <&rtcclk>;
#clock-cells = <0x01>;
phandle = <0x05>;
};
// otp@10070000 {
// compatible = "sifive,fu540-c000-otp";
// reg = <0x00 0x10070000 0x00 0x1000>;
// fuse-count = <0x1000>;
// };
clint: clint@2000000 {
interrupts-extended = <0x04 0x03 0x04 0x07 0x03 0x03 0x03 0x07>;
reg = <0x00 0x2000000 0x00 0x10000>;
compatible = "sifive,clint0", "riscv,clint0";
};
};
};
Binary file not shown.
+248
View File
@@ -0,0 +1,248 @@
/dts-v1/;
/ {
#address-cells = <0x02>;
#size-cells = <0x02>;
compatible = "sifive,hifive-unleashed-a00";
model = "SiFive HiFive Unleashed A00";
chosen {
linux,initrd-end = <0x00 0x87688400>;
linux,initrd-start = <0x00 0x84200000>;
stdout-path = "/soc/serial@10010000";
};
aliases {
serial0 = "/soc/serial@10010000";
serial1 = "/soc/serial@10011000";
ethernet0 = "/soc/ethernet@10090000";
};
gpio-restart {
compatible = "gpio-restart";
gpios = <0x07 0x0a 0x01>;
};
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
timebase-frequency = <0xf4240>;
cpu@0 {
device_type = "cpu";
reg = <0x00>;
status = "okay";
compatible = "riscv";
riscv,isa-extensions = "i", "m", "a", "c", "zicntr", "zicsr", "zifencei", "zihpm", "sdtrig";
riscv,isa-base = "rv64i";
riscv,isa = "rv64imac_zicntr_zicsr_zifencei_zihpm_sdtrig";
interrupt-controller {
#interrupt-cells = <0x01>;
interrupt-controller;
compatible = "riscv,cpu-intc";
phandle = <0x04>;
};
};
cpu@1 {
device_type = "cpu";
reg = <0x01>;
status = "okay";
compatible = "riscv";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", "zifencei", "zihpm", "sdtrig";
riscv,isa-base = "rv64i";
riscv,isa = "rv64imafdc_zicntr_zicsr_zifencei_zihpm_sdtrig";
mmu-type = "riscv,sv39";
interrupt-controller {
#interrupt-cells = <0x01>;
interrupt-controller;
compatible = "riscv,cpu-intc";
phandle = <0x03>;
};
};
};
memory@80000000 {
device_type = "memory";
reg = <0x00 0x80000000 0x00 0x8000000>;
};
rtcclk {
#clock-cells = <0x00>;
compatible = "fixed-clock";
clock-frequency = <0xf4240>;
clock-output-names = "rtcclk";
phandle = <0x02>;
};
hfclk {
#clock-cells = <0x00>;
compatible = "fixed-clock";
clock-frequency = <0x1fca055>;
clock-output-names = "hfclk";
phandle = <0x01>;
};
soc {
#address-cells = <0x02>;
#size-cells = <0x02>;
compatible = "simple-bus";
ranges;
serial@10010000 {
interrupts = <0x04>;
interrupt-parent = <0x06>;
clocks = <0x05 0x03>;
reg = <0x00 0x10010000 0x00 0x1000>;
compatible = "sifive,uart0";
};
serial@10011000 {
interrupts = <0x05>;
interrupt-parent = <0x06>;
clocks = <0x05 0x03>;
reg = <0x00 0x10011000 0x00 0x1000>;
compatible = "sifive,uart0";
};
pwm@10021000 {
#pwm-cells = <0x00>;
clocks = <0x05 0x03>;
interrupts = <0x2e 0x2f 0x30 0x31>;
interrupt-parent = <0x06>;
reg = <0x00 0x10021000 0x00 0x1000>;
compatible = "sifive,pwm0";
};
pwm@10020000 {
#pwm-cells = <0x00>;
clocks = <0x05 0x03>;
interrupts = <0x2a 0x2b 0x2c 0x2d>;
interrupt-parent = <0x06>;
reg = <0x00 0x10020000 0x00 0x1000>;
compatible = "sifive,pwm0";
};
ethernet@10090000 {
#size-cells = <0x00>;
#address-cells = <0x01>;
local-mac-address = [52 54 00 12 34 56];
clock-names = "pclk", "hclk";
clocks = <0x05 0x02 0x05 0x02>;
interrupts = <0x35>;
interrupt-parent = <0x06>;
phy-handle = <0x08>;
phy-mode = "gmii";
reg-names = "control";
reg = <0x00 0x10090000 0x00 0x2000 0x00 0x100a0000 0x00 0x1000>;
compatible = "sifive,fu540-c000-gem";
ethernet-phy@0 {
reg = <0x00>;
phandle = <0x08>;
};
};
spi@10040000 {
compatible = "sifive,spi0";
reg = <0x00 0x10040000 0x00 0x1000>;
interrupt-parent = <0x06>;
interrupts = <0x33>;
clocks = <0x05 0x03>;
#address-cells = <0x01>;
#size-cells = <0x00>;
flash@0 {
compatible = "jedec,spi-nor";
reg = <0x00>;
spi-max-frequency = <0x2faf080>;
m25p,fast-read;
spi-tx-bus-width = <0x04>;
spi-rx-bus-width = <0x04>;
};
};
spi@10050000 {
compatible = "sifive,spi0";
reg = <0x00 0x10050000 0x00 0x1000>;
interrupt-parent = <0x06>;
interrupts = <0x06>;
clocks = <0x05 0x03>;
#address-cells = <0x01>;
#size-cells = <0x00>;
mmc@0 {
compatible = "mmc-spi-slot";
reg = <0x00>;
spi-max-frequency = <0x1312d00>;
voltage-ranges = <0xce4 0xce4>;
disable-wp;
};
};
cache-controller@2010000 {
compatible = "sifive,fu540-c000-ccache";
cache-block-size = <0x40>;
cache-level = <0x02>;
cache-sets = <0x400>;
cache-size = <0x200000>;
cache-unified;
interrupt-parent = <0x06>;
interrupts = <0x01 0x02 0x03>;
reg = <0x00 0x2010000 0x00 0x1000>;
};
dma@3000000 {
compatible = "sifive,fu540-c000-pdma";
reg = <0x00 0x3000000 0x00 0x100000>;
interrupt-parent = <0x06>;
interrupts = <0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e>;
#dma-cells = <0x01>;
};
gpio@10060000 {
compatible = "sifive,gpio0";
interrupt-parent = <0x06>;
interrupts = <0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15 0x16>;
reg = <0x00 0x10060000 0x00 0x1000>;
gpio-controller;
#gpio-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x02>;
clocks = <0x05 0x03>;
phandle = <0x07>;
};
interrupt-controller@c000000 {
phandle = <0x06>;
riscv,ndev = <0x35>;
reg = <0x00 0xc000000 0x00 0x4000000>;
interrupts-extended = <0x04 0x0b 0x03 0x0b 0x03 0x09>;
interrupt-controller;
compatible = "sifive,plic-1.0.0", "riscv,plic0";
#interrupt-cells = <0x01>;
};
clock-controller@10000000 {
compatible = "sifive,fu540-c000-prci";
reg = <0x00 0x10000000 0x00 0x1000>;
clocks = <0x01 0x02>;
#clock-cells = <0x01>;
phandle = <0x05>;
};
otp@10070000 {
compatible = "sifive,fu540-c000-otp";
reg = <0x00 0x10070000 0x00 0x1000>;
fuse-count = <0x1000>;
};
clint@2000000 {
interrupts-extended = <0x04 0x03 0x04 0x07 0x03 0x03 0x03 0x07>;
reg = <0x00 0x2000000 0x00 0x10000>;
compatible = "sifive,clint0", "riscv,clint0";
};
};
};
+1
View File
@@ -67,6 +67,7 @@ ygg_driver_bsp_arm.path = "driver/bsp/arm" # PrimeCell components
ygg_driver_bsp_riscv.path = "driver/bsp/riscv"
ygg_driver_net_stmmac.path = "driver/net/stmmac"
ygg_driver_bsp_jh7110.path = "driver/bsp/jh7110"
ygg_driver_bsp_sifive.path = "driver/bsp/sifive"
[target.'cfg(target_arch = "x86_64")'.dependencies]
yboot-proto.workspace = true
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "ygg_driver_bsp_sifive"
version = "0.1.0"
edition = "2024"
[dependencies]
device-tree.workspace = true
device-api.workspace = true
yggdrasil-abi.workspace = true
libk-mm.workspace = true
libk-util.workspace = true
libk.workspace = true
tock-registers.workspace = true
log.workspace = true
bytemuck.workspace = true
futures-util.workspace = true
+121
View File
@@ -0,0 +1,121 @@
use alloc::sync::Arc;
use device_api::{
clock::{ClockController, ClockHandle, Hertz},
device::Device,
};
use device_tree::{
DeviceTreePropertyRead, TProp,
driver::{DeviceTreeClockController, Node, ProbeContext, device_tree_driver},
};
use libk::error::Error;
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{interfaces::Readable, register_structs, registers::ReadWrite};
const CLK_COREPLL: u32 = 0;
const CLK_DDRPLL: u32 = 1;
const CLK_GEMGXLPLL: u32 = 2;
const CLK_TLCLK: u32 = 3;
register_structs! {
Regs {
(0x000 => hfxosccfg: ReadWrite<u32>),
(0x004 => corepllcfg0: ReadWrite<u32>),
(0x008 => _0),
(0x00C => ddrpllcfg0: ReadWrite<u32>),
(0x010 => ddrpllcfg1: ReadWrite<u32>),
(0x014 => _1),
(0x01C => gemgxlpllcfg0: ReadWrite<u32>),
(0x020 => gemgxlpllcfg1: ReadWrite<u32>),
(0x024 => coreclksel: ReadWrite<u32>),
(0x028 => deviceresetreg: ReadWrite<u32>),
(0x02C => _2),
(0x100 => @END),
}
}
struct Prci {
clk_osc: ClockHandle,
clk_rtc: ClockHandle,
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
}
impl Device for Prci {
fn display_name(&self) -> &str {
"sifive,fu540-c000-prci"
}
}
impl ClockController for Prci {
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
let _ = &self.clk_rtc;
let regs = self.regs.lock();
match clock {
Some(CLK_TLCLK) => {
// 0 = CORE_PLL
// 1 = HFCLK
let coreclksel = regs.coreclksel.get() & 1 != 0;
let glcm = if coreclksel {
self.clk_osc.rate()?
} else {
todo!()
};
Ok(glcm / 2)
}
Some(_) => todo!(),
None => Err(Error::InvalidArgument),
}
}
fn set_clock_rate(&self, _clock: Option<u32>, _rate: Hertz) -> Result<Hertz, Error> {
Err(Error::NotImplemented)
}
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
match clock {
Some(CLK_GEMGXLPLL) | Some(CLK_DDRPLL) | Some(CLK_COREPLL) => todo!(),
Some(CLK_TLCLK) => Ok(()),
_ => Err(Error::InvalidArgument),
}
}
fn disable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
Err(Error::NotImplemented)
}
}
impl DeviceTreeClockController for Prci {
fn map_clock(self: Arc<Self>, property: &TProp, offset: usize) -> Option<(ClockHandle, usize)> {
let clock = property.read_cell(offset, 1)? as u32;
Some((
ClockHandle {
parent: self.clone(),
clock: Some(clock),
},
1,
))
}
}
device_tree_driver! {
compatible: ["sifive,fu540-c000-prci"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let clk_osc = node.clock(0)?;
let clk_rtc = node.clock(1)?;
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
let prci = Arc::new(Prci {
regs: IrqSafeSpinlock::new(regs),
clk_osc,
clk_rtc
});
node.make_clock_controller(prci.clone());
Some(prci)
}
}
}
+6
View File
@@ -0,0 +1,6 @@
#![no_std]
extern crate alloc;
mod clock;
mod uart;
+228
View File
@@ -0,0 +1,228 @@
use alloc::sync::Arc;
use device_api::{
clock::{ClockHandle, Hertz},
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use libk::{
debug::{self, DebugSink},
device::manager::DEVICE_REGISTRY,
error::Error,
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
use yggdrasil_abi::io::{TerminalOptions, TerminalOutputOptions};
register_bitfields! {
u32,
txctrl [
txen OFFSET(0) NUMBITS(1) [],
nstop OFFSET(1) NUMBITS(1) [
One = 0,
Two = 1
],
txcnt OFFSET(16) NUMBITS(3) [],
],
rxctrl [
rxen OFFSET(0) NUMBITS(1) [],
rxcnt OFFSET(16) NUMBITS(3) [],
],
interrupt [
txwm OFFSET(0) NUMBITS(1) [],
rxwm OFFSET(1) NUMBITS(1) [],
],
}
register_structs! {
Regs {
(0x00 => txdata: WriteOnly<u32>),
(0x04 => rxdata: ReadOnly<u32>),
(0x08 => txctrl: ReadWrite<u32, txctrl::Register>),
(0x0C => rxctrl: ReadWrite<u32, rxctrl::Register>),
(0x10 => ie: ReadWrite<u32, interrupt::Register>),
(0x14 => ip: ReadOnly<u32, interrupt::Register>),
(0x18 => div: ReadWrite<u32>),
(0x1C => _0),
(0x20 => @END),
}
}
struct Inner {
clock: ClockHandle,
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
}
struct Uart {
name: &'static str,
irq: IrqHandle,
clock: ClockHandle,
base: PhysicalAddress,
inner: OneTimeInit<Arc<Terminal<Inner>>>,
}
impl Regs {
fn set_baud_rate(&self, input_clk: Hertz, baud: u32) -> Result<(), Error> {
let div = Hertz::divider(input_clk, Hertz::from(baud)).ok_or(Error::InvalidArgument)?;
if div >= (1 << 20) || div == 0 {
return Err(Error::InvalidArgument);
}
let div = div - 1;
self.div.set(div);
Ok(())
}
fn baud_rate(&self, input_clk: Hertz) -> u32 {
let div = self.div.get() + 1;
(input_clk / div).0 as u32
}
fn write(&self, byte: u8) {
while !self.ip.matches_all(interrupt::txwm::SET) {
core::hint::spin_loop();
}
self.txdata.set(byte as u32);
}
}
impl Device for Uart {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
let regs = unsafe { DeviceMemoryIo::<Regs>::map(self.base, Default::default()) }?;
self.clock.enable()?;
let input_clk = self.clock.rate()?;
{
let _guard = debug::MuteGuard::acquire();
regs.txctrl.write(txctrl::txen::CLEAR);
regs.rxctrl.write(rxctrl::rxen::CLEAR);
regs.set_baud_rate(input_clk, 115200)?;
regs.txctrl.write(txctrl::txen::SET + txctrl::txcnt.val(3));
regs.rxctrl.write(rxctrl::rxen::SET + rxctrl::rxcnt.val(0));
}
let input = TerminalInput::with_capacity(64)?;
let output = Inner {
regs: IrqSafeSpinlock::new(regs),
clock: self.clock.clone(),
};
let terminal = self.inner.init(Arc::new(Terminal::from_parts(
TerminalOptions::const_default(),
input,
output,
)));
DEVICE_REGISTRY
.serial_terminal
.register(terminal.clone(), Some(self.clone()))
.ok();
Ok(())
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
let regs = self.inner.get().output().regs.lock();
regs.ie.write(interrupt::rxwm::SET);
Ok(())
}
fn display_name(&self) -> &str {
self.name
}
}
impl InterruptHandler for Uart {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let terminal = self.inner.get();
let byte = {
let regs = terminal.output().regs.lock();
if regs.ip.matches_all(interrupt::rxwm::SET) {
regs.rxdata.get() as u8
} else {
return false;
}
};
terminal.write_to_input(byte);
true
}
}
impl DebugSink for Uart {
fn putc(&self, c: u8) -> Result<(), Error> {
self.inner.get().putc_to_output(c)
}
fn puts(&self, s: &str) -> Result<(), Error> {
self.inner.get().write_to_output(s.as_bytes())?;
Ok(())
}
fn supports_control_sequences(&self) -> bool {
true
}
}
impl TerminalOutput for Inner {
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error> {
let regs = self.regs.lock();
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
regs.write(b'\r');
}
regs.write(byte);
Ok(())
}
fn write_multiple(
&self,
bytes: &[u8],
options: &TerminalOutputOptions,
) -> Result<usize, Error> {
let regs = self.regs.lock();
for &byte in bytes {
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
regs.write(b'\r');
}
regs.write(byte);
}
Ok(bytes.len())
}
fn baud_rate(&self) -> u32 {
let input_clk = self.clock.rate().unwrap();
self.regs.lock().baud_rate(input_clk)
}
fn set_baud_rate(&self, baud: u32) -> Result<(), Error> {
let input_clk = self.clock.rate().unwrap();
self.regs.lock().set_baud_rate(input_clk, baud)
}
}
device_tree_driver! {
compatible: ["sifive,uart0"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let name = node.name().unwrap_or("uart");
let base = node.map_base(context, 0)?;
let clock = node.clock(0)?;
let irq = node.interrupt(0)?;
let uart = Arc::new(Uart {
name,
irq,
clock,
base,
inner: OneTimeInit::new()
});
Some(uart)
}
}
}
+2
View File
@@ -7,11 +7,13 @@ pub use freq::{Hertz, IntoHertz};
mod freq;
#[derive(Clone)]
pub struct ClockHandle {
pub parent: Arc<dyn ClockController>,
pub clock: Option<u32>,
}
#[derive(Clone)]
pub struct ResetHandle {
pub parent: Arc<dyn ResetController>,
pub reset: Option<u32>,
+10 -2
View File
@@ -132,7 +132,10 @@ impl PhysicalMemoryManager {
/// Allocates a contiguous range of physical pages, marking it as used with `usage`
pub fn alloc_contiguous_pages(&mut self, count: usize) -> Result<PhysicalAddress, Error> {
'l0: for i in self.last_free_bit..self.page_count {
if count >= self.page_count {
return Err(Error::OutOfMemory);
}
'l0: for i in self.last_free_bit..self.page_count - count {
for j in 0..count {
if self.is_alloc(i + j) {
continue 'l0;
@@ -164,8 +167,13 @@ impl PhysicalMemoryManager {
/// `addr` must be a page-aligned physical address previously allocated by this implementation.
pub unsafe fn free_page(&mut self, page: PhysicalAddress) {
let page = page.try_into_usize().unwrap();
assert!(page >= self.offset);
if page < self.offset {
panic!("Physical page below managed area: {page:#x}");
}
let index = (page - self.offset) / L3_PAGE_SIZE;
if index >= self.page_count {
panic!("Physical page above managed area: {page:#x}");
}
STATS.used_pages.fetch_sub(1, Ordering::Relaxed);
+4
View File
@@ -204,6 +204,10 @@ pub unsafe fn init_from_iter<I: Iterator<Item = PhysicalMemoryRegion> + Clone>(
ArchitectureImpl::halt();
}
/*
000000:?:libk_mm::phys:207: page_bitmap_phys_base=0x80060000
000000:?:libk_mm::phys:208: total_count=32768
*/
let mut manager = PhysicalMemoryManager::new(
page_bitmap_phys_base,
phys_start
+1
View File
@@ -80,6 +80,7 @@ cfg_if::cfg_if! {
} else if #[cfg(target_arch = "riscv64")] {
extern crate ygg_driver_bsp_riscv;
extern crate ygg_driver_bsp_jh7110;
extern crate ygg_driver_bsp_sifive;
extern crate ygg_driver_net_stmmac;
}
+7 -3
View File
@@ -10,6 +10,7 @@ pub enum Cpu {
#[derive(Debug)]
pub enum Machine {
Virt,
SiFiveU,
}
#[derive(Debug)]
@@ -18,7 +19,7 @@ pub struct QemuRiscv64;
#[derive(Debug)]
pub enum Image {
OpenSBI {
bios: PathBuf,
bios: Option<PathBuf>,
kernel: PathBuf,
initrd: PathBuf,
},
@@ -29,6 +30,7 @@ impl IntoArgs for Machine {
command.arg("-M");
match self {
Self::Virt => command.arg("virt"),
Self::SiFiveU => command.arg("sifive_u"),
};
}
}
@@ -54,8 +56,10 @@ impl IntoArgs for Image {
command.arg(kernel);
command.arg("-initrd");
command.arg(initrd);
command.arg("-bios");
command.arg(bios);
if let Some(bios) = bios {
command.arg("-bios");
command.arg(bios);
}
}
}
}
+2 -1
View File
@@ -80,7 +80,7 @@ pub enum Board {
raspi4b,
// RISC-V boards
jh7110,
sifive_u,
}
#[derive(Debug)]
@@ -228,6 +228,7 @@ impl Board {
pub fn device_tree(&self) -> Option<&str> {
match self {
Self::raspi4b => Some("aarch64/bcm2711-rpi-4-b"),
Self::sifive_u => Some("riscv64/sifive-hifive-unleashed-a00"),
_ => None,
}
}
+22 -9
View File
@@ -236,16 +236,29 @@ fn run_riscv64(
qemu.override_qemu(qemu_bin);
}
let bios = env.workspace_root.join("boot/riscv/fw_jump.bin");
match env.board {
Board::sifive_u => qemu
.with_machine(riscv64::Machine::SiFiveU)
.with_boot_image(riscv64::Image::OpenSBI {
kernel,
initrd,
bios: None,
}),
Board::virt | Board::default => qemu
.with_machine(riscv64::Machine::Virt)
.with_boot_image(riscv64::Image::OpenSBI {
kernel,
initrd,
bios: Some(bios),
})
.with_memory_megabytes(1024)
.with_cpu(riscv64::Cpu::Rv64),
e => return Err(Error::UnsupportedEmulation(e)),
};
qemu.with_serial(QemuSerialTarget::MonStdio)
.with_machine(riscv64::Machine::Virt)
.with_cpu(riscv64::Cpu::Rv64)
.with_memory_megabytes(1024)
.disable_display()
.with_boot_image(riscv64::Image::OpenSBI {
kernel,
initrd,
bios,
});
.disable_display();
for device in devices {
qemu.with_device(device);