nios2: enable instruction/data caches
The caches get initialized on boot and flushed after XIP copy takes place. Change-Id: I642a14232835a0cf41e007860f5cdb8a2ade1f50 Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
47eb6096b1
commit
231e617593
6 changed files with 170 additions and 6 deletions
|
|
@ -4,6 +4,6 @@ ccflags-y += -I$(srctree)/kernel/microkernel/include
|
|||
|
||||
obj-y += reset.o irq_manage.o fatal.o swap.o thread.o \
|
||||
cpu_idle.o irq_offload.o prep_c.o crt0.o \
|
||||
exception.o sw_isr_table.o
|
||||
exception.o sw_isr_table.o cache.o
|
||||
|
||||
obj-$(CONFIG_IRQ_OFFLOAD) += irq_offload.o
|
||||
|
|
|
|||
72
arch/nios2/core/cache.c
Normal file
72
arch/nios2/core/cache.c
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
#include <arch/cpu.h>
|
||||
#include <misc/__assert.h>
|
||||
|
||||
|
||||
/**
|
||||
* Flush the entire instruction cache and pipeline.
|
||||
*
|
||||
* You will need to call this function if the application writes new program
|
||||
* text to memory, such as a boot copier or runtime synthesis of code. If the
|
||||
* new text was written with instructions that do not bypass cache memories,
|
||||
* this should immediately be followed by an invocation of
|
||||
* _nios2_dcache_flush_all() so that cached instruction data is committed to
|
||||
* RAM.
|
||||
*
|
||||
* See Chapter 9 of the Nios II Gen 2 Software Developer's Handbook for more
|
||||
* information on cache considerations.
|
||||
*/
|
||||
#if NIOS2_ICACHE_SIZE > 0
|
||||
void _nios2_icache_flush_all(void)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < NIOS2_ICACHE_SIZE; i += NIOS2_ICACHE_LINE_SIZE) {
|
||||
_nios2_icache_flush(i);
|
||||
}
|
||||
|
||||
/* Get rid of any stale instructions in the pipeline */
|
||||
_nios2_pipeline_flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Flush the entire data cache.
|
||||
*
|
||||
* This will be typically needed after writing new program text to memory
|
||||
* after flushing the instruction cache.
|
||||
*
|
||||
* The Nios II does not support hardware cache coherency for multi-master
|
||||
* or multi-processor systems and software coherency must be implemented
|
||||
* when communicating with shared memory. If support for this is introduced
|
||||
* in Zephyr additional APIs for flushing ranges of the data cache will need
|
||||
* to be implemented.
|
||||
*
|
||||
* See Chapter 9 of the Nios II Gen 2 Software Developer's Handbook for more
|
||||
* information on cache considerations.
|
||||
*/
|
||||
#if NIOS2_DCACHE_SIZE > 0
|
||||
void _nios2_dcache_flush_all(void)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < NIOS2_DCACHE_SIZE; i += NIOS2_DCACHE_LINE_SIZE) {
|
||||
_nios2_dcache_flush(i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -31,6 +31,7 @@ GTEXT(_interrupt_stack)
|
|||
*/
|
||||
.set noat
|
||||
|
||||
|
||||
#if CONFIG_INCLUDE_RESET_VECTOR
|
||||
/*
|
||||
* Reset vector entry point into the system. Placed into special 'reset'
|
||||
|
|
@ -42,15 +43,39 @@ GTEXT(_interrupt_stack)
|
|||
*/
|
||||
SECTION_FUNC(reset, __reset)
|
||||
|
||||
/* TODO initialize instruction cache, if present
|
||||
* ZEP-275
|
||||
#if NIOS2_ICACHE_SIZE > 0
|
||||
/* Aside from the instruction cache line associated with the reset
|
||||
* vector, the contents of the cache memories are indeterminate after
|
||||
* reset. To ensure cache coherency after reset, the reset handler
|
||||
* located at the reset vector must immediately initialize the
|
||||
* instruction cache. Next, either the reset handler or a subsequent
|
||||
* routine should proceed to initialize the data cache.
|
||||
*
|
||||
* The cache memory sizes are *always* a power of 2.
|
||||
*/
|
||||
#if NIOS2_ICACHE_SIZE > 0x8000
|
||||
movhi r2, %hi(NIOS2_ICACHE_SIZE)
|
||||
#else
|
||||
movui r2, NIOS2_ICACHE_SIZE
|
||||
#endif
|
||||
0:
|
||||
/* If ECC present, need to execute initd for each word address
|
||||
* to ensure ECC parity bits in data RAM get initialized
|
||||
*/
|
||||
#if NIOS2_ECC_PRESENT
|
||||
subi r2, r2, 4
|
||||
#else
|
||||
subi r2, r2, NIOS2_ICACHE_LINE_SIZE
|
||||
#endif
|
||||
initi r2
|
||||
bgt r2, zero, 0b
|
||||
#endif /* NIOS2_ICACHE_SIZE > 0 */
|
||||
|
||||
/* Done all we need to do here, jump to __text_start */
|
||||
movhi r1, %hi(__start)
|
||||
ori r1, r1, %lo(__start)
|
||||
jmp r1
|
||||
#endif
|
||||
#endif /* CONFIG_INCLUDE_RESET_VECTOR */
|
||||
|
||||
/* Remainder of asm-land initialization code before we can jump into
|
||||
* the C domain
|
||||
|
|
@ -61,9 +86,29 @@ SECTION_FUNC(TEXT, __start)
|
|||
* ZEP-258
|
||||
*/
|
||||
|
||||
/* TODO initialize data cache, if present
|
||||
* ZEP-275
|
||||
/* Initialize the data cache if booting from bare metal. If
|
||||
* we're not booting from our reset vector, either by a bootloader
|
||||
* or JTAG, assume caches already initialized.
|
||||
*/
|
||||
#if NIOS2_DCACHE_SIZE > 0 && defined(CONFIG_INCLUDE_RESET_VECTOR)
|
||||
/* Per documentation data cache size is always a power of two. */
|
||||
#if NIOS2_DCACHE_SIZE > 0x8000
|
||||
movhi r2, %hi(NIOS2_DCACHE_SIZE)
|
||||
#else
|
||||
movui r2, NIOS2_DCACHE_SIZE
|
||||
#endif
|
||||
0:
|
||||
/* If ECC present, need to execute initd for each word address
|
||||
* to ensure ECC parity bits in data RAM get initialized
|
||||
*/
|
||||
#if NIOS2_ECC_PRESENT
|
||||
subi r2, r2, 4
|
||||
#else
|
||||
subi r2, r2, NIOS2_DCACHE_LINE_SIZE
|
||||
#endif
|
||||
initd 0(r2)
|
||||
bgt r2, zero, 0b
|
||||
#endif /* NIOS2_DCACHE_SIZE && defined(CONFIG_INCLUDE_RESET_VECTOR) */
|
||||
|
||||
#ifdef CONFIG_INIT_STACKS
|
||||
/* Pre-populate all bytes in _interrupt_stack with 0xAA */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <stdint.h>
|
||||
#include <toolchain.h>
|
||||
#include <linker-defs.h>
|
||||
#include <nano_private.h>
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -68,6 +69,18 @@ static void dataCopy(void)
|
|||
for (n = 0; n < (unsigned int)&__data_num_words; n++) {
|
||||
pRAM[n] = pROM[n];
|
||||
}
|
||||
|
||||
/* In most XIP scenarios we copy the exception code into RAM, so need
|
||||
* to flush instruction cache.
|
||||
*/
|
||||
_nios2_icache_flush_all();
|
||||
#if NIOS2_ICACHE_SIZE > 0
|
||||
/* Only need to flush the data cache here if there actually is an
|
||||
* instruction cache, so that the cached instruction data written is
|
||||
* actually committed.
|
||||
*/
|
||||
_nios2_dcache_flush_all();
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static void dataCopy(void)
|
||||
|
|
|
|||
|
|
@ -200,6 +200,18 @@ static ALWAYS_INLINE int _IS_IN_ISR(void)
|
|||
void _irq_do_offload(void);
|
||||
#endif
|
||||
|
||||
#if NIOS2_ICACHE_SIZE > 0
|
||||
void _nios2_icache_flush_all(void);
|
||||
#else
|
||||
#define _nios2_icache_flush_all() do { } while (0)
|
||||
#endif
|
||||
|
||||
#if NIOS2_DCACHE_SIZE > 0
|
||||
void _nios2_dcache_flush_all(void);
|
||||
#else
|
||||
#define _nios2_dcache_flush_all() do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif /* _ASMLANGUAGE */
|
||||
|
||||
#endif /* _NANO_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -94,6 +94,28 @@ static inline void _nios2_report_stack_overflow(void)
|
|||
__asm__ volatile("break 3");
|
||||
}
|
||||
|
||||
/*
|
||||
* Low-level cache management functions
|
||||
*/
|
||||
static inline void _nios2_dcache_addr_flush(void *addr)
|
||||
{
|
||||
__asm__ volatile ("flushda (%0)" :: "r" (addr));
|
||||
}
|
||||
|
||||
static inline void _nios2_dcache_flush(uint32_t offset)
|
||||
{
|
||||
__asm__ volatile ("flushd (%0)" :: "r" (offset));
|
||||
}
|
||||
|
||||
static inline void _nios2_icache_flush(uint32_t offset)
|
||||
{
|
||||
__asm__ volatile ("flushi %0" :: "r" (offset));
|
||||
}
|
||||
|
||||
static inline void _nios2_pipeline_flush(void)
|
||||
{
|
||||
__asm__ volatile ("flushp");
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions for reading/writing control registers
|
||||
|
|
|
|||
Loading…
Reference in a new issue