From 49e0fe1f1256c65426bc85dacb914847960ec743 Mon Sep 17 00:00:00 2001 From: AlmAck Date: Sat, 29 Aug 2026 19:02:05 +0200 Subject: [PATCH] arch/arm/nrf53: enable the application core flash cache The nRF5340 application core comes out of reset with its flash cache disabled and nothing in the tree turns it on. nrf53_start() does call nrf53_enable_icache(), but that drives NVMC ICACHECNF and is gated on NRF53_FLASH_PREFETCH, which depends on NRF53_NETCORE -- so it is not even compiled for an application core build. The nRF5340 places the application core cache in a separate CACHE peripheral at 0x50001000. NRF53_CACHE_BASE is already defined in hardware/nrf53_memorymap_cpuapp.h, but there was no register header and no enable. Add both, behind a new NRF53_CACHE option. The option defaults to n, matching ARMV7M_ICACHE and ARMV8M_ICACHE/DCACHE, so that upgrading does not silently change the behaviour of an existing configuration. Measured on nrf5340-dk at 64 MHz with apps/benchmarks/scbench: protected-build syscall round trip 64.1 us -> 29.6 us userspace sem wait + post pair 4.75 us -> 1.95 us Flat builds benefit equally; the gain is on any flash-resident code path. Per the nRF5340 Product Specification, 'CACHE - Instruction and data cache', 'both instruction and data accesses towards flash memory or XIP code regions are cached'. The cache does not observe NVMC programming, so nrf53_flash.c has to account for it: both up_progmem_eraseblock() and up_progmem_write() read back what they just programmed to verify it, and up_progmem_ispageerased() reads a whole page, so lines covering the region being programmed are commonly resident. Bypass the cache for the duration of an erase or a write and invalidate it before re-enabling, so the verify reads the array and later readers do too. That file is built only when NRF53_PROGMEM is selected, which is not the default. Signed-off-by: AlmAck --- arch/arm/src/nrf53/Kconfig | 17 ++++++ arch/arm/src/nrf53/hardware/nrf53_cache.h | 66 +++++++++++++++++++++++ arch/arm/src/nrf53/nrf53_flash.c | 41 ++++++++++++++ arch/arm/src/nrf53/nrf53_start.c | 11 ++++ 4 files changed, 135 insertions(+) create mode 100644 arch/arm/src/nrf53/hardware/nrf53_cache.h diff --git a/arch/arm/src/nrf53/Kconfig b/arch/arm/src/nrf53/Kconfig index 501bb2d375fc3..b1b28e039bdab 100644 --- a/arch/arm/src/nrf53/Kconfig +++ b/arch/arm/src/nrf53/Kconfig @@ -445,6 +445,23 @@ endif # NRF53_SYSTIMER_RTC endmenu # System Timer +config NRF53_CACHE + bool "Application core flash cache" + depends on NRF53_APPCORE + default n + ---help--- + Enable the application core CACHE peripheral, which caches both + instruction and data accesses towards flash and XIP code regions. + The application core runs uncached without this, so enabling it is + a substantial speedup on any flash-resident code path. + + The cache does not observe writes to the memory it caches. The + in-tree progmem driver handles this, but code outside the kernel + that programs flash, or a board that maps QSPI into the XIP + window and writes it, must invalidate the cache itself. Left off + by default for that reason, matching ARMV7M_ICACHE and + ARMV8M_ICACHE/DCACHE. + config NRF53_FLASH_PREFETCH bool "Enable FLASH Pre-fetch" depends on NRF53_NETCORE diff --git a/arch/arm/src/nrf53/hardware/nrf53_cache.h b/arch/arm/src/nrf53/hardware/nrf53_cache.h new file mode 100644 index 0000000000000..fb2197dd4750c --- /dev/null +++ b/arch/arm/src/nrf53/hardware/nrf53_cache.h @@ -0,0 +1,66 @@ +/**************************************************************************** + * arch/arm/src/nrf53/hardware/nrf53_cache.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_CACHE_H +#define __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_CACHE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/nrf53_memorymap.h" + +/* The application core CACHE peripheral (flash instruction/data cache). + * Distinct from the nRF52-era NVMC ICACHECNF register, which does not + * exist on this part. + */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define NRF53_CACHE_ENABLE_OFFSET 0x500 /* Enable the cache */ +#define NRF53_CACHE_INVALIDATE_OFFSET 0x504 /* Invalidate the cache */ +#define NRF53_CACHE_INFO_OFFSET 0x508 /* Cache info */ +#define NRF53_CACHE_PROFILINGENABLE_OFFSET 0x518 /* Profiling enable */ +#define NRF53_CACHE_MODE_OFFSET 0x51c /* Cache mode */ + +/* Register addresses *******************************************************/ + +#define NRF53_CACHE_ENABLE (NRF53_CACHE_BASE + NRF53_CACHE_ENABLE_OFFSET) +#define NRF53_CACHE_INVALIDATE (NRF53_CACHE_BASE + NRF53_CACHE_INVALIDATE_OFFSET) +#define NRF53_CACHE_INFO (NRF53_CACHE_BASE + NRF53_CACHE_INFO_OFFSET) +#define NRF53_CACHE_PROFILINGENABLE (NRF53_CACHE_BASE + NRF53_CACHE_PROFILINGENABLE_OFFSET) +#define NRF53_CACHE_MODE (NRF53_CACHE_BASE + NRF53_CACHE_MODE_OFFSET) + +/* ENABLE Register **********************************************************/ + +#define CACHE_ENABLE_ENABLE (1 << 0) /* Enable cache */ + +/* INVALIDATE Register ******************************************************/ + +#define CACHE_INVALIDATE_INVALIDATE (1 << 0) /* Invalidate cache */ + +#endif /* __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_CACHE_H */ diff --git a/arch/arm/src/nrf53/nrf53_flash.c b/arch/arm/src/nrf53/nrf53_flash.c index bf795c255be8b..f8efaa1bff804 100644 --- a/arch/arm/src/nrf53/nrf53_flash.c +++ b/arch/arm/src/nrf53/nrf53_flash.c @@ -36,6 +36,9 @@ #include "hardware/nrf53_ficr.h" #include "hardware/nrf53_nvmc.h" +#ifdef CONFIG_NRF53_CACHE +# include "hardware/nrf53_cache.h" +#endif /**************************************************************************** * Pre-processor Definitions @@ -64,6 +67,35 @@ static inline uint32_t nrf53_get_pages_num(void) return getreg32(NRF53_FICR_INFO_CODESIZE); } +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* The CACHE peripheral caches both instruction and data accesses towards + * flash, and does not observe NVMC programming. A line held from before an + * erase or a write would otherwise satisfy the read-back that both paths use + * to verify what they just programmed -- up_progmem_ispageerased() reads a + * whole page, so the lines are commonly resident. + * + * Bypass the cache for the duration of the operation so the verify sees the + * array, then invalidate before re-enabling so later readers do too. + */ + +static void nrf53_flash_cache_bypass(void) +{ +#ifdef CONFIG_NRF53_CACHE + putreg32(0, NRF53_CACHE_ENABLE); +#endif +} + +static void nrf53_flash_cache_restore(void) +{ +#ifdef CONFIG_NRF53_CACHE + putreg32(CACHE_INVALIDATE_INVALIDATE, NRF53_CACHE_INVALIDATE); + putreg32(CACHE_ENABLE_ENABLE, NRF53_CACHE_ENABLE); +#endif +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -212,6 +244,8 @@ ssize_t up_progmem_eraseblock(size_t block) page_address = up_progmem_getaddress(block); + nrf53_flash_cache_bypass(); + /* Enable erase mode */ putreg32(NVMC_CONFIG_EEN, NRF53_NVMC_CONFIG); @@ -244,10 +278,12 @@ ssize_t up_progmem_eraseblock(size_t block) if (up_progmem_ispageerased(block) == 0) { + nrf53_flash_cache_restore(); return up_progmem_erasesize(block); } else { + nrf53_flash_cache_restore(); return -EIO; } } @@ -344,6 +380,8 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) addr += NRF53_FLASH_BASE; + nrf53_flash_cache_bypass(); + /* Begin flashing */ for (; count; count -= 4, pword++, addr += 4) @@ -378,10 +416,13 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count) if (getreg32(addr) != *pword) { + nrf53_flash_cache_restore(); return -EIO; } } + nrf53_flash_cache_restore(); + return written; } diff --git a/arch/arm/src/nrf53/nrf53_start.c b/arch/arm/src/nrf53/nrf53_start.c index 32a11e6334a68..d8ccc8e24928f 100644 --- a/arch/arm/src/nrf53/nrf53_start.c +++ b/arch/arm/src/nrf53/nrf53_start.c @@ -38,6 +38,7 @@ #include "nvic.h" #include "nrf53_clockconfig.h" +#include "hardware/nrf53_cache.h" #include "hardware/nrf53_nvmc.h" #include "hardware/nrf53_utils.h" #include "hardware/nrf53_uicr.h" @@ -253,6 +254,16 @@ void __start(void) nrf53_enable_profile(true); #endif +#ifdef CONFIG_NRF53_CACHE + /* Enable the application core CACHE peripheral. The nrf53_enable_icache() + * path above drives NVMC ICACHECNF and is gated on NRF53_FLASH_PREFETCH, + * which depends on NRF53_NETCORE, so nothing else enables a cache on the + * application core. + */ + + putreg32(CACHE_ENABLE_ENABLE, NRF53_CACHE_ENABLE); +#endif + #ifdef CONFIG_ARCH_PERF_EVENTS up_perf_init((void *)BOARD_SYSTICK_CLOCK); #endif