Skip to content

rpi-hal 0.11.0

Choose a tag to compare

@github-actions github-actions released this 02 Nov 22:30

Added

  • PCIe and NVMe on the Pi 5's external connector. New pcie module:
    Pcie::init(PCIE1, LinkSpeed, &timer) resets the BCM2712's pcie1
    root complex, programs its windows, trains the link and numbers the bus
    behind it (the firmware leaves this controller in reset, so no
    config.txt line is needed); functions() lists what answered and
    enable() assigns a function's memory BARs and turns on decoding and
    bus mastering. New nvme module: Nvme::new(&function, &mut Memory, &timer) brings up a controller with one polled I/O queue pair, then
    read_blocks/write_blocks/flush/shutdown on namespace 1, any
    4-byte-aligned buffer anywhere in RAM moved directly, others through a
    bounce page. The MMU now maps the first gigabyte of pcie1's outbound
    window (0x1b_0000_0000), new pac::PCIE1 token, and the nvme
    example reads, times and round-trips a block on the SSD. With the
    resident-fat feature, NvmeBlockDevice wraps an Nvme as that
    crate's BlockDevice, so a FAT32 volume on the SSD mounts like the SD
    card's; drives formatted with 512-byte blocks only, anything else is
    nvme::Error::BlockSize.

  • ADMA2 for the Pi 5's SD card, off by default. Sd::set_adma(true)
    has the controller move read_blocks' and write_blocks' data over its
    own DMA, from a table of 64-bit descriptors, for any 4-byte-aligned
    buffer anywhere in RAM (the controller sees RAM at its physical
    addresses). Same data both ways in sd_speed, reads in every mode and
    a 1 MiB write; no faster, since the FIFO already keeps up with the bus,
    and about 1% slower at 1 MiB a command for the cache maintenance, hence
    off. What it frees is the CPU, for a transfer that doesn't block, which
    isn't here yet. New Sd::adma. Internally, the cache-maintenance
    helpers now take any address, including above 4 GiB.

  • multicore on the Pi 5. Core1::spawn and its siblings start
    cores 1-3 on the BCM2712 through the firmware's PSCI CPU_ON call
    (smc), which is how the Pi 5's ARM Trusted Firmware holds them; the
    spin-table the other AArch64 boards use does not exist there, and its
    address is inside the firmware's own reserved memory. spawn panics
    with the PSCI error code if the firmware refuses. The four multicore
    examples build for the Pi 5 unchanged, and multicore_id runs there.

  • pwm on the Pi 5, over RP1's two PWM blocks. Pwm::<PWM0 | PWM1>::init(block, clock_divisor) runs the block from the 50MHz
    crystal; channel(&gpio, pin, range) hands back a Channel
    implementing embedded_hal::pwm::SetDutyCycle, with set_inverted /
    clr_inverted. Pins are the header's GPIO12/13/18/19 (Pwm0Pin) and
    the fan connector's GPIO45 (Pwm1Pin). Pwm::<PWM1>::fan_rpm reads the
    fan's speed. New pac::PWM0/PWM1 tokens, and the pwm_fan example,
    which steps the fan from off to full and prints its RPM.

  • fault-report on the Pi 5. The handler needed no changes; the
    compile_error! is gone, and the report goes out on RP1's UART0 like
    any other console write. The fault_report example reads 8 GiB there
    to fault (the BCM2712 maps its whole low 4 GiB as RAM, so the other
    boards' 0xf000_0000 is an ordinary read).

  • mem on the Pi 5. mem::heap_region and mem::image_end are
    built for the BCM2712, where they had been compiled out with the rest
    of the not-yet-ported modules though nothing in them is chip-specific.
    rpi-kickstart's heap needs them, so a Pi 5 board can have a heap
    through it. heap_alloc builds for the Pi 5.

  • High-speed SD on the Pi 5. After the 4-bit bus, Sd::init asks
    the card for high speed with CMD6 and, if it has it, switches the
    card, the host's high-speed bit and the clock from 25 to 50MHz, so a
    multi-block read goes from 12.0 to 23.9 MB/s. Best-effort like the
    4-bit bus: a card without it, or a failed switch, stays at default
    speed. The other chips stay at default speed for now. New
    sd::BusMode, Sd::bus_mode, and Sd::init_with to cap the mode, and
    the sd_speed example, which reads the same data in every mode and
    reports each one's throughput and the cost of a command.

  • UHS-I SD on the Pi 5: SDR50 and SDR104. Sd::init now asks a
    card for 1.8V signalling, switches it (CMD11, Host Control 2's 1.8V
    bit and the I/O rail's always-on GPIO line), then switches it to
    SDR104 at 200MHz or SDR50 at 100MHz (CMD6) and tunes the sampling
    point (CMD19). A multi-block read goes from 23.9 MB/s at high speed to
    47.4 (SDR50) and 72.8 (SDR104), every mode reading the same data. A
    failed step powers the card off and starts again one mode lower, down
    to high speed. New BusMode::Sdr50 and BusMode::Sdr104; init asks
    for Sdr104. Taking the clock down fully and rewriting SD_PIN_SEL on
    every clock change, and selecting the delay-line PHY, follow Linux's
    sdhci-brcmstb for this chip.

  • All of a Pi 5's RAM. The firmware reports only the first gigabyte
    to the ARM, whatever the board's size, and that is all heap_region
    covers. New mem::ram_bytes gives the board's whole RAM from its
    revision code, and mem::high_ram_region the rest above 1 GiB, with
    what lies past 4 GiB mapped first by the new
    mmu::map_ram_above_4g (1 GiB blocks, after boot, since the boot-time
    map can't know how far the RAM goes). On an 8 GB board that is
    0x4000_0000..0x2_0000_0000, 7 GiB on top of the 1014 MiB heap. The
    high_ram example writes all of it with values made from each word's
    address and reads them back. mem::Error gains UnknownRam.

Fixed

  • cpu::core_id returned 0 on every Pi 5 core. The Cortex-A76 puts
    the core number in MPIDR's Aff1 field, not Aff0. core_id, the boot
    stub's core-0 check and the secondary-core trampoline now read Aff1 on
    the BCM2712.

  • Nothing on RP1 worked with a Pi 5 bootloader from 2024-10-10 or
    later.
    Those bootloaders start PCIe memory at 2 GiB, which moves
    pcie2's window onto RP1 from CPU 0x1f_0000_0000 to 0x1c_0000_0000,
    so the first access through pac::RP1_BASE (the console UART, GPIO,
    I2C, PWM) stalled the core with no fault. New rp1::init moves the
    window back to RP1_BASE, keeping the PCIe address the bootloader
    assigned RP1, and rt's boot sequence calls it before kmain, through
    a new per-chip rpi_hal_soc_init hook in boot64.s. A program with its
    own boot sequence calls rp1::init itself, before its first RP1 access.