wolfBoot/hal/kinetis.c

372 lines
14 KiB
C

/* kinetis.c
*
* Copyright (C) 2021 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdint.h>
#include <target.h>
#include "image.h"
#include "fsl_common.h"
#include "fsl_flash.h"
#include "fsl_ftfx_cache.h"
#include "fsl_sysmpu.h"
#if defined(CPU_MK82FN256VLL15) && defined(FREESCALE_USE_LTC)
#include <wolfssl/wolfcrypt/port/nxp/ksdk_port.h>
#endif
static flash_config_t pflash;
static ftfx_cache_config_t pcache;
static int flash_init = 0;
#ifndef NVM_FLASH_WRITEONCE
# error "wolfBoot Kinetis HAL: no WRITEONCE support detected. Please define NVM_FLASH_WRITEONCE"
#endif
#ifdef __WOLFBOOT
static void CLOCK_CONFIG_SetFllExtRefDiv(uint8_t frdiv)
{
MCG->C1 = ((MCG->C1 & ~MCG_C1_FRDIV_MASK) | MCG_C1_FRDIV(frdiv));
}
static void do_flash_init(void);
/* Assert hook needed by Kinetis SDK */
void __assert_func(const char *a, int b, const char *c, const char *d)
{
while(1)
;
}
/* This are the registers for the NV flash configuration area.
* Access these field by setting the relative flags in NV_Flash_Config.
*/
#define NVTYPE_LEN (16)
const uint8_t __attribute__((section(".flash_config"))) NV_Flash_Config[NVTYPE_LEN] = {
/* Backdoor comparison key (2 words) */
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/* P-Flash protection 1 */
0xFF, 0xFF,
/* P-Flash protection 2 */
0xFF, 0xFF,
/* Flash security register */
((0xFE)),
/* Flash option register */
0xFF,
/* EERAM protection register */
0xFF,
/* D-Flash protection register */
0xFF
};
#if defined(CPU_MK82FN256VLL15)
struct stage1_config
{
uint32_t tag;
uint32_t crcStartAddress;
uint32_t crcByteCount;
uint32_t crcExpectedValue;
uint8_t enabledPeripherals;
uint8_t i2cSlaveAddress;
uint16_t peripheralDetectionTimeoutMs;
uint16_t usbVid;
uint16_t usbPid;
uint32_t usbStringsPointer;
uint8_t clockFlags;
uint8_t clockDivider;
uint8_t bootFlags;
uint8_t RESERVED1;
uint32_t mmcauConfigPointer;
uint32_t keyBlobPointer;
uint8_t RESERVED2[8];
uint32_t qspiConfigBlockPtr;
uint8_t RESERVED3[12];
};
const struct stage1_config __attribute__((section(".stage1_config")))
NV_Stage1_Config = {
.tag = 0x6766636BU, /* Magic Number */
.crcStartAddress = 0xFFFFFFFFU, /* Disable CRC check */
.crcByteCount = 0xFFFFFFFFU, /* Disable CRC check */
.crcExpectedValue = 0xFFFFFFFFU, /* Disable CRC check */
.enabledPeripherals = 0x17, /* Enable all peripherals */
.i2cSlaveAddress = 0xFF, /* Use default I2C address */
.peripheralDetectionTimeoutMs = 0x01F4U, /* Use default timeout */
.usbVid = 0xFFFFU, /* Use default USB Vendor ID */
.usbPid = 0xFFFFU, /* Use default USB Product ID */
.usbStringsPointer = 0xFFFFFFFFU, /* Use default USB Strings */
.clockFlags = 0x01, /* Enable High speed mode */
.clockDivider = 0xFF, /* Use clock divider 1 */
.bootFlags = 0x01, /* Enable communication with host */
.mmcauConfigPointer = 0xFFFFFFFFU, /* No MMCAU configuration */
.keyBlobPointer = 0x000001000, /* keyblob data is at 0x1000 */
.qspiConfigBlockPtr = 0xFFFFFFFFU /* No QSPI configuration */
};
#endif
#define MCG_PLL_DISABLE 0U /*!< MCGPLLCLK disabled */
#define OSC_CAP0P 0U /*!< Oscillator 0pF capacitor load */
#define OSC_ER_CLK_DISABLE 0U /*!< Disable external reference clock */
#define SIM_OSC32KSEL_RTC32KCLK_CLK 2U /*!< OSC32KSEL select: RTC32KCLK clock (32.768kHz) */
#define SIM_PLLFLLSEL_IRC48MCLK_CLK 3U /*!< PLLFLL select: IRC48MCLK clock */
#define SIM_PLLFLLSEL_MCGPLLCLK_CLK 1U /*!< PLLFLL select: MCGPLLCLK clock */
#define SIM_CLKDIV1_RUN_MODE_MAX_CORE_DIV 1U /*!< SIM CLKDIV1 maximum run mode core/system divider configurations */
#define SIM_CLKDIV1_RUN_MODE_MAX_BUS_DIV 3U /*!< SIM CLKDIV1 maximum run mode bus divider configurations */
#define SIM_CLKDIV1_RUN_MODE_MAX_FLEXBUS_DIV 3U /*!< SIM CLKDIV1 maximum run mode flexbus divider configurations */
#define SIM_CLKDIV1_RUN_MODE_MAX_FLASH_DIV 7U /*!< SIM CLKDIV1 maximum run mode flash divider configurations */
static void CLOCK_CONFIG_FllStableDelay(void)
{
uint32_t i = 30000U;
while (i--)
{
__NOP();
}
}
const mcg_config_t mcgConfig_BOARD_BootClockRUN =
{
.mcgMode = kMCG_ModePEE, /* PEE - PLL Engaged External */
.irclkEnableMode = kMCG_IrclkEnable, /* MCGIRCLK enabled, MCGIRCLK disabled in STOP mode */
.ircs = kMCG_IrcSlow, /* Slow internal reference clock selected */
.fcrdiv = 0x0U, /* Fast IRC divider: divided by 1 */
.frdiv = 0x0U, /* FLL reference clock divider: divided by 32 */
.drs = kMCG_DrsLow, /* Low frequency range */
.dmx32 = kMCG_Dmx32Default, /* DCO has a default range of 25% */
.oscsel = kMCG_OscselOsc, /* Selects System Oscillator (OSCCLK) */
#if defined(CPU_MK64FN1M0VLL12)
.pll0Config =
{
.enableMode = MCG_PLL_DISABLE, /* MCGPLLCLK disabled */
.prdiv = 0x13U, /* PLL Reference divider: divided by 20 */
.vdiv = 0x18U, /* VCO divider: multiplied by 48 */
},
#elif defined(CPU_MK82FN256VLL15)
.pll0Config =
{
.enableMode = MCG_PLL_DISABLE, /* MCGPLLCLK disabled */
.prdiv = 0x0U, /* PLL Reference divider: divided by 1 */
.vdiv = 0x9U, /* VCO divider: multiplied by 25 */
},
#else
# error("The selected Kinetis MPU does not have a clock line configuration. Please edit hal/kinetis.c")
#endif
};
#if defined(CPU_MK64FN1M0VLL12)
const sim_clock_config_t simConfig_BOARD_BootClockRUN =
{
.pllFllSel = SIM_PLLFLLSEL_MCGPLLCLK_CLK, /* PLLFLL select: MCGPLLCLK clock */
.er32kSrc = SIM_OSC32KSEL_RTC32KCLK_CLK, /* OSC32KSEL select: RTC32KCLK clock (32.768kHz) */
.clkdiv1 = 0x1240000U, /* SIM_CLKDIV1 - OUTDIV1: /1, OUTDIV2: /2, OUTDIV3: /3, OUTDIV4: /5 */
};
const osc_config_t oscConfig_BOARD_BootClockRUN =
{
.freq = 50000000U, /* Oscillator frequency: 50000000Hz */
.capLoad = (OSC_CAP0P), /* Oscillator capacity load: 0pF */
.workMode = kOSC_ModeExt, /* Use external clock */
.oscerConfig =
{
.enableMode = kOSC_ErClkEnable, /* Enable external reference clock, disable external reference clock in STOP mode */
}
};
#elif defined(CPU_MK82FN256VLL15)
const sim_clock_config_t simConfig_BOARD_BootClockRUN = {
.pllFllSel = SIM_PLLFLLSEL_MCGPLLCLK_CLK, /* PLLFLL select: MCGPLLCLK clock */
.pllFllDiv = 0, /* PLLFLLSEL clock divider divisor: divided by 1 */
.pllFllFrac = 0, /* PLLFLLSEL clock divider fraction: multiplied by 1 */
.er32kSrc = SIM_OSC32KSEL_RTC32KCLK_CLK, /* OSC32KSEL select: RTC32KCLK clock (32.768kHz) */
.clkdiv1 = 0x1150000U, /* SIM_CLKDIV1 - OUTDIV1: /1, OUTDIV2: /2, OUTDIV3: /2, OUTDIV4: /6 */
};
const osc_config_t oscConfig_BOARD_BootClockRUN = {
.freq = 12000000U, /* Oscillator frequency: 12000000Hz */
.capLoad = (OSC_CAP0P), /* Oscillator capacity load: 0pF */
.workMode = kOSC_ModeOscLowPower, /* Oscillator low power */
.oscerConfig = {
.enableMode =
kOSC_ErClkEnable, /* Enable external reference clock, disable external reference clock in STOP mode */
.erclkDiv = 0, /* Divider for OSCERCLK: divided by 1 */
}
};
#endif
void hal_init(void)
{
/* Disable MPU */
SYSMPU_Enable(SYSMPU, false);
#if defined(CPU_MK82FN256VLL15) && defined(FREESCALE_USE_LTC)
ksdk_port_init();
#endif
/* Set the system clock dividers in SIM to safe value. */
#if defined(CPU_MK64FN1M0VLL12)
CLOCK_SetSimSafeDivs();
#elif defined(CPU_MK82FN256VLL15)
CLOCK_SetOutDiv(SIM_CLKDIV1_RUN_MODE_MAX_CORE_DIV, SIM_CLKDIV1_RUN_MODE_MAX_BUS_DIV,
SIM_CLKDIV1_RUN_MODE_MAX_FLEXBUS_DIV, SIM_CLKDIV1_RUN_MODE_MAX_FLASH_DIV);
#endif
/* Initializes OSC0 according to board configuration. */
CLOCK_InitOsc0(&oscConfig_BOARD_BootClockRUN);
CLOCK_SetXtal0Freq(oscConfig_BOARD_BootClockRUN.freq);
/* Configure the Internal Reference clock (MCGIRCLK). */
CLOCK_SetInternalRefClkConfig(mcgConfig_BOARD_BootClockRUN.irclkEnableMode,
mcgConfig_BOARD_BootClockRUN.ircs,
mcgConfig_BOARD_BootClockRUN.fcrdiv);
/* Configure FLL external reference divider (FRDIV). */
CLOCK_CONFIG_SetFllExtRefDiv(mcgConfig_BOARD_BootClockRUN.frdiv);
/* Set MCG to PEE mode. */
CLOCK_BootToPeeMode(mcgConfig_BOARD_BootClockRUN.oscsel,
kMCG_PllClkSelPll0,
&mcgConfig_BOARD_BootClockRUN.pll0Config);
/* Set the clock configuration in SIM module. */
CLOCK_SetSimConfig(&simConfig_BOARD_BootClockRUN);
do_flash_init();
}
#if 0
void BOARD_BootClockHSRUN(void)
{
/* In HSRUN mode, the maximum allowable change in frequency of the system/bus/core/flash is
* restricted to x2, to follow this restriction, enter HSRUN mode should follow:
* 1.set CLKDIV1 to safe divider value.
* 2.set the PLL or FLL output target frequency for HSRUN mode.
* 3.switch to HSRUN mode.
* 4.switch to HSRUN mode target frequency value.
*/
/* Set the system clock dividers in SIM to safe value. */
CLOCK_SetOutDiv(SIM_CLKDIV1_RUN_MODE_MAX_CORE_DIV, SIM_CLKDIV1_RUN_MODE_MAX_BUS_DIV,
SIM_CLKDIV1_RUN_MODE_MAX_FLEXBUS_DIV, SIM_CLKDIV1_RUN_MODE_MAX_FLASH_DIV);
/* Initializes OSC0 according to board configuration. */
CLOCK_InitOsc0(&oscConfig_BOARD_BootClockHSRUN);
CLOCK_SetXtal0Freq(oscConfig_BOARD_BootClockHSRUN.freq);
/* Configure the Internal Reference clock (MCGIRCLK). */
CLOCK_SetInternalRefClkConfig(mcgConfig_BOARD_BootClockHSRUN.irclkEnableMode, mcgConfig_BOARD_BootClockHSRUN.ircs,
mcgConfig_BOARD_BootClockHSRUN.fcrdiv);
/* Configure FLL external reference divider (FRDIV). */
CLOCK_CONFIG_SetFllExtRefDiv(mcgConfig_BOARD_BootClockHSRUN.frdiv);
/* Set MCG to PEE mode. */
CLOCK_BootToPeeMode(mcgConfig_BOARD_BootClockHSRUN.oscsel, kMCG_PllClkSelPll0,
&mcgConfig_BOARD_BootClockHSRUN.pll0Config);
/* Set HSRUN power mode */
SMC_SetPowerModeProtection(SMC, kSMC_AllowPowerModeAll);
SMC_SetPowerModeHsrun(SMC);
while (SMC_GetPowerModeState(SMC) != kSMC_PowerStateHsrun)
{
}
/* Set the clock configuration in SIM module. */
CLOCK_SetSimConfig(&simConfig_BOARD_BootClockHSRUN);
/* Set SystemCoreClock variable. */
SystemCoreClock = BOARD_BOOTCLOCKHSRUN_CORE_CLOCK;
}
#endif
void hal_prepare_boot(void)
{
}
#endif
static void do_flash_init(void)
{
if (flash_init)
return;
flash_init++;
memset(&pflash, 0, sizeof(pflash));
memset(&pcache, 0, sizeof(pcache));
FLASH_Init(&pflash);
FTFx_CACHE_Init(&pcache);
FTFx_CACHE_ClearCachePrefetchSpeculation(&pcache, 1);
}
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
{
int w = 0;
int ret;
const uint8_t empty_dword[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
do_flash_init();
while (len > 0) {
if ((len < 8) || address & 0x07) {
uint8_t aligned_dword[8];
uint32_t address_align = address - (address & 0x07);
uint32_t start_off = address - address_align;
int i;
memcpy(aligned_dword, (void*)address_align, 8);
for (i = start_off; ((i < 8) && (i < len + (int)start_off)); i++)
aligned_dword[i] = data[w++];
if (memcmp(aligned_dword, empty_dword, 8) != 0) {
ret = FLASH_Program(&pflash, address_align, aligned_dword, 8);
if (ret != kStatus_FTFx_Success)
return -1;
}
address += i;
len -= i;
} else {
uint32_t len_align = len - (len & 0x07);
ret = FLASH_Program(&pflash, address, (uint8_t*)data + w, len_align);
if (ret != kStatus_FTFx_Success)
return -1;
len -= len_align;
address += len_align;
}
}
FTFx_CACHE_ClearCachePrefetchSpeculation(&pcache, 1);
return 0;
}
void RAMFUNCTION hal_flash_unlock(void)
{
}
void RAMFUNCTION hal_flash_lock(void)
{
}
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
{
int idx = 0;
do_flash_init();
do {
if (FLASH_Erase(&pflash, address + WOLFBOOT_SECTOR_SIZE * idx, WOLFBOOT_SECTOR_SIZE, kFTFx_ApiEraseKey) != kStatus_FTFx_Success)
return -1;
len -= WOLFBOOT_SECTOR_SIZE;
idx++;
} while (len > 0);
FTFx_CACHE_ClearCachePrefetchSpeculation(&pcache, 1);
return 0;
}