arc: cache.h support added for em7d and em11d SOC

An implementation to flush multiple d-cache lines has been added
per the top-level cache.h API. ZEP-1153 was opened to express
the need for MORE i-cache and d-cache APIs. For example, the current
cache.h API doesn't provide a means to invalidate d-cache lines
and has nothing for i-cache.

I've also modified some of the i-cache related aux registers to have
better names so that they won't be confused with d-cache.
These changes are for
ZEP-1176.

Change-Id: If4c5410451cc40dcd5618fc871093c8febf7e061
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
This commit is contained in:
Chuck Jordan 2016-11-04 14:48:23 -07:00 committed by Andrew Boie
commit 381cb25f63
6 changed files with 240 additions and 15 deletions

View file

@ -269,8 +269,42 @@ config ARCH_HAS_NANO_FIBER_ABORT
# omit prompt to signify a "hidden" option
default n
endmenu
config CACHE_LINE_SIZE_DETECT
bool
prompt "Detect d-cache line size at runtime"
default n
help
This option enables querying the d-cache build register for finding
the d-cache line size at the expense of taking more memory and code
and a slightly increased boot time.
If the CPU's d-cache line size is known in advance, disable this
option and manually enter the value for CACHE_LINE_SIZE.
config CACHE_LINE_SIZE
int
prompt "Cache line size" if !CACHE_LINE_SIZE_DETECT
default 32
help
Size in bytes of a CPU d-cache line.
Detect automatically at runtime by selecting CACHE_LINE_SIZE_DETECT.
config ARCH_CACHE_FLUSH_DETECT
bool
default n
config CACHE_FLUSHING
bool
default n
prompt "Enable d-cache flushing mechanism"
help
This links in the sys_cache_flush() function, which provides a
way to flush multiple lines of the d-cache.
If the d-cache is present, set this to y.
If the d-cache is NOT present, set this to n.
endmenu
source "arch/arc/soc/*/Kconfig"

View file

@ -3,7 +3,7 @@ ccflags-y +=-I$(srctree)/arch/$(ARCH)/include
obj-y += thread.o thread_entry_wrapper.o \
cpu_idle.o fast_irq.o fatal.o fault.o \
fault_s.o irq_manage.o \
fault_s.o irq_manage.o cache.o \
isr_wrapper.o regular_irq.o swap_macros.h swap.o \
sys_fatal_error_handler.o

184
arch/arc/core/cache.c Normal file
View file

