mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-22 09:21:57 -05:00
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:
parent
d6d5379445
commit
e67330971c
14 changed files with 175 additions and 52 deletions
24
Kernel/Arch/aarch64/DebugOutput.cpp
Normal file
24
Kernel/Arch/aarch64/DebugOutput.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
19
Kernel/Arch/aarch64/DebugOutput.h
Normal file
19
Kernel/Arch/aarch64/DebugOutput.h
Normal 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*);
|
||||
|
||||
}
|
15
Kernel/Arch/aarch64/PlatformInit.h
Normal file
15
Kernel/Arch/aarch64/PlatformInit.h
Normal 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);
|
||||
|
||||
}
|
54
Kernel/Arch/aarch64/PlatformInit/RaspberryPi.cpp
Normal file
54
Kernel/Arch/aarch64/PlatformInit/RaspberryPi.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue