mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
242 lines
8.4 KiB
C
242 lines
8.4 KiB
C
/*
|
|
* Copyright (C) 2015 Eistec AB
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser General
|
|
* Public License v2.1. See the file LICENSE in the top level directory for more
|
|
* details.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include "cpu.h"
|
|
#include "board.h"
|
|
|
|
/**
|
|
* @ingroup cpu_k60
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Implementation of K60 CPU initialization.
|
|
*
|
|
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
|
*/
|
|
|
|
/** @brief Current core clock frequency */
|
|
uint32_t SystemCoreClock = DEFAULT_SYSTEM_CLOCK;
|
|
/** @brief Current system clock frequency */
|
|
uint32_t SystemSysClock = DEFAULT_SYSTEM_CLOCK;
|
|
/** @brief Current bus clock frequency */
|
|
uint32_t SystemBusClock = DEFAULT_SYSTEM_CLOCK;
|
|
/** @brief Current FlexBus clock frequency */
|
|
uint32_t SystemFlexBusClock = DEFAULT_SYSTEM_CLOCK;
|
|
/** @brief Current flash clock frequency */
|
|
uint32_t SystemFlashClock = DEFAULT_SYSTEM_CLOCK;
|
|
/** @brief Number of full PIT ticks in one microsecond. */
|
|
uint32_t PIT_ticks_per_usec = (DEFAULT_SYSTEM_CLOCK / 1000000ul);
|
|
|
|
/**
|
|
* @brief Check the running CPU identification to find if we are running on the
|
|
* wrong hardware.
|
|
*/
|
|
static void check_running_cpu_revision(void);
|
|
|
|
/**
|
|
* @brief Initialize the CPU, set IRQ priorities
|
|
*/
|
|
void cpu_init(void)
|
|
{
|
|
/* initialize the Cortex-M core */
|
|
cortexm_init();
|
|
/* Check that we are running on the CPU that this code was built for */
|
|
check_running_cpu_revision();
|
|
}
|
|
|
|
static void check_running_cpu_revision(void)
|
|
{
|
|
/* Check that the running CPU revision matches the compiled revision */
|
|
if (SCB->CPUID != K60_EXPECTED_CPUID) {
|
|
uint32_t CPUID = SCB->CPUID; /* This is only to ease debugging, type
|
|
* "print /x CPUID" in gdb */
|
|
uint32_t SILICON_REVISION = (SCB->CPUID & SCB_CPUID_REVISION_Msk) + 1;
|
|
(void)CPUID; /* prevents compiler warnings about an unused variable. */
|
|
(void)SILICON_REVISION;
|
|
|
|
/* Running on the wrong CPU, the clock initialization is different
|
|
* between silicon revision 1.x and 2.x (LSB of CPUID) */
|
|
/* If you unexpectedly end up on this line when debugging:
|
|
* Rebuild the code using the correct value for K60_CPU_REV */
|
|
__ASM volatile ("bkpt #99\n");
|
|
|
|
while (1);
|
|
}
|
|
}
|
|
|
|
void SystemCoreClockUpdate(void)
|
|
{
|
|
/* Variable to store output clock frequency of the MCG module */
|
|
uint32_t MCGOUT_clock;
|
|
|
|
if ((MCG->C1 & MCG_C1_CLKS_MASK) == 0x0u) {
|
|
/* Output of FLL or PLL is selected */
|
|
if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u) {
|
|
/* FLL is selected */
|
|
if ((MCG->C1 & MCG_C1_IREFS_MASK) == 0x0u) {
|
|
/* External reference clock is selected */
|
|
#if K60_CPU_REV == 1
|
|
/* rev.1 silicon */
|
|
if ((SIM->SOPT2 & SIM_SOPT2_MCGCLKSEL_MASK) == 0x0u) {
|
|
/* System oscillator drives MCG clock */
|
|
MCGOUT_clock = CPU_XTAL_CLK_HZ;
|
|
}
|
|
else {
|
|
/* RTC 32 kHz oscillator drives MCG clock */
|
|
MCGOUT_clock = CPU_XTAL32k_CLK_HZ;
|
|
}
|
|
|
|
#else /* K60_CPU_REV */
|
|
|
|
/* rev.2 silicon */
|
|
if ((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u) {
|
|
/* System oscillator drives MCG clock */
|
|
MCGOUT_clock = CPU_XTAL_CLK_HZ;
|
|
}
|
|
else {
|
|
/* RTC 32 kHz oscillator drives MCG clock */
|
|
MCGOUT_clock = CPU_XTAL32k_CLK_HZ;
|
|
}
|
|
|
|
#endif /* K60_CPU_REV */
|
|
uint8_t divider = (uint8_t)(1u << ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT));
|
|
/* Calculate the divided FLL reference clock */
|
|
MCGOUT_clock /= divider;
|
|
|
|
if ((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x0u) {
|
|
/* If high range is enabled, additional 32 divider is active */
|
|
MCGOUT_clock /= 32u;
|
|
}
|
|
}
|
|
else {
|
|
/* The slow internal reference clock is selected */
|
|
MCGOUT_clock = CPU_INT_SLOW_CLK_HZ;
|
|
}
|
|
|
|
/* Select correct multiplier to calculate the MCG output clock */
|
|
switch (MCG->C4 & (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) {
|
|
case (0x0u):
|
|
MCGOUT_clock *= 640u;
|
|
break;
|
|
|
|
case (MCG_C4_DRST_DRS(0b01)): /* 0x20u */
|
|
MCGOUT_clock *= 1280u;
|
|
break;
|
|
|
|
case (MCG_C4_DRST_DRS(0b10)): /* 0x40u */
|
|
MCGOUT_clock *= 1920u;
|
|
break;
|
|
|
|
case (MCG_C4_DRST_DRS(0b11)): /* 0x60u */
|
|
MCGOUT_clock *= 2560u;
|
|
break;
|
|
|
|
case (MCG_C4_DMX32_MASK): /* 0x80u */
|
|
MCGOUT_clock *= 732u;
|
|
break;
|
|
|
|
case (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0b01)): /* 0xA0u */
|
|
MCGOUT_clock *= 1464u;
|
|
break;
|
|
|
|
case (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0b10)): /* 0xC0u */
|
|
MCGOUT_clock *= 2197u;
|
|
break;
|
|
|
|
case (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0b11)): /* 0xE0u */
|
|
MCGOUT_clock *= 2929u;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
/* PLL is selected */
|
|
/* Calculate the PLL reference clock */
|
|
uint8_t divider = (1u + (MCG->C5 & MCG_C5_PRDIV0_MASK));
|
|
MCGOUT_clock = (uint32_t)(CPU_XTAL_CLK_HZ / divider);
|
|
/* Calculate the MCG output clock */
|
|
divider = ((MCG->C6 & MCG_C6_VDIV0_MASK) + 24u);
|
|
MCGOUT_clock *= divider;
|
|
}
|
|
}
|
|
else if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0b01)) { /* 0x40u */
|
|
/* Internal reference clock is selected */
|
|
if ((MCG->C2 & MCG_C2_IRCS_MASK) == 0x0u) {
|
|
/* Slow internal reference clock selected */
|
|
MCGOUT_clock = CPU_INT_SLOW_CLK_HZ;
|
|
}
|
|
else {
|
|
/* Fast internal reference clock selected */
|
|
#if K60_CPU_REV == 1
|
|
/* rev.1 silicon */
|
|
MCGOUT_clock = CPU_INT_FAST_CLK_HZ;
|
|
#else /* K60_CPU_REV */
|
|
/* rev.2 silicon */
|
|
MCGOUT_clock = CPU_INT_FAST_CLK_HZ /
|
|
(1 << ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT));
|
|
#endif /* K60_CPU_REV */
|
|
}
|
|
}
|
|
else if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0b10)) { /* 0x80u */
|
|
/* External reference clock is selected */
|
|
#if K60_CPU_REV == 1
|
|
/* rev.1 silicon */
|
|
if ((SIM->SOPT2 & SIM_SOPT2_MCGCLKSEL_MASK) == 0x0u) {
|
|
/* System oscillator drives MCG clock */
|
|
MCGOUT_clock = CPU_XTAL_CLK_HZ;
|
|
}
|
|
else {
|
|
/* RTC 32 kHz oscillator drives MCG clock */
|
|
MCGOUT_clock = CPU_XTAL32k_CLK_HZ;
|
|
}
|
|
|
|
#else /* K60_CPU_REV */
|
|
|
|
/* rev.2 silicon */
|
|
if ((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u) {
|
|
/* System oscillator drives MCG clock */
|
|
MCGOUT_clock = CPU_XTAL_CLK_HZ;
|
|
}
|
|
else {
|
|
/* RTC 32 kHz oscillator drives MCG clock */
|
|
MCGOUT_clock = CPU_XTAL32k_CLK_HZ;
|
|
}
|
|
|
|
#endif /* K60_CPU_REV */
|
|
}
|
|
else {
|
|
/* Reserved value */
|
|
return;
|
|
}
|
|
|
|
/* Core clock and system clock use the same divider setting */
|
|
SystemCoreClock = SystemSysClock = (MCGOUT_clock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK)
|
|
>> SIM_CLKDIV1_OUTDIV1_SHIFT)));
|
|
SystemBusClock = (MCGOUT_clock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >>
|
|
SIM_CLKDIV1_OUTDIV2_SHIFT)));
|
|
SystemFlexBusClock = (MCGOUT_clock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV3_MASK) >>
|
|
SIM_CLKDIV1_OUTDIV3_SHIFT)));
|
|
SystemFlashClock = (MCGOUT_clock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >>
|
|
SIM_CLKDIV1_OUTDIV4_SHIFT)));
|
|
|
|
/* Module helper variables */
|
|
if (SystemBusClock >= 1000000) {
|
|
/* PIT module clock_delay_usec scale factor */
|
|
PIT_ticks_per_usec = (SystemBusClock + 500000) / 1000000; /* Rounded to nearest integer */
|
|
}
|
|
else {
|
|
/* less than 1 MHz clock frequency on the PIT module, round up. */
|
|
PIT_ticks_per_usec = 1;
|
|
}
|
|
}
|
|
|
|
/** @} */
|