mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 04:29:30 -10:00
Kernel/aarch64: Properly reset the Pi 5's Ethernet PHY via its reset pin
I previously didn't notice this was necessary since I always use netboot to boot the kernel on my Pi 5. When using netboot, the firmware resets the PHY for us. Similar to the fan driver, this code now hardcodes the reset pin number. In the future, it might be a better idea to use the devicetree for this. Upstream linux and the downstream Raspberry Pi fork unfortunately have incompatible devicetree bindings, so we will have choose one of them.
This commit is contained in:
1 parent
5962730d78
commit
b592b8a059
5 files changed
+31
-6
No files matched your search
@@ -4,14 +4,19 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Arch/Delay.h>
|
||||
#include <Kernel/Arch/aarch64/RPi/RP1/GEM.h>
|
||||
#include <Kernel/Arch/aarch64/RPi/RP1/GPIO.h>
|
||||
#include <Kernel/Arch/aarch64/RPi/RP1/RP1.h>
|
||||
#include <Kernel/Firmware/DeviceTree/DeviceTree.h>
|
||||
#include <Kernel/Net/Cadence/GEMRegisters.h>
|
||||
|
||||
namespace Kernel::RPi {
|
||||
|
||||
ErrorOr<NonnullRefPtr<RP1GEMNetworkAdapter>> 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<NonnullRefPtr<RP1GEMNetworkAdapter>> RP1GEMNetworkAdapter::create(RP1& rp1, RP1GPIO& rp1_gpio, StringView interface_name, PhysicalAddress paddr, InterruptNumber interrupt_number)
|
||||
{
|
||||
auto registers_mapping = TRY(Memory::map_typed_writable<CadenceGEMNetworkAdapter::Registers volatile>(paddr));
|
||||
|
||||
@@ -28,19 +33,33 @@ ErrorOr<NonnullRefPtr<RP1GEMNetworkAdapter>> 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<CadenceGEMNetworkAdapter::Registers volatile> registers, InterruptNumber interrupt_number)
|
||||
RP1GEMNetworkAdapter::RP1GEMNetworkAdapter(RP1& rp1, RP1GPIO& rp1_gpio, StringView interface_name, MACAddress mac_address, Memory::TypedMapping<CadenceGEMNetworkAdapter::Registers volatile> 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
|
||||
|
||||
@@ -12,18 +12,21 @@
|
||||
namespace Kernel::RPi {
|
||||
|
||||
class RP1;
|
||||
class RP1GPIO;
|
||||
|
||||
class RP1GEMNetworkAdapter final : public CadenceGEMNetworkAdapter {
|
||||
public:
|
||||
static ErrorOr<NonnullRefPtr<RP1GEMNetworkAdapter>> create(RP1&, StringView interface_name, PhysicalAddress, InterruptNumber);
|
||||
static ErrorOr<NonnullRefPtr<RP1GEMNetworkAdapter>> create(RP1&, RP1GPIO&, StringView interface_name, PhysicalAddress, InterruptNumber);
|
||||
|
||||
private:
|
||||
RP1GEMNetworkAdapter(RP1&, StringView interface_name, MACAddress, Memory::TypedMapping<CadenceGEMNetworkAdapter::Registers volatile>, InterruptNumber);
|
||||
RP1GEMNetworkAdapter(RP1&, RP1GPIO&, StringView interface_name, MACAddress, Memory::TypedMapping<CadenceGEMNetworkAdapter::Registers volatile>, 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 };
|
||||
};
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ ErrorOr<void> 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();
|
||||
|
||||
|
||||
@@ -152,6 +152,8 @@ ErrorOr<void> 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());
|
||||
|
||||
@@ -49,6 +49,7 @@ protected:
|
||||
ErrorOr<void> initialize_rx_descriptors();
|
||||
ErrorOr<void> initialize_tx_descriptors();
|
||||
|
||||
virtual void reset_phy() = 0;
|
||||
virtual void register_and_enable_interrupt() = 0;
|
||||
virtual u32 mdio_clock_input_frequency() = 0;
|
||||
|
||||
|
||||
Reference in new issue
Block a user