diff --git a/Kernel/Arch/aarch64/RPi/BroadcomSTBGPIOController.cpp b/Kernel/Arch/aarch64/RPi/BroadcomSTBGPIOController.cpp new file mode 100644 index 00000000000..8c7f9a7a979 --- /dev/null +++ b/Kernel/Arch/aarch64/RPi/BroadcomSTBGPIOController.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2026, Sönke Holz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Kernel::RPi { + +struct BroadcomSTBGPIOController::BankRegisters { + u32 _; + u32 pin_levels; + u32 pin_directions; + u32 _[5]; +}; + +static_assert(AssertSize()); + +ErrorOr> Kernel::RPi::BroadcomSTBGPIOController::create(PhysicalAddress paddr, Span bank_pin_counts) +{ + for (auto bank_pin_count : bank_pin_counts) { + if (bank_pin_count > 32) { + return EINVAL; + } + } + + auto bank_count = bank_pin_counts.size(); + auto registers = TRY(Memory::map_typed_array(paddr, bank_count, Memory::Region::Access::ReadWrite)); + + auto bank_pin_counts_array = TRY(FixedArray::create(bank_pin_counts)); + return adopt_nonnull_own_or_enomem(new (nothrow) BroadcomSTBGPIOController(move(registers), move(bank_pin_counts_array))); +} + +ErrorOr Kernel::RPi::BroadcomSTBGPIOController::set_pin_output_level(u32 pin_number, LogicLevel level) +{ + auto bank_number = pin_number / 32; + auto pin_number_in_bank = pin_number % 32; + + if (bank_number >= m_bank_pin_counts.size()) + return EINVAL; + + if (pin_number_in_bank >= m_bank_pin_counts[bank_number]) + return EINVAL; + + if (level == LogicLevel::High) + m_bank_registers[bank_number].pin_levels |= 1u << pin_number_in_bank; + else + m_bank_registers[bank_number].pin_levels &= ~(1u << pin_number_in_bank); + + return {}; +} + +ErrorOr Kernel::RPi::BroadcomSTBGPIOController::set_pin_direction(u32 pin_number, PinDirection direction) +{ + auto bank_number = pin_number / 32; + auto pin_number_in_bank = pin_number % 32; + + if (bank_number >= m_bank_pin_counts.size()) + return EINVAL; + + if (pin_number_in_bank >= m_bank_pin_counts[bank_number]) + return EINVAL; + + if (direction == PinDirection::Input) + m_bank_registers[bank_number].pin_directions |= 1u << pin_number_in_bank; + else + m_bank_registers[bank_number].pin_directions &= ~(1u << pin_number_in_bank); + + return {}; +} + +BroadcomSTBGPIOController::BroadcomSTBGPIOController(Memory::TypedMapping bank_registers, FixedArray bank_pin_counts) + : m_bank_registers(move(bank_registers)) + , m_bank_pin_counts(move(bank_pin_counts)) +{ +} + +} diff --git a/Kernel/Arch/aarch64/RPi/BroadcomSTBGPIOController.h b/Kernel/Arch/aarch64/RPi/BroadcomSTBGPIOController.h new file mode 100644 index 00000000000..b613db9cf78 --- /dev/null +++ b/Kernel/Arch/aarch64/RPi/BroadcomSTBGPIOController.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2026, Sönke Holz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Kernel::RPi { + +class BroadcomSTBGPIOController { +public: + static ErrorOr> create(PhysicalAddress, Span bank_pin_counts); + + enum class LogicLevel : bool { + Low = 0, + High = 1, + }; + + enum class PinDirection : u8 { + Input = 0, + Output = 1, + }; + + ErrorOr set_pin_output_level(u32 pin_number, LogicLevel); + ErrorOr set_pin_direction(u32 pin_number, PinDirection); + + struct BankRegisters; + +private: + BroadcomSTBGPIOController(Memory::TypedMapping, FixedArray bank_pin_counts); + + Memory::TypedMapping m_bank_registers; + FixedArray m_bank_pin_counts; +}; + +} diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 15cd9811160..7b156a28614 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -490,6 +490,7 @@ elseif("${SERENITY_ARCH}" STREQUAL "aarch64") Arch/aarch64/RPi/RP1/RP1.cpp Arch/aarch64/RPi/RP1/xHCI.cpp Arch/aarch64/RPi/SDHostController.cpp + Arch/aarch64/RPi/BroadcomSTBGPIOController.cpp Arch/aarch64/RPi/Timer.cpp Arch/aarch64/RPi/V3D/DeviceNode.cpp Arch/aarch64/RPi/V3D/PageTable.cpp