// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "RT1051LPMCommon.hpp" #include #include #include #include "Oscillator.hpp" #include "drivers/semc/DriverSEMC.hpp" #include #include "DCDC.hpp" namespace bsp { using namespace drivers; RT1051LPMCommon::RT1051LPMCommon() { driverSEMC = drivers::DriverSEMC::Create(drivers::name::ExternalRAM); CpuFreq = std::make_unique(); } std::int32_t RT1051LPMCommon::PowerOff() { board_power_off(); return 0; } std::int32_t RT1051LPMCommon::Reboot(RebootType reason) { switch (reason) { case RebootType::GoToRecoveryUpdate: set_boot_reason(boot_reason_code_update); break; case RebootType::GoToRecoveryRecovery: set_boot_reason(boot_reason_code_recovery); break; case RebootType::GoToRecoveryFactoryReset: set_boot_reason(boot_reason_code_factory); break; case RebootType::GoToRecoveryBackup: set_boot_reason(boot_reason_code_backup); break; case RebootType::GoToRecoveryRestore: set_boot_reason(boot_reason_code_restore); break; case RebootType::NormalRestart: set_boot_reason(boot_reason_code_os); break; default: set_boot_reason(boot_reason_code_unknown); } board_restart(); return 0; } enum class Change { Up, Down }; void RT1051LPMCommon::onChangeUp(CpuFrequencyMHz freq, CpuFrequencyMHz newFrequency) { if ((freq <= CpuFrequencyMHz::Level_1) && (newFrequency > CpuFrequencyMHz::Level_1)) { /* Switch to external crystal oscillator */ SwitchOscillatorSource(LowPowerMode::OscillatorSource::External); /* Switch external RAM clock source to PLL2 */ if (driverSEMC) { driverSEMC->SwitchToPLL2ClockSource(); } } } void RT1051LPMCommon::onChangeDown(CpuFrequencyMHz newFrequency) { if (newFrequency <= CpuFrequencyMHz::Level_1) { /* Switch to internal RC oscillator */ SwitchOscillatorSource(LowPowerMode::OscillatorSource::Internal); /* Switch external RAM clock source to OSC */ if (driverSEMC) { driverSEMC->SwitchToPeripheralClockSource(); } } } void RT1051LPMCommon::SetCpuFrequency(CpuFrequencyMHz freq) { if (currentFrequency == freq) { return; } /* Switch to overdrive config for any frequency change above 12MHz */ const auto isChangeAbove12MHz = (currentFrequency > CpuFrequencyMHz::Level_1) || (freq > CpuFrequencyMHz::Level_1); if (isChangeAbove12MHz) { dcdc::SwitchToOverdriveConfig(); } const auto changeDirection = (currentFrequency < freq) ? Change::Up : Change::Down; if (Change::Up == changeDirection) { onChangeUp(currentFrequency, freq); } switch (freq) { case CpuFrequencyMHz::Level_0: CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Osc_4_Mhz); break; case CpuFrequencyMHz::Level_1: CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Osc_12_Mhz); break; case CpuFrequencyMHz::Level_2: CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Osc_24_Mhz); break; case CpuFrequencyMHz::Level_3: CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_66_Mhz); break; case CpuFrequencyMHz::Level_4: CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_132_Mhz); break; case CpuFrequencyMHz::Level_5: CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_264_Mhz); break; case CpuFrequencyMHz::Level_6: CpuFreq->SetCpuFrequency(CpuFreqLPM::CpuClock::CpuClock_Pll2_528_Mhz); break; } /* Switch back to regular config after clock change is done */ if (isChangeAbove12MHz) { dcdc::SwitchToRegularConfig(); } if (Change::Down == changeDirection) { onChangeDown(freq); } LOG_INFO("CPU frequency changed to %lu", CLOCK_GetFreq(kCLOCK_CpuClk)); currentFrequency = freq; } std::uint32_t RT1051LPMCommon::GetCpuFrequency() const noexcept { return CLOCK_GetCpuClkFreq(); } void RT1051LPMCommon::SwitchOscillatorSource(LowPowerMode::OscillatorSource source) { switch (source) { case LowPowerMode::OscillatorSource::Internal: SwitchToInternalOscillator(); break; case LowPowerMode::OscillatorSource::External: SwitchToExternalOscillator(); break; } } } // namespace bsp