zephyr/arch/arm/fsl_frdm_k64f/system.c

380 lines
11 KiB
C

/* system.c - system/hardware module for fsl_frdm_k64f BSP */
/*
* Copyright (c) 2014-2015 Wind River Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3) Neither the name of Wind River Systems nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
DESCRIPTION
This module provides routines to initialize and support board-level hardware
for the fsl_frdm_k64f BSP.
*/
#include <nanokernel.h>
#include <nanokernel/cpu.h>
#include <cputype.h>
#include <board.h>
#include <drivers/k20_mcg.h>
#include <drivers/uart.h>
#include <drivers/k20_pcr.h>
#include <drivers/k20_sim.h>
#include <drivers/k6x_mpu.h>
#include <drivers/k6x_pmc.h>
#include <sections.h>
#if defined(CONFIG_PRINTK) || defined(CONFIG_STDOUT_CONSOLE)
#define DO_CONSOLE_INIT
#endif
/* 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)
#ifdef CONFIG_RUNTIME_NMI
extern void _NmiInit(void);
#define NMI_INIT() _NmiInit()
#else
#define NMI_INIT()
#endif
/*
* 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
*/
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};
/*******************************************************************************
*
* clkInit - initialize the system clock
*
* 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
* PLL Engaged External (PEE) mode and generate the maximum 120 MHz system clock.
*
* RETURNS: N/A
*
*/
static void clkInit(void)
{
uint8_t temp_reg;
K20_MCG_t *mcg_p = (K20_MCG_t *)PERIPH_ADDR_BASE_MCG; /* clk gen. ctl */
/*
* Select the 50 Mhz external clock as the MCG OSC clock.
* MCG Control 7 register:
* - Select OSCCLK0 / XTAL
*/
temp_reg = mcg_p->c7 & ~MCG_C7_OSCSEL_MASK;
temp_reg |= MCG_C7_OSCSEL_OSC0;
mcg_p->c7 = temp_reg;
/*
* 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
*/
temp_reg = mcg_p->c2 &
~(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);
mcg_p->c2 = temp_reg;
/*
* 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
*
*/
temp_reg = mcg_p->c1 &
~(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);
mcg_p->c1 = temp_reg;
/* Confirm that the external reference clock is the FLL reference source
*/
while ((mcg_p->s & MCG_S_IREFST_MASK) != 0)
;
;
/* Confirm the external ref. clock is the system clock source
* (MCGOUTCLK) */
while ((mcg_p->s & MCG_S_CLKST_MASK) != MCG_S_CLKST_EXT_REF)
;
;
/*
* 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
*/
temp_reg = mcg_p->c5 & ~MCG_C5_PRDIV0_MASK;
temp_reg |= FRDM_K64F_PLL_DIV_20;
mcg_p->c5 = temp_reg;
/*
* MCG Control 6 register:
* - Select PLL as output for PEE mode
* - Set the PLL multiplier
*/
temp_reg = mcg_p->c6 & ~(MCG_C6_PLLS_MASK | MCG_C6_VDIV0_MASK);
temp_reg |= (MCG_C6_PLLS_PLL | FRDM_K64F_PLL_MULT_48);
mcg_p->c6 = temp_reg;
/* Confirm that the PLL clock is selected as the PLL output */
while ((mcg_p->s & MCG_S_PLLST_MASK) == 0)
;
;
/* Confirm that the PLL has acquired lock */
while ((mcg_p->s & MCG_S_LOCK0_MASK) == 0)
;
;
/*
* Transition to PEE mode.
* MCG Control 1 register:
* - Select PLL as the system clock source (MCGOUTCLK)
*/
temp_reg = mcg_p->c1 & ~MCG_C1_CLKS_MASK;
temp_reg |= MCG_C1_CLKS_FLL_PLL;
mcg_p->c1 = temp_reg;
/* Confirm that the PLL output is the system clock source (MCGOUTCLK) */
while ((mcg_p->s & MCG_S_CLKST_MASK) != MCG_S_CLKST_PLL)
;
;
}
#if defined(DO_CONSOLE_INIT)
/*******************************************************************************
*
* consoleInit - initialize target-only console
*
* Only used for debugging.
*
* RETURNS: N/A
*
*/
#include <console/uart_console.h>
static void consoleInit(void)
{
uint32_t port;
uint32_t rxPin;
uint32_t txPin;
K20_PCR_t pcr = {0}; /* Pin Control Register */
/* Port/pin ctrl module */
K20_PORT_PCR_t *port_pcr_p = (K20_PORT_PCR_t *)PERIPH_ADDR_BASE_PCR;
struct uart_init_info info = {
.baud_rate = CONFIG_UART_CONSOLE_BAUDRATE,
.sys_clk_freq = CONFIG_UART_CONSOLE_CLK_FREQ,
/* Only supported in polling mode, but init all info fields */
.int_pri = CONFIG_UART_CONSOLE_INT_PRI
};
/* UART0 Rx and Tx pin assignments */
port = CONFIG_UART_CONSOLE_PORT;
rxPin = CONFIG_UART_CONSOLE_PORT_RX_PIN;
txPin = CONFIG_UART_CONSOLE_PORT_TX_PIN;
/* Enable the UART Rx and Tx Pins */
pcr.field.mux = CONFIG_UART_CONSOLE_PORT_MUX_FUNC;
port_pcr_p->port[port].pcr[rxPin] = pcr;
port_pcr_p->port[port].pcr[txPin] = pcr;
uart_init(CONFIG_UART_CONSOLE_INDEX, &info);
uart_console_init();
}
#else
#define consoleInit() \
do {/* nothing */ \
} while ((0))
#endif /* DO_CONSOLE_INIT */
/*******************************************************************************
*
* _InitHardware - perform basic hardware initialization
*
* Initialize the interrupt controller device drivers and the
* Kinetis UART device driver.
* Also initialize the timer device driver, if required.
*
* RETURNS: N/A
*/
void _InitHardware(void)
{
/* System Integration module */
K20_SIM_t *sim_p = (K20_SIM_t *)PERIPH_ADDR_BASE_SIM;
/* Power Mgt Control module */
K6x_PMC_t *pmc_p = (K6x_PMC_t *)PERIPH_ADDR_BASE_PMC;
/* Power Mgt Control module */
K6x_MPU_t *mpu_p = (K6x_MPU_t *)PERIPH_ADDR_BASE_MPU;
int oldLevel; /* old interrupt lock level */
uint32_t temp_reg;
/* disable interrupts */
oldLevel = irq_lock();
/* enable the port clocks */
sim_p->scgc5.value |= (SIM_SCGC5_PORTA_CLK_EN | SIM_SCGC5_PORTB_CLK_EN |
SIM_SCGC5_PORTC_CLK_EN | SIM_SCGC5_PORTD_CLK_EN |
SIM_SCGC5_PORTE_CLK_EN);
/* release I/O power hold to allow normal run state */
pmc_p->regsc.value |= PMC_REGSC_ACKISO_MASK;
/*
* 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.
*/
temp_reg = mpu_p->ctrlErrStatus.value;
temp_reg &= ~MPU_VALID_MASK;
temp_reg |= MPU_SLV_PORT_ERR_MASK;
mpu_p->ctrlErrStatus.value = temp_reg;
/* 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)
*/
sim_p->clkdiv1.value = ((SIM_CLKDIV(1) << SIM_CLKDIV1_OUTDIV1_SHIFT) |
(SIM_CLKDIV(2) << SIM_CLKDIV1_OUTDIV2_SHIFT) |
(SIM_CLKDIV(3) << SIM_CLKDIV1_OUTDIV3_SHIFT) |
(SIM_CLKDIV(5) << SIM_CLKDIV1_OUTDIV4_SHIFT));
clkInit(); /* Initialize PLL/system clock to 120 MHz */
consoleInit(); /* NOP if not needed */
NMI_INIT(); /* install default handler that simply resets the CPU
* if configured in the kernel, NOP otherwise */
/* restore interrupt state */
irq_unlock(oldLevel);
}