Skip to content

Commit

Permalink
nios2: enable instruction/data caches
Browse files Browse the repository at this point in the history
The caches get initialized on boot and flushed after XIP copy
takes place.

Change-Id: I642a14232835a0cf41e007860f5cdb8a2ade1f50
Signed-off-by: Andrew Boie <[email protected]>
  • Loading branch information
Andrew Boie authored and inaky-intc committed Jul 1, 2016
1 parent 47eb609 commit 231e617
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 6 deletions.
2 changes: 1 addition & 1 deletion arch/nios2/core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 72 additions & 0 deletions arch/nios2/core/cache.c
Original file line number Diff line number Diff line change
@@ -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
55 changes: 50 additions & 5 deletions arch/nios2/core/crt0.S
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
Expand All @@ -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 */
Expand Down
13 changes: 13 additions & 0 deletions arch/nios2/core/prep_c.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <stdint.h>
#include <toolchain.h>
#include <linker-defs.h>
#include <nano_private.h>

/**
*
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions arch/nios2/include/nano_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
22 changes: 22 additions & 0 deletions include/arch/nios2/nios2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 231e617

Please sign in to comment.