diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 1b47e343b0b..7d75538efa1 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -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" diff --git a/arch/arc/core/Makefile b/arch/arc/core/Makefile index ea2fdf4d5ab..0ca3634f4f0 100644 --- a/arch/arc/core/Makefile +++ b/arch/arc/core/Makefile @@ -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 diff --git a/arch/arc/core/cache.c b/arch/arc/core/cache.c new file mode 100644 index 00000000000..c289c060fb1 --- /dev/null +++ b/arch/arc/core/cache.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 or , 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 or , 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 */ + diff --git a/arch/arc/include/v2/cache.h b/arch/arc/include/v2/cache.h index cefdc22e02d..891d3298f86 100644 --- a/arch/arc/include/v2/cache.h +++ b/arch/arc/include/v2/cache.h @@ -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); } } diff --git a/arch/arc/soc/em11d/Kconfig.defconfig b/arch/arc/soc/em11d/Kconfig.defconfig index ab77b745df4..9b964605d69 100644 --- a/arch/arc/soc/em11d/Kconfig.defconfig +++ b/arch/arc/soc/em11d/Kconfig.defconfig @@ -65,6 +65,9 @@ config DCCM_BASE_ADDRESS config DCCM_SIZE default 64 +config CACHE_FLUSHING + def_bool y + if GPIO config GPIO_DW diff --git a/arch/arc/soc/em7d/Kconfig.defconfig b/arch/arc/soc/em7d/Kconfig.defconfig index 8cdb9cb4fcd..3f4a563dd3a 100644 --- a/arch/arc/soc/em7d/Kconfig.defconfig +++ b/arch/arc/soc/em7d/Kconfig.defconfig @@ -65,6 +65,9 @@ config DCCM_BASE_ADDRESS config DCCM_SIZE default 128 +config CACHE_FLUSHING + def_bool y + if GPIO config GPIO_DW