Kernel/aarch64: Use a platform init function for most of the RPi code

This required making the `debug_output` console configurable at runtime
by introducing a `DebugConsole` struct, which simply contains a callback
for printing a single character.
We should probably use something like this abstraction for all
architectures in the future.
This commit is contained in:
Sönke Holz 2024-12-06 17:40:41 +01:00
parent d6d5379445
commit e67330971c
14 changed files with 175 additions and 52 deletions

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Arch/aarch64/DebugOutput.h>
namespace Kernel {
static DebugConsole const* s_debug_console;
void set_debug_console(DebugConsole const* debug_console)
{
s_debug_console = debug_console;
}
void debug_output(char character)
{
if (s_debug_console != nullptr)
s_debug_console->write_character(character);
}
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <Kernel/Arch/DebugOutput.h>
namespace Kernel {
struct DebugConsole {
void (*write_character)(char);
};
void set_debug_console(DebugConsole const*);
}

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/StringView.h>
namespace Kernel {
void raspberry_pi_platform_init(StringView compatible_string);
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2021, Nico Weber <thakis@chromium.org>
* Copyright (c) 2024, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Arch/aarch64/PlatformInit.h>
#include <Kernel/Arch/aarch64/DebugOutput.h>
#include <Kernel/Arch/aarch64/RPi/Framebuffer.h>
#include <Kernel/Arch/aarch64/RPi/GPIO.h>
#include <Kernel/Arch/aarch64/RPi/Mailbox.h>
#include <Kernel/Arch/aarch64/RPi/Timer.h>
#include <Kernel/Arch/aarch64/RPi/UART.h>
namespace Kernel {
void raspberry_pi_platform_init(StringView)
{
static DebugConsole const s_debug_console {
.write_character = [](char character) {
RPi::UART::the().send(character);
},
};
RPi::Mailbox::initialize();
RPi::GPIO::initialize();
RPi::UART::initialize();
constexpr int baud_rate = 115'200;
// Set UART clock so that the baud rate divisor ends up as 1.0.
// FIXME: Not sure if this is a good UART clock rate.
u32 rate_in_hz = RPi::Timer::set_clock_rate(RPi::Timer::ClockID::UART, 16 * baud_rate);
// The BCM's PL011 UART is alternate function 0 on pins 14 and 15.
auto& gpio = RPi::GPIO::the();
gpio.set_pin_function(14, RPi::GPIO::PinFunction::Alternate0);
gpio.set_pin_function(15, RPi::GPIO::PinFunction::Alternate0);
gpio.set_pin_pull_up_down_state(Array { 14, 15 }, RPi::GPIO::PullUpDownState::Disable);
// Clock and pins are configured. Turn UART on.
RPi::UART::the().set_baud_rate(baud_rate, rate_in_hz);
set_debug_console(&s_debug_console);
auto firmware_version = RPi::Mailbox::the().query_firmware_version();
dmesgln("RPi: Firmware version: {}", firmware_version);
RPi::Framebuffer::initialize();
}
}

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/Arch/DebugOutput.h>
#include <Kernel/Arch/aarch64/RPi/UART.h>
namespace Kernel {
void debug_output(char ch)
{
if (!Memory::MemoryManager::is_initialized())
return;
RPi::UART::the().send(ch);
}
}

View file

@ -38,15 +38,27 @@ struct GPIOControlRegisters {
u32 test;
};
static Singleton<GPIO> s_the;
GPIO::GPIO()
: m_registers(MMIO::the().peripheral<GPIOControlRegisters>(0x20'0000).release_value_but_fixme_should_propagate_errors())
{
}
void GPIO::initialize()
{
s_the.ensure_instance();
}
bool GPIO::is_initialized()
{
return s_the.is_initialized();
}
GPIO& GPIO::the()
{
static Singleton<GPIO> instance;
return instance;
VERIFY(is_initialized());
return s_the;
}
void GPIO::set_pin_function(unsigned pin_number, PinFunction function)

View file

@ -30,6 +30,8 @@ public:
Alternate5 = 0b010,
};
static void initialize();
static bool is_initialized();
static GPIO& the();
void set_pin_function(unsigned pin_number, PinFunction);

View file

@ -38,6 +38,8 @@ constexpr u32 MBOX_EMPTY = 0x4000'0000;
constexpr int ARM_TO_VIDEOCORE_CHANNEL = 8;
static Singleton<Mailbox> s_the;
Mailbox::Mailbox()
: m_registers(MMIO::the().peripheral<MailboxRegisters>(0xb880).release_value_but_fixme_should_propagate_errors())
{
@ -61,10 +63,20 @@ bool Mailbox::MessageHeader::success() const
return m_command_tag == MBOX_RESPONSE_SUCCESS;
}
void Mailbox::initialize()
{
s_the.ensure_instance();
}
bool Mailbox::is_initialized()
{
return s_the.is_initialized();
}
Mailbox& Mailbox::the()
{
static Singleton<Mailbox> instance;
return instance;
VERIFY(is_initialized());
return s_the;
}
void Mailbox::wait_until_we_can_write() const

View file

@ -51,6 +51,8 @@ public:
u32 m_empty_tag = 0;
};
static void initialize();
static bool is_initialized();
static Mailbox& the();
// Sends message queue to VideoCore

View file

@ -5,9 +5,7 @@
*/
#include <AK/Singleton.h>
#include <Kernel/Arch/aarch64/RPi/GPIO.h>
#include <Kernel/Arch/aarch64/RPi/MMIO.h>
#include <Kernel/Arch/aarch64/RPi/Timer.h>
#include <Kernel/Arch/aarch64/RPi/UART.h>
namespace Kernel::RPi {
@ -90,6 +88,8 @@ enum ControlBits {
CTSHardwareFlowControlEnable = 1 << 15,
};
static Singleton<UART> s_the;
UART::UART()
: m_registers(MMIO::the().peripheral<UARTRegisters>(0x20'1000).release_value_but_fixme_should_propagate_errors())
{
@ -98,29 +98,25 @@ UART::UART()
// FIXME: Should wait for current transmission to end and should flush FIFO.
constexpr int baud_rate = 115'200;
// Set UART clock so that the baud rate divisor ends up as 1.0.
// FIXME: Not sure if this is a good UART clock rate.
u32 rate_in_hz = Timer::set_clock_rate(Timer::ClockID::UART, 16 * baud_rate);
// The BCM's PL011 UART is alternate function 0 on pins 14 and 15.
auto& gpio = GPIO::the();
gpio.set_pin_function(14, GPIO::PinFunction::Alternate0);
gpio.set_pin_function(15, GPIO::PinFunction::Alternate0);
gpio.set_pin_pull_up_down_state(Array { 14, 15 }, GPIO::PullUpDownState::Disable);
// Clock and pins are configured. Turn UART on.
set_baud_rate(baud_rate, rate_in_hz);
m_registers->line_control = EnableFIFOs | WordLength8Bits;
m_registers->control = UARTEnable | TransmitEnable | ReceiveEnable;
}
void UART::initialize()
{
s_the.ensure_instance();
}
bool UART::is_initialized()
{
return s_the.is_initialized();
}
UART& UART::the()
{
static Singleton<UART> instance;
return instance;
VERIFY(is_initialized());
return s_the;
}
void UART::send(u32 c)

View file

@ -19,6 +19,8 @@ struct UARTRegisters;
class UART {
public:
UART();
static void initialize();
static bool is_initialized();
static UART& the();
void send(u32 c);
@ -26,8 +28,9 @@ public:
void print_str(char const*, size_t);
private:
void set_baud_rate(int baud_rate, int uart_frequency_in_hz);
private:
void wait_until_we_can_send();
void wait_until_we_can_receive();

View file

@ -198,13 +198,6 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT NO_SANITIZE_COVERAGE void init([[maybe_
DeviceTree::run_platform_init();
#endif
#if ARCH(AARCH64)
auto firmware_version = RPi::Mailbox::the().query_firmware_version();
dmesgln("RPi: Firmware version: {}", firmware_version);
RPi::Framebuffer::initialize();
#endif
// NOTE: If the bootloader provided a framebuffer, then set up an initial console.
// If the bootloader didn't provide a framebuffer, then set up an initial text console.
// We do so we can see the output on the screen as soon as possible.

View file

@ -473,7 +473,6 @@ if ("${SERENITY_ARCH}" STREQUAL "x86_64")
elseif("${SERENITY_ARCH}" STREQUAL "aarch64")
set(RPI_SOURCES
Arch/aarch64/RPi/AUX.cpp
Arch/aarch64/RPi/DebugOutput.cpp
Arch/aarch64/RPi/Framebuffer.cpp
Arch/aarch64/RPi/GPIO.cpp
Arch/aarch64/RPi/InterruptController.cpp
@ -503,6 +502,7 @@ elseif("${SERENITY_ARCH}" STREQUAL "aarch64")
Arch/aarch64/boot.S
Arch/aarch64/CPUID.cpp
Arch/aarch64/CurrentTime.cpp
Arch/aarch64/DebugOutput.cpp
Arch/aarch64/Dummy.cpp
Arch/aarch64/FPUState.S
Arch/aarch64/InterruptManagement.cpp
@ -514,6 +514,8 @@ elseif("${SERENITY_ARCH}" STREQUAL "aarch64")
Arch/aarch64/SafeMem.cpp
Arch/aarch64/SmapDisabler.cpp
Arch/aarch64/vector_table.S
Arch/aarch64/PlatformInit/RaspberryPi.cpp
)
# Otherwise linker errors e.g undefined reference to `__aarch64_cas8_acq_rel'

View file

@ -10,6 +10,10 @@
#include <Kernel/Firmware/DeviceTree/PlatformInit.h>
#include <LibDeviceTree/FlattenedDeviceTree.h>
#if ARCH(AARCH64)
# include <Kernel/Arch/aarch64/PlatformInit.h>
#endif
namespace Kernel::DeviceTree {
struct PlatformInitTableEntry {
@ -17,7 +21,12 @@ struct PlatformInitTableEntry {
void (*init_function)(StringView compatible_string);
};
static constinit auto const s_platform_init_table = to_array<PlatformInitTableEntry>({});
static constinit auto const s_platform_init_table = to_array<PlatformInitTableEntry>({
#if ARCH(AARCH64)
{ "raspberrypi,3-model-b"sv, raspberry_pi_platform_init },
{ "raspberrypi,4-model-b"sv, raspberry_pi_platform_init },
#endif
});
void run_platform_init()
{