mirror of https://github.com/wolfSSL/wolfBoot.git
173 lines
6.9 KiB
C
173 lines
6.9 KiB
C
/* imx95_m7.h
|
|
*
|
|
* Shared definitions for the Cortex-M7 on the NXP i.MX95.
|
|
*
|
|
* Copyright (C) 2026 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
|
|
*/
|
|
|
|
/* The shared-memory layout below is read by the A55 cluster running Linux, so
|
|
* it is described in exactly one place: the HAL, the console driver and the
|
|
* test app all include this header rather than repeating the addresses. */
|
|
|
|
#ifndef IMX95_M7_H
|
|
#define IMX95_M7_H
|
|
|
|
#include <stdint.h>
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Memory map
|
|
*
|
|
* The M7's reserved DDR window is memory@80000000, 16 MiB. wolfBoot's
|
|
* partitions sit in the lower part of it (BOOT 0x80100000, UPDATE 0x80500000,
|
|
* SWAP 0x80900000); the shared window below occupies the top of it, clear of
|
|
* the RPMsg reservations at 0x88000000 which belong to the transport.
|
|
*
|
|
* 0x80F00000 console header (16 B) + ring (65520 B)
|
|
* 0x80F10000 wolfBoot status block (4 words)
|
|
* 0x80F10010 test-app status block (2 words)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define M7_DDR_BASE 0x80000000UL
|
|
#define M7_DDR_SIZE 0x01000000UL
|
|
|
|
/* Console ring. CONSOLE_REGION is the whole 64 KiB page; the ring is what is
|
|
* left of it once the header is accounted for, so the console cannot run into
|
|
* the status block above it. Cortex-M7 has a hardware UDIV, so the
|
|
* non-power-of-two modulo in uart_tx() costs a few cycles, not a helper call. */
|
|
#define CONSOLE_BASE 0x80F00000UL
|
|
#define CONSOLE_HDR_SIZE 16UL
|
|
#define CONSOLE_REGION 0x00010000UL
|
|
#define CONSOLE_SIZE (CONSOLE_REGION - CONSOLE_HDR_SIZE)
|
|
/* Stored bytes are 57 43 4F 4E, so a hexdump of the ring reads "WCON". */
|
|
#define CONSOLE_MAGIC 0x4E4F4357UL
|
|
|
|
/* Status blocks. These are read one 32-bit word at a time with devmem, which
|
|
* prints the word rather than its bytes, so the magics are spelled to read
|
|
* correctly in that view ("WBOT", "APP1") - the opposite convention from
|
|
* CONSOLE_MAGIC above, which is read from a hexdump. */
|
|
#define WOLFBOOT_STATUS_ADDR 0x80F10000UL
|
|
#define WOLFBOOT_STATUS_WORDS 4U
|
|
#define WOLFBOOT_STATUS_MAGIC 0x57424F54UL /* "WBOT" */
|
|
|
|
#define APP_STATUS_ADDR (WOLFBOOT_STATUS_ADDR + (WOLFBOOT_STATUS_WORDS * 4UL))
|
|
#define APP_STATUS_WORDS 2U
|
|
#define APP_STATUS_MAGIC 0x41505031UL /* "APP1" */
|
|
|
|
/* The ring and the status block used to overlap by exactly the header size.
|
|
* Fail the build rather than let the two drift apart again. */
|
|
typedef char imx95_console_fits_below_status[
|
|
((CONSOLE_BASE + CONSOLE_HDR_SIZE + CONSOLE_SIZE) <= WOLFBOOT_STATUS_ADDR)
|
|
? 1 : -1];
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Barriers and cache maintenance
|
|
*
|
|
* Both L1 caches are off out of reset. Once they are on, note that "volatile"
|
|
* only binds the compiler: it places no barrier on the core, and the A55 is a
|
|
* genuinely separate observer of the shared window, so publish protocols need
|
|
* a real DMB.
|
|
*
|
|
* The ARMv7-M default memory map makes 0x80000000-0x9FFFFFFF Normal
|
|
* write-through, which is why M7 stores to the shared window reach DDR at all
|
|
* without maintenance. The explicit cleans below cost close to nothing on a
|
|
* write-through line and stop that inherited attribute from being load-bearing
|
|
* if a future MPU region, NO_MPU=0 or a different carveout base changes it.
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define DMB() __asm__ volatile ("dmb 0xF" ::: "memory")
|
|
#define DSB() __asm__ volatile ("dsb 0xF" ::: "memory")
|
|
#define ISB() __asm__ volatile ("isb 0xF" ::: "memory")
|
|
|
|
#define SCB_CCR (*(volatile uint32_t *)0xE000ED14UL)
|
|
#define SCB_CCSIDR (*(volatile uint32_t *)0xE000ED80UL)
|
|
#define SCB_CSSELR (*(volatile uint32_t *)0xE000ED84UL)
|
|
#define SCB_ICIALLU (*(volatile uint32_t *)0xE000EF50UL)
|
|
#define SCB_DCISW (*(volatile uint32_t *)0xE000EF60UL)
|
|
#define SCB_DCCMVAC (*(volatile uint32_t *)0xE000EF68UL)
|
|
#define SCB_DCCSW (*(volatile uint32_t *)0xE000EF6CUL)
|
|
#define CCR_IC (1UL << 17)
|
|
#define CCR_DC (1UL << 16)
|
|
|
|
/* Cortex-M7 L1 line size. Also derived from CCSIDR where the set/way loops
|
|
* need it; this constant is only for maintenance by address. */
|
|
#define IMX95_CACHE_LINE 32UL
|
|
|
|
static inline void imx95_dcache_clean(const void *addr, uint32_t len)
|
|
{
|
|
uint32_t line;
|
|
uint32_t end;
|
|
|
|
if (len == 0)
|
|
return;
|
|
line = ((uint32_t)(uintptr_t)addr) & ~(IMX95_CACHE_LINE - 1UL);
|
|
end = (uint32_t)(uintptr_t)addr + len;
|
|
for (; line < end; line += IMX95_CACHE_LINE) {
|
|
SCB_DCCMVAC = line;
|
|
}
|
|
DSB();
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* DWT cycle counter
|
|
*
|
|
* With no console UART routed on this carrier the cycle counter is how boot
|
|
* cost gets measured: exact, free to read, and needing no peripheral.
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define CORE_DEMCR (*(volatile uint32_t *)0xE000EDFCUL)
|
|
#define DEMCR_TRCENA (1UL << 24)
|
|
#define DWT_CTRL (*(volatile uint32_t *)0xE0001000UL)
|
|
#define DWT_CYCCNTENA (1UL << 0)
|
|
#define DWT_CYCCNT (*(volatile uint32_t *)0xE0001004UL)
|
|
|
|
/* Idempotent: a second caller must not restart a counter someone else is
|
|
* already extending to 64 bits. */
|
|
static inline void imx95_dwt_init(void)
|
|
{
|
|
if ((DWT_CTRL & DWT_CYCCNTENA) != 0UL)
|
|
return;
|
|
CORE_DEMCR |= DEMCR_TRCENA;
|
|
DWT_CYCCNT = 0;
|
|
DWT_CTRL |= DWT_CYCCNTENA;
|
|
}
|
|
|
|
/* Bounded spin. Wrap-safe for any delay shorter than a full 32-bit period
|
|
* (~5.4 s at 800 MHz) because the comparison is done on the difference. */
|
|
static inline void imx95_delay_cycles(uint32_t cycles)
|
|
{
|
|
uint32_t start = DWT_CYCCNT;
|
|
|
|
while ((uint32_t)(DWT_CYCCNT - start) < cycles)
|
|
;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* SysTick (test app only; wolfBoot itself runs with interrupts off)
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
#define SYST_CSR (*(volatile uint32_t *)0xE000E010UL)
|
|
#define SYST_RVR (*(volatile uint32_t *)0xE000E014UL)
|
|
#define SYST_CVR (*(volatile uint32_t *)0xE000E018UL)
|
|
#define SYST_CSR_ENABLE (1UL << 0)
|
|
#define SYST_CSR_TICKINT (1UL << 1)
|
|
#define SYST_CSR_CLKSOURCE (1UL << 2)
|
|
#define SYST_RVR_MAX 0x00FFFFFFUL
|
|
|
|
#endif /* IMX95_M7_H */
|