riscv: initial support for hifive unmatched
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
Booting Yggdrasil OS on SiFive HiFive Unmatched Rev B RISC-V board:
|
||||||
|
|
||||||
|
* TODO: proper format for initrd image
|
||||||
|
|
||||||
|
Prerequisites:
|
||||||
|
|
||||||
|
* OpenSBI + u-boot (can use the u-boot from the Freedom U SDK that comes with the board)
|
||||||
|
* yggdrasil-kernel.bin
|
||||||
|
* initrd.img
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
|
||||||
|
1. Copy yggdrasil-kernel.bin and initrd.img into some directory and start a TFTP server there
|
||||||
|
2. Connect to HFU's serial port, ethernet and enter u-boot
|
||||||
|
3. Run the following commands in u-boot:
|
||||||
|
|
||||||
|
### If using DHCP
|
||||||
|
|
||||||
|
=> setenv autoload no
|
||||||
|
=> setenv initrd_addr_r 0x90000000
|
||||||
|
=> dhcp
|
||||||
|
=> tftpboot ${initrd_addr_r} <SERVER IP>:initrd.img
|
||||||
|
=> tftpboot ${loadaddr} <SERVER IP>:yggdrasil-kernel.bin
|
||||||
|
=> tftpboot ${fdt_addr_r} <SERVER IP>:hifive-unmatched-a00.dtb
|
||||||
|
=> fdt resize
|
||||||
|
=> booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
|
||||||
|
|
||||||
|
Two-liner (server is 13.0.0.1, board is 13.0.0.2):
|
||||||
|
|
||||||
|
setenv ipaddr 13.0.0.2;setenv initrd_addr_r 0x90000000;tftpboot ${initrd_addr_r} 13.0.0.1:initrd.img;tftpboot ${loadaddr} 13.0.0.1:yggdrasil-kernel.bin;tftpboot ${fdt_addr_r} 13.0.0.1:hifive-unmatched-a00.dtb;fdt resize
|
||||||
|
booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
|
||||||
|
|
||||||
|
One-liner without initrd
|
||||||
|
|
||||||
|
setenv ipaddr 13.0.0.2;tftpboot ${loadaddr} 13.0.0.1:yggdrasil-kernel.bin;tftpboot ${fdt_addr_r} 13.0.0.1:hifive-unmatched-a00.dtb;fdt resize;booti ${loadaddr} - ${fdt_addr_r}
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
#define CLK_COREPLL 0
|
||||||
|
#define CLK_DDRPLL 1
|
||||||
|
#define CLK_GEMGXLPLL 2
|
||||||
|
#define CLK_DVFSCOREPLL 3
|
||||||
|
#define CLK_HFPCLKPLL 4
|
||||||
|
#define CLK_CLTXPLL 5
|
||||||
|
#define CLK_TLCLK 6
|
||||||
|
#define CLK_PCLK 7
|
||||||
|
#define CLK_PCIE_AUX 8
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
compatible = "sifive,hifive-unmatched-a00", "sifive,fu740-c000", "sifive,fu740";
|
||||||
|
model = "SiFive HiFive Unmatched";
|
||||||
|
|
||||||
|
aliases {
|
||||||
|
serial0 = "/soc/serial@10010000";
|
||||||
|
serial1 = "/soc/serial@10011000";
|
||||||
|
};
|
||||||
|
|
||||||
|
chosen {
|
||||||
|
stdout-path = "serial0";
|
||||||
|
};
|
||||||
|
|
||||||
|
cpus {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
timebase-frequency = <1000000>;
|
||||||
|
|
||||||
|
cpu0: cpu@0 {
|
||||||
|
compatible = "sifive,bullet0", "riscv";
|
||||||
|
device_type = "cpu";
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
i-cache-sets = <128>;
|
||||||
|
i-cache-size = <16384>;
|
||||||
|
next-level-cache = <&ccache>;
|
||||||
|
reg = <0>;
|
||||||
|
riscv,isa = "rv64imac";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
cpu0_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu1: cpu@1 {
|
||||||
|
compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
|
||||||
|
device_type = "cpu";
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
d-cache-sets = <64>;
|
||||||
|
d-cache-size = <32768>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
i-cache-sets = <128>;
|
||||||
|
i-cache-size = <32768>;
|
||||||
|
i-tlb-sets = <1>;
|
||||||
|
i-tlb-size = <40>;
|
||||||
|
d-tlb-sets = <1>;
|
||||||
|
d-tlb-size = <40>;
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
next-level-cache = <&ccache>;
|
||||||
|
reg = <1>;
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
tlb-split;
|
||||||
|
|
||||||
|
cpu1_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu2: cpu@2 {
|
||||||
|
compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
|
||||||
|
device_type = "cpu";
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
d-cache-sets = <64>;
|
||||||
|
d-cache-size = <32768>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
i-cache-sets = <128>;
|
||||||
|
i-cache-size = <32768>;
|
||||||
|
d-tlb-sets = <1>;
|
||||||
|
d-tlb-size = <40>;
|
||||||
|
i-tlb-sets = <1>;
|
||||||
|
i-tlb-size = <40>;
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
next-level-cache = <&ccache>;
|
||||||
|
reg = <2>;
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
tlb-split;
|
||||||
|
|
||||||
|
cpu2_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu3: cpu@3 {
|
||||||
|
compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
|
||||||
|
device_type = "cpu";
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
d-cache-sets = <64>;
|
||||||
|
d-cache-size = <32768>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
i-cache-sets = <128>;
|
||||||
|
i-cache-size = <32768>;
|
||||||
|
d-tlb-sets = <1>;
|
||||||
|
d-tlb-size = <40>;
|
||||||
|
i-tlb-sets = <1>;
|
||||||
|
i-tlb-size = <40>;
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
next-level-cache = <&ccache>;
|
||||||
|
reg = <3>;
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
tlb-split;
|
||||||
|
|
||||||
|
cpu3_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu4: cpu@4 {
|
||||||
|
compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
|
||||||
|
device_type = "cpu";
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
d-cache-sets = <64>;
|
||||||
|
d-cache-size = <32768>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
i-cache-sets = <128>;
|
||||||
|
i-cache-size = <32768>;
|
||||||
|
d-tlb-sets = <1>;
|
||||||
|
d-tlb-size = <40>;
|
||||||
|
i-tlb-sets = <1>;
|
||||||
|
i-tlb-size = <40>;
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
next-level-cache = <&ccache>;
|
||||||
|
reg = <4>;
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
tlb-split;
|
||||||
|
|
||||||
|
cpu4_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
soc {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
compatible = "simple-bus";
|
||||||
|
ranges;
|
||||||
|
|
||||||
|
plic: interrupt-controller@c000000 {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
#address-cells = <0>;
|
||||||
|
compatible = "sifive,fu540-c000-plic", "sifive,plic-1.0.0";
|
||||||
|
reg = <0x00 0xc000000 0x00 0x4000000>;
|
||||||
|
riscv,ndev = <69>;
|
||||||
|
interrupt-controller;
|
||||||
|
interrupts-extended = <&cpu0_intc 0xffffffff>,
|
||||||
|
<&cpu1_intc 0xffffffff>,
|
||||||
|
<&cpu1_intc 0x09>,
|
||||||
|
<&cpu2_intc 0xffffffff>,
|
||||||
|
<&cpu2_intc 0x09>,
|
||||||
|
<&cpu3_intc 0xffffffff>,
|
||||||
|
<&cpu3_intc 0x09>,
|
||||||
|
<&cpu4_intc 0xffffffff>,
|
||||||
|
<&cpu4_intc 0x09>;
|
||||||
|
};
|
||||||
|
|
||||||
|
prci: clock-controller@10000000 {
|
||||||
|
compatible = "sifive,fu740-c000-prci";
|
||||||
|
reg = <0x00 0x10000000 0x00 0x1000>;
|
||||||
|
clocks = <&clk_hfclk>, <&clk_rtcclk>;
|
||||||
|
#clock-cells = <1>;
|
||||||
|
#reset-cells = <1>;
|
||||||
|
};
|
||||||
|
|
||||||
|
uart0: serial@10010000 {
|
||||||
|
compatible = "sifive,fu740-c000-uart", "sifive,uart0";
|
||||||
|
reg = <0x00 0x10010000 0x00 0x1000>;
|
||||||
|
interrupt-parent = <&plic>;
|
||||||
|
interrupts = <39>;
|
||||||
|
clocks = <&prci CLK_PCLK>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
uart1: serial@10011000 {
|
||||||
|
compatible = "sifive,fu740-c000-uart", "sifive,uart0";
|
||||||
|
reg = <0x00 0x10011000 0x00 0x1000>;
|
||||||
|
interrupt-parent = <&plic>;
|
||||||
|
interrupts = <40>;
|
||||||
|
clocks = <&prci CLK_PCLK>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
ccache: cache-controller@2010000 {
|
||||||
|
compatible = "sifive,fu740-c000-ccache", "cache";
|
||||||
|
cache-block-size = <64>;
|
||||||
|
cache-level = <2>;
|
||||||
|
cache-sets = <2048>;
|
||||||
|
cache-size = <0x200000>;
|
||||||
|
cache-unified;
|
||||||
|
interrupt-parent = <&plic>;
|
||||||
|
interrupts = <0x13>, <0x15>, <0x16>, <0x14>;
|
||||||
|
reg = <0x00 0x2010000 0x00 0x1000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
memory@80000000 {
|
||||||
|
device_type = "memory";
|
||||||
|
reg = <0x00 0x80000000 0x04 0x00>;
|
||||||
|
};
|
||||||
|
|
||||||
|
clk_hfclk: hfclk {
|
||||||
|
#clock-cells = <0>;
|
||||||
|
compatible = "fixed-clock";
|
||||||
|
clock-frequency = <26000000>;
|
||||||
|
clock-output-names = "hfclk";
|
||||||
|
};
|
||||||
|
|
||||||
|
clk_rtcclk: rtcclk {
|
||||||
|
#clock-cells = <0>;
|
||||||
|
compatible = "fixed-clock";
|
||||||
|
clock-frequency = <1000000>;
|
||||||
|
clock-output-names = "rtcclk";
|
||||||
|
};
|
||||||
|
};
|
||||||
Binary file not shown.
@@ -0,0 +1,577 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <0x02>;
|
||||||
|
#size-cells = <0x02>;
|
||||||
|
compatible = "sifive,hifive-unmatched-a00", "sifive,fu740-c000", "sifive,fu740";
|
||||||
|
model = "SiFive HiFive Unmatched";
|
||||||
|
|
||||||
|
aliases {
|
||||||
|
serial0 = "/soc/serial@10010000";
|
||||||
|
serial1 = "/soc/serial@10011000";
|
||||||
|
ethernet0 = "/soc/ethernet@10090000";
|
||||||
|
};
|
||||||
|
|
||||||
|
chosen {
|
||||||
|
stdout-path = "serial0";
|
||||||
|
};
|
||||||
|
|
||||||
|
cpus {
|
||||||
|
#address-cells = <0x01>;
|
||||||
|
#size-cells = <0x00>;
|
||||||
|
timebase-frequency = <0xf4240>;
|
||||||
|
|
||||||
|
cpu@0 {
|
||||||
|
compatible = "sifive,bullet0", "riscv";
|
||||||
|
device_type = "cpu";
|
||||||
|
i-cache-block-size = <0x40>;
|
||||||
|
i-cache-sets = <0x80>;
|
||||||
|
i-cache-size = <0x4000>;
|
||||||
|
next-level-cache = <0x01>;
|
||||||
|
reg = <0x00>;
|
||||||
|
riscv,isa = "rv64imac";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
interrupt-controller {
|
||||||
|
#interrupt-cells = <0x01>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
phandle = <0x02>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu@1 {
|
||||||
|
compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
|
||||||
|
d-cache-block-size = <0x40>;
|
||||||
|
d-cache-sets = <0x40>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-tlb-sets = <0x01>;
|
||||||
|
d-tlb-size = <0x28>;
|
||||||
|
device_type = "cpu";
|
||||||
|
i-cache-block-size = <0x40>;
|
||||||
|
i-cache-sets = <0x80>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-tlb-sets = <0x01>;
|
||||||
|
i-tlb-size = <0x28>;
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
next-level-cache = <0x01>;
|
||||||
|
reg = <0x01>;
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
tlb-split;
|
||||||
|
|
||||||
|
interrupt-controller {
|
||||||
|
#interrupt-cells = <0x01>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
phandle = <0x03>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu@2 {
|
||||||
|
compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
|
||||||
|
d-cache-block-size = <0x40>;
|
||||||
|
d-cache-sets = <0x40>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-tlb-sets = <0x01>;
|
||||||
|
d-tlb-size = <0x28>;
|
||||||
|
device_type = "cpu";
|
||||||
|
i-cache-block-size = <0x40>;
|
||||||
|
i-cache-sets = <0x80>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-tlb-sets = <0x01>;
|
||||||
|
i-tlb-size = <0x28>;
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
next-level-cache = <0x01>;
|
||||||
|
reg = <0x02>;
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
tlb-split;
|
||||||
|
|
||||||
|
interrupt-controller {
|
||||||
|
#interrupt-cells = <0x01>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
phandle = <0x04>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu@3 {
|
||||||
|
compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
|
||||||
|
d-cache-block-size = <0x40>;
|
||||||
|
d-cache-sets = <0x40>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-tlb-sets = <0x01>;
|
||||||
|
d-tlb-size = <0x28>;
|
||||||
|
device_type = "cpu";
|
||||||
|
i-cache-block-size = <0x40>;
|
||||||
|
i-cache-sets = <0x80>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-tlb-sets = <0x01>;
|
||||||
|
i-tlb-size = <0x28>;
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
next-level-cache = <0x01>;
|
||||||
|
reg = <0x03>;
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
tlb-split;
|
||||||
|
|
||||||
|
interrupt-controller {
|
||||||
|
#interrupt-cells = <0x01>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
phandle = <0x05>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu@4 {
|
||||||
|
compatible = "sifive,u74-mc", "sifive,bullet0", "riscv";
|
||||||
|
d-cache-block-size = <0x40>;
|
||||||
|
d-cache-sets = <0x40>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-tlb-sets = <0x01>;
|
||||||
|
d-tlb-size = <0x28>;
|
||||||
|
device_type = "cpu";
|
||||||
|
i-cache-block-size = <0x40>;
|
||||||
|
i-cache-sets = <0x80>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-tlb-sets = <0x01>;
|
||||||
|
i-tlb-size = <0x28>;
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
next-level-cache = <0x01>;
|
||||||
|
reg = <0x04>;
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
tlb-split;
|
||||||
|
|
||||||
|
interrupt-controller {
|
||||||
|
#interrupt-cells = <0x01>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
phandle = <0x06>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
soc {
|
||||||
|
#address-cells = <0x02>;
|
||||||
|
#size-cells = <0x02>;
|
||||||
|
compatible = "simple-bus";
|
||||||
|
ranges;
|
||||||
|
|
||||||
|
interrupt-controller@c000000 {
|
||||||
|
#interrupt-cells = <0x01>;
|
||||||
|
#address-cells = <0x00>;
|
||||||
|
compatible = "sifive,fu540-c000-plic", "sifive,plic-1.0.0";
|
||||||
|
reg = <0x00 0xc000000 0x00 0x4000000>;
|
||||||
|
riscv,ndev = <0x45>;
|
||||||
|
interrupt-controller;
|
||||||
|
interrupts-extended = <0x02 0xffffffff 0x03 0xffffffff 0x03 0x09 0x04 0xffffffff 0x04 0x09 0x05 0xffffffff 0x05 0x09 0x06 0xffffffff 0x06 0x09>;
|
||||||
|
phandle = <0x09>;
|
||||||
|
};
|
||||||
|
|
||||||
|
prci: clock-controller@10000000 {
|
||||||
|
compatible = "sifive,fu740-c000-prci";
|
||||||
|
reg = <0x00 0x10000000 0x00 0x1000>;
|
||||||
|
clocks = <&clk_hfclk>, <&clk_rtcclk>;
|
||||||
|
#clock-cells = <0x01>;
|
||||||
|
#reset-cells = <0x01>;
|
||||||
|
};
|
||||||
|
|
||||||
|
serial@10010000 {
|
||||||
|
compatible = "sifive,fu740-c000-uart", "sifive,uart0";
|
||||||
|
reg = <0x00 0x10010000 0x00 0x1000>;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x27>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
serial@10011000 {
|
||||||
|
compatible = "sifive,fu740-c000-uart", "sifive,uart0";
|
||||||
|
reg = <0x00 0x10011000 0x00 0x1000>;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x28>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c@10030000 {
|
||||||
|
compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
|
||||||
|
reg = <0x00 0x10030000 0x00 0x1000>;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x34>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
reg-shift = <0x02>;
|
||||||
|
reg-io-width = <0x01>;
|
||||||
|
#address-cells = <0x01>;
|
||||||
|
#size-cells = <0x00>;
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
temperature-sensor@4c {
|
||||||
|
compatible = "ti,tmp451";
|
||||||
|
reg = <0x4c>;
|
||||||
|
interrupt-parent = <0x0b>;
|
||||||
|
interrupts = <0x06 0x08>;
|
||||||
|
};
|
||||||
|
|
||||||
|
pmic@58 {
|
||||||
|
compatible = "dlg,da9063";
|
||||||
|
reg = <0x58>;
|
||||||
|
interrupt-parent = <0x0b>;
|
||||||
|
interrupts = <0x01 0x08>;
|
||||||
|
interrupt-controller;
|
||||||
|
|
||||||
|
regulators {
|
||||||
|
|
||||||
|
bcore1 {
|
||||||
|
regulator-min-microvolt = <0x100590>;
|
||||||
|
regulator-max-microvolt = <0x100590>;
|
||||||
|
regulator-min-microamp = <0x4c4b40>;
|
||||||
|
regulator-max-microamp = <0x4c4b40>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
bcore2 {
|
||||||
|
regulator-min-microvolt = <0x100590>;
|
||||||
|
regulator-max-microvolt = <0x100590>;
|
||||||
|
regulator-min-microamp = <0x4c4b40>;
|
||||||
|
regulator-max-microamp = <0x4c4b40>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
bpro {
|
||||||
|
regulator-min-microvolt = <0x1b7740>;
|
||||||
|
regulator-max-microvolt = <0x1b7740>;
|
||||||
|
regulator-min-microamp = <0x2625a0>;
|
||||||
|
regulator-max-microamp = <0x2625a0>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
bperi {
|
||||||
|
regulator-min-microvolt = <0x100590>;
|
||||||
|
regulator-max-microvolt = <0x100590>;
|
||||||
|
regulator-min-microamp = <0x16e360>;
|
||||||
|
regulator-max-microamp = <0x16e360>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
bmem {
|
||||||
|
regulator-min-microvolt = <0x124f80>;
|
||||||
|
regulator-max-microvolt = <0x124f80>;
|
||||||
|
regulator-min-microamp = <0x2dc6c0>;
|
||||||
|
regulator-max-microamp = <0x2dc6c0>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
bio {
|
||||||
|
regulator-min-microvolt = <0x124f80>;
|
||||||
|
regulator-max-microvolt = <0x124f80>;
|
||||||
|
regulator-min-microamp = <0x2dc6c0>;
|
||||||
|
regulator-max-microamp = <0x2dc6c0>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo1 {
|
||||||
|
regulator-min-microvolt = <0x1b7740>;
|
||||||
|
regulator-max-microvolt = <0x1b7740>;
|
||||||
|
regulator-min-microamp = <0x186a0>;
|
||||||
|
regulator-max-microamp = <0x186a0>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo2 {
|
||||||
|
regulator-min-microvolt = <0x1b7740>;
|
||||||
|
regulator-max-microvolt = <0x1b7740>;
|
||||||
|
regulator-min-microamp = <0x30d40>;
|
||||||
|
regulator-max-microamp = <0x30d40>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo3 {
|
||||||
|
regulator-min-microvolt = <0x325aa0>;
|
||||||
|
regulator-max-microvolt = <0x325aa0>;
|
||||||
|
regulator-min-microamp = <0x30d40>;
|
||||||
|
regulator-max-microamp = <0x30d40>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo4 {
|
||||||
|
regulator-min-microvolt = <0x2625a0>;
|
||||||
|
regulator-max-microvolt = <0x2625a0>;
|
||||||
|
regulator-min-microamp = <0x30d40>;
|
||||||
|
regulator-max-microamp = <0x30d40>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo5 {
|
||||||
|
regulator-min-microvolt = <0x325aa0>;
|
||||||
|
regulator-max-microvolt = <0x325aa0>;
|
||||||
|
regulator-min-microamp = <0x186a0>;
|
||||||
|
regulator-max-microamp = <0x186a0>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo6 {
|
||||||
|
regulator-min-microvolt = <0x1b7740>;
|
||||||
|
regulator-max-microvolt = <0x1b7740>;
|
||||||
|
regulator-min-microamp = <0x30d40>;
|
||||||
|
regulator-max-microamp = <0x30d40>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo7 {
|
||||||
|
regulator-min-microvolt = <0x325aa0>;
|
||||||
|
regulator-max-microvolt = <0x325aa0>;
|
||||||
|
regulator-min-microamp = <0x30d40>;
|
||||||
|
regulator-max-microamp = <0x30d40>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo8 {
|
||||||
|
regulator-min-microvolt = <0x325aa0>;
|
||||||
|
regulator-max-microvolt = <0x325aa0>;
|
||||||
|
regulator-min-microamp = <0x30d40>;
|
||||||
|
regulator-max-microamp = <0x30d40>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo9 {
|
||||||
|
regulator-min-microvolt = <0x100590>;
|
||||||
|
regulator-max-microvolt = <0x100590>;
|
||||||
|
regulator-min-microamp = <0x30d40>;
|
||||||
|
regulator-max-microamp = <0x30d40>;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo10 {
|
||||||
|
regulator-min-microvolt = <0xf4240>;
|
||||||
|
regulator-max-microvolt = <0xf4240>;
|
||||||
|
regulator-min-microamp = <0x493e0>;
|
||||||
|
regulator-max-microamp = <0x493e0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo11 {
|
||||||
|
regulator-min-microvolt = <0x2625a0>;
|
||||||
|
regulator-max-microvolt = <0x2625a0>;
|
||||||
|
regulator-min-microamp = <0x493e0>;
|
||||||
|
regulator-max-microamp = <0x493e0>;
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c@10031000 {
|
||||||
|
compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
|
||||||
|
reg = <0x00 0x10031000 0x00 0x1000>;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x35>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
reg-shift = <0x02>;
|
||||||
|
reg-io-width = <0x01>;
|
||||||
|
#address-cells = <0x01>;
|
||||||
|
#size-cells = <0x00>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
spi@10040000 {
|
||||||
|
compatible = "sifive,fu740-c000-spi", "sifive,spi0";
|
||||||
|
reg = <0x00 0x10040000 0x00 0x1000 0x00 0x20000000 0x00 0x10000000>;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x29>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
#address-cells = <0x01>;
|
||||||
|
#size-cells = <0x00>;
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
flash@0 {
|
||||||
|
compatible = "issi,is25wp256", "jedec,spi-nor";
|
||||||
|
reg = <0x00>;
|
||||||
|
spi-max-frequency = <0x2faf080>;
|
||||||
|
m25p,fast-read;
|
||||||
|
spi-tx-bus-width = <0x04>;
|
||||||
|
spi-rx-bus-width = <0x04>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
spi@10041000 {
|
||||||
|
compatible = "sifive,fu740-c000-spi", "sifive,spi0";
|
||||||
|
reg = <0x00 0x10041000 0x00 0x1000 0x00 0x30000000 0x00 0x10000000>;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x2a>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
#address-cells = <0x01>;
|
||||||
|
#size-cells = <0x00>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
spi@10050000 {
|
||||||
|
compatible = "sifive,fu740-c000-spi", "sifive,spi0";
|
||||||
|
reg = <0x00 0x10050000 0x00 0x1000>;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x2b>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
#address-cells = <0x01>;
|
||||||
|
#size-cells = <0x00>;
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
mmc@0 {
|
||||||
|
compatible = "mmc-spi-slot";
|
||||||
|
reg = <0x00>;
|
||||||
|
spi-max-frequency = <0x1312d00>;
|
||||||
|
voltage-ranges = <0xce4 0xce4>;
|
||||||
|
disable-wp;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
macb: ethernet@10090000 {
|
||||||
|
compatible = "sifive,fu540-c000-gem";
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x37>;
|
||||||
|
reg = <0x00 0x10090000 0x00 0x2000 0x00 0x100a0000 0x00 0x1000>;
|
||||||
|
local-mac-address = [00 00 00 00 00 00];
|
||||||
|
clock-names = "pclk", "hclk";
|
||||||
|
clocks = <&prci 0x02 &prci 0x02>;
|
||||||
|
#address-cells = <0x01>;
|
||||||
|
#size-cells = <0x00>;
|
||||||
|
status = "okay";
|
||||||
|
phy-mode = "gmii";
|
||||||
|
phy-handle = <0x0c>;
|
||||||
|
|
||||||
|
ethernet-phy@0 {
|
||||||
|
reg = <0x00>;
|
||||||
|
phandle = <0x0c>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pwm@10020000 {
|
||||||
|
compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
|
||||||
|
reg = <0x00 0x10020000 0x00 0x1000>;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x2c 0x2d 0x2e 0x2f>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
#pwm-cells = <0x03>;
|
||||||
|
status = "okay";
|
||||||
|
phandle = <0x0d>;
|
||||||
|
};
|
||||||
|
|
||||||
|
pwm@10021000 {
|
||||||
|
compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
|
||||||
|
reg = <0x00 0x10021000 0x00 0x1000>;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x30 0x31 0x32 0x33>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
#pwm-cells = <0x03>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
cache-controller@2010000 {
|
||||||
|
compatible = "sifive,fu740-c000-ccache", "cache";
|
||||||
|
cache-block-size = <0x40>;
|
||||||
|
cache-level = <0x02>;
|
||||||
|
cache-sets = <0x800>;
|
||||||
|
cache-size = <0x200000>;
|
||||||
|
cache-unified;
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x13 0x15 0x16 0x14>;
|
||||||
|
reg = <0x00 0x2010000 0x00 0x1000>;
|
||||||
|
phandle = <0x01>;
|
||||||
|
};
|
||||||
|
|
||||||
|
gpio@10060000 {
|
||||||
|
compatible = "sifive,fu740-c000-gpio", "sifive,gpio0";
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupts = <0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 0x20 0x21 0x22 0x23 0x24 0x25 0x26>;
|
||||||
|
reg = <0x00 0x10060000 0x00 0x1000>;
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <0x02>;
|
||||||
|
interrupt-controller;
|
||||||
|
#interrupt-cells = <0x02>;
|
||||||
|
clocks = <&prci 0x07>;
|
||||||
|
status = "okay";
|
||||||
|
phandle = <0x0b>;
|
||||||
|
};
|
||||||
|
|
||||||
|
pcie@e00000000 {
|
||||||
|
#address-cells = <0x03>;
|
||||||
|
#interrupt-cells = <0x01>;
|
||||||
|
#num-lanes = <0x08>;
|
||||||
|
#size-cells = <0x02>;
|
||||||
|
compatible = "sifive,fu740-pcie";
|
||||||
|
reg = <0x0e 0x00 0x01 0x00 0x0d 0xf0000000 0x00 0x10000000 0x00 0x100d0000 0x00 0x1000>;
|
||||||
|
reg-names = "dbi", "config", "mgmt";
|
||||||
|
device_type = "pci";
|
||||||
|
dma-coherent;
|
||||||
|
bus-range = <0x00 0xff>;
|
||||||
|
ranges = <0x81000000 0x00 0x60080000 0x00 0x60080000 0x00 0x10000 0x82000000 0x00 0x60090000 0x00 0x60090000 0x00 0xff70000 0x82000000 0x00 0x70000000 0x00 0x70000000 0x00 0x1000000 0xc3000000 0x20 0x00 0x20 0x00 0x20 0x00>;
|
||||||
|
num-lanes = <0x08>;
|
||||||
|
interrupts = <0x38 0x39 0x3a 0x3b 0x3c 0x3d 0x3e 0x3f 0x40>;
|
||||||
|
interrupt-names = "msi", "inta", "intb", "intc", "intd";
|
||||||
|
interrupt-parent = <0x09>;
|
||||||
|
interrupt-map-mask = <0x00 0x00 0x00 0x07>;
|
||||||
|
interrupt-map = <0x00 0x00 0x00 0x01 0x09 0x39 0x00 0x00 0x00 0x02 0x09 0x3a 0x00 0x00 0x00 0x03 0x09 0x3b 0x00 0x00 0x00 0x04 0x09 0x3c>;
|
||||||
|
clock-names = "pcie_aux";
|
||||||
|
clocks = <&prci 0x08>;
|
||||||
|
pwren-gpios = <0x0b 0x05 0x00>;
|
||||||
|
perstn-gpios = <0x0b 0x08 0x00>;
|
||||||
|
resets = <&prci 0x04>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
memory@80000000 {
|
||||||
|
device_type = "memory";
|
||||||
|
reg = <0x00 0x80000000 0x04 0x00>;
|
||||||
|
};
|
||||||
|
|
||||||
|
pwmleds {
|
||||||
|
compatible = "pwm-leds";
|
||||||
|
|
||||||
|
green-d12 {
|
||||||
|
label = "green:d12";
|
||||||
|
pwms = <0x0d 0x00 0x773594 0x01>;
|
||||||
|
active-low = <0x01>;
|
||||||
|
max-brightness = <0xff>;
|
||||||
|
linux,default-trigger = "none";
|
||||||
|
};
|
||||||
|
|
||||||
|
green-d2 {
|
||||||
|
label = "green:d2";
|
||||||
|
pwms = <0x0d 0x01 0x773594 0x01>;
|
||||||
|
active-low = <0x01>;
|
||||||
|
max-brightness = <0xff>;
|
||||||
|
linux,default-trigger = "none";
|
||||||
|
};
|
||||||
|
|
||||||
|
red-d2 {
|
||||||
|
label = "red:d2";
|
||||||
|
pwms = <0x0d 0x02 0x773594 0x01>;
|
||||||
|
active-low = <0x01>;
|
||||||
|
max-brightness = <0xff>;
|
||||||
|
linux,default-trigger = "none";
|
||||||
|
};
|
||||||
|
|
||||||
|
blue-d2 {
|
||||||
|
label = "blue:d2";
|
||||||
|
pwms = <0x0d 0x03 0x773594 0x01>;
|
||||||
|
active-low = <0x01>;
|
||||||
|
max-brightness = <0xff>;
|
||||||
|
linux,default-trigger = "none";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
clk_hfclk: hfclk {
|
||||||
|
#clock-cells = <0x00>;
|
||||||
|
compatible = "fixed-clock";
|
||||||
|
clock-frequency = <26000000>;
|
||||||
|
clock-output-names = "hfclk";
|
||||||
|
};
|
||||||
|
|
||||||
|
clk_rtcclk: rtcclk {
|
||||||
|
#clock-cells = <0x00>;
|
||||||
|
compatible = "fixed-clock";
|
||||||
|
clock-frequency = <1000000>;
|
||||||
|
clock-output-names = "rtcclk";
|
||||||
|
};
|
||||||
|
|
||||||
|
gpio-poweroff {
|
||||||
|
compatible = "gpio-poweroff";
|
||||||
|
gpios = <0x0b 0x02 0x01>;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -2,7 +2,8 @@ use alloc::{sync::Arc, vec::Vec};
|
|||||||
use device_api::{
|
use device_api::{
|
||||||
device::{Device, DeviceInitContext},
|
device::{Device, DeviceInitContext},
|
||||||
interrupt::{
|
interrupt::{
|
||||||
ExternalInterruptController, InterruptHandler, Irq, IrqHandle, IrqOptions, IrqVector,
|
ExternalInterruptController, InterruptHandler, Irq, IrqHandle, IrqOptions, IrqPriority,
|
||||||
|
IrqVector,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use device_tree::{
|
use device_tree::{
|
||||||
@@ -103,6 +104,64 @@ pub struct Plic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Plic {
|
impl Plic {
|
||||||
|
fn ensure_init(&self) -> Result<(), Error> {
|
||||||
|
self.inner.or_try_init_with(|| {
|
||||||
|
log::info!("Initialize RISC-V PLIC");
|
||||||
|
|
||||||
|
let common =
|
||||||
|
unsafe { DeviceMemoryIo::<CommonRegs>::map(self.base, Default::default())? };
|
||||||
|
|
||||||
|
for i in 0..self.max_irq {
|
||||||
|
common.PRIORITY[i].set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for context in self.context_map.iter() {
|
||||||
|
let enable_offset = ENABLE_BASE + context.index * ENABLE_STRIDE;
|
||||||
|
let control_offset = CONTROL_BASE + context.index * CONTROL_STRIDE;
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
"* HART {}: context {}, enable={:#x}, control={:#x}",
|
||||||
|
context.hart,
|
||||||
|
context.index,
|
||||||
|
enable_offset,
|
||||||
|
control_offset
|
||||||
|
);
|
||||||
|
let enable = unsafe {
|
||||||
|
DeviceMemoryIo::<ContextEnableRegs>::map(
|
||||||
|
self.base.add(enable_offset),
|
||||||
|
Default::default(),
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
let control = unsafe {
|
||||||
|
DeviceMemoryIo::<ContextControlRegs>::map(
|
||||||
|
self.base.add(control_offset),
|
||||||
|
Default::default(),
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
for i in 0..self.max_irq.div_ceil(32) {
|
||||||
|
enable.ENABLE[i].set(0);
|
||||||
|
}
|
||||||
|
control.THRESHOLD.set(0);
|
||||||
|
|
||||||
|
context.context.init(Context {
|
||||||
|
enable: IrqSafeRwLock::new(enable),
|
||||||
|
control: IrqSafeRwLock::new(control),
|
||||||
|
table: FixedInterruptTable::new(MAX_IRQS), // table: IrqSafeRwLock::new(FixedInterruptTable::new()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// self.inner.init(Inner {
|
||||||
|
// common: IrqSafeRwLock::new(common),
|
||||||
|
// });
|
||||||
|
|
||||||
|
Ok(Inner {
|
||||||
|
common: IrqSafeRwLock::new(common),
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn hart_context(&self, hart: u32) -> Option<&HartContext> {
|
fn hart_context(&self, hart: u32) -> Option<&HartContext> {
|
||||||
self.context_map.iter().find(|c| c.hart == hart)
|
self.context_map.iter().find(|c| c.hart == hart)
|
||||||
}
|
}
|
||||||
@@ -153,11 +212,20 @@ impl ExternalInterruptController for Plic {
|
|||||||
fn register_irq(
|
fn register_irq(
|
||||||
&self,
|
&self,
|
||||||
irq: Irq,
|
irq: Irq,
|
||||||
_options: IrqOptions,
|
options: IrqOptions,
|
||||||
handler: Arc<dyn InterruptHandler>,
|
handler: Arc<dyn InterruptHandler>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
self.ensure_init()?;
|
||||||
let bsp_hart_id = boot_hart_id() as u32;
|
let bsp_hart_id = boot_hart_id() as u32;
|
||||||
let irq = self.validate_irq(irq)?;
|
let irq = self.validate_irq(irq)?;
|
||||||
|
let prioval = match options.priority {
|
||||||
|
IrqPriority::Low => 3,
|
||||||
|
IrqPriority::Normal => 5,
|
||||||
|
IrqPriority::High => 7,
|
||||||
|
};
|
||||||
|
let inner = self.inner.get();
|
||||||
|
let common = inner.common.write();
|
||||||
|
common.PRIORITY[irq as usize - 1].set(prioval);
|
||||||
let context = self
|
let context = self
|
||||||
.hart_context(bsp_hart_id)
|
.hart_context(bsp_hart_id)
|
||||||
.ok_or(Error::InvalidArgument)
|
.ok_or(Error::InvalidArgument)
|
||||||
@@ -186,68 +254,24 @@ impl ExternalInterruptController for Plic {
|
|||||||
let control = context.control.write();
|
let control = context.control.write();
|
||||||
// let table = context.table.read();
|
// let table = context.table.read();
|
||||||
|
|
||||||
loop {
|
let irq = control.CLAIM.get();
|
||||||
let irq = control.CLAIM.get();
|
if irq == 0 {
|
||||||
if irq == 0 {
|
return;
|
||||||
break;
|
|
||||||
}
|
|
||||||
let vector = IrqVector::Irq(Irq::External(irq));
|
|
||||||
|
|
||||||
if !context.table.handle_irq_line(irq as usize, vector) {
|
|
||||||
log::warn!("plic: no handler for IRQ #{irq}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done servicing
|
|
||||||
control.CLAIM.set(irq);
|
|
||||||
}
|
}
|
||||||
|
let vector = IrqVector::Irq(Irq::External(irq));
|
||||||
|
|
||||||
|
if !context.table.handle_irq_line(irq as usize, vector) {
|
||||||
|
log::warn!("plic: no handler for IRQ #{irq}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done servicing
|
||||||
|
control.CLAIM.set(irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for Plic {
|
impl Device for Plic {
|
||||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||||
log::info!("Initialize RISC-V PLIC");
|
self.ensure_init()?;
|
||||||
|
|
||||||
let common = DeviceMemoryIo::<CommonRegs>::map(self.base, Default::default())?;
|
|
||||||
|
|
||||||
for i in 0..self.max_irq {
|
|
||||||
common.PRIORITY[i].set(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
for context in self.context_map.iter() {
|
|
||||||
let enable_offset = ENABLE_BASE + context.index * ENABLE_STRIDE;
|
|
||||||
let control_offset = CONTROL_BASE + context.index * CONTROL_STRIDE;
|
|
||||||
|
|
||||||
log::info!(
|
|
||||||
"* HART {}: context {}, enable={:#x}, control={:#x}",
|
|
||||||
context.hart,
|
|
||||||
context.index,
|
|
||||||
enable_offset,
|
|
||||||
control_offset
|
|
||||||
);
|
|
||||||
let enable = DeviceMemoryIo::<ContextEnableRegs>::map(
|
|
||||||
self.base.add(enable_offset),
|
|
||||||
Default::default(),
|
|
||||||
)?;
|
|
||||||
let control = DeviceMemoryIo::<ContextControlRegs>::map(
|
|
||||||
self.base.add(control_offset),
|
|
||||||
Default::default(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
for i in 0..self.max_irq.div_ceil(32) {
|
|
||||||
enable.ENABLE[i].set(0);
|
|
||||||
}
|
|
||||||
control.THRESHOLD.set(0);
|
|
||||||
|
|
||||||
context.context.init(Context {
|
|
||||||
enable: IrqSafeRwLock::new(enable),
|
|
||||||
control: IrqSafeRwLock::new(control),
|
|
||||||
table: FixedInterruptTable::new(MAX_IRQS), // table: IrqSafeRwLock::new(FixedInterruptTable::new()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
self.inner.init(Inner {
|
|
||||||
common: IrqSafeRwLock::new(common),
|
|
||||||
});
|
|
||||||
|
|
||||||
register_external_interrupt_controller(self);
|
register_external_interrupt_controller(self);
|
||||||
|
|
||||||
@@ -301,6 +325,7 @@ device_tree_driver! {
|
|||||||
) else {
|
) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
log::info!("Context #{context}: mode={mode:?}, hart={hart_id}");
|
||||||
if mode != ContextMode::ExternalS {
|
if mode != ContextMode::ExternalS {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
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_bitfields, register_structs,
|
||||||
|
registers::{ReadOnly, ReadWrite},
|
||||||
|
};
|
||||||
|
|
||||||
|
// const CLK_COREPLL: u32 = 0;
|
||||||
|
// const CLK_DDRPLL: u32 = 1;
|
||||||
|
// const CLK_GEMGXLPLL: u32 = 2;
|
||||||
|
// const CLK_DVFSCOREPLL: u32 = 3;
|
||||||
|
// const CLK_HFPCLKPLL: u32 = 4;
|
||||||
|
// const CLK_CLTXPLL: u32 = 5;
|
||||||
|
// const CLK_TLCLK: u32 = 6;
|
||||||
|
const CLK_PCLK: u32 = 7;
|
||||||
|
// const CLK_PCIE_AUX: u32 = 8;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct WrpllData {
|
||||||
|
divr: u32,
|
||||||
|
divf: u32,
|
||||||
|
divq: u32,
|
||||||
|
int_feedback: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
register_bitfields! {
|
||||||
|
u32,
|
||||||
|
PllCfg [
|
||||||
|
PLLR OFFSET(0) NUMBITS(6) [],
|
||||||
|
PLLF OFFSET(6) NUMBITS(9) [],
|
||||||
|
PLLQ OFFSET(15) NUMBITS(3) [],
|
||||||
|
PLLBYPASS OFFSET(24) NUMBITS(1) [],
|
||||||
|
PLLFSEBYPASS OFFSET(25) NUMBITS(1) [],
|
||||||
|
PLLLOCK OFFSET(31) NUMBITS(1) [],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WrpllData {
|
||||||
|
fn fbdiv(&self) -> u32 {
|
||||||
|
if self.int_feedback { 2 } else { 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_rate(&self, input_rate: Hertz) -> Hertz {
|
||||||
|
let fbdiv = self.fbdiv();
|
||||||
|
let n = input_rate * fbdiv * (self.divf + 1);
|
||||||
|
let n = n / (self.divr + 1);
|
||||||
|
n >> self.divq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
Regs {
|
||||||
|
(0x00 => hfxosccfg: ReadWrite<u32>),
|
||||||
|
(0x04 => core_pllcfg: ReadWrite<u32>),
|
||||||
|
(0x08 => core_plloutdiv: ReadWrite<u32>),
|
||||||
|
(0x0C => ddr_pllcfg: ReadWrite<u32>),
|
||||||
|
(0x10 => ddr_plloutdiv: ReadWrite<u32>),
|
||||||
|
(0x14 => _0),
|
||||||
|
(0x1C => gemgxl_pllcfg: ReadWrite<u32, PllCfg::Register>),
|
||||||
|
(0x20 => gemgxl_plloutdiv: ReadWrite<u32>),
|
||||||
|
(0x24 => core_clk_sel_reg: ReadWrite<u32>),
|
||||||
|
(0x28 => devices_reset_n: ReadWrite<u32>),
|
||||||
|
(0x2C => clk_mux_status: ReadOnly<u32>),
|
||||||
|
(0x30 => _1),
|
||||||
|
(0x38 => dvfs_core_pllcfg: ReadWrite<u32>),
|
||||||
|
(0x3C => dvfs_core_plloutdiv: ReadWrite<u32>),
|
||||||
|
(0x40 => corepllsel: ReadWrite<u32>),
|
||||||
|
(0x44 => _2),
|
||||||
|
(0x50 => hfpclk_pllcfg: ReadWrite<u32, PllCfg::Register>),
|
||||||
|
(0x54 => hfpclk_plloutdiv: ReadWrite<u32>),
|
||||||
|
(0x58 => hfpclkpllsel: ReadWrite<u32>),
|
||||||
|
(0x5C => hfpclk_div_reg: ReadWrite<u32>),
|
||||||
|
(0x60 => _3),
|
||||||
|
(0xE0 => prci_plls: ReadOnly<u32>),
|
||||||
|
(0xE4 => _4),
|
||||||
|
(0x100 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Prci {
|
||||||
|
clk_hfclk: ClockHandle,
|
||||||
|
clk_rtcclk: ClockHandle,
|
||||||
|
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Regs {
|
||||||
|
fn read_hfpclk_pll(&self) -> WrpllData {
|
||||||
|
let reg = self.hfpclk_pllcfg.extract();
|
||||||
|
let divr = reg.read(PllCfg::PLLR);
|
||||||
|
let divq = reg.read(PllCfg::PLLQ);
|
||||||
|
let divf = reg.read(PllCfg::PLLF);
|
||||||
|
WrpllData {
|
||||||
|
divq,
|
||||||
|
divr,
|
||||||
|
divf,
|
||||||
|
int_feedback: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for Prci {
|
||||||
|
fn display_name(&self) -> &str {
|
||||||
|
"sifive,fu740-c000-prci"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClockController for Prci {
|
||||||
|
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
|
||||||
|
// hart frequency: coreclk, supplied either by corepll or dvfscorepll, selected by
|
||||||
|
// corepllsel
|
||||||
|
// hfpclkpll: clock for SPI, UART, GPIO, I2C, PWM
|
||||||
|
//
|
||||||
|
let _ = &self.clk_rtcclk;
|
||||||
|
let regs = self.regs.lock();
|
||||||
|
match clock {
|
||||||
|
Some(CLK_PCLK) => {
|
||||||
|
// PCLK calculation:
|
||||||
|
// pclk <- X / hfpclkdiv
|
||||||
|
// case [hfpclkpllsel]:
|
||||||
|
// 1: X <- (hfclk)
|
||||||
|
// 0: X <- hfpclkpllcfg/out & hfpclkpll
|
||||||
|
// hfpclkdiv <- [hfpclk_div_reg] + 2
|
||||||
|
|
||||||
|
let hfpclkpllsel = regs.hfpclkpllsel.get() & 1 != 0;
|
||||||
|
let hfpclk_div_reg = regs.hfpclk_div_reg.get() + 2;
|
||||||
|
let x = match hfpclkpllsel {
|
||||||
|
true => self.clk_hfclk.rate()?,
|
||||||
|
false => {
|
||||||
|
let pclk_pll = regs.read_hfpclk_pll();
|
||||||
|
pclk_pll.output_rate(self.clk_hfclk.rate()?)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(x / hfpclk_div_reg)
|
||||||
|
}
|
||||||
|
Some(_) => {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
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,fu740-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_hfclk = node.clock(0)?;
|
||||||
|
let clk_rtcclk = node.clock(1)?;
|
||||||
|
|
||||||
|
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
|
||||||
|
|
||||||
|
let prci = Arc::new(Prci {
|
||||||
|
regs: IrqSafeSpinlock::new(regs),
|
||||||
|
clk_hfclk,
|
||||||
|
clk_rtcclk
|
||||||
|
});
|
||||||
|
|
||||||
|
node.make_clock_controller(prci.clone());
|
||||||
|
|
||||||
|
Some(prci)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod clock;
|
mod clock_fu540;
|
||||||
|
mod clock_fu740;
|
||||||
mod ethernet;
|
mod ethernet;
|
||||||
mod uart;
|
mod uart;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use device_api::{
|
use device_api::{
|
||||||
clock::{ClockHandle, Hertz},
|
clock::{ClockHandle, Hertz},
|
||||||
device::{Device, DeviceInitContext},
|
device::{Device, DeviceInitContext},
|
||||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
interrupt::{InterruptHandler, IrqHandle, IrqPriority, IrqVector},
|
||||||
};
|
};
|
||||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||||
use libk::{
|
use libk::{
|
||||||
@@ -16,9 +18,12 @@ use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
|||||||
use tock_registers::{
|
use tock_registers::{
|
||||||
interfaces::{Readable, Writeable},
|
interfaces::{Readable, Writeable},
|
||||||
register_bitfields, register_structs,
|
register_bitfields, register_structs,
|
||||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
registers::{ReadOnly, ReadWrite},
|
||||||
|
};
|
||||||
|
use yggdrasil_abi::{
|
||||||
|
io::{TerminalOptions, TerminalOutputOptions},
|
||||||
|
process::ProcessId,
|
||||||
};
|
};
|
||||||
use yggdrasil_abi::io::{TerminalOptions, TerminalOutputOptions};
|
|
||||||
|
|
||||||
register_bitfields! {
|
register_bitfields! {
|
||||||
u32,
|
u32,
|
||||||
@@ -42,7 +47,7 @@ register_bitfields! {
|
|||||||
|
|
||||||
register_structs! {
|
register_structs! {
|
||||||
Regs {
|
Regs {
|
||||||
(0x00 => txdata: WriteOnly<u32>),
|
(0x00 => txdata: ReadWrite<u32>),
|
||||||
(0x04 => rxdata: ReadOnly<u32>),
|
(0x04 => rxdata: ReadOnly<u32>),
|
||||||
(0x08 => txctrl: ReadWrite<u32, txctrl::Register>),
|
(0x08 => txctrl: ReadWrite<u32, txctrl::Register>),
|
||||||
(0x0C => rxctrl: ReadWrite<u32, rxctrl::Register>),
|
(0x0C => rxctrl: ReadWrite<u32, rxctrl::Register>),
|
||||||
@@ -57,6 +62,7 @@ register_structs! {
|
|||||||
struct Inner {
|
struct Inner {
|
||||||
clock: ClockHandle,
|
clock: ClockHandle,
|
||||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||||
|
active: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Uart {
|
struct Uart {
|
||||||
@@ -69,6 +75,7 @@ struct Uart {
|
|||||||
|
|
||||||
impl Regs {
|
impl Regs {
|
||||||
fn set_baud_rate(&self, input_clk: Hertz, baud: u32) -> Result<(), Error> {
|
fn set_baud_rate(&self, input_clk: Hertz, baud: u32) -> Result<(), Error> {
|
||||||
|
// Check: given f_in=130MHz, baud=115200 should give div = 0x468
|
||||||
let div = Hertz::divider(input_clk, Hertz::from(baud)).ok_or(Error::InvalidArgument)?;
|
let div = Hertz::divider(input_clk, Hertz::from(baud)).ok_or(Error::InvalidArgument)?;
|
||||||
if div >= (1 << 20) || div == 0 {
|
if div >= (1 << 20) || div == 0 {
|
||||||
return Err(Error::InvalidArgument);
|
return Err(Error::InvalidArgument);
|
||||||
@@ -84,9 +91,25 @@ impl Regs {
|
|||||||
(input_clk / div).0 as u32
|
(input_clk / div).0 as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_txfifo_full(&self) -> bool {
|
||||||
|
self.txdata.get() & (1 << 31) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&self) -> Option<u8> {
|
||||||
|
let val = self.rxdata.get();
|
||||||
|
if val & (1 << 31) == 0 {
|
||||||
|
Some(val as u8)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn write(&self, byte: u8) {
|
fn write(&self, byte: u8) {
|
||||||
while !self.ip.matches_all(interrupt::txwm::SET) {
|
while self.is_txfifo_full() {
|
||||||
core::hint::spin_loop();
|
for _ in 0..10000 {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.txdata.set(byte as u32);
|
self.txdata.set(byte as u32);
|
||||||
}
|
}
|
||||||
@@ -98,6 +121,7 @@ impl Device for Uart {
|
|||||||
|
|
||||||
self.clock.enable()?;
|
self.clock.enable()?;
|
||||||
let input_clk = self.clock.rate()?;
|
let input_clk = self.clock.rate()?;
|
||||||
|
log::info!("input_clk = {input_clk}");
|
||||||
|
|
||||||
{
|
{
|
||||||
let _guard = debug::MuteGuard::acquire();
|
let _guard = debug::MuteGuard::acquire();
|
||||||
@@ -106,13 +130,18 @@ impl Device for Uart {
|
|||||||
regs.rxctrl.write(rxctrl::rxen::CLEAR);
|
regs.rxctrl.write(rxctrl::rxen::CLEAR);
|
||||||
regs.set_baud_rate(input_clk, 115200)?;
|
regs.set_baud_rate(input_clk, 115200)?;
|
||||||
regs.txctrl.write(txctrl::txen::SET + txctrl::txcnt.val(3));
|
regs.txctrl.write(txctrl::txen::SET + txctrl::txcnt.val(3));
|
||||||
regs.rxctrl.write(rxctrl::rxen::SET + rxctrl::rxcnt.val(0));
|
}
|
||||||
|
|
||||||
|
// Drain Rx FIFO
|
||||||
|
while regs.read().is_some() {
|
||||||
|
core::hint::spin_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let input = TerminalInput::with_capacity(64)?;
|
let input = TerminalInput::with_capacity(64)?;
|
||||||
let output = Inner {
|
let output = Inner {
|
||||||
regs: IrqSafeSpinlock::new(regs),
|
regs: IrqSafeSpinlock::new(regs),
|
||||||
clock: self.clock.clone(),
|
clock: self.clock.clone(),
|
||||||
|
active: AtomicBool::new(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let terminal = self.inner.init(Arc::new(Terminal::from_parts(
|
let terminal = self.inner.init(Arc::new(Terminal::from_parts(
|
||||||
@@ -130,10 +159,9 @@ impl Device for Uart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||||
self.irq.register(self.clone())?;
|
self.irq
|
||||||
|
.register_with_priority(IrqPriority::Low, self.clone())?;
|
||||||
self.irq.enable()?;
|
self.irq.enable()?;
|
||||||
let regs = self.inner.get().output().regs.lock();
|
|
||||||
regs.ie.write(interrupt::rxwm::SET);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,15 +173,27 @@ impl Device for Uart {
|
|||||||
impl InterruptHandler for Uart {
|
impl InterruptHandler for Uart {
|
||||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||||
let terminal = self.inner.get();
|
let terminal = self.inner.get();
|
||||||
let byte = {
|
let regs = terminal.output().regs.lock();
|
||||||
let regs = terminal.output().regs.lock();
|
let ip = regs.ip.extract();
|
||||||
if regs.ip.matches_all(interrupt::rxwm::SET) {
|
if ip.get() == 0 {
|
||||||
regs.rxdata.get() as u8
|
return false;
|
||||||
} else {
|
}
|
||||||
return false;
|
|
||||||
|
let mut count = 0;
|
||||||
|
let mut bytes = [0; 32];
|
||||||
|
// if ip.matches_all(interrupt::rxwm::SET) {
|
||||||
|
while let Some(byte) = regs.read() {
|
||||||
|
bytes[count] = byte;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
drop(regs);
|
||||||
|
for &byte in &bytes[..count] {
|
||||||
|
if byte != 0 {
|
||||||
|
terminal.write_to_input(byte);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
terminal.write_to_input(byte);
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,6 +212,20 @@ impl DebugSink for Uart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalOutput for Inner {
|
impl TerminalOutput for Inner {
|
||||||
|
fn open(&self, _pid: ProcessId) -> Result<(), Error> {
|
||||||
|
if !self.active.swap(true, Ordering::Acquire) {
|
||||||
|
log::info!("sifive-uart: start");
|
||||||
|
let regs = self.regs.lock();
|
||||||
|
regs.rxctrl.write(rxctrl::rxen::SET + rxctrl::rxcnt.val(0));
|
||||||
|
// Drain Rx FIFO
|
||||||
|
while regs.read().is_some() {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
|
regs.ie.write(interrupt::rxwm::SET);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error> {
|
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error> {
|
||||||
let regs = self.regs.lock();
|
let regs = self.regs.lock();
|
||||||
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
|
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use core::{
|
use core::{
|
||||||
fmt,
|
fmt,
|
||||||
ops::{Div, Mul},
|
ops::{Div, Mul, Shr},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
@@ -48,6 +48,14 @@ impl From<u64> for Hertz {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Shr<u32> for Hertz {
|
||||||
|
type Output = Hertz;
|
||||||
|
|
||||||
|
fn shr(self, rhs: u32) -> Self::Output {
|
||||||
|
Self(self.0 >> rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Mul<u32> for Hertz {
|
impl Mul<u32> for Hertz {
|
||||||
type Output = Hertz;
|
type Output = Hertz;
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,19 @@ pub enum IrqTrigger {
|
|||||||
Level,
|
Level,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum IrqPriority {
|
||||||
|
Low,
|
||||||
|
#[default]
|
||||||
|
Normal,
|
||||||
|
High,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct IrqOptions {
|
pub struct IrqOptions {
|
||||||
pub level: IrqLevel,
|
pub level: IrqLevel,
|
||||||
pub trigger: IrqTrigger,
|
pub trigger: IrqTrigger,
|
||||||
|
pub priority: IrqPriority,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
@@ -152,6 +161,18 @@ impl IrqHandle {
|
|||||||
self.intc.register_irq(self.irq, self.options, handler)
|
self.intc.register_irq(self.irq, self.options, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn register_with_priority(
|
||||||
|
&self,
|
||||||
|
priority: IrqPriority,
|
||||||
|
handler: Arc<dyn InterruptHandler>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let options = IrqOptions {
|
||||||
|
priority,
|
||||||
|
..self.options
|
||||||
|
};
|
||||||
|
self.intc.register_irq(self.irq, options, handler)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn enable(&self) -> Result<(), Error> {
|
pub fn enable(&self) -> Result<(), Error> {
|
||||||
self.intc.enable_irq(self.irq)
|
self.intc.enable_irq(self.irq)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,11 +54,7 @@ impl<K: Eq, V> LruCacheBucket<K, V> {
|
|||||||
pub fn entry_mut(&mut self, key: &K) -> EntryMut<'_, K, V> {
|
pub fn entry_mut(&mut self, key: &K) -> EntryMut<'_, K, V> {
|
||||||
let mut cursor = self.data.cursor_front_mut();
|
let mut cursor = self.data.cursor_front_mut();
|
||||||
|
|
||||||
loop {
|
while let Some(node) = cursor.current() {
|
||||||
let Some(node) = cursor.current() else {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
// If entry found corresponding to the key, remove it and reinsert at the front
|
// If entry found corresponding to the key, remove it and reinsert at the front
|
||||||
if &node.0 == key {
|
if &node.0 == key {
|
||||||
// Safety: just checked it's not None above, so safe
|
// Safety: just checked it's not None above, so safe
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ pub struct DeviceTreeOptions {
|
|||||||
impl Default for DebugOptions {
|
impl Default for DebugOptions {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
serial_level: LogLevel::Info,
|
serial_level: LogLevel::Debug,
|
||||||
display_level: LogLevel::Info,
|
display_level: LogLevel::Info,
|
||||||
disable_program_trace: false,
|
disable_program_trace: false,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ pub fn kinit() -> Result<(), Error> {
|
|||||||
load_kernel_symbol_table(&mut ioctx, "/kernel.sym")?;
|
load_kernel_symbol_table(&mut ioctx, "/kernel.sym")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::info!("Starting init");
|
||||||
|
|
||||||
{
|
{
|
||||||
let group_id = Process::create_group();
|
let group_id = Process::create_group();
|
||||||
let options = LoadOptions {
|
let options = LoadOptions {
|
||||||
|
|||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
/bin/echo info >/sys/debug/1/level
|
||||||
@@ -85,6 +85,7 @@ fn usage(_cmd: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
|
logsink::setup_logging(false);
|
||||||
let args: Vec<_> = env::args().collect();
|
let args: Vec<_> = env::args().collect();
|
||||||
if args.len() != 2 {
|
if args.len() != 2 {
|
||||||
eprintln!("Incorrect rc usage, expected 2 args, got {}", args.len());
|
eprintln!("Incorrect rc usage, expected 2 args, got {}", args.len());
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
use std::{io::BufReader, marker::PhantomData, process::ExitCode};
|
use std::{
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
io::BufReader,
|
||||||
|
marker::PhantomData,
|
||||||
|
process::ExitCode,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
builtin::{self, Envs},
|
builtin::{self, Envs},
|
||||||
|
command::{ExpandedInputRedirect, ExpandedOutputRedirect},
|
||||||
error::Error,
|
error::Error,
|
||||||
exec::{Execution, InheritStdout, Input, Outcome, Output, exec_pipeline, wait_for_pipeline},
|
exec::{Execution, InheritStdout, Input, Outcome, Output, exec_pipeline, wait_for_pipeline},
|
||||||
syntax::parse::{BinaryOperator, ConditionalExpression, Expression},
|
syntax::parse::{BinaryOperator, ConditionalExpression, Expression},
|
||||||
@@ -13,12 +19,35 @@ pub fn evaluate_pipeline(
|
|||||||
pipeline: &ExpandedPipeline,
|
pipeline: &ExpandedPipeline,
|
||||||
env: &mut Environment,
|
env: &mut Environment,
|
||||||
) -> Result<(Outcome, Option<ExitCode>), Error> {
|
) -> Result<(Outcome, Option<ExitCode>), Error> {
|
||||||
|
assert!(!pipeline.elements.is_empty());
|
||||||
|
|
||||||
let mut executions = vec![];
|
let mut executions = vec![];
|
||||||
let mut stdins = vec![];
|
let mut stdins = vec![];
|
||||||
let mut stdouts = vec![];
|
let mut stdouts = vec![];
|
||||||
|
|
||||||
let pipeline_stdin = Input::Inherit;
|
let first = pipeline.elements.first().unwrap();
|
||||||
let pipeline_stdout = Output::<InheritStdout>::Inherit(PhantomData);
|
let last = pipeline.elements.last().unwrap();
|
||||||
|
|
||||||
|
let pipeline_stdin = match first.stdin.as_ref() {
|
||||||
|
Some(ExpandedInputRedirect::File(path)) => {
|
||||||
|
Input::File(File::open(path).map(BufReader::new)?)
|
||||||
|
}
|
||||||
|
None => Input::Inherit,
|
||||||
|
};
|
||||||
|
let pipeline_stdout = match last.stdout.as_ref() {
|
||||||
|
Some(ExpandedOutputRedirect::File(path, append)) => {
|
||||||
|
let mut opts = OpenOptions::new();
|
||||||
|
opts.create(true).write(true);
|
||||||
|
if *append {
|
||||||
|
opts.append(true);
|
||||||
|
} else {
|
||||||
|
opts.truncate(true);
|
||||||
|
}
|
||||||
|
let file = opts.open(path)?;
|
||||||
|
Output::File(file)
|
||||||
|
}
|
||||||
|
None => Output::<InheritStdout>::Inherit(PhantomData),
|
||||||
|
};
|
||||||
|
|
||||||
stdins.push(pipeline_stdin);
|
stdins.push(pipeline_stdin);
|
||||||
for _ in 1..pipeline.elements.len() {
|
for _ in 1..pipeline.elements.len() {
|
||||||
|
|||||||
@@ -1,19 +1,39 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use env::Environment;
|
use env::Environment;
|
||||||
|
|
||||||
use crate::syntax::parse::{PipelineElement, PipelineExpression};
|
use crate::syntax::{
|
||||||
|
lex::{InputRedirect, OutputRedirectTarget, Redirect, WordToken},
|
||||||
|
parse::{PipelineElement, PipelineExpression},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod env;
|
pub mod env;
|
||||||
pub mod eval;
|
pub mod eval;
|
||||||
|
|
||||||
|
pub enum ExpandedInputRedirect {
|
||||||
|
File(PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ExpandedOutputRedirect {
|
||||||
|
File(PathBuf, bool),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ExpandedPipelineElement {
|
pub struct ExpandedPipelineElement {
|
||||||
pub words: Vec<String>,
|
pub words: Vec<String>,
|
||||||
pub envs: Vec<(String, String)>,
|
pub envs: Vec<(String, String)>,
|
||||||
|
pub stdin: Option<ExpandedInputRedirect>,
|
||||||
|
pub stdout: Option<ExpandedOutputRedirect>,
|
||||||
|
pub stderr: Option<ExpandedOutputRedirect>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExpandedPipeline {
|
pub struct ExpandedPipeline {
|
||||||
pub elements: Vec<ExpandedPipelineElement>,
|
pub elements: Vec<ExpandedPipelineElement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expand_path(word: &WordToken, env: &Environment) -> PathBuf {
|
||||||
|
env.expand(word).join(" ").into()
|
||||||
|
}
|
||||||
|
|
||||||
impl ExpandedPipelineElement {
|
impl ExpandedPipelineElement {
|
||||||
pub fn from_syntax(env: &Environment, element: &PipelineElement) -> Self {
|
pub fn from_syntax(env: &Environment, element: &PipelineElement) -> Self {
|
||||||
// TODO redirects
|
// TODO redirects
|
||||||
@@ -24,6 +44,36 @@ impl ExpandedPipelineElement {
|
|||||||
.collect();
|
.collect();
|
||||||
let mut envs = vec![];
|
let mut envs = vec![];
|
||||||
|
|
||||||
|
let mut stdin = None;
|
||||||
|
let mut stdout = None;
|
||||||
|
let mut stderr = None;
|
||||||
|
|
||||||
|
for redirect in &element.redirects {
|
||||||
|
match redirect {
|
||||||
|
Redirect::Input(input) => match input {
|
||||||
|
InputRedirect::Heredoc(_) => todo!("Heredoc input redirects"),
|
||||||
|
InputRedirect::Filename(filename) => {
|
||||||
|
let path = expand_path(filename, env);
|
||||||
|
stdin = Some(ExpandedInputRedirect::File(path));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Redirect::Output(output) => {
|
||||||
|
let source = match output.source {
|
||||||
|
Some("1") | Some("out") | None => &mut stdout,
|
||||||
|
Some("2") | Some("err") => &mut stderr,
|
||||||
|
Some(p) => todo!("Unhandled output redirect source: {p:?}"),
|
||||||
|
};
|
||||||
|
let target = match &output.target {
|
||||||
|
OutputRedirectTarget::Filename(filename) => {
|
||||||
|
ExpandedOutputRedirect::File(expand_path(filename, env), output.append)
|
||||||
|
}
|
||||||
|
OutputRedirectTarget::Descriptor(_) => todo!("Output redirect to FD"),
|
||||||
|
};
|
||||||
|
*source = Some(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
words.retain(|word| {
|
words.retain(|word| {
|
||||||
if let Some((key, value)) = word.split_once('=')
|
if let Some((key, value)) = word.split_once('=')
|
||||||
&& !key.ends_with(' ')
|
&& !key.ends_with(' ')
|
||||||
@@ -36,7 +86,13 @@ impl ExpandedPipelineElement {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self { words, envs }
|
Self {
|
||||||
|
words,
|
||||||
|
envs,
|
||||||
|
stdin,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ impl<'e> CargoBuilder<'e> {
|
|||||||
command
|
command
|
||||||
.arg(arg)
|
.arg(arg)
|
||||||
.arg("-Zbuild-std=core,alloc")
|
.arg("-Zbuild-std=core,alloc")
|
||||||
|
.arg("-Zjson-target-spec")
|
||||||
.arg(&format!("-Zbuild-std-features={build_std_features}"))
|
.arg(&format!("-Zbuild-std-features={build_std_features}"))
|
||||||
.arg(&format!("--target={target}"));
|
.arg(&format!("--target={target}"));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user