2015-04-10 16:44:37 -07:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014-2015 Wind River Systems, Inc.
|
2016-07-23 10:13:01 -05:00
|
|
|
* Copyright (c) 2016, Freescale Semiconductor, Inc.
|
2015-04-10 16:44:37 -07:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2015-04-10 16:44:37 -07:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2015-04-10 16:44:37 -07:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
2015-04-10 16:44:37 -07:00
|
|
|
*/
|
|
|
|
|
2015-12-04 10:09:39 -05:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* @brief System/hardware module for fsl_frdm_k64f platform
|
|
|
|
*
|
2015-10-20 09:42:33 -07:00
|
|
|
* This module provides routines to initialize and support board-level
|
|
|
|
* hardware for the fsl_frdm_k64f platform.
|
2015-07-01 17:22:39 -04:00
|
|
|
*/
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
#include <nanokernel.h>
|
2015-07-14 10:28:51 -07:00
|
|
|
#include <device.h>
|
|
|
|
#include <init.h>
|
2015-12-17 08:54:35 -05:00
|
|
|
#include <soc.h>
|
2015-10-15 09:48:03 +03:00
|
|
|
#include <uart.h>
|
2015-04-10 16:44:37 -07:00
|
|
|
#include <sections.h>
|
2016-07-23 10:13:01 -05:00
|
|
|
#include <fsl_common.h>
|
2016-03-08 13:13:02 -08:00
|
|
|
#include <arch/cpu.h>
|
|
|
|
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/* board's setting for PLL multipler (PRDIV0) */
|
|
|
|
#define FRDM_K64F_PLL_DIV_20 (20 - 1)
|
|
|
|
|
|
|
|
/* board's setting for PLL multipler (VDIV0) */
|
|
|
|
#define FRDM_K64F_PLL_MULT_48 (48 - 24)
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
/* MCG register field encodings */
|
|
|
|
#define MCG_C1_CLKS_FLL_PLL (MCG_C1_CLKS(0))
|
|
|
|
#define MCG_C1_CLKS_EXT_REF (MCG_C1_CLKS(2))
|
|
|
|
#define MCG_C1_FRDIV_32_1024 (MCG_C1_FRDIV(5))
|
|
|
|
#define MCG_C1_IREFS_EXT (MCG_C1_IREFS(0))
|
|
|
|
#define MCG_C2_RANGE_VHIGH (MCG_C2_RANGE(2))
|
|
|
|
#define MCG_C2_HGO_LO_PWR (MCG_C2_HGO(0))
|
|
|
|
#define MCG_C2_EREFS_EXT_CLK (MCG_C2_EREFS(0))
|
|
|
|
#define MCG_C6_PLLS_PLL (MCG_C6_PLLS(1))
|
|
|
|
#define MCG_C7_OSCSEL_OSC0 (MCG_C7_OSCSEL(0))
|
|
|
|
#define MCG_S_CLKST_EXT_REF (MCG_S_CLKST(2))
|
|
|
|
#define MCG_S_CLKST_PLL (MCG_S_CLKST(3))
|
|
|
|
|
2015-04-10 16:44:37 -07:00
|
|
|
/*
|
|
|
|
* K64F Flash configuration fields
|
|
|
|
* These 16 bytes, which must be loaded to address 0x400, include default
|
|
|
|
* protection and security settings.
|
|
|
|
* They are loaded at reset to various Flash Memory module (FTFE) registers.
|
|
|
|
*
|
|
|
|
* The structure is:
|
|
|
|
* -Backdoor Comparison Key for unsecuring the MCU - 8 bytes
|
|
|
|
* -Program flash protection bytes, 4 bytes, written to FPROT0-3
|
|
|
|
* -Flash security byte, 1 byte, written to FSEC
|
|
|
|
* -Flash nonvolatile option byte, 1 byte, written to FOPT
|
|
|
|
* -Reserved, 1 byte, (Data flash protection byte for FlexNVM)
|
|
|
|
* -Reserved, 1 byte, (EEPROM protection byte for FlexNVM)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
uint8_t __security_frdm_k64f_section __security_frdm_k64f[] = {
|
|
|
|
/* Backdoor Comparison Key (unused) */
|
|
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
|
|
/* Program flash protection; 1 bit/region - 0=protected, 1=unprotected
|
2015-10-20 09:42:33 -07:00
|
|
|
*/
|
2015-04-10 16:44:37 -07:00
|
|
|
0xFF, 0xFF, 0xFF, 0xFF,
|
|
|
|
/*
|
|
|
|
* Flash security: Backdoor key disabled, Mass erase enabled,
|
|
|
|
* Factory access enabled, MCU is unsecure
|
|
|
|
*/
|
|
|
|
0xFE,
|
|
|
|
/* Flash nonvolatile option: NMI enabled, EzPort enabled, Normal boot */
|
|
|
|
0xFF,
|
|
|
|
/* Reserved for FlexNVM feature (unsupported by this MCU) */
|
|
|
|
0xFF, 0xFF};
|
|
|
|
|
2015-07-01 17:22:39 -04:00
|
|
|
/**
|
|
|
|
*
|
2015-07-01 17:51:40 -04:00
|
|
|
* @brief Initialize the system clock
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
|
|
|
* This routine will configure the multipurpose clock generator (MCG) to
|
|
|
|
* set up the system clock.
|
|
|
|
* The MCG has nine possible modes, including Stop mode. This routine assumes
|
|
|
|
* that the current MCG mode is FLL Engaged Internal (FEI), as from reset.
|
|
|
|
* It transitions through the FLL Bypassed External (FBE) and
|
|
|
|
* PLL Bypassed External (PBE) modes to get to the desired
|
2015-10-20 09:42:33 -07:00
|
|
|
* PLL Engaged External (PEE) mode and generate the maximum 120 MHz system
|
|
|
|
* clock.
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
2015-07-01 17:29:04 -04:00
|
|
|
* @return N/A
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
|
|
|
*/
|
2015-04-10 16:44:37 -07:00
|
|
|
|
2016-04-28 15:08:11 -07:00
|
|
|
static ALWAYS_INLINE void clkInit(void)
|
2015-04-10 16:44:37 -07:00
|
|
|
{
|
|
|
|
uint8_t temp_reg;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Select the 50 Mhz external clock as the MCG OSC clock.
|
|
|
|
* MCG Control 7 register:
|
|
|
|
* - Select OSCCLK0 / XTAL
|
|
|
|
*/
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
temp_reg = MCG->C7 & ~MCG_C7_OSCSEL_MASK;
|
2015-04-10 16:44:37 -07:00
|
|
|
temp_reg |= MCG_C7_OSCSEL_OSC0;
|
2016-07-23 10:13:01 -05:00
|
|
|
MCG->C7 = temp_reg;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Transition MCG from FEI mode (at reset) to FBE mode.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MCG Control 2 register:
|
|
|
|
* - Set oscillator frequency range = very high for 50 MHz external
|
|
|
|
* clock
|
|
|
|
* - Set oscillator mode = low power
|
|
|
|
* - Select external reference clock as the oscillator source
|
|
|
|
*/
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
temp_reg = MCG->C2 &
|
2015-04-10 16:44:37 -07:00
|
|
|
~(MCG_C2_RANGE_MASK | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK);
|
|
|
|
|
|
|
|
temp_reg |=
|
|
|
|
(MCG_C2_RANGE_VHIGH | MCG_C2_HGO_LO_PWR | MCG_C2_EREFS_EXT_CLK);
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
MCG->C2 = temp_reg;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* MCG Control 1 register:
|
|
|
|
* - Set system clock source (MCGOUTCLK) = external reference clock
|
|
|
|
* - Set FLL external reference divider = 1024 (MCG_C1_FRDIV_32_1024)
|
|
|
|
* to get the FLL frequency of 50 MHz/1024 = 48.828KHz
|
|
|
|
* (Note: If FLL frequency must be in the in 31.25KHz-39.0625KHz
|
|
|
|
*range,
|
|
|
|
* the FLL external reference divider = 1280
|
|
|
|
*(MCG_C1_FRDIV_64_1280)
|
|
|
|
* to get 50 MHz/1280 = 39.0625KHz)
|
|
|
|
* - Select the external reference clock as the FLL reference source
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
temp_reg = MCG->C1 &
|
2015-04-10 16:44:37 -07:00
|
|
|
~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK);
|
|
|
|
|
|
|
|
temp_reg |=
|
|
|
|
(MCG_C1_CLKS_EXT_REF | MCG_C1_FRDIV_32_1024 | MCG_C1_IREFS_EXT);
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
MCG->C1 = temp_reg;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
2015-10-20 09:42:33 -07:00
|
|
|
/*
|
|
|
|
* Confirm that the external reference clock is the FLL reference
|
|
|
|
* source
|
2015-04-10 16:44:37 -07:00
|
|
|
*/
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
while ((MCG->S & MCG_S_IREFST_MASK) != 0)
|
2015-04-10 16:44:37 -07:00
|
|
|
;
|
|
|
|
;
|
|
|
|
|
2015-10-20 09:42:33 -07:00
|
|
|
/*
|
|
|
|
* Confirm the external ref. clock is the system clock source
|
|
|
|
* (MCGOUTCLK)
|
|
|
|
*/
|
2015-04-10 16:44:37 -07:00
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_EXT_REF)
|
2015-04-10 16:44:37 -07:00
|
|
|
;
|
|
|
|
;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Transition to PBE mode.
|
|
|
|
* Configure the PLL frequency in preparation for PEE mode.
|
|
|
|
* The goal is PEE mode with a 120 MHz system clock source (MCGOUTCLK),
|
|
|
|
* which is calculated as (oscillator clock / PLL divider) * PLL
|
|
|
|
* multiplier,
|
|
|
|
* where oscillator clock = 50MHz, PLL divider = 20 and PLL multiplier =
|
|
|
|
* 48.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MCG Control 5 register:
|
|
|
|
* - Set the PLL divider
|
|
|
|
*/
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
temp_reg = MCG->C5 & ~MCG_C5_PRDIV0_MASK;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
temp_reg |= FRDM_K64F_PLL_DIV_20;
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
MCG->C5 = temp_reg;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* MCG Control 6 register:
|
|
|
|
* - Select PLL as output for PEE mode
|
|
|
|
* - Set the PLL multiplier
|
|
|
|
*/
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
temp_reg = MCG->C6 & ~(MCG_C6_PLLS_MASK | MCG_C6_VDIV0_MASK);
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
temp_reg |= (MCG_C6_PLLS_PLL | FRDM_K64F_PLL_MULT_48);
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
MCG->C6 = temp_reg;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/* Confirm that the PLL clock is selected as the PLL output */
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
while ((MCG->S & MCG_S_PLLST_MASK) == 0)
|
2015-04-10 16:44:37 -07:00
|
|
|
;
|
|
|
|
;
|
|
|
|
|
|
|
|
/* Confirm that the PLL has acquired lock */
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
while ((MCG->S & MCG_S_LOCK0_MASK) == 0)
|
2015-04-10 16:44:37 -07:00
|
|
|
;
|
|
|
|
;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Transition to PEE mode.
|
|
|
|
* MCG Control 1 register:
|
|
|
|
* - Select PLL as the system clock source (MCGOUTCLK)
|
|
|
|
*/
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
temp_reg = MCG->C1 & ~MCG_C1_CLKS_MASK;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
temp_reg |= MCG_C1_CLKS_FLL_PLL;
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
MCG->C1 = temp_reg;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/* Confirm that the PLL output is the system clock source (MCGOUTCLK) */
|
|
|
|
|
2016-07-23 10:13:01 -05:00
|
|
|
while ((MCG->S & MCG_S_CLKST_MASK) != MCG_S_CLKST_PLL)
|
2015-04-10 16:44:37 -07:00
|
|
|
;
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
2015-07-01 17:22:39 -04:00
|
|
|
/**
|
|
|
|
*
|
2015-07-01 17:51:40 -04:00
|
|
|
* @brief Perform basic hardware initialization
|
2015-07-01 17:22:39 -04:00
|
|
|
*
|
|
|
|
* Initialize the interrupt controller device drivers and the
|
|
|
|
* Kinetis UART device driver.
|
|
|
|
* Also initialize the timer device driver, if required.
|
|
|
|
*
|
2015-07-14 10:28:51 -07:00
|
|
|
* @return 0
|
2015-07-01 17:22:39 -04:00
|
|
|
*/
|
2015-04-10 16:44:37 -07:00
|
|
|
|
2015-07-14 10:28:51 -07:00
|
|
|
static int fsl_frdm_k64f_init(struct device *arg)
|
2015-04-10 16:44:37 -07:00
|
|
|
{
|
2015-07-14 10:28:51 -07:00
|
|
|
ARG_UNUSED(arg);
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
int oldLevel; /* old interrupt lock level */
|
|
|
|
uint32_t temp_reg;
|
|
|
|
|
|
|
|
/* disable interrupts */
|
|
|
|
oldLevel = irq_lock();
|
|
|
|
|
|
|
|
/* enable the port clocks */
|
2016-07-23 10:13:01 -05:00
|
|
|
SIM->SCGC5 |= (SIM_SCGC5_PORTA(1) | SIM_SCGC5_PORTB(1) |
|
|
|
|
SIM_SCGC5_PORTC(1) | SIM_SCGC5_PORTD(1) |
|
|
|
|
SIM_SCGC5_PORTE(1));
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/* release I/O power hold to allow normal run state */
|
2016-07-23 10:13:01 -05:00
|
|
|
PMC->REGSC |= PMC_REGSC_ACKISO_MASK;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Disable memory protection and clear slave port errors.
|
|
|
|
* Note that the K64F does not implement the optional ARMv7-M memory
|
|
|
|
* protection unit (MPU), specified by the architecture (PMSAv7), in the
|
|
|
|
* Cortex-M4 core. Instead, the processor includes its own MPU module.
|
|
|
|
*/
|
2016-07-23 10:13:01 -05:00
|
|
|
temp_reg = MPU->CESR;
|
|
|
|
temp_reg &= ~MPU_CESR_VLD_MASK;
|
|
|
|
temp_reg |= MPU_CESR_SPERR_MASK;
|
|
|
|
MPU->CESR = temp_reg;
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/* clear all faults */
|
|
|
|
|
|
|
|
_ScbMemFaultAllFaultsReset();
|
|
|
|
_ScbBusFaultAllFaultsReset();
|
|
|
|
_ScbUsageFaultAllFaultsReset();
|
|
|
|
|
|
|
|
_ScbHardFaultAllFaultsReset();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the clock dividers for:
|
|
|
|
* core and system clocks = 120 MHz (PLL/OUTDIV1)
|
|
|
|
* bus clock = 60 MHz (PLL/OUTDIV2)
|
|
|
|
* FlexBus clock = 40 MHz (PLL/OUTDIV3)
|
|
|
|
* Flash clock = 24 MHz (PLL/OUTDIV4)
|
|
|
|
*/
|
2016-07-23 10:13:01 -05:00
|
|
|
SIM->CLKDIV1 = (
|
|
|
|
SIM_CLKDIV1_OUTDIV1(CONFIG_K64_CORE_CLOCK_DIVIDER - 1) |
|
|
|
|
SIM_CLKDIV1_OUTDIV2(CONFIG_K64_BUS_CLOCK_DIVIDER - 1) |
|
|
|
|
SIM_CLKDIV1_OUTDIV3(CONFIG_K64_FLEXBUS_CLOCK_DIVIDER - 1) |
|
|
|
|
SIM_CLKDIV1_OUTDIV4(CONFIG_K64_FLASH_CLOCK_DIVIDER - 1));
|
2015-04-10 16:44:37 -07:00
|
|
|
|
2015-10-20 09:42:33 -07:00
|
|
|
/* Initialize PLL/system clock to 120 MHz */
|
|
|
|
clkInit();
|
2015-04-10 16:44:37 -07:00
|
|
|
|
2015-10-20 09:42:33 -07:00
|
|
|
/*
|
|
|
|
* install default handler that simply resets the CPU
|
2015-10-20 09:42:33 -07:00
|
|
|
* if configured in the kernel, NOP otherwise
|
2015-10-20 09:42:33 -07:00
|
|
|
*/
|
|
|
|
NMI_INIT();
|
2015-04-10 16:44:37 -07:00
|
|
|
|
|
|
|
/* restore interrupt state */
|
|
|
|
irq_unlock(oldLevel);
|
2015-07-14 10:28:51 -07:00
|
|
|
return 0;
|
2015-04-10 16:44:37 -07:00
|
|
|
}
|
2015-07-14 10:28:51 -07:00
|
|
|
|
2016-01-28 15:16:31 -05:00
|
|
|
SYS_INIT(fsl_frdm_k64f_init, PRIMARY, 0);
|