Newer
Older
minerva / Kernel / Arch / aarch64 / RPi / RP1.cpp
@minerva minerva on 13 Jul 2 KB Initial commit
/*
 * Copyright (c) 2025, Sönke Holz <sholz8530@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <Kernel/Arch/aarch64/RPi/RP1.h>
#include <Kernel/Bus/PCI/BarMapping.h>
#include <Kernel/Bus/USB/USBManagement.h>
#include <Kernel/Bus/USB/xHCI/xHCIController.h>
#include <Kernel/Interrupts/IRQHandler.h>

namespace Kernel::RPi {

class RP1xHCIController final : public USB::xHCIController {
public:
    static ErrorOr<NonnullLockRefPtr<RP1xHCIController>> try_to_initialize(PhysicalAddress, size_t index, size_t interrupt_number);

private:
    RP1xHCIController(Memory::TypedMapping<u8> registers_mapping, size_t index, size_t interrupt_number);

    // ^xHCIController
    virtual bool using_message_signalled_interrupts() const override { return m_using_message_signalled_interrupts; }
    virtual ErrorOr<OwnPtr<GenericInterruptHandler>> create_interrupter(u16 interrupter_id) override;
    virtual ErrorOr<void> write_dmesgln_prefix(StringBuilder& builder) const override
    {
        TRY(builder.try_appendff("xHCI: RP1 USBHOST{}: "sv, m_index));
        return {};
    }

    size_t m_index { 0 };
    size_t m_interrupt_number { 0 };
    bool m_using_message_signalled_interrupts { false };
};

ErrorOr<NonnullLockRefPtr<RP1xHCIController>> RP1xHCIController::try_to_initialize(PhysicalAddress paddr, size_t index, size_t interrupt_number)
{
    auto registers_mapping = TRY(Memory::map_typed_writable<u8>(paddr));

    auto controller = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) RP1xHCIController(move(registers_mapping), index, interrupt_number)));
    TRY(controller->initialize());
    return controller;
}

UNMAP_AFTER_INIT RP1xHCIController::RP1xHCIController(Memory::TypedMapping<u8> registers_mapping, size_t index, size_t interrupt_number)
    : xHCIController(move(registers_mapping))
    , m_index(index)
    , m_interrupt_number(interrupt_number)
{
}

ErrorOr<OwnPtr<GenericInterruptHandler>> RP1xHCIController::create_interrupter(u16)
{
    // FIXME: Add interrupt support. This requires adding support for the BCM2712 MSI-X interrupt controller.
    return nullptr;
}

ErrorOr<void> RP1::try_to_initialize_xhci_controllers(PCI::DeviceIdentifier const& pci_identifier)
{
    PCI::enable_memory_space(pci_identifier);
    PCI::enable_bus_mastering(pci_identifier);

    auto bar1_address = TRY(get_bar_address(pci_identifier, PCI::HeaderType0BaseRegister::BAR1));

    // Chapter 5. USB, https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf
    // The interrupt numbers are taken from the devicetree.
    auto usbhost0 = TRY(RP1xHCIController::try_to_initialize(bar1_address.offset(0x20'0000), 0, 31));
    auto usbhost1 = TRY(RP1xHCIController::try_to_initialize(bar1_address.offset(0x30'0000), 1, 36));

    USB::USBManagement::the().add_controller(usbhost0);
    USB::USBManagement::the().add_controller(usbhost1);

    return {};
}

}