Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d5f70c6a7c | |||
| 1736582613 | |||
| 1f670a66a4 | |||
| 60f3572fec | |||
| f5d3809f37 | |||
| 1261c037f8 | |||
| fd8e1df696 | |||
| befdf63c7c | |||
| 679ac51602 | |||
| 7909fa3808 | |||
| 4b98ec1ce2 | |||
| 37ad3702d0 | |||
| 505a57abda | |||
| 677ec96c08 | |||
| 7064a21d8d | |||
| 6d31142258 | |||
| d7df44b1d9 | |||
| 1552bb27f4 | |||
| 7f256cf3a6 | |||
| f416414b93 | |||
| 0386e3916d | |||
| 31176fb5aa | |||
| 1411f1eed0 | |||
| 4c5309fa15 | |||
| 1012abceec | |||
| a6a6dba155 | |||
| 7f46da9ebd | |||
| 1a87bc3666 | |||
| 4f648142c8 | |||
| 0e979a9e09 | |||
| ed9d7a7145 | |||
| 6b5dd9f673 | |||
| 58dbaddf11 | |||
| 218e391505 | |||
| 2a49c655c2 | |||
| d108494314 | |||
| 195c19e225 | |||
| 21a8361eec | |||
| fd0a3f50ea | |||
| c72c8f88d7 | |||
| e44b616998 | |||
| 7abb950a8f | |||
| 57143f9d8d | |||
| 3491e1a227 | |||
| 61644bdef5 | |||
| e1b905c65a | |||
| 9855142c25 | |||
| bb4e805733 | |||
| ecf1c18240 | |||
| a87c8a7ee2 | |||
| 312458b8f0 |
Generated
+69
-47
@@ -25,7 +25,6 @@ dependencies = [
|
||||
name = "abi-lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
@@ -33,7 +32,6 @@ dependencies = [
|
||||
name = "abi-serde"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@@ -407,15 +405,6 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.146"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97117b1434b79833f39a5fabdf82f890bd98c1988334dea1cb67f7e627fa311"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.10"
|
||||
@@ -469,6 +458,7 @@ dependencies = [
|
||||
name = "device-api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"device-api-macros",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
@@ -499,7 +489,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "discrete_range_map"
|
||||
version = "0.6.2"
|
||||
source = "git+https://git.alnyan.me/yggdrasil/discrete_range_map.git#6b54882b190b02fb013f22cbe9664f6273e846ae"
|
||||
source = "git+https://git.alnyan.me/yggdrasil/discrete_range_map.git#0c932f7cc7ff55253519e3465ddeea8fe69083be"
|
||||
dependencies = [
|
||||
"btree_monstrousity",
|
||||
"either",
|
||||
@@ -1199,9 +1189,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
version = "0.2.180"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@@ -1290,9 +1280,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.8"
|
||||
source = "git+https://git.alnyan.me/yggdrasil/libm.git#ace5825d9683d2bf4a71c8f18f2c854660c297b2"
|
||||
source = "git+https://git.alnyan.me/yggdrasil/libm.git#78b62c33fc6a56b6c063c19bbffc5224616b7028"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
@@ -1329,7 +1318,6 @@ version = "0.1.0"
|
||||
name = "libyalloc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
"rustc-std-workspace-core",
|
||||
"yggdrasil-rt",
|
||||
@@ -1353,6 +1341,12 @@ version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.4"
|
||||
@@ -1787,7 +1781,20 @@ dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.11.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
@@ -2004,15 +2011,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.16.0"
|
||||
version = "3.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
|
||||
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom 0.3.1",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"rustix 1.1.3",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
@@ -2388,7 +2394,7 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"rustix",
|
||||
"rustix 0.38.44",
|
||||
"winsafe",
|
||||
]
|
||||
|
||||
@@ -2557,8 +2563,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"rustix",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"rustix 0.38.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2589,6 +2595,7 @@ dependencies = [
|
||||
"semver 1.0.25",
|
||||
"serde",
|
||||
"tar",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"walkdir",
|
||||
@@ -2657,6 +2664,7 @@ dependencies = [
|
||||
name = "ygg_driver_bsp_bcm283x"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytemuck",
|
||||
"device-api",
|
||||
"device-tree",
|
||||
@@ -2702,6 +2710,25 @@ dependencies = [
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_bsp_sifive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytemuck",
|
||||
"device-api",
|
||||
"device-tree",
|
||||
"futures-util",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
"libk-util",
|
||||
"log",
|
||||
"static_assertions",
|
||||
"tock-registers",
|
||||
"ygg_driver_net_core",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_fat32"
|
||||
version = "0.1.0"
|
||||
@@ -2733,6 +2760,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytemuck",
|
||||
"device-api",
|
||||
"kernel-fs",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
@@ -2749,6 +2777,7 @@ name = "ygg_driver_net_igbe"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"device-api",
|
||||
"futures-util",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
"libk-util",
|
||||
@@ -2855,6 +2884,19 @@ dependencies = [
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_serial_8250"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"device-api",
|
||||
"device-tree",
|
||||
"kernel-arch-x86",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
"libk-util",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_usb"
|
||||
version = "0.1.0"
|
||||
@@ -2872,25 +2914,6 @@ dependencies = [
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_usb_dwc2"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"atomic_enum",
|
||||
"bytemuck",
|
||||
"device-api",
|
||||
"device-tree",
|
||||
"futures-util",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
"libk-util",
|
||||
"log",
|
||||
"tock-registers",
|
||||
"ygg_driver_usb",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_usb_xhci"
|
||||
version = "0.1.0"
|
||||
@@ -2987,7 +3010,6 @@ dependencies = [
|
||||
"abi-lib",
|
||||
"abi-serde",
|
||||
"bytemuck",
|
||||
"compiler_builtins",
|
||||
"prettyplease",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
@@ -3038,6 +3060,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",
|
||||
@@ -3047,8 +3070,8 @@ dependencies = [
|
||||
"ygg_driver_net_stmmac",
|
||||
"ygg_driver_nvme",
|
||||
"ygg_driver_pci",
|
||||
"ygg_driver_serial_8250",
|
||||
"ygg_driver_usb",
|
||||
"ygg_driver_usb_dwc2",
|
||||
"ygg_driver_usb_xhci",
|
||||
"ygg_driver_virtio_blk",
|
||||
"ygg_driver_virtio_gpu",
|
||||
@@ -3064,7 +3087,6 @@ dependencies = [
|
||||
"abi-lib",
|
||||
"abi-serde",
|
||||
"cc",
|
||||
"compiler_builtins",
|
||||
"libm",
|
||||
"prettyplease",
|
||||
"rustc-std-workspace-alloc",
|
||||
|
||||
@@ -89,6 +89,7 @@ features = ["no_std_stream"]
|
||||
|
||||
[workspace.lints.rust]
|
||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(rust_analyzer)'] }
|
||||
unsafe_op_in_unsafe_fn.level = "deny"
|
||||
[workspace.lints.clippy]
|
||||
derivable_impls = { level = "allow" }
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ Main features
|
||||
-------------
|
||||
|
||||
* Architecture support:
|
||||
* [aarch64](kernel/src/arch/aarch64)
|
||||
* [x86_64](kernel/src/arch/x86_64)
|
||||
* [i686](kernel/src/arch/i686) (Pentium Pro and later)
|
||||
* [aarch64](kernel/arch/aarch64)
|
||||
* [x86_64](kernel/arch/x86_64)
|
||||
* [riscv64](kernel/arch/riscv64)
|
||||
* Core features:
|
||||
* Kernel/userspace preemptive multithreading
|
||||
* Kernel-space multitasking with `async`/`await` runtime
|
||||
@@ -24,6 +24,7 @@ Main features
|
||||
* sysfs
|
||||
* devfs
|
||||
* ext2
|
||||
* fat32 (read-only)
|
||||
* Userspace features:
|
||||
* [Kernel-user ABI](lib/abi-def/yggdrasil.abi) generated from a rust-like description language
|
||||
* Sanitized system calls better suited for use in Rust
|
||||
@@ -33,33 +34,37 @@ Main features
|
||||
* Synchronization primitives through futex-like interface
|
||||
* Unix-like signals and exceptions
|
||||
* [Dynamic loader](userspace/dyn-loader) for linking with shared libraries
|
||||
* Runs DOOM
|
||||
* Hardware features:
|
||||
* PCI Express devices
|
||||
* NVMe drive support (read/write, currently x86_64 only, due to lack of MSI-X support on aarch64/i686).
|
||||
* AHCI SATA drive support (read/write)
|
||||
* NVMe drive support
|
||||
* AHCI SATA drive support
|
||||
* xHCI USB host controller
|
||||
* VirtIO Network + GPU framebuffer support
|
||||
* USB HID keyboards
|
||||
* USB device support
|
||||
* Hub driver
|
||||
* HID keyboards and mice
|
||||
* Mass storage (BBB)
|
||||
* Partial hardware support for aarch64/riscv64 SBCs like StarFive VisionFive 2 and Raspberry Pi 4
|
||||
|
||||
aarch64-specific:
|
||||
|
||||
* PSCI for SMP start-up and power control
|
||||
* PL011 serial port
|
||||
* PL061 GPIO controller
|
||||
* PL031 RTC
|
||||
* ARM generic timer as system/monotonic timer
|
||||
* GICv2 IRQ controller
|
||||
* GICv2 IRQ controller + GICv2m MSI interrupts
|
||||
|
||||
x86-specific:
|
||||
|
||||
* Boot options:
|
||||
* x86_64: UEFI [yboot](https://git.alnyan.me/yggdrasil/yboot)
|
||||
* i686: multiboot/grub
|
||||
* Boot via UEFI [yboot](https://git.alnyan.me/yggdrasil/yboot)
|
||||
* I/O and Local APIC IRQ controllers
|
||||
* PS/2 keyboard
|
||||
* HPET for x86_64
|
||||
* i8253-based timer for i686 or as a fallback timer
|
||||
* i8253 as a fallback timer
|
||||
* COM ports
|
||||
* ACPI, [work in progress](https://github.com/rust-osdev/acpi), mostly broken
|
||||
on real hardware, so currently disabled
|
||||
* ACPI, [work in progress](https://github.com/rust-osdev/acpi)
|
||||
* ACPI shutdown
|
||||
* PCI IRQ pin routing
|
||||
* Events like power button, etc.
|
||||
@@ -122,7 +127,6 @@ General plans (in no particular order)
|
||||
2. Get a full LLVM build to work
|
||||
3. Get rustc to work
|
||||
4. Get self-hosted
|
||||
5. Run doom (?)
|
||||
|
||||
In addition to eternal code cleanup, I've been doing quite a lazy job at that lately...
|
||||
|
||||
|
||||
@@ -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}
|
||||
+3
-2
@@ -33,10 +33,11 @@ $ booti ${loadaddr} ${initrd_addr_r}:<initrd-size> ${fdt_addr_r}
|
||||
|
||||
env set ipaddr 13.0.0.2; env set initrd_addr_r 0x70000000; tftpboot ${initrd_addr_r} 13.0.0.1:initrd.img; tftpboot ${loadaddr} 13.0.0.1:yggdrasil-kernel.bin; load mmc 1:3 ${fdt_addr_r} dtbs/6.6.20-starfive/starfive/${fdtfile}; fdt resize; booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
|
||||
|
||||
env set ipaddr 13.0.0.2; env set initrd_addr_r 0x70000000; 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:vf2.dtb; fdt resize; booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
|
||||
|
||||
#### For DHCP boot with BUILD-MACHINE-IP-ADDR 192.168.88.10
|
||||
|
||||
dhcp
|
||||
dhcp; env set initrd_addr_r 0x70000000; tftpboot ${initrd_addr_r} 192.168.88.10:initrd.img; tftpboot ${loadaddr} 192.168.88.10:yggdrasil-kernel.bin; load mmc 1:3 ${fdt_addr_r} dtbs/6.6.20-starfive/starfive/${fdtfile}; fdt resize; booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
|
||||
dhcp; env set initrd_addr_r 0x70000000; tftpboot ${initrd_addr_r} 192.168.88.10:initrd.img; tftpboot ${loadaddr} 192.168.88.10:yggdrasil-kernel.bin; tftpboot ${fdt_addr_r} 192.168.88.10:vf2.dtb; fdt resize; booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
|
||||
|
||||
|
||||
Missing drivers:
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
"arch": "aarch64",
|
||||
"os": "none",
|
||||
"abi": "softfloat",
|
||||
"rustc-abi": "softfloat",
|
||||
"llvm-target": "aarch64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
|
||||
"max-atomic-width": 128,
|
||||
"target-pointer-width": "64",
|
||||
"target-pointer-width": 64,
|
||||
"features": "+v8a,+strict-align,-neon,-fp-armv8",
|
||||
|
||||
"disable-redzone": true,
|
||||
|
||||
Binary file not shown.
@@ -264,16 +264,15 @@
|
||||
compatible = "gpio-keys";
|
||||
|
||||
poweroff {
|
||||
gpios = <0x8007 0x03 0x00>;
|
||||
gpios = <&gpio 0x03 0x00>;
|
||||
linux,code = <0x74>;
|
||||
label = "GPIO Key Poweroff";
|
||||
};
|
||||
};
|
||||
|
||||
pl061@9030000 {
|
||||
phandle = <0x8007>;
|
||||
gpio: pl061@9030000 {
|
||||
clock-names = "apb_pclk";
|
||||
clocks = <0x8000>;
|
||||
clocks = <&clk_24mhz>;
|
||||
interrupts = <0x00 0x07 0x04>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <0x02>;
|
||||
@@ -299,15 +298,15 @@
|
||||
|
||||
pl031@9010000 {
|
||||
clock-names = "apb_pclk";
|
||||
clocks = <0x8000>;
|
||||
clocks = <&clk_24mhz>;
|
||||
interrupts = <0x00 0x02 0x04>;
|
||||
reg = <0x00 0x9010000 0x00 0x1000>;
|
||||
compatible = "arm,pl031", "arm,primecell";
|
||||
};
|
||||
|
||||
pl011@9000000 {
|
||||
uart0: pl011@9000000 {
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
clocks = <0x8000 0x8000>;
|
||||
clocks = <&clk_24mhz &clk_24mhz>;
|
||||
interrupts = <0x00 0x01 0x04>;
|
||||
reg = <0x00 0x9000000 0x00 0x1000>;
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
@@ -411,8 +410,7 @@
|
||||
compatible = "arm,armv8-timer", "arm,armv7-timer";
|
||||
};
|
||||
|
||||
apb-pclk {
|
||||
phandle = <0x8000>;
|
||||
clk_24mhz: apb-pclk {
|
||||
clock-output-names = "clk24mhz";
|
||||
clock-frequency = <0x16e3600>;
|
||||
#clock-cells = <0x00>;
|
||||
@@ -0,0 +1,669 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include <aarch64/gicv2.h>
|
||||
|
||||
/memreserve/ 0x0000000000000000 0x0000000000001000;
|
||||
/ {
|
||||
compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
|
||||
model = "Raspberry Pi 4 Model B";
|
||||
#address-cells = <0x02>;
|
||||
#size-cells = <0x01>;
|
||||
interrupt-parent = <&gicv2>;
|
||||
|
||||
aliases {
|
||||
serial0 = "/soc/serial@7e201000";
|
||||
serial1 = "/soc/serial@7e215040";
|
||||
blconfig = "/reserved-memory/nvram@0";
|
||||
};
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial1:115200n8";
|
||||
};
|
||||
|
||||
reserved-memory {
|
||||
#address-cells = <0x02>;
|
||||
#size-cells = <0x01>;
|
||||
ranges;
|
||||
|
||||
linux,cma {
|
||||
compatible = "shared-dma-pool";
|
||||
size = <0x4000000>;
|
||||
reusable;
|
||||
linux,cma-default;
|
||||
alloc-ranges = <0x00 0x00 0x40000000>;
|
||||
};
|
||||
|
||||
nvram@0 {
|
||||
compatible = "raspberrypi,bootloader-config", "nvmem-rmem";
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x01>;
|
||||
reg = <0x00 0x00 0x00>;
|
||||
no-map;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x01>;
|
||||
ranges = <0x7e000000 0x00 0xfe000000 0x01800000>,
|
||||
<0x7c000000 0x00 0xfc000000 0x02000000>,
|
||||
<0x40000000 0x00 0xff800000 0x00800000>;
|
||||
dma-ranges = <0xc0000000 0x00 0x00 0x40000000>;
|
||||
|
||||
timer@7e003000 {
|
||||
compatible = "brcm,bcm2835-system-timer";
|
||||
reg = <0x7e003000 0x1000>;
|
||||
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clock-frequency = <0xf4240>;
|
||||
};
|
||||
|
||||
txp@7e004000 {
|
||||
compatible = "brcm,bcm2835-txp";
|
||||
reg = <0x7e004000 0x20>;
|
||||
interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
dsi0: dsi@7e209000 {
|
||||
compatible = "brcm,bcm2835-dsi0";
|
||||
reg = <0x7e209000 0x78>;
|
||||
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
#clock-cells = <0x01>;
|
||||
clocks = <&cprman 0x20>,
|
||||
<&cprman 0x2f>,
|
||||
<&cprman 0x31>;
|
||||
clock-names = "phy", "escape", "pixel";
|
||||
clock-output-names = "dsi0_byte", "dsi0_ddr2", "dsi0_ddr";
|
||||
status = "disabled";
|
||||
power-domains = <&power 0x11>;
|
||||
};
|
||||
|
||||
dsi1: dsi@7e700000 {
|
||||
compatible = "brcm,bcm2711-dsi1";
|
||||
reg = <0x7e700000 0x8c>;
|
||||
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
#clock-cells = <0x01>;
|
||||
clocks = <&cprman 0x23>,
|
||||
<&cprman 0x30>,
|
||||
<&cprman 0x32>;
|
||||
clock-names = "phy", "escape", "pixel";
|
||||
clock-output-names = "dsi1_byte", "dsi1_ddr2", "dsi1_ddr";
|
||||
status = "disabled";
|
||||
power-domains = <&power 0x12>;
|
||||
};
|
||||
|
||||
cprman: cprman@7e101000 {
|
||||
compatible = "brcm,bcm2711-cprman";
|
||||
#clock-cells = <0x01>;
|
||||
reg = <0x7e101000 0x2000>;
|
||||
clocks = <&clk_osc>,
|
||||
<&dsi0 0x00>,
|
||||
<&dsi0 0x01>,
|
||||
<&dsi0 0x02>,
|
||||
<&dsi1 0x00>,
|
||||
<&dsi1 0x01>,
|
||||
<&dsi1 0x02>;
|
||||
};
|
||||
|
||||
mbox: mailbox@7e00b880 {
|
||||
compatible = "brcm,bcm2835-mbox";
|
||||
reg = <0x7e00b880 0x40>;
|
||||
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#mbox-cells = <0x00>;
|
||||
};
|
||||
|
||||
gpio: gpio@7e200000 {
|
||||
compatible = "brcm,bcm2711-gpio";
|
||||
reg = <0x7e200000 0xb4>;
|
||||
interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <0x02>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <0x02>;
|
||||
pinctrl-names = "default";
|
||||
bootph-all;
|
||||
|
||||
// UART
|
||||
uart0_ctsrts_gpio30: uart0_ctsrts_gpio30 {
|
||||
brcm,pins = <30>, <31>;
|
||||
brcm,pull = <2>, <0>;
|
||||
brcm,function = <7>;
|
||||
};
|
||||
uart0_gpio32: uart0_gpio32 {
|
||||
brcm,pins = <32>, <33>;
|
||||
brcm,pull = <0>, <2>;
|
||||
brcm,function = <8>;
|
||||
};
|
||||
uart1_gpio14: uart1_gpio14 {
|
||||
brcm,pins = <14>, <15>;
|
||||
brcm,function = <2>;
|
||||
bootph-all;
|
||||
};
|
||||
uart2_gpio: uart2_pins {
|
||||
brcm,pins = <0>, <1>;
|
||||
brcm,function = <3>;
|
||||
brcm,pull = <0>, <2>;
|
||||
};
|
||||
|
||||
// I²C
|
||||
i2c0if_gpio0: i2c0if-gpio0 {
|
||||
brcm,pins = <0>, <1>;
|
||||
brcm,function = <4>;
|
||||
};
|
||||
i2c0if_gpio44: i2c0if-gpio44 {
|
||||
brcm,pins = <44>, <45>;
|
||||
brcm,function = <5>;
|
||||
};
|
||||
i2c1_gpio: i2c1 {
|
||||
brcm,pins = <2>, <3>;
|
||||
brcm,function = <4>;
|
||||
brcm,pull = <2>;
|
||||
};
|
||||
i2c3_gpio: i2c3 {
|
||||
brcm,pins = <4>, <5>;
|
||||
brcm,function = <2>;
|
||||
brcm,pull = <2>;
|
||||
};
|
||||
i2c4_gpio: i2c4 {
|
||||
brcm,pins = <8>, <9>;
|
||||
brcm,function = <2>;
|
||||
brcm,pull = <2>;
|
||||
};
|
||||
i2c5_gpio: i2c5 {
|
||||
brcm,pins = <12>, <13>;
|
||||
brcm,function = <2>;
|
||||
brcm,pull = <2>;
|
||||
};
|
||||
i2c6_gpio: i2c6 {
|
||||
brcm,pins = <22>, <23>;
|
||||
brcm,function = <2>;
|
||||
brcm,pull = <2>;
|
||||
};
|
||||
|
||||
// SPI
|
||||
spi0_gpio: spi0_pins {
|
||||
brcm,pins = <9>, <10>, <11>;
|
||||
brcm,function = <4>;
|
||||
};
|
||||
spi0_cs_gpio: spi0_cs_pins {
|
||||
brcm,pins = <8>, <7>;
|
||||
brcm,function = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
uart0: serial@7e201000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201000 0x200>;
|
||||
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x13>,
|
||||
<&cprman 0x14>;
|
||||
clock-names = "uartclk",
|
||||
"apb_pclk";
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart0_ctsrts_gpio30>, <&uart0_gpio32>;
|
||||
uart-has-rtscts;
|
||||
status = "okay";
|
||||
skip-init;
|
||||
bootph-all;
|
||||
};
|
||||
|
||||
aux: aux@7e215000 {
|
||||
compatible = "brcm,bcm2835-aux";
|
||||
#clock-cells = <0x01>;
|
||||
reg = <0x7e215000 0x08>;
|
||||
clocks = <&cprman 0x14>;
|
||||
};
|
||||
|
||||
uart1: serial@7e215040 {
|
||||
compatible = "brcm,bcm2835-aux-uart";
|
||||
reg = <0x7e215040 0x40>;
|
||||
interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&aux 0x00>;
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart1_gpio14>;
|
||||
skip-init;
|
||||
bootph-all;
|
||||
};
|
||||
|
||||
i2c0if: i2c@7e205000 {
|
||||
compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
|
||||
reg = <0x7e205000 0x200>;
|
||||
interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x14>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
status = "disabled";
|
||||
clock-frequency = <0x186a0>;
|
||||
};
|
||||
|
||||
i2c0mux: i2c0mux {
|
||||
compatible = "i2c-mux-pinctrl";
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
i2c-parent = <&i2c0if>;
|
||||
status = "disabled";
|
||||
pinctrl-names = "i2c0", "i2c_csi_dsi";
|
||||
pinctrl-0 = <&i2c0if_gpio0>;
|
||||
pinctrl-1 = <&i2c0if_gpio44>;
|
||||
|
||||
i2c0: i2c@0 {
|
||||
reg = <0x00>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
};
|
||||
|
||||
i2c_csi_dsi: i2c@1 {
|
||||
reg = <0x01>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
};
|
||||
};
|
||||
i2c1: i2c@7e804000 {
|
||||
compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
|
||||
reg = <0x7e804000 0x1000>;
|
||||
interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x14>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c1_gpio>;
|
||||
clock-frequency = <0x186a0>;
|
||||
};
|
||||
// TODO: memory access crashes on qemu (not implemented?)
|
||||
i2c3: i2c@7e205600 {
|
||||
compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
|
||||
reg = <0x7e205600 0x200>;
|
||||
interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x14>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
status = "disabled";
|
||||
pinctrl-0 = <&i2c3_gpio>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
// TODO: memory access crashes on qemu (not implemented?)
|
||||
i2c4: i2c@7e205800 {
|
||||
compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
|
||||
reg = <0x7e205800 0x200>;
|
||||
interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x14>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
status = "disabled";
|
||||
pinctrl-0 = <&i2c4_gpio>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
// TODO: memory access crashes on qemu (not implemented?)
|
||||
i2c5: i2c@7e205a00 {
|
||||
compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
|
||||
reg = <0x7e205a00 0x200>;
|
||||
interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x14>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
status = "disabled";
|
||||
pinctrl-0 = <&i2c5_gpio>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
// TODO: memory access crashes on qemu (not implemented?)
|
||||
i2c6: i2c@7e205c00 {
|
||||
compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
|
||||
reg = <0x7e205c00 0x200>;
|
||||
interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x14>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
status = "disabled";
|
||||
pinctrl-0 = <&i2c6_gpio>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
spi0: spi@7e204000 {
|
||||
compatible = "brcm,bcm2835-spi";
|
||||
reg = <0x7e204000 0x200>;
|
||||
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x14>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
status = "okay";
|
||||
dmas = <&dma 0x06>,
|
||||
<&dma 0x07>;
|
||||
dma-names = "tx", "rx";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spi0_gpio>, <&spi0_cs_gpio>;
|
||||
cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
|
||||
|
||||
spi0_0: spidev@0 {
|
||||
compatible = "spidev";
|
||||
reg = <0x00>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
spi-max-frequency = <125000000>;
|
||||
};
|
||||
|
||||
spi0_1: spidev@1 {
|
||||
compatible = "spidev";
|
||||
reg = <0x01>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
spi-max-frequency = <125000000>;
|
||||
};
|
||||
};
|
||||
|
||||
l1_intc: local_intc@40000000 {
|
||||
compatible = "brcm,bcm2836-l1-intc";
|
||||
reg = <0x40000000 0x100>;
|
||||
};
|
||||
|
||||
gicv2: interrupt-controller@40041000 {
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <0x03>;
|
||||
compatible = "arm,gic-400";
|
||||
reg = <0x40041000 0x1000>,
|
||||
<0x40042000 0x2000>,
|
||||
<0x40044000 0x2000>,
|
||||
<0x40046000 0x2000>;
|
||||
interrupts = <GIC_PPI 9 (IRQ_TYPE_LEVEL_HIGH | GIC_CPU_MASK_SIMPLE(4))>;
|
||||
};
|
||||
|
||||
avs_monitor: avs-monitor@7d5d2000 {
|
||||
compatible = "brcm,bcm2711-avs-monitor", "syscon", "simple-mfd";
|
||||
reg = <0x7d5d2000 0xf00>;
|
||||
};
|
||||
|
||||
dma: dma@7e007000 {
|
||||
compatible = "brcm,bcm2835-dma";
|
||||
reg = <0x7e007000 0xb00>;
|
||||
interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "dma0",
|
||||
"dma1",
|
||||
"dma2",
|
||||
"dma3",
|
||||
"dma4",
|
||||
"dma5",
|
||||
"dma6",
|
||||
"dma7",
|
||||
"dma8",
|
||||
"dma9",
|
||||
"dma10";
|
||||
#dma-cells = <0x01>;
|
||||
brcm,dma-channel-mask = <0x7f5>;
|
||||
};
|
||||
|
||||
pm_wdt: watchdog@7e100000 {
|
||||
compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
|
||||
#power-domain-cells = <0x01>;
|
||||
#reset-cells = <0x01>;
|
||||
reg = <0x7e100000 0x114>,
|
||||
<0x7e00a000 0x24>,
|
||||
<0x7ec11000 0x20>;
|
||||
clocks = <&cprman 0x15>,
|
||||
<&cprman 0x1d>,
|
||||
<&cprman 0x17>,
|
||||
<&cprman 0x16>;
|
||||
clock-names = "v3d", "peri_image", "h264", "isp";
|
||||
system-power-controller;
|
||||
};
|
||||
|
||||
uart2: serial@7e201400 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201400 0x200>;
|
||||
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x13>,
|
||||
<&cprman 0x14>;
|
||||
clock-names = "uartclk",
|
||||
"apb_pclk";
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
pinctrl-0 = <&uart2_gpio>;
|
||||
pinctrl-names = "default";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart3: serial@7e201600 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201600 0x200>;
|
||||
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x13>,
|
||||
<&cprman 0x14>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart4: serial@7e201800 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201800 0x200>;
|
||||
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x13>,
|
||||
<&cprman 0x14>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart5: serial@7e201a00 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201a00 0x200>;
|
||||
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cprman 0x13>,
|
||||
<&cprman 0x14>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
clk_dvp: clock@7ef00000 {
|
||||
compatible = "brcm,brcm2711-dvp";
|
||||
reg = <0x7ef00000 0x10>;
|
||||
clocks = <&clk_108m>;
|
||||
#clock-cells = <0x01>;
|
||||
#reset-cells = <0x01>;
|
||||
};
|
||||
|
||||
l2_intc: interrupt-controller@7ef00100 {
|
||||
compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc";
|
||||
reg = <0x7ef00100 0x30>;
|
||||
interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <0x01>;
|
||||
};
|
||||
|
||||
firmware: firmware {
|
||||
compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x01>;
|
||||
mboxes = <&mbox>;
|
||||
dma-ranges;
|
||||
|
||||
clk_firmware: clocks {
|
||||
compatible = "raspberrypi,firmware-clocks";
|
||||
#clock-cells = <0x01>;
|
||||
};
|
||||
|
||||
gpio_firmware: gpio {
|
||||
compatible = "raspberrypi,firmware-gpio";
|
||||
gpio-controller;
|
||||
#gpio-cells = <0x02>;
|
||||
status = "okay";
|
||||
gpio-line-names = "BT_ON", "WL_ON", "PWR_LED_OFF", "GLOBAL_RESET", "VDD_SD_IO_SEL", "CAM_GPIO", "SD_PWR_ON", "";
|
||||
};
|
||||
|
||||
firmware_reset: reset {
|
||||
compatible = "raspberrypi,firmware-reset";
|
||||
#reset-cells = <0x01>;
|
||||
};
|
||||
};
|
||||
|
||||
power: power {
|
||||
compatible = "raspberrypi,bcm2835-power";
|
||||
firmware = <&firmware>;
|
||||
#power-domain-cells = <0x01>;
|
||||
};
|
||||
|
||||
vchiq: mailbox@7e00b840 {
|
||||
compatible = "brcm,bcm2835-vchiq";
|
||||
reg = <0x7e00b840 0x3c>;
|
||||
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
clocks {
|
||||
clk_osc: clk-osc {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0x00>;
|
||||
clock-output-names = "osc";
|
||||
clock-frequency = <54000000>;
|
||||
};
|
||||
|
||||
clk_usb: clk-usb {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0x00>;
|
||||
clock-output-names = "otg";
|
||||
clock-frequency = <480000000>;
|
||||
};
|
||||
};
|
||||
|
||||
clk_27m: clk-27M {
|
||||
#clock-cells = <0x00>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <27000000>;
|
||||
clock-output-names = "27MHz-clock";
|
||||
};
|
||||
|
||||
clk_108m: clk-108M {
|
||||
#clock-cells = <0x00>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <108000000>;
|
||||
clock-output-names = "108MHz-clock";
|
||||
};
|
||||
|
||||
pmu: arm-pmu {
|
||||
compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3";
|
||||
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-affinity = <0x21>,
|
||||
<0x22>,
|
||||
<0x23>,
|
||||
<0x24>;
|
||||
};
|
||||
|
||||
arm_timer: timer {
|
||||
compatible = "arm,armv8-timer";
|
||||
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
|
||||
<GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
|
||||
<GIC_PPI 15 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
|
||||
<GIC_PPI 16 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
|
||||
arm,cpu-registers-not-fw-configured;
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
enable-method = "brcm,bcm2836-smp";
|
||||
|
||||
cpu0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a72";
|
||||
reg = <0x00>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x00 0xd8>;
|
||||
};
|
||||
|
||||
cpu1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a72";
|
||||
reg = <0x01>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x00 0xe0>;
|
||||
};
|
||||
|
||||
cpu2: cpu@2 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a72";
|
||||
reg = <0x02>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x00 0xe8>;
|
||||
};
|
||||
|
||||
cpu3: cpu@3 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a72";
|
||||
reg = <0x03>;
|
||||
enable-method = "spin-table";
|
||||
cpu-release-addr = <0x00 0xf0>;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led_act: led-act {
|
||||
label = "ACT";
|
||||
default-state = "keep";
|
||||
linux,default-trigger = "heartbeat";
|
||||
gpios = <&gpio 0x2a 0x00>;
|
||||
};
|
||||
|
||||
led_pwr: led-pwr {
|
||||
label = "PWR";
|
||||
gpios = <&gpio_firmware 0x02 0x01>;
|
||||
default-state = "keep";
|
||||
linux,default-trigger = "default-on";
|
||||
};
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x00 0x00 0x00>;
|
||||
};
|
||||
|
||||
sd_io_1v8_reg {
|
||||
compatible = "regulator-gpio";
|
||||
regulator-name = "vdd-sd-io";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
regulator-settling-time-us = <0x1388>;
|
||||
gpios = <&gpio_firmware 0x04 0x00>;
|
||||
states = <3300000 0x01>,
|
||||
<1800000 0x00>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sd_vcc_reg {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc-sd";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
enable-active-high;
|
||||
gpio = <&gpio_firmware 0x06 0x00>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#define GIC_SPI 0
|
||||
#define GIC_PPI 1
|
||||
|
||||
#define GIC_CPU_MASK_RAW(x) ((x) << 8)
|
||||
#define GIC_CPU_MASK_SIMPLE(num) GIC_CPU_MASK_RAW((1 << (num)) - 1)
|
||||
|
||||
#define IRQ_TYPE_NONE 0
|
||||
#define IRQ_TYPE_EDGE_RISING 1
|
||||
#define IRQ_TYPE_EDGE_FALLING 2
|
||||
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)
|
||||
#define IRQ_TYPE_LEVEL_HIGH 4
|
||||
#define IRQ_TYPE_LEVEL_LOW 8
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,319 @@
|
||||
/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>;
|
||||
};
|
||||
|
||||
pwm0: pwm@10020000 {
|
||||
compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
|
||||
reg = <0x00 0x10020000 0x00 0x1000>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <44>, <45>, <46>, <47>;
|
||||
clocks = <&prci CLK_PCLK>;
|
||||
#pwm-cells = <3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pwm1: pwm@10021000 {
|
||||
compatible = "sifive,fu740-c000-pwm", "sifive,pwm0";
|
||||
reg = <0x00 0x10021000 0x00 0x1000>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <48>, <49>, <50>, <51>;
|
||||
clocks = <&prci CLK_PCLK>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
i2c0: i2c@10030000 {
|
||||
compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
|
||||
reg = <0x00 0x10030000 0x00 0x1000>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <52>;
|
||||
clocks = <&prci CLK_PCLK>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
i2c1: i2c@10031000 {
|
||||
compatible = "sifive,fu740-c000-i2c", "sifive,i2c0";
|
||||
reg = <0x00 0x10031000 0x00 0x1000>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <53>;
|
||||
clocks = <&prci CLK_PCLK>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x00 0x80000000 0x04 0x00>;
|
||||
};
|
||||
|
||||
leds: pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
|
||||
green-d12 {
|
||||
label = "green:d12";
|
||||
pwms = <&pwm0 0 7812500 0x01>;
|
||||
active-low = <1>;
|
||||
max-brightness = <255>;
|
||||
linux,default-trigger = "none";
|
||||
};
|
||||
|
||||
green-d2 {
|
||||
label = "green:d2";
|
||||
pwms = <&pwm0 1 7812500 0x01>;
|
||||
active-low = <1>;
|
||||
max-brightness = <255>;
|
||||
linux,default-trigger = "none";
|
||||
};
|
||||
|
||||
red-d2 {
|
||||
label = "red:d2";
|
||||
pwms = <&pwm0 2 7812500 0x01>;
|
||||
active-low = <0x01>;
|
||||
max-brightness = <0xff>;
|
||||
linux,default-trigger = "none";
|
||||
};
|
||||
|
||||
blue-d2 {
|
||||
label = "blue:d2";
|
||||
pwms = <&pwm0 3 7812500 0x01>;
|
||||
active-low = <1>;
|
||||
max-brightness = <255>;
|
||||
linux,default-trigger = "none";
|
||||
};
|
||||
};
|
||||
|
||||
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";
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,308 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||
/*
|
||||
* Copyright (C) 2022 Emil Renner Berthing <kernel@esmil.dk>
|
||||
* Copyright (C) 2022 StarFive Technology Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __JH7110_PINFUNC_H__
|
||||
#define __JH7110_PINFUNC_H__
|
||||
|
||||
/*
|
||||
* mux bits:
|
||||
* | 31 - 24 | 23 - 16 | 15 - 10 | 9 - 8 | 7 - 0 |
|
||||
* | din | dout | doen | function | gpio nr |
|
||||
*
|
||||
* dout: output signal
|
||||
* doen: output enable signal
|
||||
* din: optional input signal, 0xff = none
|
||||
* function: function selector
|
||||
* gpio nr: gpio number, 0 - 63
|
||||
*/
|
||||
#define GPIOMUX(n, dout, doen, din) ( \
|
||||
(((din) & 0xff) << 24) | \
|
||||
(((dout) & 0xff) << 16) | \
|
||||
(((doen) & 0x3f) << 10) | \
|
||||
((n) & 0x3f))
|
||||
|
||||
#define PINMUX(n, func) ((1 << 10) | (((func) & 0x3) << 8) | ((n) & 0xff))
|
||||
|
||||
/* sys_iomux dout */
|
||||
#define GPOUT_LOW 0
|
||||
#define GPOUT_HIGH 1
|
||||
#define GPOUT_SYS_WAVE511_UART_TX 2
|
||||
#define GPOUT_SYS_CAN0_STBY 3
|
||||
#define GPOUT_SYS_CAN0_TST_NEXT_BIT 4
|
||||
#define GPOUT_SYS_CAN0_TST_SAMPLE_POINT 5
|
||||
#define GPOUT_SYS_CAN0_TXD 6
|
||||
#define GPOUT_SYS_USB_DRIVE_VBUS 7
|
||||
#define GPOUT_SYS_QSPI_CS1 8
|
||||
#define GPOUT_SYS_SPDIF 9
|
||||
#define GPOUT_SYS_HDMI_CEC_SDA 10
|
||||
#define GPOUT_SYS_HDMI_DDC_SCL 11
|
||||
#define GPOUT_SYS_HDMI_DDC_SDA 12
|
||||
#define GPOUT_SYS_WATCHDOG 13
|
||||
#define GPOUT_SYS_I2C0_CLK 14
|
||||
#define GPOUT_SYS_I2C0_DATA 15
|
||||
#define GPOUT_SYS_SDIO0_BACK_END_POWER 16
|
||||
#define GPOUT_SYS_SDIO0_CARD_POWER_EN 17
|
||||
#define GPOUT_SYS_SDIO0_CCMD_OD_PULLUP_EN 18
|
||||
#define GPOUT_SYS_SDIO0_RST 19
|
||||
#define GPOUT_SYS_UART0_TX 20
|
||||
#define GPOUT_SYS_HIFI4_JTAG_TDO 21
|
||||
#define GPOUT_SYS_JTAG_TDO 22
|
||||
#define GPOUT_SYS_PDM_MCLK 23
|
||||
#define GPOUT_SYS_PWM_CHANNEL0 24
|
||||
#define GPOUT_SYS_PWM_CHANNEL1 25
|
||||
#define GPOUT_SYS_PWM_CHANNEL2 26
|
||||
#define GPOUT_SYS_PWM_CHANNEL3 27
|
||||
#define GPOUT_SYS_PWMDAC_LEFT 28
|
||||
#define GPOUT_SYS_PWMDAC_RIGHT 29
|
||||
#define GPOUT_SYS_SPI0_CLK 30
|
||||
#define GPOUT_SYS_SPI0_FSS 31
|
||||
#define GPOUT_SYS_SPI0_TXD 32
|
||||
#define GPOUT_SYS_GMAC_PHYCLK 33
|
||||
#define GPOUT_SYS_I2SRX_BCLK 34
|
||||
#define GPOUT_SYS_I2SRX_LRCK 35
|
||||
#define GPOUT_SYS_I2STX0_BCLK 36
|
||||
#define GPOUT_SYS_I2STX0_LRCK 37
|
||||
#define GPOUT_SYS_MCLK 38
|
||||
#define GPOUT_SYS_TDM_CLK 39
|
||||
#define GPOUT_SYS_TDM_SYNC 40
|
||||
#define GPOUT_SYS_TDM_TXD 41
|
||||
#define GPOUT_SYS_TRACE_DATA0 42
|
||||
#define GPOUT_SYS_TRACE_DATA1 43
|
||||
#define GPOUT_SYS_TRACE_DATA2 44
|
||||
#define GPOUT_SYS_TRACE_DATA3 45
|
||||
#define GPOUT_SYS_TRACE_REF 46
|
||||
#define GPOUT_SYS_CAN1_STBY 47
|
||||
#define GPOUT_SYS_CAN1_TST_NEXT_BIT 48
|
||||
#define GPOUT_SYS_CAN1_TST_SAMPLE_POINT 49
|
||||
#define GPOUT_SYS_CAN1_TXD 50
|
||||
#define GPOUT_SYS_I2C1_CLK 51
|
||||
#define GPOUT_SYS_I2C1_DATA 52
|
||||
#define GPOUT_SYS_SDIO1_BACK_END_POWER 53
|
||||
#define GPOUT_SYS_SDIO1_CARD_POWER_EN 54
|
||||
#define GPOUT_SYS_SDIO1_CLK 55
|
||||
#define GPOUT_SYS_SDIO1_CMD_OD_PULLUP_EN 56
|
||||
#define GPOUT_SYS_SDIO1_CMD 57
|
||||
#define GPOUT_SYS_SDIO1_DATA0 58
|
||||
#define GPOUT_SYS_SDIO1_DATA1 59
|
||||
#define GPOUT_SYS_SDIO1_DATA2 60
|
||||
#define GPOUT_SYS_SDIO1_DATA3 61
|
||||
#define GPOUT_SYS_SDIO1_DATA4 62
|
||||
#define GPOUT_SYS_SDIO1_DATA5 63
|
||||
#define GPOUT_SYS_SDIO1_DATA6 64
|
||||
#define GPOUT_SYS_SDIO1_DATA7 65
|
||||
#define GPOUT_SYS_SDIO1_RST 66
|
||||
#define GPOUT_SYS_UART1_RTS 67
|
||||
#define GPOUT_SYS_UART1_TX 68
|
||||
#define GPOUT_SYS_I2STX1_SDO0 69
|
||||
#define GPOUT_SYS_I2STX1_SDO1 70
|
||||
#define GPOUT_SYS_I2STX1_SDO2 71
|
||||
#define GPOUT_SYS_I2STX1_SDO3 72
|
||||
#define GPOUT_SYS_SPI1_CLK 73
|
||||
#define GPOUT_SYS_SPI1_FSS 74
|
||||
#define GPOUT_SYS_SPI1_TXD 75
|
||||
#define GPOUT_SYS_I2C2_CLK 76
|
||||
#define GPOUT_SYS_I2C2_DATA 77
|
||||
#define GPOUT_SYS_UART2_RTS 78
|
||||
#define GPOUT_SYS_UART2_TX 79
|
||||
#define GPOUT_SYS_SPI2_CLK 80
|
||||
#define GPOUT_SYS_SPI2_FSS 81
|
||||
#define GPOUT_SYS_SPI2_TXD 82
|
||||
#define GPOUT_SYS_I2C3_CLK 83
|
||||
#define GPOUT_SYS_I2C3_DATA 84
|
||||
#define GPOUT_SYS_UART3_TX 85
|
||||
#define GPOUT_SYS_SPI3_CLK 86
|
||||
#define GPOUT_SYS_SPI3_FSS 87
|
||||
#define GPOUT_SYS_SPI3_TXD 88
|
||||
#define GPOUT_SYS_I2C4_CLK 89
|
||||
#define GPOUT_SYS_I2C4_DATA 90
|
||||
#define GPOUT_SYS_UART4_RTS 91
|
||||
#define GPOUT_SYS_UART4_TX 92
|
||||
#define GPOUT_SYS_SPI4_CLK 93
|
||||
#define GPOUT_SYS_SPI4_FSS 94
|
||||
#define GPOUT_SYS_SPI4_TXD 95
|
||||
#define GPOUT_SYS_I2C5_CLK 96
|
||||
#define GPOUT_SYS_I2C5_DATA 97
|
||||
#define GPOUT_SYS_UART5_RTS 98
|
||||
#define GPOUT_SYS_UART5_TX 99
|
||||
#define GPOUT_SYS_SPI5_CLK 100
|
||||
#define GPOUT_SYS_SPI5_FSS 101
|
||||
#define GPOUT_SYS_SPI5_TXD 102
|
||||
#define GPOUT_SYS_I2C6_CLK 103
|
||||
#define GPOUT_SYS_I2C6_DATA 104
|
||||
#define GPOUT_SYS_SPI6_CLK 105
|
||||
#define GPOUT_SYS_SPI6_FSS 106
|
||||
#define GPOUT_SYS_SPI6_TXD 107
|
||||
|
||||
/* aon_iomux dout */
|
||||
#define GPOUT_AON_CLK_32K_OUT 2
|
||||
#define GPOUT_AON_PTC0_PWM4 3
|
||||
#define GPOUT_AON_PTC0_PWM5 4
|
||||
#define GPOUT_AON_PTC0_PWM6 5
|
||||
#define GPOUT_AON_PTC0_PWM7 6
|
||||
#define GPOUT_AON_CLK_GCLK0 7
|
||||
#define GPOUT_AON_CLK_GCLK1 8
|
||||
#define GPOUT_AON_CLK_GCLK2 9
|
||||
|
||||
/* sys_iomux doen */
|
||||
#define GPOEN_ENABLE 0
|
||||
#define GPOEN_DISABLE 1
|
||||
#define GPOEN_SYS_HDMI_CEC_SDA 2
|
||||
#define GPOEN_SYS_HDMI_DDC_SCL 3
|
||||
#define GPOEN_SYS_HDMI_DDC_SDA 4
|
||||
#define GPOEN_SYS_I2C0_CLK 5
|
||||
#define GPOEN_SYS_I2C0_DATA 6
|
||||
#define GPOEN_SYS_HIFI4_JTAG_TDO 7
|
||||
#define GPOEN_SYS_JTAG_TDO 8
|
||||
#define GPOEN_SYS_PWM0_CHANNEL0 9
|
||||
#define GPOEN_SYS_PWM0_CHANNEL1 10
|
||||
#define GPOEN_SYS_PWM0_CHANNEL2 11
|
||||
#define GPOEN_SYS_PWM0_CHANNEL3 12
|
||||
#define GPOEN_SYS_SPI0_NSSPCTL 13
|
||||
#define GPOEN_SYS_SPI0_NSSP 14
|
||||
#define GPOEN_SYS_TDM_SYNC 15
|
||||
#define GPOEN_SYS_TDM_TXD 16
|
||||
#define GPOEN_SYS_I2C1_CLK 17
|
||||
#define GPOEN_SYS_I2C1_DATA 18
|
||||
#define GPOEN_SYS_SDIO1_CMD 19
|
||||
#define GPOEN_SYS_SDIO1_DATA0 20
|
||||
#define GPOEN_SYS_SDIO1_DATA1 21
|
||||
#define GPOEN_SYS_SDIO1_DATA2 22
|
||||
#define GPOEN_SYS_SDIO1_DATA3 23
|
||||
#define GPOEN_SYS_SDIO1_DATA4 24
|
||||
#define GPOEN_SYS_SDIO1_DATA5 25
|
||||
#define GPOEN_SYS_SDIO1_DATA6 26
|
||||
#define GPOEN_SYS_SDIO1_DATA7 27
|
||||
#define GPOEN_SYS_SPI1_NSSPCTL 28
|
||||
#define GPOEN_SYS_SPI1_NSSP 29
|
||||
#define GPOEN_SYS_I2C2_CLK 30
|
||||
#define GPOEN_SYS_I2C2_DATA 31
|
||||
#define GPOEN_SYS_SPI2_NSSPCTL 32
|
||||
#define GPOEN_SYS_SPI2_NSSP 33
|
||||
#define GPOEN_SYS_I2C3_CLK 34
|
||||
#define GPOEN_SYS_I2C3_DATA 35
|
||||
#define GPOEN_SYS_SPI3_NSSPCTL 36
|
||||
#define GPOEN_SYS_SPI3_NSSP 37
|
||||
#define GPOEN_SYS_I2C4_CLK 38
|
||||
#define GPOEN_SYS_I2C4_DATA 39
|
||||
#define GPOEN_SYS_SPI4_NSSPCTL 40
|
||||
#define GPOEN_SYS_SPI4_NSSP 41
|
||||
#define GPOEN_SYS_I2C5_CLK 42
|
||||
#define GPOEN_SYS_I2C5_DATA 43
|
||||
#define GPOEN_SYS_SPI5_NSSPCTL 44
|
||||
#define GPOEN_SYS_SPI5_NSSP 45
|
||||
#define GPOEN_SYS_I2C6_CLK 46
|
||||
#define GPOEN_SYS_I2C6_DATA 47
|
||||
#define GPOEN_SYS_SPI6_NSSPCTL 48
|
||||
#define GPOEN_SYS_SPI6_NSSP 49
|
||||
|
||||
/* aon_iomux doen */
|
||||
#define GPOEN_AON_PTC0_OE_N_4 2
|
||||
#define GPOEN_AON_PTC0_OE_N_5 3
|
||||
#define GPOEN_AON_PTC0_OE_N_6 4
|
||||
#define GPOEN_AON_PTC0_OE_N_7 5
|
||||
|
||||
/* sys_iomux gin */
|
||||
#define GPI_NONE 255
|
||||
|
||||
#define GPI_SYS_WAVE511_UART_RX 0
|
||||
#define GPI_SYS_CAN0_RXD 1
|
||||
#define GPI_SYS_USB_OVERCURRENT 2
|
||||
#define GPI_SYS_SPDIF 3
|
||||
#define GPI_SYS_JTAG_RST 4
|
||||
#define GPI_SYS_HDMI_CEC_SDA 5
|
||||
#define GPI_SYS_HDMI_DDC_SCL 6
|
||||
#define GPI_SYS_HDMI_DDC_SDA 7
|
||||
#define GPI_SYS_HDMI_HPD 8
|
||||
#define GPI_SYS_I2C0_CLK 9
|
||||
#define GPI_SYS_I2C0_DATA 10
|
||||
#define GPI_SYS_SDIO0_CD 11
|
||||
#define GPI_SYS_SDIO0_INT 12
|
||||
#define GPI_SYS_SDIO0_WP 13
|
||||
#define GPI_SYS_UART0_RX 14
|
||||
#define GPI_SYS_HIFI4_JTAG_TCK 15
|
||||
#define GPI_SYS_HIFI4_JTAG_TDI 16
|
||||
#define GPI_SYS_HIFI4_JTAG_TMS 17
|
||||
#define GPI_SYS_HIFI4_JTAG_RST 18
|
||||
#define GPI_SYS_JTAG_TDI 19
|
||||
#define GPI_SYS_JTAG_TMS 20
|
||||
#define GPI_SYS_PDM_DMIC0 21
|
||||
#define GPI_SYS_PDM_DMIC1 22
|
||||
#define GPI_SYS_I2SRX_SDIN0 23
|
||||
#define GPI_SYS_I2SRX_SDIN1 24
|
||||
#define GPI_SYS_I2SRX_SDIN2 25
|
||||
#define GPI_SYS_SPI0_CLK 26
|
||||
#define GPI_SYS_SPI0_FSS 27
|
||||
#define GPI_SYS_SPI0_RXD 28
|
||||
#define GPI_SYS_JTAG_TCK 29
|
||||
#define GPI_SYS_MCLK_EXT 30
|
||||
#define GPI_SYS_I2SRX_BCLK 31
|
||||
#define GPI_SYS_I2SRX_LRCK 32
|
||||
#define GPI_SYS_I2STX1_BCLK 33
|
||||
#define GPI_SYS_I2STX1_LRCK 34
|
||||
#define GPI_SYS_TDM_CLK 35
|
||||
#define GPI_SYS_TDM_RXD 36
|
||||
#define GPI_SYS_TDM_SYNC 37
|
||||
#define GPI_SYS_CAN1_RXD 38
|
||||
#define GPI_SYS_I2C1_CLK 39
|
||||
#define GPI_SYS_I2C1_DATA 40
|
||||
#define GPI_SYS_SDIO1_CD 41
|
||||
#define GPI_SYS_SDIO1_INT 42
|
||||
#define GPI_SYS_SDIO1_WP 43
|
||||
#define GPI_SYS_SDIO1_CMD 44
|
||||
#define GPI_SYS_SDIO1_DATA0 45
|
||||
#define GPI_SYS_SDIO1_DATA1 46
|
||||
#define GPI_SYS_SDIO1_DATA2 47
|
||||
#define GPI_SYS_SDIO1_DATA3 48
|
||||
#define GPI_SYS_SDIO1_DATA4 49
|
||||
#define GPI_SYS_SDIO1_DATA5 50
|
||||
#define GPI_SYS_SDIO1_DATA6 51
|
||||
#define GPI_SYS_SDIO1_DATA7 52
|
||||
#define GPI_SYS_SDIO1_STRB 53
|
||||
#define GPI_SYS_UART1_CTS 54
|
||||
#define GPI_SYS_UART1_RX 55
|
||||
#define GPI_SYS_SPI1_CLK 56
|
||||
#define GPI_SYS_SPI1_FSS 57
|
||||
#define GPI_SYS_SPI1_RXD 58
|
||||
#define GPI_SYS_I2C2_CLK 59
|
||||
#define GPI_SYS_I2C2_DATA 60
|
||||
#define GPI_SYS_UART2_CTS 61
|
||||
#define GPI_SYS_UART2_RX 62
|
||||
#define GPI_SYS_SPI2_CLK 63
|
||||
#define GPI_SYS_SPI2_FSS 64
|
||||
#define GPI_SYS_SPI2_RXD 65
|
||||
#define GPI_SYS_I2C3_CLK 66
|
||||
#define GPI_SYS_I2C3_DATA 67
|
||||
#define GPI_SYS_UART3_RX 68
|
||||
#define GPI_SYS_SPI3_CLK 69
|
||||
#define GPI_SYS_SPI3_FSS 70
|
||||
#define GPI_SYS_SPI3_RXD 71
|
||||
#define GPI_SYS_I2C4_CLK 72
|
||||
#define GPI_SYS_I2C4_DATA 73
|
||||
#define GPI_SYS_UART4_CTS 74
|
||||
#define GPI_SYS_UART4_RX 75
|
||||
#define GPI_SYS_SPI4_CLK 76
|
||||
#define GPI_SYS_SPI4_FSS 77
|
||||
#define GPI_SYS_SPI4_RXD 78
|
||||
#define GPI_SYS_I2C5_CLK 79
|
||||
#define GPI_SYS_I2C5_DATA 80
|
||||
#define GPI_SYS_UART5_CTS 81
|
||||
#define GPI_SYS_UART5_RX 82
|
||||
#define GPI_SYS_SPI5_CLK 83
|
||||
#define GPI_SYS_SPI5_FSS 84
|
||||
#define GPI_SYS_SPI5_RXD 85
|
||||
#define GPI_SYS_I2C6_CLK 86
|
||||
#define GPI_SYS_I2C6_DATA 87
|
||||
#define GPI_SYS_SPI6_CLK 88
|
||||
#define GPI_SYS_SPI6_FSS 89
|
||||
#define GPI_SYS_SPI6_RXD 90
|
||||
|
||||
/* aon_iomux gin */
|
||||
#define GPI_AON_PMU_GPIO_WAKEUP_0 0
|
||||
#define GPI_AON_PMU_GPIO_WAKEUP_1 1
|
||||
#define GPI_AON_PMU_GPIO_WAKEUP_2 2
|
||||
#define GPI_AON_PMU_GPIO_WAKEUP_3 3
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@
|
||||
#size-cells = <0x00>;
|
||||
timebase-frequency = <0x989680>;
|
||||
|
||||
cpu@0 {
|
||||
cpu0: cpu@0 {
|
||||
phandle = <0x01>;
|
||||
device_type = "cpu";
|
||||
reg = <0x00>;
|
||||
@@ -52,7 +52,7 @@
|
||||
riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_zmmul_za64rs_zaamo_zalrsc_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_shcounterenw_shgatpa_shtvala_shvsatpa_shvstvala_shvstvecd_ssccptr_sscounterenw_sstc_sstvala_sstvecd_ssu64xl_svadu_svvptc";
|
||||
mmu-type = "riscv,sv57";
|
||||
|
||||
interrupt-controller {
|
||||
cpu0_intc: interrupt-controller {
|
||||
#interrupt-cells = <0x01>;
|
||||
interrupt-controller;
|
||||
compatible = "riscv,cpu-intc";
|
||||
@@ -61,11 +61,9 @@
|
||||
};
|
||||
|
||||
cpu-map {
|
||||
|
||||
cluster0 {
|
||||
|
||||
core0 {
|
||||
cpu = <0x01>;
|
||||
cpu = <&cpu0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -186,7 +184,8 @@
|
||||
phandle = <0x03>;
|
||||
riscv,ndev = <0x5f>;
|
||||
reg = <0x00 0xc000000 0x00 0x600000>;
|
||||
interrupts-extended = <0x02 0x0b 0x02 0x09>;
|
||||
interrupts-extended = <&cpu0_intc 0x0b>,
|
||||
<&cpu0_intc 0x09>;
|
||||
interrupt-controller;
|
||||
compatible = "sifive,plic-1.0.0", "riscv,plic0";
|
||||
#address-cells = <0x00>;
|
||||
@@ -194,7 +193,8 @@
|
||||
};
|
||||
|
||||
clint@2000000 {
|
||||
interrupts-extended = <0x02 0x03 0x02 0x07>;
|
||||
interrupts-extended = <&cpu0_intc 0x03>,
|
||||
<&cpu0_intc 0x07>;
|
||||
reg = <0x00 0x2000000 0x00 0x10000>;
|
||||
compatible = "sifive,clint0", "riscv,clint0";
|
||||
};
|
||||
@@ -0,0 +1,252 @@
|
||||
/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 = <&gpio 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 = <4>;
|
||||
interrupt-parent = <&plic>;
|
||||
clocks = <&prci 0x03>;
|
||||
reg = <0x00 0x10010000 0x00 0x1000>;
|
||||
compatible = "sifive,uart0";
|
||||
};
|
||||
|
||||
uart1: serial@10011000 {
|
||||
interrupts = <5>;
|
||||
interrupt-parent = <&plic>;
|
||||
clocks = <&prci 0x03>;
|
||||
reg = <0x00 0x10011000 0x00 0x1000>;
|
||||
compatible = "sifive,uart0";
|
||||
};
|
||||
|
||||
pwm0: pwm@10020000 {
|
||||
#pwm-cells = <0>;
|
||||
clocks = <&prci 0x03>;
|
||||
interrupts = <42>, <43>, <44>, <45>;
|
||||
interrupt-parent = <&plic>;
|
||||
reg = <0x00 0x10020000 0x00 0x1000>;
|
||||
compatible = "sifive,pwm0";
|
||||
};
|
||||
|
||||
pwm1: pwm@10021000 {
|
||||
#pwm-cells = <0>;
|
||||
clocks = <&prci 0x03>;
|
||||
interrupts = <46>, <47>, <48>, <49>;
|
||||
interrupt-parent = <&plic>;
|
||||
reg = <0x00 0x10021000 0x00 0x1000>;
|
||||
compatible = "sifive,pwm0";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gmac0: ethernet@10090000 {
|
||||
#size-cells = <0x00>;
|
||||
#address-cells = <0x01>;
|
||||
local-mac-address = [52 54 00 12 34 56];
|
||||
clock-names = "pclk", "hclk";
|
||||
clocks = <&prci 0x02>, <&prci 0x02>;
|
||||
interrupts = <0x35>;
|
||||
interrupt-parent = <&plic>;
|
||||
phy-handle = <&gmac0_phy>;
|
||||
phy-mode = "gmii";
|
||||
reg-names = "control";
|
||||
reg = <0x00 0x10090000 0x00 0x2000>,
|
||||
<0x00 0x100a0000 0x00 0x1000>;
|
||||
compatible = "sifive,fu540-c000-gem";
|
||||
|
||||
gmac0_phy: ethernet-phy@0 {
|
||||
reg = <0x00>;
|
||||
};
|
||||
};
|
||||
|
||||
// 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 = <&prci 0x03>;
|
||||
phandle = <0x07>;
|
||||
};
|
||||
|
||||
plic: interrupt-controller@c000000 {
|
||||
phandle = <0x06>;
|
||||
riscv,ndev = <0x35>;
|
||||
reg = <0x00 0xc000000 0x00 0x4000000>;
|
||||
interrupts-extended = <&cpu0_intc 0x0b>, <&cpu1_intc 0x0b>, <&cpu1_intc 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 = <&cpu0_intc 0x03>, <&cpu0_intc 0x07>, <&cpu1_intc 0x03>, <&cpu1_intc 0x07>;
|
||||
reg = <0x00 0x2000000 0x00 0x10000>;
|
||||
compatible = "sifive,clint0", "riscv,clint0";
|
||||
};
|
||||
};
|
||||
};
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
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>;
|
||||
};
|
||||
};
|
||||
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";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"arch": "riscv64",
|
||||
"os": "none",
|
||||
"abi": "softfloat",
|
||||
"cpu": "generic-rv64",
|
||||
"llvm-abiname": "lp64",
|
||||
"llvm-target": "riscv64",
|
||||
"data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
|
||||
"max-atomic-width": 64,
|
||||
"target-pointer-width": "64",
|
||||
"target-pointer-width": 64,
|
||||
"features": "+m,+a,+c",
|
||||
|
||||
"disable-redzone": true,
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
"crt-objects-fallback": "false",
|
||||
"emit-debug-gdb-scripts": false,
|
||||
"llvm-abiname": "lp64",
|
||||
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "ld.lld"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"llvm-target": "x86_64-unknown-linux-gnu",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"max-atomic-width": 64,
|
||||
"target-pointer-width": "64",
|
||||
"target-pointer-width": 64,
|
||||
"features": "-avx,-sse,-avx2,+soft-float",
|
||||
|
||||
"disable-redzone": true,
|
||||
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "yggdrasil-kernel"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
build = "build.rs"
|
||||
authors = ["Mark Poliakov <mark@alnyan.me>"]
|
||||
|
||||
@@ -35,6 +35,7 @@ ygg_driver_ahci = { path = "driver/block/ahci" }
|
||||
ygg_driver_input = { path = "driver/input" }
|
||||
ygg_driver_usb_xhci.path = "driver/usb/xhci"
|
||||
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
|
||||
ygg_driver_serial_8250.path = "driver/serial/uart8250"
|
||||
|
||||
memfs = { path = "driver/fs/memfs" }
|
||||
ext2 = { path = "driver/fs/ext2" }
|
||||
@@ -58,7 +59,6 @@ device-tree.workspace = true
|
||||
kernel-arch-aarch64.workspace = true
|
||||
ygg_driver_bsp_arm.path = "driver/bsp/arm"
|
||||
ygg_driver_bsp_bcm283x.path = "driver/bsp/bcm283x"
|
||||
ygg_driver_usb_dwc2.path = "driver/usb/dwc2"
|
||||
|
||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||
device-tree.workspace = true
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kernel-arch"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
|
||||
kernel-arch-x86_64.path = "x86_64"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kernel-arch-aarch64"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi.workspace = true
|
||||
|
||||
@@ -66,7 +66,7 @@ impl FpContext {
|
||||
///
|
||||
/// It is up to the caller to ensure `this` is a valid pointer to store the FPU context in.
|
||||
pub unsafe fn store(this: *mut Self) {
|
||||
__aarch64_fp_store_context(this as _)
|
||||
unsafe { __aarch64_fp_store_context(this as _) }
|
||||
}
|
||||
|
||||
/// Loads the FPU with the context stored in `this` pointer.
|
||||
@@ -75,7 +75,7 @@ impl FpContext {
|
||||
///
|
||||
/// It is up to the caller to ensure `this` is a valid pointer to load the FPU context from.
|
||||
pub unsafe fn restore(this: *const Self) {
|
||||
__aarch64_fp_restore_context(this as _)
|
||||
unsafe { __aarch64_fp_restore_context(this as _) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,12 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
stack.push(entry as _);
|
||||
stack.push(arg);
|
||||
|
||||
setup_common_context(&mut stack, __aarch64_task_enter_kernel as _, 0, 0);
|
||||
setup_common_context(
|
||||
&mut stack,
|
||||
(__aarch64_task_enter_kernel as *const ()).addr(),
|
||||
0,
|
||||
0,
|
||||
);
|
||||
|
||||
let sp = stack.build();
|
||||
|
||||
@@ -212,7 +217,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
|
||||
setup_common_context(
|
||||
&mut stack,
|
||||
__aarch64_task_enter_user as _,
|
||||
(__aarch64_task_enter_user as *const ()).addr(),
|
||||
ttbr0,
|
||||
context.thread_pointer as _,
|
||||
);
|
||||
@@ -231,9 +236,8 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
}
|
||||
|
||||
unsafe fn enter(&self) -> ! {
|
||||
FpContext::restore(self.fp_context.get());
|
||||
|
||||
__aarch64_enter_task(self.inner.get())
|
||||
unsafe { FpContext::restore(self.fp_context.get()) };
|
||||
unsafe { __aarch64_enter_task(self.inner.get()) }
|
||||
}
|
||||
|
||||
unsafe fn switch(&self, from: &Self) {
|
||||
@@ -241,19 +245,20 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
let src = from.inner.get();
|
||||
|
||||
if dst != src {
|
||||
// Save the old context
|
||||
FpContext::store(from.fp_context.get());
|
||||
// Load next context
|
||||
FpContext::restore(self.fp_context.get());
|
||||
unsafe {
|
||||
// Save the old context
|
||||
FpContext::store(from.fp_context.get());
|
||||
// Load next context
|
||||
FpContext::restore(self.fp_context.get());
|
||||
|
||||
__aarch64_switch_task(self.inner.get(), from.inner.get())
|
||||
__aarch64_switch_task(self.inner.get(), from.inner.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn switch_and_drop(&self, thread: *const ()) {
|
||||
FpContext::restore(self.fp_context.get());
|
||||
|
||||
__aarch64_switch_task_and_drop(self.inner.get(), thread);
|
||||
unsafe { FpContext::restore(self.fp_context.get()) };
|
||||
unsafe { __aarch64_switch_task_and_drop(self.inner.get(), thread) };
|
||||
}
|
||||
|
||||
fn set_thread_pointer(&self, _tp: usize) {
|
||||
@@ -293,7 +298,7 @@ fn setup_common_context(builder: &mut StackBuilder, entry: usize, ttbr0: u64, tp
|
||||
builder.push(0); // x19
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn __aarch64_enter_task(to: *mut TaskContextInner) -> !;
|
||||
fn __aarch64_switch_task(to: *mut TaskContextInner, from: *mut TaskContextInner);
|
||||
fn __aarch64_switch_task_and_drop(to: *mut TaskContextInner, thread: *const ()) -> !;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#![no_std]
|
||||
#![feature(decl_macro)]
|
||||
#![allow(clippy::new_without_default)]
|
||||
|
||||
extern crate alloc;
|
||||
@@ -13,11 +12,11 @@ use aarch64_cpu::{
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use device_api::interrupt::LocalInterruptController;
|
||||
use kernel_arch_interface::{
|
||||
Architecture,
|
||||
cpu::{CpuData, CpuImpl, IpiQueue},
|
||||
guard::IrqGuard,
|
||||
task::Scheduler,
|
||||
util::OneTimeInit,
|
||||
Architecture,
|
||||
};
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||
|
||||
@@ -25,7 +24,7 @@ pub mod context;
|
||||
pub mod mem;
|
||||
|
||||
pub use context::TaskContextImpl;
|
||||
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
|
||||
pub use mem::{KernelTableManagerImpl, process::ProcessAddressSpaceImpl};
|
||||
|
||||
pub struct ArchitectureImpl;
|
||||
|
||||
@@ -101,7 +100,7 @@ impl Architecture for ArchitectureImpl {
|
||||
let id = (MPIDR_EL1.get() & 0xFF) as u32;
|
||||
let cpu = Box::leak(Box::new(CpuImpl::<Self, S>::new(id, data)));
|
||||
|
||||
cpu.set_local();
|
||||
unsafe { cpu.set_local() };
|
||||
}
|
||||
|
||||
fn local_cpu() -> *mut () {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use core::ops::Range;
|
||||
|
||||
use aarch64_cpu::registers::{TTBR0_EL1, TTBR1_EL1};
|
||||
use kernel_arch_interface::{mem::DeviceMemoryAttributes, KERNEL_VIRT_OFFSET};
|
||||
use kernel_arch_interface::{KERNEL_VIRT_OFFSET, mem::DeviceMemoryAttributes};
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
device::{DevicePageManager, DevicePageTableLevel},
|
||||
@@ -10,7 +10,7 @@ use libk_mm_interface::{
|
||||
|
||||
use crate::mem::{
|
||||
auto_lower_address,
|
||||
table::{PageAttributes, PageEntry, PageTable, L1, L2, L3},
|
||||
table::{L1, L2, L3, PageAttributes, PageEntry, PageTable},
|
||||
tlb_flush_range_va,
|
||||
};
|
||||
|
||||
@@ -98,22 +98,26 @@ impl DevicePageTableLevel for L3DeviceMemory {
|
||||
}
|
||||
|
||||
pub unsafe fn setup() {
|
||||
// 0..IDENTITY_SIZE_L1 -> lower RAM region
|
||||
for i in 0..IDENTITY_SIZE_L1 {
|
||||
let phys = PhysicalAddress::from_usize(i << L1::SHIFT);
|
||||
KERNEL_L1[i] = PageEntry::normal_block(phys, PageAttributes::empty());
|
||||
}
|
||||
unsafe {
|
||||
// 0..IDENTITY_SIZE_L1 -> lower RAM region
|
||||
for i in 0..IDENTITY_SIZE_L1 {
|
||||
let phys = PhysicalAddress::from_usize(i << L1::SHIFT);
|
||||
KERNEL_L1[i] = PageEntry::normal_block(phys, PageAttributes::empty());
|
||||
}
|
||||
|
||||
// DEVICE_L1 -> Device L2 table
|
||||
// 0..DEVICE_MAPPING_L3_COUNT -> Device L3 tables -> Device L3 pages
|
||||
// ..512 -> Device L2 pages
|
||||
for i in 0..DEVICE_MAPPING_L3_COUNT {
|
||||
// DEVICE_L1 -> Device L2 table
|
||||
// 0..DEVICE_MAPPING_L3_COUNT -> Device L3 tables -> Device L3 pages
|
||||
// ..512 -> Device L2 pages
|
||||
for i in 0..DEVICE_MAPPING_L3_COUNT {
|
||||
let phys = PhysicalAddress::from_usize(auto_lower_address(
|
||||
&raw const DEVICE_MEMORY.normal.0[i],
|
||||
));
|
||||
DEVICE_MEMORY.large.0[i] = PageEntry::table(phys, PageAttributes::empty());
|
||||
}
|
||||
let phys =
|
||||
PhysicalAddress::from_usize(auto_lower_address(&raw const DEVICE_MEMORY.normal.0[i]));
|
||||
DEVICE_MEMORY.large.0[i] = PageEntry::table(phys, PageAttributes::empty());
|
||||
PhysicalAddress::from_usize(auto_lower_address(&raw const DEVICE_MEMORY.large.0));
|
||||
KERNEL_L1[DEVICE_L1] = PageEntry::table(phys, PageAttributes::empty());
|
||||
}
|
||||
let phys = PhysicalAddress::from_usize(auto_lower_address(&raw const DEVICE_MEMORY.large.0));
|
||||
KERNEL_L1[DEVICE_L1] = PageEntry::table(phys, PageAttributes::empty());
|
||||
}
|
||||
|
||||
pub unsafe fn load() {
|
||||
|
||||
@@ -4,9 +4,9 @@ use aarch64_cpu::{
|
||||
registers::{MAIR_EL1, SCTLR_EL1, TCR_EL1},
|
||||
};
|
||||
use kernel_arch_interface::{
|
||||
KERNEL_VIRT_OFFSET,
|
||||
mem::{DeviceMemoryAttributes, KernelTableManager, RawDeviceMemoryMapping},
|
||||
sync::IrqSafeSpinlock,
|
||||
KERNEL_VIRT_OFFSET,
|
||||
};
|
||||
use libk_mm_interface::{address::PhysicalAddress, table::EntryLevel};
|
||||
use tock_registers::interfaces::{ReadWriteable, Writeable};
|
||||
@@ -14,7 +14,7 @@ use yggdrasil_abi::error::Error;
|
||||
|
||||
pub use intrinsics::*;
|
||||
|
||||
use crate::{mem::table::L1, ArchitectureImpl};
|
||||
use crate::{ArchitectureImpl, mem::table::L1};
|
||||
|
||||
pub mod fixed;
|
||||
pub mod intrinsics;
|
||||
@@ -52,14 +52,18 @@ impl KernelTableManager for KernelTableManagerImpl {
|
||||
attrs: DeviceMemoryAttributes,
|
||||
) -> Result<RawDeviceMemoryMapping<Self>, Error> {
|
||||
let _lock = KERNEL_MEMORY_LOCK.lock();
|
||||
#[allow(static_mut_refs)]
|
||||
fixed::DEVICE_MEMORY.map_device_pages(PhysicalAddress::from_u64(base), count, attrs)
|
||||
unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
fixed::DEVICE_MEMORY.map_device_pages(PhysicalAddress::from_u64(base), count, attrs)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn unmap_device_pages(mapping: &RawDeviceMemoryMapping<Self>) {
|
||||
let _lock = KERNEL_MEMORY_LOCK.lock();
|
||||
#[allow(static_mut_refs)]
|
||||
fixed::DEVICE_MEMORY.unmap_device_pages(mapping);
|
||||
unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
fixed::DEVICE_MEMORY.unmap_device_pages(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,15 +136,19 @@ unsafe fn enable_mmu() {
|
||||
SCTLR_EL1.modify(SCTLR_EL1::M::Enable);
|
||||
|
||||
// Enable caches
|
||||
enable_icache();
|
||||
enable_dcache();
|
||||
unsafe {
|
||||
enable_icache();
|
||||
enable_dcache();
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn init_lower(bsp: bool) {
|
||||
setup_memory_attributes();
|
||||
if bsp {
|
||||
fixed::setup();
|
||||
unsafe {
|
||||
if bsp {
|
||||
fixed::setup();
|
||||
}
|
||||
fixed::load();
|
||||
enable_mmu();
|
||||
}
|
||||
fixed::load();
|
||||
enable_mmu();
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ use libk_mm_interface::{
|
||||
};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{mem::table::PageEntry, KernelTableManagerImpl};
|
||||
use crate::{KernelTableManagerImpl, mem::table::PageEntry};
|
||||
|
||||
use super::{
|
||||
dc_cvac, ic_iallu,
|
||||
table::{PageAttributes, PageTable, L1, L2, L3},
|
||||
table::{L1, L2, L3, PageAttributes, PageTable},
|
||||
tlb_flush_asid, tlb_flush_vaae1,
|
||||
};
|
||||
|
||||
@@ -97,8 +97,10 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
|
||||
}
|
||||
|
||||
unsafe fn clear(&mut self) {
|
||||
self.l1
|
||||
.drop_range::<TA>(0..((Self::UPPER_LIMIT_PFN * L3::SIZE).page_index::<L1>()));
|
||||
unsafe {
|
||||
self.l1
|
||||
.drop_range::<TA>(0..((Self::UPPER_LIMIT_PFN * L3::SIZE).page_index::<L1>()))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use crate::KernelTableManagerImpl;
|
||||
use super::dc_cvac;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct PageAttributes: u64 {
|
||||
const PRESENT = 1 << 0;
|
||||
|
||||
@@ -71,8 +71,8 @@ pub struct L3;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EntryType {
|
||||
Table(PhysicalAddress),
|
||||
Page(PhysicalAddress),
|
||||
Table(PageAttributes, PhysicalAddress),
|
||||
Page(PageAttributes, PhysicalAddress),
|
||||
Invalid,
|
||||
}
|
||||
|
||||
@@ -103,8 +103,8 @@ impl<L: EntryLevel> PageTable<L> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_zeroed<'a, TA: TableAllocator>(
|
||||
) -> Result<PhysicalRefMut<'a, Self, KernelTableManagerImpl>, Error> {
|
||||
pub fn new_zeroed<'a, TA: TableAllocator>()
|
||||
-> Result<PhysicalRefMut<'a, Self, KernelTableManagerImpl>, Error> {
|
||||
let physical = TA::allocate_page_table()?;
|
||||
let mut table =
|
||||
unsafe { PhysicalRefMut::<'a, Self, KernelTableManagerImpl>::map(physical) };
|
||||
@@ -132,7 +132,7 @@ impl<L: EntryLevel> PageTable<L> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let inner = PhysicalRefMut::map(physical);
|
||||
let inner = unsafe { PhysicalRefMut::map(physical) };
|
||||
Some(inner)
|
||||
}
|
||||
}
|
||||
@@ -234,12 +234,16 @@ where
|
||||
let entry = self[index];
|
||||
|
||||
if let Some(table) = entry.as_table() {
|
||||
let mut table_ref: PhysicalRefMut<PageTable<L::NextLevel>, KernelTableManagerImpl> =
|
||||
PhysicalRefMut::map(table);
|
||||
unsafe {
|
||||
let mut table_ref: PhysicalRefMut<
|
||||
PageTable<L::NextLevel>,
|
||||
KernelTableManagerImpl,
|
||||
> = PhysicalRefMut::map(table);
|
||||
|
||||
table_ref.drop_all::<TA>();
|
||||
table_ref.drop_all::<TA>();
|
||||
|
||||
TA::free_page_table(table);
|
||||
TA::free_page_table(table);
|
||||
}
|
||||
} else if entry.is_present() {
|
||||
// Memory must've been cleared beforehand, so no non-table entries must be present
|
||||
panic!(
|
||||
@@ -307,9 +311,14 @@ impl<L: NonTerminalEntryLevel> PageEntry<L> {
|
||||
if !self.is_present() {
|
||||
EntryType::Invalid
|
||||
} else if let Some(table) = self.as_table() {
|
||||
EntryType::Table(table)
|
||||
let attributes = self.attributes();
|
||||
EntryType::Table(attributes, table)
|
||||
} else {
|
||||
EntryType::Page(PhysicalAddress::from_u64(self.0 & !Self::ATTR_MASK))
|
||||
let attributes = self.attributes();
|
||||
EntryType::Page(
|
||||
attributes,
|
||||
PhysicalAddress::from_u64(self.0 & !Self::ATTR_MASK),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,8 +435,26 @@ impl From<PageAttributes> for MapAttributes {
|
||||
impl fmt::Display for EntryType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Table(address) => write!(f, "table @ {address:#x}"),
|
||||
Self::Page(address) => write!(f, "page @ {address:#x}"),
|
||||
&Self::Table(attrs, address) => {
|
||||
let mask = match attrs & PageAttributes::AP_ACCESS_MASK {
|
||||
PageAttributes::AP_BOTH_READONLY => "r- r-",
|
||||
PageAttributes::AP_BOTH_READWRITE => "rw rw",
|
||||
PageAttributes::AP_KERNEL_READONLY => "r- --",
|
||||
PageAttributes::AP_KERNEL_READWRITE => "rw --",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
write!(f, "table @ {address:#010x} {mask}")
|
||||
}
|
||||
&Self::Page(attrs, address) => {
|
||||
let mask = match attrs & PageAttributes::AP_ACCESS_MASK {
|
||||
PageAttributes::AP_BOTH_READONLY => "r- r-",
|
||||
PageAttributes::AP_BOTH_READWRITE => "rw rw",
|
||||
PageAttributes::AP_KERNEL_READONLY => "r- --",
|
||||
PageAttributes::AP_KERNEL_READWRITE => "rw --",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
write!(f, "page @ {address:#010x} {mask}")
|
||||
}
|
||||
Self::Invalid => f.write_str("<invalid>"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kernel-arch-hosted"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
kernel-arch-interface.workspace = true
|
||||
|
||||
@@ -7,16 +7,16 @@ use std::{
|
||||
|
||||
use device_api::dma::{DmaAllocation, DmaAllocator};
|
||||
use kernel_arch_interface::{
|
||||
Architecture,
|
||||
cpu::{CpuData, IpiQueue},
|
||||
mem::{
|
||||
DeviceMemoryAttributes, KernelTableManager, PhysicalMemoryAllocator, RawDeviceMemoryMapping,
|
||||
},
|
||||
task::{Scheduler, TaskContext, UserContextInfo},
|
||||
Architecture,
|
||||
};
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
process::ProcessAddressSpaceManager,
|
||||
process::{PageAttributeUpdate, ProcessAddressSpaceManager},
|
||||
table::{MapAttributes, TableAllocator},
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
@@ -164,6 +164,14 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
unsafe fn update_page_attributes(
|
||||
&mut self,
|
||||
_address: usize,
|
||||
_update: &PageAttributeUpdate,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn translate(&self, _address: usize) -> Result<(PhysicalAddress, MapAttributes), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kernel-arch-interface"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi.workspace = true
|
||||
|
||||
@@ -7,7 +7,7 @@ use alloc::vec::Vec;
|
||||
use device_api::interrupt::IpiMessage;
|
||||
|
||||
use crate::{
|
||||
guard::IrqGuard, sync::IrqSafeSpinlock, task::Scheduler, util::OneTimeInit, Architecture,
|
||||
Architecture, guard::IrqGuard, sync::IrqSafeSpinlock, task::Scheduler, util::OneTimeInit,
|
||||
};
|
||||
|
||||
#[repr(C, align(0x10))]
|
||||
@@ -94,7 +94,7 @@ impl<A: Architecture, S: Scheduler + 'static> CpuImpl<A, S> {
|
||||
///
|
||||
/// See [Architecture::set_local_cpu].
|
||||
pub unsafe fn set_local(&'static mut self) {
|
||||
A::set_local_cpu(self as *mut _ as *mut _)
|
||||
unsafe { A::set_local_cpu(self as *mut _ as *mut _) }
|
||||
}
|
||||
|
||||
pub fn try_local<'a>() -> Option<LocalCpuImpl<'a, A, S>> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#![no_std]
|
||||
#![feature(step_trait, const_trait_impl, never_type, decl_macro)]
|
||||
#![feature(never_type)]
|
||||
#![allow(clippy::new_without_default)]
|
||||
|
||||
use core::ops::Range;
|
||||
|
||||
@@ -86,7 +86,7 @@ impl<A: KernelTableManager> RawDeviceMemoryMapping<A> {
|
||||
size: usize,
|
||||
attrs: DeviceMemoryAttributes,
|
||||
) -> Result<Self, Error> {
|
||||
A::map_device_pages(base, size, attrs)
|
||||
unsafe { A::map_device_pages(base, size, attrs) }
|
||||
}
|
||||
|
||||
/// Consumes the device mapping, leaking its address without deallocating the translation
|
||||
|
||||
@@ -6,7 +6,7 @@ use core::{
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
use crate::{guard::IrqGuard, Architecture};
|
||||
use crate::{Architecture, guard::IrqGuard};
|
||||
|
||||
pub struct Spinlock<A: Architecture, T> {
|
||||
value: UnsafeCell<T>,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use core::{arch::global_asm, cell::UnsafeCell, marker::PhantomData};
|
||||
|
||||
use kernel_arch_interface::{
|
||||
Architecture,
|
||||
mem::{KernelTableManager, PhysicalMemoryAllocator},
|
||||
task::{StackBuilder, TaskContext, UserContextInfo},
|
||||
Architecture,
|
||||
};
|
||||
use libk_mm_interface::address::PhysicalAddress;
|
||||
use tock_registers::{
|
||||
@@ -13,9 +13,9 @@ use tock_registers::{
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
ArchitectureImpl, PerCpuData,
|
||||
mem::{self},
|
||||
registers::SATP,
|
||||
ArchitectureImpl, PerCpuData,
|
||||
};
|
||||
|
||||
pub const CONTEXT_SIZE: usize = 14 * size_of::<usize>();
|
||||
@@ -86,7 +86,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
stack.push(context.entry);
|
||||
stack.push(context.argument);
|
||||
|
||||
setup_common_context(&mut stack, __rv64_task_enter_user as _);
|
||||
setup_common_context(&mut stack, (__rv64_task_enter_user as *const ()).addr());
|
||||
|
||||
let sp = stack.build();
|
||||
let satp = InMemoryRegister::new(0);
|
||||
@@ -118,7 +118,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
stack.push(entry as _);
|
||||
stack.push(arg);
|
||||
|
||||
setup_common_context(&mut stack, __rv64_task_enter_kernel as _);
|
||||
setup_common_context(&mut stack, (__rv64_task_enter_kernel as *const ()).addr());
|
||||
|
||||
let sp = stack.build();
|
||||
|
||||
|
||||
@@ -11,18 +11,18 @@ use core::{
|
||||
use alloc::{boxed::Box, collections::btree_map::BTreeMap, vec::Vec};
|
||||
use device_api::interrupt::LocalInterruptController;
|
||||
use kernel_arch_interface::{
|
||||
Architecture,
|
||||
cpu::{CpuData, CpuImpl, IpiQueue},
|
||||
sync::IrqSafeSpinlock,
|
||||
task::Scheduler,
|
||||
util::OneTimeInit,
|
||||
Architecture,
|
||||
};
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable};
|
||||
|
||||
use registers::SSTATUS;
|
||||
|
||||
pub mod mem;
|
||||
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
|
||||
pub use mem::{KernelTableManagerImpl, process::ProcessAddressSpaceImpl};
|
||||
pub mod context;
|
||||
pub use context::TaskContextImpl;
|
||||
pub mod intrinsics;
|
||||
|
||||
@@ -2,12 +2,11 @@ use kernel_arch_interface::sync::IrqSafeSpinlock;
|
||||
use libk_mm_interface::{address::PhysicalAddress, table::EntryLevel};
|
||||
|
||||
use crate::{
|
||||
mem::{
|
||||
auto_lower_address,
|
||||
table::{PageEntry, PageTable, L1},
|
||||
KERNEL_VIRT_OFFSET,
|
||||
},
|
||||
ArchitectureImpl,
|
||||
mem::{
|
||||
KERNEL_VIRT_OFFSET, auto_lower_address,
|
||||
table::{L1, PageEntry, PageTable},
|
||||
},
|
||||
};
|
||||
|
||||
pub const IDENTITY_SIZE_L1: usize = 64;
|
||||
|
||||
@@ -3,13 +3,13 @@ use kernel_arch_interface::mem::{
|
||||
};
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
table::{page_index, EntryLevel, EntryLevelExt},
|
||||
table::{EntryLevel, EntryLevelExt, page_index},
|
||||
};
|
||||
use tock_registers::interfaces::Writeable;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
mem::table::{PageTable, L1, L3},
|
||||
mem::table::{L1, L3, PageTable},
|
||||
registers::SATP,
|
||||
};
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ use crate::mem::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
table::{DroppableRange, PageTable, L1, L2, L3},
|
||||
KernelTableManagerImpl, USER_BOUNDARY,
|
||||
table::{DroppableRange, L1, L2, L3, PageTable},
|
||||
};
|
||||
|
||||
pub struct ProcessAddressSpaceImpl<TA: TableAllocator> {
|
||||
|
||||
@@ -10,8 +10,8 @@ use libk_mm_interface::{
|
||||
pointer::{PhysicalRef, PhysicalRefMut},
|
||||
process::PageAttributeUpdate,
|
||||
table::{
|
||||
page_index, EntryLevel, EntryLevelDrop, NextPageTable, NonTerminalEntryLevel,
|
||||
TableAllocator,
|
||||
EntryLevel, EntryLevelDrop, NextPageTable, NonTerminalEntryLevel, TableAllocator,
|
||||
page_index,
|
||||
},
|
||||
};
|
||||
use yggdrasil_abi::error::Error;
|
||||
@@ -109,8 +109,8 @@ impl<L: EntryLevel> PageTable<L> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_zeroed<'a, TA: TableAllocator>(
|
||||
) -> Result<PhysicalRefMut<'a, PageTable<L>, KernelTableManagerImpl>, Error> {
|
||||
pub fn new_zeroed<'a, TA: TableAllocator>()
|
||||
-> Result<PhysicalRefMut<'a, PageTable<L>, KernelTableManagerImpl>, Error> {
|
||||
let physical = TA::allocate_page_table()?;
|
||||
let mut table =
|
||||
unsafe { PhysicalRefMut::<'a, Self, KernelTableManagerImpl>::map(physical) };
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use device_api::{ResetDevice, device::Device};
|
||||
use yggdrasil_abi::{error::Error, primitive_enum};
|
||||
|
||||
const EXT_HSM: u64 = 0x48534D;
|
||||
@@ -6,6 +7,7 @@ const EXT_DBCN: u64 = 0x4442434E;
|
||||
const EXT_SPI: u64 = 0x735049;
|
||||
const EXT_SYSTEM_SHUTDOWN: u64 = 0x53525354;
|
||||
const EXT_SYSTEM_SHUTDOWN_LEGACY: u64 = 0x08;
|
||||
const EXT_SYSTEM_RESET: u64 = 0x53525354;
|
||||
|
||||
primitive_enum! {
|
||||
pub enum Status: i64 {
|
||||
@@ -52,6 +54,20 @@ impl From<i64> for SbiError {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SbiResetMethod;
|
||||
|
||||
impl Device for SbiResetMethod {
|
||||
fn display_name(&self) -> &str {
|
||||
"SBI reset"
|
||||
}
|
||||
}
|
||||
|
||||
impl ResetDevice for SbiResetMethod {
|
||||
unsafe fn reset(&self) -> ! {
|
||||
sbi_system_reset()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[inline(always)]
|
||||
unsafe fn sbi_do_call(
|
||||
@@ -78,11 +94,7 @@ unsafe fn sbi_do_call(
|
||||
);
|
||||
}
|
||||
let a0 = a0 as i64;
|
||||
if a0 == 0 {
|
||||
Ok(a1)
|
||||
} else {
|
||||
Err(a0.into())
|
||||
}
|
||||
if a0 == 0 { Ok(a1) } else { Err(a0.into()) }
|
||||
}
|
||||
|
||||
pub fn sbi_hart_start(hart_id: u64, start_addr: u64, opaque: u64) -> Result<(), Error> {
|
||||
@@ -111,6 +123,11 @@ pub fn sbi_set_timer(next_event: u64) {
|
||||
unsafe { sbi_do_call(EXT_TIME, 0x00, next_event, 0, 0, 0, 0, 0) }.ok();
|
||||
}
|
||||
|
||||
pub fn sbi_system_reset() -> ! {
|
||||
unsafe { sbi_do_call(EXT_SYSTEM_RESET, 0x00, 0x01, 0x00, 0, 0, 0, 0) }.ok();
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn sbi_system_shutdown() -> ! {
|
||||
unsafe { sbi_do_call(EXT_SYSTEM_SHUTDOWN, 0x00, 0, 0, 0, 0, 0, 0) }.ok();
|
||||
unsafe { sbi_do_call(EXT_SYSTEM_SHUTDOWN_LEGACY, 0x00, 0, 0, 0, 0, 0, 0) }.ok();
|
||||
|
||||
@@ -35,7 +35,7 @@ cfg_if! {
|
||||
|
||||
pub use imp::{ArchitectureImpl, KernelTableManagerImpl, ProcessAddressSpaceImpl, TaskContextImpl};
|
||||
|
||||
pub use kernel_arch_interface::{guard, mem, sync, task, util, Architecture, KERNEL_VIRT_OFFSET};
|
||||
pub use kernel_arch_interface::{Architecture, KERNEL_VIRT_OFFSET, guard, mem, sync, task, util};
|
||||
|
||||
pub type CpuImpl<S> = kernel_arch_interface::cpu::CpuImpl<ArchitectureImpl, S>;
|
||||
pub type LocalCpuImpl<'a, S> = kernel_arch_interface::cpu::LocalCpuImpl<'a, ArchitectureImpl, S>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kernel-arch-x86"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
kernel-arch-interface.workspace = true
|
||||
|
||||
@@ -170,36 +170,40 @@ impl CpuFeatureSet for CpuFeatures {
|
||||
|
||||
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
|
||||
unsafe fn raw_cpuid(eax: u32, result: &mut [u32]) {
|
||||
core::arch::asm!(
|
||||
r#"
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
r#"
|
||||
push %rbx
|
||||
cpuid
|
||||
mov %ebx, {0:e}
|
||||
pop %rbx
|
||||
"#,
|
||||
out(reg) result[0],
|
||||
out("edx") result[1],
|
||||
out("ecx") result[2],
|
||||
in("eax") eax,
|
||||
options(att_syntax)
|
||||
);
|
||||
out(reg) result[0],
|
||||
out("edx") result[1],
|
||||
out("ecx") result[2],
|
||||
in("eax") eax,
|
||||
options(att_syntax)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", rust_analyzer))]
|
||||
unsafe fn raw_cpuid(eax: u32, result: &mut [u32]) {
|
||||
core::arch::asm!(
|
||||
r#"
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
r#"
|
||||
push %ebx
|
||||
cpuid
|
||||
mov %ebx, {0:e}
|
||||
pop %ebx
|
||||
"#,
|
||||
out(reg) result[0],
|
||||
out("edx") result[1],
|
||||
out("ecx") result[2],
|
||||
in("eax") eax,
|
||||
options(att_syntax)
|
||||
);
|
||||
out(reg) result[0],
|
||||
out("edx") result[1],
|
||||
out("ecx") result[2],
|
||||
in("eax") eax,
|
||||
options(att_syntax)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn cpuid_features() -> (EcxFeatures, EdxFeatures, ExtEdxFeatures) {
|
||||
|
||||
+34
-32
@@ -225,42 +225,44 @@ mod imp {
|
||||
offset: gdt_addr,
|
||||
};
|
||||
|
||||
core::arch::asm!(
|
||||
r#"
|
||||
wbinvd
|
||||
lgdt ({0})
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
r#"
|
||||
wbinvd
|
||||
lgdt ({0})
|
||||
|
||||
// Have to use iretq here
|
||||
mov %rsp, %rcx
|
||||
leaq 1f(%rip), %rax
|
||||
// Have to use iretq here
|
||||
mov %rsp, %rcx
|
||||
leaq 1f(%rip), %rax
|
||||
|
||||
// SS:RSP
|
||||
pushq $0x10
|
||||
pushq %rcx
|
||||
// SS:RSP
|
||||
pushq $0x10
|
||||
pushq %rcx
|
||||
|
||||
// RFLAGS
|
||||
pushfq
|
||||
// RFLAGS
|
||||
pushfq
|
||||
|
||||
// CS:RIP
|
||||
pushq $0x08
|
||||
pushq %rax
|
||||
iretq
|
||||
1:
|
||||
mov $0x10, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
// CS:RIP
|
||||
pushq $0x08
|
||||
pushq %rax
|
||||
iretq
|
||||
1:
|
||||
mov $0x10, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
mov $0x28, %ax
|
||||
ltr %ax
|
||||
"#,
|
||||
in(reg) &gdtr,
|
||||
out("rax") _,
|
||||
out("rcx") _,
|
||||
options(att_syntax)
|
||||
);
|
||||
mov $0x28, %ax
|
||||
ltr %ax
|
||||
"#,
|
||||
in(reg) &gdtr,
|
||||
out("rax") _,
|
||||
out("rcx") _,
|
||||
options(att_syntax)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes and loads the GDT data structure for the current CPU.
|
||||
@@ -270,7 +272,7 @@ mod imp {
|
||||
/// Intended to be called once per each CPU during their early initialization.
|
||||
pub unsafe fn init() -> usize {
|
||||
let (gdt, tss) = create_gdt();
|
||||
load_gdt(gdt);
|
||||
unsafe { load_gdt(gdt) };
|
||||
(tss as *const Tss).addr()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,9 @@ impl IoPortAccess<u32> for IoPort<u32> {
|
||||
#[inline]
|
||||
pub unsafe fn inb(port: u16) -> u8 {
|
||||
let value: u8;
|
||||
core::arch::asm!("inb %dx, %al", in("dx") port, out("al") value, options(att_syntax));
|
||||
unsafe {
|
||||
core::arch::asm!("inb %dx, %al", in("dx") port, out("al") value, options(att_syntax))
|
||||
};
|
||||
value
|
||||
}
|
||||
|
||||
@@ -88,7 +90,9 @@ pub unsafe fn inb(port: u16) -> u8 {
|
||||
#[inline]
|
||||
pub unsafe fn inw(port: u16) -> u16 {
|
||||
let value: u16;
|
||||
core::arch::asm!("inw %dx, %ax", in("dx") port, out("ax") value, options(att_syntax));
|
||||
unsafe {
|
||||
core::arch::asm!("inw %dx, %ax", in("dx") port, out("ax") value, options(att_syntax))
|
||||
};
|
||||
value
|
||||
}
|
||||
|
||||
@@ -100,7 +104,9 @@ pub unsafe fn inw(port: u16) -> u16 {
|
||||
#[inline]
|
||||
pub unsafe fn inl(port: u16) -> u32 {
|
||||
let value: u32;
|
||||
core::arch::asm!("inl %dx, %eax", in("dx") port, out("eax") value, options(att_syntax));
|
||||
unsafe {
|
||||
core::arch::asm!("inl %dx, %eax", in("dx") port, out("eax") value, options(att_syntax))
|
||||
};
|
||||
value
|
||||
}
|
||||
|
||||
@@ -111,7 +117,9 @@ pub unsafe fn inl(port: u16) -> u32 {
|
||||
/// Provides direct access to port I/O, unsafe.
|
||||
#[inline]
|
||||
pub unsafe fn outb(port: u16, value: u8) {
|
||||
core::arch::asm!("outb %al, %dx", in("dx") port, in("al") value, options(att_syntax));
|
||||
unsafe {
|
||||
core::arch::asm!("outb %al, %dx", in("dx") port, in("al") value, options(att_syntax))
|
||||
};
|
||||
}
|
||||
|
||||
/// Writes a 16-bit value to the I/O port.
|
||||
@@ -121,7 +129,9 @@ pub unsafe fn outb(port: u16, value: u8) {
|
||||
/// Provides direct access to port I/O, unsafe.
|
||||
#[inline]
|
||||
pub unsafe fn outw(port: u16, value: u16) {
|
||||
core::arch::asm!("outw %ax, %dx", in("dx") port, in("ax") value, options(att_syntax));
|
||||
unsafe {
|
||||
core::arch::asm!("outw %ax, %dx", in("dx") port, in("ax") value, options(att_syntax))
|
||||
};
|
||||
}
|
||||
|
||||
/// Writes a 32-bit value to the I/O port.
|
||||
@@ -131,7 +141,9 @@ pub unsafe fn outw(port: u16, value: u16) {
|
||||
/// Provides direct access to port I/O, unsafe.
|
||||
#[inline]
|
||||
pub unsafe fn outl(port: u16, value: u32) {
|
||||
core::arch::asm!("outl %eax, %dx", in("dx") port, in("eax") value, options(att_syntax));
|
||||
unsafe {
|
||||
core::arch::asm!("outl %eax, %dx", in("dx") port, in("eax") value, options(att_syntax))
|
||||
};
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(iter_chain, new_zeroed_alloc, box_as_ptr)]
|
||||
#![feature(box_as_ptr)]
|
||||
#![allow(clippy::new_without_default)]
|
||||
#![no_std]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kernel-arch-x86_64"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi.workspace = true
|
||||
|
||||
@@ -4,14 +4,14 @@ use kernel_arch_interface::{
|
||||
mem::{KernelTableManager, PhysicalMemoryAllocator},
|
||||
task::{ForkFrame, StackBuilder, TaskContext, TaskFrame, UserContextInfo},
|
||||
};
|
||||
use kernel_arch_x86::registers::{FpuContext, CR3, MSR_IA32_FS_BASE};
|
||||
use kernel_arch_x86::registers::{CR3, FpuContext, MSR_IA32_FS_BASE};
|
||||
use libk_mm_interface::address::PhysicalAddress;
|
||||
use tock_registers::interfaces::Writeable;
|
||||
use yggdrasil_abi::{arch::SavedFrame, error::Error};
|
||||
|
||||
use crate::{
|
||||
mem::{auto_lower_address, fixed},
|
||||
ArchitectureImpl,
|
||||
mem::{auto_lower_address, fixed},
|
||||
};
|
||||
|
||||
/// Frame saved onto the stack when taking an IRQ
|
||||
@@ -255,7 +255,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
type Context = TaskContextImpl<K, PA>;
|
||||
|
||||
unsafe fn fork(&self, address_space: u64) -> Result<TaskContextImpl<K, PA>, Error> {
|
||||
TaskContextImpl::from_syscall_frame(self, address_space)
|
||||
unsafe { TaskContextImpl::from_syscall_frame(self, address_space) }
|
||||
}
|
||||
|
||||
fn set_return_value(&mut self, value: u64) {
|
||||
@@ -405,18 +405,20 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
}
|
||||
|
||||
unsafe fn store_state(&self) {
|
||||
FpuContext::store(self.fpu_context.get());
|
||||
unsafe { FpuContext::store(self.fpu_context.get()) };
|
||||
// No need to save TSS/%cr3/%fs base back into the TCB, only the kernel
|
||||
// can make changes to those
|
||||
}
|
||||
|
||||
unsafe fn load_state(&self) {
|
||||
FpuContext::restore(self.fpu_context.get());
|
||||
// When the task is interrupted from Ring 3, make the CPU load
|
||||
// the top of its kernel stack
|
||||
ArchitectureImpl::set_local_tss_sp0(self.tss_rsp0);
|
||||
MSR_IA32_FS_BASE.set((*self.inner.get()).fs_base as u64);
|
||||
CR3.set_address(self.cr3);
|
||||
unsafe {
|
||||
FpuContext::restore(self.fpu_context.get());
|
||||
// When the task is interrupted from Ring 3, make the CPU load
|
||||
// the top of its kernel stack
|
||||
ArchitectureImpl::set_local_tss_sp0(self.tss_rsp0);
|
||||
MSR_IA32_FS_BASE.set((*self.inner.get()).fs_base as u64);
|
||||
CR3.set_address(self.cr3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +447,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
stack.push(entry as _);
|
||||
stack.push(arg);
|
||||
|
||||
setup_common_context(&mut stack, __x86_64_task_enter_kernel as _);
|
||||
setup_common_context(&mut stack, (__x86_64_task_enter_kernel as *const ()).addr());
|
||||
|
||||
let sp = stack.build();
|
||||
|
||||
@@ -483,7 +485,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
stack.push(context.argument);
|
||||
stack.push(context.stack_pointer);
|
||||
|
||||
setup_common_context(&mut stack, __x86_64_task_enter_user as _);
|
||||
setup_common_context(&mut stack, (__x86_64_task_enter_user as *const ()).addr());
|
||||
|
||||
let sp = stack.build();
|
||||
let rsp0 = stack_base + USER_TASK_PAGES * 0x1000;
|
||||
@@ -506,8 +508,10 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
}
|
||||
|
||||
unsafe fn enter(&self) -> ! {
|
||||
self.load_state();
|
||||
__x86_64_enter_task(self.inner.get())
|
||||
unsafe {
|
||||
self.load_state();
|
||||
__x86_64_enter_task(self.inner.get())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn switch(&self, from: &Self) {
|
||||
@@ -515,14 +519,18 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
return;
|
||||
}
|
||||
|
||||
from.store_state();
|
||||
self.load_state();
|
||||
__x86_64_switch_task(self.inner.get(), from.inner.get())
|
||||
unsafe {
|
||||
from.store_state();
|
||||
self.load_state();
|
||||
__x86_64_switch_task(self.inner.get(), from.inner.get())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn switch_and_drop(&self, thread: *const ()) {
|
||||
self.load_state();
|
||||
__x86_64_switch_and_drop(self.inner.get(), thread)
|
||||
unsafe {
|
||||
self.load_state();
|
||||
__x86_64_switch_and_drop(self.inner.get(), thread)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_thread_pointer(&self, tp: usize) {
|
||||
@@ -561,7 +569,7 @@ fn setup_common_context(builder: &mut StackBuilder, entry: usize) {
|
||||
builder.push(0); // %rbx
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn __x86_64_task_enter_kernel();
|
||||
fn __x86_64_task_enter_user();
|
||||
fn __x86_64_task_enter_from_fork();
|
||||
|
||||
@@ -11,10 +11,10 @@ use core::{
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
|
||||
use kernel_arch_interface::{
|
||||
Architecture,
|
||||
cpu::{CpuData, CpuImpl, IpiQueue},
|
||||
task::Scheduler,
|
||||
util::OneTimeInit,
|
||||
Architecture,
|
||||
};
|
||||
use kernel_arch_x86::{cpuid::CpuFeatures, registers::MSR_IA32_KERNEL_GS_BASE};
|
||||
use libk_mm_interface::address::PhysicalAddress;
|
||||
@@ -24,7 +24,7 @@ pub mod context;
|
||||
pub mod mem;
|
||||
|
||||
pub use context::TaskContextImpl;
|
||||
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
|
||||
pub use mem::{KernelTableManagerImpl, process::ProcessAddressSpaceImpl};
|
||||
|
||||
pub struct ArchitectureImpl;
|
||||
|
||||
@@ -103,7 +103,7 @@ impl Architecture for ArchitectureImpl {
|
||||
|
||||
unsafe fn set_local_cpu(cpu: *mut ()) {
|
||||
MSR_IA32_KERNEL_GS_BASE.set(cpu as u64);
|
||||
core::arch::asm!("wbinvd; swapgs");
|
||||
unsafe { core::arch::asm!("wbinvd; swapgs") };
|
||||
}
|
||||
|
||||
fn local_cpu() -> *mut () {
|
||||
@@ -127,7 +127,7 @@ impl Architecture for ArchitectureImpl {
|
||||
)));
|
||||
cpu.this = cpu.deref_mut();
|
||||
|
||||
cpu.set_local();
|
||||
unsafe { cpu.set_local() };
|
||||
}
|
||||
|
||||
fn idle_task() -> extern "C" fn(usize) -> ! {
|
||||
@@ -153,10 +153,12 @@ impl Architecture for ArchitectureImpl {
|
||||
|
||||
unsafe fn set_interrupt_mask(mask: bool) -> bool {
|
||||
let old = Self::interrupt_mask();
|
||||
if mask {
|
||||
core::arch::asm!("cli");
|
||||
} else {
|
||||
core::arch::asm!("sti");
|
||||
unsafe {
|
||||
if mask {
|
||||
core::arch::asm!("cli");
|
||||
} else {
|
||||
core::arch::asm!("sti");
|
||||
}
|
||||
}
|
||||
old
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
use core::ops::Range;
|
||||
|
||||
use kernel_arch_interface::{mem::DeviceMemoryAttributes, sync::IrqSafeSpinlock, Architecture};
|
||||
use kernel_arch_interface::{Architecture, mem::DeviceMemoryAttributes, sync::IrqSafeSpinlock};
|
||||
use kernel_arch_x86::registers::CR3;
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
device::{DevicePageManager, DevicePageTableLevel},
|
||||
table::{page_index, EntryLevel},
|
||||
table::{EntryLevel, page_index},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ArchitectureImpl, KERNEL_VIRT_OFFSET,
|
||||
mem::{
|
||||
auto_lower_address,
|
||||
table::{PageAttributes, PageEntry, PageTable, L0, L1, L2, L3},
|
||||
table::{L0, L1, L2, L3, PageAttributes, PageEntry, PageTable},
|
||||
},
|
||||
ArchitectureImpl, KERNEL_VIRT_OFFSET,
|
||||
};
|
||||
|
||||
pub const IDENTITY_SIZE_L1: usize = 64;
|
||||
@@ -101,29 +101,33 @@ impl DevicePageTableLevel for L3DeviceMemory {
|
||||
}
|
||||
|
||||
pub(super) unsafe fn setup(have_1gib_pages: bool) {
|
||||
let phys = PhysicalAddress::from_usize(auto_lower_address(&raw const KERNEL_PDPT));
|
||||
KERNEL_PML4[KERNEL_L0I] = PageEntry::table(phys, PageAttributes::WRITABLE);
|
||||
unsafe {
|
||||
let phys = PhysicalAddress::from_usize(auto_lower_address(&raw const KERNEL_PDPT));
|
||||
KERNEL_PML4[KERNEL_L0I] = PageEntry::table(phys, PageAttributes::WRITABLE);
|
||||
|
||||
if have_1gib_pages {
|
||||
for i in 0..IDENTITY_SIZE_L1 {
|
||||
let phys = PhysicalAddress::from_usize(i * L1::SIZE);
|
||||
KERNEL_PDPT[i] = PageEntry::<L1>::block(phys, PageAttributes::WRITABLE);
|
||||
if have_1gib_pages {
|
||||
for i in 0..IDENTITY_SIZE_L1 {
|
||||
let phys = PhysicalAddress::from_usize(i * L1::SIZE);
|
||||
KERNEL_PDPT[i] = PageEntry::<L1>::block(phys, PageAttributes::WRITABLE);
|
||||
}
|
||||
} else {
|
||||
// TODO
|
||||
ArchitectureImpl::halt();
|
||||
}
|
||||
} else {
|
||||
// TODO
|
||||
ArchitectureImpl::halt();
|
||||
}
|
||||
|
||||
// DEVICE_L1 -> Device L2 table
|
||||
// 0..DEVICE_MAPPING_L3_COUNT -> Device L3 tables -> Device L3 pages
|
||||
// ..512 -> Device L2 pages
|
||||
for i in 0..DEVICE_MAPPING_L3_COUNT {
|
||||
// DEVICE_L1 -> Device L2 table
|
||||
// 0..DEVICE_MAPPING_L3_COUNT -> Device L3 tables -> Device L3 pages
|
||||
// ..512 -> Device L2 pages
|
||||
for i in 0..DEVICE_MAPPING_L3_COUNT {
|
||||
let phys = PhysicalAddress::from_usize(auto_lower_address(
|
||||
&raw const DEVICE_MEMORY.normal.0[i],
|
||||
));
|
||||
DEVICE_MEMORY.large.0[i] = PageEntry::table(phys, PageAttributes::WRITABLE);
|
||||
}
|
||||
let phys =
|
||||
PhysicalAddress::from_usize(auto_lower_address(&raw const DEVICE_MEMORY.normal.0[i]));
|
||||
DEVICE_MEMORY.large.0[i] = PageEntry::table(phys, PageAttributes::WRITABLE);
|
||||
PhysicalAddress::from_usize(auto_lower_address(&raw const DEVICE_MEMORY.large.0));
|
||||
KERNEL_PDPT[DEVICE_L1] = PageEntry::table(phys, PageAttributes::WRITABLE);
|
||||
}
|
||||
let phys = PhysicalAddress::from_usize(auto_lower_address(&raw const DEVICE_MEMORY.large.0));
|
||||
KERNEL_PDPT[DEVICE_L1] = PageEntry::table(phys, PageAttributes::WRITABLE);
|
||||
}
|
||||
|
||||
pub(super) unsafe fn load() {
|
||||
|
||||
@@ -6,7 +6,7 @@ use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::KERNEL_VIRT_OFFSET;
|
||||
|
||||
use self::table::{PageTable, L0, L1};
|
||||
use self::table::{L0, L1, PageTable};
|
||||
|
||||
pub mod fixed;
|
||||
pub mod process;
|
||||
@@ -41,13 +41,17 @@ impl KernelTableManager for KernelTableManagerImpl {
|
||||
) -> Result<RawDeviceMemoryMapping<Self>, Error> {
|
||||
let _lock = fixed::LOCK.lock();
|
||||
#[allow(static_mut_refs)]
|
||||
fixed::DEVICE_MEMORY.map_device_pages(PhysicalAddress::from_u64(base), count, attrs)
|
||||
unsafe {
|
||||
fixed::DEVICE_MEMORY.map_device_pages(PhysicalAddress::from_u64(base), count, attrs)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn unmap_device_pages(mapping: &RawDeviceMemoryMapping<Self>) {
|
||||
let _lock = fixed::LOCK.lock();
|
||||
#[allow(static_mut_refs)]
|
||||
fixed::DEVICE_MEMORY.unmap_device_pages(mapping);
|
||||
unsafe {
|
||||
fixed::DEVICE_MEMORY.unmap_device_pages(mapping)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +88,11 @@ pub fn auto_lower_address<T>(pointer: *const T) -> usize {
|
||||
/// Unsafe, must only be called by BSP during its early init, must already be in "higher-half"
|
||||
#[inline(never)]
|
||||
pub unsafe fn init_fixed_tables(have_1gib_pages: bool, bsp: bool) {
|
||||
fixed::setup(have_1gib_pages);
|
||||
if bsp {
|
||||
fixed::load();
|
||||
unsafe {
|
||||
fixed::setup(have_1gib_pages);
|
||||
if bsp {
|
||||
fixed::load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,5 +101,5 @@ pub unsafe fn init_fixed_tables(have_1gib_pages: bool, bsp: bool) {
|
||||
/// `address` must be page-aligned.
|
||||
#[inline]
|
||||
pub unsafe fn flush_tlb_entry(address: usize) {
|
||||
core::arch::asm!("invlpg ({0})", in(reg) address, options(att_syntax));
|
||||
unsafe { core::arch::asm!("invlpg ({0})", in(reg) address, options(att_syntax)) };
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::KernelTableManagerImpl;
|
||||
|
||||
use super::{
|
||||
clone_kernel_tables, flush_tlb_entry,
|
||||
table::{PageEntry, PageTable, L0, L1, L2, L3},
|
||||
table::{L0, L1, L2, L3, PageEntry, PageTable},
|
||||
};
|
||||
|
||||
/// Represents a process or kernel address space. Because x86-64 does not have cool stuff like
|
||||
@@ -85,8 +85,10 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
|
||||
}
|
||||
|
||||
unsafe fn clear(&mut self) {
|
||||
self.l0
|
||||
.drop_range::<TA>(0..((Self::UPPER_LIMIT_PFN * L3::SIZE).page_index::<L1>()));
|
||||
unsafe {
|
||||
self.l0
|
||||
.drop_range::<TA>(0..((Self::UPPER_LIMIT_PFN * L3::SIZE).page_index::<L1>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -220,12 +220,12 @@ impl<L: EntryLevel> PageTable<L> {
|
||||
/// Unsafe: the caller must ensure the provided reference is properly aligned and contains sane
|
||||
/// data.
|
||||
pub unsafe fn from_raw_slice_mut(data: &mut [PageEntry<L>; 512]) -> &mut Self {
|
||||
core::mem::transmute(data)
|
||||
unsafe { core::mem::transmute(data) }
|
||||
}
|
||||
|
||||
/// Allocates a new page table, filling it with non-preset entries
|
||||
pub fn new_zeroed<'a, TA: TableAllocator>(
|
||||
) -> Result<PhysicalRefMut<'a, Self, KernelTableManagerImpl>, Error> {
|
||||
pub fn new_zeroed<'a, TA: TableAllocator>()
|
||||
-> Result<PhysicalRefMut<'a, Self, KernelTableManagerImpl>, Error> {
|
||||
let physical = TA::allocate_page_table()?;
|
||||
let mut table =
|
||||
unsafe { PhysicalRefMut::<'a, Self, KernelTableManagerImpl>::map(physical) };
|
||||
@@ -243,8 +243,10 @@ impl<L: EntryLevel> PageTable<L> {
|
||||
///
|
||||
/// The caller must ensure the table is no longer in use and is not referenced anymore.
|
||||
pub unsafe fn free<TA: TableAllocator>(this: PhysicalRefMut<Self, KernelTableManagerImpl>) {
|
||||
let physical = this.as_physical_address();
|
||||
TA::free_page_table(physical);
|
||||
unsafe {
|
||||
let physical = this.as_physical_address();
|
||||
TA::free_page_table(physical);
|
||||
}
|
||||
}
|
||||
|
||||
// /// Returns the physical address of this table
|
||||
@@ -303,25 +305,29 @@ where
|
||||
const FULL_RANGE: Range<usize> = 0..512;
|
||||
|
||||
unsafe fn drop_range<TA: TableAllocator>(&mut self, range: Range<usize>) {
|
||||
for index in range {
|
||||
let entry = self[index];
|
||||
unsafe {
|
||||
for index in range {
|
||||
let entry = self[index];
|
||||
|
||||
if let Some(table) = entry.as_table() {
|
||||
let mut table_ref: PhysicalRefMut<PageTable<L::NextLevel>, KernelTableManagerImpl> =
|
||||
PhysicalRefMut::map(table);
|
||||
if let Some(table) = entry.as_table() {
|
||||
let mut table_ref: PhysicalRefMut<
|
||||
PageTable<L::NextLevel>,
|
||||
KernelTableManagerImpl,
|
||||
> = PhysicalRefMut::map(table);
|
||||
|
||||
table_ref.drop_all::<TA>();
|
||||
table_ref.drop_all::<TA>();
|
||||
|
||||
TA::free_page_table(table);
|
||||
} else if entry.is_present() {
|
||||
// Memory must've been cleared beforehand, so no non-table entries must be present
|
||||
panic!(
|
||||
"Expected a table containing only tables, got table[{}] = {:#x?}",
|
||||
index, entry.0
|
||||
);
|
||||
TA::free_page_table(table);
|
||||
} else if entry.is_present() {
|
||||
// Memory must've been cleared beforehand, so no non-table entries must be present
|
||||
panic!(
|
||||
"Expected a table containing only tables, got table[{}] = {:#x?}",
|
||||
index, entry.0
|
||||
);
|
||||
}
|
||||
|
||||
self[index] = PageEntry::INVALID;
|
||||
}
|
||||
|
||||
self[index] = PageEntry::INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,9 +6,9 @@ use std::{
|
||||
};
|
||||
|
||||
use abi_generator::{
|
||||
abi::{ty::TypeWidth, AbiBuilder},
|
||||
syntax::UnwrapFancy,
|
||||
TargetEnv,
|
||||
abi::{AbiBuilder, ty::TypeWidth},
|
||||
syntax::UnwrapFancy,
|
||||
};
|
||||
|
||||
fn build_x86_64() {
|
||||
|
||||
@@ -7,7 +7,7 @@ use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, Irq, IrqVector},
|
||||
};
|
||||
use kernel_arch_x86::{intrinsics, ISA_IRQ_OFFSET};
|
||||
use kernel_arch_x86::{ISA_IRQ_OFFSET, intrinsics};
|
||||
use libk::device::external_interrupt_controller;
|
||||
use libk_mm::{
|
||||
address::{PhysicalAddress, Virtualize},
|
||||
@@ -15,8 +15,8 @@ use libk_mm::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
mem::{read_memory, write_memory},
|
||||
ACPI_SYSTEM,
|
||||
mem::{read_memory, write_memory},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
||||
@@ -5,7 +5,7 @@ use acpi::AcpiTables;
|
||||
use acpi_system::{AcpiInterruptMethod, AcpiSleepState, AcpiSystem};
|
||||
use alloc::boxed::Box;
|
||||
use libk::error::Error;
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "ygg_driver_ahci"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
authors = ["Mark Poliakov <mark@alnyan.me>"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
use core::mem::{MaybeUninit, size_of};
|
||||
|
||||
use device_api::dma::DmaAllocator;
|
||||
use libk::dma::{BusAddress, DmaBuffer, DmaSliceMut};
|
||||
use tock_registers::register_structs;
|
||||
|
||||
use crate::{data::AtaString, error::AhciError, MAX_PRD_SIZE};
|
||||
use crate::{MAX_PRD_SIZE, data::AtaString, error::AhciError};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
#[repr(u8)]
|
||||
@@ -115,7 +115,7 @@ impl AtaCommand for AtaIdentify {
|
||||
}
|
||||
|
||||
unsafe fn into_response(self) -> Self::Response {
|
||||
DmaBuffer::assume_init(self.buffer)
|
||||
unsafe { DmaBuffer::assume_init(self.buffer) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ use libk_util::{ConstAssert, IsTrue};
|
||||
use static_assertions::const_assert_eq;
|
||||
|
||||
use crate::{
|
||||
MAX_PRD_SIZE,
|
||||
command::{AtaCommand, AtaIdentify, AtaIdentifyResponse},
|
||||
error::AhciError,
|
||||
MAX_PRD_SIZE,
|
||||
};
|
||||
|
||||
pub const COMMAND_LIST_LENGTH: usize = 32;
|
||||
@@ -20,7 +20,7 @@ const AHCI_FIS_REG_H2D: u8 = 0x27;
|
||||
#[repr(C)]
|
||||
pub struct AtaString<const N: usize>
|
||||
where
|
||||
ConstAssert<{ N % 2 == 0 }>: IsTrue,
|
||||
ConstAssert<{ N.is_multiple_of(2) }>: IsTrue,
|
||||
{
|
||||
data: [u8; N],
|
||||
}
|
||||
@@ -243,7 +243,7 @@ impl AtaIdentifyResponse {
|
||||
|
||||
impl<const N: usize> AtaString<N>
|
||||
where
|
||||
ConstAssert<{ N % 2 == 0 }>: IsTrue,
|
||||
ConstAssert<{ N.is_multiple_of(2) }>: IsTrue,
|
||||
{
|
||||
#[allow(clippy::inherent_to_string)]
|
||||
pub fn to_string(&self) -> String {
|
||||
|
||||
@@ -15,18 +15,18 @@ use device_api::{
|
||||
use error::AhciError;
|
||||
use libk::{device::manager::probe_partitions, dma::DmaBuffer, fs::devfs, task::runtime};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use port::AhciPort;
|
||||
use regs::{PortRegs, Regs};
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||
use ygg_driver_pci::{
|
||||
PciCommandRegister, PciConfigurationSpace,
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
PciCommandRegister, PciConfigurationSpace,
|
||||
};
|
||||
use yggdrasil_abi::{error::Error, io::FileMode};
|
||||
|
||||
use crate::regs::{Version, CAP, GHC, SSTS};
|
||||
use crate::regs::{CAP, GHC, SSTS, Version};
|
||||
|
||||
mod command;
|
||||
mod data;
|
||||
|
||||
@@ -16,18 +16,18 @@ use libk::{
|
||||
error::Error,
|
||||
};
|
||||
use libk_mm::{
|
||||
address::PhysicalAddress, device::DeviceMemoryIo, table::MapAttributes, OnDemandPage,
|
||||
PageProvider, VirtualPage,
|
||||
OnDemandPage, PageProvider, VirtualPage, address::PhysicalAddress, device::DeviceMemoryIo,
|
||||
table::MapAttributes,
|
||||
};
|
||||
use libk_util::{sync::IrqSafeSpinlock, waker::QueueWaker, OneTimeInit};
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock, waker::QueueWaker};
|
||||
use tock_registers::interfaces::{Readable, Writeable};
|
||||
|
||||
use crate::{
|
||||
command::{AtaCommand, AtaIdentify, AtaReadDmaEx},
|
||||
data::{CommandListEntry, CommandTable, ReceivedFis, COMMAND_LIST_LENGTH},
|
||||
error::AhciError,
|
||||
regs::{PortRegs, CMD_PENDING, CMD_READY, IE, TFD},
|
||||
AhciController, MAX_COMMANDS, MAX_PRD_SIZE, SECTOR_SIZE,
|
||||
command::{AtaCommand, AtaIdentify, AtaReadDmaEx},
|
||||
data::{COMMAND_LIST_LENGTH, CommandListEntry, CommandTable, ReceivedFis},
|
||||
error::AhciError,
|
||||
regs::{CMD_PENDING, CMD_READY, IE, PortRegs, TFD},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
@@ -319,11 +319,11 @@ impl BlockDevice for AhciPort {
|
||||
position: u64,
|
||||
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
|
||||
) -> Result<(), Error> {
|
||||
if buffer.len() % SECTOR_SIZE != 0 {
|
||||
if !buffer.len().is_multiple_of(SECTOR_SIZE) {
|
||||
log::warn!("ahci: misaligned buffer size: {}", buffer.len());
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
if position % SECTOR_SIZE as u64 != 0 {
|
||||
if !position.is_multiple_of(SECTOR_SIZE as u64) {
|
||||
log::warn!("ahci: misaligned read");
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "ygg_driver_nvme"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
authors = ["Mark Poliakov <mark@alnyan.me>"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use core::fmt::{self, Write};
|
||||
|
||||
use libk::dma::BusAddress;
|
||||
use tock_registers::{interfaces::Readable, register_structs, registers::ReadOnly, UIntLike};
|
||||
use tock_registers::{UIntLike, interfaces::Readable, register_structs, registers::ReadOnly};
|
||||
|
||||
use crate::queue::PhysicalRegionPage;
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ use libk::{
|
||||
error::Error,
|
||||
};
|
||||
use libk_mm::{
|
||||
OnDemandPage, PageProvider, PageSlice, VirtualPage,
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
table::MapAttributes,
|
||||
OnDemandPage, PageProvider, PageSlice, VirtualPage,
|
||||
};
|
||||
|
||||
use crate::{command::IdentifyNamespaceRequest, register_nvme_namespace, IoDirection};
|
||||
use crate::{IoDirection, command::IdentifyNamespaceRequest, register_nvme_namespace};
|
||||
|
||||
use super::{error::NvmeError, NvmeController};
|
||||
use super::{NvmeController, error::NvmeError};
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct NvmeNamespace {
|
||||
@@ -92,10 +92,10 @@ impl BlockDevice for NvmeNamespace {
|
||||
position: u64,
|
||||
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
|
||||
) -> Result<(), Error> {
|
||||
if position % self.block_size() as u64 != 0 {
|
||||
if !position.is_multiple_of(self.block_size() as u64) {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
if buffer.len() % self.block_size() != 0 || buffer.is_empty() {
|
||||
if !buffer.len().is_multiple_of(self.block_size()) || buffer.is_empty() {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
let lba = position / self.block_size() as u64;
|
||||
@@ -115,10 +115,10 @@ impl BlockDevice for NvmeNamespace {
|
||||
}
|
||||
|
||||
async fn write_aligned(&self, position: u64, buffer: DmaSlice<'_, u8>) -> Result<(), Error> {
|
||||
if position % self.block_size() as u64 != 0 {
|
||||
if !position.is_multiple_of(self.block_size() as u64) {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
if buffer.len() % self.block_size() != 0 || buffer.is_empty() {
|
||||
if !buffer.len().is_multiple_of(self.block_size()) || buffer.is_empty() {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
let lba = position / self.block_size() as u64;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(const_trait_impl, let_chains, if_let_guard, maybe_uninit_slice)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![allow(missing_docs)]
|
||||
#![no_std]
|
||||
// TODO
|
||||
@@ -7,7 +7,7 @@
|
||||
extern crate alloc;
|
||||
|
||||
use core::{
|
||||
mem::{size_of, MaybeUninit},
|
||||
mem::{MaybeUninit, size_of},
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
time::Duration,
|
||||
};
|
||||
@@ -27,10 +27,10 @@ use libk::{
|
||||
fs::devfs,
|
||||
task::{cpu_count, cpu_index, runtime},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo, L3_PAGE_SIZE};
|
||||
use libk_mm::{L3_PAGE_SIZE, address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{
|
||||
sync::{IrqGuard, IrqSafeSpinlock},
|
||||
OneTimeInit,
|
||||
sync::{IrqGuard, IrqSafeSpinlock},
|
||||
};
|
||||
use queue::PrpList;
|
||||
use regs::{CAP, CC};
|
||||
@@ -40,9 +40,9 @@ use tock_registers::{
|
||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||
};
|
||||
use ygg_driver_pci::{
|
||||
PciCommandRegister, PciConfigurationSpace,
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
PciCommandRegister, PciConfigurationSpace,
|
||||
};
|
||||
use yggdrasil_abi::{error::Error, io::FileMode};
|
||||
|
||||
@@ -284,8 +284,8 @@ impl NvmeController {
|
||||
|
||||
unsafe fn doorbell_pair(&self, idx: usize) -> (*mut u32, *mut u32) {
|
||||
let regs = self.regs.lock();
|
||||
let sq_ptr = regs.doorbell_ptr(self.doorbell_shift, false, idx);
|
||||
let cq_ptr = regs.doorbell_ptr(self.doorbell_shift, true, idx);
|
||||
let sq_ptr = unsafe { regs.doorbell_ptr(self.doorbell_shift, false, idx) };
|
||||
let cq_ptr = unsafe { regs.doorbell_ptr(self.doorbell_shift, true, idx) };
|
||||
(sq_ptr, cq_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ impl PrpList {
|
||||
size: usize,
|
||||
) -> Result<Self, NvmeError> {
|
||||
// TODO hardcoded page size
|
||||
if base.into_u64() % 0x1000 != 0 {
|
||||
if !base.into_u64().is_multiple_of(0x1000) {
|
||||
todo!();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(generic_const_exprs, maybe_uninit_slice)]
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
#![no_std]
|
||||
|
||||
@@ -23,11 +23,11 @@ use libk::{
|
||||
task::{runtime, sync::AsyncMutex},
|
||||
};
|
||||
use libk_mm::{
|
||||
address::PhysicalAddress, table::MapAttributes, OnDemandPage, PageProvider, VirtualPage,
|
||||
OnDemandPage, PageProvider, VirtualPage, address::PhysicalAddress, table::MapAttributes,
|
||||
};
|
||||
use libk_util::{
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
|
||||
OneTimeInit,
|
||||
sync::{IrqSafeSpinlock, spin_rwlock::IrqSafeRwLock},
|
||||
};
|
||||
use transport::{ScsiTransport, ScsiTransportWrapper};
|
||||
use yggdrasil_abi::io::FileMode;
|
||||
@@ -40,7 +40,7 @@ pub mod transport;
|
||||
|
||||
pub struct ScsiEnclosure {
|
||||
transport: AsyncMutex<ScsiTransportWrapper>,
|
||||
units: Vec<IrqSafeRwLock<Option<Arc<ScsiUnit>>>>,
|
||||
units: Vec<AsyncMutex<Option<Arc<ScsiUnit>>>>,
|
||||
index: OneTimeInit<u32>,
|
||||
shutdown: AtomicBool,
|
||||
}
|
||||
@@ -60,7 +60,7 @@ impl ScsiEnclosure {
|
||||
lun_count: usize,
|
||||
) -> Result<Arc<Self>, Error> {
|
||||
let transport = AsyncMutex::new(ScsiTransportWrapper::new(transport));
|
||||
let units = (0..lun_count).map(|_| IrqSafeRwLock::new(None)).collect();
|
||||
let units = (0..lun_count).map(|_| AsyncMutex::new(None)).collect();
|
||||
let this = Arc::new(Self {
|
||||
transport,
|
||||
units,
|
||||
@@ -74,7 +74,7 @@ impl ScsiEnclosure {
|
||||
if this.probe_lun(i as u8).await
|
||||
&& let Ok(unit) = ScsiUnit::setup(this.clone(), i as u8).await
|
||||
{
|
||||
*this.units[i].write() = Some(unit);
|
||||
*this.units[i].lock().await = Some(unit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ impl ScsiEnclosure {
|
||||
async fn poll(self: &Arc<Self>) {
|
||||
let index = *self.index.get();
|
||||
for lun in 0..self.units.len() {
|
||||
let mut slot = self.units[lun].write();
|
||||
let mut slot = self.units[lun].lock().await;
|
||||
let present = self.probe_lun(lun as u8).await;
|
||||
|
||||
if let Some(unit) = slot.as_ref() {
|
||||
@@ -143,12 +143,12 @@ impl ScsiEnclosure {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn detach(&self) {
|
||||
pub async fn detach(&self) {
|
||||
self.shutdown.store(true, Ordering::Release);
|
||||
let index = self.index.try_get().copied();
|
||||
|
||||
for unit in self.units.iter() {
|
||||
if let Some(unit) = unit.write().take() {
|
||||
if let Some(unit) = unit.lock().await.take() {
|
||||
unit.detach();
|
||||
}
|
||||
}
|
||||
@@ -214,11 +214,11 @@ impl BlockDevice for ScsiUnit {
|
||||
position: u64,
|
||||
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
|
||||
) -> Result<(), Error> {
|
||||
if position % self.lba_size as u64 != 0 {
|
||||
if !position.is_multiple_of(self.lba_size as u64) {
|
||||
log::warn!("scsi: misaligned read");
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
if buffer.len() % self.lba_size != 0 {
|
||||
if !buffer.len().is_multiple_of(self.lba_size) {
|
||||
log::warn!("scsi: misaligned buffer size");
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
@@ -368,10 +368,11 @@ fn register_unit(enclosure_index: u32, lun: u8, unit: Arc<ScsiUnit>) {
|
||||
}
|
||||
|
||||
fn remove_enclosure(index: u32) {
|
||||
log::info!("scsi: enclosure {index} detached");
|
||||
|
||||
let mut devices = SCSI_ENCLOSURES.lock();
|
||||
let mut bitmap = SCSI_BITMAP.lock();
|
||||
|
||||
*bitmap &= !(1 << index);
|
||||
devices.remove(&index);
|
||||
log::info!("scsi: enclosure {index} detached");
|
||||
}
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
// TODO baud rate configuration
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use libk::{
|
||||
debug::DebugSink,
|
||||
device::manager::DEVICE_REGISTRY,
|
||||
vfs::{Terminal, TerminalInput, TerminalOutput},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use tock_registers::{
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||
};
|
||||
use yggdrasil_abi::{error::Error, io::TerminalOptions};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{TerminalOptions, TerminalOutputOptions},
|
||||
};
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
@@ -89,14 +93,25 @@ impl Io {
|
||||
}
|
||||
|
||||
impl TerminalOutput for Pl011Inner {
|
||||
fn write(&self, byte: u8) -> Result<(), Error> {
|
||||
self.io.lock().send(byte);
|
||||
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error> {
|
||||
let mut lock = self.io.lock();
|
||||
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
|
||||
lock.send(b'\r');
|
||||
}
|
||||
lock.send(byte);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
|
||||
fn write_multiple(
|
||||
&self,
|
||||
bytes: &[u8],
|
||||
options: &TerminalOutputOptions,
|
||||
) -> Result<usize, Error> {
|
||||
let mut lock = self.io.lock();
|
||||
for &byte in bytes {
|
||||
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
|
||||
lock.send(b'\r');
|
||||
}
|
||||
lock.send(byte);
|
||||
}
|
||||
Ok(bytes.len())
|
||||
@@ -117,6 +132,11 @@ impl DebugSink for Pl011 {
|
||||
self.inner.get().putc_to_output(byte)
|
||||
}
|
||||
|
||||
fn puts(&self, s: &str) -> Result<(), Error> {
|
||||
self.inner.get().write_to_output(s.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn supports_control_sequences(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::device::{Device, DeviceInitContext};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use libk::{
|
||||
error::Error,
|
||||
fs::sysfs::{self, nodes::SysfsRtcNode},
|
||||
|
||||
@@ -11,11 +11,11 @@ use device_api::{
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{
|
||||
device_tree_driver, util::generic_gpio_config, DeviceTreeGpioPins, DeviceTreePinController,
|
||||
Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext, device_tree_driver,
|
||||
util::generic_gpio_config,
|
||||
},
|
||||
};
|
||||
use libk::event::signal_gpio_event;
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
|
||||
@@ -16,3 +16,4 @@ tock-registers.workspace = true
|
||||
log.workspace = true
|
||||
bytemuck.workspace = true
|
||||
futures-util.workspace = true
|
||||
async-trait.workspace = true
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockController, ClockHandle},
|
||||
clock::{ClockController, ClockHandle, Hertz, IntoHertz},
|
||||
device::{Device, DeviceInitContext},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{device_tree_driver, DeviceTreeClockController, Node, ProbeContext},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{DeviceTreeClockController, Node, ProbeContext, device_tree_driver},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use tock_registers::{
|
||||
interfaces::ReadWriteable,
|
||||
register_bitfields, register_structs,
|
||||
@@ -54,10 +54,10 @@ impl ClockController for Bcm2835Aux {
|
||||
let regs = regs.lock();
|
||||
match clock {
|
||||
Some(0) => {
|
||||
// TODO CPRMAN driver
|
||||
regs.AUX_ENABLES.modify(AUX_ENABLES::MU_ENABLE::SET);
|
||||
Ok(())
|
||||
}
|
||||
None => todo!(),
|
||||
_ => Err(Error::InvalidArgument),
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,16 @@ impl ClockController for Bcm2835Aux {
|
||||
fn disable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
|
||||
match clock {
|
||||
Some(0) => {
|
||||
// TODO CPRMAN driver
|
||||
Ok(54u64.mhz())
|
||||
}
|
||||
_ => Err(Error::InvalidArgument),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceTreeClockController for Bcm2835Aux {
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::ClockHandle,
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
debug::DebugSink,
|
||||
device::manager::DEVICE_REGISTRY,
|
||||
vfs::{Terminal, TerminalInput, TerminalOutput},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use tock_registers::{
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, ReadWrite},
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{TerminalOptions, TerminalOutputOptions},
|
||||
};
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
AUX_MU_IER_REG [
|
||||
RX_IRQ OFFSET(0) NUMBITS(1) [],
|
||||
TX_IRQ OFFSET(1) NUMBITS(1) [],
|
||||
],
|
||||
AUX_MU_IIR_REG [
|
||||
IID OFFSET(1) NUMBITS(2) [
|
||||
None = 0,
|
||||
TxEmpty = 1,
|
||||
RxNotEmpty = 2,
|
||||
],
|
||||
PENDING OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
AUX_MU_LSR_REG [
|
||||
TX_EMPTY OFFSET(5) NUMBITS(1) [],
|
||||
]
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
Regs {
|
||||
(0x00 => AUX_MU_IO_REG: ReadWrite<u32>),
|
||||
(0x04 => AUX_MU_IER_REG: ReadWrite<u32, AUX_MU_IER_REG::Register>),
|
||||
(0x08 => AUX_MU_IIR_REG: ReadWrite<u32, AUX_MU_IIR_REG::Register>),
|
||||
(0x0C => _0),
|
||||
(0x14 => AUX_MU_LSR_REG: ReadOnly<u32, AUX_MU_LSR_REG::Register>),
|
||||
(0x18 => _1),
|
||||
(0x30 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
}
|
||||
|
||||
/// Broadcom 283x mini-UART driver
|
||||
pub struct Bcm2835AuxUart {
|
||||
base: PhysicalAddress,
|
||||
irq: IrqHandle,
|
||||
clock: ClockHandle,
|
||||
inner: OneTimeInit<Arc<Terminal<Inner>>>,
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
fn write_byte(&self, byte: u8) -> Result<(), Error> {
|
||||
if byte == b'\n' {
|
||||
self.write_byte(b'\r').ok();
|
||||
}
|
||||
|
||||
while !self
|
||||
.AUX_MU_LSR_REG
|
||||
.matches_all(AUX_MU_LSR_REG::TX_EMPTY::SET)
|
||||
{
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
self.AUX_MU_IO_REG.set(byte as u32);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_bytes(&self, bytes: &[u8]) -> Result<(), Error> {
|
||||
for &byte in bytes {
|
||||
self.write_byte(byte)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TerminalOutput for Inner {
|
||||
fn write(&self, byte: u8) -> Result<(), Error> {
|
||||
self.regs.lock().write_byte(byte)
|
||||
}
|
||||
|
||||
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
|
||||
self.regs.lock().write_bytes(bytes)?;
|
||||
Ok(bytes.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugSink for Bcm2835AuxUart {
|
||||
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 InterruptHandler for Bcm2835AuxUart {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let inner = self.inner.get();
|
||||
|
||||
let (status, byte) = {
|
||||
let regs = inner.output().regs.lock();
|
||||
|
||||
// Reset IRQ
|
||||
regs.AUX_MU_IIR_REG.modify(AUX_MU_IIR_REG::IID::SET);
|
||||
|
||||
let byte = regs.AUX_MU_IO_REG.get() as u8;
|
||||
let status = regs
|
||||
.AUX_MU_IIR_REG
|
||||
.matches_all(AUX_MU_IIR_REG::PENDING::SET);
|
||||
|
||||
(status, byte)
|
||||
};
|
||||
|
||||
if status {
|
||||
inner.write_to_input(byte);
|
||||
}
|
||||
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for Bcm2835AuxUart {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
// TODO initialize pinctrl
|
||||
|
||||
self.clock.enable()?;
|
||||
|
||||
let regs = unsafe { DeviceMemoryIo::map(self.base, Default::default()) }?;
|
||||
let config = TerminalOptions {
|
||||
output: TerminalOutputOptions::NL_TO_CRNL,
|
||||
..Default::default()
|
||||
};
|
||||
let output = Inner {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
};
|
||||
let input = TerminalInput::with_capacity(64)?;
|
||||
|
||||
let inner = self
|
||||
.inner
|
||||
.init(Arc::new(Terminal::from_parts(config, input, output)));
|
||||
|
||||
DEVICE_REGISTRY
|
||||
.serial_terminal
|
||||
.register(inner.clone(), Some(self.clone()))
|
||||
.ok();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
self.irq.register(self.clone())?;
|
||||
self.irq.enable()?;
|
||||
|
||||
let inner = self.inner.get().output();
|
||||
let regs = inner.regs.lock();
|
||||
|
||||
regs.AUX_MU_IER_REG
|
||||
.modify(AUX_MU_IER_REG::RX_IRQ::SET + AUX_MU_IER_REG::TX_IRQ::CLEAR);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"bcm2835 mini-UART"
|
||||
}
|
||||
}
|
||||
|
||||
// TODO handle pinctrl
|
||||
device_tree_driver! {
|
||||
compatible: ["brcm,bcm2835-aux-uart"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
let irq = node.interrupt(0)?;
|
||||
let clock = node.clock(0)?;
|
||||
|
||||
Some(Arc::new(Bcm2835AuxUart {
|
||||
base,
|
||||
irq,
|
||||
clock,
|
||||
inner: OneTimeInit::new(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockController, ClockHandle, Hertz},
|
||||
device::{Device, DeviceInitContext},
|
||||
};
|
||||
use device_tree::{
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{DeviceTreeClockController, Node, ProbeContext, device_tree_driver},
|
||||
};
|
||||
use libk::error::Error;
|
||||
|
||||
use crate::mbox::{Bcm2835Mbox, Bcm2835VcClock};
|
||||
|
||||
const CLK_VPU: u32 = 0x14;
|
||||
|
||||
struct Cprman {
|
||||
clk_osc: ClockHandle,
|
||||
mbox: Arc<Bcm2835Mbox>,
|
||||
}
|
||||
|
||||
impl Device for Cprman {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
let _ = &self.clk_osc;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"bcm2711-cprman"
|
||||
}
|
||||
}
|
||||
|
||||
impl ClockController for Cprman {
|
||||
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
|
||||
let vc_clock = match clock {
|
||||
Some(CLK_VPU) => Bcm2835VcClock::Core,
|
||||
Some(n) => todo!("clock_rate({n:#02x})"),
|
||||
None => return Err(Error::InvalidArgument),
|
||||
};
|
||||
|
||||
let rate = self.mbox.vc_clock_rate(vc_clock)?;
|
||||
|
||||
Ok(rate)
|
||||
}
|
||||
|
||||
fn set_clock_rate(&self, clock: Option<u32>, rate: Hertz) -> Result<Hertz, Error> {
|
||||
let _ = clock;
|
||||
let _ = rate;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||
let _ = clock;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||
let _ = clock;
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceTreeClockController for Cprman {
|
||||
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: ["brcm,bcm2711-cprman"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let _base = node.map_base(context, 0)?;
|
||||
let mbox = Node::by_compatible("brcm,bcm2835-mbox", true).unwrap().device().unwrap();
|
||||
let mbox = Arc::downcast::<Bcm2835Mbox>(mbox.as_any()).unwrap();
|
||||
let clk_osc = node.clock(0)?;
|
||||
|
||||
let cprman = Arc::new(Cprman {
|
||||
clk_osc,
|
||||
mbox,
|
||||
});
|
||||
|
||||
node.make_clock_controller(cprman.clone());
|
||||
Some(cprman)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@ use device_api::{
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{
|
||||
device_tree_driver, util::generic_gpio_config, DeviceTreeGpioPins, DeviceTreePinController,
|
||||
Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext, device_tree_driver,
|
||||
util::generic_gpio_config,
|
||||
},
|
||||
};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use device_api::{
|
||||
clock::{ClockHandle, Hertz},
|
||||
device::{Device, DeviceInitContext},
|
||||
i2c::{I2CAddress, I2CController, I2CMessage, I2CTransfer},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use futures_util::task::AtomicWaker;
|
||||
use libk::{device::manager::DEVICE_REGISTRY, error::Error};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::{OneTimeInit, event::BitmapEvent, sync::spin_rwlock::IrqSafeRwLock};
|
||||
use tock_registers::{
|
||||
LocalRegisterCopy,
|
||||
fields::FieldValue,
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::ReadWrite,
|
||||
};
|
||||
use yggdrasil_abi::io::device::i2c::I2CMasterInfo;
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
C [
|
||||
I2CEN OFFSET(15) NUMBITS(1) [],
|
||||
INTR OFFSET(10) NUMBITS(1) [],
|
||||
INTT OFFSET(9) NUMBITS(1) [],
|
||||
INTD OFFSET(8) NUMBITS(1) [],
|
||||
ST OFFSET(7) NUMBITS(1) [],
|
||||
CLEAR OFFSET(4) NUMBITS(2) [],
|
||||
READ OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
S [
|
||||
CLKT OFFSET(9) NUMBITS(1) [],
|
||||
ERR OFFSET(8) NUMBITS(1) [],
|
||||
RXF OFFSET(7) NUMBITS(1) [],
|
||||
TXE OFFSET(6) NUMBITS(1) [],
|
||||
RXD OFFSET(5) NUMBITS(1) [],
|
||||
TXD OFFSET(4) NUMBITS(1) [],
|
||||
RXR OFFSET(3) NUMBITS(1) [],
|
||||
TXW OFFSET(2) NUMBITS(1) [],
|
||||
DONE OFFSET(1) NUMBITS(1) [],
|
||||
TA OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
Regs {
|
||||
(0x00 => C: ReadWrite<u32, C::Register>),
|
||||
(0x04 => S: ReadWrite<u32, S::Register>),
|
||||
(0x08 => DLEN: ReadWrite<u32>),
|
||||
(0x0C => A: ReadWrite<u32>),
|
||||
(0x10 => FIFO: ReadWrite<u32>),
|
||||
(0x14 => DIV: ReadWrite<u32>),
|
||||
(0x18 => DEL: ReadWrite<u32>),
|
||||
(0x1C => CLKT: ReadWrite<u32>),
|
||||
(0x20 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
struct I2CState {
|
||||
status: BitmapEvent<AtomicWaker>,
|
||||
}
|
||||
|
||||
struct I2C {
|
||||
name: &'static str,
|
||||
clock_frequency: Option<Hertz>,
|
||||
irq: IrqHandle,
|
||||
clock: Option<ClockHandle>,
|
||||
regs: IrqSafeRwLock<DeviceMemoryIo<'static, Regs>>,
|
||||
index: OneTimeInit<u32>,
|
||||
state: I2CState,
|
||||
}
|
||||
|
||||
impl I2CState {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
status: BitmapEvent::new(AtomicWaker::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All of these are thread-unsafe, but I2C subsystem locks the peripheral by process
|
||||
impl I2C {
|
||||
async fn wait_for_event(&self) -> LocalRegisterCopy<u32, S::Register> {
|
||||
let event = self.state.status.wait().await;
|
||||
LocalRegisterCopy::new(event as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for I2C {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
// TODO
|
||||
let _ = &self.clock;
|
||||
|
||||
log::info!("{}: initialize", self.name);
|
||||
let regs = self.regs.write();
|
||||
regs.C.set(0);
|
||||
|
||||
let index = DEVICE_REGISTRY.i2c.register_bus(self.clone())?;
|
||||
self.index.init(index);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
self.irq.register(self.clone())?;
|
||||
self.irq.enable()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for I2C {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let regs = self.regs.write();
|
||||
let event = regs.S.extract();
|
||||
// log::info!("I2C irq {:#x}", event.get());
|
||||
let mut clear = FieldValue::none();
|
||||
if event.matches_all(S::RXR::SET) {
|
||||
clear += C::INTR::CLEAR;
|
||||
}
|
||||
if event.matches_all(S::TXW::SET) {
|
||||
clear += C::INTT::CLEAR;
|
||||
}
|
||||
if event.matches_all(S::DONE::SET) {
|
||||
clear += C::INTD::CLEAR;
|
||||
}
|
||||
regs.C.modify(clear);
|
||||
self.state.status.signal(event.get() as u64);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl I2CController for I2C {
|
||||
fn bus_number(&self) -> u32 {
|
||||
*self.index.get()
|
||||
}
|
||||
|
||||
fn child_number(&self) -> Option<u32> {
|
||||
None
|
||||
}
|
||||
|
||||
fn set_speed(&self, speed: Hertz) -> Result<Hertz, Error> {
|
||||
if let Some(frequency) = self.clock_frequency {
|
||||
// Fixed frequency
|
||||
if speed == frequency {
|
||||
Ok(speed)
|
||||
} else {
|
||||
Err(Error::InvalidArgument)
|
||||
}
|
||||
} else {
|
||||
todo!("Set i2c speed = {speed}")
|
||||
}
|
||||
}
|
||||
|
||||
fn capabilities(&self) -> I2CMasterInfo {
|
||||
let max_speed_hz = if let Some(frequency) = self.clock_frequency {
|
||||
frequency
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
.0 as u32;
|
||||
I2CMasterInfo {
|
||||
max_speed_hz,
|
||||
supports_10bit_addresses: true,
|
||||
}
|
||||
}
|
||||
|
||||
async fn i2c_transfer(
|
||||
&self,
|
||||
address: I2CAddress,
|
||||
transfer: &mut I2CTransfer,
|
||||
) -> Result<usize, Error> {
|
||||
// TODO validate transfer
|
||||
let address = address.as_8_bit().ok_or(Error::NotImplemented)?;
|
||||
let repeat_start = transfer.repeat_start;
|
||||
let mut nbytes = 0;
|
||||
let mut error = None;
|
||||
for (i, message) in transfer.messages.iter_mut().enumerate() {
|
||||
if i == 0 || repeat_start {
|
||||
let (read, len) = match message {
|
||||
I2CMessage::Read(buffer) => (true, buffer.len()),
|
||||
I2CMessage::Write(buffer) => (false, buffer.len()),
|
||||
};
|
||||
// log::info!("{}: START {:#x} read={}", self.name, address, read);
|
||||
let read = if read { C::READ::SET } else { C::READ::CLEAR };
|
||||
let regs = self.regs.write();
|
||||
regs.S.write(S::ERR::SET + S::DONE::SET);
|
||||
regs.DLEN.set(len as u32);
|
||||
regs.C.modify(C::ST::CLEAR);
|
||||
regs.A.set(address as u32);
|
||||
regs.C.modify(
|
||||
read + C::ST::SET + C::I2CEN::SET + C::INTD::SET + C::INTR::SET + C::INTT::SET,
|
||||
);
|
||||
}
|
||||
|
||||
let mut pos = 0;
|
||||
let status = loop {
|
||||
let s = self.wait_for_event().await;
|
||||
let regs = self.regs.write();
|
||||
if s.matches_all(S::ERR::SET) || s.matches_all(S::DONE::SET) {
|
||||
break s;
|
||||
}
|
||||
match message {
|
||||
I2CMessage::Write(buffer) => {
|
||||
if s.matches_all(S::TXW::SET) {
|
||||
while regs.S.matches_all(S::TXD::SET) && pos < buffer.len() {
|
||||
let byte = buffer[pos];
|
||||
// log::info!("{}: tx {:#x}", self.name, byte);
|
||||
regs.FIFO.set(byte as u32);
|
||||
pos += 1;
|
||||
nbytes += 1;
|
||||
}
|
||||
}
|
||||
regs.C.modify(C::INTT::SET);
|
||||
}
|
||||
I2CMessage::Read(buffer) => {
|
||||
if s.matches_all(S::RXR::SET) {
|
||||
while regs.S.matches_all(S::RXD::SET) && pos < buffer.len() {
|
||||
let byte = regs.FIFO.get() as u8;
|
||||
// log::info!("{}: rx {:#x}", self.name, byte);
|
||||
buffer[pos] = byte;
|
||||
pos += 1;
|
||||
nbytes += 1;
|
||||
}
|
||||
}
|
||||
regs.C.modify(C::INTR::SET);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Finalize message
|
||||
let regs = self.regs.write();
|
||||
if status.matches_all(S::ERR::SET) {
|
||||
regs.S.write(S::DONE::SET + S::ERR::SET);
|
||||
error = Some(Error::HostUnreachable);
|
||||
break;
|
||||
} else if status.matches_all(S::DONE::SET) {
|
||||
regs.S.write(S::DONE::SET);
|
||||
} else {
|
||||
log::error!("{}: transfer finished without DONE or ERR set", self.name);
|
||||
log::error!("{}: S = {:#x}", self.name, status.get());
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
// Finish transfer
|
||||
// log::info!(
|
||||
// "{}: finish xfer, error={:?}, nbytes={}",
|
||||
// self.name,
|
||||
// error,
|
||||
// nbytes
|
||||
// );
|
||||
let regs = self.regs.write();
|
||||
regs.C.set(0);
|
||||
|
||||
match error {
|
||||
Some(error) => Err(error),
|
||||
None => Ok(nbytes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["brcm,bcm2711-i2c", "brcm,bcm2835-i2c"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let clock_frequency = node.prop_usize("clock-frequency").map(|p| Hertz(p as u64));
|
||||
let base = node.map_base(context, 0)?;
|
||||
let name = node.name().unwrap_or("bcm2835-i2c");
|
||||
let irq = node.interrupt(0)?;
|
||||
let clock = node.clock(0);
|
||||
|
||||
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
|
||||
|
||||
let i2c = Arc::new(I2C {
|
||||
name,
|
||||
clock_frequency,
|
||||
irq,
|
||||
clock,
|
||||
index: OneTimeInit::new(),
|
||||
regs: IrqSafeRwLock::new(regs),
|
||||
state: I2CState::new()
|
||||
});
|
||||
|
||||
node.make_i2c_controller(i2c.clone());
|
||||
|
||||
Some(i2c)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,9 @@
|
||||
extern crate alloc;
|
||||
|
||||
mod aux;
|
||||
mod aux_uart;
|
||||
// mod aux_uart;
|
||||
mod cprman;
|
||||
mod gpio;
|
||||
mod i2c;
|
||||
mod mbox;
|
||||
mod spi;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use core::{cell::UnsafeCell, mem::MaybeUninit};
|
||||
use core::{any::Any, cell::UnsafeCell, mem::MaybeUninit};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use device_api::device::{Device, DeviceInitContext};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use device_api::{
|
||||
clock::Hertz,
|
||||
device::{Device, DeviceInitContext},
|
||||
};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use kernel_arch_aarch64::mem::table::L3;
|
||||
use libk::device::{
|
||||
display::{
|
||||
@@ -11,10 +14,10 @@ use libk::device::{
|
||||
manager::DEVICE_REGISTRY,
|
||||
};
|
||||
use libk_mm::{
|
||||
OnDemandPage, PageBox, PageProvider, VirtualPage,
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
device::DeviceMemoryIo,
|
||||
table::{EntryLevel, MapAttributes},
|
||||
OnDemandPage, PageBox, PageProvider, VirtualPage,
|
||||
};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use tock_registers::{
|
||||
@@ -61,7 +64,13 @@ register_structs! {
|
||||
}
|
||||
}
|
||||
|
||||
struct Bcm2835Mbox {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
#[repr(u32)]
|
||||
pub(crate) enum Bcm2835VcClock {
|
||||
Core = 4,
|
||||
}
|
||||
|
||||
pub(crate) struct Bcm2835Mbox {
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
}
|
||||
|
||||
@@ -85,13 +94,20 @@ impl Device for Bcm2835Mbox {
|
||||
fn display_name(&self) -> &str {
|
||||
"bcm2835-mbox"
|
||||
}
|
||||
|
||||
fn as_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Bcm2835Mbox {
|
||||
const RAM_TO_GPU_OFFSET: u32 = 0x40000000;
|
||||
|
||||
const CHANNEL_FRAMEBUFFER: u32 = 1;
|
||||
const CHANNEL_ARM2VC: u32 = 8;
|
||||
|
||||
pub unsafe fn call_raw(&self, buffer: PhysicalAddress, channel: u32) -> Result<(), Error> {
|
||||
log::info!("bcm2835-mbox: mbox call buffer={buffer:#x}, channel={channel}");
|
||||
log::debug!("bcm2835-mbox: mbox call buffer={buffer:#x}, channel={channel}");
|
||||
|
||||
let address = buffer
|
||||
.try_into_u32()
|
||||
@@ -125,10 +141,31 @@ impl Bcm2835Mbox {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn configure_framebuffer(
|
||||
&self,
|
||||
mode_info: &DisplayMode,
|
||||
) -> Result<FramebufferResponse, Error> {
|
||||
pub fn vc_clock_rate(&self, clock: Bcm2835VcClock) -> Result<Hertz, Error> {
|
||||
let mut buffer = PageBox::new_slice(0u32, 4096 / 4)?;
|
||||
buffer[0] = 9 * 4; // buffer size
|
||||
buffer[1] = 0; // process request
|
||||
|
||||
// Tag 1 (Response)
|
||||
buffer[2] = 0x00030002; // tag
|
||||
buffer[3] = 0; // value buffer size
|
||||
buffer[4] = 0; // request
|
||||
buffer[5] = clock as u32; // value buffer[0]
|
||||
buffer[6] = 0; // value buffer[1]
|
||||
buffer[7] = 0;
|
||||
|
||||
// End tag
|
||||
buffer[8] = 0;
|
||||
|
||||
unsafe { self.call_raw(buffer.as_physical_address(), Self::CHANNEL_ARM2VC) }?;
|
||||
if buffer[4] == 0 || buffer[1] == 0 {
|
||||
todo!();
|
||||
}
|
||||
let rate = Hertz::from(buffer[6]);
|
||||
Ok(rate)
|
||||
}
|
||||
|
||||
fn configure_framebuffer(&self, mode_info: &DisplayMode) -> Result<FramebufferResponse, Error> {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
struct FramebufferRequest {
|
||||
@@ -158,7 +195,7 @@ impl Bcm2835Mbox {
|
||||
}))?;
|
||||
|
||||
// TODO flush cache for buffer
|
||||
unsafe { self.call_raw(buffer.as_physical_address(), 0x01) }?;
|
||||
unsafe { self.call_raw(buffer.as_physical_address(), Self::CHANNEL_FRAMEBUFFER) }?;
|
||||
|
||||
let buffer = buffer.get_mut();
|
||||
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
use core::iter;
|
||||
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use device_api::{
|
||||
clock::{ClockHandle, Hertz},
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::IrqHandle,
|
||||
spi::SpiController,
|
||||
};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use libk::{device::manager::DEVICE_REGISTRY, error::Error};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use tock_registers::{
|
||||
interfaces::{Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::ReadWrite,
|
||||
};
|
||||
use yggdrasil_abi::io::device::spi::{SpiClockPhase, SpiClockPolarity, SpiConfig};
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
CS [
|
||||
LEN_LONG OFFSET(25) NUMBITS(1) [],
|
||||
DMA_LEN OFFSET(24) NUMBITS(1) [],
|
||||
CSPOL2 OFFSET(23) NUMBITS(1) [],
|
||||
CSPOL1 OFFSET(22) NUMBITS(1) [],
|
||||
CSPOL0 OFFSET(21) NUMBITS(1) [],
|
||||
RXF OFFSET(20) NUMBITS(1) [],
|
||||
RXR OFFSET(19) NUMBITS(1) [],
|
||||
TXD OFFSET(18) NUMBITS(1) [],
|
||||
RXD OFFSET(17) NUMBITS(1) [],
|
||||
DONE OFFSET(16) NUMBITS(1) [],
|
||||
LEN OFFSET(13) NUMBITS(1) [],
|
||||
REN OFFSET(12) NUMBITS(1) [],
|
||||
ADCS OFFSET(11) NUMBITS(1) [],
|
||||
INTR OFFSET(10) NUMBITS(1) [],
|
||||
INTD OFFSET(9) NUMBITS(1) [],
|
||||
DMAEN OFFSET(8) NUMBITS(1) [],
|
||||
TA OFFSET(7) NUMBITS(1) [],
|
||||
CSPOL OFFSET(6) NUMBITS(1) [],
|
||||
CLEAR OFFSET(4) NUMBITS(2) [],
|
||||
CPOL OFFSET(3) NUMBITS(1) [
|
||||
IdleLow = 0,
|
||||
IdleHigh = 1
|
||||
],
|
||||
CPHA OFFSET(2) NUMBITS(1) [
|
||||
CaptureOnFirstTransition = 0,
|
||||
CaptureOnSecondTransition = 1
|
||||
],
|
||||
CS OFFSET(0) NUMBITS(2) [],
|
||||
]
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
Regs {
|
||||
(0x00 => CS: ReadWrite<u32, CS::Register>),
|
||||
(0x04 => FIFO: ReadWrite<u32>),
|
||||
(0x08 => CLK: ReadWrite<u32>),
|
||||
(0x0C => DLEN: ReadWrite<u32>),
|
||||
(0x10 => LTOH: ReadWrite<u32>),
|
||||
(0x14 => DC: ReadWrite<u32>),
|
||||
(0x18 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Spi {
|
||||
name: &'static str,
|
||||
clock: ClockHandle,
|
||||
irq: IrqHandle,
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
}
|
||||
|
||||
impl Device for Spi {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
let _ = &self.irq;
|
||||
let regs = self.regs.lock();
|
||||
regs.CS.set(0);
|
||||
|
||||
DEVICE_REGISTRY.spi.register_bus(self.clone()).ok();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
fn start_transfer(&self, core_clock: Hertz, config: &SpiConfig) -> Result<(), Error> {
|
||||
let want_clock = Hertz::from(config.frequency.unwrap_or(100000));
|
||||
let divider = Hertz::divider(core_clock, want_clock).ok_or(Error::InvalidArgument)?;
|
||||
let divider: u16 = divider.try_into().map_err(|_| Error::InvalidArgument)?;
|
||||
let divider = divider.wrapping_add(1) & !1;
|
||||
|
||||
let mut cs = CS::REN::SET + CS::TA::SET;
|
||||
if let Some(cs_index) = config.chip_select_index
|
||||
&& cs_index < 3
|
||||
{
|
||||
cs += CS::CS.val(cs_index);
|
||||
}
|
||||
if let Some(cpol) = config.clock_polarity {
|
||||
match cpol {
|
||||
SpiClockPolarity::IdleLow => cs += CS::CPOL::IdleLow,
|
||||
SpiClockPolarity::IdleHigh => cs += CS::CPOL::IdleHigh,
|
||||
}
|
||||
}
|
||||
if let Some(cpha) = config.clock_phase {
|
||||
match cpha {
|
||||
SpiClockPhase::CaptureOnFirstTransition => cs += CS::CPHA::CaptureOnFirstTransition,
|
||||
SpiClockPhase::CaptureOnSecondTransition => {
|
||||
cs += CS::CPHA::CaptureOnSecondTransition
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.CLK.set(divider as u32);
|
||||
self.CS.write(cs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tx_rx_byte(&self, tx: u8) -> Result<Option<u8>, Error> {
|
||||
// Wait for tx
|
||||
loop {
|
||||
let status = self.CS.extract();
|
||||
if status.matches_all(CS::TXD::SET) {
|
||||
break;
|
||||
}
|
||||
if status.matches_all(CS::DONE::SET) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
self.FIFO.set(tx as u32);
|
||||
// Wait for rx
|
||||
loop {
|
||||
let status = self.CS.extract();
|
||||
if status.matches_all(CS::RXD::SET) {
|
||||
break;
|
||||
}
|
||||
if status.matches_all(CS::DONE::SET) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
Ok(Some(self.FIFO.get() as u8))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl SpiController for Spi {
|
||||
async fn spi_transfer(
|
||||
&self,
|
||||
tx_buffer: &[u8],
|
||||
rx_buffer: &mut [u8],
|
||||
config: &SpiConfig,
|
||||
) -> Result<usize, Error> {
|
||||
// TODO interrupt/DMA
|
||||
log::debug!("{}: spi_transfer {} bytes", self.name, rx_buffer.len());
|
||||
let core_clock = self.clock.rate()?;
|
||||
let regs = self.regs.lock();
|
||||
regs.start_transfer(core_clock, config)?;
|
||||
|
||||
let mut len = 0;
|
||||
for (&tx, rx) in iter::zip(tx_buffer, rx_buffer) {
|
||||
match regs.tx_rx_byte(tx)? {
|
||||
Some(b) => {
|
||||
*rx = b;
|
||||
len += 1;
|
||||
}
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["brcm,bcm2835-spi"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let name = node.name().unwrap_or("bcm2835-spi");
|
||||
let base = node.map_base(context, 0)?;
|
||||
let irq = node.interrupt(0)?;
|
||||
let clock = node.clock(0)?;
|
||||
|
||||
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
|
||||
|
||||
let spi = Arc::new(Spi {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
name,
|
||||
clock,
|
||||
irq
|
||||
});
|
||||
|
||||
Some(spi)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,11 @@ use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{
|
||||
device_tree_driver, lookup_phandle, DeviceTreeClockController, DeviceTreeResetController,
|
||||
DeviceTreeSyscon, Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeClockController, DeviceTreeResetController, DeviceTreeSyscon, Node, ProbeContext,
|
||||
device_tree_driver, lookup_phandle,
|
||||
},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
@@ -57,6 +57,16 @@ const SYSCRG_GMAC0_GTXC: usize = 0x1BC / 4;
|
||||
// uart
|
||||
const SYSCRG_UART0_APB: usize = 0x244 / 4;
|
||||
const SYSCRG_UART0_CORE: usize = 0x248 / 4;
|
||||
const SYSCRG_UART1_APB: usize = 0x24C / 4;
|
||||
const SYSCRG_UART1_CORE: usize = 0x250 / 4;
|
||||
const SYSCRG_UART2_APB: usize = 0x254 / 4;
|
||||
const SYSCRG_UART2_CORE: usize = 0x258 / 4;
|
||||
const SYSCRG_UART3_APB: usize = 0x25C / 4;
|
||||
const SYSCRG_UART3_CORE: usize = 0x260 / 4;
|
||||
const SYSCRG_UART4_APB: usize = 0x264 / 4;
|
||||
const SYSCRG_UART4_CORE: usize = 0x268 / 4;
|
||||
const SYSCRG_UART5_APB: usize = 0x26C / 4;
|
||||
const SYSCRG_UART5_CORE: usize = 0x270 / 4;
|
||||
// jtag
|
||||
const SYSCRG_JTAG_CERTIFICATION_TRNG: usize = 0x2F4 / 4;
|
||||
const SYSCRG_CLOCK_COUNT: usize = SYSCRG_JTAG_CERTIFICATION_TRNG + 1;
|
||||
@@ -171,7 +181,7 @@ trait ClockDefinition {
|
||||
const CLOCKS: &'static [Option<(&'static str, ClockDef)>];
|
||||
}
|
||||
|
||||
const SYSCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
|
||||
const SYSCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
|
||||
use ClockDef::*;
|
||||
|
||||
let mut t = [const { None }; SYSCRG_CLOCK_COUNT];
|
||||
@@ -226,11 +236,21 @@ const SYSCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
|
||||
// uart
|
||||
t[SYSCRG_UART0_APB] = Some(("clk_uart0_apb", Gate(SYSCRG_APB0)));
|
||||
t[SYSCRG_UART0_CORE] = Some(("clk_uart0_core", Gate(SYSCRG_OSC)));
|
||||
t[SYSCRG_UART1_APB] = Some(("clk_uart1_apb", Gate(SYSCRG_APB0)));
|
||||
t[SYSCRG_UART1_CORE] = Some(("clk_uart1_core", Gate(SYSCRG_OSC)));
|
||||
t[SYSCRG_UART2_APB] = Some(("clk_uart2_apb", Gate(SYSCRG_APB0)));
|
||||
t[SYSCRG_UART2_CORE] = Some(("clk_uart2_core", Gate(SYSCRG_OSC)));
|
||||
t[SYSCRG_UART3_APB] = Some(("clk_uart3_apb", Gate(SYSCRG_APB0)));
|
||||
t[SYSCRG_UART3_CORE] = Some(("clk_uart3_core", GateDiv(10, SYSCRG_PERH_ROOT)));
|
||||
t[SYSCRG_UART4_APB] = Some(("clk_uart4_apb", Gate(SYSCRG_APB0)));
|
||||
t[SYSCRG_UART4_CORE] = Some(("clk_uart4_core", GateDiv(10, SYSCRG_PERH_ROOT)));
|
||||
t[SYSCRG_UART5_APB] = Some(("clk_uart5_apb", Gate(SYSCRG_APB0)));
|
||||
t[SYSCRG_UART5_CORE] = Some(("clk_uart5_core", GateDiv(10, SYSCRG_PERH_ROOT)));
|
||||
|
||||
t
|
||||
};
|
||||
|
||||
const AONCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
|
||||
const AONCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
|
||||
use ClockDef::*;
|
||||
|
||||
let mut t = [const { None }; AONCRG_CLOCK_COUNT];
|
||||
@@ -262,7 +282,7 @@ const AONCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
|
||||
t
|
||||
};
|
||||
|
||||
const STGCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
|
||||
const STGCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
|
||||
use ClockDef::*;
|
||||
|
||||
let mut t = [const { None }; STGCRG_CLOCK_COUNT];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
#![allow(unsafe_op_in_unsafe_fn, clippy::eq_op, clippy::erasing_op)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
@@ -8,15 +8,14 @@ use device_api::{
|
||||
},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{
|
||||
device_tree_driver,
|
||||
util::{generic_gpio_config, GenericPinctrlBiasConfig, GenericPinctrlConfig},
|
||||
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext, device_tree_driver,
|
||||
util::{GenericPinctrlBiasConfig, GenericPinctrlConfig, generic_gpio_config},
|
||||
},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
|
||||
use libk_util::{bit::BitField, sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use libk_util::{OneTimeInit, bit::BitField, sync::IrqSafeSpinlock};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::device::{Device, DeviceInitContext};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use libk::{
|
||||
error::Error,
|
||||
fs::sysfs::{self, nodes::SysfsRtcNode},
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
@@ -2,20 +2,23 @@ use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{
|
||||
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq,
|
||||
IrqHandle, IrqOptions, IrqVector,
|
||||
ExternalInterruptController, InterruptHandler, Irq, IrqHandle, IrqOptions, IrqPriority,
|
||||
IrqVector,
|
||||
},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{
|
||||
device_tree_driver, lookup_phandle, DeviceTreeInterruptController, Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeInterruptController, Node, ProbeContext, device_tree_driver, lookup_phandle,
|
||||
},
|
||||
};
|
||||
use kernel_arch_riscv64::boot_hart_id;
|
||||
use libk::{arch::Cpu, device::register_external_interrupt_controller};
|
||||
use libk::{
|
||||
arch::Cpu,
|
||||
device::{interrupt::FixedInterruptTable, register_external_interrupt_controller},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
|
||||
use libk_util::{OneTimeInit, sync::spin_rwlock::IrqSafeRwLock};
|
||||
use tock_registers::{
|
||||
interfaces::{Readable, Writeable},
|
||||
register_structs,
|
||||
@@ -77,8 +80,7 @@ register_structs! {
|
||||
struct Context {
|
||||
enable: IrqSafeRwLock<DeviceMemoryIo<'static, ContextEnableRegs>>,
|
||||
control: IrqSafeRwLock<DeviceMemoryIo<'static, ContextControlRegs>>,
|
||||
// TODO scale the table depending on effective MAX_IRQS value
|
||||
table: IrqSafeRwLock<FixedInterruptTable<128>>,
|
||||
table: FixedInterruptTable,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
@@ -95,13 +97,71 @@ struct HartContext {
|
||||
/// RISC-V Platform-Level Interrupt Controller (PLIC) device
|
||||
pub struct Plic {
|
||||
base: PhysicalAddress,
|
||||
max_irqs: usize,
|
||||
max_irq: usize,
|
||||
// hart id -> context map
|
||||
context_map: Vec<HartContext>,
|
||||
inner: OneTimeInit<Inner>,
|
||||
}
|
||||
|
||||
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> {
|
||||
self.context_map.iter().find(|c| c.hart == hart)
|
||||
}
|
||||
@@ -115,8 +175,8 @@ impl Plic {
|
||||
log::error!("plic: irq cannot be zero");
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
if irq as usize >= self.max_irqs {
|
||||
log::error!("plic: irq ({}) >= max_irqs ({})", irq, self.max_irqs);
|
||||
if irq as usize > self.max_irq {
|
||||
log::error!("plic: irq ({}) > max_irq ({})", irq, self.max_irq);
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
Ok(irq)
|
||||
@@ -152,24 +212,33 @@ impl ExternalInterruptController for Plic {
|
||||
fn register_irq(
|
||||
&self,
|
||||
irq: Irq,
|
||||
_options: IrqOptions,
|
||||
options: IrqOptions,
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
self.ensure_init()?;
|
||||
let bsp_hart_id = boot_hart_id() as u32;
|
||||
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
|
||||
.hart_context(bsp_hart_id)
|
||||
.ok_or(Error::InvalidArgument)
|
||||
.inspect_err(|_| log::error!("plic: no context for hart {bsp_hart_id}"))?
|
||||
.context
|
||||
.get();
|
||||
let mut table = context.table.write();
|
||||
// let mut table = context.table.write();
|
||||
|
||||
log::info!(
|
||||
"Bind irq #{irq} -> hart {bsp_hart_id}, {:?}",
|
||||
handler.display_name()
|
||||
);
|
||||
|
||||
table.insert(irq as usize, handler)?;
|
||||
context.table.insert(irq as usize, handler);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -183,72 +252,26 @@ impl ExternalInterruptController for Plic {
|
||||
let context = context.context.get();
|
||||
|
||||
let control = context.control.write();
|
||||
let table = context.table.read();
|
||||
// let table = context.table.read();
|
||||
|
||||
loop {
|
||||
let irq = control.CLAIM.get();
|
||||
if irq == 0 {
|
||||
break;
|
||||
}
|
||||
let vector = IrqVector::Irq(Irq::External(irq));
|
||||
|
||||
if let Some(handler) = table.handler(irq as usize) {
|
||||
handler.clone().handle_irq(vector);
|
||||
} else {
|
||||
log::warn!("plic: no handler for IRQ #{irq}");
|
||||
}
|
||||
|
||||
// Done servicing
|
||||
control.CLAIM.set(irq);
|
||||
let irq = control.CLAIM.get();
|
||||
if irq == 0 {
|
||||
return;
|
||||
}
|
||||
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 {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
log::info!("Initialize RISC-V PLIC");
|
||||
|
||||
let common = DeviceMemoryIo::<CommonRegs>::map(self.base, Default::default())?;
|
||||
|
||||
for i in 0..self.max_irqs - 1 {
|
||||
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_irqs.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: IrqSafeRwLock::new(FixedInterruptTable::new()),
|
||||
});
|
||||
}
|
||||
|
||||
self.inner.init(Inner {
|
||||
common: IrqSafeRwLock::new(common),
|
||||
});
|
||||
self.ensure_init()?;
|
||||
|
||||
register_external_interrupt_controller(self);
|
||||
|
||||
@@ -290,7 +313,7 @@ device_tree_driver! {
|
||||
let ndev = node.prop_usize("riscv,ndev")?;
|
||||
let iext = node.property("interrupts-extended")?;
|
||||
|
||||
let max_irqs = MAX_IRQS.min(ndev);
|
||||
let max_irq = MAX_IRQS.min(ndev);
|
||||
|
||||
// Parse the context -> hart mapping, only select S-mode external interrupts
|
||||
let mut context_map = Vec::new();
|
||||
@@ -302,6 +325,7 @@ device_tree_driver! {
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
log::info!("Context #{context}: mode={mode:?}, hart={hart_id}");
|
||||
if mode != ContextMode::ExternalS {
|
||||
continue;
|
||||
}
|
||||
@@ -323,7 +347,7 @@ device_tree_driver! {
|
||||
|
||||
let intc = Arc::new(Plic {
|
||||
base,
|
||||
max_irqs,
|
||||
max_irq,
|
||||
context_map,
|
||||
inner: OneTimeInit::new(),
|
||||
});
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
[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
|
||||
ygg_driver_net_core.path = "../../net/core"
|
||||
|
||||
static_assertions.workspace = true
|
||||
tock-registers.workspace = true
|
||||
log.workspace = true
|
||||
bytemuck.workspace = true
|
||||
futures-util.workspace = true
|
||||
async-trait.workspace = true
|
||||
@@ -0,0 +1,190 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockController, ClockHandle, Hertz},
|
||||
device::{Device, DeviceInitContext},
|
||||
};
|
||||
use device_tree::{
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{DeviceTreeClockController, Node, ProbeContext, device_tree_driver},
|
||||
};
|
||||
use libk::error::Error;
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use tock_registers::{
|
||||
interfaces::{Readable, Writeable},
|
||||
register_structs,
|
||||
registers::ReadWrite,
|
||||
};
|
||||
|
||||
use crate::pll::{PllCfg, WrpllData};
|
||||
|
||||
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, PllCfg::Register>),
|
||||
(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>>,
|
||||
init: OneTimeInit<()>,
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
fn read_core_pll(&self) -> WrpllData {
|
||||
let pll = self.corepllcfg0.extract();
|
||||
let divr = pll.read(PllCfg::PLLR);
|
||||
let divf = pll.read(PllCfg::PLLF);
|
||||
let divq = pll.read(PllCfg::PLLQ);
|
||||
WrpllData {
|
||||
divq,
|
||||
divr,
|
||||
divf,
|
||||
int_feedback: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Prci {
|
||||
fn ensure_init(&self) {
|
||||
// U-Boot should configure coreclk to 1GHz, but when booting
|
||||
// in QEMU, there is not U-Boot stage, and some peripherals
|
||||
// like PWM expect the clock to be configured this way. So
|
||||
// this needs to be done manually here
|
||||
self.init.or_init_with(|| {
|
||||
let regs = self.regs.lock();
|
||||
if regs.coreclksel.get() != 0 {
|
||||
// coreclk configured to hfclk
|
||||
// configure corepll to output 1GHz and switch to it
|
||||
// divf = 150
|
||||
// divr = 4
|
||||
// divq = 1
|
||||
regs.corepllcfg0.write(
|
||||
PllCfg::PLLF.val(150)
|
||||
+ PllCfg::PLLR.val(4)
|
||||
+ PllCfg::PLLQ.val(1)
|
||||
+ PllCfg::PLLFSEBYPASS::SET,
|
||||
);
|
||||
while !regs.corepllcfg0.matches_all(PllCfg::PLLLOCK::SET) {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
regs.coreclksel.set(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for Prci {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
self.ensure_init();
|
||||
if let Ok(coreclk) = self.clock_rate(Some(CLK_COREPLL)) {
|
||||
log::info!("coreclk = {coreclk}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"sifive,fu540-c000-prci"
|
||||
}
|
||||
}
|
||||
|
||||
impl ClockController for Prci {
|
||||
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
|
||||
self.ensure_init();
|
||||
let _ = &self.clk_rtc;
|
||||
match clock {
|
||||
Some(CLK_COREPLL) => {
|
||||
let regs = self.regs.lock();
|
||||
let hfclk = self.clk_osc.rate()?;
|
||||
// == 0 -> use corepll
|
||||
// == 1 -> use hfclk
|
||||
let coreclksel = regs.coreclksel.get() != 0;
|
||||
let coreclk = match coreclksel {
|
||||
true => hfclk,
|
||||
false => {
|
||||
let pll = regs.read_core_pll();
|
||||
pll.output_rate(hfclk)
|
||||
}
|
||||
};
|
||||
Ok(coreclk)
|
||||
}
|
||||
Some(CLK_TLCLK) => {
|
||||
let coreclk = self.clock_rate(Some(CLK_COREPLL))?;
|
||||
Ok(coreclk / 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> {
|
||||
self.ensure_init();
|
||||
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,
|
||||
init: OneTimeInit::new()
|
||||
});
|
||||
|
||||
node.make_clock_controller(prci.clone());
|
||||
|
||||
Some(prci)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
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::{ReadOnly, ReadWrite},
|
||||
};
|
||||
|
||||
use crate::pll::{PllCfg, WrpllData};
|
||||
|
||||
// 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;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
use core::{mem::MaybeUninit, time::Duration};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::ClockHandle,
|
||||
device::{Device, DeviceInitContext},
|
||||
dma::DmaAllocator,
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{
|
||||
InitSequence, Node, ProbeContext, device_tree_driver, util::read_mac_address,
|
||||
};
|
||||
use futures_util::task::AtomicWaker;
|
||||
use libk::{
|
||||
dma::DmaBuffer,
|
||||
error::Error,
|
||||
task::runtime::{self, with_timeout},
|
||||
};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::{OneTimeInit, event::BitmapEvent, sync::IrqSafeSpinlock};
|
||||
use tock_registers::{
|
||||
LocalRegisterCopy,
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
};
|
||||
use ygg_driver_net_core::{
|
||||
RxPacket,
|
||||
ephy::PhyAccess,
|
||||
interface::{NetworkDevice, NetworkInterfaceType},
|
||||
util::GenericQueue,
|
||||
};
|
||||
use yggdrasil_abi::net::{MacAddress, link::LinkState};
|
||||
|
||||
use crate::ethernet::{
|
||||
queue::Descriptor,
|
||||
regs::{ControlRegs, Regs},
|
||||
};
|
||||
|
||||
const RX_BUF_SIZE_MUL: usize = 64;
|
||||
|
||||
mod queue;
|
||||
mod regs;
|
||||
|
||||
// TODO multiqueue
|
||||
struct Ethernet {
|
||||
// Device tree info
|
||||
name: &'static str,
|
||||
irq: IrqHandle,
|
||||
clk_pclk: ClockHandle,
|
||||
clk_hclk: ClockHandle,
|
||||
local_mac_address: Option<MacAddress>,
|
||||
|
||||
// Memory/HW
|
||||
// caps: Capabilities,
|
||||
dma: OneTimeInit<Arc<dyn DmaAllocator>>,
|
||||
control_regs: IrqSafeSpinlock<DeviceMemoryIo<'static, ControlRegs>>,
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
|
||||
// Operation
|
||||
queue: OneTimeInit<GenericQueue<Descriptor, Descriptor>>,
|
||||
softirq: BitmapEvent<AtomicWaker>,
|
||||
iface_id: OneTimeInit<u32>,
|
||||
}
|
||||
|
||||
// bitflags! {
|
||||
// pub struct CapFlags: u32 {
|
||||
// const MACB_IS_GEM: bit 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
// struct Capabilities {
|
||||
// flags: CapFlags,
|
||||
// queue_mask: u32,
|
||||
// queue_count: usize,
|
||||
// }
|
||||
|
||||
impl Ethernet {
|
||||
fn probe(node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let name = node.name().unwrap_or("gemgxl");
|
||||
let irq = node.interrupt(0)?;
|
||||
let clk_pclk = node.named_clock("pclk")?;
|
||||
let clk_hclk = node.named_clock("hclk")?;
|
||||
let base = node.map_base(context, 0)?;
|
||||
let base_control = node.map_base(context, 1)?;
|
||||
let local_mac_address = read_mac_address(node);
|
||||
|
||||
let regs = unsafe { DeviceMemoryIo::<Regs>::map(base, Default::default()) }.ok()?;
|
||||
let control_regs = unsafe { DeviceMemoryIo::map(base_control, Default::default()) }.ok()?;
|
||||
|
||||
// let caps = regs.probe_capabilities();
|
||||
|
||||
let gem = Arc::new(Ethernet {
|
||||
name,
|
||||
clk_pclk,
|
||||
clk_hclk,
|
||||
irq,
|
||||
local_mac_address,
|
||||
|
||||
// caps,
|
||||
dma: OneTimeInit::new(),
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
control_regs: IrqSafeSpinlock::new(control_regs),
|
||||
|
||||
queue: OneTimeInit::new(),
|
||||
softirq: BitmapEvent::new(AtomicWaker::new()),
|
||||
iface_id: OneTimeInit::new(),
|
||||
});
|
||||
|
||||
context.sequence = Some(InitSequence::Late);
|
||||
|
||||
Some(gem)
|
||||
}
|
||||
|
||||
async fn softirq(self: Arc<Self>) {
|
||||
let iface = *self.iface_id.get();
|
||||
let queue = self.queue.get();
|
||||
|
||||
loop {
|
||||
let event_fut = self.softirq.wait();
|
||||
let bits = match with_timeout(event_fut, Duration::from_millis(100)).await {
|
||||
Ok(bits) => bits as u32,
|
||||
Err(_) => {
|
||||
queue.consume_tx().ok();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let status = LocalRegisterCopy::<_, regs::Interrupt::Register>::new(bits);
|
||||
|
||||
if status.matches_all(regs::Interrupt::RCOMP::SET) {
|
||||
queue
|
||||
.consume_rx(&**self.dma.get(), None, |packet, _len| {
|
||||
let packet = RxPacket::new(packet, 0, iface);
|
||||
ygg_driver_net_core::receive_packet(packet).ok();
|
||||
})
|
||||
.ok();
|
||||
|
||||
let regs = self.regs.lock();
|
||||
regs.interrupt_enable.write(regs::Interrupt::RCOMP::SET);
|
||||
}
|
||||
if status.matches_all(regs::Interrupt::TCOMP::SET) {
|
||||
queue.consume_tx().ok();
|
||||
|
||||
let regs = self.regs.lock();
|
||||
regs.interrupt_enable.write(regs::Interrupt::RCOMP::SET);
|
||||
}
|
||||
if status.matches_all(regs::Interrupt::LINK::SET) {
|
||||
log::info!("Link status changed");
|
||||
let regs = self.regs.lock();
|
||||
regs.interrupt_enable.write(regs::Interrupt::LINK::SET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn start_xmit(&self, frame: DmaBuffer<[u8]>) -> Result<(), Error> {
|
||||
let queue = self.queue.get();
|
||||
|
||||
queue.try_push_xmit(frame)?;
|
||||
|
||||
let regs = self.regs.lock();
|
||||
regs.network_control
|
||||
.modify(regs::NetworkControl::TSTART::SET);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for Ethernet {
|
||||
unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
|
||||
let _ = (&self.clk_pclk, &self.clk_hclk, &self.control_regs);
|
||||
log::info!("{}: hw address {:?}", self.name, self.local_mac_address);
|
||||
// TODO enable clocks
|
||||
let dma = self.dma.init(cx.dma_allocator);
|
||||
let regs = self.regs.lock();
|
||||
|
||||
let queue = self.queue.init(GenericQueue::with_capacity(
|
||||
&**dma,
|
||||
256,
|
||||
256,
|
||||
queue::RX_BUFFER_SIZE,
|
||||
)?);
|
||||
|
||||
let rx_queue_base = queue.rx_buffer_base().try_into_u32().unwrap();
|
||||
let tx_queue_base = queue.tx_buffer_base().try_into_u32().unwrap();
|
||||
|
||||
regs.interrupt_disable.set(0xFFFFFFFF);
|
||||
|
||||
regs.rx_buffer_queue_base.set(rx_queue_base);
|
||||
regs.tx_buffer_queue_base.set(tx_queue_base);
|
||||
regs.dma_config.write(
|
||||
regs::DmaConfig::RX_BUF_SIZE.val((queue::RX_BUFFER_SIZE / RX_BUF_SIZE_MUL) as _),
|
||||
);
|
||||
|
||||
regs.network_control.modify(regs::NetworkControl::MPE::SET);
|
||||
|
||||
{
|
||||
let phy = PhyAccess::new(&**regs, 0);
|
||||
let phy_id = phy.id()?;
|
||||
log::info!("{}: PHY {:04x}:{:04x}", self.name, phy_id.0, phy_id.1);
|
||||
phy.setup_link(false, None)?;
|
||||
}
|
||||
|
||||
regs.network_config.write(regs::NetworkConfig::PROMISC::SET);
|
||||
regs.network_control
|
||||
.modify(regs::NetworkControl::TE::SET + regs::NetworkControl::RE::SET);
|
||||
|
||||
// if (GEM_BFEXT(DAW64, gem_readl(...)))
|
||||
// hw_dma_cap |= HW_DMA_CAP_64B
|
||||
|
||||
regs.interrupt_enable.write(
|
||||
regs::Interrupt::LINK::SET + regs::Interrupt::RCOMP::SET + regs::Interrupt::TCOMP::SET,
|
||||
);
|
||||
|
||||
let iface =
|
||||
ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self.clone());
|
||||
self.iface_id.init(iface.id());
|
||||
|
||||
runtime::spawn(self.clone().softirq())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
self.irq.register(self.clone())?;
|
||||
self.irq.enable()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkDevice for Ethernet {
|
||||
fn allocate_transmit_buffer(&self, len: usize) -> Result<DmaBuffer<[MaybeUninit<u8>]>, Error> {
|
||||
DmaBuffer::new_uninit_slice(&**self.dma.get(), len)
|
||||
}
|
||||
|
||||
fn transmit_buffer(&self, buffer: DmaBuffer<[u8]>) -> Result<(), Error> {
|
||||
self.start_xmit(buffer)
|
||||
}
|
||||
|
||||
fn packet_prefix_size(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn read_hardware_address(&self) -> MacAddress {
|
||||
// TODO from registers
|
||||
self.local_mac_address.unwrap()
|
||||
}
|
||||
|
||||
fn link_state(&self) -> LinkState {
|
||||
self.regs.lock().link_state()
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for Ethernet {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
const MASK: u32 = regs::Interrupt::RCOMP::SET.value
|
||||
| regs::Interrupt::TCOMP::SET.value
|
||||
| regs::Interrupt::LINK::SET.value;
|
||||
|
||||
let regs = self.regs.lock();
|
||||
let status = regs.interrupt_status.get();
|
||||
// Mask the IRQ and send it to softirq handler
|
||||
regs.interrupt_disable.set(MASK & status);
|
||||
self.softirq.signal(status as u64);
|
||||
|
||||
status != 0
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["sifive,fu540-c000-gem"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
Ethernet::probe(node, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
use libk::{dma::BusAddress, error::Error};
|
||||
use ygg_driver_net_core::util::{GenericRxDescriptor, GenericTxDescriptor};
|
||||
|
||||
pub const RX_BUFFER_SIZE: usize = 4096;
|
||||
|
||||
static_assertions::const_assert_eq!(RX_BUFFER_SIZE % super::RX_BUF_SIZE_MUL, 0);
|
||||
static_assertions::const_assert_ne!(RX_BUFFER_SIZE / super::RX_BUF_SIZE_MUL, 0);
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct Descriptor {
|
||||
address: u32,
|
||||
control: u32,
|
||||
}
|
||||
|
||||
impl GenericTxDescriptor for Descriptor {
|
||||
// USED = 0: owned by hardware
|
||||
// USED = 1: owned by software
|
||||
const EMPTY: Self = Self {
|
||||
address: 0,
|
||||
control: Self::DESC_1_USED,
|
||||
};
|
||||
const EMPTY_LAST: Self = Self {
|
||||
address: 0,
|
||||
control: Self::DESC_1_USED | Self::DESC_1_TX_WRAP,
|
||||
};
|
||||
|
||||
fn consume(&mut self) -> Option<Result<(), Error>> {
|
||||
if self.control & Self::DESC_1_USED != 0 && self.address != 0 {
|
||||
Some(Ok(()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_tx(
|
||||
&mut self,
|
||||
buffer_address: BusAddress,
|
||||
size: usize,
|
||||
index: usize,
|
||||
capacity: usize,
|
||||
) -> Result<(), Error> {
|
||||
let buffer_address = buffer_address.try_into_u32()?;
|
||||
if !(8..8192).contains(&size) {
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
let mut control = size as u32 | Self::DESC_1_TX_LAST;
|
||||
if index == capacity - 1 {
|
||||
control |= Self::DESC_1_TX_WRAP;
|
||||
}
|
||||
self.address = buffer_address;
|
||||
self.control = control;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl GenericRxDescriptor for Descriptor {
|
||||
fn consume(&mut self) -> Option<Result<usize, Error>> {
|
||||
if self.address & Self::DESC_0_RX_OWNERSHIP != 0 {
|
||||
Some(Ok((self.control & Self::LENGTH) as usize))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_rx(buffer_address: BusAddress, _size: usize, last: bool) -> Result<Self, Error> {
|
||||
let mut address = buffer_address.try_into_u32()?;
|
||||
if last {
|
||||
address |= Self::DESC_0_RX_WRAP;
|
||||
}
|
||||
Ok(Self {
|
||||
control: 0,
|
||||
address,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Descriptor {
|
||||
const DESC_1_USED: u32 = 1 << 31;
|
||||
const LENGTH: u32 = 0x1FFF;
|
||||
|
||||
const DESC_1_TX_WRAP: u32 = 1 << 30;
|
||||
const DESC_1_TX_LAST: u32 = 1 << 15;
|
||||
|
||||
const DESC_0_RX_OWNERSHIP: u32 = 1 << 0;
|
||||
const DESC_0_RX_WRAP: u32 = 1 << 1;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user