@ -0,0 +1,184 @@
/* cache.c - d-cache support for ARC CPUs */
/*
* Copyright (c) 2016 Synopsys, Inc. All rights reserved.
*
* 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.
*/
/**
* @file
* @brief d-cache manipulation
*
* This module contains functions for manipulation of the d-cache.
*/
#include <nanokernel.h>
#include <arch/cpu.h>
#include <misc/util.h>
#include <toolchain.h>
#include <cache.h>
#include <linker-defs.h>
#include <arch/arc/v2/aux_regs.h>
#include <nano_internal.h>
#include <misc/__assert.h>
#include <init.h>
#if defined(CONFIG_CACHE_FLUSHING)
#if (CONFIG_CACHE_LINE_SIZE == 0) && !defined(CONFIG_CACHE_LINE_SIZE_DETECT)
#error Cannot use this implementation with a cache line size of 0
#endif
#if defined(CONFIG_CACHE_LINE_SIZE_DETECT)
#define DCACHE_LINE_SIZE sys_cache_line_size
#else
#define DCACHE_LINE_SIZE CONFIG_CACHE_LINE_SIZE
#endif
#define DC_CTRL_DC_ENABLE 0x0 /* enable d-cache */
#define DC_CTRL_DC_DISABLE 0x1 /* disable d-cache */
#define DC_CTRL_INVALID_ONLY 0x0 /* invalid d-cache only */
#define DC_CTRL_INVALID_FLUSH 0x40 /* invalid and flush d-cache */
#define DC_CTRL_ENABLE_FLUSH_LOCKED 0x80 /* locked d-cache can be flushed */
#define DC_CTRL_DISABLE_FLUSH_LOCKED 0x0 /* locked d-cache cannot be flushed */
#define DC_CTRL_FLUSH_STATUS 0x100/* flush status */
#define DC_CTRL_DIRECT_ACCESS 0x0 /* direct access mode */
#define DC_CTRL_INDIRECT_ACCESS 0x20 /* indirect access mode */
#define DC_CTRL_OP_SUCCEEDED 0x4 /* d-cache operation succeeded */
static int dcache_available(void)
{
unsigned long val = _arc_v2_aux_reg_read(_ARC_V2_D_CACHE_BUILD);
val &= 0xff; /* extract version */
return (val == 0)?0:1;
}
static void dcache_dc_ctrl(uint32_t dcache_en_mask)
{
if (!dcache_available())
return;
_arc_v2_aux_reg_write(_ARC_V2_DC_CTRL, dcache_en_mask);
}
static void dcache_enable(void)
{
dcache_dc_ctrl(DC_CTRL_DC_ENABLE);
}
/**
*
* @brief Flush multiple d-cache lines to memory
*
* No alignment is required for either <start_addr> or <size>, but since
* dcache_flush_mlines() iterates on the d-cache lines, a cache line
* alignment for both is optimal.
*
* The d-cache line size is specified either via the CONFIG_CACHE_LINE_SIZE
* kconfig option or it is detected at runtime.
*
* @param start_addr the pointer to start the multi-line flush
* @param size the number of bytes that are to be flushed
*
* @return N/A
*/
static void dcache_flush_mlines(uint32_t start_addr, uint32_t size)
{
uint32_t end_addr;
unsigned int key;
if (!dcache_available() || (size == 0)) {
return;
}
end_addr = start_addr + size - 1;
start_addr &= (uint32_t)(~(DCACHE_LINE_SIZE - 1));
key = irq_lock(); /* --enter critical section-- */
do {
_arc_v2_aux_reg_write(_ARC_V2_DC_FLDL, start_addr);
__asm__ volatile("nop_s");
__asm__ volatile("nop_s");
__asm__ volatile("nop_s");
/* wait for flush completion */
do {
if ((_arc_v2_aux_reg_read(_ARC_V2_DC_CTRL) &
DC_CTRL_FLUSH_STATUS) == 0)
break;
} while (1);
start_addr += DCACHE_LINE_SIZE;
} while (start_addr <= end_addr);
irq_unlock(key); /* --exit critical section-- */
}
/**
*
* @brief Flush d-cache lines to main memory
*
* No alignment is required for either <virt> or <size>, but since
* sys_cache_flush() iterates on the d-cache lines, a d-cache line alignment for
* both is optimal.
*
* The d-cache line size is specified either via the CONFIG_CACHE_LINE_SIZE
* kconfig option or it is detected at runtime.
*
* @param start_addr the pointer to start the multi-line flush
* @param size the number of bytes that are to be flushed
*
* @return N/A
*/
void sys_cache_flush(vaddr_t start_addr, size_t size)
{
dcache_flush_mlines((uint32_t)start_addr, (uint32_t)size);
}
#if defined(CONFIG_CACHE_LINE_SIZE_DETECT)
size_t sys_cache_line_size;
static void init_dcache_line_size(void)
{
uint32_t val;
val = _arc_v2_aux_reg_read(_ARC_V2_D_CACHE_BUILD);
__ASSERT((val&0xff) != 0, "d-cache is not present");
val = ((val>>16) & 0xf) + 1;
val *= 16;
sys_cache_line_size = (size_t) val;
}
#endif
static int init_dcache(struct device *unused)
{
ARG_UNUSED(unused);
dcache_enable();
#if defined(CONFIG_CACHE_LINE_SIZE_DETECT)
init_dcache_line_size();
#endif
return 0;
}
SYS_INIT(init_dcache, PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
#endif /* CONFIG_CACHE_FLUSHING */

View file

@ -16,10 +16,10 @@
/**
* @file
* @brief Cache helper functions (ARC)
* @brief Cache helper functions and defines (ARC)
*
* This file contains private nanokernel structures definitions and various
* other definitions for the ARCv2 processor architecture.
* This file contains cache related functions and definitions for the
* ARCv2 processor architecture.
*/
#ifndef _ARCV2_CACHE__H_
@ -33,28 +33,29 @@ extern "C" {
#ifndef _ASMLANGUAGE
#define CACHE_ENABLE 0x00
#define CACHE_DISABLE 0x01
#define CACHE_DIRECT 0x00
#define CACHE_CACHE_CONTROLLED 0x20
/* i-cache defines for IC_CTRL register */
#define IC_CACHE_ENABLE 0x00
#define IC_CACHE_DISABLE 0x01
#define IC_CACHE_DIRECT 0x00
#define IC_CACHE_INDIRECT 0x20
/*
* @brief Sets the I-cache
* @brief Initialize the I-cache
*
* Enables cache and sets the direct access.
* Enables the i-cache and sets it to direct access mode.
*/
static ALWAYS_INLINE void _icache_setup(void)
{
uint32_t icache_config = (
CACHE_DIRECT | /* direct mapping (one-way assoc.) */
CACHE_ENABLE /* i-cache enabled */
IC_CACHE_DIRECT | /* direct mapping (one-way assoc.) */
IC_CACHE_ENABLE /* i-cache enabled */
);
uint32_t val;
val = _arc_v2_aux_reg_read(_ARC_V2_I_CACHE_BUILD);
val &= 0xff;
if (val != 0) {
/* configure i-cache if present */
if (val != 0) { /* is i-cache present? */
/* configure i-cache */
_arc_v2_aux_reg_write(_ARC_V2_IC_CTRL, icache_config);
}
}

View file

@ -65,6 +65,9 @@ config DCCM_BASE_ADDRESS
config DCCM_SIZE
default 64
config CACHE_FLUSHING
def_bool y
if GPIO
config GPIO_DW

View file

@ -65,6 +65,9 @@ config DCCM_BASE_ADDRESS
config DCCM_SIZE
default 128
config CACHE_FLUSHING
def_bool y
if GPIO
config GPIO_DW