Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 717bbda123 | |||
| aa86f377f2 | |||
| e8acfb5a40 | |||
| b5d704064d |
Generated
+51
-46
@@ -258,6 +258,26 @@ version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||
|
||||
[[package]]
|
||||
name = "bitfield"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db1bcd90f88eabbf0cadbfb87a45bceeaebcd3b4bc9e43da379cd2ef0162590d"
|
||||
dependencies = [
|
||||
"bitfield-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitfield-macros"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3787a07661997bfc05dd3431e379c0188573f78857080cf682e1393ab8e4d64c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -469,7 +489,6 @@ dependencies = [
|
||||
name = "device-api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"device-api-macros",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
@@ -500,7 +519,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "discrete_range_map"
|
||||
version = "0.6.2"
|
||||
source = "git+https://git.alnyan.me/yggdrasil/discrete_range_map.git#0c932f7cc7ff55253519e3465ddeea8fe69083be"
|
||||
source = "git+https://git.alnyan.me/yggdrasil/discrete_range_map.git#6b54882b190b02fb013f22cbe9664f6273e846ae"
|
||||
dependencies = [
|
||||
"btree_monstrousity",
|
||||
"either",
|
||||
@@ -1200,9 +1219,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.180"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
@@ -1354,12 +1373,6 @@ 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"
|
||||
@@ -1794,20 +1807,7 @@ dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"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",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
@@ -2024,14 +2024,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.24.0"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
|
||||
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom 0.3.1",
|
||||
"once_cell",
|
||||
"rustix 1.1.3",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
@@ -2407,7 +2408,7 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"rustix 0.38.44",
|
||||
"rustix",
|
||||
"winsafe",
|
||||
]
|
||||
|
||||
@@ -2576,8 +2577,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"rustix 0.38.44",
|
||||
"linux-raw-sys",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2608,7 +2609,6 @@ dependencies = [
|
||||
"semver 1.0.25",
|
||||
"serde",
|
||||
"tar",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"walkdir",
|
||||
@@ -2677,7 +2677,6 @@ dependencies = [
|
||||
name = "ygg_driver_bsp_bcm283x"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytemuck",
|
||||
"device-api",
|
||||
"device-tree",
|
||||
@@ -2748,6 +2747,25 @@ dependencies = [
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_mmc_generic_sdhci"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bitfield",
|
||||
"bitflags 2.8.0",
|
||||
"bytemuck",
|
||||
"device-api",
|
||||
"device-tree",
|
||||
"futures-util",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
"libk-util",
|
||||
"log",
|
||||
"tock-registers",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_net_core"
|
||||
version = "0.1.0"
|
||||
@@ -2876,19 +2894,6 @@ 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"
|
||||
@@ -3055,6 +3060,7 @@ dependencies = [
|
||||
"ygg_driver_bsp_riscv",
|
||||
"ygg_driver_fat32",
|
||||
"ygg_driver_input",
|
||||
"ygg_driver_mmc_generic_sdhci",
|
||||
"ygg_driver_net_core",
|
||||
"ygg_driver_net_igbe",
|
||||
"ygg_driver_net_loopback",
|
||||
@@ -3062,7 +3068,6 @@ 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",
|
||||
|
||||
@@ -9,9 +9,9 @@ Main features
|
||||
-------------
|
||||
|
||||
* Architecture support:
|
||||
* [aarch64](kernel/arch/aarch64)
|
||||
* [x86_64](kernel/arch/x86_64)
|
||||
* [riscv64](kernel/arch/riscv64)
|
||||
* [aarch64](kernel/src/arch/aarch64)
|
||||
* [x86_64](kernel/src/arch/x86_64)
|
||||
* [i686](kernel/src/arch/i686) (Pentium Pro and later)
|
||||
* Core features:
|
||||
* Kernel/userspace preemptive multithreading
|
||||
* Kernel-space multitasking with `async`/`await` runtime
|
||||
@@ -24,7 +24,6 @@ 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
|
||||
@@ -34,37 +33,33 @@ 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
|
||||
* AHCI SATA drive support
|
||||
* 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)
|
||||
* xHCI USB host controller
|
||||
* VirtIO Network + GPU framebuffer support
|
||||
* 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
|
||||
* USB HID keyboards
|
||||
|
||||
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 + GICv2m MSI interrupts
|
||||
* GICv2 IRQ controller
|
||||
|
||||
x86-specific:
|
||||
|
||||
* Boot via UEFI [yboot](https://git.alnyan.me/yggdrasil/yboot)
|
||||
* Boot options:
|
||||
* x86_64: UEFI [yboot](https://git.alnyan.me/yggdrasil/yboot)
|
||||
* i686: multiboot/grub
|
||||
* I/O and Local APIC IRQ controllers
|
||||
* PS/2 keyboard
|
||||
* HPET for x86_64
|
||||
* i8253 as a fallback timer
|
||||
* i8253-based timer for i686 or as a fallback timer
|
||||
* COM ports
|
||||
* ACPI, [work in progress](https://github.com/rust-osdev/acpi)
|
||||
* ACPI, [work in progress](https://github.com/rust-osdev/acpi), mostly broken
|
||||
on real hardware, so currently disabled
|
||||
* ACPI shutdown
|
||||
* PCI IRQ pin routing
|
||||
* Events like power button, etc.
|
||||
@@ -127,6 +122,7 @@ 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...
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ $ booti ${loadaddr} ${initrd_addr_r}:<SIZE-PRINTED-WHEN-LOADING-INITRD> ${fdt_ad
|
||||
###### a quick command for a development boot
|
||||
###### (FIXME when initrd gets larger than 64MiB)
|
||||
|
||||
env set ipaddr 13.0.0.2; env set fdt_addr_r 0x11000000; env set initrd_addr_r 0x04000000; tftpboot ${initrd_addr_r} 13.0.0.1:initrd.tar; tftpboot ${loadaddr} 13.0.0.1:kernel.bin; load mmc 0:1 ${fdt_addr_r} bcm2711-rpi-4-b.dtb; fdt addr ${fdt_addr_r}; fdt resize; fdt memory 0x0 0x3C000000; booti ${loadaddr} ${initrd_addr_r}:67108864 ${fdt_addr_r}
|
||||
env set ipaddr 13.0.0.2; env set fdt_addr_r 0x11000000; env set initrd_addr_r 0x20000000; tftpboot ${initrd_addr_r} 13.0.0.1:initrd.img; tftpboot ${loadaddr} 13.0.0.1:yggdrasil-kernel.bin; load mmc 1:1 ${fdt_addr_r} bcm2711-rpi-4-b.dtb; fdt addr ${fdt_addr_r}; fdt resize; fdt memory 0x0 0x3C000000; booti ${loadaddr} ${initrd_addr_r}:0x4000000 ${fdt_addr_r}
|
||||
|
||||
dhcp;
|
||||
env set initrd_addr_r 0x20000000; tftpboot ${initrd_addr_r} 192.168.88.10:initrd.img; tftpboot ${loadaddr} 192.168.88.10:yggdrasil-kernel.bin; load mmc 1:1 ${fdt_addr_r} bcm2711-rpi-4-b.dtb; fdt addr ${fdt_addr_r}; fdt resize; fdt memory 0x0 0x3C000000; booti ${loadaddr} ${initrd_addr_r}:0x4000000 ${fdt_addr_r}
|
||||
|
||||
+2
-3
@@ -33,11 +33,10 @@ $ 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; 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}
|
||||
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}
|
||||
|
||||
|
||||
Missing drivers:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"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,15 +264,16 @@
|
||||
compatible = "gpio-keys";
|
||||
|
||||
poweroff {
|
||||
gpios = <&gpio 0x03 0x00>;
|
||||
gpios = <0x8007 0x03 0x00>;
|
||||
linux,code = <0x74>;
|
||||
label = "GPIO Key Poweroff";
|
||||
};
|
||||
};
|
||||
|
||||
gpio: pl061@9030000 {
|
||||
pl061@9030000 {
|
||||
phandle = <0x8007>;
|
||||
clock-names = "apb_pclk";
|
||||
clocks = <&clk_24mhz>;
|
||||
clocks = <0x8000>;
|
||||
interrupts = <0x00 0x07 0x04>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <0x02>;
|
||||
@@ -298,15 +299,15 @@
|
||||
|
||||
pl031@9010000 {
|
||||
clock-names = "apb_pclk";
|
||||
clocks = <&clk_24mhz>;
|
||||
clocks = <0x8000>;
|
||||
interrupts = <0x00 0x02 0x04>;
|
||||
reg = <0x00 0x9010000 0x00 0x1000>;
|
||||
compatible = "arm,pl031", "arm,primecell";
|
||||
};
|
||||
|
||||
uart0: pl011@9000000 {
|
||||
pl011@9000000 {
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
clocks = <&clk_24mhz &clk_24mhz>;
|
||||
clocks = <0x8000 0x8000>;
|
||||
interrupts = <0x00 0x01 0x04>;
|
||||
reg = <0x00 0x9000000 0x00 0x1000>;
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
@@ -410,7 +411,8 @@
|
||||
compatible = "arm,armv8-timer", "arm,armv7-timer";
|
||||
};
|
||||
|
||||
clk_24mhz: apb-pclk {
|
||||
apb-pclk {
|
||||
phandle = <0x8000>;
|
||||
clock-output-names = "clk24mhz";
|
||||
clock-frequency = <0x16e3600>;
|
||||
#clock-cells = <0x00>;
|
||||
@@ -1,669 +0,0 @@
|
||||
/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>;
|
||||
};
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
#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.
@@ -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 nvme.max_host_mem_size_mb=0";
|
||||
bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_headphones=0 cgroup_disable=memory numa_policy=interleave";
|
||||
phandle = <0x54>;
|
||||
};
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
reg = <0x7e00b880 0x40>;
|
||||
interrupts = <0x00 0x21 0x04>;
|
||||
#mbox-cells = <0x00>;
|
||||
phandle = <0x31>;
|
||||
phandle = <0x35>;
|
||||
};
|
||||
|
||||
gpio@7e200000 {
|
||||
@@ -252,7 +252,7 @@
|
||||
i2c0if-gpio0 {
|
||||
brcm,pins = <0x00 0x01>;
|
||||
brcm,function = <0x04>;
|
||||
phandle = <0x35>;
|
||||
phandle = <0x33>;
|
||||
};
|
||||
|
||||
i2c0if-gpio28 {
|
||||
@@ -264,7 +264,7 @@
|
||||
i2c0if-gpio44 {
|
||||
brcm,pins = <0x2c 0x2d>;
|
||||
brcm,function = <0x05>;
|
||||
phandle = <0x36>;
|
||||
phandle = <0x34>;
|
||||
};
|
||||
|
||||
i2c1-gpio2 {
|
||||
@@ -958,64 +958,64 @@
|
||||
};
|
||||
};
|
||||
|
||||
gpioout {
|
||||
brcm,pins = <0x06>;
|
||||
brcm,function = <0x01>;
|
||||
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>;
|
||||
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 = <0xb5>;
|
||||
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 = <0xb6>;
|
||||
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 = <0xb7>;
|
||||
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 = <0xb8>;
|
||||
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 = <0xb9>;
|
||||
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 = <0xba>;
|
||||
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>;
|
||||
};
|
||||
|
||||
alt0 {
|
||||
brcm,pins = <0x04 0x05 0x07 0x08 0x09 0x0a 0x0b>;
|
||||
brcm,function = <0x04>;
|
||||
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 = <0x33>;
|
||||
phandle = <0x31>;
|
||||
};
|
||||
|
||||
uart2_pins {
|
||||
@@ -1194,17 +1194,17 @@
|
||||
brcm,pins = <0x28 0x29>;
|
||||
brcm,function = <0x04>;
|
||||
brcm,pull = <0x00>;
|
||||
phandle = <0x32>;
|
||||
phandle = <0x36>;
|
||||
};
|
||||
};
|
||||
|
||||
serial@7e201000 {
|
||||
compatible = "arm,pl011-axi";
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201000 0x200>;
|
||||
interrupts = <0x00 0x79 0x04>;
|
||||
clocks = <0x08 0x13 0x08 0x14>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
arm,primecell-periphid = <0x341011>;
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
status = "okay";
|
||||
cts-event-workaround;
|
||||
pinctrl-names = "default";
|
||||
@@ -1295,7 +1295,7 @@
|
||||
#size-cells = <0x00>;
|
||||
status = "disabled";
|
||||
clock-frequency = <0x186a0>;
|
||||
phandle = <0x34>;
|
||||
phandle = <0x32>;
|
||||
};
|
||||
|
||||
dpi@7e208000 {
|
||||
@@ -1404,8 +1404,8 @@
|
||||
compatible = "brcm,bcm2711-hvs";
|
||||
reg = <0x7e400000 0x8000>;
|
||||
interrupts = <0x00 0x61 0x04>;
|
||||
clocks = <0x14 0x04>;
|
||||
status = "disabled";
|
||||
clocks = <0x14 0x04>;
|
||||
phandle = <0xc4>;
|
||||
};
|
||||
|
||||
@@ -1424,38 +1424,6 @@
|
||||
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>;
|
||||
@@ -1478,11 +1446,10 @@
|
||||
#size-cells = <0x00>;
|
||||
clocks = <0x16>;
|
||||
clock-names = "otg";
|
||||
dr_mode = "host";
|
||||
phys = <0x17>;
|
||||
phy-names = "usb2-phy";
|
||||
power-domains = <0x10 0x06>;
|
||||
interrupt-names = "usb", "soft";
|
||||
power-domains = <0x10 0x06>;
|
||||
status = "disabled";
|
||||
phandle = <0xc5>;
|
||||
};
|
||||
@@ -1544,12 +1511,12 @@
|
||||
};
|
||||
|
||||
serial@7e201400 {
|
||||
compatible = "arm,pl011-axi";
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201400 0x200>;
|
||||
interrupts = <0x00 0x79 0x04>;
|
||||
clocks = <0x08 0x13 0x08 0x14>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
arm,primecell-periphid = <0x341011>;
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
status = "disabled";
|
||||
pinctrl-0 = <0x18>;
|
||||
pinctrl-names = "default";
|
||||
@@ -1557,12 +1524,12 @@
|
||||
};
|
||||
|
||||
serial@7e201600 {
|
||||
compatible = "arm,pl011-axi";
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201600 0x200>;
|
||||
interrupts = <0x00 0x79 0x04>;
|
||||
clocks = <0x08 0x13 0x08 0x14>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
arm,primecell-periphid = <0x341011>;
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
status = "disabled";
|
||||
pinctrl-0 = <0x19>;
|
||||
pinctrl-names = "default";
|
||||
@@ -1570,12 +1537,12 @@
|
||||
};
|
||||
|
||||
serial@7e201800 {
|
||||
compatible = "arm,pl011-axi";
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201800 0x200>;
|
||||
interrupts = <0x00 0x79 0x04>;
|
||||
clocks = <0x08 0x13 0x08 0x14>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
arm,primecell-periphid = <0x341011>;
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
status = "disabled";
|
||||
pinctrl-0 = <0x1a>;
|
||||
pinctrl-names = "default";
|
||||
@@ -1583,12 +1550,12 @@
|
||||
};
|
||||
|
||||
serial@7e201a00 {
|
||||
compatible = "arm,pl011-axi";
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x7e201a00 0x200>;
|
||||
interrupts = <0x00 0x79 0x04>;
|
||||
clocks = <0x08 0x13 0x08 0x14>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
arm,primecell-periphid = <0x341011>;
|
||||
arm,primecell-periphid = <0x241011>;
|
||||
status = "disabled";
|
||||
pinctrl-0 = <0x1b>;
|
||||
pinctrl-names = "default";
|
||||
@@ -1836,9 +1803,113 @@
|
||||
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";
|
||||
mboxes = <0x31>;
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x01>;
|
||||
mboxes = <0x35>;
|
||||
dma-ranges;
|
||||
phandle = <0x06>;
|
||||
|
||||
clocks {
|
||||
@@ -1864,7 +1935,7 @@
|
||||
|
||||
vcio {
|
||||
compatible = "raspberrypi,vcio";
|
||||
phandle = <0xdb>;
|
||||
phandle = <0xdf>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1880,88 +1951,8 @@
|
||||
reg = <0x7e00b840 0x3c>;
|
||||
interrupts = <0x00 0x22 0x04>;
|
||||
pinctrl-names = "default";
|
||||
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>;
|
||||
};
|
||||
pinctrl-0 = <0x36>;
|
||||
phandle = <0xe0>;
|
||||
};
|
||||
|
||||
gpiomem {
|
||||
@@ -1973,12 +1964,12 @@
|
||||
compatible = "brcm,bcm2708-fb";
|
||||
firmware = <0x06>;
|
||||
status = "okay";
|
||||
phandle = <0xe2>;
|
||||
phandle = <0xe1>;
|
||||
};
|
||||
|
||||
sound {
|
||||
status = "disabled";
|
||||
phandle = <0xe3>;
|
||||
phandle = <0xe2>;
|
||||
};
|
||||
|
||||
nvmem {
|
||||
@@ -1991,7 +1982,7 @@
|
||||
firmware = <0x06>;
|
||||
reg = <0x00 0xa6>;
|
||||
status = "okay";
|
||||
phandle = <0xe4>;
|
||||
phandle = <0xe3>;
|
||||
};
|
||||
|
||||
nvmem_cust {
|
||||
@@ -2044,7 +2035,7 @@
|
||||
compatible = "brcm,bcm2711-vc5";
|
||||
status = "disabled";
|
||||
raspberrypi,firmware = <0x06>;
|
||||
phandle = <0xe5>;
|
||||
phandle = <0xe4>;
|
||||
};
|
||||
|
||||
clk-27M {
|
||||
@@ -2069,7 +2060,7 @@
|
||||
#size-cells = <0x01>;
|
||||
ranges = <0x00 0x7e000000 0x00 0xfe000000 0x1800000>;
|
||||
dma-ranges = <0x00 0xc0000000 0x00 0x00 0x40000000>;
|
||||
phandle = <0xe6>;
|
||||
phandle = <0xe5>;
|
||||
|
||||
mmc@7e340000 {
|
||||
compatible = "brcm,bcm2711-emmc2";
|
||||
@@ -2085,8 +2076,8 @@
|
||||
};
|
||||
};
|
||||
|
||||
pmu {
|
||||
compatible = "arm,cortex-a72-pmu";
|
||||
arm-pmu {
|
||||
compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3", "arm,cortex-a7-pmu";
|
||||
interrupts = <0x00 0x10 0x04 0x00 0x11 0x04 0x00 0x12 0x04 0x00 0x13 0x04>;
|
||||
interrupt-affinity = <0x39 0x3a 0x3b 0x3c>;
|
||||
};
|
||||
@@ -2094,13 +2085,14 @@
|
||||
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 = <0xe7>;
|
||||
phandle = <0xe6>;
|
||||
|
||||
cpu@0 {
|
||||
device_type = "cpu";
|
||||
@@ -2181,9 +2173,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 0x40000000 0x00 0x00 0x00 0x00 0x00 0xfc000000>;
|
||||
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>;
|
||||
dma-ranges = <0x04 0x7c000000 0x00 0xfc000000 0x00 0x3800000 0x00 0x00 0x00 0x00 0x04 0x00>;
|
||||
phandle = <0xe8>;
|
||||
phandle = <0xe7>;
|
||||
|
||||
pcie@7d500000 {
|
||||
compatible = "brcm,bcm2711-pcie";
|
||||
@@ -2198,7 +2190,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 0xc0000000 0x06 0x00 0x00 0x40000000>;
|
||||
ranges = <0x2000000 0x00 0x80000000 0x06 0x00 0x00 0x80000000>;
|
||||
dma-ranges = <0x2000000 0x00 0x00 0x00 0x00 0x00 0xc0000000>;
|
||||
brcm,enable-ssc;
|
||||
phandle = <0x3e>;
|
||||
@@ -2226,7 +2218,7 @@
|
||||
status = "okay";
|
||||
phy-handle = <0x40>;
|
||||
phy-mode = "rgmii-rxid";
|
||||
phandle = <0xe9>;
|
||||
phandle = <0xe8>;
|
||||
|
||||
mdio@e14 {
|
||||
compatible = "brcm,genet-mdio-v5";
|
||||
@@ -2234,7 +2226,7 @@
|
||||
reg-names = "mdio";
|
||||
#address-cells = <0x01>;
|
||||
#size-cells = <0x00>;
|
||||
phandle = <0xea>;
|
||||
phandle = <0xe9>;
|
||||
|
||||
ethernet-phy@1 {
|
||||
reg = <0x01>;
|
||||
@@ -2244,15 +2236,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
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>;
|
||||
@@ -2269,41 +2252,33 @@
|
||||
reg = <0x00 0x7e9c0000 0x00 0x100000>;
|
||||
interrupts = <0x00 0xb0 0x04>;
|
||||
power-domains = <0x10 0x06>;
|
||||
phandle = <0xec>;
|
||||
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";
|
||||
};
|
||||
};
|
||||
|
||||
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_regulator {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "cam1-reg";
|
||||
enable-active-high;
|
||||
status = "okay";
|
||||
gpio = <0x0b 0x05 0x00>;
|
||||
phandle = <0x53>;
|
||||
};
|
||||
|
||||
cam1_clk {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0x00>;
|
||||
status = "disabled";
|
||||
phandle = <0xee>;
|
||||
phandle = <0xeb>;
|
||||
};
|
||||
|
||||
cam0_regulator {
|
||||
@@ -2311,14 +2286,14 @@
|
||||
regulator-name = "cam0-reg";
|
||||
enable-active-high;
|
||||
status = "disabled";
|
||||
phandle = <0xef>;
|
||||
phandle = <0xec>;
|
||||
};
|
||||
|
||||
cam0_clk {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0x00>;
|
||||
status = "disabled";
|
||||
phandle = <0xf0>;
|
||||
phandle = <0xed>;
|
||||
};
|
||||
|
||||
cam_dummy_reg {
|
||||
@@ -2341,17 +2316,17 @@
|
||||
uart1 = "", "", "", "Dstatus";
|
||||
i2s = "", "", "", "Estatus";
|
||||
spi = "", "", "", "Fstatus";
|
||||
i2c0 = "", "", "", "4status", "", "", "", "Gstatus";
|
||||
i2c0 = "", "", "", "2status", "", "", "", "Gstatus";
|
||||
i2c1 = "", "", "", "Hstatus";
|
||||
i2c = "", "", "", "Hstatus";
|
||||
i2c_arm = "", "", "", "Hstatus";
|
||||
i2c_vc = "", "", "", "4status", "", "", "", "Gstatus";
|
||||
i2c0_baudrate = "", "", "", "4clock-frequency:0";
|
||||
i2c_vc = "", "", "", "2status", "", "", "", "Gstatus";
|
||||
i2c0_baudrate = "", "", "", "2clock-frequency:0";
|
||||
i2c1_baudrate = "", "", "", "Hclock-frequency:0";
|
||||
i2c_baudrate = "", "", "", "Hclock-frequency:0";
|
||||
i2c_arm_baudrate = "", "", "", "Hclock-frequency:0";
|
||||
i2c_vc_baudrate = "", "", "", "4clock-frequency:0";
|
||||
watchdog = "", "", "", "Iearly-watchdog?";
|
||||
i2c_vc_baudrate = "", "", "", "2clock-frequency:0";
|
||||
watchdog = "", "", "", "Istatus";
|
||||
random = "", "", "", "Jstatus";
|
||||
sd_overclock = "", "", "", "Kbrcm,overclock-50:0";
|
||||
sd_force_pio = "", "", "", "Kbrcm,force-pio?";
|
||||
@@ -2390,15 +2365,32 @@
|
||||
pwr_led_trigger = "", "", "", "[linux,default-trigger";
|
||||
eth_led0 = "", "", "", "@led-modes:0";
|
||||
eth_led1 = "", "", "", "@led-modes:4";
|
||||
eth_max_speed = "", "", "", "@max-speed:0";
|
||||
};
|
||||
|
||||
regulator-cam1 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "cam1-reg";
|
||||
enable-active-high;
|
||||
gpio = <0x0b 0x05 0x00>;
|
||||
phandle = <0x53>;
|
||||
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-sd-io-1v8 {
|
||||
@@ -2432,7 +2424,7 @@
|
||||
regulator-max-microvolt = <0x325aa0>;
|
||||
regulator-min-microvolt = <0x325aa0>;
|
||||
regulator-name = "3v3";
|
||||
phandle = <0xf1>;
|
||||
phandle = <0xef>;
|
||||
};
|
||||
|
||||
fixedregulator_5v0 {
|
||||
@@ -2441,7 +2433,7 @@
|
||||
regulator-max-microvolt = <0x4c4b40>;
|
||||
regulator-min-microvolt = <0x4c4b40>;
|
||||
regulator-name = "5v0";
|
||||
phandle = <0xf2>;
|
||||
phandle = <0xf0>;
|
||||
};
|
||||
|
||||
zone_dma {
|
||||
@@ -2456,7 +2448,7 @@
|
||||
#size-cells = <0x02>;
|
||||
ranges = <0x7c500000 0x00 0xfc500000 0x00 0x3300000 0x40000000 0x00 0xff800000 0x00 0x800000>;
|
||||
dma-ranges = <0x00 0x00 0x00 0x04 0x00>;
|
||||
phandle = <0xf3>;
|
||||
phandle = <0xf1>;
|
||||
|
||||
v3d@7ec04000 {
|
||||
compatible = "brcm,2711-v3d";
|
||||
@@ -2468,7 +2460,7 @@
|
||||
clocks-names = "v3d";
|
||||
interrupts = <0x00 0x4a 0x04>;
|
||||
status = "disabled";
|
||||
phandle = <0xf4>;
|
||||
phandle = <0xf2>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2569,8 +2561,6 @@
|
||||
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";
|
||||
@@ -2579,6 +2569,8 @@
|
||||
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";
|
||||
@@ -2629,8 +2621,6 @@
|
||||
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";
|
||||
@@ -2667,6 +2657,17 @@
|
||||
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";
|
||||
@@ -2674,16 +2675,6 @@
|
||||
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";
|
||||
@@ -2708,18 +2699,17 @@
|
||||
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";
|
||||
leds = "/leds";
|
||||
led_act = "/leds/led-act";
|
||||
led_pwr = "/leds/led-pwr";
|
||||
cam1_reg = "/cam1_regulator";
|
||||
cam1_clk = "/cam1_clk";
|
||||
cam0_regulator = "/cam0_regulator";
|
||||
cam0_clk = "/cam0_clk";
|
||||
cam0_reg = "/cam_dummy_reg";
|
||||
cam_dummy_reg = "/cam_dummy_reg";
|
||||
cam1_reg = "/regulator-cam1";
|
||||
leds = "/leds";
|
||||
led_act = "/leds/led-act";
|
||||
led_pwr = "/leds/led-pwr";
|
||||
sd_io_1v8_reg = "/regulator-sd-io-1v8";
|
||||
sd_vcc_reg = "/regulator-sd-vcc";
|
||||
vdd_3v3_reg = "/fixedregulator_3v3";
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -38,7 +38,7 @@
|
||||
#size-cells = <0x00>;
|
||||
timebase-frequency = <0x989680>;
|
||||
|
||||
cpu0: cpu@0 {
|
||||
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";
|
||||
|
||||
cpu0_intc: interrupt-controller {
|
||||
interrupt-controller {
|
||||
#interrupt-cells = <0x01>;
|
||||
interrupt-controller;
|
||||
compatible = "riscv,cpu-intc";
|
||||
@@ -61,9 +61,11 @@
|
||||
};
|
||||
|
||||
cpu-map {
|
||||
|
||||
cluster0 {
|
||||
|
||||
core0 {
|
||||
cpu = <&cpu0>;
|
||||
cpu = <0x01>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -184,8 +186,7 @@
|
||||
phandle = <0x03>;
|
||||
riscv,ndev = <0x5f>;
|
||||
reg = <0x00 0xc000000 0x00 0x600000>;
|
||||
interrupts-extended = <&cpu0_intc 0x0b>,
|
||||
<&cpu0_intc 0x09>;
|
||||
interrupts-extended = <0x02 0x0b 0x02 0x09>;
|
||||
interrupt-controller;
|
||||
compatible = "sifive,plic-1.0.0", "riscv,plic0";
|
||||
#address-cells = <0x00>;
|
||||
@@ -193,8 +194,7 @@
|
||||
};
|
||||
|
||||
clint@2000000 {
|
||||
interrupts-extended = <&cpu0_intc 0x03>,
|
||||
<&cpu0_intc 0x07>;
|
||||
interrupts-extended = <0x02 0x03 0x02 0x07>;
|
||||
reg = <0x00 0x2000000 0x00 0x10000>;
|
||||
compatible = "sifive,clint0", "riscv,clint0";
|
||||
};
|
||||
@@ -1,308 +0,0 @@
|
||||
/* 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
Binary file not shown.
@@ -6,7 +6,7 @@
|
||||
"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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "yggdrasil-kernel"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
authors = ["Mark Poliakov <mark@alnyan.me>"]
|
||||
|
||||
@@ -35,7 +35,6 @@ 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" }
|
||||
@@ -59,6 +58,7 @@ device-tree.workspace = true
|
||||
kernel-arch-aarch64.workspace = true
|
||||
ygg_driver_bsp_arm.path = "driver/bsp/arm"
|
||||
ygg_driver_bsp_bcm283x.path = "driver/bsp/bcm283x"
|
||||
ygg_driver_mmc_generic_sdhci.path = "driver/mmc/generic-sdhci"
|
||||
|
||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||
device-tree.workspace = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kernel-arch"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
|
||||
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
|
||||
kernel-arch-x86_64.path = "x86_64"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kernel-arch-aarch64"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi.workspace = true
|
||||
|
||||
@@ -66,7 +66,7 @@ impl FpContext {
|
||||
///
|
||||
/// It is up to the caller to ensure `this` is a valid pointer to store the FPU context in.
|
||||
pub unsafe fn store(this: *mut Self) {
|
||||
unsafe { __aarch64_fp_store_context(this as _) }
|
||||
__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) {
|
||||
unsafe { __aarch64_fp_restore_context(this as _) }
|
||||
__aarch64_fp_restore_context(this as _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,12 +177,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
stack.push(entry as _);
|
||||
stack.push(arg);
|
||||
|
||||
setup_common_context(
|
||||
&mut stack,
|
||||
(__aarch64_task_enter_kernel as *const ()).addr(),
|
||||
0,
|
||||
0,
|
||||
);
|
||||
setup_common_context(&mut stack, __aarch64_task_enter_kernel as _, 0, 0);
|
||||
|
||||
let sp = stack.build();
|
||||
|
||||
@@ -217,7 +212,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
|
||||
setup_common_context(
|
||||
&mut stack,
|
||||
(__aarch64_task_enter_user as *const ()).addr(),
|
||||
__aarch64_task_enter_user as _,
|
||||
ttbr0,
|
||||
context.thread_pointer as _,
|
||||
);
|
||||
@@ -236,8 +231,9 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
}
|
||||
|
||||
unsafe fn enter(&self) -> ! {
|
||||
unsafe { FpContext::restore(self.fp_context.get()) };
|
||||
unsafe { __aarch64_enter_task(self.inner.get()) }
|
||||
FpContext::restore(self.fp_context.get());
|
||||
|
||||
__aarch64_enter_task(self.inner.get())
|
||||
}
|
||||
|
||||
unsafe fn switch(&self, from: &Self) {
|
||||
@@ -245,20 +241,19 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
let src = from.inner.get();
|
||||
|
||||
if dst != src {
|
||||
unsafe {
|
||||
// Save the old context
|
||||
FpContext::store(from.fp_context.get());
|
||||
// Load next context
|
||||
FpContext::restore(self.fp_context.get());
|
||||
// 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 ()) {
|
||||
unsafe { FpContext::restore(self.fp_context.get()) };
|
||||
unsafe { __aarch64_switch_task_and_drop(self.inner.get(), thread) };
|
||||
FpContext::restore(self.fp_context.get());
|
||||
|
||||
__aarch64_switch_task_and_drop(self.inner.get(), thread);
|
||||
}
|
||||
|
||||
fn set_thread_pointer(&self, _tp: usize) {
|
||||
@@ -298,7 +293,7 @@ fn setup_common_context(builder: &mut StackBuilder, entry: usize, ttbr0: u64, tp
|
||||
builder.push(0); // x19
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
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 ()) -> !;
|
||||
|
||||
@@ -13,11 +13,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 +25,7 @@ pub mod context;
|
||||
pub mod mem;
|
||||
|
||||
pub use context::TaskContextImpl;
|
||||
pub use mem::{KernelTableManagerImpl, process::ProcessAddressSpaceImpl};
|
||||
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
|
||||
|
||||
pub struct ArchitectureImpl;
|
||||
|
||||
@@ -101,7 +101,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)));
|
||||
|
||||
unsafe { cpu.set_local() };
|
||||
cpu.set_local();
|
||||
}
|
||||
|
||||
fn local_cpu() -> *mut () {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use core::ops::Range;
|
||||
|
||||
use aarch64_cpu::registers::{TTBR0_EL1, TTBR1_EL1};
|
||||
use kernel_arch_interface::{KERNEL_VIRT_OFFSET, mem::DeviceMemoryAttributes};
|
||||
use kernel_arch_interface::{mem::DeviceMemoryAttributes, KERNEL_VIRT_OFFSET};
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
device::{DevicePageManager, DevicePageTableLevel},
|
||||
@@ -10,7 +10,7 @@ use libk_mm_interface::{
|
||||
|
||||
use crate::mem::{
|
||||
auto_lower_address,
|
||||
table::{L1, L2, L3, PageAttributes, PageEntry, PageTable},
|
||||
table::{PageAttributes, PageEntry, PageTable, L1, L2, L3},
|
||||
tlb_flush_range_va,
|
||||
};
|
||||
|
||||
@@ -98,26 +98,22 @@ impl DevicePageTableLevel for L3DeviceMemory {
|
||||
}
|
||||
|
||||
pub unsafe fn setup() {
|
||||
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 {
|
||||
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.large.0));
|
||||
KERNEL_L1[DEVICE_L1] = PageEntry::table(phys, PageAttributes::empty());
|
||||
// 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 {
|
||||
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.large.0));
|
||||
KERNEL_L1[DEVICE_L1] = PageEntry::table(phys, PageAttributes::empty());
|
||||
}
|
||||
|
||||
pub unsafe fn load() {
|
||||
|
||||
@@ -4,9 +4,9 @@ use aarch64_cpu::{
|
||||
registers::{MAIR_EL1, SCTLR_EL1, TCR_EL1},
|
||||
};
|
||||
use kernel_arch_interface::{
|
||||
KERNEL_VIRT_OFFSET,
|
||||
mem::{DeviceMemoryAttributes, KernelTableManager, RawDeviceMemoryMapping},
|
||||
sync::IrqSafeSpinlock,
|
||||
KERNEL_VIRT_OFFSET,
|
||||
};
|
||||
use libk_mm_interface::{address::PhysicalAddress, table::EntryLevel};
|
||||
use tock_registers::interfaces::{ReadWriteable, Writeable};
|
||||
@@ -14,7 +14,7 @@ use yggdrasil_abi::error::Error;
|
||||
|
||||
pub use intrinsics::*;
|
||||
|
||||
use crate::{ArchitectureImpl, mem::table::L1};
|
||||
use crate::{mem::table::L1, ArchitectureImpl};
|
||||
|
||||
pub mod fixed;
|
||||
pub mod intrinsics;
|
||||
@@ -52,18 +52,14 @@ impl KernelTableManager for KernelTableManagerImpl {
|
||||
attrs: DeviceMemoryAttributes,
|
||||
) -> Result<RawDeviceMemoryMapping<Self>, Error> {
|
||||
let _lock = KERNEL_MEMORY_LOCK.lock();
|
||||
unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
fixed::DEVICE_MEMORY.map_device_pages(PhysicalAddress::from_u64(base), count, attrs)
|
||||
}
|
||||
#[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();
|
||||
unsafe {
|
||||
#[allow(static_mut_refs)]
|
||||
fixed::DEVICE_MEMORY.unmap_device_pages(mapping);
|
||||
}
|
||||
#[allow(static_mut_refs)]
|
||||
fixed::DEVICE_MEMORY.unmap_device_pages(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,19 +132,15 @@ unsafe fn enable_mmu() {
|
||||
SCTLR_EL1.modify(SCTLR_EL1::M::Enable);
|
||||
|
||||
// Enable caches
|
||||
unsafe {
|
||||
enable_icache();
|
||||
enable_dcache();
|
||||
}
|
||||
enable_icache();
|
||||
enable_dcache();
|
||||
}
|
||||
|
||||
pub unsafe fn init_lower(bsp: bool) {
|
||||
setup_memory_attributes();
|
||||
unsafe {
|
||||
if bsp {
|
||||
fixed::setup();
|
||||
}
|
||||
fixed::load();
|
||||
enable_mmu();
|
||||
if bsp {
|
||||
fixed::setup();
|
||||
}
|
||||
fixed::load();
|
||||
enable_mmu();
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ use libk_mm_interface::{
|
||||
};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{KernelTableManagerImpl, mem::table::PageEntry};
|
||||
use crate::{mem::table::PageEntry, KernelTableManagerImpl};
|
||||
|
||||
use super::{
|
||||
dc_cvac, ic_iallu,
|
||||
table::{L1, L2, L3, PageAttributes, PageTable},
|
||||
table::{PageAttributes, PageTable, L1, L2, L3},
|
||||
tlb_flush_asid, tlb_flush_vaae1,
|
||||
};
|
||||
|
||||
@@ -97,10 +97,8 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
|
||||
}
|
||||
|
||||
unsafe fn clear(&mut self) {
|
||||
unsafe {
|
||||
self.l1
|
||||
.drop_range::<TA>(0..((Self::UPPER_LIMIT_PFN * L3::SIZE).page_index::<L1>()))
|
||||
};
|
||||
self.l1
|
||||
.drop_range::<TA>(0..((Self::UPPER_LIMIT_PFN * L3::SIZE).page_index::<L1>()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use crate::KernelTableManagerImpl;
|
||||
use super::dc_cvac;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct PageAttributes: u64 {
|
||||
const PRESENT = 1 << 0;
|
||||
|
||||
@@ -71,8 +71,8 @@ pub struct L3;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EntryType {
|
||||
Table(PageAttributes, PhysicalAddress),
|
||||
Page(PageAttributes, PhysicalAddress),
|
||||
Table(PhysicalAddress),
|
||||
Page(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 = unsafe { PhysicalRefMut::map(physical) };
|
||||
let inner = PhysicalRefMut::map(physical);
|
||||
Some(inner)
|
||||
}
|
||||
}
|
||||
@@ -234,16 +234,12 @@ where
|
||||
let entry = self[index];
|
||||
|
||||
if let Some(table) = entry.as_table() {
|
||||
unsafe {
|
||||
let mut table_ref: PhysicalRefMut<
|
||||
PageTable<L::NextLevel>,
|
||||
KernelTableManagerImpl,
|
||||
> = PhysicalRefMut::map(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);
|
||||
}
|
||||
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!(
|
||||
@@ -311,14 +307,9 @@ impl<L: NonTerminalEntryLevel> PageEntry<L> {
|
||||
if !self.is_present() {
|
||||
EntryType::Invalid
|
||||
} else if let Some(table) = self.as_table() {
|
||||
let attributes = self.attributes();
|
||||
EntryType::Table(attributes, table)
|
||||
EntryType::Table(table)
|
||||
} else {
|
||||
let attributes = self.attributes();
|
||||
EntryType::Page(
|
||||
attributes,
|
||||
PhysicalAddress::from_u64(self.0 & !Self::ATTR_MASK),
|
||||
)
|
||||
EntryType::Page(PhysicalAddress::from_u64(self.0 & !Self::ATTR_MASK))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,26 +426,8 @@ impl From<PageAttributes> for MapAttributes {
|
||||
impl fmt::Display for EntryType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
&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::Table(address) => write!(f, "table @ {address:#x}"),
|
||||
Self::Page(address) => write!(f, "page @ {address:#x}"),
|
||||
Self::Invalid => f.write_str("<invalid>"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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::{PageAttributeUpdate, ProcessAddressSpaceManager},
|
||||
process::ProcessAddressSpaceManager,
|
||||
table::{MapAttributes, TableAllocator},
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
@@ -164,14 +164,6 @@ 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!()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use alloc::vec::Vec;
|
||||
use device_api::interrupt::IpiMessage;
|
||||
|
||||
use crate::{
|
||||
Architecture, guard::IrqGuard, sync::IrqSafeSpinlock, task::Scheduler, util::OneTimeInit,
|
||||
guard::IrqGuard, sync::IrqSafeSpinlock, task::Scheduler, util::OneTimeInit, Architecture,
|
||||
};
|
||||
|
||||
#[repr(C, align(0x10))]
|
||||
|
||||
@@ -6,7 +6,7 @@ use core::{
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
use crate::{Architecture, guard::IrqGuard};
|
||||
use crate::{guard::IrqGuard, Architecture};
|
||||
|
||||
pub struct Spinlock<A: Architecture, T> {
|
||||
value: UnsafeCell<T>,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use core::{arch::global_asm, cell::UnsafeCell, marker::PhantomData};
|
||||
|
||||
use kernel_arch_interface::{
|
||||
Architecture,
|
||||
mem::{KernelTableManager, PhysicalMemoryAllocator},
|
||||
task::{StackBuilder, TaskContext, UserContextInfo},
|
||||
Architecture,
|
||||
};
|
||||
use libk_mm_interface::address::PhysicalAddress;
|
||||
use tock_registers::{
|
||||
@@ -13,9 +13,9 @@ use tock_registers::{
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
ArchitectureImpl, PerCpuData,
|
||||
mem::{self},
|
||||
registers::SATP,
|
||||
ArchitectureImpl, PerCpuData,
|
||||
};
|
||||
|
||||
pub const CONTEXT_SIZE: usize = 14 * size_of::<usize>();
|
||||
@@ -86,7 +86,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
stack.push(context.entry);
|
||||
stack.push(context.argument);
|
||||
|
||||
setup_common_context(&mut stack, (__rv64_task_enter_user as *const ()).addr());
|
||||
setup_common_context(&mut stack, __rv64_task_enter_user as _);
|
||||
|
||||
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 *const ()).addr());
|
||||
setup_common_context(&mut stack, __rv64_task_enter_kernel as _);
|
||||
|
||||
let sp = stack.build();
|
||||
|
||||
|
||||
@@ -11,18 +11,18 @@ use core::{
|
||||
use alloc::{boxed::Box, collections::btree_map::BTreeMap, vec::Vec};
|
||||
use device_api::interrupt::LocalInterruptController;
|
||||
use kernel_arch_interface::{
|
||||
Architecture,
|
||||
cpu::{CpuData, CpuImpl, IpiQueue},
|
||||
sync::IrqSafeSpinlock,
|
||||
task::Scheduler,
|
||||
util::OneTimeInit,
|
||||
Architecture,
|
||||
};
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable};
|
||||
|
||||
use registers::SSTATUS;
|
||||
|
||||
pub mod mem;
|
||||
pub use mem::{KernelTableManagerImpl, process::ProcessAddressSpaceImpl};
|
||||
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
|
||||
pub mod context;
|
||||
pub use context::TaskContextImpl;
|
||||
pub mod intrinsics;
|
||||
|
||||
@@ -2,11 +2,12 @@ use kernel_arch_interface::sync::IrqSafeSpinlock;
|
||||
use libk_mm_interface::{address::PhysicalAddress, table::EntryLevel};
|
||||
|
||||
use crate::{
|
||||
ArchitectureImpl,
|
||||
mem::{
|
||||
KERNEL_VIRT_OFFSET, auto_lower_address,
|
||||
table::{L1, PageEntry, PageTable},
|
||||
auto_lower_address,
|
||||
table::{PageEntry, PageTable, L1},
|
||||
KERNEL_VIRT_OFFSET,
|
||||
},
|
||||
ArchitectureImpl,
|
||||
};
|
||||
|
||||
pub const IDENTITY_SIZE_L1: usize = 64;
|
||||
|
||||
@@ -3,13 +3,13 @@ use kernel_arch_interface::mem::{
|
||||
};
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
table::{EntryLevel, EntryLevelExt, page_index},
|
||||
table::{page_index, EntryLevel, EntryLevelExt},
|
||||
};
|
||||
use tock_registers::interfaces::Writeable;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
mem::table::{L1, L3, PageTable},
|
||||
mem::table::{PageTable, L1, L3},
|
||||
registers::SATP,
|
||||
};
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ use crate::mem::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
table::{DroppableRange, PageTable, L1, L2, L3},
|
||||
KernelTableManagerImpl, USER_BOUNDARY,
|
||||
table::{DroppableRange, L1, L2, L3, PageTable},
|
||||
};
|
||||
|
||||
pub struct ProcessAddressSpaceImpl<TA: TableAllocator> {
|
||||
|
||||
@@ -10,8 +10,8 @@ use libk_mm_interface::{
|
||||
pointer::{PhysicalRef, PhysicalRefMut},
|
||||
process::PageAttributeUpdate,
|
||||
table::{
|
||||
EntryLevel, EntryLevelDrop, NextPageTable, NonTerminalEntryLevel, TableAllocator,
|
||||
page_index,
|
||||
page_index, EntryLevel, EntryLevelDrop, NextPageTable, NonTerminalEntryLevel,
|
||||
TableAllocator,
|
||||
},
|
||||
};
|
||||
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) };
|
||||
|
||||
@@ -78,7 +78,11 @@ 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> {
|
||||
|
||||
@@ -35,7 +35,7 @@ cfg_if! {
|
||||
|
||||
pub use imp::{ArchitectureImpl, KernelTableManagerImpl, ProcessAddressSpaceImpl, TaskContextImpl};
|
||||
|
||||
pub use kernel_arch_interface::{Architecture, KERNEL_VIRT_OFFSET, guard, mem, sync, task, util};
|
||||
pub use kernel_arch_interface::{guard, mem, sync, task, util, Architecture, KERNEL_VIRT_OFFSET};
|
||||
|
||||
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,4 +1,4 @@
|
||||
#![feature(box_as_ptr)]
|
||||
#![feature(iter_chain, new_zeroed_alloc, box_as_ptr)]
|
||||
#![allow(clippy::new_without_default)]
|
||||
#![no_std]
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ use kernel_arch_interface::{
|
||||
mem::{KernelTableManager, PhysicalMemoryAllocator},
|
||||
task::{ForkFrame, StackBuilder, TaskContext, TaskFrame, UserContextInfo},
|
||||
};
|
||||
use kernel_arch_x86::registers::{CR3, FpuContext, MSR_IA32_FS_BASE};
|
||||
use kernel_arch_x86::registers::{FpuContext, CR3, MSR_IA32_FS_BASE};
|
||||
use libk_mm_interface::address::PhysicalAddress;
|
||||
use tock_registers::interfaces::Writeable;
|
||||
use yggdrasil_abi::{arch::SavedFrame, error::Error};
|
||||
|
||||
use crate::{
|
||||
ArchitectureImpl,
|
||||
mem::{auto_lower_address, fixed},
|
||||
ArchitectureImpl,
|
||||
};
|
||||
|
||||
/// Frame saved onto the stack when taking an IRQ
|
||||
@@ -445,7 +445,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 *const ()).addr());
|
||||
setup_common_context(&mut stack, __x86_64_task_enter_kernel as _);
|
||||
|
||||
let sp = stack.build();
|
||||
|
||||
@@ -483,7 +483,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 *const ()).addr());
|
||||
setup_common_context(&mut stack, __x86_64_task_enter_user as _);
|
||||
|
||||
let sp = stack.build();
|
||||
let rsp0 = stack_base + USER_TASK_PAGES * 0x1000;
|
||||
|
||||
@@ -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::{KernelTableManagerImpl, process::ProcessAddressSpaceImpl};
|
||||
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
|
||||
|
||||
pub struct ArchitectureImpl;
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
use core::ops::Range;
|
||||
|
||||
use kernel_arch_interface::{Architecture, mem::DeviceMemoryAttributes, sync::IrqSafeSpinlock};
|
||||
use kernel_arch_interface::{mem::DeviceMemoryAttributes, sync::IrqSafeSpinlock, Architecture};
|
||||
use kernel_arch_x86::registers::CR3;
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
device::{DevicePageManager, DevicePageTableLevel},
|
||||
table::{EntryLevel, page_index},
|
||||
table::{page_index, EntryLevel},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ArchitectureImpl, KERNEL_VIRT_OFFSET,
|
||||
mem::{
|
||||
auto_lower_address,
|
||||
table::{L0, L1, L2, L3, PageAttributes, PageEntry, PageTable},
|
||||
table::{PageAttributes, PageEntry, PageTable, L0, L1, L2, L3},
|
||||
},
|
||||
ArchitectureImpl, KERNEL_VIRT_OFFSET,
|
||||
};
|
||||
|
||||
pub const IDENTITY_SIZE_L1: usize = 64;
|
||||
|
||||
@@ -6,7 +6,7 @@ use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::KERNEL_VIRT_OFFSET;
|
||||
|
||||
use self::table::{L0, L1, PageTable};
|
||||
use self::table::{PageTable, L0, L1};
|
||||
|
||||
pub mod fixed;
|
||||
pub mod process;
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::KernelTableManagerImpl;
|
||||
|
||||
use super::{
|
||||
clone_kernel_tables, flush_tlb_entry,
|
||||
table::{L0, L1, L2, L3, PageEntry, PageTable},
|
||||
table::{PageEntry, PageTable, L0, L1, L2, L3},
|
||||
};
|
||||
|
||||
/// Represents a process or kernel address space. Because x86-64 does not have cool stuff like
|
||||
|
||||
@@ -224,8 +224,8 @@ impl<L: EntryLevel> PageTable<L> {
|
||||
}
|
||||
|
||||
/// 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) };
|
||||
|
||||
+2
-2
@@ -6,9 +6,9 @@ use std::{
|
||||
};
|
||||
|
||||
use abi_generator::{
|
||||
TargetEnv,
|
||||
abi::{AbiBuilder, ty::TypeWidth},
|
||||
abi::{ty::TypeWidth, AbiBuilder},
|
||||
syntax::UnwrapFancy,
|
||||
TargetEnv,
|
||||
};
|
||||
|
||||
fn build_x86_64() {
|
||||
|
||||
@@ -7,7 +7,7 @@ use device_api::{
|
||||
device::Device,
|
||||
interrupt::{InterruptHandler, Irq, IrqVector},
|
||||
};
|
||||
use kernel_arch_x86::{ISA_IRQ_OFFSET, intrinsics};
|
||||
use kernel_arch_x86::{intrinsics, ISA_IRQ_OFFSET};
|
||||
use libk::device::external_interrupt_controller;
|
||||
use libk_mm::{
|
||||
address::{PhysicalAddress, Virtualize},
|
||||
@@ -15,8 +15,8 @@ use libk_mm::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ACPI_SYSTEM,
|
||||
mem::{read_memory, write_memory},
|
||||
ACPI_SYSTEM,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
||||
@@ -5,7 +5,7 @@ use acpi::AcpiTables;
|
||||
use acpi_system::{AcpiInterruptMethod, AcpiSleepState, AcpiSystem};
|
||||
use alloc::boxed::Box;
|
||||
use libk::error::Error;
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use core::mem::{MaybeUninit, size_of};
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
|
||||
use device_api::dma::DmaAllocator;
|
||||
use libk::dma::{BusAddress, DmaBuffer, DmaSliceMut};
|
||||
use tock_registers::register_structs;
|
||||
|
||||
use crate::{MAX_PRD_SIZE, data::AtaString, error::AhciError};
|
||||
use crate::{data::AtaString, error::AhciError, MAX_PRD_SIZE};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
#[repr(u8)]
|
||||
|
||||
@@ -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.is_multiple_of(2) }>: IsTrue,
|
||||
ConstAssert<{ N % 2 == 0 }>: IsTrue,
|
||||
{
|
||||
data: [u8; N],
|
||||
}
|
||||
@@ -243,7 +243,7 @@ impl AtaIdentifyResponse {
|
||||
|
||||
impl<const N: usize> AtaString<N>
|
||||
where
|
||||
ConstAssert<{ N.is_multiple_of(2) }>: IsTrue,
|
||||
ConstAssert<{ N % 2 == 0 }>: IsTrue,
|
||||
{
|
||||
#[allow(clippy::inherent_to_string)]
|
||||
pub fn to_string(&self) -> String {
|
||||
|
||||
@@ -15,18 +15,18 @@ use device_api::{
|
||||
use error::AhciError;
|
||||
use libk::{device::manager::probe_partitions, dma::DmaBuffer, fs::devfs, task::runtime};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
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::{CAP, GHC, SSTS, Version};
|
||||
use crate::regs::{Version, CAP, GHC, SSTS};
|
||||
|
||||
mod command;
|
||||
mod data;
|
||||
|
||||
@@ -16,18 +16,18 @@ use libk::{
|
||||
error::Error,
|
||||
};
|
||||
use libk_mm::{
|
||||
OnDemandPage, PageProvider, VirtualPage, address::PhysicalAddress, device::DeviceMemoryIo,
|
||||
table::MapAttributes,
|
||||
address::PhysicalAddress, device::DeviceMemoryIo, table::MapAttributes, OnDemandPage,
|
||||
PageProvider, VirtualPage,
|
||||
};
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock, waker::QueueWaker};
|
||||
use libk_util::{sync::IrqSafeSpinlock, waker::QueueWaker, OneTimeInit};
|
||||
use tock_registers::interfaces::{Readable, Writeable};
|
||||
|
||||
use crate::{
|
||||
AhciController, MAX_COMMANDS, MAX_PRD_SIZE, SECTOR_SIZE,
|
||||
command::{AtaCommand, AtaIdentify, AtaReadDmaEx},
|
||||
data::{COMMAND_LIST_LENGTH, CommandListEntry, CommandTable, ReceivedFis},
|
||||
data::{CommandListEntry, CommandTable, ReceivedFis, COMMAND_LIST_LENGTH},
|
||||
error::AhciError,
|
||||
regs::{CMD_PENDING, CMD_READY, IE, PortRegs, TFD},
|
||||
regs::{PortRegs, CMD_PENDING, CMD_READY, IE, TFD},
|
||||
AhciController, MAX_COMMANDS, MAX_PRD_SIZE, SECTOR_SIZE,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
@@ -319,11 +319,11 @@ impl BlockDevice for AhciPort {
|
||||
position: u64,
|
||||
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
|
||||
) -> Result<(), Error> {
|
||||
if !buffer.len().is_multiple_of(SECTOR_SIZE) {
|
||||
if buffer.len() % SECTOR_SIZE != 0 {
|
||||
log::warn!("ahci: misaligned buffer size: {}", buffer.len());
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
if !position.is_multiple_of(SECTOR_SIZE as u64) {
|
||||
if position % SECTOR_SIZE as u64 != 0 {
|
||||
log::warn!("ahci: misaligned read");
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "ygg_driver_nvme"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
authors = ["Mark Poliakov <mark@alnyan.me>"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use core::fmt::{self, Write};
|
||||
|
||||
use libk::dma::BusAddress;
|
||||
use tock_registers::{UIntLike, interfaces::Readable, register_structs, registers::ReadOnly};
|
||||
use tock_registers::{interfaces::Readable, register_structs, registers::ReadOnly, UIntLike};
|
||||
|
||||
use crate::queue::PhysicalRegionPage;
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ use libk::{
|
||||
error::Error,
|
||||
};
|
||||
use libk_mm::{
|
||||
OnDemandPage, PageProvider, PageSlice, VirtualPage,
|
||||
address::{AsPhysicalAddress, PhysicalAddress},
|
||||
table::MapAttributes,
|
||||
OnDemandPage, PageProvider, PageSlice, VirtualPage,
|
||||
};
|
||||
|
||||
use crate::{IoDirection, command::IdentifyNamespaceRequest, register_nvme_namespace};
|
||||
use crate::{command::IdentifyNamespaceRequest, register_nvme_namespace, IoDirection};
|
||||
|
||||
use super::{NvmeController, error::NvmeError};
|
||||
use super::{error::NvmeError, NvmeController};
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct NvmeNamespace {
|
||||
@@ -92,10 +92,10 @@ impl BlockDevice for NvmeNamespace {
|
||||
position: u64,
|
||||
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
|
||||
) -> Result<(), Error> {
|
||||
if !position.is_multiple_of(self.block_size() as u64) {
|
||||
if position % self.block_size() as u64 != 0 {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
if !buffer.len().is_multiple_of(self.block_size()) || buffer.is_empty() {
|
||||
if buffer.len() % self.block_size() != 0 || 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.is_multiple_of(self.block_size() as u64) {
|
||||
if position % self.block_size() as u64 != 0 {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
if !buffer.len().is_multiple_of(self.block_size()) || buffer.is_empty() {
|
||||
if buffer.len() % self.block_size() != 0 || buffer.is_empty() {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
let lba = position / self.block_size() as u64;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(const_trait_impl, if_let_guard)]
|
||||
#![feature(const_trait_impl, let_chains, if_let_guard, maybe_uninit_slice)]
|
||||
#![allow(missing_docs)]
|
||||
#![no_std]
|
||||
// TODO
|
||||
@@ -7,7 +7,7 @@
|
||||
extern crate alloc;
|
||||
|
||||
use core::{
|
||||
mem::{MaybeUninit, size_of},
|
||||
mem::{size_of, MaybeUninit},
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
time::Duration,
|
||||
};
|
||||
@@ -27,10 +27,10 @@ use libk::{
|
||||
fs::devfs,
|
||||
task::{cpu_count, cpu_index, runtime},
|
||||
};
|
||||
use libk_mm::{L3_PAGE_SIZE, address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo, L3_PAGE_SIZE};
|
||||
use libk_util::{
|
||||
OneTimeInit,
|
||||
sync::{IrqGuard, IrqSafeSpinlock},
|
||||
OneTimeInit,
|
||||
};
|
||||
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 = unsafe { regs.doorbell_ptr(self.doorbell_shift, false, idx) };
|
||||
let cq_ptr = unsafe { regs.doorbell_ptr(self.doorbell_shift, true, idx) };
|
||||
let sq_ptr = regs.doorbell_ptr(self.doorbell_shift, false, idx);
|
||||
let cq_ptr = regs.doorbell_ptr(self.doorbell_shift, true, idx);
|
||||
(sq_ptr, cq_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ impl PrpList {
|
||||
size: usize,
|
||||
) -> Result<Self, NvmeError> {
|
||||
// TODO hardcoded page size
|
||||
if !base.into_u64().is_multiple_of(0x1000) {
|
||||
if base.into_u64() % 0x1000 != 0 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(generic_const_exprs)]
|
||||
#![feature(generic_const_exprs, maybe_uninit_slice)]
|
||||
#![allow(incomplete_features)]
|
||||
#![no_std]
|
||||
|
||||
@@ -23,11 +23,11 @@ use libk::{
|
||||
task::{runtime, sync::AsyncMutex},
|
||||
};
|
||||
use libk_mm::{
|
||||
OnDemandPage, PageProvider, VirtualPage, address::PhysicalAddress, table::MapAttributes,
|
||||
address::PhysicalAddress, table::MapAttributes, OnDemandPage, PageProvider, VirtualPage,
|
||||
};
|
||||
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<AsyncMutex<Option<Arc<ScsiUnit>>>>,
|
||||
units: Vec<IrqSafeRwLock<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(|_| AsyncMutex::new(None)).collect();
|
||||
let units = (0..lun_count).map(|_| IrqSafeRwLock::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].lock().await = Some(unit);
|
||||
*this.units[i].write() = 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].lock().await;
|
||||
let mut slot = self.units[lun].write();
|
||||
let present = self.probe_lun(lun as u8).await;
|
||||
|
||||
if let Some(unit) = slot.as_ref() {
|
||||
@@ -143,12 +143,12 @@ impl ScsiEnclosure {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn detach(&self) {
|
||||
pub 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.lock().await.take() {
|
||||
if let Some(unit) = unit.write().take() {
|
||||
unit.detach();
|
||||
}
|
||||
}
|
||||
@@ -214,11 +214,11 @@ impl BlockDevice for ScsiUnit {
|
||||
position: u64,
|
||||
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
|
||||
) -> Result<(), Error> {
|
||||
if !position.is_multiple_of(self.lba_size as u64) {
|
||||
if position % self.lba_size as u64 != 0 {
|
||||
log::warn!("scsi: misaligned read");
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
if !buffer.len().is_multiple_of(self.lba_size) {
|
||||
if buffer.len() % self.lba_size != 0 {
|
||||
log::warn!("scsi: misaligned buffer size");
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
@@ -235,7 +235,7 @@ impl BlockDevice for ScsiUnit {
|
||||
let mut transport = self.enclosure.transport.lock().await;
|
||||
|
||||
// TODO DmaSliceMut subslicing
|
||||
let (buffer, range) = buffer.into_parts();
|
||||
let (buffer, range) = unsafe { buffer.into_parts() };
|
||||
let mut offset = range.start;
|
||||
|
||||
for i in (0..lba_count).step_by(self.max_lba_per_request) {
|
||||
@@ -368,11 +368,10 @@ 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,26 +1,22 @@
|
||||
// TODO baud rate configuration
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
debug::DebugSink,
|
||||
device::manager::DEVICE_REGISTRY,
|
||||
vfs::{Terminal, TerminalInput, TerminalOutput},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use tock_registers::{
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{TerminalOptions, TerminalOutputOptions},
|
||||
};
|
||||
use yggdrasil_abi::{error::Error, io::TerminalOptions};
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
@@ -93,25 +89,14 @@ impl Io {
|
||||
}
|
||||
|
||||
impl TerminalOutput for Pl011Inner {
|
||||
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(b'\n');
|
||||
fn write(&self, byte: u8) -> Result<(), Error> {
|
||||
self.io.lock().send(byte);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_multiple(
|
||||
&self,
|
||||
bytes: &[u8],
|
||||
options: &TerminalOutputOptions,
|
||||
) -> Result<usize, Error> {
|
||||
fn write_multiple(&self, bytes: &[u8]) -> 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())
|
||||
@@ -132,11 +117,6 @@ impl DebugSink for Pl011 {
|
||||
self.inner.get().putc_to_output(byte)
|
||||
}
|
||||
|
||||
fn puts(&self, s: &str) -> Result<(), Error> {
|
||||
self.inner.get().write_to_output(s.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn supports_control_sequences(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::device::{Device, DeviceInitContext};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
error::Error,
|
||||
fs::sysfs::{self, nodes::SysfsRtcNode},
|
||||
|
||||
@@ -11,11 +11,11 @@ use device_api::{
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::{
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext, device_tree_driver,
|
||||
util::generic_gpio_config,
|
||||
device_tree_driver, util::generic_gpio_config, DeviceTreeGpioPins, DeviceTreePinController,
|
||||
Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
};
|
||||
use libk::event::signal_gpio_event;
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
|
||||
@@ -16,4 +16,3 @@ tock-registers.workspace = true
|
||||
log.workspace = true
|
||||
bytemuck.workspace = true
|
||||
futures-util.workspace = true
|
||||
async-trait.workspace = true
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockController, ClockHandle, Hertz, IntoHertz},
|
||||
clock::{ClockController, ClockHandle},
|
||||
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::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
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,16 +65,6 @@ 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 {
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::ClockHandle,
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
debug::DebugSink,
|
||||
device::manager::DEVICE_REGISTRY,
|
||||
vfs::{Terminal, TerminalInput, TerminalOutput},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use tock_registers::{
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, ReadWrite},
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{TerminalOptions, TerminalOutputOptions},
|
||||
};
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
AUX_MU_IER_REG [
|
||||
RX_IRQ OFFSET(0) NUMBITS(1) [],
|
||||
TX_IRQ OFFSET(1) NUMBITS(1) [],
|
||||
],
|
||||
AUX_MU_IIR_REG [
|
||||
IID OFFSET(1) NUMBITS(2) [
|
||||
None = 0,
|
||||
TxEmpty = 1,
|
||||
RxNotEmpty = 2,
|
||||
],
|
||||
PENDING OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
AUX_MU_LSR_REG [
|
||||
TX_EMPTY OFFSET(5) NUMBITS(1) [],
|
||||
]
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
Regs {
|
||||
(0x00 => AUX_MU_IO_REG: ReadWrite<u32>),
|
||||
(0x04 => AUX_MU_IER_REG: ReadWrite<u32, AUX_MU_IER_REG::Register>),
|
||||
(0x08 => AUX_MU_IIR_REG: ReadWrite<u32, AUX_MU_IIR_REG::Register>),
|
||||
(0x0C => _0),
|
||||
(0x14 => AUX_MU_LSR_REG: ReadOnly<u32, AUX_MU_LSR_REG::Register>),
|
||||
(0x18 => _1),
|
||||
(0x30 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
}
|
||||
|
||||
/// Broadcom 283x mini-UART driver
|
||||
pub struct Bcm2835AuxUart {
|
||||
base: PhysicalAddress,
|
||||
irq: IrqHandle,
|
||||
clock: ClockHandle,
|
||||
inner: OneTimeInit<Arc<Terminal<Inner>>>,
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
fn write_byte(&self, byte: u8) -> Result<(), Error> {
|
||||
if byte == b'\n' {
|
||||
self.write_byte(b'\r').ok();
|
||||
}
|
||||
|
||||
while !self
|
||||
.AUX_MU_LSR_REG
|
||||
.matches_all(AUX_MU_LSR_REG::TX_EMPTY::SET)
|
||||
{
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
self.AUX_MU_IO_REG.set(byte as u32);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_bytes(&self, bytes: &[u8]) -> Result<(), Error> {
|
||||
for &byte in bytes {
|
||||
self.write_byte(byte)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TerminalOutput for Inner {
|
||||
fn write(&self, byte: u8) -> Result<(), Error> {
|
||||
self.regs.lock().write_byte(byte)
|
||||
}
|
||||
|
||||
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
|
||||
self.regs.lock().write_bytes(bytes)?;
|
||||
Ok(bytes.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugSink for Bcm2835AuxUart {
|
||||
fn putc(&self, c: u8) -> Result<(), Error> {
|
||||
self.inner.get().putc_to_output(c)
|
||||
}
|
||||
|
||||
fn puts(&self, s: &str) -> Result<(), Error> {
|
||||
self.inner.get().write_to_output(s.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn supports_control_sequences(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for Bcm2835AuxUart {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let inner = self.inner.get();
|
||||
|
||||
let (status, byte) = {
|
||||
let regs = inner.output().regs.lock();
|
||||
|
||||
// Reset IRQ
|
||||
regs.AUX_MU_IIR_REG.modify(AUX_MU_IIR_REG::IID::SET);
|
||||
|
||||
let byte = regs.AUX_MU_IO_REG.get() as u8;
|
||||
let status = regs
|
||||
.AUX_MU_IIR_REG
|
||||
.matches_all(AUX_MU_IIR_REG::PENDING::SET);
|
||||
|
||||
(status, byte)
|
||||
};
|
||||
|
||||
if status {
|
||||
inner.write_to_input(byte);
|
||||
}
|
||||
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for Bcm2835AuxUart {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
// TODO initialize pinctrl
|
||||
|
||||
self.clock.enable()?;
|
||||
|
||||
let regs = unsafe { DeviceMemoryIo::map(self.base, Default::default()) }?;
|
||||
let config = TerminalOptions {
|
||||
output: TerminalOutputOptions::NL_TO_CRNL,
|
||||
..Default::default()
|
||||
};
|
||||
let output = Inner {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
};
|
||||
let input = TerminalInput::with_capacity(64)?;
|
||||
|
||||
let inner = self
|
||||
.inner
|
||||
.init(Arc::new(Terminal::from_parts(config, input, output)));
|
||||
|
||||
DEVICE_REGISTRY
|
||||
.serial_terminal
|
||||
.register(inner.clone(), Some(self.clone()))
|
||||
.ok();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
self.irq.register(self.clone())?;
|
||||
self.irq.enable()?;
|
||||
|
||||
let inner = self.inner.get().output();
|
||||
let regs = inner.regs.lock();
|
||||
|
||||
regs.AUX_MU_IER_REG
|
||||
.modify(AUX_MU_IER_REG::RX_IRQ::SET + AUX_MU_IER_REG::TX_IRQ::CLEAR);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"bcm2835 mini-UART"
|
||||
}
|
||||
}
|
||||
|
||||
// TODO handle pinctrl
|
||||
device_tree_driver! {
|
||||
compatible: ["brcm,bcm2835-aux-uart"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
let irq = node.interrupt(0)?;
|
||||
let clock = node.clock(0)?;
|
||||
|
||||
Some(Arc::new(Bcm2835AuxUart {
|
||||
base,
|
||||
irq,
|
||||
clock,
|
||||
inner: OneTimeInit::new(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockController, ClockHandle, Hertz},
|
||||
device::{Device, DeviceInitContext},
|
||||
};
|
||||
use device_tree::{
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{DeviceTreeClockController, Node, ProbeContext, device_tree_driver},
|
||||
};
|
||||
use libk::error::Error;
|
||||
|
||||
use crate::mbox::{Bcm2835Mbox, Bcm2835VcClock};
|
||||
|
||||
const CLK_VPU: u32 = 0x14;
|
||||
|
||||
struct Cprman {
|
||||
clk_osc: ClockHandle,
|
||||
mbox: Arc<Bcm2835Mbox>,
|
||||
}
|
||||
|
||||
impl Device for Cprman {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
let _ = &self.clk_osc;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"bcm2711-cprman"
|
||||
}
|
||||
}
|
||||
|
||||
impl ClockController for Cprman {
|
||||
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
|
||||
let vc_clock = match clock {
|
||||
Some(CLK_VPU) => Bcm2835VcClock::Core,
|
||||
Some(n) => todo!("clock_rate({n:#02x})"),
|
||||
None => return Err(Error::InvalidArgument),
|
||||
};
|
||||
|
||||
let rate = self.mbox.vc_clock_rate(vc_clock)?;
|
||||
|
||||
Ok(rate)
|
||||
}
|
||||
|
||||
fn set_clock_rate(&self, clock: Option<u32>, rate: Hertz) -> Result<Hertz, Error> {
|
||||
let _ = clock;
|
||||
let _ = rate;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||
let _ = clock;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||
let _ = clock;
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceTreeClockController for Cprman {
|
||||
fn map_clock(self: Arc<Self>, property: &TProp, offset: usize) -> Option<(ClockHandle, usize)> {
|
||||
let clock = property.read_cell(offset, 1)? as u32;
|
||||
Some((
|
||||
ClockHandle {
|
||||
parent: self.clone(),
|
||||
clock: Some(clock),
|
||||
},
|
||||
1,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["brcm,bcm2711-cprman"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let _base = node.map_base(context, 0)?;
|
||||
let mbox = Node::by_compatible("brcm,bcm2835-mbox", true).unwrap().device().unwrap();
|
||||
let mbox = Arc::downcast::<Bcm2835Mbox>(mbox.as_any()).unwrap();
|
||||
let clk_osc = node.clock(0)?;
|
||||
|
||||
let cprman = Arc::new(Cprman {
|
||||
clk_osc,
|
||||
mbox,
|
||||
});
|
||||
|
||||
node.make_clock_controller(cprman.clone());
|
||||
Some(cprman)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@ use device_api::{
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::{
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext, device_tree_driver,
|
||||
util::generic_gpio_config,
|
||||
device_tree_driver, util::generic_gpio_config, DeviceTreeGpioPins, DeviceTreePinController,
|
||||
Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockHandle, Hertz},
|
||||
device::{Device, DeviceInitContext},
|
||||
i2c::{I2CAddress, I2CController},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
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::{OneTimeInit, sync::spin_rwlock::IrqSafeRwLock};
|
||||
use tock_registers::{
|
||||
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 I2C {
|
||||
name: &'static str,
|
||||
clock_frequency: Option<Hertz>,
|
||||
irq: IrqHandle,
|
||||
clock: Option<ClockHandle>,
|
||||
regs: IrqSafeRwLock<DeviceMemoryIo<'static, Regs>>,
|
||||
index: OneTimeInit<u32>,
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
fn start_transfer(&self, name: &str, buflen: u16, address: I2CAddress, read: bool) {
|
||||
log::debug!(
|
||||
"{}: start address={}, read={}, len={}",
|
||||
name,
|
||||
address,
|
||||
read,
|
||||
buflen
|
||||
);
|
||||
|
||||
let address = address.as_8_bit().unwrap();
|
||||
let read = if read { C::READ::SET } else { C::READ::CLEAR };
|
||||
|
||||
self.S.write(S::ERR::SET + S::DONE::SET);
|
||||
self.DLEN.set(buflen as u32);
|
||||
self.C.modify(C::ST::CLEAR + C::I2CEN::CLEAR);
|
||||
self.A.set(address as u32);
|
||||
self.C.modify(read + C::ST::SET + C::I2CEN::SET);
|
||||
}
|
||||
|
||||
fn finish_transfer(&self, name: &str) -> Result<(), Error> {
|
||||
log::debug!("{}: finish transfer", name);
|
||||
let status = self.S.extract();
|
||||
self.C.set(0);
|
||||
if status.matches_all(S::ERR::SET) {
|
||||
self.S.write(S::DONE::SET + S::ERR::SET);
|
||||
return Err(Error::HostUnreachable);
|
||||
}
|
||||
if status.matches_all(S::DONE::SET) {
|
||||
self.S.write(S::DONE::SET);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_byte(&self, byte: u8) -> Result<bool, Error> {
|
||||
loop {
|
||||
let status = self.S.extract();
|
||||
if status.matches_all(S::ERR::SET) {
|
||||
self.C.write(C::CLEAR.val(1));
|
||||
self.S.write(S::ERR::SET + S::DONE::SET);
|
||||
// TODO better code
|
||||
return Err(Error::HostUnreachable);
|
||||
}
|
||||
if status.matches_all(S::DONE::SET) {
|
||||
self.C.set(0);
|
||||
self.S.write(S::DONE::SET);
|
||||
return Ok(false);
|
||||
}
|
||||
if status.matches_all(S::TXD::SET) {
|
||||
self.FIFO.set(byte as u32);
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
|
||||
fn read_byte(&self) -> Result<Option<u8>, Error> {
|
||||
loop {
|
||||
let status = self.S.extract();
|
||||
if status.matches_all(S::ERR::SET) {
|
||||
self.C.write(C::CLEAR.val(1));
|
||||
self.S.write(S::ERR::SET + S::DONE::SET);
|
||||
// TODO better code
|
||||
return Err(Error::HostUnreachable);
|
||||
}
|
||||
if status.matches_all(S::DONE::SET) {
|
||||
self.C.set(0);
|
||||
self.S.write(S::DONE::SET);
|
||||
return Ok(None);
|
||||
}
|
||||
if status.matches_all(S::RXD::SET) {
|
||||
let val = self.FIFO.get() as u8;
|
||||
return Ok(Some(val));
|
||||
}
|
||||
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
// TODO
|
||||
let _ = &self.irq;
|
||||
// self.irq.register(self.clone())?;
|
||||
// self.irq.enable()?;
|
||||
// let regs = self.regs.write();
|
||||
// regs.C.modify(C::INTD::SET);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for I2C {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn i2c_write(&self, address: I2CAddress, buffer: &[u8]) -> Result<usize, Error> {
|
||||
let buflen: u16 = buffer
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| Error::InvalidArgument)?;
|
||||
let regs = self.regs.write();
|
||||
// TODO DMA/interrupts
|
||||
regs.start_transfer(self.name, buflen, address, false);
|
||||
let mut bytes_written = 0;
|
||||
// let mut done = false;
|
||||
for &byte in buffer {
|
||||
if regs.write_byte(byte)? {
|
||||
bytes_written += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
regs.finish_transfer(self.name)?;
|
||||
Ok(bytes_written)
|
||||
}
|
||||
|
||||
fn i2c_read(&self, address: I2CAddress, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
let buflen: u16 = buffer
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| Error::InvalidArgument)?;
|
||||
let regs = self.regs.write();
|
||||
// TODO DMA/interrupts
|
||||
regs.start_transfer(self.name, buflen, address, true);
|
||||
let mut bytes_read = 0;
|
||||
// let mut done = false;
|
||||
for byte in buffer {
|
||||
if let Some(val) = regs.read_byte()? {
|
||||
*byte = val;
|
||||
bytes_read += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
regs.finish_transfer(self.name)?;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
});
|
||||
|
||||
node.make_i2c_controller(i2c.clone());
|
||||
|
||||
Some(i2c)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,6 @@
|
||||
extern crate alloc;
|
||||
|
||||
mod aux;
|
||||
// mod aux_uart;
|
||||
mod cprman;
|
||||
mod aux_uart;
|
||||
mod gpio;
|
||||
mod i2c;
|
||||
mod mbox;
|
||||
mod spi;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use core::{any::Any, cell::UnsafeCell, mem::MaybeUninit};
|
||||
use core::{cell::UnsafeCell, mem::MaybeUninit};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::Hertz,
|
||||
device::{Device, DeviceInitContext},
|
||||
};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use device_api::device::{Device, DeviceInitContext};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use kernel_arch_aarch64::mem::table::L3;
|
||||
use libk::device::{
|
||||
display::{
|
||||
@@ -14,10 +11,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::{
|
||||
@@ -64,13 +61,7 @@ register_structs! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
#[repr(u32)]
|
||||
pub(crate) enum Bcm2835VcClock {
|
||||
Core = 4,
|
||||
}
|
||||
|
||||
pub(crate) struct Bcm2835Mbox {
|
||||
struct Bcm2835Mbox {
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
}
|
||||
|
||||
@@ -94,20 +85,13 @@ 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::debug!("bcm2835-mbox: mbox call buffer={buffer:#x}, channel={channel}");
|
||||
log::info!("bcm2835-mbox: mbox call buffer={buffer:#x}, channel={channel}");
|
||||
|
||||
let address = buffer
|
||||
.try_into_u32()
|
||||
@@ -141,31 +125,10 @@ impl Bcm2835Mbox {
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
pub fn configure_framebuffer(
|
||||
&self,
|
||||
mode_info: &DisplayMode,
|
||||
) -> Result<FramebufferResponse, Error> {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
struct FramebufferRequest {
|
||||
@@ -195,7 +158,7 @@ impl Bcm2835Mbox {
|
||||
}))?;
|
||||
|
||||
// TODO flush cache for buffer
|
||||
unsafe { self.call_raw(buffer.as_physical_address(), Self::CHANNEL_FRAMEBUFFER) }?;
|
||||
unsafe { self.call_raw(buffer.as_physical_address(), 0x01) }?;
|
||||
|
||||
let buffer = buffer.get_mut();
|
||||
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
use core::iter;
|
||||
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use device_api::{
|
||||
clock::{ClockHandle, Hertz},
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::IrqHandle,
|
||||
spi::SpiController,
|
||||
};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use libk::{device::manager::DEVICE_REGISTRY, error::Error};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use tock_registers::{
|
||||
interfaces::{Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::ReadWrite,
|
||||
};
|
||||
use yggdrasil_abi::io::device::spi::{SpiClockPhase, SpiClockPolarity, SpiConfig};
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
CS [
|
||||
LEN_LONG OFFSET(25) NUMBITS(1) [],
|
||||
DMA_LEN OFFSET(24) NUMBITS(1) [],
|
||||
CSPOL2 OFFSET(23) NUMBITS(1) [],
|
||||
CSPOL1 OFFSET(22) NUMBITS(1) [],
|
||||
CSPOL0 OFFSET(21) NUMBITS(1) [],
|
||||
RXF OFFSET(20) NUMBITS(1) [],
|
||||
RXR OFFSET(19) NUMBITS(1) [],
|
||||
TXD OFFSET(18) NUMBITS(1) [],
|
||||
RXD OFFSET(17) NUMBITS(1) [],
|
||||
DONE OFFSET(16) NUMBITS(1) [],
|
||||
LEN OFFSET(13) NUMBITS(1) [],
|
||||
REN OFFSET(12) NUMBITS(1) [],
|
||||
ADCS OFFSET(11) NUMBITS(1) [],
|
||||
INTR OFFSET(10) NUMBITS(1) [],
|
||||
INTD OFFSET(9) NUMBITS(1) [],
|
||||
DMAEN OFFSET(8) NUMBITS(1) [],
|
||||
TA OFFSET(7) NUMBITS(1) [],
|
||||
CSPOL OFFSET(6) NUMBITS(1) [],
|
||||
CLEAR OFFSET(4) NUMBITS(2) [],
|
||||
CPOL OFFSET(3) NUMBITS(1) [
|
||||
IdleLow = 0,
|
||||
IdleHigh = 1
|
||||
],
|
||||
CPHA OFFSET(2) NUMBITS(1) [
|
||||
CaptureOnFirstTransition = 0,
|
||||
CaptureOnSecondTransition = 1
|
||||
],
|
||||
CS OFFSET(0) NUMBITS(2) [],
|
||||
]
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
Regs {
|
||||
(0x00 => CS: ReadWrite<u32, CS::Register>),
|
||||
(0x04 => FIFO: ReadWrite<u32>),
|
||||
(0x08 => CLK: ReadWrite<u32>),
|
||||
(0x0C => DLEN: ReadWrite<u32>),
|
||||
(0x10 => LTOH: ReadWrite<u32>),
|
||||
(0x14 => DC: ReadWrite<u32>),
|
||||
(0x18 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Spi {
|
||||
name: &'static str,
|
||||
clock: ClockHandle,
|
||||
irq: IrqHandle,
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
}
|
||||
|
||||
impl Device for Spi {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
let _ = &self.irq;
|
||||
let regs = self.regs.lock();
|
||||
regs.CS.set(0);
|
||||
|
||||
DEVICE_REGISTRY.spi.register_bus(self.clone()).ok();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
fn start_transfer(&self, core_clock: Hertz, config: &SpiConfig) -> Result<(), Error> {
|
||||
let want_clock = Hertz::from(config.frequency.unwrap_or(100000));
|
||||
let divider = Hertz::divider(core_clock, want_clock).ok_or(Error::InvalidArgument)?;
|
||||
let divider: u16 = divider.try_into().map_err(|_| Error::InvalidArgument)?;
|
||||
let divider = divider.wrapping_add(1) & !1;
|
||||
|
||||
let mut cs = CS::REN::SET + CS::TA::SET;
|
||||
if let Some(cs_index) = config.chip_select_index
|
||||
&& cs_index < 3
|
||||
{
|
||||
cs += CS::CS.val(cs_index);
|
||||
}
|
||||
if let Some(cpol) = config.clock_polarity {
|
||||
match cpol {
|
||||
SpiClockPolarity::IdleLow => cs += CS::CPOL::IdleLow,
|
||||
SpiClockPolarity::IdleHigh => cs += CS::CPOL::IdleHigh,
|
||||
}
|
||||
}
|
||||
if let Some(cpha) = config.clock_phase {
|
||||
match cpha {
|
||||
SpiClockPhase::CaptureOnFirstTransition => cs += CS::CPHA::CaptureOnFirstTransition,
|
||||
SpiClockPhase::CaptureOnSecondTransition => {
|
||||
cs += CS::CPHA::CaptureOnSecondTransition
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.CLK.set(divider as u32);
|
||||
self.CS.write(cs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tx_rx_byte(&self, tx: u8) -> Result<Option<u8>, Error> {
|
||||
// Wait for tx
|
||||
loop {
|
||||
let status = self.CS.extract();
|
||||
if status.matches_all(CS::TXD::SET) {
|
||||
break;
|
||||
}
|
||||
if status.matches_all(CS::DONE::SET) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
self.FIFO.set(tx as u32);
|
||||
// Wait for rx
|
||||
loop {
|
||||
let status = self.CS.extract();
|
||||
if status.matches_all(CS::RXD::SET) {
|
||||
break;
|
||||
}
|
||||
if status.matches_all(CS::DONE::SET) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
Ok(Some(self.FIFO.get() as u8))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl SpiController for Spi {
|
||||
async fn spi_transfer(
|
||||
&self,
|
||||
tx_buffer: &[u8],
|
||||
rx_buffer: &mut [u8],
|
||||
config: &SpiConfig,
|
||||
) -> Result<usize, Error> {
|
||||
// TODO interrupt/DMA
|
||||
log::debug!("{}: spi_transfer {} bytes", self.name, rx_buffer.len());
|
||||
let core_clock = self.clock.rate()?;
|
||||
let regs = self.regs.lock();
|
||||
regs.start_transfer(core_clock, config)?;
|
||||
|
||||
let mut len = 0;
|
||||
for (&tx, rx) in iter::zip(tx_buffer, rx_buffer) {
|
||||
match regs.tx_rx_byte(tx)? {
|
||||
Some(b) => {
|
||||
*rx = b;
|
||||
len += 1;
|
||||
}
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["brcm,bcm2835-spi"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let name = node.name().unwrap_or("bcm2835-spi");
|
||||
let base = node.map_base(context, 0)?;
|
||||
let irq = node.interrupt(0)?;
|
||||
let clock = node.clock(0)?;
|
||||
|
||||
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
|
||||
|
||||
let spi = Arc::new(Spi {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
name,
|
||||
clock,
|
||||
irq
|
||||
});
|
||||
|
||||
Some(spi)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,11 @@ use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
};
|
||||
use device_tree::{
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeClockController, DeviceTreeResetController, DeviceTreeSyscon, Node, ProbeContext,
|
||||
device_tree_driver, lookup_phandle,
|
||||
device_tree_driver, lookup_phandle, DeviceTreeClockController, DeviceTreeResetController,
|
||||
DeviceTreeSyscon, Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
@@ -57,16 +57,6 @@ 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;
|
||||
@@ -181,7 +171,7 @@ trait ClockDefinition {
|
||||
const CLOCKS: &'static [Option<(&'static str, ClockDef)>];
|
||||
}
|
||||
|
||||
const SYSCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
|
||||
const SYSCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
|
||||
use ClockDef::*;
|
||||
|
||||
let mut t = [const { None }; SYSCRG_CLOCK_COUNT];
|
||||
@@ -236,21 +226,11 @@ const SYSCRG_CLOCKS: &[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: &[Option<(&'static str, ClockDef)>] = &const {
|
||||
const AONCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
|
||||
use ClockDef::*;
|
||||
|
||||
let mut t = [const { None }; AONCRG_CLOCK_COUNT];
|
||||
@@ -282,7 +262,7 @@ const AONCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
|
||||
t
|
||||
};
|
||||
|
||||
const STGCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
|
||||
const STGCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
|
||||
use ClockDef::*;
|
||||
|
||||
let mut t = [const { None }; STGCRG_CLOCK_COUNT];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![allow(unsafe_op_in_unsafe_fn, clippy::eq_op, clippy::erasing_op)]
|
||||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
@@ -8,14 +8,15 @@ use device_api::{
|
||||
},
|
||||
};
|
||||
use device_tree::{
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext, device_tree_driver,
|
||||
util::{GenericPinctrlBiasConfig, GenericPinctrlConfig, generic_gpio_config},
|
||||
device_tree_driver,
|
||||
util::{generic_gpio_config, GenericPinctrlBiasConfig, GenericPinctrlConfig},
|
||||
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
|
||||
use libk_util::{OneTimeInit, bit::BitField, sync::IrqSafeSpinlock};
|
||||
use libk_util::{bit::BitField, sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::device::{Device, DeviceInitContext};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
error::Error,
|
||||
fs::sysfs::{self, nodes::SysfsRtcNode},
|
||||
|
||||
@@ -2,22 +2,20 @@ use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{
|
||||
ExternalInterruptController, InterruptHandler, Irq, IrqHandle, IrqOptions, IrqVector,
|
||||
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq,
|
||||
IrqHandle, IrqOptions, IrqVector,
|
||||
},
|
||||
};
|
||||
use device_tree::{
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{
|
||||
DeviceTreeInterruptController, Node, ProbeContext, device_tree_driver, lookup_phandle,
|
||||
device_tree_driver, lookup_phandle, DeviceTreeInterruptController, Node, ProbeContext,
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
};
|
||||
use kernel_arch_riscv64::boot_hart_id;
|
||||
use libk::{
|
||||
arch::Cpu,
|
||||
device::{interrupt::FixedInterruptTable, register_external_interrupt_controller},
|
||||
};
|
||||
use libk::{arch::Cpu, device::register_external_interrupt_controller};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{OneTimeInit, sync::spin_rwlock::IrqSafeRwLock};
|
||||
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
|
||||
use tock_registers::{
|
||||
interfaces::{Readable, Writeable},
|
||||
register_structs,
|
||||
@@ -79,7 +77,8 @@ register_structs! {
|
||||
struct Context {
|
||||
enable: IrqSafeRwLock<DeviceMemoryIo<'static, ContextEnableRegs>>,
|
||||
control: IrqSafeRwLock<DeviceMemoryIo<'static, ContextControlRegs>>,
|
||||
table: FixedInterruptTable,
|
||||
// TODO scale the table depending on effective MAX_IRQS value
|
||||
table: IrqSafeRwLock<FixedInterruptTable<128>>,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
@@ -164,13 +163,13 @@ impl ExternalInterruptController for Plic {
|
||||
.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()
|
||||
);
|
||||
context.table.insert(irq as usize, handler);
|
||||
|
||||
table.insert(irq as usize, handler)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -184,7 +183,7 @@ 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();
|
||||
@@ -193,7 +192,9 @@ impl ExternalInterruptController for Plic {
|
||||
}
|
||||
let vector = IrqVector::Irq(Irq::External(irq));
|
||||
|
||||
if !context.table.handle_irq_line(irq as usize, vector) {
|
||||
if let Some(handler) = table.handler(irq as usize) {
|
||||
handler.clone().handle_irq(vector);
|
||||
} else {
|
||||
log::warn!("plic: no handler for IRQ #{irq}");
|
||||
}
|
||||
|
||||
@@ -241,7 +242,7 @@ impl Device for Plic {
|
||||
context.context.init(Context {
|
||||
enable: IrqSafeRwLock::new(enable),
|
||||
control: IrqSafeRwLock::new(control),
|
||||
table: FixedInterruptTable::new(MAX_IRQS), // table: IrqSafeRwLock::new(FixedInterruptTable::new()),
|
||||
table: IrqSafeRwLock::new(FixedInterruptTable::new()),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "ygg_driver_pci"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
authors = ["Mark Poliakov <mark@alnyan.me>"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -498,7 +498,7 @@ impl MsiXVectorTableAccess<'_> {
|
||||
|
||||
impl MsiXVectorTable<'_> {
|
||||
unsafe fn memory_from_raw_parts(base: PhysicalAddress, len: usize) -> Result<Self, Error> {
|
||||
let vectors = unsafe { DeviceMemoryIoMut::map_slice(base, len, Default::default()) }?;
|
||||
let vectors = DeviceMemoryIoMut::map_slice(base, len, Default::default())?;
|
||||
Ok(Self {
|
||||
access: MsiXVectorTableAccess::Memory(vectors),
|
||||
len,
|
||||
|
||||
@@ -9,13 +9,13 @@ use device_api::{
|
||||
},
|
||||
};
|
||||
use libk::device::external_interrupt_controller;
|
||||
use libk_util::{OneTimeInit, sync::spin_rwlock::IrqSafeRwLock};
|
||||
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
PciAddress, PciCommandRegister, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo,
|
||||
capability::{MsiCapability, MsiXCapability, MsiXVectorTable},
|
||||
driver::PciDriver,
|
||||
PciAddress, PciCommandRegister, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo,
|
||||
};
|
||||
|
||||
/// Describes a PCI device
|
||||
@@ -152,21 +152,22 @@ impl PciDeviceInfo {
|
||||
let mut result = None;
|
||||
if want_msix
|
||||
&& let Some(mut msix) = self.config_space.capability::<MsiXCapability>()
|
||||
&& let Ok(mut vt) = msix.vector_table()
|
||||
{
|
||||
if let Some(mut msi) = self.config_space.capability::<MsiCapability>() {
|
||||
msi.set_enabled(false);
|
||||
if let Ok(mut vt) = msix.vector_table() {
|
||||
if let Some(mut msi) = self.config_space.capability::<MsiCapability>() {
|
||||
msi.set_enabled(false);
|
||||
}
|
||||
|
||||
vt.mask_all();
|
||||
|
||||
msix.set_function_mask(false);
|
||||
msix.set_enabled(true);
|
||||
|
||||
result = Some(ConfiguredInterruptMode::MsiX(
|
||||
msi_route.controller.clone(),
|
||||
vt,
|
||||
));
|
||||
}
|
||||
|
||||
vt.mask_all();
|
||||
|
||||
msix.set_function_mask(false);
|
||||
msix.set_enabled(true);
|
||||
|
||||
result = Some(ConfiguredInterruptMode::MsiX(
|
||||
msi_route.controller.clone(),
|
||||
vt,
|
||||
));
|
||||
}
|
||||
|
||||
// Fall back to MSI if MSI-x is not available or not requested
|
||||
|
||||
@@ -5,8 +5,8 @@ use device_api::interrupt::MessageInterruptController;
|
||||
use libk::error::Error;
|
||||
|
||||
use crate::{
|
||||
PciAddress,
|
||||
device::{PciInterrupt, PciInterruptRoute, PciMsiRoute},
|
||||
PciAddress,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! PCI/PCIe bus interfaces
|
||||
#![no_std]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(let_chains, decl_macro)]
|
||||
#![allow(clippy::missing_transmute_annotations, clippy::identity_op)]
|
||||
|
||||
extern crate alloc;
|
||||
@@ -20,7 +20,7 @@ use libk::{
|
||||
fs::sysfs::{self, object::KObject},
|
||||
};
|
||||
use libk_mm::address::PhysicalAddress;
|
||||
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use space::legacy;
|
||||
use yggdrasil_abi::{error::Error, primitive_enum};
|
||||
|
||||
@@ -36,9 +36,9 @@ mod nodes;
|
||||
mod space;
|
||||
|
||||
pub use space::{
|
||||
PciConfigSpace, PciConfigurationSpace,
|
||||
ecam::PciEcam,
|
||||
legacy::{LegacyPciAccess, PciLegacyConfigurationSpace},
|
||||
PciConfigSpace, PciConfigurationSpace,
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
|
||||
@@ -17,7 +17,7 @@ pub macro pci_driver(
|
||||
matches: [$($kind:ident $match:tt),+ $(,)?],
|
||||
driver: $driver:tt
|
||||
) {
|
||||
#[unsafe(link_section = ".init_array")]
|
||||
#[link_section = ".init_array"]
|
||||
#[used]
|
||||
static __REGISTER_FN: extern "C" fn() = __register_fn;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use libk::{
|
||||
};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
|
||||
use crate::{PciBaseAddress, PciCapabilityId, PciConfigurationSpace, device::PciBusDevice};
|
||||
use crate::{device::PciBusDevice, PciBaseAddress, PciCapabilityId, PciConfigurationSpace};
|
||||
|
||||
pub(crate) fn make_sysfs_object(
|
||||
device: PciBusDevice,
|
||||
|
||||
@@ -32,7 +32,7 @@ impl PciEcam {
|
||||
/// regions. The address must be aligned to a 4KiB boundary and be valid for accesses within a
|
||||
/// 4KiB-sized range.
|
||||
pub unsafe fn map(phys_addr: PhysicalAddress) -> Result<Self, Error> {
|
||||
let mapping = unsafe { DeviceMemoryMapping::map(phys_addr, 0x1000, Default::default()) }?;
|
||||
let mapping = DeviceMemoryMapping::map(phys_addr, 0x1000, Default::default())?;
|
||||
Ok(Self { mapping })
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ impl PciEcam {
|
||||
+ address.function as usize)
|
||||
* 0x1000,
|
||||
);
|
||||
let this = unsafe { Self::map(phys_addr) }?;
|
||||
let this = Self::map(phys_addr)?;
|
||||
|
||||
Ok(if this.is_valid() { Some(this) } else { None })
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use alloc::sync::Arc;
|
||||
use legacy::PciLegacyConfigurationSpace;
|
||||
|
||||
use super::{PciAddress, PciBaseAddress, PciCapability, PciCapabilityId, PciEcam};
|
||||
use crate::{PciCommandRegister, PciStatusRegister, device::PciInterruptPin};
|
||||
use crate::{device::PciInterruptPin, PciCommandRegister, PciStatusRegister};
|
||||
|
||||
pub(super) mod ecam;
|
||||
pub(super) mod legacy;
|
||||
@@ -26,7 +26,9 @@ macro_rules! pci_config_field_setter {
|
||||
$self.write_u32($offset, $value)
|
||||
};
|
||||
|
||||
($self:ident, u16, $offset:expr, $value:expr) => {{ $self.write_u16($offset, $value) }};
|
||||
($self:ident, u16, $offset:expr, $value:expr) => {{
|
||||
$self.write_u16($offset, $value)
|
||||
}};
|
||||
|
||||
($self:ident, u8, $offset:expr, $value:expr) => {
|
||||
$self.write_u8($offset, $value)
|
||||
@@ -220,7 +222,11 @@ pub trait PciConfigurationSpace {
|
||||
|
||||
fn interrupt_line(&self) -> Option<u8> {
|
||||
let value = self.read_u8(0x3C);
|
||||
if value < 16 { Some(value) } else { None }
|
||||
if value < 16 {
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
@@ -242,7 +248,7 @@ pub trait PciConfigurationSpace {
|
||||
PciBaseAddress::Memory32(_) => PciBaseAddress::Memory32(0xFFFFFFF0),
|
||||
PciBaseAddress::Memory64(_) => PciBaseAddress::Memory64(0xFFFFFFFFFFFFFFF0),
|
||||
};
|
||||
unsafe { self.set_bar(index, mask_value) };
|
||||
self.set_bar(index, mask_value);
|
||||
let new_value = self.bar(index).unwrap();
|
||||
|
||||
let size = match new_value {
|
||||
@@ -252,7 +258,7 @@ pub trait PciConfigurationSpace {
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
unsafe { self.set_bar(index, orig_value) };
|
||||
self.set_bar(index, orig_value);
|
||||
self.set_command(cmd);
|
||||
|
||||
size
|
||||
@@ -296,7 +302,7 @@ pub trait PciConfigurationSpace {
|
||||
fn bar(&self, index: usize) -> Option<PciBaseAddress> {
|
||||
assert!(index < 6);
|
||||
|
||||
if index.is_multiple_of(2) {
|
||||
if index % 2 == 0 {
|
||||
let w0 = self.read_u32(0x10 + index * 4);
|
||||
|
||||
match w0 & 1 {
|
||||
|
||||
@@ -6,12 +6,13 @@ use libk_util::{queue::UnboundedMpmcQueue, sync::spin_rwlock::IrqSafeRwLock};
|
||||
use crate::{
|
||||
class_driver,
|
||||
device::{UsbBusAddress, UsbDeviceAccess},
|
||||
host::UsbHostController,
|
||||
UsbHostController,
|
||||
};
|
||||
|
||||
pub struct UsbBusManager {
|
||||
busses: IrqSafeRwLock<BTreeMap<u16, Arc<dyn UsbHostController>>>,
|
||||
devices: IrqSafeRwLock<BTreeMap<UsbBusAddress, Arc<UsbDeviceAccess>>>,
|
||||
|
||||
last_bus_address: AtomicU16,
|
||||
}
|
||||
|
||||
@@ -32,9 +33,9 @@ impl UsbBusManager {
|
||||
QUEUE.push_back(device);
|
||||
}
|
||||
|
||||
pub async fn detach_device(address: UsbBusAddress) {
|
||||
pub fn detach_device(address: UsbBusAddress) {
|
||||
if let Some(device) = BUS_MANAGER.devices.write().remove(&address) {
|
||||
device.handle_detach().await;
|
||||
device.handle_detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,26 +45,20 @@ pub async fn bus_handler() {
|
||||
|
||||
loop {
|
||||
let new_device = QUEUE.pop_front().await;
|
||||
let id_vendor = new_device.device_descriptor.id_vendor;
|
||||
let id_product = new_device.device_descriptor.id_product;
|
||||
log::info!(
|
||||
"{} ({}): {:?}-speed USB device connected: {:?} {:?} ({:04x}:{:04x})",
|
||||
new_device.bus_address(),
|
||||
new_device.port_string(),
|
||||
"New {:?}-speed USB device connected: {}",
|
||||
new_device.speed(),
|
||||
new_device.vendor_str,
|
||||
new_device.product_str,
|
||||
id_vendor,
|
||||
id_product
|
||||
new_device.bus_address()
|
||||
);
|
||||
|
||||
class_driver::spawn_driver(new_device).await;
|
||||
class_driver::spawn_driver(new_device).await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
static BUS_MANAGER: UsbBusManager = UsbBusManager {
|
||||
busses: IrqSafeRwLock::new(BTreeMap::new()),
|
||||
devices: IrqSafeRwLock::new(BTreeMap::new()),
|
||||
|
||||
last_bus_address: AtomicU16::new(0),
|
||||
};
|
||||
static QUEUE: UnboundedMpmcQueue<Arc<UsbDeviceAccess>> = UnboundedMpmcQueue::new();
|
||||
|
||||
+21
-89
@@ -2,12 +2,13 @@ use core::mem::MaybeUninit;
|
||||
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use yggdrasil_abi::io::{KeyboardKey, KeyboardKeyEvent, MouseEvent};
|
||||
use yggdrasil_abi::io::{KeyboardKey, KeyboardKeyEvent};
|
||||
|
||||
use crate::{class_driver::UsbInterfaceDriver, device::UsbInterfaceAccess, error::UsbError};
|
||||
use crate::{device::UsbDeviceAccess, error::UsbError, info::UsbDeviceClass};
|
||||
|
||||
use super::{UsbClassInfo, UsbDriver};
|
||||
|
||||
pub struct UsbHidKeyboardDriver;
|
||||
pub struct UsbHidMouseDriver;
|
||||
|
||||
const MODIFIER_MAP: &[KeyboardKey] = &[
|
||||
KeyboardKey::LControl,
|
||||
@@ -53,20 +54,11 @@ impl KeyboardState {
|
||||
54 => KeyboardKey::Char(b','),
|
||||
55 => KeyboardKey::Char(b'.'),
|
||||
56 => KeyboardKey::Char(b'/'),
|
||||
|
||||
58..=69 => KeyboardKey::F(k - 58),
|
||||
73 => KeyboardKey::Insert,
|
||||
74 => KeyboardKey::Home,
|
||||
75 => KeyboardKey::PageUp,
|
||||
76 => KeyboardKey::Delete,
|
||||
77 => KeyboardKey::End,
|
||||
78 => KeyboardKey::PageDown,
|
||||
79 => KeyboardKey::Right,
|
||||
80 => KeyboardKey::Left,
|
||||
81 => KeyboardKey::Down,
|
||||
82 => KeyboardKey::Up,
|
||||
|
||||
_ => {
|
||||
log::warn!("Unknown key: {}", k);
|
||||
log::debug!("Unknown key: {}", k);
|
||||
KeyboardKey::Unknown
|
||||
}
|
||||
}
|
||||
@@ -133,25 +125,14 @@ impl KeyboardState {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UsbInterfaceDriver for UsbHidKeyboardDriver {
|
||||
async fn run(self: Arc<Self>, interface: UsbInterfaceAccess) -> Result<(), UsbError> {
|
||||
log::info!("{}: HID keyboard", interface.address());
|
||||
impl UsbDriver for UsbHidKeyboardDriver {
|
||||
async fn run(self: Arc<Self>, device: Arc<UsbDeviceAccess>) -> Result<(), UsbError> {
|
||||
// TODO not sure whether to use boot protocol (easy) or GetReport
|
||||
let config = device.select_configuration(|_| true).await?.unwrap();
|
||||
|
||||
let endpoint_infos = interface.endpoints();
|
||||
if endpoint_infos.is_empty() {
|
||||
log::warn!(
|
||||
"{}: no available endpoints in interface description",
|
||||
interface.address()
|
||||
);
|
||||
return Err(UsbError::InvalidConfiguration);
|
||||
}
|
||||
|
||||
let pipe = interface
|
||||
.device()
|
||||
.open_interrupt_in_pipe(
|
||||
endpoint_infos[0].number,
|
||||
endpoint_infos[0].max_packet_size as _,
|
||||
)
|
||||
log::info!("Setup HID keyboard");
|
||||
let pipe = device
|
||||
.open_interrupt_in_pipe(1, config.endpoints[0].max_packet_size as u16)
|
||||
.await?;
|
||||
|
||||
let mut buffer = [0; 8];
|
||||
@@ -175,7 +156,7 @@ impl UsbInterfaceDriver for UsbHidKeyboardDriver {
|
||||
|
||||
for &event in events {
|
||||
log::trace!("Generic Keyboard: {:?}", event);
|
||||
ygg_driver_input::send_keyboard_event(event);
|
||||
ygg_driver_input::send_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,61 +165,12 @@ impl UsbInterfaceDriver for UsbHidKeyboardDriver {
|
||||
"USB HID Keyboard"
|
||||
}
|
||||
|
||||
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool {
|
||||
class == 0x03 && subclass == 0x01 && protocol == 0x01
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UsbInterfaceDriver for UsbHidMouseDriver {
|
||||
async fn run(self: Arc<Self>, interface: UsbInterfaceAccess) -> Result<(), UsbError> {
|
||||
log::info!("{}: HID mouse", interface.address());
|
||||
|
||||
let endpoint_infos = interface.endpoints();
|
||||
if endpoint_infos.is_empty() {
|
||||
log::warn!(
|
||||
"{}: no available endpoints in interface description",
|
||||
interface.address()
|
||||
);
|
||||
return Err(UsbError::InvalidConfiguration);
|
||||
}
|
||||
|
||||
let pipe = interface
|
||||
.device()
|
||||
.open_interrupt_in_pipe(
|
||||
endpoint_infos[0].number,
|
||||
endpoint_infos[0].max_packet_size as _,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut buffer = [0; 8];
|
||||
|
||||
loop {
|
||||
let len = pipe.read(&mut buffer).await?;
|
||||
if len < 4 {
|
||||
continue;
|
||||
}
|
||||
let data = &buffer[..len];
|
||||
|
||||
let buttons = data[0];
|
||||
let dx = data[1] as i8;
|
||||
let dy = data[2] as i8;
|
||||
|
||||
log::trace!("mouse {dx:+},{dy:+} {buttons:08b}");
|
||||
ygg_driver_input::send_mouse_event(MouseEvent {
|
||||
dx,
|
||||
dy,
|
||||
buttons,
|
||||
unused: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"USB HID Mouse"
|
||||
}
|
||||
|
||||
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool {
|
||||
class == 0x03 && subclass == 0x01 && protocol == 0x02
|
||||
fn probe(&self, class: &UsbClassInfo, _device: &UsbDeviceAccess) -> bool {
|
||||
log::info!(
|
||||
"class = {:?}, subclass = {:02x}",
|
||||
class.class,
|
||||
class.subclass
|
||||
);
|
||||
class.class == UsbDeviceClass::Hid && (class.subclass == 0x00 || class.subclass == 0x01)
|
||||
}
|
||||
}
|
||||
@@ -1,384 +0,0 @@
|
||||
use core::{mem::MaybeUninit, num::NonZeroU8, time::Duration};
|
||||
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use libk::{task::runtime, time::monotonic_time};
|
||||
use yggdrasil_abi::bitflags;
|
||||
|
||||
use crate::{
|
||||
class_driver::UsbDeviceDriver,
|
||||
descriptor::UsbHubDescriptorHeader,
|
||||
device::{UsbDeviceAccess, UsbSpeed},
|
||||
error::UsbError,
|
||||
pipe::control::ControlTransferSetup,
|
||||
};
|
||||
|
||||
pub struct UsbHubDriver;
|
||||
|
||||
const BM_REQUEST_TYPE_GET_HUB_DESCRIPTOR: u8 = 0b10100000;
|
||||
const BM_REQUEST_TYPE_GET_PORT_STATUS: u8 = 0b10100011;
|
||||
const BM_REQUEST_TYPE_PORT_FEATURE: u8 = 0b00100011;
|
||||
|
||||
const B_REQUEST_GET_STATUS: u8 = 0x00;
|
||||
const B_REQUEST_CLEAR_FEATURE: u8 = 0x01;
|
||||
const B_REQUEST_SET_FEATURE: u8 = 0x03;
|
||||
const B_REQUEST_GET_DESCRIPTOR: u8 = 0x06;
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u16)]
|
||||
pub enum PortFeatureSelector {
|
||||
PortConnection = 0,
|
||||
PortEnable = 1,
|
||||
PortSuspend = 2,
|
||||
PortOverCurrent = 3,
|
||||
PortReset = 4,
|
||||
PortPower = 8,
|
||||
PortLowSpeed = 9,
|
||||
CPortConnection = 16,
|
||||
CPortEnable = 17,
|
||||
CPortSuspend = 18,
|
||||
CPortOverCurrent = 19,
|
||||
CPortReset = 20,
|
||||
PortTest = 21,
|
||||
PortIndicator = 22,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct UsbHubPortStatus: u16 {
|
||||
const PORT_CONNECTION: bit 0;
|
||||
const PORT_ENABLE: bit 1;
|
||||
const PORT_SUSPEND: bit 2;
|
||||
const PORT_OVER_CURRENT: bit 3;
|
||||
const PORT_RESET: bit 4;
|
||||
const PORT_POWER: bit 8;
|
||||
const PORT_LOW_SPEED: bit 9;
|
||||
const PORT_HIGH_SPEED: bit 10;
|
||||
const PORT_TEST: bit 11;
|
||||
const PORT_INDICATOR: bit 12;
|
||||
}
|
||||
}
|
||||
bitflags! {
|
||||
pub struct UsbHubPortChange: u16 {
|
||||
const C_PORT_CONNECTION: bit 0;
|
||||
const C_PORT_ENABLE: bit 1;
|
||||
const C_PORT_SUSPEND: bit 2;
|
||||
const C_PORT_OVER_CURRENT: bit 3;
|
||||
const C_PORT_RESET: bit 4;
|
||||
}
|
||||
}
|
||||
|
||||
struct UsbHub {
|
||||
device: Arc<UsbDeviceAccess>,
|
||||
hub_descriptor: UsbHubDescriptorHeader,
|
||||
children: u64,
|
||||
// TODO extra info
|
||||
}
|
||||
|
||||
impl UsbHub {
|
||||
pub async fn setup(device: Arc<UsbDeviceAccess>) -> Result<Self, UsbError> {
|
||||
let control_pipe = device.control_pipe();
|
||||
let mut hub_descriptor = MaybeUninit::uninit();
|
||||
|
||||
let len = control_pipe
|
||||
.control_transfer_in(
|
||||
ControlTransferSetup {
|
||||
bm_request_type: BM_REQUEST_TYPE_GET_HUB_DESCRIPTOR,
|
||||
b_request: B_REQUEST_GET_DESCRIPTOR,
|
||||
w_value: 0,
|
||||
w_index: 0,
|
||||
w_length: size_of::<UsbHubDescriptorHeader>() as _,
|
||||
},
|
||||
hub_descriptor.as_bytes_mut(),
|
||||
)
|
||||
.await?;
|
||||
if len != size_of::<UsbHubDescriptorHeader>() {
|
||||
return Err(UsbError::TruncatedDescriptor(
|
||||
size_of::<UsbHubDescriptorHeader>(),
|
||||
len,
|
||||
));
|
||||
}
|
||||
let hub_descriptor: UsbHubDescriptorHeader = unsafe { hub_descriptor.assume_init() };
|
||||
if hub_descriptor.b_nr_ports < 1 {
|
||||
log::warn!(
|
||||
"{}: ignoring hub with zero downstream ports",
|
||||
device.device.bus_address()
|
||||
);
|
||||
return Err(UsbError::InvalidDescriptorField);
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"{}: setting up {:?}-speed hub, {} downstream ports",
|
||||
device.device.bus_address(),
|
||||
device.device.speed(),
|
||||
hub_descriptor.b_nr_ports
|
||||
);
|
||||
|
||||
device.configure_hub(&hub_descriptor).await?;
|
||||
|
||||
// TODO power on the ports?
|
||||
Ok(Self {
|
||||
device,
|
||||
hub_descriptor,
|
||||
children: 0,
|
||||
})
|
||||
}
|
||||
|
||||
async fn set_port_feature(
|
||||
&mut self,
|
||||
port: NonZeroU8,
|
||||
feature: PortFeatureSelector,
|
||||
) -> Result<(), UsbError> {
|
||||
self.device
|
||||
.control_pipe()
|
||||
.control_transfer(ControlTransferSetup {
|
||||
bm_request_type: BM_REQUEST_TYPE_PORT_FEATURE,
|
||||
b_request: B_REQUEST_SET_FEATURE,
|
||||
w_value: feature as _,
|
||||
w_index: port.get() as _,
|
||||
w_length: 0,
|
||||
})
|
||||
.await
|
||||
}
|
||||
async fn clear_port_feature(
|
||||
&mut self,
|
||||
port: NonZeroU8,
|
||||
feature: PortFeatureSelector,
|
||||
) -> Result<(), UsbError> {
|
||||
self.device
|
||||
.control_pipe()
|
||||
.control_transfer(ControlTransferSetup {
|
||||
bm_request_type: BM_REQUEST_TYPE_PORT_FEATURE,
|
||||
b_request: B_REQUEST_CLEAR_FEATURE,
|
||||
w_value: feature as _,
|
||||
w_index: port.get() as _,
|
||||
w_length: 0,
|
||||
})
|
||||
.await
|
||||
}
|
||||
async fn clear_port_changes(
|
||||
&mut self,
|
||||
port: NonZeroU8,
|
||||
change: UsbHubPortChange,
|
||||
) -> Result<(), UsbError> {
|
||||
if change.contains(UsbHubPortChange::C_PORT_RESET) {
|
||||
self.clear_port_feature(port, PortFeatureSelector::CPortReset)
|
||||
.await?;
|
||||
}
|
||||
if change.contains(UsbHubPortChange::C_PORT_CONNECTION) {
|
||||
self.clear_port_feature(port, PortFeatureSelector::CPortConnection)
|
||||
.await?;
|
||||
}
|
||||
if change.contains(UsbHubPortChange::C_PORT_ENABLE) {
|
||||
self.clear_port_feature(port, PortFeatureSelector::CPortEnable)
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_port_status(
|
||||
&mut self,
|
||||
port: NonZeroU8,
|
||||
) -> Result<(UsbHubPortStatus, UsbHubPortChange), UsbError> {
|
||||
let mut buffer = [MaybeUninit::uninit(); 2];
|
||||
let len = self
|
||||
.device
|
||||
.control_pipe()
|
||||
.control_transfer_in(
|
||||
ControlTransferSetup {
|
||||
bm_request_type: BM_REQUEST_TYPE_GET_PORT_STATUS,
|
||||
b_request: B_REQUEST_GET_STATUS,
|
||||
w_value: 0,
|
||||
w_index: port.get() as _,
|
||||
w_length: 4,
|
||||
},
|
||||
buffer.as_bytes_mut(),
|
||||
)
|
||||
.await?;
|
||||
if len != 4 {
|
||||
return Err(UsbError::TruncatedDescriptor(4, len));
|
||||
}
|
||||
let [w0, w1] = unsafe { MaybeUninit::array_assume_init(buffer) };
|
||||
let status = UsbHubPortStatus(w0);
|
||||
let change = UsbHubPortChange(w1);
|
||||
Ok((status, change))
|
||||
}
|
||||
|
||||
async fn reset_port(&mut self, port: NonZeroU8) -> Result<UsbHubPortStatus, UsbError> {
|
||||
self.set_port_feature(port, PortFeatureSelector::PortReset)
|
||||
.await?;
|
||||
|
||||
// Wait for reset to be asserted
|
||||
let deadline = monotonic_time() + Duration::from_secs(3);
|
||||
let mut status;
|
||||
let mut change;
|
||||
|
||||
loop {
|
||||
(status, change) = self.get_port_status(port).await?;
|
||||
|
||||
self.clear_port_changes(port, change).await?;
|
||||
|
||||
if status.contains(UsbHubPortStatus::PORT_RESET)
|
||||
|| status.contains(UsbHubPortStatus::PORT_ENABLE)
|
||||
|| !status.contains(UsbHubPortStatus::PORT_CONNECTION)
|
||||
{
|
||||
// Port reset got asserted or port got enabled
|
||||
break;
|
||||
}
|
||||
|
||||
if monotonic_time() >= deadline {
|
||||
log::warn!("Port reset did not assert in 3 sec");
|
||||
return Ok(status);
|
||||
}
|
||||
}
|
||||
|
||||
if status.contains(UsbHubPortStatus::PORT_ENABLE)
|
||||
|| !status.contains(UsbHubPortStatus::PORT_CONNECTION)
|
||||
{
|
||||
return Ok(status);
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn setup_connected_port(&mut self, port: NonZeroU8) -> Result<(), UsbError> {
|
||||
let status = self.reset_port(port).await?;
|
||||
if !status.contains(UsbHubPortStatus::PORT_CONNECTION) {
|
||||
log::warn!(
|
||||
"{}: port {} disconnected during reset",
|
||||
self.device.bus_address(),
|
||||
port
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
if !status.contains(UsbHubPortStatus::PORT_ENABLE) {
|
||||
log::warn!("{}: port {} did not reset", self.device.bus_address(), port);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let usb_speed = match (
|
||||
status.contains(UsbHubPortStatus::PORT_LOW_SPEED),
|
||||
status.contains(UsbHubPortStatus::PORT_HIGH_SPEED),
|
||||
) {
|
||||
(false, false) => UsbSpeed::Full,
|
||||
(true, false) => UsbSpeed::Low,
|
||||
(false, true) => UsbSpeed::High,
|
||||
(true, true) => todo!(),
|
||||
};
|
||||
log::info!(
|
||||
"{}: hub port {}: {:?}-speed device connected",
|
||||
self.device.bus_address(),
|
||||
port,
|
||||
usb_speed
|
||||
);
|
||||
let port_string = self.device.port_string().append(port);
|
||||
if let Err(error) = self
|
||||
.device
|
||||
.host_controller()
|
||||
.setup_hub_device(self.device.clone(), port_string, usb_speed)
|
||||
.await
|
||||
{
|
||||
log::error!(
|
||||
"{}: hub port {} ({}) setup failed: {:?}",
|
||||
self.device.bus_address(),
|
||||
port,
|
||||
port_string,
|
||||
error
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
self.children |= 1 << (port.get() - 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn disconnect_port(&mut self, port: NonZeroU8) -> Result<(), UsbError> {
|
||||
let port_string = self.device.port_string().append(port);
|
||||
self.children &= !(1 << (port.get() - 1));
|
||||
self.device
|
||||
.host_controller()
|
||||
.disconnect_device(port_string)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn poll_port(&mut self, port: NonZeroU8) -> Result<(), UsbError> {
|
||||
let (status, change) = self.get_port_status(port).await?;
|
||||
if change.contains(UsbHubPortChange::C_PORT_CONNECTION) {
|
||||
// Clear feature: C_PORT_CONNECTION
|
||||
self.clear_port_feature(port, PortFeatureSelector::CPortConnection)
|
||||
.await?;
|
||||
|
||||
if status.contains(UsbHubPortStatus::PORT_CONNECTION) {
|
||||
self.setup_connected_port(port).await?;
|
||||
} else if let Err(error) = self.disconnect_port(port).await {
|
||||
log::warn!(
|
||||
"{}: hub port {} did not disconnect cleanly: {:?}",
|
||||
self.device.bus_address(),
|
||||
port,
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn poll(&mut self) -> bool {
|
||||
for i in 0..self.hub_descriptor.b_nr_ports {
|
||||
let port = NonZeroU8::new(i + 1).unwrap();
|
||||
if let Err(error) = self.poll_port(port).await {
|
||||
log::error!(
|
||||
"{}: hub port {} poll error: {:?}",
|
||||
self.device.bus_address(),
|
||||
port,
|
||||
error
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
async fn cleanup(&mut self) {
|
||||
for i in 0..self.hub_descriptor.b_nr_ports {
|
||||
let port = NonZeroU8::new(i + 1).unwrap();
|
||||
if self.children & (1 << i) != 0 {
|
||||
if let Err(error) = self.disconnect_port(port).await {
|
||||
log::warn!(
|
||||
"{}: downstream {} disconnect error: {:?}",
|
||||
self.device.bus_address(),
|
||||
port,
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(mut self) -> Result<(), UsbError> {
|
||||
loop {
|
||||
if !self.poll().await {
|
||||
self.cleanup().await;
|
||||
return Ok(());
|
||||
}
|
||||
runtime::sleep(Duration::from_millis(100)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UsbDeviceDriver for UsbHubDriver {
|
||||
async fn run(self: Arc<Self>, device: Arc<UsbDeviceAccess>) -> Result<(), UsbError> {
|
||||
let hub = UsbHub::setup(device).await?;
|
||||
hub.run().await
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"USB Hub"
|
||||
}
|
||||
|
||||
fn probe(&self, class: u8, subclass: u8, protocol: u8, vid: u16, pid: u16) -> bool {
|
||||
let _ = (protocol, vid, pid);
|
||||
class == 0x09 && subclass == 0x00
|
||||
}
|
||||
}
|
||||
@@ -7,25 +7,20 @@ use libk::{
|
||||
dma::{DmaBuffer, DmaSliceMut},
|
||||
error::Error,
|
||||
};
|
||||
use ygg_driver_scsi::{ScsiEnclosure, transport::ScsiTransport};
|
||||
use ygg_driver_scsi::{transport::ScsiTransport, ScsiEnclosure};
|
||||
|
||||
use crate::{
|
||||
class_driver::UsbInterfaceDriver,
|
||||
communication::UsbDirection,
|
||||
device::{UsbDeviceDetachHandler, UsbInterfaceAccess},
|
||||
device::{UsbDeviceAccess, UsbDeviceDetachHandler},
|
||||
error::UsbError,
|
||||
info::UsbEndpointType,
|
||||
info::{UsbDeviceClass, UsbEndpointType},
|
||||
pipe::{
|
||||
control::ControlTransferSetup,
|
||||
control::{ControlTransferSetup, UsbClassSpecificRequest},
|
||||
normal::{UsbBulkInPipeAccess, UsbBulkOutPipeAccess},
|
||||
},
|
||||
};
|
||||
|
||||
const BM_REQUEST_TYPE_BULK_ONLY_MASS_STORAGE_RESET: u8 = 0b00100001;
|
||||
const BM_REQUEST_TYPE_GET_MAX_LUN: u8 = 0b10100001;
|
||||
|
||||
const B_REQUEST_BULK_ONLY_MASS_STORAGE_RESET: u8 = 0b11111111;
|
||||
const B_REQUEST_GET_MAX_LUN: u8 = 0b11111110;
|
||||
use super::{UsbClassInfo, UsbDriver};
|
||||
|
||||
pub struct UsbMassStorageDriverBulkOnly;
|
||||
|
||||
@@ -55,7 +50,7 @@ struct Csw {
|
||||
|
||||
struct Bbb {
|
||||
#[allow(unused)]
|
||||
interface: UsbInterfaceAccess,
|
||||
device: Arc<UsbDeviceAccess>,
|
||||
in_pipe: UsbBulkInPipeAccess,
|
||||
out_pipe: UsbBulkOutPipeAccess,
|
||||
last_tag: u32,
|
||||
@@ -65,12 +60,12 @@ struct DetachHandler(Arc<ScsiEnclosure>);
|
||||
|
||||
impl Bbb {
|
||||
pub fn new(
|
||||
interface: UsbInterfaceAccess,
|
||||
device: Arc<UsbDeviceAccess>,
|
||||
in_pipe: UsbBulkInPipeAccess,
|
||||
out_pipe: UsbBulkOutPipeAccess,
|
||||
) -> Result<Self, UsbError> {
|
||||
Ok(Self {
|
||||
interface,
|
||||
device,
|
||||
in_pipe,
|
||||
out_pipe,
|
||||
last_tag: 0,
|
||||
@@ -177,49 +172,60 @@ impl ScsiTransport for Bbb {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UsbDeviceDetachHandler for DetachHandler {
|
||||
async fn handle_device_detach(&self) {
|
||||
self.0.detach().await;
|
||||
fn handle_device_detach(&self) {
|
||||
log::info!("Mass storage detached");
|
||||
self.0.detach();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Pod, Zeroable, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct BulkOnlyMassStorageReset;
|
||||
|
||||
#[derive(Debug, Pod, Zeroable, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct GetMaxLun;
|
||||
|
||||
impl UsbClassSpecificRequest for BulkOnlyMassStorageReset {
|
||||
const BM_REQUEST_TYPE: u8 = 0b00100001;
|
||||
const B_REQUEST: u8 = 0b11111111;
|
||||
}
|
||||
|
||||
impl UsbClassSpecificRequest for GetMaxLun {
|
||||
const BM_REQUEST_TYPE: u8 = 0b10100001;
|
||||
const B_REQUEST: u8 = 0b11111110;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UsbInterfaceDriver for UsbMassStorageDriverBulkOnly {
|
||||
async fn run(self: Arc<Self>, interface: UsbInterfaceAccess) -> Result<(), UsbError> {
|
||||
let endpoints = interface.endpoints();
|
||||
let bulk_in = endpoints
|
||||
.iter()
|
||||
.find(|ep| ep.ty == UsbEndpointType::Bulk && ep.direction == UsbDirection::In);
|
||||
let bulk_out = endpoints
|
||||
.iter()
|
||||
.find(|ep| ep.ty == UsbEndpointType::Bulk && ep.direction == UsbDirection::Out);
|
||||
|
||||
let (Some(bulk_in), Some(bulk_out)) = (bulk_in, bulk_out) else {
|
||||
log::warn!(
|
||||
"{}: BBB mass storage needs at least 2 bulk endpoints",
|
||||
interface.address()
|
||||
);
|
||||
return Err(UsbError::InvalidConfiguration);
|
||||
};
|
||||
|
||||
let control_pipe = interface.device().control_pipe();
|
||||
let in_pipe = interface
|
||||
.device()
|
||||
.open_bulk_in_pipe(bulk_in.number, bulk_in.max_packet_size as _)
|
||||
impl UsbDriver for UsbMassStorageDriverBulkOnly {
|
||||
async fn run(self: Arc<Self>, device: Arc<UsbDeviceAccess>) -> Result<(), UsbError> {
|
||||
// TODO filter to only accept BBB config
|
||||
let config = device.select_configuration(|_| true).await?.unwrap();
|
||||
// Bulk-in, bulk-out
|
||||
assert_eq!(config.endpoints.len(), 2);
|
||||
let control_pipe = device.control_pipe();
|
||||
let (in_index, in_info) = config
|
||||
.find_endpoint(|ep| ep.is(UsbEndpointType::Bulk, UsbDirection::In))
|
||||
.ok_or(UsbError::InvalidConfiguration)?;
|
||||
let (out_index, out_info) = config
|
||||
.find_endpoint(|ep| ep.is(UsbEndpointType::Bulk, UsbDirection::Out))
|
||||
.ok_or(UsbError::InvalidConfiguration)?;
|
||||
let in_pipe = device
|
||||
.open_bulk_in_pipe(in_index, in_info.max_packet_size as u16)
|
||||
.await?;
|
||||
let out_pipe = interface
|
||||
.device()
|
||||
.open_bulk_out_pipe(bulk_out.number, bulk_out.max_packet_size as _)
|
||||
let out_pipe = device
|
||||
.open_bulk_out_pipe(out_index, out_info.max_packet_size as u16)
|
||||
.await?;
|
||||
|
||||
// Perform a Bulk-Only Mass Storage Reset
|
||||
// TODO interface id?
|
||||
control_pipe
|
||||
.control_transfer(ControlTransferSetup {
|
||||
bm_request_type: BM_REQUEST_TYPE_BULK_ONLY_MASS_STORAGE_RESET,
|
||||
b_request: B_REQUEST_BULK_ONLY_MASS_STORAGE_RESET,
|
||||
bm_request_type: BulkOnlyMassStorageReset::BM_REQUEST_TYPE,
|
||||
b_request: BulkOnlyMassStorageReset::B_REQUEST,
|
||||
w_value: 0,
|
||||
w_index: interface.number() as _,
|
||||
w_index: 0,
|
||||
w_length: 0,
|
||||
})
|
||||
.await?;
|
||||
@@ -230,10 +236,10 @@ impl UsbInterfaceDriver for UsbMassStorageDriverBulkOnly {
|
||||
let len = control_pipe
|
||||
.control_transfer_in(
|
||||
ControlTransferSetup {
|
||||
bm_request_type: BM_REQUEST_TYPE_GET_MAX_LUN,
|
||||
b_request: B_REQUEST_GET_MAX_LUN,
|
||||
bm_request_type: GetMaxLun::BM_REQUEST_TYPE,
|
||||
b_request: GetMaxLun::B_REQUEST,
|
||||
w_value: 0,
|
||||
w_index: interface.number() as _,
|
||||
w_index: 0,
|
||||
w_length: 1,
|
||||
},
|
||||
&mut buffer,
|
||||
@@ -245,13 +251,13 @@ impl UsbInterfaceDriver for UsbMassStorageDriverBulkOnly {
|
||||
unsafe { buffer[0].assume_init() }
|
||||
};
|
||||
|
||||
let bbb = Bbb::new(interface.clone(), in_pipe, out_pipe)?;
|
||||
let bbb = Bbb::new(device.clone(), in_pipe, out_pipe)?;
|
||||
let scsi = ScsiEnclosure::setup(Box::new(bbb), max_lun as usize + 1)
|
||||
.await
|
||||
.inspect_err(|error| log::error!("msc: scsi error {error:?}"))
|
||||
.map_err(|_| UsbError::DriverError)?;
|
||||
let detach = DetachHandler(scsi.clone());
|
||||
interface.device().set_detach_handler(Arc::new(detach));
|
||||
device.set_detach_handler(Arc::new(detach));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -260,9 +266,8 @@ impl UsbInterfaceDriver for UsbMassStorageDriverBulkOnly {
|
||||
"USB Mass Storage"
|
||||
}
|
||||
|
||||
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool {
|
||||
fn probe(&self, class: &UsbClassInfo, _device: &UsbDeviceAccess) -> bool {
|
||||
// TODO support other protocols
|
||||
let _ = subclass;
|
||||
class == 0x08 && protocol == 0x50
|
||||
class.class == UsbDeviceClass::MassStorage && class.interface_protocol_number == 0x50
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,145 +1,117 @@
|
||||
// TODO Split drivers into device and interface drivers
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use async_trait::async_trait;
|
||||
use libk::task::runtime;
|
||||
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
|
||||
|
||||
use crate::{
|
||||
device::{UsbDeviceAccess, UsbInterfaceAccess},
|
||||
device::UsbDeviceAccess,
|
||||
error::UsbError,
|
||||
info::{UsbDeviceClass, UsbDeviceProtocol},
|
||||
};
|
||||
|
||||
mod hid;
|
||||
mod hub;
|
||||
mod mass_storage;
|
||||
mod serial;
|
||||
pub mod hid_keyboard;
|
||||
pub mod mass_storage;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UsbClassInfo {
|
||||
pub class: UsbDeviceClass,
|
||||
pub subclass: u8,
|
||||
pub protocol: UsbDeviceProtocol,
|
||||
pub device_protocol_number: u8,
|
||||
pub interface_protocol_number: u8,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait UsbDeviceDriver: Send + Sync {
|
||||
pub trait UsbDriver: Send + Sync {
|
||||
async fn run(self: Arc<Self>, device: Arc<UsbDeviceAccess>) -> Result<(), UsbError>;
|
||||
|
||||
fn name(&self) -> &'static str;
|
||||
fn probe(&self, class: u8, subclass: u8, protocol: u8, vid: u16, pid: u16) -> bool;
|
||||
fn probe(&self, class: &UsbClassInfo, device: &UsbDeviceAccess) -> bool;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait UsbInterfaceDriver: Send + Sync {
|
||||
async fn run(self: Arc<Self>, interface: UsbInterfaceAccess) -> Result<(), UsbError>;
|
||||
async fn extract_class_info(device: &UsbDeviceAccess) -> Result<Option<UsbClassInfo>, UsbError> {
|
||||
if device.info.num_configurations != 1 {
|
||||
return Ok(None);
|
||||
}
|
||||
let device_info = &device.info;
|
||||
let config_info = device.query_configuration_info(0).await?;
|
||||
|
||||
fn name(&self) -> &'static str;
|
||||
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool;
|
||||
if !config_info.interfaces.is_empty() {
|
||||
let if_info = &config_info.interfaces[0];
|
||||
|
||||
let class = if device_info.device_class == UsbDeviceClass::FromInterface {
|
||||
if_info.interface_class
|
||||
} else {
|
||||
device_info.device_class
|
||||
};
|
||||
let subclass = if device_info.device_subclass == 0 {
|
||||
if_info.interface_subclass
|
||||
} else {
|
||||
device_info.device_subclass
|
||||
};
|
||||
let protocol = if device_info.device_protocol == UsbDeviceProtocol::FromInterface {
|
||||
if_info.interface_protocol
|
||||
} else {
|
||||
device_info.device_protocol
|
||||
};
|
||||
|
||||
Ok(Some(UsbClassInfo {
|
||||
class,
|
||||
subclass,
|
||||
protocol,
|
||||
interface_protocol_number: if_info.interface_protocol_number,
|
||||
device_protocol_number: device_info.device_protocol_number,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
async fn spawn_device_driver(device: Arc<UsbDeviceAccess>) -> Result<bool, UsbError> {
|
||||
let class = device.device_descriptor.device_class;
|
||||
let subclass = device.device_descriptor.device_subclass;
|
||||
let protocol = device.device_descriptor.device_protocol;
|
||||
let vid = device.device_descriptor.id_vendor;
|
||||
let pid = device.device_descriptor.id_product;
|
||||
let Some(driver) = USB_DEVICE_DRIVERS.read().iter().find_map(|driver| {
|
||||
driver
|
||||
.probe(class, subclass, protocol, vid, pid)
|
||||
.then(|| driver.clone())
|
||||
}) else {
|
||||
return Ok(false);
|
||||
async fn pick_driver(
|
||||
device: &UsbDeviceAccess,
|
||||
) -> Result<Option<Arc<dyn UsbDriver + 'static>>, UsbError> {
|
||||
let Some(class) = extract_class_info(device).await? else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// if let Some(driver) = pick_driver(&device)? {
|
||||
runtime::spawn(async move {
|
||||
let name = driver.name();
|
||||
match driver.run(device).await {
|
||||
e @ Err(UsbError::DeviceDisconnected) => {
|
||||
log::warn!(
|
||||
"Driver {:?} did not exit cleanly: device disconnected",
|
||||
name,
|
||||
);
|
||||
|
||||
e
|
||||
}
|
||||
e => e,
|
||||
for driver in USB_DEVICE_DRIVERS.read().iter() {
|
||||
if driver.probe(&class, device) {
|
||||
return Ok(Some(driver.clone()));
|
||||
}
|
||||
})
|
||||
.map_err(UsbError::SystemError)?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn spawn_interface_driver(interface: UsbInterfaceAccess) -> Result<(), UsbError> {
|
||||
let (class, subclass, protocol) = interface.class();
|
||||
let Some(driver) = USB_INTERFACE_DRIVERS.read().iter().find_map(|driver| {
|
||||
driver
|
||||
.probe(class, subclass, protocol)
|
||||
.then(|| driver.clone())
|
||||
}) else {
|
||||
return Ok(());
|
||||
};
|
||||
pub async fn spawn_driver(device: Arc<UsbDeviceAccess>) -> Result<(), UsbError> {
|
||||
if let Some(driver) = pick_driver(&device).await? {
|
||||
runtime::spawn(async move {
|
||||
let name = driver.name();
|
||||
match driver.run(device).await {
|
||||
e @ Err(UsbError::DeviceDisconnected) => {
|
||||
log::warn!(
|
||||
"Driver {:?} did not exit cleanly: device disconnected",
|
||||
name,
|
||||
);
|
||||
|
||||
runtime::spawn(async move {
|
||||
let name = driver.name();
|
||||
match driver.run(interface).await {
|
||||
e @ Err(UsbError::DeviceDisconnected) => {
|
||||
log::warn!(
|
||||
"Driver {:?} did not exit cleanly: device disconnected",
|
||||
name,
|
||||
);
|
||||
|
||||
e
|
||||
e
|
||||
}
|
||||
e => e,
|
||||
}
|
||||
e => e,
|
||||
}
|
||||
})
|
||||
.map_err(UsbError::SystemError)?;
|
||||
|
||||
})
|
||||
.map_err(UsbError::SystemError)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn spawn_driver(device: Arc<UsbDeviceAccess>) {
|
||||
match spawn_device_driver(device.clone()).await {
|
||||
Ok(true) => return,
|
||||
Ok(false) => (),
|
||||
Err(error) => {
|
||||
log::error!(
|
||||
"{}: device driver probe failed: {:?}",
|
||||
device.bus_address(),
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
// Enumerate interfaces
|
||||
for index in 0..device.configuration0_info.interfaces.len() as u8 {
|
||||
let access = device.interface(index);
|
||||
if let Err(error) = spawn_interface_driver(access).await {
|
||||
log::error!(
|
||||
"{}: interface {} driver probe failed: {:?}",
|
||||
device.bus_address(),
|
||||
index,
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_device_driver(driver: Arc<dyn UsbDeviceDriver + 'static>) {
|
||||
pub fn register_driver(driver: Arc<dyn UsbDriver + 'static>) {
|
||||
// TODO check for duplicates
|
||||
USB_DEVICE_DRIVERS.write().push(driver);
|
||||
}
|
||||
|
||||
pub fn register_interface_driver(driver: Arc<dyn UsbInterfaceDriver + 'static>) {
|
||||
USB_INTERFACE_DRIVERS.write().push(driver);
|
||||
}
|
||||
|
||||
pub fn register_default_class_drivers() {
|
||||
register_device_driver(Arc::new(hub::UsbHubDriver));
|
||||
register_device_driver(Arc::new(serial::FT232Driver));
|
||||
register_interface_driver(Arc::new(hid::UsbHidKeyboardDriver));
|
||||
register_interface_driver(Arc::new(hid::UsbHidMouseDriver));
|
||||
register_interface_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly));
|
||||
// register_driver(Arc::new(hub::UsbHubDriver));
|
||||
// register_driver(Arc::new(hid_keyboard::UsbHidKeyboardDriver));
|
||||
// register_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly));
|
||||
register_driver(Arc::new(hid_keyboard::UsbHidKeyboardDriver));
|
||||
register_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly));
|
||||
}
|
||||
|
||||
static USB_DEVICE_DRIVERS: IrqSafeRwLock<Vec<Arc<dyn UsbDeviceDriver + 'static>>> =
|
||||
IrqSafeRwLock::new(Vec::new());
|
||||
static USB_INTERFACE_DRIVERS: IrqSafeRwLock<Vec<Arc<dyn UsbInterfaceDriver + 'static>>> =
|
||||
static USB_DEVICE_DRIVERS: IrqSafeRwLock<Vec<Arc<dyn UsbDriver + 'static>>> =
|
||||
IrqSafeRwLock::new(Vec::new());
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use libk::{
|
||||
block,
|
||||
error::Error,
|
||||
fs::devfs,
|
||||
vfs::{Terminal, TerminalInput, TerminalOutput},
|
||||
};
|
||||
use libk_util::sync::{IrqSafeSpinlock, spin_rwlock::IrqSafeRwLock};
|
||||
use yggdrasil_abi::{
|
||||
io::{FileMode, TerminalOptions, TerminalOutputOptions},
|
||||
process::ProcessId,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
class_driver::UsbDeviceDriver,
|
||||
communication::UsbDirection,
|
||||
device::{UsbDeviceAccess, UsbDeviceDetachHandler},
|
||||
error::UsbError,
|
||||
info::UsbEndpointType,
|
||||
pipe::{control::ControlTransferSetup, normal::UsbBulkOutPipeAccess},
|
||||
};
|
||||
|
||||
pub struct FT232Driver;
|
||||
struct FT232Device {
|
||||
device: Arc<UsbDeviceAccess>,
|
||||
bulk_out: UsbBulkOutPipeAccess,
|
||||
baud_rate: IrqSafeRwLock<u32>,
|
||||
}
|
||||
|
||||
pub struct UsbSerialDeviceWrapper {
|
||||
device: Arc<dyn UsbSerialDevice>,
|
||||
index: u32,
|
||||
disconnected: AtomicBool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait UsbSerialDevice: Send + Sync + 'static {
|
||||
async fn setup(&self) -> Result<(), UsbError>;
|
||||
|
||||
async fn set_baud_rate(&self, baud: u32) -> Result<(), UsbError>;
|
||||
fn baud_rate(&self) -> u32;
|
||||
|
||||
async fn write(&self, buffer: &[u8], options: TerminalOutputOptions)
|
||||
-> Result<usize, UsbError>;
|
||||
|
||||
fn display_name(&self) -> &str;
|
||||
fn device(&self) -> &Arc<UsbDeviceAccess>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UsbDeviceDetachHandler for UsbSerialDeviceWrapper {
|
||||
async fn handle_device_detach(&self) {
|
||||
self.disconnected.store(true, Ordering::Release);
|
||||
log::info!("USB serial #{} disconnected", self.index);
|
||||
remove_usb_serial(self.index);
|
||||
}
|
||||
}
|
||||
|
||||
impl TerminalOutput for UsbSerialDeviceWrapper {
|
||||
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error> {
|
||||
self.write_multiple(&[byte], options)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_multiple(
|
||||
&self,
|
||||
bytes: &[u8],
|
||||
options: &TerminalOutputOptions,
|
||||
) -> Result<usize, Error> {
|
||||
if self.disconnected.load(Ordering::Acquire) {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
let result = block!(self.device.write(bytes, *options).await)?;
|
||||
match result {
|
||||
Ok(len) => Ok(len),
|
||||
Err(UsbError::MemoryError(err) | UsbError::SystemError(err)) => Err(err),
|
||||
Err(error) => {
|
||||
log::warn!("{}: write error: {:?}", self.device.display_name(), error);
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn baud_rate(&self) -> u32 {
|
||||
self.device.baud_rate()
|
||||
}
|
||||
|
||||
fn set_baud_rate(&self, baud: u32) -> Result<(), Error> {
|
||||
if self.disconnected.load(Ordering::Acquire) {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
let result = block!(self.device.set_baud_rate(baud).await)?;
|
||||
match result {
|
||||
Ok(()) => Ok(()),
|
||||
Err(UsbError::MemoryError(err) | UsbError::SystemError(err)) => Err(err),
|
||||
Err(error) => {
|
||||
log::warn!(
|
||||
"{}: baud rate set error: {:?}",
|
||||
self.device.display_name(),
|
||||
error
|
||||
);
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn open(&self, pid: ProcessId) -> Result<(), Error> {
|
||||
if self.disconnected.load(Ordering::Acquire) {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
let _ = pid;
|
||||
let result = block! { self.device.setup().await }?;
|
||||
match result {
|
||||
Ok(()) => Ok(()),
|
||||
Err(UsbError::MemoryError(err) | UsbError::SystemError(err)) => Err(err),
|
||||
Err(error) => {
|
||||
log::warn!("{}: setup error: {:?}", self.device.display_name(), error);
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FT232Device {
|
||||
const FTDI_RESET: u8 = 0;
|
||||
const FTDI_SET_BAUD_RATE: u8 = 3;
|
||||
|
||||
async fn ftdi_reset(&self, port: u16) -> Result<(), UsbError> {
|
||||
self.device
|
||||
.control_pipe()
|
||||
.control_transfer(ControlTransferSetup {
|
||||
bm_request_type: 0b01000000,
|
||||
b_request: Self::FTDI_RESET,
|
||||
w_value: 0,
|
||||
w_index: port,
|
||||
w_length: 0,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn ftdi_set_baud_rate(&self, port: u16, baud: u32) -> Result<(), UsbError> {
|
||||
let w_value = match baud {
|
||||
300 => 0x2710,
|
||||
600 => 0x1388,
|
||||
1200 => 0x09C4,
|
||||
2400 => 0x04E2,
|
||||
4800 => 0x0271,
|
||||
9600 => 0x4138,
|
||||
19200 => 0x809C,
|
||||
38400 => 0xC04E,
|
||||
57600 => 0x0034,
|
||||
115200 => 0x001A,
|
||||
230400 => 0x000D,
|
||||
460800 => 0x4006,
|
||||
921600 => 0x8003,
|
||||
_ => {
|
||||
log::warn!("ft232: unsupported baud rate {baud}");
|
||||
return Err(UsbError::InvalidConfiguration);
|
||||
}
|
||||
};
|
||||
|
||||
self.device
|
||||
.control_pipe()
|
||||
.control_transfer(ControlTransferSetup {
|
||||
bm_request_type: 0b01000000,
|
||||
b_request: Self::FTDI_SET_BAUD_RATE,
|
||||
w_value,
|
||||
w_index: port,
|
||||
w_length: 0,
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UsbSerialDevice for FT232Device {
|
||||
async fn setup(&self) -> Result<(), UsbError> {
|
||||
log::info!("ft232: setup");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_baud_rate(&self, baud: u32) -> Result<(), UsbError> {
|
||||
self.ftdi_set_baud_rate(0, baud).await?;
|
||||
// *self.baud_rate.write() = baud;
|
||||
log::info!("ft232: set baud rate {baud}");
|
||||
Ok(())
|
||||
}
|
||||
fn baud_rate(&self) -> u32 {
|
||||
*self.baud_rate.read()
|
||||
}
|
||||
|
||||
async fn write(
|
||||
&self,
|
||||
buffer: &[u8],
|
||||
options: TerminalOutputOptions,
|
||||
) -> Result<usize, UsbError> {
|
||||
if options.contains(TerminalOutputOptions::NL_TO_CRNL) {
|
||||
for &byte in buffer {
|
||||
if byte == b'\n' {
|
||||
self.bulk_out.write(b"\r").await?;
|
||||
}
|
||||
self.bulk_out.write(&[byte]).await?;
|
||||
}
|
||||
Ok(buffer.len())
|
||||
} else {
|
||||
self.bulk_out.write(buffer).await
|
||||
}
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"FT232 Serial Converter"
|
||||
}
|
||||
fn device(&self) -> &Arc<UsbDeviceAccess> {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UsbDeviceDriver for FT232Driver {
|
||||
async fn run(self: Arc<Self>, device: Arc<UsbDeviceAccess>) -> Result<(), UsbError> {
|
||||
let interface = device.interface(0);
|
||||
let endpoints = interface.endpoints();
|
||||
|
||||
let bulk_in = endpoints
|
||||
.iter()
|
||||
.find(|ep| ep.ty == UsbEndpointType::Bulk && ep.direction == UsbDirection::In)
|
||||
.ok_or(UsbError::InvalidConfiguration)?;
|
||||
let bulk_out = endpoints
|
||||
.iter()
|
||||
.find(|ep| ep.ty == UsbEndpointType::Bulk && ep.direction == UsbDirection::Out)
|
||||
.ok_or(UsbError::InvalidConfiguration)?;
|
||||
|
||||
let bulk_in = device
|
||||
.open_bulk_in_pipe(bulk_in.number, bulk_in.max_packet_size as _)
|
||||
.await?;
|
||||
let bulk_out = device
|
||||
.open_bulk_out_pipe(bulk_out.number, bulk_out.max_packet_size as _)
|
||||
.await?;
|
||||
|
||||
let ft232 = Arc::new(FT232Device {
|
||||
device,
|
||||
bulk_out,
|
||||
baud_rate: IrqSafeRwLock::new(115200),
|
||||
});
|
||||
ft232.ftdi_reset(0).await?;
|
||||
let terminal = register_usb_serial(ft232)?;
|
||||
|
||||
let mut buffer = [0; 3];
|
||||
loop {
|
||||
let len = bulk_in.read(&mut buffer).await?;
|
||||
if len < 2 {
|
||||
continue;
|
||||
}
|
||||
for &byte in &buffer[2..len] {
|
||||
terminal.write_to_input(byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"FT232 Serial Converter"
|
||||
}
|
||||
|
||||
fn probe(&self, class: u8, subclass: u8, protocol: u8, vid: u16, pid: u16) -> bool {
|
||||
let _ = (class, subclass, protocol);
|
||||
vid == 0x0403 && pid == 0x6001
|
||||
}
|
||||
}
|
||||
|
||||
static USB_SERIALS: IrqSafeSpinlock<BTreeMap<u32, Arc<Terminal<Arc<UsbSerialDeviceWrapper>>>>> =
|
||||
IrqSafeSpinlock::new(BTreeMap::new());
|
||||
|
||||
fn register_usb_serial(
|
||||
serial: Arc<dyn UsbSerialDevice>,
|
||||
) -> Result<Arc<Terminal<Arc<UsbSerialDeviceWrapper>>>, UsbError> {
|
||||
let mut serials = USB_SERIALS.lock();
|
||||
for i in 0..64 {
|
||||
if serials.contains_key(&i) {
|
||||
continue;
|
||||
}
|
||||
let wrapper = Arc::new(UsbSerialDeviceWrapper {
|
||||
device: serial,
|
||||
index: i,
|
||||
disconnected: AtomicBool::new(false),
|
||||
});
|
||||
wrapper.device.device().set_detach_handler(wrapper.clone());
|
||||
let input = TerminalInput::with_capacity(64).expect("Couldn't allocate input buffer");
|
||||
let terminal = Arc::new(Terminal::from_parts(
|
||||
TerminalOptions::const_default(),
|
||||
input,
|
||||
wrapper,
|
||||
));
|
||||
serials.insert(i, terminal.clone());
|
||||
let name = alloc::format!("ttyUSB{i}");
|
||||
devfs::add_named_char_device(terminal.clone(), name.clone(), FileMode::new(0o600)).ok();
|
||||
return Ok(terminal);
|
||||
}
|
||||
Err(UsbError::DriverError)
|
||||
}
|
||||
|
||||
fn remove_usb_serial(index: u32) {
|
||||
let serial = USB_SERIALS.lock().remove(&index);
|
||||
if serial.is_none() {
|
||||
log::warn!("usb-serial #{index} doesn't exist in the table");
|
||||
}
|
||||
let name = alloc::format!("ttyUSB{index}");
|
||||
devfs::remove_node(name).ok();
|
||||
}
|
||||
@@ -4,22 +4,9 @@ use crate::{
|
||||
communication::UsbDirection,
|
||||
device::UsbSpeed,
|
||||
error::UsbError,
|
||||
info::{UsbEndpointType, UsbVersion},
|
||||
// info::{UsbDeviceClass, UsbDeviceProtocol, UsbEndpointType, UsbVersion},
|
||||
info::{UsbDeviceClass, UsbDeviceProtocol, UsbEndpointType, UsbVersion},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)]
|
||||
#[repr(C, packed)]
|
||||
pub struct UsbDeviceDescriptor0 {
|
||||
pub length: u8,
|
||||
pub ty: u8,
|
||||
pub bcd_usb: u16,
|
||||
pub device_class: u8,
|
||||
pub device_subclass: u8,
|
||||
pub device_protocol: u8,
|
||||
pub max_packet_size_0: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)]
|
||||
#[repr(C, packed)]
|
||||
pub struct UsbDeviceDescriptor {
|
||||
@@ -104,27 +91,16 @@ pub struct UsbOtherSpeedConfiguration {
|
||||
pub max_power: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)]
|
||||
#[repr(C, packed)]
|
||||
pub struct UsbHubDescriptorHeader {
|
||||
pub b_desc_length: u8,
|
||||
pub b_descriptor_type: u8,
|
||||
pub b_nr_ports: u8,
|
||||
pub w_hub_characteristics: u16,
|
||||
pub b_pwr_on_2_pwr_good: u8,
|
||||
pub b_hub_contr_current: u8,
|
||||
impl UsbInterfaceDescriptor {
|
||||
pub fn class(&self) -> UsbDeviceClass {
|
||||
UsbDeviceClass::try_from(self.interface_class).unwrap_or(UsbDeviceClass::Unknown)
|
||||
}
|
||||
|
||||
pub fn protocol(&self) -> UsbDeviceProtocol {
|
||||
UsbDeviceProtocol::try_from(self.interface_protocol).unwrap_or(UsbDeviceProtocol::Unknown)
|
||||
}
|
||||
}
|
||||
|
||||
// impl UsbInterfaceDescriptor {
|
||||
// pub fn class(&self) -> UsbDeviceClass {
|
||||
// UsbDeviceClass::try_from(self.interface_class).unwrap_or(UsbDeviceClass::Unknown)
|
||||
// }
|
||||
//
|
||||
// pub fn protocol(&self) -> UsbDeviceProtocol {
|
||||
// UsbDeviceProtocol::try_from(self.interface_protocol).unwrap_or(UsbDeviceProtocol::Unknown)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
impl UsbEndpointDescriptor {
|
||||
pub fn direction(&self) -> UsbDirection {
|
||||
match self.endpoint_address >> 7 {
|
||||
@@ -149,16 +125,16 @@ impl UsbEndpointDescriptor {
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
impl UsbDeviceDescriptor {
|
||||
// pub fn class(&self) -> UsbDeviceClass {
|
||||
// UsbDeviceClass::try_from(self.device_class).unwrap_or(UsbDeviceClass::Unknown)
|
||||
// }
|
||||
//
|
||||
// pub fn protocol(&self) -> UsbDeviceProtocol {
|
||||
// UsbDeviceProtocol::try_from(self.device_protocol).unwrap_or(UsbDeviceProtocol::Unknown)
|
||||
// }
|
||||
//
|
||||
pub fn class(&self) -> UsbDeviceClass {
|
||||
UsbDeviceClass::try_from(self.device_class).unwrap_or(UsbDeviceClass::Unknown)
|
||||
}
|
||||
|
||||
pub fn protocol(&self) -> UsbDeviceProtocol {
|
||||
UsbDeviceProtocol::try_from(self.device_protocol).unwrap_or(UsbDeviceProtocol::Unknown)
|
||||
}
|
||||
|
||||
pub fn max_packet_size(&self, version: UsbVersion, speed: UsbSpeed) -> Result<usize, UsbError> {
|
||||
match (version.is_version_3(), speed, self.max_packet_size_0) {
|
||||
(true, UsbSpeed::Super, 9) => Ok(1 << 9),
|
||||
|
||||
+127
-282
@@ -1,27 +1,15 @@
|
||||
use core::{any::Any, fmt, ops::Deref};
|
||||
use core::{fmt, ops::Deref};
|
||||
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use async_trait::async_trait;
|
||||
use libk::{
|
||||
error::Error,
|
||||
fs::sysfs::{
|
||||
self,
|
||||
attribute::{StringAttribute, StringAttributeOps},
|
||||
object::KObject,
|
||||
},
|
||||
};
|
||||
use libk_util::OneTimeInit;
|
||||
use libk_util::sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard};
|
||||
|
||||
use crate::{
|
||||
descriptor::{UsbDeviceDescriptor, UsbHubDescriptorHeader},
|
||||
error::UsbError,
|
||||
host::UsbHostController,
|
||||
info::{PortString, UsbConfigurationInfo, UsbEndpointInfo, UsbEndpointType, UsbInterfaceInfo},
|
||||
info::{
|
||||
UsbConfigurationInfo, UsbDeviceInfo, UsbEndpointInfo, UsbEndpointType, UsbInterfaceInfo,
|
||||
UsbVersion,
|
||||
},
|
||||
pipe::{
|
||||
control::{ConfigurationDescriptorEntry, UsbControlPipeAccess},
|
||||
normal::{
|
||||
@@ -29,10 +17,10 @@ use crate::{
|
||||
UsbNormalPipeOut,
|
||||
},
|
||||
},
|
||||
UsbHostController,
|
||||
};
|
||||
|
||||
// High-level structures for info provided through descriptors
|
||||
type UsbDeviceKObject = KObject<Weak<UsbDeviceAccess>>;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct UsbBusAddress {
|
||||
@@ -40,28 +28,10 @@ pub struct UsbBusAddress {
|
||||
pub device: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct UsbInterfaceAddress {
|
||||
pub bus: UsbBusAddress,
|
||||
pub interface: u8,
|
||||
}
|
||||
|
||||
pub struct UsbDeviceAccess {
|
||||
pub device: Arc<dyn UsbDevice>,
|
||||
pub device_descriptor: UsbDeviceDescriptor,
|
||||
pub product_str: Option<String>,
|
||||
pub vendor_str: Option<String>,
|
||||
pub configuration0_info: UsbConfigurationInfo,
|
||||
|
||||
kobject: OneTimeInit<Arc<UsbDeviceKObject>>,
|
||||
}
|
||||
|
||||
// USB device, limited in scope by one interface
|
||||
#[derive(Clone)]
|
||||
pub struct UsbInterfaceAccess {
|
||||
device: Arc<UsbDeviceAccess>,
|
||||
interface_index: u8,
|
||||
endpoint_start_index: u8,
|
||||
pub info: UsbDeviceInfo,
|
||||
pub current_configuration: IrqSafeRwLock<Option<UsbConfigurationInfo>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
@@ -72,9 +42,8 @@ pub enum UsbSpeed {
|
||||
Super,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait UsbDeviceDetachHandler: Send + Sync {
|
||||
async fn handle_device_detach(&self);
|
||||
fn handle_device_detach(&self);
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -97,231 +66,66 @@ pub trait UsbDevice: Send + Sync {
|
||||
ty: UsbEndpointType,
|
||||
) -> Result<Box<dyn UsbNormalPipeOut>, UsbError>;
|
||||
|
||||
async fn configure_hub(&self, hub_descriptor: &UsbHubDescriptorHeader) -> Result<(), UsbError>;
|
||||
|
||||
// fn port_number(&self) -> u8;
|
||||
fn port_string(&self) -> &PortString;
|
||||
fn port_number(&self) -> u8;
|
||||
fn bus_address(&self) -> UsbBusAddress;
|
||||
fn speed(&self) -> UsbSpeed;
|
||||
fn host_controller(&self) -> Arc<dyn UsbHostController>;
|
||||
fn as_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
|
||||
fn controller_ref(&self) -> &dyn UsbHostController;
|
||||
|
||||
fn set_detach_handler(&self, handler: Arc<dyn UsbDeviceDetachHandler>);
|
||||
async fn handle_detach(&self);
|
||||
fn handle_detach(&self);
|
||||
|
||||
fn debug(&self) {}
|
||||
}
|
||||
|
||||
impl UsbDeviceAccess {
|
||||
fn usb_kobject() -> Option<&'static Arc<KObject<()>>> {
|
||||
static USB_KOBJECT: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
|
||||
|
||||
USB_KOBJECT.or_init_with_opt(|| {
|
||||
let bus_kobject = sysfs::bus()?;
|
||||
let usb_kobject = KObject::new(());
|
||||
bus_kobject.add_object("usb", usb_kobject.clone()).ok()?;
|
||||
Some(usb_kobject)
|
||||
})
|
||||
}
|
||||
|
||||
fn setup_kobject(self: &Arc<Self>) -> Result<(), Error> {
|
||||
struct Id;
|
||||
struct DeviceClass;
|
||||
struct VendorString;
|
||||
struct ProductString;
|
||||
|
||||
impl StringAttributeOps for Id {
|
||||
type Data = Weak<UsbDeviceAccess>;
|
||||
const NAME: &'static str = "id";
|
||||
|
||||
fn read(state: &Self::Data) -> Result<String, Error> {
|
||||
let state = state.upgrade().ok_or(Error::InvalidOperation)?;
|
||||
let id_product = state.device_descriptor.id_product;
|
||||
let id_vendor = state.device_descriptor.id_vendor;
|
||||
Ok(alloc::format!("{id_vendor:04x}:{id_product:04x}",))
|
||||
}
|
||||
}
|
||||
|
||||
impl StringAttributeOps for DeviceClass {
|
||||
type Data = Weak<UsbDeviceAccess>;
|
||||
const NAME: &'static str = "device_class";
|
||||
|
||||
fn read(state: &Self::Data) -> Result<String, Error> {
|
||||
let state = state.upgrade().ok_or(Error::InvalidOperation)?;
|
||||
Ok(alloc::format!(
|
||||
"{:02x}:{:02x}:{:02x}",
|
||||
state.device_descriptor.device_class,
|
||||
state.device_descriptor.device_subclass,
|
||||
state.device_descriptor.device_protocol
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl StringAttributeOps for VendorString {
|
||||
type Data = Weak<UsbDeviceAccess>;
|
||||
const NAME: &'static str = "vendor_str";
|
||||
|
||||
fn read(state: &Self::Data) -> Result<String, Error> {
|
||||
let state = state.upgrade().ok_or(Error::InvalidOperation)?;
|
||||
if let Some(vendor_str) = state.vendor_str.as_ref() {
|
||||
Ok(vendor_str.clone())
|
||||
} else {
|
||||
Ok(String::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StringAttributeOps for ProductString {
|
||||
type Data = Weak<UsbDeviceAccess>;
|
||||
const NAME: &'static str = "product_str";
|
||||
|
||||
fn read(state: &Self::Data) -> Result<String, Error> {
|
||||
let state = state.upgrade().ok_or(Error::InvalidOperation)?;
|
||||
if let Some(product_str) = state.product_str.as_ref() {
|
||||
Ok(product_str.clone())
|
||||
} else {
|
||||
Ok(String::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let usb_kobject = Self::usb_kobject().ok_or(Error::DoesNotExist)?;
|
||||
let dev_kobject = KObject::new(Arc::downgrade(self));
|
||||
dev_kobject.add_attribute(StringAttribute::from(Id)).ok();
|
||||
dev_kobject
|
||||
.add_attribute(StringAttribute::from(DeviceClass))
|
||||
.ok();
|
||||
dev_kobject
|
||||
.add_attribute(StringAttribute::from(ProductString))
|
||||
.ok();
|
||||
dev_kobject
|
||||
.add_attribute(StringAttribute::from(VendorString))
|
||||
.ok();
|
||||
let name = alloc::format!("{}", self.device.bus_address());
|
||||
usb_kobject.add_object(name, dev_kobject.clone())?;
|
||||
self.kobject.init(dev_kobject);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Expected device state:
|
||||
///
|
||||
/// * Link-layer stuff has been reset and established properly by the HCD
|
||||
/// * Device is not yet configured
|
||||
/// * Control pipe for the device has been properly set up
|
||||
/// * Device has been assigned a bus address
|
||||
pub async fn setup(raw: Arc<dyn UsbDevice>) -> Result<Arc<Self>, UsbError> {
|
||||
let control_pipe = raw.control_pipe();
|
||||
let device_descriptor = control_pipe.query_device_descriptor().await?;
|
||||
if device_descriptor.num_configurations < 1 {
|
||||
return Err(UsbError::InvalidDescriptorField);
|
||||
}
|
||||
let config_descriptor = control_pipe.query_configuration_descriptor(0).await?;
|
||||
pub async fn setup(raw: Arc<dyn UsbDevice>) -> Result<Self, UsbError> {
|
||||
let control = raw.control_pipe();
|
||||
|
||||
// Use configuration 0
|
||||
control_pipe
|
||||
.set_configuration(config_descriptor.configuration().config_val as _)
|
||||
.await?;
|
||||
let device_desc = control.query_device_descriptor().await?;
|
||||
|
||||
let vendor_str = control_pipe
|
||||
.query_string(device_descriptor.manufacturer_str)
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
log::warn!(
|
||||
"{}: manufacturer string query error: {:?}",
|
||||
let bcd_usb = device_desc.bcd_usb;
|
||||
let usb_version = UsbVersion::from_bcd_usb(device_desc.bcd_usb)
|
||||
.ok_or(UsbError::InvalidDescriptorField)
|
||||
.inspect_err(|_| {
|
||||
log::error!(
|
||||
"{}: unsupported/invalid USB version: {:#x}",
|
||||
raw.bus_address(),
|
||||
e
|
||||
bcd_usb
|
||||
)
|
||||
})
|
||||
.ok();
|
||||
let product_str = control_pipe
|
||||
.query_string(device_descriptor.product_str)
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
log::warn!("{}: product string query error: {:?}", raw.bus_address(), e)
|
||||
})
|
||||
.ok();
|
||||
})?;
|
||||
|
||||
// Extract configuration 0 information
|
||||
// let query = control_pipe.query_configuration_descriptor(index).await?;
|
||||
let manufacturer = control.query_string(device_desc.manufacturer_str).await?;
|
||||
let product = control.query_string(device_desc.product_str).await?;
|
||||
|
||||
let configuration_name = control_pipe
|
||||
.query_string(config_descriptor.configuration().config_str)
|
||||
.await
|
||||
.ok();
|
||||
let info = UsbDeviceInfo {
|
||||
manufacturer,
|
||||
product,
|
||||
usb_version,
|
||||
|
||||
let mut endpoints = Vec::new();
|
||||
let mut interfaces = Vec::new();
|
||||
id_vendor: device_desc.id_vendor,
|
||||
id_product: device_desc.id_product,
|
||||
|
||||
for desc in config_descriptor.descriptors() {
|
||||
match desc {
|
||||
ConfigurationDescriptorEntry::Interface(iface) => {
|
||||
let name = control_pipe.query_string(iface.interface_str).await.ok();
|
||||
interfaces.push(UsbInterfaceInfo {
|
||||
name,
|
||||
number: iface.interface_number,
|
||||
num_endpoints: iface.num_endpoints,
|
||||
device_class: device_desc.class(),
|
||||
device_subclass: device_desc.device_subclass,
|
||||
device_protocol: device_desc.protocol(),
|
||||
device_protocol_number: device_desc.device_protocol,
|
||||
|
||||
interface_class: iface.interface_class,
|
||||
interface_subclass: iface.interface_subclass,
|
||||
interface_protocol: iface.interface_protocol,
|
||||
});
|
||||
}
|
||||
ConfigurationDescriptorEntry::Endpoint(ep) => {
|
||||
endpoints.push(UsbEndpointInfo {
|
||||
number: ep.number(),
|
||||
direction: ep.direction(),
|
||||
max_packet_size: ep.max_packet_size as _,
|
||||
ty: ep.transfer_type(),
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
num_configurations: device_desc.num_configurations,
|
||||
|
||||
interfaces.sort_by_key(|r| r.number);
|
||||
endpoints.sort_by_key(|r| r.number);
|
||||
|
||||
let configuration0_info = UsbConfigurationInfo {
|
||||
name: configuration_name,
|
||||
config_value: config_descriptor.configuration().config_val,
|
||||
interfaces,
|
||||
endpoints,
|
||||
max_packet_size: device_desc.max_packet_size(usb_version, raw.speed())?,
|
||||
};
|
||||
|
||||
let device = Arc::new(Self {
|
||||
Ok(Self {
|
||||
device: raw,
|
||||
device_descriptor,
|
||||
product_str,
|
||||
vendor_str,
|
||||
configuration0_info,
|
||||
kobject: OneTimeInit::new(),
|
||||
});
|
||||
|
||||
if let Err(error) = device.setup_kobject() {
|
||||
log::error!(
|
||||
"{} kobject setup error: {:?}",
|
||||
device.device.bus_address(),
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
pub fn interface(self: &Arc<Self>, interface_index: u8) -> UsbInterfaceAccess {
|
||||
let endpoint_start_index = self
|
||||
.configuration0_info
|
||||
.interfaces
|
||||
.iter()
|
||||
.take(interface_index as usize)
|
||||
.map(|r| r.num_endpoints)
|
||||
.sum();
|
||||
|
||||
UsbInterfaceAccess {
|
||||
device: self.clone(),
|
||||
interface_index,
|
||||
endpoint_start_index,
|
||||
}
|
||||
info,
|
||||
current_configuration: IrqSafeRwLock::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn open_interrupt_in_pipe(
|
||||
@@ -360,6 +164,90 @@ impl UsbDeviceAccess {
|
||||
Ok(UsbBulkOutPipeAccess(pipe))
|
||||
}
|
||||
|
||||
pub fn read_current_configuration(
|
||||
&self,
|
||||
) -> IrqSafeRwLockReadGuard<'_, Option<UsbConfigurationInfo>> {
|
||||
self.current_configuration.read()
|
||||
}
|
||||
|
||||
pub async fn select_configuration<F: Fn(&UsbConfigurationInfo) -> bool>(
|
||||
&self,
|
||||
predicate: F,
|
||||
) -> Result<Option<UsbConfigurationInfo>, UsbError> {
|
||||
let mut current_config = self.current_configuration.write();
|
||||
let control_pipe = self.control_pipe();
|
||||
|
||||
for i in 0..self.info.num_configurations {
|
||||
let info = self.query_configuration_info(i).await?;
|
||||
|
||||
if predicate(&info) {
|
||||
log::debug!("Selected configuration: {:#?}", info);
|
||||
let config = current_config.insert(info);
|
||||
|
||||
control_pipe
|
||||
.set_configuration(config.config_value as _)
|
||||
.await?;
|
||||
|
||||
return Ok(Some(config.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub async fn query_configuration_info(
|
||||
&self,
|
||||
index: u8,
|
||||
) -> Result<UsbConfigurationInfo, UsbError> {
|
||||
if index >= self.info.num_configurations {
|
||||
return Err(UsbError::InvalidConfiguration);
|
||||
}
|
||||
let control_pipe = self.control_pipe();
|
||||
let query = control_pipe.query_configuration_descriptor(index).await?;
|
||||
|
||||
let configuration_name = control_pipe
|
||||
.query_string(query.configuration().config_str)
|
||||
.await?;
|
||||
|
||||
let mut endpoints = Vec::new();
|
||||
let mut interfaces = Vec::new();
|
||||
|
||||
for desc in query.descriptors() {
|
||||
match desc {
|
||||
ConfigurationDescriptorEntry::Endpoint(ep) => {
|
||||
endpoints.push(UsbEndpointInfo {
|
||||
number: ep.number(),
|
||||
direction: ep.direction(),
|
||||
max_packet_size: ep.max_packet_size as _,
|
||||
ty: ep.transfer_type(),
|
||||
});
|
||||
}
|
||||
ConfigurationDescriptorEntry::Interface(iface) => {
|
||||
let name = control_pipe.query_string(iface.interface_str).await?;
|
||||
interfaces.push(UsbInterfaceInfo {
|
||||
name,
|
||||
number: iface.interface_number,
|
||||
|
||||
interface_class: iface.class(),
|
||||
interface_subclass: iface.interface_subclass,
|
||||
interface_protocol: iface.protocol(),
|
||||
interface_protocol_number: iface.interface_protocol,
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let info = UsbConfigurationInfo {
|
||||
name: configuration_name,
|
||||
config_value: query.configuration().config_val,
|
||||
interfaces,
|
||||
endpoints,
|
||||
};
|
||||
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
pub fn set_detach_handler(&self, handler: Arc<dyn UsbDeviceDetachHandler>) {
|
||||
self.device.set_detach_handler(handler);
|
||||
}
|
||||
@@ -378,46 +266,3 @@ impl fmt::Display for UsbBusAddress {
|
||||
write!(f, "{}:{}", self.bus, self.device)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for UsbInterfaceAddress {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}.{}", self.bus, self.interface)
|
||||
}
|
||||
}
|
||||
|
||||
impl UsbInterfaceAccess {
|
||||
fn interface_info(&self) -> &UsbInterfaceInfo {
|
||||
&self.device.configuration0_info.interfaces[self.interface_index as usize]
|
||||
}
|
||||
|
||||
pub fn number(&self) -> u8 {
|
||||
self.interface_index
|
||||
}
|
||||
|
||||
pub fn endpoints(&self) -> &[UsbEndpointInfo] {
|
||||
let info = self.interface_info();
|
||||
let start = self.endpoint_start_index as usize;
|
||||
let end = start + info.num_endpoints as usize;
|
||||
&self.device.configuration0_info.endpoints[start..end]
|
||||
}
|
||||
|
||||
pub fn device(&self) -> &Arc<UsbDeviceAccess> {
|
||||
&self.device
|
||||
}
|
||||
|
||||
pub fn address(&self) -> UsbInterfaceAddress {
|
||||
UsbInterfaceAddress {
|
||||
bus: self.device.bus_address(),
|
||||
interface: self.interface_index,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn class(&self) -> (u8, u8, u8) {
|
||||
let i = self.interface_info();
|
||||
(
|
||||
i.interface_class,
|
||||
i.interface_subclass,
|
||||
i.interface_protocol,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ pub enum TransferError {
|
||||
BufferError,
|
||||
UsbTransactionError,
|
||||
Stall,
|
||||
Shutdown,
|
||||
Other(u8),
|
||||
}
|
||||
|
||||
@@ -30,17 +29,13 @@ pub enum UsbError {
|
||||
DeviceBusy,
|
||||
DeviceDisconnected,
|
||||
TransferFailed(TransferError),
|
||||
TruncatedDescriptor(usize, usize),
|
||||
// Driver errors
|
||||
DriverError,
|
||||
}
|
||||
|
||||
impl From<TransferError> for UsbError {
|
||||
fn from(value: TransferError) -> Self {
|
||||
match value {
|
||||
TransferError::Shutdown => Self::DeviceDisconnected,
|
||||
value => Self::TransferFailed(value),
|
||||
}
|
||||
Self::TransferFailed(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use device_api::device::Device;
|
||||
|
||||
use crate::{
|
||||
device::{UsbDeviceAccess, UsbSpeed},
|
||||
error::UsbError,
|
||||
info::PortString,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
pub trait UsbHostController: Device + Sync + Send {
|
||||
async fn setup_hub_device(
|
||||
self: Arc<Self>,
|
||||
hub: Arc<UsbDeviceAccess>,
|
||||
port_string: PortString,
|
||||
usb_speed: UsbSpeed,
|
||||
) -> Result<(), UsbError>;
|
||||
async fn disconnect_device(self: Arc<Self>, port_string: PortString) -> Result<(), UsbError>;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use core::{fmt, num::NonZeroU8};
|
||||
use core::fmt;
|
||||
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use yggdrasil_abi::primitive_enum;
|
||||
|
||||
use crate::communication::UsbDirection;
|
||||
|
||||
@@ -38,21 +39,31 @@ pub enum UsbVersion {
|
||||
Usb32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct PortString(u64);
|
||||
primitive_enum! {
|
||||
pub enum UsbDeviceClass: u8 {
|
||||
FromInterface = 0x00,
|
||||
Hid = 0x03,
|
||||
MassStorage = 0x08,
|
||||
Unknown = 0xFF,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct PortStringIter(u64);
|
||||
primitive_enum! {
|
||||
pub enum UsbDeviceProtocol: u8 {
|
||||
FromInterface = 0x00,
|
||||
Unknown = 0xFF,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UsbInterfaceInfo {
|
||||
pub name: Option<String>,
|
||||
pub name: String,
|
||||
pub number: u8,
|
||||
pub num_endpoints: u8,
|
||||
|
||||
pub interface_class: u8,
|
||||
pub interface_class: UsbDeviceClass,
|
||||
pub interface_subclass: u8,
|
||||
pub interface_protocol: u8,
|
||||
pub interface_protocol: UsbDeviceProtocol,
|
||||
pub interface_protocol_number: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -65,12 +76,33 @@ pub struct UsbEndpointInfo {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UsbConfigurationInfo {
|
||||
pub name: Option<String>,
|
||||
pub name: String,
|
||||
pub config_value: u8,
|
||||
pub interfaces: Vec<UsbInterfaceInfo>,
|
||||
pub endpoints: Vec<UsbEndpointInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UsbDeviceInfo {
|
||||
pub manufacturer: String,
|
||||
pub product: String,
|
||||
|
||||
pub usb_version: UsbVersion,
|
||||
|
||||
pub id_vendor: u16,
|
||||
pub id_product: u16,
|
||||
|
||||
pub device_class: UsbDeviceClass,
|
||||
pub device_subclass: u8,
|
||||
pub device_protocol: UsbDeviceProtocol,
|
||||
pub device_protocol_number: u8,
|
||||
|
||||
/// Max packet size for endpoint zero
|
||||
pub max_packet_size: usize,
|
||||
|
||||
pub num_configurations: u8,
|
||||
}
|
||||
|
||||
impl UsbVersion {
|
||||
pub fn is_version_3(&self) -> bool {
|
||||
matches!(self, Self::Usb30 | Self::Usb31 | Self::Usb32)
|
||||
@@ -119,59 +151,3 @@ impl UsbConfigurationInfo {
|
||||
Some((index as u8 + 1, info))
|
||||
}
|
||||
}
|
||||
|
||||
impl PortString {
|
||||
pub const fn new_root_port(root_hub_port_number: NonZeroU8) -> Self {
|
||||
Self(root_hub_port_number.get() as u64)
|
||||
}
|
||||
|
||||
pub const fn root_hub_port_number(&self) -> NonZeroU8 {
|
||||
unsafe { NonZeroU8::new_unchecked((self.0 & 0xF) as u8) }
|
||||
}
|
||||
|
||||
pub fn append(mut self, port: NonZeroU8) -> Self {
|
||||
for i in 0..16 {
|
||||
let pos = i * 4;
|
||||
if (self.0 >> pos) & 0xF == 0 {
|
||||
self.0 |= (port.get() as u64) << pos;
|
||||
return self;
|
||||
}
|
||||
}
|
||||
panic!("Port route string too long");
|
||||
}
|
||||
|
||||
pub fn parent_hub_port_number(&self) -> Option<NonZeroU8> {
|
||||
self.iter().last()
|
||||
}
|
||||
|
||||
pub const fn raw(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> PortStringIter {
|
||||
PortStringIter(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PortString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "<port ")?;
|
||||
for (i, port) in self.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, ".")?;
|
||||
}
|
||||
write!(f, "{port}")?;
|
||||
}
|
||||
write!(f, ">")
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for PortStringIter {
|
||||
type Item = NonZeroU8;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let port = NonZeroU8::new((self.0 & 0xF) as u8)?;
|
||||
self.0 >>= 4;
|
||||
Some(port)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#![no_std]
|
||||
#![allow(clippy::new_without_default, incomplete_features)]
|
||||
#![allow(clippy::new_without_default)]
|
||||
#![feature(
|
||||
generic_const_exprs,
|
||||
iter_array_chunks,
|
||||
maybe_uninit_slice,
|
||||
maybe_uninit_as_bytes,
|
||||
maybe_uninit_fill,
|
||||
maybe_uninit_array_assume_init
|
||||
maybe_uninit_write_slice,
|
||||
maybe_uninit_fill
|
||||
)]
|
||||
|
||||
extern crate alloc;
|
||||
@@ -15,7 +15,6 @@ pub mod communication;
|
||||
pub mod descriptor;
|
||||
pub mod device;
|
||||
pub mod error;
|
||||
pub mod host;
|
||||
pub mod info;
|
||||
pub mod pipe;
|
||||
pub mod util;
|
||||
@@ -25,3 +24,5 @@ pub mod class_driver;
|
||||
// pub use communication::{UsbControlTransfer, UsbDirection, UsbTransferStatus, UsbTransferToken};
|
||||
|
||||
pub trait UsbEndpoint: Sync {}
|
||||
|
||||
pub trait UsbHostController: Sync + Send {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use core::{
|
||||
mem::{MaybeUninit, size_of},
|
||||
mem::{size_of, MaybeUninit},
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
@@ -10,8 +10,8 @@ use libk_mm::PageBox;
|
||||
|
||||
use crate::{
|
||||
descriptor::{
|
||||
UsbConfigurationDescriptor, UsbDeviceDescriptor, UsbDeviceDescriptor0, UsbDeviceQualifier,
|
||||
UsbEndpointDescriptor, UsbInterfaceDescriptor, UsbOtherSpeedConfiguration,
|
||||
UsbConfigurationDescriptor, UsbDeviceDescriptor, UsbDeviceQualifier, UsbEndpointDescriptor,
|
||||
UsbInterfaceDescriptor, UsbOtherSpeedConfiguration,
|
||||
},
|
||||
error::UsbError,
|
||||
};
|
||||
@@ -34,6 +34,11 @@ pub trait UsbDeviceRequest: Sized + Pod {
|
||||
const B_REQUEST: u8;
|
||||
}
|
||||
|
||||
pub trait UsbClassSpecificRequest: Sized + Pod {
|
||||
const BM_REQUEST_TYPE: u8;
|
||||
const B_REQUEST: u8;
|
||||
}
|
||||
|
||||
pub trait UsbDescriptorRequest: UsbDeviceRequest {
|
||||
const DESCRIPTOR_TYPE: u8;
|
||||
}
|
||||
@@ -61,7 +66,7 @@ impl<U: UsbDescriptorRequest> UsbDeviceRequest for U {
|
||||
}
|
||||
|
||||
fn decode_usb_string(bytes: &[u8]) -> Result<String, UsbError> {
|
||||
if !bytes.len().is_multiple_of(2) {
|
||||
if bytes.len() % 2 != 0 {
|
||||
return Err(UsbError::InvalidDescriptorField);
|
||||
}
|
||||
|
||||
@@ -172,25 +177,6 @@ impl ConfigurationDescriptorQuery {
|
||||
}
|
||||
|
||||
impl UsbControlPipeAccess {
|
||||
pub async fn query_device_descriptor_0(&self) -> Result<UsbDeviceDescriptor0, UsbError> {
|
||||
assert_eq!(size_of::<UsbDeviceDescriptor0>(), 8);
|
||||
let mut buffer = MaybeUninit::uninit();
|
||||
|
||||
self.control_transfer_in(
|
||||
ControlTransferSetup {
|
||||
bm_request_type: 0b10000000,
|
||||
b_request: 0x06,
|
||||
w_value: 0x100,
|
||||
w_index: 0,
|
||||
w_length: size_of::<UsbDeviceDescriptor0>() as _,
|
||||
},
|
||||
buffer.as_bytes_mut(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(unsafe { buffer.assume_init() })
|
||||
}
|
||||
|
||||
pub async fn query_device_descriptor(&self) -> Result<UsbDeviceDescriptor, UsbError> {
|
||||
let mut buffer = MaybeUninit::uninit();
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use libk::{
|
||||
use walk::{DirentIter, DirentIterMut};
|
||||
use yggdrasil_abi::io::{DirectoryEntry, FileType};
|
||||
|
||||
use crate::{Dirent, Ext2Fs, Inode, file::RegularNode, inode::InodeAccess, symlink::SymlinkNode};
|
||||
use crate::{file::RegularNode, inode::InodeAccess, symlink::SymlinkNode, Dirent, Ext2Fs, Inode};
|
||||
|
||||
mod walk;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use yggdrasil_abi::{
|
||||
util::FixedString,
|
||||
};
|
||||
|
||||
use crate::{Dirent, Ext2Fs, access::InodeBlock, data::FsRequiredFeatures};
|
||||
use crate::{access::InodeBlock, data::FsRequiredFeatures, Dirent, Ext2Fs};
|
||||
|
||||
use super::DirentName;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user