blob: 571ae29f5b8a8f3bd71b7c9c397aea2aa2679731 [file] [log] [blame]
/* Copyright (c) 2021 Intel Corporation
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __INTEL_ADSP_CPU_INIT_H
#define __INTEL_ADSP_CPU_INIT_H
#include <zephyr/arch/arch_inlines.h>
#include <zephyr/arch/xtensa/arch.h>
#include <xtensa/config/core-isa.h>
#include <xtensa/corebits.h>
#include <adsp_memory.h>
#define MEMCTL_VALUE (MEMCTL_INV_EN | MEMCTL_ICWU_MASK | MEMCTL_DCWA_MASK | \
MEMCTL_DCWU_MASK | MEMCTL_L0IBUF_EN)
#define ATOMCTL_BY_RCW BIT(0) /* RCW Transaction for Bypass Memory */
#define ATOMCTL_WT_RCW BIT(2) /* RCW Transaction for Writethrough Cacheable Memory */
#define ATOMCTL_WB_RCW BIT(4) /* RCW Transaction for Writeback Cacheable Memory */
#define ATOMCTL_VALUE (ATOMCTL_BY_RCW | ATOMCTL_WT_RCW | ATOMCTL_WB_RCW)
/* Low-level CPU initialization. Call this immediately after entering
* C code to initialize the cache, protection and synchronization
* features.
*/
static ALWAYS_INLINE void cpu_early_init(void)
{
uint32_t reg;
#ifdef CONFIG_ADSP_NEED_POWER_ON_CACHE
/* First, we need to power the cache SRAM banks on! Write a bit
* for each cache way in the bottom half of the L1CCFG register
* and poll the top half for them to turn on.
*/
uint32_t dmask = BIT(ADSP_CxL1CCAP_DCMWC) - 1;
uint32_t imask = BIT(ADSP_CxL1CCAP_ICMWC) - 1;
uint32_t waymask = (imask << 8) | dmask;
ADSP_CxL1CCFG_REG = waymask;
while (((ADSP_CxL1CCFG_REG >> 16) & waymask) != waymask) {
}
/* Prefetcher also power gates, same interface */
ADSP_CxL1PCFG_REG = 1;
while ((ADSP_CxL1PCFG_REG & 0x10000) == 0) {
}
#endif
/* Now set up the Xtensa CPU to enable the cache logic. The
* details of the fields are somewhat complicated, but per the
* ISA ref: "Turning on caches at power-up usually consists of
* writing a constant with bits[31:8] all 1’s to MEMCTL.".
* Also set bit 0 to enable the LOOP extension instruction
* fetch buffer.
*/
#if XCHAL_USE_MEMCTL
reg = MEMCTL_VALUE;
XTENSA_WSR("MEMCTL", reg);
__asm__ volatile("rsync");
#endif
#if XCHAL_HAVE_THREADPTR
reg = 0;
XTENSA_WUR("THREADPTR", reg);
#endif
/* Likewise enable prefetching. Sadly these values are not
* architecturally defined by Xtensa (they're just documented
* as priority hints), so this constant is just copied from
* SOF for now. If we care about prefetch priority tuning
* we're supposed to ask Cadence I guess.
*/
reg = ADSP_L1_CACHE_PREFCTL_VALUE;
XTENSA_WSR("PREFCTL", reg);
__asm__ volatile("rsync");
/* Finally we need to enable the cache in the Region
* Protection Option "TLB" entries. The hardware defaults
* have this set to RW/uncached everywhere.
*/
ARCH_XTENSA_SET_RPO_TLB();
/* Initialize ATOMCTL: Hardware defaults for S32C1I use
* "internal" operations, meaning they are atomic only WRT the
* local CPU! We need external transactions on the shared
* bus.
*/
reg = ATOMCTL_VALUE;
XTENSA_WSR("ATOMCTL", reg);
/* Initialize interrupts to "disabled" */
reg = 0;
XTENSA_WSR("INTENABLE", reg);
/* Finally VECBASE. Note that on core 0 startup, we're still
* running in IMR and the vectors at this address won't be
* copied into HP-SRAM until later. That's OK, as interrupts
* are still disabled at this stage and will remain so
* consistently until Zephyr switches into the main thread.
*/
reg = VECBASE_RESET_PADDR_SRAM;
XTENSA_WSR("VECBASE", reg);
}
#endif /* __INTEL_ADSP_CPU_INIT_H */