/* kinetis_hw.c * * Copyright (C) 2006-2024 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL 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 2 of the License, or * (at your option) any later version. * * wolfSSL 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 "hw.h" #include "user_settings.h" #if defined(FREESCALE) && defined(K_SERIES) /********************************************** * NOTE: Customize for actual hardware **********************************************/ // CPU include for Rowley CrossWorks packages // $(TargetsDir) location: // On Mac OS/X: Users/USERNAME/Library/Rowley Associates Limited/CrossWorks for ARM/packages/targets/ // On Windows: C:/Users/USERNAME/Application Data/Local/Rowley Associates Limited/CrossWorks for ARM/packages/targets/ // On Linux: home/USERNAME/.rowley_associates_limited/CrossWorks for ARM/v4/packages/targets/ // Located in $(TargetsDir)/Kinetis/CMSIS/ #ifdef FREESCALE_KSDK_BM #include "fsl_common.h" #include "fsl_debug_console.h" #include "fsl_rtc.h" #include "fsl_trng.h" #include "fsl_lpuart.h" #include "fsl_port.h" #include "clock_config.h" #else #include // Located in $(TargetsDir)/Kinetis/CMSIS/ #endif // System clock #ifdef FREESCALE_KSDK_BM #define SYS_CLK_HZ SystemCoreClock #else #define SYS_CLK_HZ 96000000ul /* Core system clock in Hz */ #define SYS_CLK_DRS MCG_C4_DRST_DRS(0x03) /* DRS 0=24MHz, 1=48MHz, 2=72MHz, 3=96MHz */ #define SYS_CLK_DMX MCG_C4_DMX32_MASK /* 0=Disable DMX32 (lower actual speed), MCG_C4_DMX32_MASK=Enable DMX32 */ #define SYS_CLK_DIV 1 /* System clock divisor */ #define BUS_CLK_DIV 2 /* Bus clock divisor */ #define BUS_CLK_KHZ (SYS_CLK_HZ/BUS_CLK_DIV) /* Helper to calculate bus speed for UART */ #define FLASH_CLK_DIV 4 /* Flash clock divisor */ #endif // UART TX Port, Pin, Mux and Baud #ifdef FREESCALE_KSDK_BM #define UART_PORT LPUART4 /* UART Port */ #define UART_TX_PORT PORTC /* UART TX Port */ #define UART_TX_PIN 15U /* UART TX Pin */ #define UART_TX_MUX kPORT_MuxAlt3 /* Kinetis UART pin mux */ #elif defined (WOLFSSL_FRDM_K64) #define UART_PORT UART0 /* UART Port */ #define UART_TX_PORT PORTB /* UART TX Port */ #define UART_TX_PIN 17U /* UART TX Pin */ #define UART_TX_MUX 0x3 /* Kinetis UART pin mux */ #else #define UART_PORT UART4 /* UART Port */ #define UART_TX_PORT PORTE /* UART TX Port */ #define UART_TX_PIN 24U /* UART TX Pin */ #define UART_TX_MUX 0x3 /* Kinetis UART pin mux */ #endif #define UART_BAUD_RATE 115200 /* UART Baud Rate */ #ifdef WOLFSSL_FRDM_K64 #define UART_BAUD UART_BAUD_RATE*8 #else #define UART_BAUD UART_BAUD_RATE #endif /* Note: You will also need to update the UART clock gate in hw_uart_init (SIM_SCGC1_UART5_MASK) */ /* Note: TWR-K60 is UART3, PTC17 */ /* Note: FRDM-K64 is UART4, PTE24 or UART0 PTB17 for OpenOCD (SIM_SCGC4_UART0_MASK)*/ /* Note: TWR-K64 is UART5, PTE8 */ /* Note: FRDM-K82F is LPUART4 PTC15 Alt3 (OpenOCD UART) */ /***********************************************/ // Private functions static uint32_t mDelayCyclesPerUs = 0; #define NOP_FOR_LOOP_INSTRUCTION_COUNT 6 static void delay_nop(uint32_t count) { int i; for(i=0; iCLKDIV1 = SIM_CLKDIV1_OUTDIV1(SYS_CLK_DIV-1) | SIM_CLKDIV1_OUTDIV2(BUS_CLK_DIV-1) | SIM_CLKDIV1_OUTDIV3(BUS_CLK_DIV-1) | SIM_CLKDIV1_OUTDIV4(FLASH_CLK_DIV-1); /* Configure FEI internal clock speed */ MCG->C4 = (SYS_CLK_DMX | SYS_CLK_DRS); while((MCG->C4 & (MCG_C4_DRST_DRS_MASK | MCG_C4_DMX32_MASK)) != (SYS_CLK_DMX | SYS_CLK_DRS)); #endif } static void hw_gpio_init(void) { #ifdef FREESCALE_KSDK_BM CLOCK_EnableClock(kCLOCK_PortA); CLOCK_EnableClock(kCLOCK_PortB); CLOCK_EnableClock(kCLOCK_PortC); CLOCK_EnableClock(kCLOCK_PortD); CLOCK_EnableClock(kCLOCK_PortE); #else /* Enable clocks to all GPIO ports */ SIM->SCGC5 |= (SIM_SCGC5_PORTA_MASK | SIM_SCGC5_PORTB_MASK #ifdef SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTC_MASK #endif #ifdef SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTD_MASK #endif #ifdef SIM_SCGC5_PORTE_MASK | SIM_SCGC5_PORTE_MASK #endif ); #if 0 /* Debug clock */ /* ClockOut on PTC3 */ PORTC->PCR[3] = PORT_PCR_MUX(0x05); /* Alt 5 */ SIM_SOPT2 |= SIM_SOPT2_CLKOUTSEL(0); /* FlexBus CLKOUT */ #endif #endif } static void hw_uart_init(void) { #ifdef FREESCALE_KSDK_BM PORT_SetPinMux(UART_TX_PORT, UART_TX_PIN, UART_TX_MUX); CLOCK_SetLpuartClock(1); /* MCGPLLCLK */ DbgConsole_Init((uint32_t)UART_PORT, UART_BAUD, DEBUG_CONSOLE_DEVICE_TYPE_LPUART, SYS_CLK_HZ); #else register uint16_t sbr, brfa; uint8_t temp; #ifdef WOLFSSL_FRDM_K64 /* Enable UART core clock ONLY for FRDM-K64F */ SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; #else /* Enable UART core clock */ /* Note: Remember to update me if UART_PORT changes */ SIM->SCGC1 |= SIM_SCGC1_UART4_MASK; #endif /* Configure UART TX pin */ UART_TX_PORT->PCR[UART_TX_PIN] = PORT_PCR_MUX(UART_TX_MUX); /* Disable transmitter and receiver while we change settings. */ UART_PORT->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK ); /* Configure the UART for 8-bit mode, no parity */ UART_PORT->C1 = 0; /* Calculate baud settings */ sbr = (uint16_t)((BUS_CLK_KHZ * 1000)/(UART_BAUD * 16)); temp = UART_PORT->BDH & ~(UART_BDH_SBR(0x1F)); UART_PORT->BDH = temp | UART_BDH_SBR(((sbr & 0x1F00) >> 8)); UART_PORT->BDL = (uint8_t)(sbr & UART_BDL_SBR_MASK); /* Determine if a fractional divider is needed to get closer to the baud rate */ brfa = (((BUS_CLK_KHZ * 32000)/(UART_BAUD * 16)) - (sbr * 32)); temp = UART_PORT->C4 & ~(UART_C4_BRFA(0x1F)); UART_PORT->C4 = temp | UART_C4_BRFA(brfa); /* Enable receiver and transmitter */ UART_PORT->C2 |= (UART_C2_TE_MASK | UART_C2_RE_MASK); #endif } static void hw_rtc_init(void) { /* Init nop delay */ mDelayCyclesPerUs = (SYS_CLK_HZ / 1000000 / NOP_FOR_LOOP_INSTRUCTION_COUNT); /* Enable RTC clock and oscillator */ SIM->SCGC6 |= SIM_SCGC6_RTC_MASK; if (RTC->SR & RTC_SR_TIF_MASK) { /* Resets the RTC registers except for the SWR bit */ RTC->CR |= RTC_CR_SWR_MASK; RTC->CR &= ~RTC_CR_SWR_MASK; /* Set TSR register to 0x1 to avoid the TIF bit being set in the SR register */ RTC->TSR = 1; } /* Disable RTC Interrupts */ RTC->IER = 0; /* Enable OSC */ if ((RTC->CR & RTC_CR_OSCE_MASK) == 0) { /* Turn on */ RTC->CR |= RTC_CR_OSCE_MASK; /* Wait RTC startup delay 1000 us */ delay_us(1000); } /* Enable counter */ RTC->SR |= RTC_SR_TCE_MASK; } static void hw_rand_init(void) { #ifdef FREESCALE_KSDK_BM trng_config_t trngConfig; TRNG_GetDefaultConfig(&trngConfig); /* Set sample mode of the TRNG ring oscillator to Von Neumann, for better random data.*/ trngConfig.sampleMode = kTRNG_SampleModeVonNeumann; /* Initialize TRNG */ TRNG_Init(TRNG0, &trngConfig); #else /* Enable RNG clocks */ SIM->SCGC6 |= SIM_SCGC6_RNGA_MASK; SIM->SCGC3 |= SIM_SCGC3_RNGA_MASK; /* Wake up RNG to normal mode (take out of sleep) */ RNG->CR &= ~RNG_CR_SLP_MASK; /* Enable High Assurance mode (Enables notification of security violations via SR[SECV]) */ RNG->CR |= RNG_CR_HA_MASK; /* Enable RNG generation to RANDOUT FIFO */ RNG->CR |= RNG_CR_GO_MASK; #endif } /* Public Functions */ void hw_init(void) { hw_mcg_init(); hw_gpio_init(); hw_uart_init(); hw_rtc_init(); hw_rand_init(); } uint32_t hw_get_time_sec(void) { /* Return RTC seconds */ return RTC->TSR; } uint32_t hw_get_time_msec(void) { /* RTC TPR precision register increments every 32.768 kHz clock cycle */ /* Convert with rounding crystal count (32768 or (1 << 15)) to milliseconds */ return ( ((uint32_t)RTC->TPR * 1000) + ((1 << 15) / 2) ) / (1 << 15); } void hw_uart_printchar(int c) { #ifdef FREESCALE_KSDK_BM LPUART_WriteBlocking(UART_PORT, (const uint8_t*)&c, 1); /* Send the character */ #else while(!(UART_PORT->S1 & UART_S1_TDRE_MASK)); /* Wait until space is available in the FIFO */ UART_PORT->D = (uint8_t)c; /* Send the character */ #endif } uint32_t hw_rand(void) { uint32_t rng; #ifdef FREESCALE_KSDK_BM TRNG_GetRandomData(TRNG0, &rng, sizeof(rng)); #else while((RNG->SR & RNG_SR_OREG_LVL(0xF)) == 0) {}; /* Wait until FIFO has a value available */ rng = RNG->OR; /* Return next value in FIFO output register */ #endif return rng; } void delay_us(uint32_t microseconds) { delay_nop(mDelayCyclesPerUs * microseconds); } // Watchdog void hw_watchdog_disable(void) { WDOG->UNLOCK = 0xC520; WDOG->UNLOCK = 0xD928; WDOG->STCTRLH = WDOG_STCTRLH_ALLOWUPDATE_MASK; } // Flash configuration #define FSEC_UNSECURE 2 #define FSEC_SECURE 0 #define FSEC_FSLACC_DENIED 2 #define FSEC_FSLACC_GRANTED 3 #define FSEC_KEY_ENABLED 2 #define FSEC_KEY_DISABLED 3 #define FSEC_MASS_ERASE_DISABLE 2 #define FSEC_MASS_ERASE_ENABLE 3 struct flash_conf { uint8_t backdoor_key[8]; /* Backdoor Comparison Key */ uint8_t fprot[4]; /* Program flash protection bytes */ uint8_t fsec; /* Flash security byte */ uint8_t fopt; /* Flash nonvolatile option byte */ uint8_t feprot; /* FlexNVM: EEPROM protection byte */ uint8_t fdprot; /* FlexNVM: Data flash protection byte */ }; const struct flash_conf flash_conf __attribute__ ((section (".flashconf"),used)) = { .backdoor_key = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, .fprot = { 0xFF, 0xFF, 0xFF, 0xFF }, .fsec = NV_FSEC_SEC(FSEC_UNSECURE) | NV_FSEC_FSLACC(FSEC_FSLACC_GRANTED) | NV_FSEC_MEEN(FSEC_MASS_ERASE_ENABLE) | NV_FSEC_KEYEN(FSEC_KEY_DISABLED), .fopt = 0xFF, .feprot = 0xFF, .fdprot = 0xFF }; #endif /* FREESCALE && K_SERIES */