sifive: initial support for hifive unleashed a00
This commit is contained in:
Generated
+17
@@ -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.
@@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod clock;
|
||||
mod uart;
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user