blob: 7168ecc6643130e2d3f0e090468b1d4654e06b49 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/uart/all.h>
#include <lib/uart/null.h>
#include <dev/hdcp/amlogic_s912/init.h>
#include <dev/hw_rng/amlogic_rng/init.h>
#include <dev/hw_watchdog/generic32/init.h>
#include <dev/init.h>
#include <dev/interrupt/arm_gicv2_init.h>
#include <dev/interrupt/arm_gicv3_init.h>
#include <dev/power/as370/init.h>
#include <dev/power/motmot/init.h>
#include <dev/psci.h>
#include <dev/timer/arm_generic.h>
#include <dev/uart/amlogic_s905/init.h>
#include <dev/uart/dw8250/init.h>
#include <dev/uart/motmot/init.h>
#include <dev/uart/pl011/init.h>
#include <ktl/type_traits.h>
#include <ktl/variant.h>
#include <phys/arch/arch-handoff.h>
#include <ktl/enforce.h>
namespace {
// Overloads to satisfy the degenerate 'no config present' case in
// `ktl::visit(..., arch_handoff.gic_driver)` below. Related overloads defined
// in <dev/interrupt/arm_gicv{2,3}_init.h>.
void ArmGicInitEarly(const ktl::monostate& no_config) {}
void ArmGicInitLate(const ktl::monostate& no_config) {}
// Overloads for early UART initialization below.
void UartInitEarly(uint32_t extra, const uart::null::Driver::config_type& config) {}
void UartInitEarly(uint32_t extra, const dcfg_simple_t& config) {
switch (extra) {
case KDRV_AMLOGIC_UART:
AmlogicS905UartInitEarly(config);
break;
case KDRV_DW8250_UART:
Dw8250UartInitEarly(config);
break;
case KDRV_MOTMOT_UART:
MotmotUartInitEarly(config);
break;
case KDRV_PL011_UART:
Pl011UartInitEarly(config);
break;
}
}
void UartInitLate(uint32_t extra) {
switch (extra) {
case KDRV_AMLOGIC_UART:
AmlogicS905UartInitLate();
break;
case KDRV_DW8250_UART:
Dw8250UartInitLate();
break;
case KDRV_MOTMOT_UART:
MotmotUartInitLate();
break;
case KDRV_PL011_UART:
Pl011UartInitLate();
break;
}
}
} // namespace
void ArchDriverHandoffEarly(const ArchPhysHandoff& arch_handoff) {
// Configure the GIC first so that the remaining drivers can freely register
// interrupt handlers.
ktl::visit([](const auto& config) { ArmGicInitEarly(config); }, arch_handoff.gic_driver);
if (arch_handoff.generic_32bit_watchdog_driver) {
Generic32BitWatchdogEarlyInit(arch_handoff.generic_32bit_watchdog_driver.value());
}
if (arch_handoff.generic_timer_driver) {
ArmGenericTimerInit(arch_handoff.generic_timer_driver.value());
}
if (arch_handoff.psci_driver) {
PsciInit(arch_handoff.psci_driver.value());
}
if (arch_handoff.as370_power_driver) {
as370_power_init_early();
}
if (arch_handoff.motmot_power_driver) {
motmot_power_init_early();
}
}
void ArchDriverHandoffLate(const ArchPhysHandoff& arch_handoff) {
// First, as above.
ktl::visit([](const auto& config) { ArmGicInitLate(config); }, arch_handoff.gic_driver);
if (arch_handoff.amlogic_hdcp_driver) {
AmlogicS912HdcpInit(arch_handoff.amlogic_hdcp_driver.value());
}
if (arch_handoff.amlogic_rng_driver) {
AmlogicRngInit(arch_handoff.amlogic_rng_driver.value());
}
if (arch_handoff.generic_32bit_watchdog_driver) {
Generic32BitWatchdogLateInit();
}
}
void ArchUartDriverHandoffEarly(const uart::all::Driver& serial) {
ktl::visit([](const auto& uart) { UartInitEarly(uart.extra(), uart.config()); }, serial);
}
void ArchUartDriverHandoffLate(const uart::all::Driver& serial) {
ktl::visit([](const auto& uart) { UartInitLate(uart.extra()); }, serial);
}