112 lines
3.5 KiB
C
112 lines
3.5 KiB
C
/* 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.
|
||
*
|
||
* If we have MMU enabled, we don't need to do this right now.
|
||
* Let use the default configuration and properly configure the
|
||
* MMU when running from RAM.
|
||
*/
|
||
#ifndef CONFIG_MMU
|
||
ARCH_XTENSA_SET_RPO_TLB();
|
||
#endif
|
||
|
||
|
||
/* 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 */
|