/* * Copyright (c) 2016 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief System/hardware module for Nordic Semiconductor nRF52 family processor * * This module provides routines to initialize and support board-level hardware * for the Nordic Semiconductor nRF52 family processor. */ #include #include #include #include #ifdef CONFIG_RUNTIME_NMI extern void _NmiInit(void); #define NMI_INIT() _NmiInit() #else #define NMI_INIT() #endif #include "nrf.h" #define __SYSTEM_CLOCK_64M (64000000UL) #ifdef CONFIG_SOC_NRF52832 static bool ftpan_32(void) { if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)) { if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0)) { return true; } } return false; } static bool ftpan_37(void) { if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)) { if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0)) { return true; } } return false; } static bool ftpan_36(void) { if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)) { if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0)) { return true; } } return false; } static void nordicsemi_nrf52832_init(void) { /* Workaround for FTPAN-32 "DIF: Debug session automatically * enables TracePort pins" found at Product Anomaly document * for your device located at https://www.nordicsemi.com/ */ if (ftpan_32()) { CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; } /* Workaround for FTPAN-37 "AMLI: EasyDMA is slow with Radio, * ECB, AAR and CCM." found at Product Anomaly document * for your device located at https://www.nordicsemi.com/ */ if (ftpan_37()) { *(volatile uint32_t *)0x400005A0 = 0x3; } /* Workaround for FTPAN-36 "CLOCK: Some registers are not * reset when expected." found at Product Anomaly document * for your device located at https://www.nordicsemi.com/ */ if (ftpan_36()) { NRF_CLOCK->EVENTS_DONE = 0; NRF_CLOCK->EVENTS_CTTO = 0; } /* Configure GPIO pads as pPin Reset pin if Pin Reset * capabilities desired. If CONFIG_GPIO_AS_PINRESET is not * defined, pin reset will not be available. One GPIO (see * Product Specification to see which one) will then be * reserved for PinReset and not available as normal GPIO. */ #if defined(CONFIG_GPIO_AS_PINRESET) if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) || ((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))) { NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { ; } NRF_UICR->PSELRESET[0] = 21; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { ; } NRF_UICR->PSELRESET[1] = 21; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { ; } NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { ; } NVIC_SystemReset(); } #endif /* Enable SWO trace functionality. If ENABLE_SWO is not * defined, SWO pin will be used as GPIO (see Product * Specification to see which one). */ #if defined(ENABLE_SWO) CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos; #endif /* Enable Trace functionality. If ENABLE_TRACE is not * defined, TRACE pins will be used as GPIOs (see Product * Specification to see which ones). */ #if defined(ENABLE_TRACE) CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos; #endif } #endif /* CONFIG_SOC_NRF52832 */ #ifdef CONFIG_SOC_NRF52840 static bool errata_36(void) { if ((*(uint32_t *)0x10000130ul == 0x8ul) && (*(uint32_t *)0x10000134ul == 0x0ul)) { return true; } return false; } static bool errata_98(void) { if ((*(uint32_t *)0x10000130ul == 0x8ul) && (*(uint32_t *)0x10000134ul == 0x0ul)) { return true; } return false; } static bool errata_103(void) { if ((*(uint32_t *)0x10000130ul == 0x8ul) && (*(uint32_t *)0x10000134ul == 0x0ul)) { return true; } return false; } static bool errata_115(void) { if ((*(uint32_t *)0x10000130ul == 0x8ul) && (*(uint32_t *)0x10000134ul == 0x0ul)) { return true; } return false; } static bool errata_120(void) { if ((*(uint32_t *)0x10000130ul == 0x8ul) && (*(uint32_t *)0x10000134ul == 0x0ul)) { return true; } return false; } static void nordicsemi_nrf52840_init(void) { /* Workaround for Errata 36 "CLOCK: Some registers are not reset when * expected" found at the Errata document for your device located at * https://infocenter.nordicsemi.com/ */ if (errata_36()) { NRF_CLOCK->EVENTS_DONE = 0; NRF_CLOCK->EVENTS_CTTO = 0; NRF_CLOCK->CTIV = 0; } /* Workaround for Errata 98 "NFCT: Not able to communicate with the * peer" found at the Errata document for your device located at * https://infocenter.nordicsemi.com/ */ if (errata_98()) { *(volatile uint32_t *)0x4000568Cul = 0x00038148ul; } /* Workaround for Errata 103 "CCM: Wrong reset value of CCM * MAXPACKETSIZE" found at the Errata document for your device * located at https://infocenter.nordicsemi.com/ */ if (errata_103()) { NRF_CCM->MAXPACKETSIZE = 0xFBul; } /* Workaround for Errata 115 "RAM: RAM content cannot be trusted upon * waking up from System ON Idle or System OFF mode" found at the * Errata document for your device located at * https://infocenter.nordicsemi.com/ */ if (errata_115()) { *(volatile uint32_t *)0x40000EE4 = (*(volatile uint32_t *) 0x40000EE4 & 0xFFFFFFF0) | (*(uint32_t *)0x10000258 & 0x0000000F); } /* Workaround for Errata 120 "QSPI: Data read or written is corrupted" * found at the Errata document for your device located at * https://infocenter.nordicsemi.com/ */ if (errata_120()) { *(volatile uint32_t *)0x40029640ul = 0x200ul; } /* Configure GPIO pads as pPin Reset pin if Pin Reset capabilities * desired. * If CONFIG_GPIO_AS_PINRESET is not defined, pin reset will not be * available. One GPIO (see Product Specification to see which one) will * then be reserved for PinReset and not available as normal GPIO. */ #if defined(CONFIG_GPIO_AS_PINRESET) if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) || ((NRF_UICR->PSELRESET[1] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))) { NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { } NRF_UICR->PSELRESET[0] = 18; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { } NRF_UICR->PSELRESET[1] = 18; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { } NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { } NVIC_SystemReset(); } #endif /* Enable SWO trace functionality. If ENABLE_SWO is not defined, SWO pin * will be used as GPIO (see Product Specification to see which one). */ #if defined(ENABLE_SWO) CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos; NRF_P1->PIN_CNF[0] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); #endif /* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE * pins will be used as GPIOs (see Product Specification to see which * ones). */ #if defined(ENABLE_TRACE) CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos; NRF_P0->PIN_CNF[7] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_P1->PIN_CNF[0] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_P0->PIN_CNF[12] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_P0->PIN_CNF[11] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); NRF_P1->PIN_CNF[9] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); #endif } #endif /* CONFIG_SOC_NRF52840 */ uint32_t SystemCoreClock __used = __SYSTEM_CLOCK_64M; static void clock_init(void) { SystemCoreClock = __SYSTEM_CLOCK_64M; } static int nordicsemi_nrf52_init(struct device *arg) { uint32_t key; ARG_UNUSED(arg); key = irq_lock(); /* Setup the vector table offset register (VTOR), * which is located at the beginning of flash area. */ _scs_relocate_vector_table((void *)CONFIG_FLASH_BASE_ADDRESS); #ifdef CONFIG_SOC_NRF52832 nordicsemi_nrf52832_init(); #endif #ifdef CONFIG_SOC_NRF52840 nordicsemi_nrf52840_init(); #endif /* Enable the FPU if the compiler used floating point unit * instructions. Since the FPU consumes energy, remember to * disable FPU use in the compiler if floating point unit * operations are not used in your code. */ #if defined(CONFIG_FLOAT) SCB->CPACR |= (3UL << 20) | (3UL << 22); __DSB(); __ISB(); #endif /* Configure NFCT pins as GPIOs if NFCT is not to be used in * your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined, * two GPIOs (see Product Specification to see which ones) * will be reserved for NFC and will not be available as * normal GPIOs. */ #if defined(CONFIG_NFCT_PINS_AS_GPIOS) if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)) { NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { ; } NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { ; } NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; while (NRF_NVMC->READY == NVMC_READY_READY_Busy) { ; } NVIC_SystemReset(); } #endif /* Reset all faults */ _ScbMemFaultAllFaultsReset(); _ScbBusFaultAllFaultsReset(); _ScbUsageFaultAllFaultsReset(); _ScbHardFaultAllFaultsReset(); /* Setup master clock */ clock_init(); /* Install default handler that simply resets the CPU * if configured in the kernel, NOP otherwise */ NMI_INIT(); irq_unlock(key); return 0; } SYS_INIT(nordicsemi_nrf52_init, PRE_KERNEL_1, 0);