diff --git a/Kernel/Arch/aarch64/RPi/RP1/GEM.cpp b/Kernel/Arch/aarch64/RPi/RP1/GEM.cpp index 9e5922675ea..66335596c0d 100644 --- a/Kernel/Arch/aarch64/RPi/RP1/GEM.cpp +++ b/Kernel/Arch/aarch64/RPi/RP1/GEM.cpp @@ -4,14 +4,19 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include +#include #include #include #include namespace Kernel::RPi { -ErrorOr> RP1GEMNetworkAdapter::create(RP1& rp1, StringView interface_name, PhysicalAddress paddr, InterruptNumber interrupt_number) +// Taken from the devicetree. The reset pin is active-low. +static constexpr u32 PHY_RESET_GPIO_PIN = 32; + +ErrorOr> RP1GEMNetworkAdapter::create(RP1& rp1, RP1GPIO& rp1_gpio, StringView interface_name, PhysicalAddress paddr, InterruptNumber interrupt_number) { auto registers_mapping = TRY(Memory::map_typed_writable(paddr)); @@ -28,19 +33,33 @@ ErrorOr> RP1GEMNetworkAdapter::create(RP1& r return EINVAL; } - auto adapter = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) RP1GEMNetworkAdapter(rp1, interface_name, mac_address, move(registers_mapping), interrupt_number))); + rp1_gpio.set_output_override(PHY_RESET_GPIO_PIN, RP1GPIO::OutputOverride::ForceHigh); + rp1_gpio.set_output_enable_override(PHY_RESET_GPIO_PIN, RP1GPIO::OutputEnableOverride::ForceEnable); + rp1_gpio.set_pin_function(PHY_RESET_GPIO_PIN, RP1GPIO::FUNCTION_NONE); + rp1_gpio.set_pin_enabled(PHY_RESET_GPIO_PIN, true); + + auto adapter = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) RP1GEMNetworkAdapter(rp1, rp1_gpio, interface_name, mac_address, move(registers_mapping), interrupt_number))); TRY(adapter->initialize()); return adapter; } -RP1GEMNetworkAdapter::RP1GEMNetworkAdapter(RP1& rp1, StringView interface_name, MACAddress mac_address, Memory::TypedMapping registers, InterruptNumber interrupt_number) +RP1GEMNetworkAdapter::RP1GEMNetworkAdapter(RP1& rp1, RP1GPIO& rp1_gpio, StringView interface_name, MACAddress mac_address, Memory::TypedMapping registers, InterruptNumber interrupt_number) : CadenceGEMNetworkAdapter(interface_name, mac_address, move(registers)) , m_rp1(rp1) + , m_rp1_gpio(rp1_gpio) , m_interrupt_number(interrupt_number) { } +void RP1GEMNetworkAdapter::reset_phy() +{ + // The 5 ms PHY reset time is taken from the devicetree. + m_rp1_gpio.set_output_override(PHY_RESET_GPIO_PIN, RP1GPIO::OutputOverride::ForceLow); + microseconds_delay(5'000); + m_rp1_gpio.set_output_override(PHY_RESET_GPIO_PIN, RP1GPIO::OutputOverride::ForceHigh); +} + void RP1GEMNetworkAdapter::register_and_enable_interrupt() { // 6.2. MSIx configuration registers diff --git a/Kernel/Arch/aarch64/RPi/RP1/GEM.h b/Kernel/Arch/aarch64/RPi/RP1/GEM.h index 6671b610117..8441e2a291f 100644 --- a/Kernel/Arch/aarch64/RPi/RP1/GEM.h +++ b/Kernel/Arch/aarch64/RPi/RP1/GEM.h @@ -12,18 +12,21 @@ namespace Kernel::RPi { class RP1; +class RP1GPIO; class RP1GEMNetworkAdapter final : public CadenceGEMNetworkAdapter { public: - static ErrorOr> create(RP1&, StringView interface_name, PhysicalAddress, InterruptNumber); + static ErrorOr> create(RP1&, RP1GPIO&, StringView interface_name, PhysicalAddress, InterruptNumber); private: - RP1GEMNetworkAdapter(RP1&, StringView interface_name, MACAddress, Memory::TypedMapping, InterruptNumber); + RP1GEMNetworkAdapter(RP1&, RP1GPIO&, StringView interface_name, MACAddress, Memory::TypedMapping, InterruptNumber); + virtual void reset_phy() override; virtual void register_and_enable_interrupt() override; virtual u32 mdio_clock_input_frequency() override; RP1& m_rp1; + RP1GPIO& m_rp1_gpio; InterruptNumber m_interrupt_number { 0 }; }; diff --git a/Kernel/Arch/aarch64/RPi/RP1/RP1.cpp b/Kernel/Arch/aarch64/RPi/RP1/RP1.cpp index 1b099d15b86..e3fc7e661c7 100644 --- a/Kernel/Arch/aarch64/RPi/RP1/RP1.cpp +++ b/Kernel/Arch/aarch64/RPi/RP1/RP1.cpp @@ -77,7 +77,7 @@ ErrorOr RP1::initialize() // Chapter 7. Ethernet auto gem_interface_name = TRY(NetworkingManagement::generate_interface_name_from_pci_address(device_identifier())); - auto gem = TRY(RP1GEMNetworkAdapter::create(*this, gem_interface_name.representable_view(), bar1_address.offset(0x10'0000), 6)); + auto gem = TRY(RP1GEMNetworkAdapter::create(*this, gpio, gem_interface_name.representable_view(), bar1_address.offset(0x10'0000), 6)); NetworkingManagement::the().register_adapter(gem).release_value_but_fixme_should_propagate_errors(); diff --git a/Kernel/Net/Cadence/GEM.cpp b/Kernel/Net/Cadence/GEM.cpp index 287eedbac65..7fcd9e12a0a 100644 --- a/Kernel/Net/Cadence/GEM.cpp +++ b/Kernel/Net/Cadence/GEM.cpp @@ -152,6 +152,8 @@ ErrorOr CadenceGEMNetworkAdapter::initialize() m_registers->network_control |= Registers::NetworkControl::EnableManagementPort; + reset_phy(); + m_mdio_handling_process = TRY(spawn_mdio_handling_task(PHY_ID)); TRY(initialize_rx_descriptors()); diff --git a/Kernel/Net/Cadence/GEM.h b/Kernel/Net/Cadence/GEM.h index 8815239dc7b..40cc3a4fa50 100644 --- a/Kernel/Net/Cadence/GEM.h +++ b/Kernel/Net/Cadence/GEM.h @@ -49,6 +49,7 @@ protected: ErrorOr initialize_rx_descriptors(); ErrorOr initialize_tx_descriptors(); + virtual void reset_phy() = 0; virtual void register_and_enable_interrupt() = 0; virtual u32 mdio_clock_input_frequency() = 0;