Compare commits

64 Commits

Author SHA1 Message Date
alnyan d5f70c6a7c red: move more logic into lysp 2026-06-04 17:35:55 +03:00
alnyan 1736582613 lysp: more string prelude, fallible set_global_value 2026-06-04 17:35:30 +03:00
alnyan 1f670a66a4 red: rework command and key handling 2026-06-04 13:15:54 +03:00
alnyan 60f3572fec lysp: fix (explain ...) for macros 2026-06-04 13:15:25 +03:00
alnyan f5d3809f37 lysp: rework and/or, add prelude functions 2026-06-04 12:47:21 +03:00
alnyan 1261c037f8 lysp: rework upvalue handling 2026-06-03 11:24:32 +03:00
alnyan fd8e1df696 lysp: add hashtable support 2026-06-02 17:21:47 +03:00
alnyan befdf63c7c lysp: add dotted pair notation 2026-06-02 09:42:45 +03:00
alnyan 679ac51602 red: add .gitignore 2026-05-30 17:27:17 +03:00
alnyan 7909fa3808 red: add eval/set/unset commands 2026-05-28 17:50:07 +03:00
alnyan 4b98ec1ce2 red: add syntax highlighting and lysp support 2026-05-28 15:51:32 +03:00
alnyan 37ad3702d0 userspace: add lysp interpreter/compiler 2026-05-28 14:37:49 +03:00
alnyan 505a57abda pl011: fix incorrect byte written in write() 2026-05-28 14:37:25 +03:00
alnyan 677ec96c08 sysutils/top: better ui 2026-03-31 17:23:41 +03:00
alnyan 7064a21d8d libterm: fix incorrect bg index decode 2026-03-31 17:12:03 +03:00
alnyan 6d31142258 sysutils: add cpu/memory information to top 2026-03-30 12:23:25 +03:00
alnyan d7df44b1d9 lib/term: move from tui to ratatui 2026-03-28 20:45:38 +02:00
alnyan 1552bb27f4 toolchain: migrate to 1.94.0 toolchain 2026-03-28 01:59:17 +02:00
alnyan 7f256cf3a6 i2c: improve i2c architecture, add sifive i2c driver 2026-03-25 19:07:59 +02:00
alnyan f416414b93 char: add pwm subsystem, add sifive pwm driver 2026-03-23 14:02:02 +02:00
alnyan 0386e3916d maint: fix irq priority addition for aarch64/x86_64 2026-03-20 16:01:26 +02:00
alnyan 31176fb5aa riscv: initial support for hifive unmatched 2026-03-20 15:24:55 +02:00
alnyan 1411f1eed0 maint: update rustc to 1.95.0-nightly 2026-03-19 10:51:42 +02:00
alnyan 4c5309fa15 rsh: add rcp, remote copy program 2026-02-08 14:57:12 +02:00
alnyan 1012abceec cross: add unix i2c/spi stubs 2026-02-07 16:11:15 +02:00
alnyan a6a6dba155 net/stmmac: use GenericQueue 2026-02-07 15:47:40 +02:00
alnyan 7f46da9ebd net: unify netdev tx/rx queue interface 2026-02-07 14:13:09 +02:00
alnyan 1a87bc3666 sifive: support for cadence gemgxl ethernet 2026-02-05 17:10:14 +02:00
alnyan 4f648142c8 sifive: initial support for hifive unleashed a00 2026-02-04 17:34:37 +02:00
alnyan 0e979a9e09 spi: initial spi device support 2026-02-04 14:46:57 +02:00
alnyan ed9d7a7145 usb: add ft232 driver 2026-02-03 17:28:15 +02:00
alnyan 6b5dd9f673 irq: more flexible interrupt tables 2026-02-03 13:29:49 +02:00
alnyan 58dbaddf11 i2c: implement initial support for i2c devices 2026-02-03 12:08:15 +02:00
alnyan 218e391505 aarch64: better page fault info 2026-02-03 12:07:52 +02:00
alnyan 2a49c655c2 8250: fix reg-io-width/reg-shift for raspi4b 2026-01-19 11:36:01 +02:00
alnyan d108494314 8250: merge bcm aux uart into 8250 driver 2026-01-19 11:06:05 +02:00
alnyan 195c19e225 serial: unify 8250 drivers, better dts support 2026-01-16 23:18:46 +02:00
alnyan 21a8361eec usb: more keys for hid keyboard 2026-01-14 09:11:00 +02:00
alnyan fd0a3f50ea maint: update README.md 2026-01-14 09:06:03 +02:00
alnyan c72c8f88d7 usb: add support for usb hubs 2026-01-14 08:58:46 +02:00
alnyan e44b616998 sysutils: add a showkey program 2026-01-08 14:45:14 +02:00
alnyan 7abb950a8f block: fix rustc migration error 2026-01-06 18:17:11 +02:00
alnyan 57143f9d8d maint: migrate to rustc 1.94.0-nightly 2026-01-06 14:41:08 +02:00
alnyan 3491e1a227 graphics/iv: add image viewer program 2025-12-29 17:17:42 +02:00
alnyan 61644bdef5 netutils/ping: add sigint handler 2025-12-04 08:30:08 +02:00
alnyan e1b905c65a shell: improve interactive mode 2025-11-19 08:57:47 +02:00
alnyan 9855142c25 cross: *nix support for serial module 2025-10-17 15:25:11 +03:00
alnyan bb4e805733 tar: better error reporting 2025-10-17 09:38:28 +03:00
alnyan ecf1c18240 shell: add basic tab completion (single-option) 2025-10-17 09:24:54 +03:00
alnyan a87c8a7ee2 WIP: Add tar utility 2025-10-16 10:42:41 +03:00
alnyan 312458b8f0 sysutils: add serial console program 2025-10-10 09:21:20 +03:00
alnyan 33474c10d3 bcm2711: update dtb 2025-09-26 16:51:43 +03:00
alnyan e934b4d696 aarch64: simplify GIC init 2025-09-17 14:18:06 +03:00
alnyan 6d8d97d492 maint: remove raqote dependency 2025-09-17 11:23:29 +03:00
alnyan ca01f57873 ports: add GNU GMP 6.3.0 2025-08-28 16:34:14 +03:00
alnyan 9be467d5d5 ports: add doomgeneric 2025-08-25 10:39:59 +03:00
alnyan 0c2ebbf7b3 fat32: move cluster chain cache to FileNode 2025-08-16 09:05:39 +03:00
alnyan cb4c0bc4b0 sysutils: add tree utility 2025-08-15 08:38:38 +03:00
alnyan c1b62aef1d memfs: take mtimes from tar 2025-08-14 15:55:38 +03:00
alnyan 6469914be1 rtc: implement google,goldfish-rtc 2025-08-14 15:17:41 +03:00
alnyan 131e6adc3d riscv: fix irqhandle migration 2025-08-14 15:11:26 +03:00
alnyan 322cb0a958 rtc: improve rtc device drivers 2025-08-14 15:08:19 +03:00
alnyan 6552fa8059 irq: FullIrq -> IrqHandle 2025-08-14 11:34:00 +03:00
alnyan 0ff48fd520 sysutils: implement poweroff 2025-08-14 10:31:09 +03:00
789 changed files with 108122 additions and 9954 deletions
Generated
+69 -27
View File
@@ -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"
@@ -2968,7 +3010,6 @@ dependencies = [
"abi-lib",
"abi-serde",
"bytemuck",
"compiler_builtins",
"prettyplease",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
@@ -3019,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",
@@ -3028,6 +3070,7 @@ dependencies = [
"ygg_driver_net_stmmac",
"ygg_driver_nvme",
"ygg_driver_pci",
"ygg_driver_serial_8250",
"ygg_driver_usb",
"ygg_driver_usb_xhci",
"ygg_driver_virtio_blk",
@@ -3044,7 +3087,6 @@ dependencies = [
"abi-lib",
"abi-serde",
"cc",
"compiler_builtins",
"libm",
"prettyplease",
"rustc-std-workspace-alloc",
+2
View File
@@ -7,6 +7,7 @@ exclude = [
"toolchain",
"userspace/dynload-program",
"userspace/lib/ygglibc",
"userspace",
"toolchain-c"
]
members = [
@@ -88,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" }
+18 -14
View File
@@ -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...
+35
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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>;
+669
View File
@@ -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>;
};
};
+14
View File
@@ -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
Binary file not shown.
+319
View File
@@ -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";
};
};
+308
View File
@@ -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.
@@ -68,7 +68,7 @@
chosen {
stdout-path = "serial0:115200n8";
bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory numa_policy=interleave";
bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory numa_policy=interleave nvme.max_host_mem_size_mb=0";
phandle = <0x54>;
};
@@ -172,7 +172,7 @@
reg = <0x7e00b880 0x40>;
interrupts = <0x00 0x21 0x04>;
#mbox-cells = <0x00>;
phandle = <0x35>;
phandle = <0x31>;
};
gpio@7e200000 {
@@ -252,7 +252,7 @@
i2c0if-gpio0 {
brcm,pins = <0x00 0x01>;
brcm,function = <0x04>;
phandle = <0x33>;
phandle = <0x35>;
};
i2c0if-gpio28 {
@@ -264,7 +264,7 @@
i2c0if-gpio44 {
brcm,pins = <0x2c 0x2d>;
brcm,function = <0x05>;
phandle = <0x34>;
phandle = <0x36>;
};
i2c1-gpio2 {
@@ -958,64 +958,64 @@
};
};
dpi_18bit_cpadhi_gpio0 {
brcm,pins = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x14 0x15 0x16 0x17 0x18 0x19>;
brcm,function = <0x06>;
brcm,pull = <0x00>;
phandle = <0xb2>;
};
dpi_18bit_cpadhi_gpio2 {
brcm,pins = <0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x14 0x15 0x16 0x17 0x18 0x19>;
brcm,function = <0x06>;
phandle = <0xb3>;
};
dpi_18bit_gpio0 {
brcm,pins = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15>;
brcm,function = <0x06>;
phandle = <0xb4>;
};
dpi_18bit_gpio2 {
brcm,pins = <0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15>;
brcm,function = <0x06>;
phandle = <0xb5>;
};
dpi_16bit_gpio0 {
brcm,pins = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13>;
brcm,function = <0x06>;
phandle = <0xb6>;
};
dpi_16bit_gpio2 {
brcm,pins = <0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13>;
brcm,function = <0x06>;
phandle = <0xb7>;
};
dpi_16bit_cpadhi_gpio0 {
brcm,pins = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x14 0x15 0x16 0x17 0x18>;
brcm,function = <0x06>;
phandle = <0xb8>;
};
dpi_16bit_cpadhi_gpio2 {
brcm,pins = <0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x14 0x15 0x16 0x17 0x18>;
brcm,function = <0x06>;
phandle = <0xb9>;
};
gpioout {
brcm,pins = <0x06>;
brcm,function = <0x01>;
phandle = <0xba>;
phandle = <0xb2>;
};
alt0 {
brcm,pins = <0x04 0x05 0x07 0x08 0x09 0x0a 0x0b>;
brcm,function = <0x04>;
phandle = <0xb3>;
};
dpi_18bit_cpadhi_gpio0 {
brcm,pins = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x14 0x15 0x16 0x17 0x18 0x19>;
brcm,function = <0x06>;
brcm,pull = <0x00>;
phandle = <0xb4>;
};
dpi_18bit_cpadhi_gpio2 {
brcm,pins = <0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x14 0x15 0x16 0x17 0x18 0x19>;
brcm,function = <0x06>;
phandle = <0xb5>;
};
dpi_18bit_gpio0 {
brcm,pins = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15>;
brcm,function = <0x06>;
phandle = <0xb6>;
};
dpi_18bit_gpio2 {
brcm,pins = <0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15>;
brcm,function = <0x06>;
phandle = <0xb7>;
};
dpi_16bit_gpio0 {
brcm,pins = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13>;
brcm,function = <0x06>;
phandle = <0xb8>;
};
dpi_16bit_gpio2 {
brcm,pins = <0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13>;
brcm,function = <0x06>;
phandle = <0xb9>;
};
dpi_16bit_cpadhi_gpio0 {
brcm,pins = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x14 0x15 0x16 0x17 0x18>;
brcm,function = <0x06>;
phandle = <0xba>;
};
dpi_16bit_cpadhi_gpio2 {
brcm,pins = <0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x14 0x15 0x16 0x17 0x18>;
brcm,function = <0x06>;
phandle = <0xbb>;
};
@@ -1131,7 +1131,7 @@
brcm,pins = <0x22 0x23 0x24 0x25 0x26 0x27>;
brcm,function = <0x07>;
brcm,pull = <0x00 0x02 0x02 0x02 0x02 0x02>;
phandle = <0x31>;
phandle = <0x33>;
};
uart2_pins {
@@ -1194,17 +1194,17 @@
brcm,pins = <0x28 0x29>;
brcm,function = <0x04>;
brcm,pull = <0x00>;
phandle = <0x36>;
phandle = <0x32>;
};
};
serial@7e201000 {
compatible = "arm,pl011", "arm,primecell";
compatible = "arm,pl011-axi";
reg = <0x7e201000 0x200>;
interrupts = <0x00 0x79 0x04>;
clocks = <0x08 0x13 0x08 0x14>;
clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x241011>;
arm,primecell-periphid = <0x341011>;
status = "okay";
cts-event-workaround;
pinctrl-names = "default";
@@ -1295,7 +1295,7 @@
#size-cells = <0x00>;
status = "disabled";
clock-frequency = <0x186a0>;
phandle = <0x32>;
phandle = <0x34>;
};
dpi@7e208000 {
@@ -1404,8 +1404,8 @@
compatible = "brcm,bcm2711-hvs";
reg = <0x7e400000 0x8000>;
interrupts = <0x00 0x61 0x04>;
status = "disabled";
clocks = <0x14 0x04>;
status = "disabled";
phandle = <0xc4>;
};
@@ -1424,6 +1424,38 @@
phandle = <0x05>;
};
csi@7e800000 {
compatible = "brcm,bcm2835-unicam";
reg = <0x7e800000 0x800 0x7e802000 0x04>;
reg-names = "unicam", "cmi";
interrupts = <0x00 0x66 0x04>;
brcm,num-data-lanes = <0x02>;
status = "disabled";
clocks = <0x08 0x2d 0x14 0x04>;
clock-names = "lp", "vpu";
power-domains = <0x10 0x0c>;
phandle = <0x51>;
port {
};
};
csi@7e801000 {
compatible = "brcm,bcm2835-unicam";
reg = <0x7e801000 0x800 0x7e802004 0x04>;
reg-names = "unicam", "cmi";
interrupts = <0x00 0x67 0x04>;
brcm,num-data-lanes = <0x02>;
status = "disabled";
clocks = <0x08 0x2e 0x14 0x04>;
clock-names = "lp", "vpu";
power-domains = <0x10 0x0d>;
phandle = <0x50>;
port {
};
};
i2c@7e804000 {
compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c";
reg = <0x7e804000 0x1000>;
@@ -1446,10 +1478,11 @@
#size-cells = <0x00>;
clocks = <0x16>;
clock-names = "otg";
dr_mode = "host";
phys = <0x17>;
phy-names = "usb2-phy";
interrupt-names = "usb", "soft";
power-domains = <0x10 0x06>;
interrupt-names = "usb", "soft";
status = "disabled";
phandle = <0xc5>;
};
@@ -1511,12 +1544,12 @@
};
serial@7e201400 {
compatible = "arm,pl011", "arm,primecell";
compatible = "arm,pl011-axi";
reg = <0x7e201400 0x200>;
interrupts = <0x00 0x79 0x04>;
clocks = <0x08 0x13 0x08 0x14>;
clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x241011>;
arm,primecell-periphid = <0x341011>;
status = "disabled";
pinctrl-0 = <0x18>;
pinctrl-names = "default";
@@ -1524,12 +1557,12 @@
};
serial@7e201600 {
compatible = "arm,pl011", "arm,primecell";
compatible = "arm,pl011-axi";
reg = <0x7e201600 0x200>;
interrupts = <0x00 0x79 0x04>;
clocks = <0x08 0x13 0x08 0x14>;
clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x241011>;
arm,primecell-periphid = <0x341011>;
status = "disabled";
pinctrl-0 = <0x19>;
pinctrl-names = "default";
@@ -1537,12 +1570,12 @@
};
serial@7e201800 {
compatible = "arm,pl011", "arm,primecell";
compatible = "arm,pl011-axi";
reg = <0x7e201800 0x200>;
interrupts = <0x00 0x79 0x04>;
clocks = <0x08 0x13 0x08 0x14>;
clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x241011>;
arm,primecell-periphid = <0x341011>;
status = "disabled";
pinctrl-0 = <0x1a>;
pinctrl-names = "default";
@@ -1550,12 +1583,12 @@
};
serial@7e201a00 {
compatible = "arm,pl011", "arm,primecell";
compatible = "arm,pl011-axi";
reg = <0x7e201a00 0x200>;
interrupts = <0x00 0x79 0x04>;
clocks = <0x08 0x13 0x08 0x14>;
clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x241011>;
arm,primecell-periphid = <0x341011>;
status = "disabled";
pinctrl-0 = <0x1b>;
pinctrl-names = "default";
@@ -1803,113 +1836,9 @@
phandle = <0x30>;
};
mmcnr@7e300000 {
compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci";
reg = <0x7e300000 0x100>;
interrupts = <0x00 0x7e 0x04>;
clocks = <0x08 0x1c>;
dmas = <0x0c 0x0b>;
dma-names = "rx-tx";
brcm,overclock-50 = <0x00>;
non-removable;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <0x31>;
bus-width = <0x04>;
phandle = <0x4d>;
};
firmwarekms@7e600000 {
compatible = "raspberrypi,rpi-firmware-kms-2711";
reg = <0x7e600000 0x100>;
interrupts = <0x00 0x70 0x04>;
brcm,firmware = <0x06>;
status = "disabled";
phandle = <0xdb>;
};
smi@7e600000 {
compatible = "brcm,bcm2835-smi";
reg = <0x7e600000 0x100>;
interrupts = <0x00 0x70 0x04>;
clocks = <0x08 0x2a>;
assigned-clocks = <0x08 0x2a>;
assigned-clock-rates = <0x7735940>;
dmas = <0x0c 0x04>;
dma-names = "rx-tx";
status = "disabled";
phandle = <0xdc>;
};
csi@7e800000 {
compatible = "brcm,bcm2835-unicam";
reg = <0x7e800000 0x800 0x7e802000 0x04>;
interrupts = <0x00 0x66 0x04>;
clocks = <0x08 0x2d 0x14 0x04>;
clock-names = "lp", "vpu";
power-domains = <0x10 0x0c>;
#address-cells = <0x01>;
#size-cells = <0x00>;
#clock-cells = <0x01>;
status = "disabled";
phandle = <0x51>;
};
csi@7e801000 {
compatible = "brcm,bcm2835-unicam";
reg = <0x7e801000 0x800 0x7e802004 0x04>;
interrupts = <0x00 0x67 0x04>;
clocks = <0x08 0x2e 0x14 0x04>;
clock-names = "lp", "vpu";
power-domains = <0x10 0x0d>;
#address-cells = <0x01>;
#size-cells = <0x00>;
#clock-cells = <0x01>;
status = "disabled";
brcm,num-data-lanes = <0x02>;
phandle = <0x50>;
};
axiperf {
compatible = "brcm,bcm2711-axiperf";
reg = <0x7e009800 0x100 0x7ee08000 0x100>;
firmware = <0x06>;
status = "disabled";
phandle = <0x4e>;
};
i2c0mux {
compatible = "i2c-mux-pinctrl";
#address-cells = <0x01>;
#size-cells = <0x00>;
i2c-parent = <0x32>;
status = "disabled";
pinctrl-names = "i2c0", "i2c_csi_dsi";
pinctrl-0 = <0x33>;
pinctrl-1 = <0x34>;
phandle = <0x47>;
i2c@0 {
reg = <0x00>;
#address-cells = <0x01>;
#size-cells = <0x00>;
phandle = <0xdd>;
};
i2c@1 {
reg = <0x01>;
#address-cells = <0x01>;
#size-cells = <0x00>;
phandle = <0xde>;
};
};
firmware {
compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
#address-cells = <0x01>;
#size-cells = <0x01>;
mboxes = <0x35>;
dma-ranges;
mboxes = <0x31>;
phandle = <0x06>;
clocks {
@@ -1935,7 +1864,7 @@
vcio {
compatible = "raspberrypi,vcio";
phandle = <0xdf>;
phandle = <0xdb>;
};
};
@@ -1951,8 +1880,88 @@
reg = <0x7e00b840 0x3c>;
interrupts = <0x00 0x22 0x04>;
pinctrl-names = "default";
pinctrl-0 = <0x36>;
phandle = <0xe0>;
pinctrl-0 = <0x32>;
phandle = <0xdc>;
};
mmcnr@7e300000 {
compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci";
reg = <0x7e300000 0x100>;
interrupts = <0x00 0x7e 0x04>;
clocks = <0x08 0x1c>;
dmas = <0x0c 0x0b>;
dma-names = "rx-tx";
brcm,overclock-50 = <0x00>;
non-removable;
status = "okay";
#address-cells = <0x01>;
#size-cells = <0x00>;
pinctrl-names = "default";
pinctrl-0 = <0x33>;
bus-width = <0x04>;
phandle = <0x4d>;
wifi@1 {
reg = <0x01>;
compatible = "brcm,bcm4329-fmac";
phandle = <0xdd>;
};
};
firmwarekms@7e600000 {
compatible = "raspberrypi,rpi-firmware-kms-2711";
reg = <0x7e600000 0x100>;
interrupts = <0x00 0x70 0x04>;
brcm,firmware = <0x06>;
status = "disabled";
phandle = <0xde>;
};
smi@7e600000 {
compatible = "brcm,bcm2835-smi";
reg = <0x7e600000 0x100>;
interrupts = <0x00 0x70 0x04>;
clocks = <0x08 0x2a>;
assigned-clocks = <0x08 0x2a>;
assigned-clock-rates = <0x7735940>;
dmas = <0x0c 0x04>;
dma-names = "rx-tx";
status = "disabled";
phandle = <0xdf>;
};
axiperf {
compatible = "brcm,bcm2711-axiperf";
reg = <0x7e009800 0x100 0x7ee08000 0x100>;
firmware = <0x06>;
status = "disabled";
phandle = <0x4e>;
};
i2c0mux {
compatible = "i2c-mux-pinctrl";
#address-cells = <0x01>;
#size-cells = <0x00>;
i2c-parent = <0x34>;
status = "disabled";
pinctrl-names = "i2c0", "i2c_csi_dsi";
pinctrl-0 = <0x35>;
pinctrl-1 = <0x36>;
phandle = <0x47>;
i2c@0 {
reg = <0x00>;
#address-cells = <0x01>;
#size-cells = <0x00>;
phandle = <0xe0>;
};
i2c@1 {
reg = <0x01>;
#address-cells = <0x01>;
#size-cells = <0x00>;
phandle = <0xe1>;
};
};
gpiomem {
@@ -1964,12 +1973,12 @@
compatible = "brcm,bcm2708-fb";
firmware = <0x06>;
status = "okay";
phandle = <0xe1>;
phandle = <0xe2>;
};
sound {
status = "disabled";
phandle = <0xe2>;
phandle = <0xe3>;
};
nvmem {
@@ -1982,7 +1991,7 @@
firmware = <0x06>;
reg = <0x00 0xa6>;
status = "okay";
phandle = <0xe3>;
phandle = <0xe4>;
};
nvmem_cust {
@@ -2035,7 +2044,7 @@
compatible = "brcm,bcm2711-vc5";
status = "disabled";
raspberrypi,firmware = <0x06>;
phandle = <0xe4>;
phandle = <0xe5>;
};
clk-27M {
@@ -2060,7 +2069,7 @@
#size-cells = <0x01>;
ranges = <0x00 0x7e000000 0x00 0xfe000000 0x1800000>;
dma-ranges = <0x00 0xc0000000 0x00 0x00 0x40000000>;
phandle = <0xe5>;
phandle = <0xe6>;
mmc@7e340000 {
compatible = "brcm,bcm2711-emmc2";
@@ -2076,8 +2085,8 @@
};
};
arm-pmu {
compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3", "arm,cortex-a7-pmu";
pmu {
compatible = "arm,cortex-a72-pmu";
interrupts = <0x00 0x10 0x04 0x00 0x11 0x04 0x00 0x12 0x04 0x00 0x13 0x04>;
interrupt-affinity = <0x39 0x3a 0x3b 0x3c>;
};
@@ -2085,14 +2094,13 @@
timer {
compatible = "arm,armv8-timer";
interrupts = <0x01 0x0d 0xf08 0x01 0x0e 0xf08 0x01 0x0b 0xf08 0x01 0x0a 0xf08>;
arm,cpu-registers-not-fw-configured;
};
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
enable-method = "brcm,bcm2836-smp";
phandle = <0xe6>;
phandle = <0xe7>;
cpu@0 {
device_type = "cpu";
@@ -2173,9 +2181,9 @@
compatible = "simple-bus";
#address-cells = <0x02>;
#size-cells = <0x02>;
ranges = <0x00 0x7c000000 0x00 0xfc000000 0x00 0x3800000 0x00 0x40000000 0x00 0xff800000 0x00 0x800000 0x06 0x00 0x06 0x00 0x00 0x80000000 0x00 0x00 0x00 0x00 0x00 0xfc000000>;
ranges = <0x00 0x7c000000 0x00 0xfc000000 0x00 0x3800000 0x00 0x40000000 0x00 0xff800000 0x00 0x800000 0x06 0x00 0x06 0x00 0x00 0x40000000 0x00 0x00 0x00 0x00 0x00 0xfc000000>;
dma-ranges = <0x04 0x7c000000 0x00 0xfc000000 0x00 0x3800000 0x00 0x00 0x00 0x00 0x04 0x00>;
phandle = <0xe7>;
phandle = <0xe8>;
pcie@7d500000 {
compatible = "brcm,bcm2711-pcie";
@@ -2190,7 +2198,7 @@
interrupt-map = <0x00 0x00 0x00 0x01 0x01 0x00 0x8f 0x04 0x00 0x00 0x00 0x02 0x01 0x00 0x90 0x04 0x00 0x00 0x00 0x03 0x01 0x00 0x91 0x04 0x00 0x00 0x00 0x04 0x01 0x00 0x92 0x04>;
msi-controller;
msi-parent = <0x3e>;
ranges = <0x2000000 0x00 0x80000000 0x06 0x00 0x00 0x80000000>;
ranges = <0x2000000 0x00 0xc0000000 0x06 0x00 0x00 0x40000000>;
dma-ranges = <0x2000000 0x00 0x00 0x00 0x00 0x00 0xc0000000>;
brcm,enable-ssc;
phandle = <0x3e>;
@@ -2218,7 +2226,7 @@
status = "okay";
phy-handle = <0x40>;
phy-mode = "rgmii-rxid";
phandle = <0xe8>;
phandle = <0xe9>;
mdio@e14 {
compatible = "brcm,genet-mdio-v5";
@@ -2226,7 +2234,7 @@
reg-names = "mdio";
#address-cells = <0x01>;
#size-cells = <0x00>;
phandle = <0xe9>;
phandle = <0xea>;
ethernet-phy@1 {
reg = <0x01>;
@@ -2236,6 +2244,15 @@
};
};
codec@7eb10000 {
compatible = "brcm,bcm2711-hevc-dec", "raspberrypi,hevc-dec";
reg = <0x00 0x7eb00000 0x00 0x10000 0x00 0x7eb10000 0x00 0x1000>;
reg-names = "hevc", "intc";
interrupts = <0x00 0x62 0x04>;
clocks = <0x14 0x0b>;
phandle = <0xeb>;
};
dma@7e007b00 {
compatible = "brcm,bcm2711-dma";
reg = <0x00 0x7e007b00 0x00 0x400>;
@@ -2252,33 +2269,41 @@
reg = <0x00 0x7e9c0000 0x00 0x100000>;
interrupts = <0x00 0xb0 0x04>;
power-domains = <0x10 0x06>;
phandle = <0xea>;
};
codec@7eb10000 {
compatible = "raspberrypi,rpivid-vid-decoder";
reg = <0x00 0x7eb10000 0x00 0x1000 0x00 0x7eb00000 0x00 0x10000>;
reg-names = "intc", "hevc";
interrupts = <0x00 0x62 0x04>;
clocks = <0x14 0x0b>;
clock-names = "hevc";
phandle = <0xec>;
};
};
cam1_regulator {
compatible = "regulator-fixed";
regulator-name = "cam1-reg";
enable-active-high;
status = "okay";
gpio = <0x0b 0x05 0x00>;
phandle = <0x53>;
memory@0 {
device_type = "memory";
reg = <0x00 0x00 0x00>;
};
leds {
compatible = "gpio-leds";
phandle = <0xed>;
led-act {
label = "ACT";
default-state = "off";
linux,default-trigger = "mmc0";
gpios = <0x07 0x2a 0x00>;
phandle = <0x5a>;
};
led-pwr {
label = "PWR";
gpios = <0x0b 0x02 0x01>;
default-state = "off";
linux,default-trigger = "default-on";
phandle = <0x5b>;
};
};
cam1_clk {
compatible = "fixed-clock";
#clock-cells = <0x00>;
status = "disabled";
phandle = <0xeb>;
phandle = <0xee>;
};
cam0_regulator {
@@ -2286,14 +2311,14 @@
regulator-name = "cam0-reg";
enable-active-high;
status = "disabled";
phandle = <0xec>;
phandle = <0xef>;
};
cam0_clk {
compatible = "fixed-clock";
#clock-cells = <0x00>;
status = "disabled";
phandle = <0xed>;
phandle = <0xf0>;
};
cam_dummy_reg {
@@ -2316,17 +2341,17 @@
uart1 = "", "", "", "Dstatus";
i2s = "", "", "", "Estatus";
spi = "", "", "", "Fstatus";
i2c0 = "", "", "", "2status", "", "", "", "Gstatus";
i2c0 = "", "", "", "4status", "", "", "", "Gstatus";
i2c1 = "", "", "", "Hstatus";
i2c = "", "", "", "Hstatus";
i2c_arm = "", "", "", "Hstatus";
i2c_vc = "", "", "", "2status", "", "", "", "Gstatus";
i2c0_baudrate = "", "", "", "2clock-frequency:0";
i2c_vc = "", "", "", "4status", "", "", "", "Gstatus";
i2c0_baudrate = "", "", "", "4clock-frequency:0";
i2c1_baudrate = "", "", "", "Hclock-frequency:0";
i2c_baudrate = "", "", "", "Hclock-frequency:0";
i2c_arm_baudrate = "", "", "", "Hclock-frequency:0";
i2c_vc_baudrate = "", "", "", "2clock-frequency:0";
watchdog = "", "", "", "Istatus";
i2c_vc_baudrate = "", "", "", "4clock-frequency:0";
watchdog = "", "", "", "Iearly-watchdog?";
random = "", "", "", "Jstatus";
sd_overclock = "", "", "", "Kbrcm,overclock-50:0";
sd_force_pio = "", "", "", "Kbrcm,force-pio?";
@@ -2365,32 +2390,15 @@
pwr_led_trigger = "", "", "", "[linux,default-trigger";
eth_led0 = "", "", "", "@led-modes:0";
eth_led1 = "", "", "", "@led-modes:4";
eth_max_speed = "", "", "", "@max-speed:0";
};
memory@0 {
device_type = "memory";
reg = <0x00 0x00 0x00>;
};
leds {
compatible = "gpio-leds";
phandle = <0xee>;
led-act {
label = "ACT";
default-state = "off";
linux,default-trigger = "mmc0";
gpios = <0x07 0x2a 0x00>;
phandle = <0x5a>;
};
led-pwr {
label = "PWR";
gpios = <0x0b 0x02 0x01>;
default-state = "off";
linux,default-trigger = "default-on";
phandle = <0x5b>;
};
regulator-cam1 {
compatible = "regulator-fixed";
regulator-name = "cam1-reg";
enable-active-high;
gpio = <0x0b 0x05 0x00>;
phandle = <0x53>;
};
regulator-sd-io-1v8 {
@@ -2424,7 +2432,7 @@
regulator-max-microvolt = <0x325aa0>;
regulator-min-microvolt = <0x325aa0>;
regulator-name = "3v3";
phandle = <0xef>;
phandle = <0xf1>;
};
fixedregulator_5v0 {
@@ -2433,7 +2441,7 @@
regulator-max-microvolt = <0x4c4b40>;
regulator-min-microvolt = <0x4c4b40>;
regulator-name = "5v0";
phandle = <0xf0>;
phandle = <0xf2>;
};
zone_dma {
@@ -2448,7 +2456,7 @@
#size-cells = <0x02>;
ranges = <0x7c500000 0x00 0xfc500000 0x00 0x3300000 0x40000000 0x00 0xff800000 0x00 0x800000>;
dma-ranges = <0x00 0x00 0x00 0x04 0x00>;
phandle = <0xf1>;
phandle = <0xf3>;
v3d@7ec04000 {
compatible = "brcm,2711-v3d";
@@ -2460,7 +2468,7 @@
clocks-names = "v3d";
interrupts = <0x00 0x4a 0x04>;
status = "disabled";
phandle = <0xf2>;
phandle = <0xf4>;
};
};
@@ -2561,6 +2569,8 @@
uart4_ctsrts_gpio10 = "/soc/gpio@7e200000/uart4-ctsrts-gpio10";
uart5_gpio12 = "/soc/gpio@7e200000/uart5-gpio12";
uart5_ctsrts_gpio14 = "/soc/gpio@7e200000/uart5-ctsrts-gpio14";
gpioout = "/soc/gpio@7e200000/gpioout";
alt0 = "/soc/gpio@7e200000/alt0";
dpi_18bit_cpadhi_gpio0 = "/soc/gpio@7e200000/dpi_18bit_cpadhi_gpio0";
dpi_18bit_cpadhi_gpio2 = "/soc/gpio@7e200000/dpi_18bit_cpadhi_gpio2";
dpi_18bit_gpio0 = "/soc/gpio@7e200000/dpi_18bit_gpio0";
@@ -2569,8 +2579,6 @@
dpi_16bit_gpio2 = "/soc/gpio@7e200000/dpi_16bit_gpio2";
dpi_16bit_cpadhi_gpio0 = "/soc/gpio@7e200000/dpi_16bit_cpadhi_gpio0";
dpi_16bit_cpadhi_gpio2 = "/soc/gpio@7e200000/dpi_16bit_cpadhi_gpio2";
gpioout = "/soc/gpio@7e200000/gpioout";
alt0 = "/soc/gpio@7e200000/alt0";
spi0_pins = "/soc/gpio@7e200000/spi0_pins";
spi0_cs_pins = "/soc/gpio@7e200000/spi0_cs_pins";
spi3_pins = "/soc/gpio@7e200000/spi3_pins";
@@ -2621,6 +2629,8 @@
sdhci = "/soc/mmc@7e300000";
hvs = "/soc/hvs@7e400000";
dsi1 = "/soc/dsi@7e700000";
csi0 = "/soc/csi@7e800000";
csi1 = "/soc/csi@7e801000";
i2c_arm = "/soc/i2c@7e804000";
i2c1 = "/soc/i2c@7e804000";
usb = "/soc/usb@7e980000";
@@ -2657,17 +2667,6 @@
ddc0 = "/soc/i2c@7ef04500";
hdmi1 = "/soc/hdmi@7ef05700";
ddc1 = "/soc/i2c@7ef09500";
mmcnr = "/soc/mmcnr@7e300000";
firmwarekms = "/soc/firmwarekms@7e600000";
smi = "/soc/smi@7e600000";
csi0 = "/soc/csi@7e800000";
csi1 = "/soc/csi@7e801000";
axiperf = "/soc/axiperf";
i2c0mux = "/soc/i2c0mux";
i2c_csi_dsi0 = "/soc/i2c0mux/i2c@0";
i2c_vc = "/soc/i2c0mux/i2c@0";
i2c0 = "/soc/i2c0mux/i2c@0";
i2c_csi_dsi = "/soc/i2c0mux/i2c@1";
firmware = "/soc/firmware";
firmware_clocks = "/soc/firmware/clocks";
expgpio = "/soc/firmware/gpio";
@@ -2675,6 +2674,16 @@
vcio = "/soc/firmware/vcio";
power = "/soc/power";
vchiq = "/soc/mailbox@7e00b840";
mmcnr = "/soc/mmcnr@7e300000";
brcmf = "/soc/mmcnr@7e300000/wifi@1";
firmwarekms = "/soc/firmwarekms@7e600000";
smi = "/soc/smi@7e600000";
axiperf = "/soc/axiperf";
i2c0mux = "/soc/i2c0mux";
i2c_csi_dsi0 = "/soc/i2c0mux/i2c@0";
i2c_vc = "/soc/i2c0mux/i2c@0";
i2c0 = "/soc/i2c0mux/i2c@0";
i2c_csi_dsi = "/soc/i2c0mux/i2c@1";
fb = "/soc/fb";
sound = "/soc/sound";
nvmem_otp = "/soc/nvmem/nvmem_otp";
@@ -2699,17 +2708,18 @@
genet = "/scb/ethernet@7d580000";
genet_mdio = "/scb/ethernet@7d580000/mdio@e14";
phy1 = "/scb/ethernet@7d580000/mdio@e14/ethernet-phy@1";
hevc_dec = "/scb/codec@7eb10000";
dma40 = "/scb/dma@7e007b00";
xhci = "/scb/xhci@7e9c0000";
cam1_reg = "/cam1_regulator";
leds = "/leds";
led_act = "/leds/led-act";
led_pwr = "/leds/led-pwr";
cam1_clk = "/cam1_clk";
cam0_regulator = "/cam0_regulator";
cam0_clk = "/cam0_clk";
cam0_reg = "/cam_dummy_reg";
cam_dummy_reg = "/cam_dummy_reg";
leds = "/leds";
led_act = "/leds/led-act";
led_pwr = "/leds/led-pwr";
cam1_reg = "/regulator-cam1";
sd_io_1v8_reg = "/regulator-sd-io-1v8";
sd_vcc_reg = "/regulator-sd-vcc";
vdd_3v3_reg = "/fixedregulator_3v3";
Binary file not shown.
+577
View File
@@ -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.
+248
View File
@@ -0,0 +1,248 @@
/dts-v1/;
/ {
#address-cells = <0x02>;
#size-cells = <0x02>;
compatible = "sifive,hifive-unleashed-a00";
model = "SiFive HiFive Unleashed A00";
chosen {
linux,initrd-end = <0x00 0x87688400>;
linux,initrd-start = <0x00 0x84200000>;
stdout-path = "/soc/serial@10010000";
};
aliases {
serial0 = "/soc/serial@10010000";
serial1 = "/soc/serial@10011000";
ethernet0 = "/soc/ethernet@10090000";
};
gpio-restart {
compatible = "gpio-restart";
gpios = <0x07 0x0a 0x01>;
};
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
timebase-frequency = <0xf4240>;
cpu@0 {
device_type = "cpu";
reg = <0x00>;
status = "okay";
compatible = "riscv";
riscv,isa-extensions = "i", "m", "a", "c", "zicntr", "zicsr", "zifencei", "zihpm", "sdtrig";
riscv,isa-base = "rv64i";
riscv,isa = "rv64imac_zicntr_zicsr_zifencei_zihpm_sdtrig";
interrupt-controller {
#interrupt-cells = <0x01>;
interrupt-controller;
compatible = "riscv,cpu-intc";
phandle = <0x04>;
};
};
cpu@1 {
device_type = "cpu";
reg = <0x01>;
status = "okay";
compatible = "riscv";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", "zifencei", "zihpm", "sdtrig";
riscv,isa-base = "rv64i";
riscv,isa = "rv64imafdc_zicntr_zicsr_zifencei_zihpm_sdtrig";
mmu-type = "riscv,sv39";
interrupt-controller {
#interrupt-cells = <0x01>;
interrupt-controller;
compatible = "riscv,cpu-intc";
phandle = <0x03>;
};
};
};
memory@80000000 {
device_type = "memory";
reg = <0x00 0x80000000 0x00 0x8000000>;
};
rtcclk {
#clock-cells = <0x00>;
compatible = "fixed-clock";
clock-frequency = <0xf4240>;
clock-output-names = "rtcclk";
phandle = <0x02>;
};
hfclk {
#clock-cells = <0x00>;
compatible = "fixed-clock";
clock-frequency = <0x1fca055>;
clock-output-names = "hfclk";
phandle = <0x01>;
};
soc {
#address-cells = <0x02>;
#size-cells = <0x02>;
compatible = "simple-bus";
ranges;
serial@10010000 {
interrupts = <0x04>;
interrupt-parent = <0x06>;
clocks = <0x05 0x03>;
reg = <0x00 0x10010000 0x00 0x1000>;
compatible = "sifive,uart0";
};
serial@10011000 {
interrupts = <0x05>;
interrupt-parent = <0x06>;
clocks = <0x05 0x03>;
reg = <0x00 0x10011000 0x00 0x1000>;
compatible = "sifive,uart0";
};
pwm@10021000 {
#pwm-cells = <0x00>;
clocks = <0x05 0x03>;
interrupts = <0x2e 0x2f 0x30 0x31>;
interrupt-parent = <0x06>;
reg = <0x00 0x10021000 0x00 0x1000>;
compatible = "sifive,pwm0";
};
pwm@10020000 {
#pwm-cells = <0x00>;
clocks = <0x05 0x03>;
interrupts = <0x2a 0x2b 0x2c 0x2d>;
interrupt-parent = <0x06>;
reg = <0x00 0x10020000 0x00 0x1000>;
compatible = "sifive,pwm0";
};
ethernet@10090000 {
#size-cells = <0x00>;
#address-cells = <0x01>;
local-mac-address = [52 54 00 12 34 56];
clock-names = "pclk", "hclk";
clocks = <0x05 0x02 0x05 0x02>;
interrupts = <0x35>;
interrupt-parent = <0x06>;
phy-handle = <0x08>;
phy-mode = "gmii";
reg-names = "control";
reg = <0x00 0x10090000 0x00 0x2000 0x00 0x100a0000 0x00 0x1000>;
compatible = "sifive,fu540-c000-gem";
ethernet-phy@0 {
reg = <0x00>;
phandle = <0x08>;
};
};
spi@10040000 {
compatible = "sifive,spi0";
reg = <0x00 0x10040000 0x00 0x1000>;
interrupt-parent = <0x06>;
interrupts = <0x33>;
clocks = <0x05 0x03>;
#address-cells = <0x01>;
#size-cells = <0x00>;
flash@0 {
compatible = "jedec,spi-nor";
reg = <0x00>;
spi-max-frequency = <0x2faf080>;
m25p,fast-read;
spi-tx-bus-width = <0x04>;
spi-rx-bus-width = <0x04>;
};
};
spi@10050000 {
compatible = "sifive,spi0";
reg = <0x00 0x10050000 0x00 0x1000>;
interrupt-parent = <0x06>;
interrupts = <0x06>;
clocks = <0x05 0x03>;
#address-cells = <0x01>;
#size-cells = <0x00>;
mmc@0 {
compatible = "mmc-spi-slot";
reg = <0x00>;
spi-max-frequency = <0x1312d00>;
voltage-ranges = <0xce4 0xce4>;
disable-wp;
};
};
cache-controller@2010000 {
compatible = "sifive,fu540-c000-ccache";
cache-block-size = <0x40>;
cache-level = <0x02>;
cache-sets = <0x400>;
cache-size = <0x200000>;
cache-unified;
interrupt-parent = <0x06>;
interrupts = <0x01 0x02 0x03>;
reg = <0x00 0x2010000 0x00 0x1000>;
};
dma@3000000 {
compatible = "sifive,fu540-c000-pdma";
reg = <0x00 0x3000000 0x00 0x100000>;
interrupt-parent = <0x06>;
interrupts = <0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e>;
#dma-cells = <0x01>;
};
gpio@10060000 {
compatible = "sifive,gpio0";
interrupt-parent = <0x06>;
interrupts = <0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x12 0x13 0x14 0x15 0x16>;
reg = <0x00 0x10060000 0x00 0x1000>;
gpio-controller;
#gpio-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x02>;
clocks = <0x05 0x03>;
phandle = <0x07>;
};
interrupt-controller@c000000 {
phandle = <0x06>;
riscv,ndev = <0x35>;
reg = <0x00 0xc000000 0x00 0x4000000>;
interrupts-extended = <0x04 0x0b 0x03 0x0b 0x03 0x09>;
interrupt-controller;
compatible = "sifive,plic-1.0.0", "riscv,plic0";
#interrupt-cells = <0x01>;
};
clock-controller@10000000 {
compatible = "sifive,fu540-c000-prci";
reg = <0x00 0x10000000 0x00 0x1000>;
clocks = <0x01 0x02>;
#clock-cells = <0x01>;
phandle = <0x05>;
};
otp@10070000 {
compatible = "sifive,fu540-c000-otp";
reg = <0x00 0x10070000 0x00 0x1000>;
fuse-count = <0x1000>;
};
clint@2000000 {
interrupts-extended = <0x04 0x03 0x04 0x07 0x03 0x03 0x03 0x07>;
reg = <0x00 0x2000000 0x00 0x10000>;
compatible = "sifive,clint0", "riscv,clint0";
};
};
};
+2 -3
View File
@@ -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"
+1 -1
View File
@@ -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 -1
View File
@@ -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" }
@@ -66,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 -1
View File
@@ -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 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "kernel-arch-aarch64"
version = "0.1.0"
edition = "2021"
edition = "2024"
[dependencies]
yggdrasil-abi.workspace = true
+21 -16
View File
@@ -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 ()) -> !;
+3 -4
View File
@@ -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 () {
+19 -15
View File
@@ -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() {
+20 -12
View File
@@ -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();
}
+6 -4
View File
@@ -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>()))
};
}
}
+41 -14
View File
@@ -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 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "kernel-arch-hosted"
version = "0.1.0"
edition = "2021"
edition = "2024"
[dependencies]
kernel-arch-interface.workspace = true
+10 -2
View File
@@ -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 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "kernel-arch-interface"
version = "0.1.0"
edition = "2021"
edition = "2024"
[dependencies]
yggdrasil-abi.workspace = true
+2 -2
View File
@@ -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 -1
View File
@@ -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;
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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>,
+4 -4
View File
@@ -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();
+2 -2
View File
@@ -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;
+4 -5
View File
@@ -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;
+2 -2
View File
@@ -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,
};
+1 -1
View File
@@ -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> {
+4 -4
View File
@@ -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) };
+30 -5
View File
@@ -1,9 +1,13 @@
use device_api::{ResetDevice, device::Device};
use yggdrasil_abi::{error::Error, primitive_enum};
const EXT_HSM: u64 = 0x48534D;
const EXT_TIME: u64 = 0x54494D45;
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 {
@@ -50,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(
@@ -76,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> {
@@ -108,3 +122,14 @@ pub fn sbi_debug_console_write_byte(byte: u8) {
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();
unreachable!()
}
+1 -1
View File
@@ -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 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "kernel-arch-x86"
version = "0.1.0"
edition = "2021"
edition = "2024"
[dependencies]
kernel-arch-interface.workspace = true
+20 -16
View File
@@ -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
View File
@@ -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()
}
}
+18 -6
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "kernel-arch-x86_64"
version = "0.1.0"
edition = "2021"
edition = "2024"
[dependencies]
yggdrasil-abi.workspace = true
+28 -20
View File
@@ -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();
+10 -8
View File
@@ -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
}
+26 -22
View File
@@ -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() {
+13 -7
View File
@@ -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)) };
}
+5 -3
View File
@@ -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>()));
}
}
}
+26 -20
View File
@@ -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
View File
@@ -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() {
+2 -2
View File
@@ -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)]
+14 -9
View File
@@ -1,11 +1,11 @@
#![feature(allocator_api)]
#![feature(allocator_api, never_type)]
#![no_std]
use acpi::AcpiTables;
use acpi_system::{AcpiInterruptMethod, AcpiSystem};
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;
@@ -45,6 +45,17 @@ pub fn get_pci_route(
.ok()
}
pub fn power_off() -> Result<!, Error> {
let system = ACPI_SYSTEM.get();
unsafe {
system.lock().enter_sleep_state(AcpiSleepState::S5).ok();
loop {
core::arch::asm!("cli; hlt");
}
}
}
/// Initializes ACPI management
pub fn switch_to_acpi(tables: &'static AcpiTables<AcpiHandlerImpl>) -> Result<(), Error> {
// NOTE mostly broken for real HW
@@ -67,12 +78,6 @@ pub fn switch_to_acpi(tables: &'static AcpiTables<AcpiHandlerImpl>) -> Result<()
// // 6. Do something with the devices
// // 7. Actually enter the S5 state
// unsafe {
// PLATFORM
// .send_ipi(IpiDeliveryTarget::OtherCpus, IpiMessage::Shutdown)
// .unwrap();
// }
// SHUTDOWN_FENCE.signal();
// SHUTDOWN_FENCE.wait_all(CPU_COUNT.load(Ordering::Acquire));
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "ygg_driver_ahci"
version = "0.1.0"
edition = "2021"
edition = "2024"
authors = ["Mark Poliakov <mark@alnyan.me>"]
[dependencies]
+3 -3
View File
@@ -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) }
}
}
+3 -3
View File
@@ -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 {
+3 -3
View File
@@ -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;
+9 -9
View File
@@ -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 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "ygg_driver_nvme"
version = "0.1.0"
edition = "2021"
edition = "2024"
authors = ["Mark Poliakov <mark@alnyan.me>"]
[dependencies]
+1 -1
View File
@@ -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;
+7 -7
View File
@@ -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;
+7 -7
View File
@@ -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)
}
}
+1 -1
View File
@@ -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!();
}
+13 -12
View File
@@ -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
View File
@@ -4,4 +4,5 @@
extern crate alloc;
mod pl011;
mod pl031;
mod pl061;
+31 -13
View File
@@ -1,22 +1,26 @@
// TODO baud rate configuration
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{FullIrq, InterruptHandler, IrqVector},
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::{external_interrupt_controller, manager::DEVICE_REGISTRY},
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,
@@ -68,7 +72,7 @@ struct Pl011Inner {
pub struct Pl011 {
inner: OneTimeInit<Arc<Terminal<Pl011Inner>>>,
base: PhysicalAddress,
irq: FullIrq,
irq: IrqHandle,
}
impl Io {
@@ -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
}
@@ -164,14 +184,12 @@ impl Device for Pl011 {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
self.irq.register(self.clone())?;
{
let io = self.inner.get().output().io.lock();
io.regs.IMSC.modify(IMSC::RXIM::SET);
}
intc.enable_irq(self.irq.irq)?;
self.irq.enable()?;
Ok(())
}
+66
View File
@@ -0,0 +1,66 @@
use alloc::sync::Arc;
use device_api::device::{Device, DeviceInitContext};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use libk::{
error::Error,
fs::sysfs::{self, nodes::SysfsRtcNode},
};
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
interfaces::Readable,
register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
register_structs! {
#[allow(non_snake_case)]
Regs {
(0x00 => RTCDR: ReadOnly<u32>),
(0x04 => RTCMR: ReadWrite<u32>),
(0x08 => RTCLR: ReadWrite<u32>),
(0x0C => RTCCR: ReadWrite<u32>),
(0x10 => RTCIMSC: ReadWrite<u32>),
(0x14 => RTCRIS: ReadOnly<u32>),
(0x18 => RTCMIS: ReadOnly<u32>),
(0x1C => RTCICR: WriteOnly<u32>),
(0x20 => @END),
}
}
struct Pl031 {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
}
impl SysfsRtcNode for Pl031 {
fn read(&self) -> Result<u64, Error> {
let regs = self.regs.lock();
Ok(regs.RTCDR.get() as _)
}
}
impl Device for Pl031 {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
sysfs::nodes::add_rtc_node(self.clone());
Ok(())
}
fn display_name(&self) -> &str {
"ARM PL031 RTC"
}
}
device_tree_driver! {
compatible: ["arm,pl031"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
let rtc = Arc::new(Pl031 { regs: IrqSafeSpinlock::new(regs) });
Some(rtc)
}
}
}
+9 -10
View File
@@ -8,16 +8,16 @@ use device_api::{
GpioController, GpioInterruptEvent, GpioInterruptMode, GpioPinLevel, PinHandle,
SinglePinDirection,
},
interrupt::{FullIrq, InterruptHandler, IrqVector},
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::{device::external_interrupt_controller, event::signal_gpio_event};
use libk::event::signal_gpio_event;
use libk_mm::device::DeviceMemoryIo;
use libk_util::{bit::BitField, sync::IrqSafeSpinlock};
use tock_registers::{
@@ -50,7 +50,7 @@ register_structs! {
struct Pl061 {
#[allow(unused)]
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
irq: FullIrq,
irq: IrqHandle,
clocks: Vec<ClockHandle>,
resets: Vec<ResetHandle>,
gpio_events: [AtomicU64; 8],
@@ -69,9 +69,8 @@ impl Device for Pl061 {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
intc.enable_irq(self.irq.irq)?;
self.irq.register(self.clone())?;
self.irq.enable()?;
Ok(())
}
+1
View File
@@ -16,3 +16,4 @@ tock-registers.workspace = true
log.workspace = true
bytemuck.workspace = true
futures-util.workspace = true
async-trait.workspace = true
+14 -4
View File
@@ -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 {
-209
View File
@@ -1,209 +0,0 @@
use alloc::sync::Arc;
use device_api::{
clock::ClockHandle,
device::{Device, DeviceInitContext},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::DebugSink,
device::{external_interrupt_controller, 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: FullIrq,
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> {
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
intc.enable_irq(self.irq.irq)?;
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(),
}))
}
}
}
+93
View File
@@ -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)
}
}
}
+8 -10
View File
@@ -2,16 +2,15 @@ use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
gpio::{GpioController, GpioInterruptEvent, PinHandle},
interrupt::{FullIrq, InterruptHandler, IrqVector},
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::device::external_interrupt_controller;
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
@@ -69,7 +68,7 @@ register_structs! {
struct Bcm2711Gpio {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
#[allow(unused)]
irqs: [FullIrq; 2],
irqs: [IrqHandle; 2],
}
impl Regs {
@@ -142,10 +141,9 @@ impl Device for Bcm2711Gpio {
regs.configure_pin_interrupts(pin, false, false, false, false);
}
let intc = external_interrupt_controller()?;
for irq in self.irqs.iter() {
intc.register_irq(irq.irq, irq.options, self.clone())?;
intc.enable_irq(irq.irq)?;
irq.register(self.clone())?;
irq.enable()?;
}
Ok(())
+298
View File
@@ -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)
}
}
}
+4 -1
View File
@@ -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;
+48 -11
View File
@@ -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();
+202
View File
@@ -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)
}
}
}
+27 -7
View File
@@ -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 -1
View File
@@ -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;
+5 -6
View File
@@ -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)]
@@ -0,0 +1,70 @@
use alloc::sync::Arc;
use device_api::device::{Device, DeviceInitContext};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use libk::{
error::Error,
fs::sysfs::{self, nodes::SysfsRtcNode},
};
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
interfaces::Readable,
register_structs,
registers::{ReadOnly, ReadWrite},
};
use yggdrasil_abi::time::NANOSECONDS_IN_SECOND;
register_structs! {
#[allow(non_snake_case)]
Regs {
(0x00 => TIME_LOW: ReadOnly<u32>),
(0x04 => TIME_HIGH: ReadOnly<u32>),
(0x08 => ALARM_LOW: ReadWrite<u32>),
(0x0C => ALARM_HIGH: ReadWrite<u32>),
(0x10 => IRQ_ENABLED: ReadWrite<u32>),
(0x14 => CLEAR_ALARM: ReadWrite<u32>),
(0x18 => ALARM_STATUS: ReadOnly<u32>),
(0x1C => CLEAR_INTERRUPT: ReadWrite<u32>),
(0x20 => @END),
}
}
struct Rtc {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
}
impl SysfsRtcNode for Rtc {
fn read(&self) -> Result<u64, Error> {
let regs = self.regs.lock();
let low = regs.TIME_LOW.get();
let high = regs.TIME_HIGH.get();
let t = ((high as u64) << 32) | (low as u64);
Ok(t / NANOSECONDS_IN_SECOND)
}
}
impl Device for Rtc {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
sysfs::nodes::add_rtc_node(self.clone());
Ok(())
}
fn display_name(&self) -> &str {
"Google Goldfish RTC"
}
}
device_tree_driver! {
compatible: ["google,goldfish-rtc"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
let rtc = Arc::new(Rtc { regs: IrqSafeSpinlock::new(regs) });
Some(rtc)
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
#![allow(unsafe_op_in_unsafe_fn)]
#![no_std]
extern crate alloc;
mod goldfish_rtc;
mod plic;
+104 -79
View File
@@ -2,20 +2,23 @@ use alloc::{sync::Arc, vec::Vec};
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
InterruptTable, Irq, 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);
@@ -261,11 +284,12 @@ impl Device for Plic {
}
impl DeviceTreeInterruptController for Plic {
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq> {
fn map_interrupt(self: Arc<Self>, property: &TProp, offset: usize) -> Option<IrqHandle> {
let num = property.read_cell(offset, 1)?;
Some(FullIrq {
Some(IrqHandle {
irq: Irq::External(num as _),
options: IrqOptions::default(),
intc: self.clone(),
})
}
@@ -289,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();
@@ -301,6 +325,7 @@ device_tree_driver! {
) else {
continue;
};
log::info!("Context #{context}: mode={mode:?}, hart={hart_id}");
if mode != ContextMode::ExternalS {
continue;
}
@@ -322,7 +347,7 @@ device_tree_driver! {
let intc = Arc::new(Plic {
base,
max_irqs,
max_irq,
context_map,
inner: OneTimeInit::new(),
});
+20
View File
@@ -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
+190
View File
@@ -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)
}
}
}
+171
View File
@@ -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