From: Javier Jalle <javier.ja...@gaisler.com> --- c/src/lib/libbsp/sparc/Makefile.am | 4 + c/src/lib/libbsp/sparc/leon2/Makefile.am | 4 + c/src/lib/libbsp/sparc/leon2/preinstall.am | 4 + c/src/lib/libbsp/sparc/leon3/Makefile.am | 4 + c/src/lib/libbsp/sparc/leon3/preinstall.am | 4 + c/src/lib/libbsp/sparc/shared/include/l2c.h | 201 +++ c/src/lib/libbsp/sparc/shared/l2c/l2c.c | 2109 +++++++++++++++++++++++++++ cpukit/libdrvmgr/drvmgr_confdefs.h | 4 + 8 files changed, 2334 insertions(+) create mode 100644 c/src/lib/libbsp/sparc/shared/include/l2c.h create mode 100644 c/src/lib/libbsp/sparc/shared/l2c/l2c.c
diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am index 0691dd4..43e1d9e 100644 --- a/c/src/lib/libbsp/sparc/Makefile.am +++ b/c/src/lib/libbsp/sparc/Makefile.am @@ -95,6 +95,10 @@ EXTRA_DIST += shared/include/grcan.h # MEM EXTRA_DIST += shared/mem/mctrl.c +# L2CACHE +EXTRA_DIST += shared/l2c/l2c.c +EXTRA_DIST += shared/include/l2c.h + # MIL-STD-B1553 (Core1553BRM) EXTRA_DIST += shared/1553/b1553brm.c EXTRA_DIST += shared/1553/b1553rt.c diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am b/c/src/lib/libbsp/sparc/leon2/Makefile.am index 8e424d8..29a2ebd 100644 --- a/c/src/lib/libbsp/sparc/leon2/Makefile.am +++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am @@ -188,6 +188,10 @@ libbsp_a_SOURCES += ../../sparc/shared/analog/gradcdac.c libbsp_a_SOURCES += ../../sparc/shared/mem/mctrl.c include_bsp_HEADERS += ../../sparc/shared/include/mctrl.h +# l2cache +libbsp_a_SOURCES += ../../sparc/shared/l2c/l2c.c +include_bsp_HEADERS += ../../sparc/shared/include/l2c.h + # timer libbsp_a_SOURCES += timer/timer.c diff --git a/c/src/lib/libbsp/sparc/leon2/preinstall.am b/c/src/lib/libbsp/sparc/leon2/preinstall.am index f249c3c..c37b77a 100644 --- a/c/src/lib/libbsp/sparc/leon2/preinstall.am +++ b/c/src/lib/libbsp/sparc/leon2/preinstall.am @@ -253,6 +253,10 @@ $(PROJECT_INCLUDE)/bsp/mctrl.h: ../../sparc/shared/include/mctrl.h $(PROJECT_INC $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/mctrl.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/mctrl.h +$(PROJECT_INCLUDE)/bsp/l2c.h: ../../sparc/shared/include/l2c.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/l2c.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/l2c.h + $(PROJECT_INCLUDE)/bsp/grtc.h: ../../sparc/shared/include/grtc.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/grtc.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/grtc.h diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am index fe17bf0..84669b7 100644 --- a/c/src/lib/libbsp/sparc/leon3/Makefile.am +++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am @@ -205,6 +205,10 @@ libbsp_a_SOURCES += ../../sparc/shared/analog/gradcdac.c libbsp_a_SOURCES += ../../sparc/shared/mem/mctrl.c include_bsp_HEADERS += ../../sparc/shared/include/mctrl.h +# l2cache +libbsp_a_SOURCES += ../../sparc/shared/l2c/l2c.c +include_bsp_HEADERS += ../../sparc/shared/include/l2c.h + # timer libbsp_a_SOURCES += timer/timer.c libbsp_a_SOURCES += timer/watchdog.c diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am b/c/src/lib/libbsp/sparc/leon3/preinstall.am index b517758..84ec208 100644 --- a/c/src/lib/libbsp/sparc/leon3/preinstall.am +++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am @@ -281,6 +281,10 @@ $(PROJECT_INCLUDE)/bsp/mctrl.h: ../../sparc/shared/include/mctrl.h $(PROJECT_INC $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/mctrl.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/mctrl.h +$(PROJECT_INCLUDE)/bsp/l2c.h: ../../sparc/shared/include/l2c.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/l2c.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/l2c.h + $(PROJECT_INCLUDE)/bsp/watchdog.h: include/watchdog.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/watchdog.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/watchdog.h diff --git a/c/src/lib/libbsp/sparc/shared/include/l2c.h b/c/src/lib/libbsp/sparc/shared/include/l2c.h new file mode 100644 index 0000000..52473dd --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/include/l2c.h @@ -0,0 +1,201 @@ +/* + * GRLIB L2CACHE Driver + * + * COPYRIGHT (c) 2017 + * Cobham Gaisler AB + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + * OVERVIEW + * ======== + * This driver controls the L2CACHE device located + * at an on-chip AMBA. + */ + +#ifndef __L2CACHE_H__ +#define __L2CACHE_H__ + +#include <stdint.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern void l2cache_register_drv(void); + +#define L2CACHE_ERR_OK 0 +#define L2CACHE_ERR_NOINIT -1 +#define L2CACHE_ERR_EINVAL -2 +#define L2CACHE_ERR_TOOMANY -3 +#define L2CACHE_ERR_ERROR -4 + +/* L2C Flush options */ +#define L2CACHE_OPTIONS_FLUSH_WAIT (0x1 << 2) +#define L2CACHE_OPTIONS_FLUSH_INVALIDATE (0x3 << 0) +#define L2CACHE_OPTIONS_FLUSH_WRITEBACK (0x2 << 0) +#define L2CACHE_OPTIONS_FLUSH_INV_WBACK (0x1 << 0) +#define L2CACHE_OPTIONS_FLUSH_NONE (0 << 0) + +/* L2C Status */ +#define L2CACHE_STATUS_ENABLED 1 +#define L2CACHE_STATUS_SPLIT_ENABLED (0x1 << 1) +#define L2CACHE_STATUS_EDAC_ENABLED (0x1 << 2) +#define L2CACHE_STATUS_REPL (0x3 << L2CACHE_STATUS_REPL_BIT) +#define L2CACHE_STATUS_REPL_BIT 3 +#define L2CACHE_STATUS_WRITETHROUGH (0x1 << 5) +#define L2CACHE_STATUS_LOCK (0xf << L2CACHE_STATUS_LOCK_BIT) +#define L2CACHE_STATUS_LOCK_BIT 6 +#define L2CACHE_STATUS_SCRUB_ENABLED (0x1 << 10) +#define L2CACHE_STATUS_INT (0xf << L2CACHE_STATUS_INT_BIT) +#define L2CACHE_STATUS_INT_BIT 11 +#define L2CACHE_STATUS_INT_BCKEND (0x1 << 11) +#define L2CACHE_STATUS_INT_WPHIT (0x1 << 12) +#define L2CACHE_STATUS_INT_UEE (0x1 << 13) +#define L2CACHE_STATUS_INT_CEE (0x1 << 14) +#define L2CACHE_STATUS_SCRUB_DELAY (0xffff << L2CACHE_STATUS_SCRUB_DELAY_BIT) +#define L2CACHE_STATUS_SCRUB_DELAY_BIT 15 +#define L2CACHE_STATUS_SIGN_BIT 31 + +/* status helper macros */ +#define L2CACHE_ENABLED(status) (status & L2CACHE_STATUS_ENABLED) +#define L2CACHE_DISABLED(status) (!(status & L2CACHE_STATUS_ENABLED)) +#define L2CACHE_SPLIT_ENABLED(status) (status & L2CACHE_STATUS_SPLIT_ENABLED) +#define L2CACHE_SPLIT_DISABLED(status) \ + (!(status & L2CACHE_STATUS_SPLIT_ENABLED)) +#define L2CACHE_EDAC_ENABLED(status) (status & L2CACHE_STATUS_EDAC_ENABLED) +#define L2CACHE_EDAC_DISABLED(status) (!(status & L2CACHE_STATUS_EDAC_ENABLED)) +#define L2CACHE_REPL(status) \ + ((status & L2CACHE_STATUS_REPL) >> L2CACHE_STATUS_REPL_BIT) +#define L2CACHE_WRITETHROUGH(status) (status & L2CACHE_STATUS_WRITETHROUGH) +#define L2CACHE_WRITEBACK(status) (!(status & L2CACHE_STATUS_WRITETHROUGH)) +#define L2CACHE_LOCKED_WAYS(status) \ + ((status & L2CACHE_STATUS_LOCK) >> L2CACHE_STATUS_LOCK_BIT) +#define L2CACHE_SCRUB_ENABLED(status) (status & L2CACHE_STATUS_SCRUB_ENABLED) +#define L2CACHE_SCRUB_DISABLED(status) \ + (!(status & L2CACHE_STATUS_SCRUB_ENABLED)) +#define L2CACHE_SCRUB_DELAY(status) \ + ((status & L2CACHE_STATUS_SCRUB_DELAY) >> L2CACHE_STATUS_SCRUB_DELAY_BIT) +#define L2CACHE_INT_ENABLED(status) (status & L2CACHE_STATUS_INT) +#define L2CACHE_INT_DISABLED(status) (!(status & L2CACHE_STATUS_INT)) +extern int l2cache_status(void); + +/* L2C Setup */ +extern int l2cache_enable(int flush); +extern int l2cache_disable(int flush); + +extern int l2cache_split_enable(void); +extern int l2cache_split_disable(void); + +extern int l2cache_edac_enable(int flush); +extern int l2cache_edac_disable(int flush); + +extern int l2cache_scrub_enable(int delay); +extern int l2cache_scrub_disable(void); +extern int l2cache_scrub_line(int way, int index); + +extern int l2cache_writethrough(int flush); +extern int l2cache_writeback(int flush); + +#define L2CACHE_OPTIONS_REPL_INDEX_WAY_BIT (2) +#define L2CACHE_OPTIONS_REPL_MASTERIDX_MOD (3 << 0) +#define L2CACHE_OPTIONS_REPL_MASTERIDX_IDX (2 << 0) +#define L2CACHE_OPTIONS_REPL_RANDOM (1 << 0) +#define L2CACHE_OPTIONS_REPL_LRU (0 << 0) +extern int l2cache_replacement(int options, int flush); + +/* L2C Flush */ +extern int l2cache_flush(int flush); +extern int l2cache_flush_address(uint32_t addr, int size, int flush); +extern int l2cache_flush_line(int way, int index, int flush); +extern int l2cache_flush_way(int way, int flush); + +/* L2C Lock way */ +#define L2CACHE_OPTIONS_DIRTY (0x1 << 2) +#define L2CACHE_OPTIONS_VALID (0x1 << 1) +#define L2CACHE_OPTIONS_FETCH (0x1 << 0) +#define L2CACHE_OPTIONS_DISABLE 2 +#define L2CACHE_OPTIONS_ENABLE 1 +#define L2CACHE_OPTIONS_NONE 0 +extern int l2cache_lock_way(uint32_t tag, int options, int flush, int enable); +extern int l2cache_unlock(void); + +/* L2C Fill a way */ +extern int l2cache_fill_way(int way, uint32_t tag, int options, int flush); + +/* L2C MTRR */ +#define L2CACHE_OPTIONS_MTRR_ACCESS_WRITETHROUGH (0x1 << 2) +#define L2CACHE_OPTIONS_MTRR_ACCESS_UNCACHED (0x0 << 2) +#define L2CACHE_OPTIONS_MTRR_WRITEPROT_ENABLE (0x1 << 1) +#define L2CACHE_OPTIONS_MTRR_WRITEPROT_DISABLE (0x0 << 1) +extern int l2cache_mtrr_enable(int id, uint32_t addr, uint32_t mask, + int options, int flush); +extern int l2cache_mtrr_disable(int id); + +/* L2C Debug print */ +extern int l2cache_print(void); + +/* L2C Interrupts */ +/* Function Interrupt-Code ISR callback prototype. + * arg - Custom arg provided by user + * addr - Cacheline addr that generated the error + * status - Error status register of the L2CACHE core + */ +typedef void (*l2cache_isr_t)(void *arg, uint32_t addr, uint32_t status); +#define L2CACHE_INTERRUPT_ALL (0xf << 0) +#define L2CACHE_INTERRUPT_BACKENDERROR (0x1 << 3) +#define L2CACHE_INTERRUPT_WPROTHIT (0x1 << 2) +#define L2CACHE_INTERRUPT_UNCORRERROR (0x1 << 1) +#define L2CACHE_INTERRUPT_CORRERROR (0x1 << 0) +extern int l2cache_isr_register( l2cache_isr_t isr, void * arg, int options); +extern int l2cache_isr_unregister(void); +extern int l2cache_interrupt_mask(int options); +extern int l2cache_interrupt_unmask(int options); + +/* L2C error interface */ +#define L2CACHE_STATUS_MULTIPLEERRORS 2 +#define L2CACHE_STATUS_NEWERROR 1 +#define L2CACHE_STATUS_NOERROR 0 +extern int l2cache_error_status(uint32_t * addr, uint32_t * status); + +/*#define TEST_L2CACHE*/ +#ifdef TEST_L2CACHE +/* Used for internal testing */ +/* + * L2CACHE Tag private data struture + */ +struct l2cache_tag { + uint32_t tag; + int valid; + int dirty; + int lru; +}; + +/* + * L2CACHE Line private data struture + */ +struct l2cache_dataline { + uint32_t data[16]; + int words; +}; +extern int l2cache_get_index( uint32_t addr); +extern uint32_t l2cache_get_tag( uint32_t addr); + +extern int l2cache_diag_tag( int way, int index, struct l2cache_tag * tag); +extern int l2cache_diag_line( int way, int index, + struct l2cache_dataline * dataline); + +#define L2CACHE_HIT 1 +#define L2CACHE_MISS 0 +extern int l2cache_lookup(uint32_t addr, int * way); + +extern int l2cache_error_inject_address( uint32_t addr, uint32_t mask); +#endif /* TEST_L2CACHE */ + +#ifdef __cplusplus +} +#endif + +#endif /* __L2CACHE_H__ */ diff --git a/c/src/lib/libbsp/sparc/shared/l2c/l2c.c b/c/src/lib/libbsp/sparc/shared/l2c/l2c.c new file mode 100644 index 0000000..0388a13 --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/l2c/l2c.c @@ -0,0 +1,2109 @@ +/* + * GRLIB L2CACHE Driver + * + * COPYRIGHT (c) 2017 + * Cobham Gaisler AB + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <stdlib.h> +#include <drvmgr/drvmgr.h> +#include <drvmgr/ambapp_bus.h> +#include <ambapp.h> +#include <rtems.h> +#include <rtems/bspIo.h> +#include <grlib.h> +#include <bsp.h> +#include <bsp/l2c.h> + +/*#define STATIC*/ +#define STATIC static + +/*#define INLINE*/ +#define INLINE inline + +#define UNUSED __attribute__((unused)) + +/*#define DEBUG 1*/ + +#ifdef DEBUG +#define DBG(x...) printf(x) +#else +#define DBG(x...) +#endif + +/* + * L2CACHE CTRL register fields + */ +#define L2C_CTRL_EN (0x1 << L2C_CTRL_EN_BIT) +#define L2C_CTRL_EDAC (0x1 << L2C_CTRL_EDAC_BIT) +#define L2C_CTRL_REPL (0x3 << L2C_CTRL_REPL_BIT) +#define L2C_CTRL_IWAY (0xf << L2C_CTRL_IWAY_BIT) +#define L2C_CTRL_LOCK (0xf << L2C_CTRL_LOCK_BIT) +#define L2C_CTRL_HPRHB (0x1 << L2C_CTRL_HPRHB_BIT) +#define L2C_CTRL_HPB (0x1 << L2C_CTRL_HPB_BIT) +#define L2C_CTRL_UC (0x1 << L2C_CTRL_UC_BIT) +#define L2C_CTRL_HC (0x1 << L2C_CTRL_HC_BIT) +#define L2C_CTRL_WP (0x1 << L2C_CTRL_WP_BIT) +#define L2C_CTRL_HP (0x1 << L2C_CTRL_HP_BIT) + +#define L2C_CTRL_EN_BIT 31 +#define L2C_CTRL_EDAC_BIT 30 +#define L2C_CTRL_REPL_BIT 28 +#define L2C_CTRL_IWAY_BIT 12 +#define L2C_CTRL_LOCK_BIT 8 +#define L2C_CTRL_HPRHB_BIT 5 +#define L2C_CTRL_HPB_BIT 4 +#define L2C_CTRL_UC_BIT 3 +#define L2C_CTRL_HC_BIT 2 +#define L2C_CTRL_WP_BIT 1 +#define L2C_CTRL_HP_BIT 0 + +/* + * L2CACHE STATUS register fields + */ +#define L2C_STAT_LS (0x1 << L2C_STAT_LS_BIT) +#define L2C_STAT_AT (0x1 << L2C_STAT_AT_BIT) +#define L2C_STAT_MP (0x1 << L2C_STAT_MP_BIT) +#define L2C_STAT_MTRR (0x3f << L2C_STAT_MTRR_BIT) +#define L2C_STAT_BBUSW (0x7 << L2C_STAT_BBUSW_BIT) +#define L2C_STAT_WAYSIZE (0x7ff << L2C_STAT_WAYSIZE_BIT) +#define L2C_STAT_WAY (0x3 << L2C_STAT_WAY_BIT) + +#define L2C_STAT_LS_BIT 24 +#define L2C_STAT_AT_BIT 23 +#define L2C_STAT_MP_BIT 22 +#define L2C_STAT_MTRR_BIT 16 +#define L2C_STAT_BBUSW_BIT 13 +#define L2C_STAT_WAYSIZE_BIT 2 +#define L2C_STAT_WAY_BIT 0 + +/* + * L2CACHE MTRR register fields + */ +#define L2C_MTRR_ADDR (0x3fff << L2C_MTRR_ADDR_BIT) +#define L2C_MTRR_ACC (0x3 << L2C_MTRR_ACC_BIT) +#define L2C_MTRR_MASK (0x3fff << L2C_MTRR_MASK_BIT) +#define L2C_MTRR_WP (0x1 << L2C_MTRR_WP_BIT) +#define L2C_MTRR_AC (0x1 << L2C_MTRR_AC_BIT) + +#define L2C_MTRR_ADDR_BIT 18 +#define L2C_MTRR_ACC_BIT 16 +#define L2C_MTRR_MASK_BIT 2 +#define L2C_MTRR_WP_BIT 1 +#define L2C_MTRR_AC_BIT 0 + +#define L2C_MTRR_UNCACHED 0 +#define L2C_MTRR_WRITETHROUGH (0x1 << L2C_MTRR_ACC_BIT) +#define L2C_MTRR_WRITEPROT_ENABLE L2C_MTRR_WP +#define L2C_MTRR_WRITEPROT_DISABLE 0 +#define L2C_MTRR_ACCESSCONTROL_ENABLE L2C_MTRR_AC +#define L2C_MTRR_ACCESSCONTROL_DISABLE 0 + +#define REG_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (unsigned int)(val)) +#define REG_READ(addr) (*(volatile unsigned int *)(addr)) + +/* + * L2CACHE FLUSHMEM register fields + */ +#define L2C_FLUSH_ADDR (0x7ffffff << L2C_FLUSH_ADDR_BIT) +#define L2C_FLUSH_DI (0x1 << L2C_FLUSH_DI_BIT) +#define L2C_FLUSH_FMODE (0x7 << L2C_FLUSH_FMODE_BIT) + +#define L2C_FLUSH_ADDR_BIT 5 +#define L2C_FLUSH_DI_BIT 3 +#define L2C_FLUSH_FMODE_BIT 0 + +#define L2C_FLUSH_FMODE_INV_ONE (0x1 << L2C_FLUSH_FMODE_BIT) +#define L2C_FLUSH_FMODE_WB_ONE (0x2 << L2C_FLUSH_FMODE_BIT) +#define L2C_FLUSH_FMODE_INV_WB_ONE (0x3 << L2C_FLUSH_FMODE_BIT) +#define L2C_FLUSH_FMODE_INV_ALL (0x5 << L2C_FLUSH_FMODE_BIT) +#define L2C_FLUSH_FMODE_WB_ALL (0x6 << L2C_FLUSH_FMODE_BIT) +#define L2C_FLUSH_FMODE_INV_WB_ALL (0x7 << L2C_FLUSH_FMODE_BIT) + +/* + * L2CACHE FLUSSETINDEX register fields + */ +#define L2C_FLUSHSI_INDEX (0xffff << L2C_FLUSHSI_INDEX_BIT) +#define L2C_FLUSHSI_TAG (0x3fffff << L2C_FLUSHSI_TAG_BIT) +#define L2C_FLUSHSI_FL (0x1 << L2C_FLUSHSI_FL_BIT) +#define L2C_FLUSHSI_VB (0x1 << L2C_FLUSHSI_VB_BIT) +#define L2C_FLUSHSI_DB (0x1 << L2C_FLUSHSI_DB_BIT) +#define L2C_FLUSHSI_WAY (0x3 << L2C_FLUSHSI_WAY_BIT) +#define L2C_FLUSHSI_DI (0x1 << L2C_FLUSHSI_DI_BIT) +#define L2C_FLUSHSI_WF (0x1 << L2C_FLUSHSI_WF_BIT) +#define L2C_FLUSHSI_FMODE (0x3 << L2C_FLUSHSI_FMODE_BIT) + +#define L2C_FLUSHSI_INDEX_BIT 16 +#define L2C_FLUSHSI_TAG_BIT 10 +#define L2C_FLUSHSI_FL_BIT 9 +#define L2C_FLUSHSI_VB_BIT 8 +#define L2C_FLUSHSI_DB_BIT 7 +#define L2C_FLUSHSI_WAY_BIT 4 +#define L2C_FLUSHSI_DI_BIT 3 +#define L2C_FLUSHSI_WF_BIT 2 +#define L2C_FLUSHSI_FMODE_BIT 0 + +#define L2C_FLUSHSI_FMODE_SET_INV_ONE (0x1 << L2C_FLUSHSI_FMODE_BIT) +#define L2C_FLUSHSI_FMODE_SET_WB_ONE (0x2 << L2C_FLUSHSI_FMODE_BIT) +#define L2C_FLUSHSI_FMODE_SET_INV_WB_ONE (0x3 << L2C_FLUSHSI_FMODE_BIT) +#define L2C_FLUSHSI_FMODE_WAY_UPDATE (0x1 << L2C_FLUSHSI_FMODE_BIT) +#define L2C_FLUSHSI_FMODE_WAY_WB (0x2 << L2C_FLUSHSI_FMODE_BIT) +#define L2C_FLUSHSI_FMODE_WAY_UPDATE_WB_ALL (0x3 << L2C_FLUSHSI_FMODE_BIT) + +/* + * L2CACHE ERROR register fields + */ +#define L2C_ERROR_AHBM (0xf << L2C_ERROR_AHBM_BIT) +#define L2C_ERROR_SCRUB (0x1 << L2C_ERROR_SCRUB_BIT) +#define L2C_ERROR_TYPE (0x7 << L2C_ERROR_TYPE_BIT) +#define L2C_ERROR_TAG (0x1 << L2C_ERROR_TAG_BIT) +#define L2C_ERROR_COR (0x1 << L2C_ERROR_COR_BIT) +#define L2C_ERROR_MULTI (0x1 << L2C_ERROR_MULTI_BIT) +#define L2C_ERROR_VALID (0x1 << L2C_ERROR_VALID_BIT) +#define L2C_ERROR_DISERESP (0x1 << L2C_ERROR_DISERESP_BIT) +#define L2C_ERROR_CEC (0x7 << L2C_ERROR_CEC_BIT) +#define L2C_ERROR_IRQP (0xf << L2C_ERROR_IRQP_BIT) +#define L2C_ERROR_IRQM (0xf << L2C_ERROR_IRQM_BIT) +#define L2C_ERROR_IRQM_BCKEND (0x1 << L2C_ERROR_IRQM_BCKEND_BIT) +#define L2C_ERROR_IRQM_WPROT (0x1 << L2C_ERROR_IRQM_WPROT_BIT) +#define L2C_ERROR_IRQM_UNCORR (0x1 << L2C_ERROR_IRQM_UNCORR_BIT) +#define L2C_ERROR_IRQM_CORR (0x1 << L2C_ERROR_IRQM_CORR_BIT) +#define L2C_ERROR_SCB (0x3 << L2C_ERROR_SCB_BIT) +#define L2C_ERROR_STCB (0x3 << L2C_ERROR_STCB_BIT) +#define L2C_ERROR_XCB (0x1 << L2C_ERROR_XCB_BIT) +#define L2C_ERROR_RCB (0x1 << L2C_ERROR_RCB_BIT) +#define L2C_ERROR_COMP (0x1 << L2C_ERROR_COMP_BIT) +#define L2C_ERROR_RST (0x1 << L2C_ERROR_RST_BIT) + +#define L2C_ERROR_AHBM_BIT 28 +#define L2C_ERROR_SCRUB_BIT 27 +#define L2C_ERROR_TYPE_BIT 24 +#define L2C_ERROR_TAG_BIT 23 +#define L2C_ERROR_COR_BIT 22 +#define L2C_ERROR_MULTI_BIT 21 +#define L2C_ERROR_VALID_BIT 20 +#define L2C_ERROR_DISERESP_BIT 19 +#define L2C_ERROR_CEC_BIT 16 +#define L2C_ERROR_IRQP_BIT 12 +#define L2C_ERROR_IRQM_BCKEND_BIT 11 +#define L2C_ERROR_IRQM_WPROT_BIT 10 +#define L2C_ERROR_IRQM_UNCORR_BIT 9 +#define L2C_ERROR_IRQM_CORR_BIT 8 +#define L2C_ERROR_IRQM_BIT 8 +#define L2C_ERROR_SCB_BIT 6 +#define L2C_ERROR_STCB_BIT 4 +#define L2C_ERROR_XCB_BIT 3 +#define L2C_ERROR_RCB_BIT 2 +#define L2C_ERROR_COMP_BIT 1 +#define L2C_ERROR_RST_BIT 0 + +/* + * L2CACHE DATA CHECK BITS register fields + */ +#define L2C_DCB_CB (0xfffffff << L2C_DCB_CB_BIT) + +#define L2C_DCB_CB_BIT 0 + +/* + * L2CACHE SCRUB register fields + */ +#define L2C_SCRUB_INDEX (0xffff << L2C_SCRUB_INDEX_BIT) +#define L2C_SCRUB_WAY (0x3 << L2C_SCRUB_WAY_BIT) +#define L2C_SCRUB_PEN (0x1 << L2C_SCRUB_PEN_BIT) +#define L2C_SCRUB_EN (0x1 << L2C_SCRUB_EN_BIT) + +#define L2C_SCRUB_INDEX_BIT 16 +#define L2C_SCRUB_WAY_BIT 2 +#define L2C_SCRUB_PEN_BIT 1 +#define L2C_SCRUB_EN_BIT 0 + +/* + * L2CACHE SCRUBDELAY register fields + */ +#define L2C_SCRUB_DEL (0xffff << L2C_SCRUB_DEL_BIT) + +#define L2C_SCRUB_DEL_BIT 0 + +/* + * L2CACHE ERROR INJECT register fields + */ +#define L2C_ERRINJ_ADDR (0x3fffffff << L2C_ERRINJ_ADDR_BIT) +#define L2C_ERRINJ_EN (0x1 << L2C_ERRINJ_EN_BIT) + +#define L2C_ERRINJ_ADDR_BIT 2 +#define L2C_ERRINJ_EN_BIT 0 + +/* + * L2CACHE ACCESS CONTROL register fields + */ +#define L2C_ACCCTRL_SPLITQ (0x1 << L2C_ACCCTRL_SPLITQ_BIT) +#define L2C_ACCCTRL_NHM (0x1 << L2C_ACCCTRL_NHM_BIT) +#define L2C_ACCCTRL_BERR (0x1 << L2C_ACCCTRL_BERR_BIT) +#define L2C_ACCCTRL_OAPM (0x1 << L2C_ACCCTRL_OAPM_BIT) +#define L2C_ACCCTRL_FLINE (0x1 << L2C_ACCCTRL_FLINE_BIT) +#define L2C_ACCCTRL_DBPF (0x1 << L2C_ACCCTRL_DBPF_BIT) +#define L2C_ACCCTRL_128WF (0x1 << L2C_ACCCTRL_128WF_BIT) +#define L2C_ACCCTRL_DBPWS (0x1 << L2C_ACCCTRL_DBPWS_BIT) +#define L2C_ACCCTRL_SPLIT (0x1 << L2C_ACCCTRL_SPLIT_BIT) + +#define L2C_ACCCTRL_SPLITQ_BIT 10 +#define L2C_ACCCTRL_NHM_BIT 9 +#define L2C_ACCCTRL_BERR_BIT 8 +#define L2C_ACCCTRL_OAPM_BIT 7 +#define L2C_ACCCTRL_FLINE_BIT 6 +#define L2C_ACCCTRL_DBPF_BIT 5 +#define L2C_ACCCTRL_128WF_BIT 4 +#define L2C_ACCCTRL_DBPWS_BIT 2 +#define L2C_ACCCTRL_SPLIT_BIT 1 + +#ifdef TEST_L2CACHE +/* + * L2CACHE TAG fields + */ +#define L2C_TAG_TAG (0xfffffc << L2C_TAG_TAG_BIT) +#define L2C_TAG_VALID (0x3 << L2C_TAG_VALID_BIT) +#define L2C_TAG_DIRTY (0x3 << L2C_TAG_DIRTY_BIT) +#define L2C_TAG_LRU (0x3 << L2C_TAG_LRU_BIT) + +#define L2C_TAG_TAG_BIT 10 +#define L2C_TAG_VALID_BIT 8 +#define L2C_TAG_DIRTY_BIT 6 +#define L2C_TAG_LRU_BIT 0 + +#endif /* TEST_L2CACHE */ + +#define DEVNAME_LEN 9 +/* + * L2CACHE Driver private data struture + */ +struct l2cache_priv { + struct drvmgr_dev *dev; + char devname[DEVNAME_LEN]; + + /* L2CACHE control registers */ + struct l2c_regs *regs; + + /* L2CACHE status */ + int ways; + int waysize; + int linesize; + int index; + int mtrr; + int ft_support; + int split_support; + + /* User defined ISR */ + l2cache_isr_t isr; + void *isr_arg; +}; + +/* + * L2CACHE internal prototypes + */ +/* -Register access functions */ +STATIC INLINE int l2cache_reg_ctrl_enable(void); +STATIC INLINE int l2cache_reg_ctrl_disable(void); +STATIC INLINE int l2cache_reg_ctrl_locked_set(int locked); +STATIC INLINE int l2cache_reg_ctrl_edac_set(int edac); +STATIC INLINE int l2cache_reg_ctrl_repl(int policy); +STATIC INLINE int l2cache_reg_ctrl_iway(int way); +STATIC INLINE int l2cache_reg_ctrl_writep(int policy); +STATIC INLINE unsigned int l2cache_reg_ctrl(void); +STATIC INLINE unsigned int l2cache_reg_status(void); +STATIC INLINE int l2cache_reg_mtrr_set(int index, unsigned int addr, + unsigned int mask, int options); +UNUSED STATIC INLINE unsigned int l2cache_reg_mtrr_get(int index); +STATIC INLINE int l2cache_reg_flushmem(unsigned int addr, int options); +STATIC INLINE int l2cache_reg_flushline(int way, int index, int options); +STATIC INLINE int l2cache_reg_flushway(unsigned int tag, int way, int options); +STATIC INLINE unsigned int l2cache_reg_error(void); +STATIC INLINE int l2cache_reg_error_reset(void); +STATIC INLINE int l2cache_reg_error_irqmask(int mask); +STATIC INLINE unsigned int l2cache_reg_error_addr(void); +STATIC INLINE unsigned int l2cache_reg_scrub(void); +STATIC INLINE int l2cache_reg_scrub_enable(int delay); +STATIC INLINE int l2cache_reg_scrub_disable(void); +STATIC INLINE unsigned int l2cache_reg_scrub_delay(void); +STATIC INLINE int l2cache_reg_scrub_line(int way, int index); +STATIC INLINE unsigned int l2cache_reg_accctrl(void); +STATIC INLINE int l2cache_reg_accctrl_split_disable(void); +STATIC INLINE int l2cache_reg_accctrl_split_enable(void); +#ifdef TEST_L2CACHE +STATIC INLINE int l2cache_reg_error_dcb(unsigned int cb); +STATIC INLINE int l2cache_reg_error_inject(unsigned int addr); +STATIC INLINE unsigned int l2cache_reg_diagtag(int way, int index); +STATIC INLINE unsigned int l2cache_reg_diagdata(int way, int index, int word); +STATIC unsigned int log2int(unsigned int v); +#endif /* TEST_L2CACHE */ + +/* -Control functions */ +STATIC int l2cache_ctrl_status(void); +STATIC void l2cache_flushwait(void); + +/* -Init function */ +STATIC int l2cache_init(struct l2cache_priv *priv); + +/* -Init function called by drvmgr */ +int l2cache_init1(struct drvmgr_dev *dev); + +/* -IRQ handler */ +void l2cache_isr(void *arg); + +/* + * L2CACHE static members + */ +static struct l2cache_priv *l2cachepriv = NULL; +#ifdef DEBUG +static char * repl_names[4] = {"LRU","Random","Master-Idx-1","Master-IDx-2"}; +#endif + +/* L2CACHE DRIVER */ + +struct drvmgr_drv_ops l2cache_ops = +{ + .init = {l2cache_init1, NULL, NULL, NULL}, + .remove = NULL, + .info = NULL +}; + +struct amba_dev_id l2cache_ids[] = +{ + {VENDOR_GAISLER, GAISLER_L2CACHE}, + {0, 0} /* Mark end of table */ +}; + +struct amba_drv_info l2cache_info = +{ + { + DRVMGR_OBJ_DRV, /* Driver */ + NULL, /* Next driver */ + NULL, /* Device list */ + DRIVER_AMBAPP_GAISLER_L2CACHE_ID,/* Driver ID */ + "L2CACHE_DRV", /* Driver Name */ + DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ + &l2cache_ops, + NULL, /* Funcs */ + 0, /* No devices yet */ + sizeof(struct l2cache_priv), /* Make drvmgr alloc private */ + }, + &l2cache_ids[0] +}; + +void l2cache_register_drv(void) +{ + DBG("Registering L2CACHE driver\n"); + drvmgr_drv_register(&l2cache_info.general); +} + +/* Initializes the L2CACHE core and driver + * + * Return values + * 0 Successful initalization + */ +STATIC int l2cache_init(struct l2cache_priv *priv) +{ + struct ambapp_ahb_info *ahb; + struct amba_dev_info *ainfo = priv->dev->businfo; + + /* Find L2CACHE core from Plug&Play information */ + ahb = ainfo->info.ahb_slv; + + /* Found L2CACHE core, init private structure */ + priv->regs = (struct l2c_regs *)ahb->start[1]; + + /* Initialize L2CACHE status */ + unsigned int status = l2cache_reg_status(); + priv->ways = (status & L2C_STAT_WAY) + 1; + priv->waysize = + ((status & L2C_STAT_WAYSIZE) >> L2C_STAT_WAYSIZE_BIT) * 1024; + priv->linesize = ((status & L2C_STAT_LS)? 64 : 32); + priv->index = ((priv->waysize)/(priv->linesize)); + priv->mtrr = (status & L2C_STAT_MTRR) >> L2C_STAT_MTRR_BIT; + priv->ft_support = (status & L2C_STAT_MP) >> L2C_STAT_MP_BIT; + + /* Probe split support. */ + int split_old = 0; + int split_new = 0; + split_old = (l2cache_reg_accctrl() & L2C_ACCCTRL_SPLIT); + if (split_old){ + l2cache_reg_accctrl_split_disable(); + }else{ + l2cache_reg_accctrl_split_enable(); + } + split_new = (l2cache_reg_accctrl() & L2C_ACCCTRL_SPLIT); + if (split_old){ + l2cache_reg_accctrl_split_enable(); + }else{ + l2cache_reg_accctrl_split_disable(); + } + priv->split_support = + ((split_new ^ split_old) >> L2C_ACCCTRL_SPLIT_BIT) & 1; + + DBG("L2CACHE driver initialized\n"); + + return 0; +} + +/* Called when a core is found with the AMBA device and vendor ID + * given in l2cache_ids[]. IRQ, Console does not work here + */ +int l2cache_init1(struct drvmgr_dev *dev) +{ + int status; + struct l2cache_priv *priv; + + DBG("L2CACHE[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); + + if (l2cachepriv) { + DBG("Driver only supports one L2CACHE core\n"); + return DRVMGR_FAIL; + } + + priv = dev->priv; + if (!priv) + return DRVMGR_NOMEM; + + priv->dev = dev; + strncpy(&priv->devname[0], "l2cache0", DEVNAME_LEN); + l2cachepriv = priv; + + /* Initialize L2CACHE Hardware */ + status = l2cache_init(priv); + if (status) { + printf("Failed to initialize l2cache driver %d\n", status); + return -1; + } + + return DRVMGR_OK; +} + +STATIC INLINE int l2cache_reg_ctrl_enable(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->control); + REG_WRITE(&priv->regs->control, (ctrl | L2C_CTRL_EN)); + return 0; +} + +STATIC INLINE int l2cache_reg_ctrl_disable(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->control); + REG_WRITE(&priv->regs->control, (ctrl & ~(L2C_CTRL_EN))); + return 0; +} + +STATIC INLINE int l2cache_reg_ctrl_repl(int policy) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->control); + REG_WRITE(&priv->regs->control, + ((ctrl & ~(L2C_CTRL_REPL)) | + ((policy << L2C_CTRL_REPL_BIT) & L2C_CTRL_REPL)) + ); + return 0; +} + +STATIC INLINE int l2cache_reg_ctrl_iway(int way) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->control); + REG_WRITE(&priv->regs->control, + ((ctrl & ~(L2C_CTRL_IWAY)) | + ((way << L2C_CTRL_IWAY_BIT) & L2C_CTRL_IWAY)) + ); + return 0; +} + +STATIC INLINE int l2cache_reg_ctrl_writep(int policy) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->control); + REG_WRITE(&priv->regs->control, + ((ctrl & ~(L2C_CTRL_WP)) | ((policy << L2C_CTRL_WP_BIT) & L2C_CTRL_WP)) + ); + return 0; +} + +STATIC INLINE int l2cache_reg_ctrl_locked_set(int locked) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->control); + ctrl = (ctrl & ~(L2C_CTRL_LOCK)); + REG_WRITE(&priv->regs->control, + ctrl | + ((locked << L2C_CTRL_LOCK_BIT) & L2C_CTRL_LOCK)); + return 0; +} + +STATIC INLINE int l2cache_reg_ctrl_edac_set(int edac) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->control); + REG_WRITE(&priv->regs->control, + (ctrl & ~(L2C_CTRL_EDAC)) | + (edac? L2C_CTRL_EDAC:0)); + return 0; +} + +STATIC INLINE unsigned int l2cache_reg_ctrl(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + return REG_READ(&priv->regs->control); +} + +STATIC INLINE unsigned int l2cache_reg_status(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + return REG_READ(&priv->regs->status); +} + +STATIC INLINE int l2cache_reg_mtrr_set(int index, unsigned int addr, + unsigned int mask, int options) +{ + struct l2cache_priv *priv = l2cachepriv; + + /* Set mtrr */ + addr = addr & L2C_MTRR_ADDR; + mask = (mask >> 16) & L2C_MTRR_MASK; + options = ((options & ~(L2C_MTRR_ADDR)) & ~(L2C_MTRR_MASK)); + unsigned int mtrr = 0 | addr | mask | options; + REG_WRITE(&priv->regs->mtrr[index], mtrr); + return 0; +} + +UNUSED STATIC INLINE unsigned int l2cache_reg_mtrr_get(int index) +{ + struct l2cache_priv *priv = l2cachepriv; + + return REG_READ(&priv->regs->mtrr[index]); +} + +STATIC INLINE int l2cache_reg_flushmem(unsigned int addr, int options) +{ + struct l2cache_priv *priv = l2cachepriv; + + options = (options & ~(L2C_FLUSH_ADDR)); + REG_WRITE(&priv->regs->flush_mem_addr, (addr & L2C_FLUSH_ADDR) | options); + return 0; +} + +STATIC INLINE int l2cache_reg_flushline(int way, int index, int options) +{ + struct l2cache_priv *priv = l2cachepriv; + + options = 0 | (options & (L2C_FLUSHSI_FMODE)); + REG_WRITE(&priv->regs->flush_set_index, + ((index << L2C_FLUSHSI_INDEX_BIT) & L2C_FLUSHSI_INDEX) | + ((way << L2C_FLUSHSI_WAY_BIT) & L2C_FLUSHSI_WAY) | + options + ); + return 0; +} + +STATIC INLINE int l2cache_reg_flushway(unsigned int tag, int way, int options) +{ + struct l2cache_priv *priv = l2cachepriv; + + options = (options & ~(L2C_FLUSHSI_TAG | L2C_FLUSHSI_WAY)) + | L2C_FLUSHSI_WF; + REG_WRITE(&priv->regs->flush_set_index, + (tag & L2C_FLUSHSI_TAG) | + ( (way << L2C_FLUSHSI_WAY_BIT) & L2C_FLUSHSI_WAY) | + options); + return 0; +} + +STATIC INLINE unsigned int l2cache_reg_error(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + return REG_READ(&priv->regs->error_status_control); +} + +STATIC INLINE int l2cache_reg_error_reset(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->error_status_control); + REG_WRITE(&priv->regs->error_status_control, ctrl | L2C_ERROR_RST); + return 0; +} + +STATIC INLINE int l2cache_reg_error_irqmask(int mask) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->error_status_control); + REG_WRITE(&priv->regs->error_status_control, + (ctrl & ~(L2C_ERROR_IRQM)) | (mask & L2C_ERROR_IRQM)); + return 0; +} + +STATIC INLINE unsigned int l2cache_reg_error_addr(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + return REG_READ(&priv->regs->error_addr); +} + +STATIC INLINE unsigned int l2cache_reg_scrub(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + return REG_READ(&priv->regs->scrub_control_status); +} + +STATIC INLINE int l2cache_reg_scrub_enable(int delay) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->scrub_control_status); + REG_WRITE(&priv->regs->scrub_delay, + (delay << L2C_SCRUB_DEL_BIT) & L2C_SCRUB_DEL); + REG_WRITE(&priv->regs->scrub_control_status, ctrl | L2C_SCRUB_EN); + return 0; +} + +STATIC INLINE int l2cache_reg_scrub_disable(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + unsigned int ctrl = REG_READ(&priv->regs->scrub_control_status); + REG_WRITE(&priv->regs->scrub_control_status, ctrl & ~(L2C_SCRUB_EN)); + return 0; +} + +STATIC INLINE int l2cache_reg_scrub_line(int way, int index) +{ + struct l2cache_priv *priv = l2cachepriv; + + REG_WRITE(&priv->regs->scrub_control_status, + ((index << L2C_SCRUB_INDEX_BIT) & L2C_SCRUB_INDEX) | + ((way << L2C_SCRUB_WAY_BIT) & L2C_SCRUB_WAY) | + L2C_SCRUB_PEN); + return 0; +} + +STATIC INLINE unsigned int l2cache_reg_scrub_delay(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + return REG_READ(&priv->regs->scrub_delay); +} + +STATIC INLINE unsigned int l2cache_reg_accctrl(void){ + struct l2cache_priv *priv = l2cachepriv; + + return REG_READ(&priv->regs->access_control); +} + +STATIC INLINE int l2cache_reg_accctrl_split_disable(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + /* Disable split */ + unsigned int ctrl = REG_READ(&priv->regs->access_control); + REG_WRITE(&priv->regs->access_control, (ctrl & ~(L2C_ACCCTRL_SPLIT))); + return 0; +} + +STATIC INLINE int l2cache_reg_accctrl_split_enable(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + /* Enable split */ + unsigned int ctrl = REG_READ(&priv->regs->access_control); + REG_WRITE(&priv->regs->access_control, (ctrl | (L2C_ACCCTRL_SPLIT))); + return 0; +} + +STATIC INLINE int l2cache_ctrl_status(void) +{ + return ((l2cache_reg_ctrl() >> L2C_CTRL_EN_BIT) & 0x1); +} + +STATIC void l2cache_flushwait(void) +{ + /* Read any L2cache register to wait until flush is done */ + /* The L2 will block any access until the flush is done */ + /* Force read operation */ + //asm volatile ("" : : "r" (l2cache_reg_status())); + (void) l2cache_reg_status(); + return; +} + +#ifdef TEST_L2CACHE +STATIC INLINE int l2cache_reg_error_dcb(unsigned int cb) +{ + struct l2cache_priv *priv = l2cachepriv; + + REG_WRITE(&priv->regs->data_check_bit, (cb & L2C_DCB_CB)); + return 0; +} + +STATIC INLINE int l2cache_reg_error_inject(unsigned int addr) +{ + struct l2cache_priv *priv = l2cachepriv; + + REG_WRITE(&priv->regs->error_injection, + (addr & L2C_ERRINJ_ADDR) | L2C_ERRINJ_EN); + return 0; +} + +STATIC INLINE unsigned int l2cache_reg_diagtag(int way, int index) +{ + struct l2cache_priv *priv = l2cachepriv; + + int offset = (index*8 + way); + return REG_READ(&priv->regs->diag_iface_tag[offset]); +} + +STATIC INLINE unsigned int l2cache_reg_diagdata(int way, int index, int word) +{ + struct l2cache_priv *priv = l2cachepriv; + + int offset = (index*(priv->linesize/4) + way*0x20000 + word); + return REG_READ(&priv->regs->diag_iface_data[offset]); +} + +STATIC unsigned int log2int(unsigned int v) +{ + unsigned r = 0; + while (v >>= 1) { + r++; + } + return r; +} + +/* Return the index for a given addr */ +int l2cache_get_index( uint32_t addr) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + return (addr % priv->waysize)/(priv->linesize); +} + +/* Return the tag for a given addr */ +uint32_t l2cache_get_tag( uint32_t addr) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + uint32_t tmp; + int i = log2int(priv->waysize); + tmp = (addr >> i); + tmp = (tmp << i); + return tmp; +} + +int l2cache_lookup(uint32_t addr, int * way) +{ + struct l2cache_priv * priv = l2cachepriv; + int i; + struct l2cache_tag gottag; + int ret; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + uint32_t exptag = l2cache_get_tag(addr); + int index = l2cache_get_index(addr); + + /* Check all tags in the set */ + for(i=0; i< priv->ways; i++){ + ret = l2cache_diag_tag(i, index, &gottag); + if (ret != L2CACHE_ERR_OK){ + return ret; + } + /*DBG("L2CACHE gottag: way=%d, valid=%d, tag=0x%08x.\n", + * i, gottag.valid, gottag.tag);*/ + /* Check if valid */ + if (gottag.valid){ + /* Check if they are the same */ + if (gottag.tag == exptag){ + /* HIT! */ + if (way){ + *way = i; + } + DBG("L2CACHE lookup: index=%d, tag=0x%08x HIT way=%d.\n", + index, (unsigned int) exptag, i); + return L2CACHE_HIT; + } + } + } + DBG("L2CACHE lookup: index=%d, tag=0x%08x MISS.\n", + index, (unsigned int) exptag); + /* MISS! */ + return L2CACHE_MISS; +} + +/* Diagnostic Accesses */ +#define l2cache_tag_valid(val) ((val & L2C_TAG_VALID) >> L2C_TAG_VALID_BIT) +#define l2cache_tag_dirty(val) ((val & L2C_TAG_DIRTY) >> L2C_TAG_DIRTY_BIT) +#define l2cache_tag_lru(val) ((val & L2C_TAG_LRU) >> L2C_TAG_LRU_BIT) +int l2cache_diag_tag( int way, int index, struct l2cache_tag * tag) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (way >= priv->ways){ + DBG("L2CACHE has only %d ways.\n", priv->ways); + return L2CACHE_ERR_EINVAL; + } + + if (index >= priv->index){ + DBG("L2CACHE has only %d lines.\n", priv->index); + return L2CACHE_ERR_EINVAL; + } + + unsigned int val = l2cache_reg_diagtag(way,index); + + if (tag){ + tag->tag = l2cache_get_tag(val); + tag->valid = l2cache_tag_valid(val); + tag->dirty = l2cache_tag_dirty(val); + tag->lru = l2cache_tag_lru(val); + }else{ + return L2CACHE_ERR_EINVAL; + } + return L2CACHE_ERR_OK; +} + +int l2cache_diag_line( int way, int index, struct l2cache_dataline * dataline) +{ + struct l2cache_priv * priv = l2cachepriv; + int i; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (way >= priv->ways){ + DBG("L2CACHE has only %d ways.\n", priv->ways); + return L2CACHE_ERR_EINVAL; + } + + if (index >= priv->index){ + DBG("L2CACHE has only %d lines.\n", priv->index); + return L2CACHE_ERR_EINVAL; + } + + if (dataline){ + dataline->words = (priv->linesize/4); + for (i=0; i< (priv->linesize/4); i++){ + dataline->data[i] = l2cache_reg_diagdata(way,index,i); + } + }else{ + return L2CACHE_ERR_EINVAL; + } + return L2CACHE_ERR_OK; +} + +/* Inject an error on a given addr */ +int l2cache_error_inject_address( uint32_t addr, uint32_t mask) +{ + struct l2cache_priv * priv = l2cachepriv; + int word; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (!priv->ft_support){ + DBG("L2CACHE does not have EDAC support.\n"); + return L2CACHE_ERR_ERROR; + } + + if (addr & 0x3){ + DBG("Address not aligned to 32-bit.\n"); + return L2CACHE_ERR_EINVAL; + } + + /* Get word index */ + word = (addr % priv->linesize)/4; + + /* Shift mask to proper word */ + mask = (mask << (7*(priv->ways - word - 1))); + + /* Write DCB mask to XOR */ + l2cache_reg_error_dcb(mask); + + /* Inject error */ + l2cache_reg_error_inject(addr); + + DBG("L2CACHE error injected in 0x%08x (0x%08x).\n", + (unsigned int) addr, (unsigned int) mask); + + return L2CACHE_ERR_OK; +} + +#endif /* TEST_L2CACHE */ + +/* L2CACHE Interrupt handler, called when there may be a L2CACHE interrupt. + */ +void l2cache_isr(void *arg) +{ + struct l2cache_priv *priv = arg; + unsigned int sts = l2cache_reg_error(); + unsigned int addr = l2cache_reg_error_addr(); + + /* Make sure that the interrupt is pending and unmasked, + * otherwise it migth have been other core + * sharing the same interrupt line */ + if ( ((sts & L2C_ERROR_IRQP) >> L2C_ERROR_IRQP_BIT) & + ((sts & L2C_ERROR_IRQM) >> L2C_ERROR_IRQM_BIT)){ + /* Reset error status */ + l2cache_reg_error_reset(); + /* Execute user IRQ (ther will always be one ISR */ + /* Give cacheline address */ + (priv->isr)(priv->isr_arg, (addr & ~(0x1f)), sts); + } +} + +/* Enable L2CACHE: + */ +int l2cache_enable(int flush) +{ + int ret; + + /* Flush checks flus parameter and INIT state */ + ret = l2cache_flush(flush); + if (ret < 0){ + return ret; + } + + l2cache_reg_ctrl_enable(); + + DBG("L2CACHE enabled\n"); + return L2CACHE_ERR_OK; +} + +/* Disable L2CACHE: + */ +int l2cache_disable(int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if ((flush < 0) || + (flush > + (L2CACHE_OPTIONS_FLUSH_INVALIDATE | L2CACHE_OPTIONS_FLUSH_WAIT)) + ){ + DBG("L2CACHE wrong flush option.\n"); + return L2CACHE_ERR_EINVAL; + } + + /* Flush & invalidate all cache. Also disable L2C */ + switch(flush & 0x3){ + case L2CACHE_OPTIONS_FLUSH_NONE: + l2cache_reg_ctrl_disable(); + break; + case L2CACHE_OPTIONS_FLUSH_INV_WBACK: + l2cache_reg_flushmem(0, L2C_FLUSH_FMODE_INV_WB_ALL | L2C_FLUSH_DI); + break; + case L2CACHE_OPTIONS_FLUSH_WRITEBACK: + l2cache_reg_flushmem(0, L2C_FLUSH_FMODE_WB_ALL | L2C_FLUSH_DI); + break; + case L2CACHE_OPTIONS_FLUSH_INVALIDATE: + default: + l2cache_reg_flushmem(0, L2C_FLUSH_FMODE_INV_ALL | L2C_FLUSH_DI); + break; + } + + if (flush & L2CACHE_OPTIONS_FLUSH_WAIT){ + l2cache_flushwait(); + } + + DBG("L2CACHE disabled\n"); + return L2CACHE_ERR_OK; +} + +/* Status L2CACHE: + */ +int l2cache_status(void) +{ + struct l2cache_priv * priv = l2cachepriv; + int status; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + unsigned int ctrl = l2cache_reg_ctrl(); + int locked = (ctrl & L2C_CTRL_LOCK) >> L2C_CTRL_LOCK_BIT; + int enabled = ((ctrl & L2C_CTRL_EN) >> L2C_CTRL_EN_BIT) & 0x1; + int edac = (ctrl & L2C_CTRL_EDAC) >> L2C_CTRL_EDAC_BIT; + int repl = (ctrl & L2C_CTRL_REPL) >> L2C_CTRL_REPL_BIT; + int writep = (ctrl & L2C_CTRL_WP) >> L2C_CTRL_WP_BIT; + + unsigned int acc = l2cache_reg_accctrl(); + int split = (acc & L2C_ACCCTRL_SPLIT) >> L2C_ACCCTRL_SPLIT_BIT; + + unsigned int err = l2cache_reg_error(); + int interrupts = (err & L2C_ERROR_IRQM) >> L2C_ERROR_IRQM_BIT; + + unsigned int scr = l2cache_reg_scrub(); + int scrub = (scr & L2C_SCRUB_EN) >> L2C_SCRUB_EN_BIT; + + unsigned int dly = l2cache_reg_scrub_delay(); + int delay = (dly & L2C_SCRUB_DEL) >> L2C_SCRUB_DEL_BIT; + + status = 0| + (enabled? L2CACHE_STATUS_ENABLED: 0) | + (split? L2CACHE_STATUS_SPLIT_ENABLED: 0) | + (edac? L2CACHE_STATUS_EDAC_ENABLED: 0) | + ((repl & 0x3) << L2CACHE_STATUS_REPL_BIT) | + (writep? L2CACHE_STATUS_WRITETHROUGH: 0) | + ((locked & 0xf) << L2CACHE_STATUS_LOCK_BIT) | + ((interrupts & 0xf) << L2CACHE_STATUS_INT_BIT) | + (scrub? L2CACHE_STATUS_SCRUB_ENABLED: 0) | + ((delay & 0xffff) << L2CACHE_STATUS_SCRUB_DELAY_BIT); + + return status; +} + +/* Flush L2CACHE: + */ +int l2cache_flush(int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if ((flush < 0) || + (flush > + (L2CACHE_OPTIONS_FLUSH_INVALIDATE | L2CACHE_OPTIONS_FLUSH_WAIT)) + ){ + DBG("L2CACHE wrong flush option.\n"); + return L2CACHE_ERR_EINVAL; + } + + switch(flush & 0x3){ + case L2CACHE_OPTIONS_FLUSH_NONE: + break; + case L2CACHE_OPTIONS_FLUSH_INV_WBACK: + l2cache_reg_flushmem(0, L2C_FLUSH_FMODE_INV_WB_ALL); + break; + case L2CACHE_OPTIONS_FLUSH_WRITEBACK: + l2cache_reg_flushmem(0, L2C_FLUSH_FMODE_WB_ALL); + break; + case L2CACHE_OPTIONS_FLUSH_INVALIDATE: + default: + l2cache_reg_flushmem(0, L2C_FLUSH_FMODE_INV_ALL); + break; + } + + if (flush & L2CACHE_OPTIONS_FLUSH_WAIT){ + l2cache_flushwait(); + } + + DBG("L2CACHE flushed\n"); + return L2CACHE_ERR_OK; +} + +/* Flush L2CACHE address: + */ +int l2cache_flush_address(uint32_t addr, int size, int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + uint32_t endaddr; + int options; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if ((flush < 0) || + (flush > + (L2CACHE_OPTIONS_FLUSH_INVALIDATE | L2CACHE_OPTIONS_FLUSH_WAIT)) + ){ + DBG("L2CACHE wrong flush option.\n"); + return L2CACHE_ERR_EINVAL; + } + + if (size <= 0){ + DBG("L2CACHE wrong size.\n"); + return L2CACHE_ERR_EINVAL; + } + + switch(flush & 0x3){ + case L2CACHE_OPTIONS_FLUSH_NONE: + break; + case L2CACHE_OPTIONS_FLUSH_INV_WBACK: + options=L2C_FLUSH_FMODE_INV_WB_ONE; + break; + case L2CACHE_OPTIONS_FLUSH_WRITEBACK: + options=L2C_FLUSH_FMODE_WB_ONE; + break; + case L2CACHE_OPTIONS_FLUSH_INVALIDATE: + default: + options=L2C_FLUSH_FMODE_INV_ONE; + break; + } + + if ( (flush & 0x3) == L2CACHE_OPTIONS_FLUSH_NONE){ + return L2CACHE_ERR_OK; + } + + /* Get the end address */ + endaddr = (addr + size); + + /* Start on first cacheline address */ + addr = addr - (addr % priv->linesize); + while( addr < endaddr){ + /* Flush address */ + l2cache_reg_flushmem(addr, options); + /* Update next line */ + addr += priv->linesize; + } + + if (flush & L2CACHE_OPTIONS_FLUSH_WAIT){ + l2cache_flushwait(); + } + + DBG("L2CACHE address range flushed\n"); + return L2CACHE_ERR_OK; +} + +/* Flush L2CACHE line: + */ +int l2cache_flush_line(int way, int index, int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if ((flush < 0) || + (flush > + (L2CACHE_OPTIONS_FLUSH_INVALIDATE | L2CACHE_OPTIONS_FLUSH_WAIT)) + ){ + DBG("L2CACHE wrong flush option.\n"); + return L2CACHE_ERR_EINVAL; + } + + if ((index < 0) || (index >= priv->index)){ + DBG("L2CACHE only has %d lines.\n", priv->index); + return L2CACHE_ERR_EINVAL; + } + + if ((way < 0 ) || (way >= priv->ways)){ + DBG("L2CACHE only has %d ways.\n", priv->ways); + return L2CACHE_ERR_EINVAL; + } + + switch(flush & 0x3){ + case L2CACHE_OPTIONS_FLUSH_NONE: + break; + case L2CACHE_OPTIONS_FLUSH_INV_WBACK: + l2cache_reg_flushline(way, index, + L2C_FLUSHSI_FMODE_SET_INV_WB_ONE); + break; + case L2CACHE_OPTIONS_FLUSH_WRITEBACK: + l2cache_reg_flushline(way, index, L2C_FLUSHSI_FMODE_SET_WB_ONE); + break; + case L2CACHE_OPTIONS_FLUSH_INVALIDATE: + default: + l2cache_reg_flushline(way, index, L2C_FLUSHSI_FMODE_SET_INV_ONE); + break; + } + + if (flush & L2CACHE_OPTIONS_FLUSH_WAIT){ + l2cache_flushwait(); + } + + DBG("L2CACHE line [%d,%d] flushed\n", way, index); + return L2CACHE_ERR_OK; +} + +/* Flush L2CACHE way: + */ +int l2cache_flush_way(int way, int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if ((flush < 0) || + (flush > + (L2CACHE_OPTIONS_FLUSH_INVALIDATE | L2CACHE_OPTIONS_FLUSH_WAIT)) + ){ + DBG("L2CACHE wrong flush option.\n"); + return L2CACHE_ERR_EINVAL; + } + + if ((way < 0 ) || (way >= priv->ways)){ + DBG("L2CACHE only has %d ways.\n", priv->ways); + return L2CACHE_ERR_EINVAL; + } + + switch(flush & 0x3){ + case L2CACHE_OPTIONS_FLUSH_NONE: + break; + case L2CACHE_OPTIONS_FLUSH_INVALIDATE: + l2cache_reg_flushway(0, way, L2C_FLUSHSI_FMODE_WAY_UPDATE); + break; + case L2CACHE_OPTIONS_FLUSH_WRITEBACK: + l2cache_reg_flushway(0, way, L2C_FLUSHSI_FMODE_WAY_WB); + break; + case L2CACHE_OPTIONS_FLUSH_INV_WBACK: + default: + l2cache_reg_flushway(0, way, L2C_FLUSHSI_FMODE_WAY_UPDATE_WB_ALL); + break; + } + + if (flush & L2CACHE_OPTIONS_FLUSH_WAIT){ + l2cache_flushwait(); + } + + DBG("L2CACHE way [%d] flushed\n",way); + return L2CACHE_ERR_OK; +} + +/* Fill L2CACHE way: + */ +int l2cache_fill_way(int way, uint32_t tag, int options, int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + int flags; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if ((way < 0 ) || (way >= priv->ways)){ + DBG("L2CACHE only has %d ways.\n", priv->ways); + return L2CACHE_ERR_EINVAL; + } + + /* Check input parameters */ + if (tag & 0x000003ff){ + DBG("Only using bits 31:10 of Addr/Mask\n"); + return L2CACHE_ERR_EINVAL; + } + + /* Perform the Way-flush */ + flags = ((options & L2CACHE_OPTIONS_FETCH)? L2C_FLUSHSI_FL:0) | + ((options & L2CACHE_OPTIONS_VALID)? L2C_FLUSHSI_VB:0) | + ((options & L2CACHE_OPTIONS_DIRTY)? L2C_FLUSHSI_DB:0); + + /*DBG("L2CACHE lock way: Locked=%d, way=%d, option=0x%04x\n", + * locked, way, flags);*/ + + switch(flush & 0x3){ + case L2CACHE_OPTIONS_FLUSH_NONE: + break; + case L2CACHE_OPTIONS_FLUSH_INVALIDATE: + l2cache_reg_flushway(tag, way, + flags | L2C_FLUSHSI_FMODE_WAY_UPDATE); + break; + case L2CACHE_OPTIONS_FLUSH_WRITEBACK: + l2cache_reg_flushway(tag, way, flags | L2C_FLUSHSI_FMODE_WAY_WB); + break; + case L2CACHE_OPTIONS_FLUSH_INV_WBACK: + default: + l2cache_reg_flushway(tag, way, + flags | L2C_FLUSHSI_FMODE_WAY_UPDATE_WB_ALL); + break; + } + + if (flush & L2CACHE_OPTIONS_FLUSH_WAIT){ + l2cache_flushwait(); + } + + DBG("Way[%d] filled with Tag 0x%08x\n", way, (unsigned int) tag); + + return L2CACHE_ERR_OK; +} + +/* Lock L2CACHE way: + */ +int l2cache_lock_way(uint32_t tag, int options, int flush, int enable) +{ + struct l2cache_priv * priv = l2cachepriv; + int enabled; + int way; + int locked; + int flags; + int ret; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + locked = L2CACHE_LOCKED_WAYS(l2cache_status()); + if (locked >= priv->ways){ + DBG("L2CACHE only has %d ways.\n", priv->ways); + return L2CACHE_ERR_TOOMANY; + } + + /* Check input parameters */ + if (tag & 0x000003ff){ + DBG("Only using bits 31:10 of Addr/Mask\n"); + return L2CACHE_ERR_EINVAL; + } + + /* Check L2C status */ + enabled = l2cache_ctrl_status(); + + /* Disable L2C */ + ret = l2cache_disable(flush); + if (ret < 0){ + return ret; + } + + /* Increase number of locked ways */ + locked++; + way = priv->ways - locked; + l2cache_reg_ctrl_locked_set(locked); + + /* Perform the Way-flush */ + flags = ((options & L2CACHE_OPTIONS_FETCH)? L2C_FLUSHSI_FL:0) | + ((options & L2CACHE_OPTIONS_VALID)? L2C_FLUSHSI_VB:0) | + ((options & L2CACHE_OPTIONS_DIRTY)? L2C_FLUSHSI_DB:0); + + /*DBG("L2CACHE lock way: Locked=%d, way=%d, option=0x%04x\n", + * locked, way, flags);*/ + + switch(flush & 0x3){ + case L2CACHE_OPTIONS_FLUSH_NONE: + break; + case L2CACHE_OPTIONS_FLUSH_INVALIDATE: + l2cache_reg_flushway(tag, way, + flags | L2C_FLUSHSI_FMODE_WAY_UPDATE); + break; + case L2CACHE_OPTIONS_FLUSH_WRITEBACK: + l2cache_reg_flushway(tag, way, flags | L2C_FLUSHSI_FMODE_WAY_WB); + break; + case L2CACHE_OPTIONS_FLUSH_INV_WBACK: + default: + l2cache_reg_flushway(tag, way, + flags | L2C_FLUSHSI_FMODE_WAY_UPDATE_WB_ALL); + break; + } + + /* Reenable L2C if required */ + switch(enable){ + case L2CACHE_OPTIONS_ENABLE: + l2cache_reg_ctrl_enable(); + break; + case L2CACHE_OPTIONS_DISABLE: + break; + case L2CACHE_OPTIONS_NONE: + default: + if (enabled) { + l2cache_reg_ctrl_enable(); + } + break; + } + + if (flush & L2CACHE_OPTIONS_FLUSH_WAIT){ + l2cache_flushwait(); + } + + DBG("Way[%d] locked with Tag 0x%08x\n", way, (unsigned int) tag); + + return L2CACHE_ERR_OK; +} + +/* Unlock L2CACHE waw: + */ +int l2cache_unlock() +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + /* Set number of locked ways to 0*/ + l2cache_reg_ctrl_locked_set(0); + + DBG("L2CACHE ways unlocked\n"); + + return L2CACHE_ERR_OK; +} + +/* Setup L2CACHE: + * Parameters: + * -options: Can be: + */ +int l2cache_mtrr_enable(int index, uint32_t addr, uint32_t mask, int options, + int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + int enabled; + int flags; + int ret; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (index < 0){ + DBG("Wrong index\n"); + return L2CACHE_ERR_EINVAL; + } + + if (index >= priv->mtrr){ + DBG("Not enough MTRR registers\n"); + return L2CACHE_ERR_TOOMANY; + } + + /* Check input parameters */ + if ((addr & 0x0003ffff) || (mask & 0x0003ffff)){ + DBG("Only using bits 31:18 of Addr/Mask\n"); + return L2CACHE_ERR_EINVAL; + } + + /* Check L2C status */ + enabled = l2cache_ctrl_status(); + + /* Disable L2C */ + ret = l2cache_disable(flush); + if (ret < 0){ + return ret; + } + + /* Decode options */ + flags = 0 | + (options & L2CACHE_OPTIONS_MTRR_ACCESS_WRITETHROUGH? + L2C_MTRR_WRITETHROUGH : + L2C_MTRR_UNCACHED) | + (options & L2CACHE_OPTIONS_MTRR_WRITEPROT_ENABLE? + L2C_MTRR_WRITEPROT_ENABLE : + L2C_MTRR_WRITEPROT_DISABLE) | + L2C_MTRR_ACCESSCONTROL_ENABLE; + + /* Configure mtrr */ + l2cache_reg_mtrr_set(index, addr, mask, flags); + + /* Enable cache again (if needed) */ + if (enabled){ + l2cache_reg_ctrl_enable(); + } + + DBG("MTRR[%d] succesfully configured for 0x%08x (mask 0x%08x), " + "access=%s, wprot=%s\n", + index, (unsigned int) addr, (unsigned int) mask, + (options & L2CACHE_OPTIONS_MTRR_ACCESS_WRITETHROUGH? + "WRITETHROUGH":"UNCACHED"), + (options & L2CACHE_OPTIONS_MTRR_WRITEPROT_ENABLE? "ENABLE":"DISABLE") + ); + + return L2CACHE_ERR_OK; +} + +/* Setup L2CACHE: + * Parameters: + * -options: Can be: + */ +int l2cache_mtrr_disable(int index) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (index < 0){ + DBG("Wrong index\n"); + return L2CACHE_ERR_EINVAL; + } + + if (index >= priv->mtrr){ + DBG("Not enough MTRR registers\n"); + return L2CACHE_ERR_TOOMANY; + } + + /* Configure mtrr */ + l2cache_reg_mtrr_set(index, 0, 0, L2C_MTRR_ACCESSCONTROL_DISABLE); + + DBG("MTRR[%d] disabled\n", index); + + return L2CACHE_ERR_OK; +} + +/* Print L2CACHE status + * DEBUG function + */ +int l2cache_print(void) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + #ifdef DEBUG + int status = l2cache_status(); + if (status < 0){ + return status; + } + printf("L2cache: Ways:%d. Waysize:%d, Linesize:%d, Lines:%d\n" + " MTRR:%d, FT:%s, Locked:%d, Split:%s\n" + " REPL:%s, WP:%s, EDAC:%s, Enabled:%s\n" + " Scrub:%s, S-Delay:%d\n", + priv->ways, + priv->waysize, + priv->linesize, + (priv->index * priv->ways), + priv->mtrr, + (priv->ft_support? "Available":"N/A"), + L2CACHE_LOCKED_WAYS(status), + (priv->split_support? (L2CACHE_SPLIT_ENABLED(status)? + "Enabled":"Disabled"):"N/A"), + repl_names[L2CACHE_REPL(status)], + (L2CACHE_WRITETHROUGH(status)? "Write-through":"Write-back"), + (L2CACHE_EDAC_ENABLED(status)? "Enabled":"Disabled"), + (L2CACHE_ENABLED(status)? "Yes":"No"), + (L2CACHE_SCRUB_ENABLED(status)? "Enabled":"Disabled"), + L2CACHE_SCRUB_DELAY(status) + ); + if (l2cache_ctrl_status()){ + printf("L2cache enabled.\n"); + }else{ + printf("L2cache disabled.\n"); + } + #endif + return L2CACHE_ERR_OK; +} + +int l2cache_split_enable(void) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (!priv->split_support){ + DBG("L2CACHE does not have split support.\n"); + return L2CACHE_ERR_ERROR; + } + + l2cache_reg_accctrl_split_enable(); + DBG("L2CACHE split is now enabled\n"); + + return L2CACHE_ERR_OK; +} + +int l2cache_split_disable(void) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (!priv->split_support){ + DBG("L2CACHE does not have split support.\n"); + return L2CACHE_ERR_ERROR; + } + + l2cache_reg_accctrl_split_disable(); + DBG("L2CACHE split is now disabled\n"); + + return L2CACHE_ERR_OK; +} + +int l2cache_edac_enable(int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + int enabled; + int ret; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (!priv->ft_support){ + DBG("L2CACHE does not have EDAC support.\n"); + return L2CACHE_ERR_ERROR; + } + + /* Check that L2C is enabled */ + enabled = l2cache_ctrl_status(); + + /* Disable&Flush L2C */ + ret = l2cache_disable(flush); + if (ret < 0){ + return ret; + } + + /* Clear error register */ + l2cache_reg_error_reset(); + + /* Enable EDAC */ + l2cache_reg_ctrl_edac_set(1); + + /* Enable cache again */ + if (enabled){ + l2cache_reg_ctrl_enable(); + } + + DBG("L2CACHE EDAC is now enabled\n"); + + return L2CACHE_ERR_OK; +} + +int l2cache_edac_disable(int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + int enabled; + int ret; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (!priv->ft_support){ + DBG("L2CACHE does not have EDAC support.\n"); + return L2CACHE_ERR_ERROR; + } + + /* Check that L2C is enabled */ + enabled = l2cache_ctrl_status(); + + /* Disable&Flush L2C */ + ret = l2cache_disable(flush); + if (ret < 0){ + return ret; + } + + /* Disable EDAC */ + l2cache_reg_ctrl_edac_set(0); + + /* Clear error register */ + l2cache_reg_error_reset(); + + /* Enable cache again */ + if (enabled){ + l2cache_reg_ctrl_enable(); + } + + DBG("L2CACHE EDAC is now disabled\n"); + + return L2CACHE_ERR_OK; +} + +int l2cache_scrub_enable(int delay) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (!priv->ft_support){ + DBG("L2CACHE does not have EDAC support.\n"); + return L2CACHE_ERR_ERROR; + } + + /* Enable Scrub */ + l2cache_reg_scrub_enable(delay); + + DBG("L2CACHE Scrub is now enabled\n"); + + return L2CACHE_ERR_OK; +} + +int l2cache_scrub_disable(void) +{ + struct l2cache_priv * priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (!priv->ft_support){ + DBG("L2CACHE does not have EDAC support.\n"); + return L2CACHE_ERR_ERROR; + } + + /* Disable Scrub */ + l2cache_reg_scrub_disable(); + + DBG("L2CACHE Scrub is now disabled\n"); + + return L2CACHE_ERR_OK; +} + +int l2cache_scrub_line(int way, int index) +{ + struct l2cache_priv * priv = l2cachepriv; + unsigned int scrub; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (!priv->ft_support){ + DBG("L2CACHE does not have EDAC support.\n"); + return L2CACHE_ERR_ERROR; + } + + if ((index < 0) || (index >= priv->index)){ + DBG("L2CACHE only has %d lines.\n", priv->index); + return L2CACHE_ERR_EINVAL; + } + + if ((way < 0) || (way >= priv->ways)){ + DBG("L2CACHE only has %d ways.\n", priv->ways); + return L2CACHE_ERR_EINVAL; + } + + /* Check pending bit */ + scrub = l2cache_reg_scrub(); + if ( (scrub & L2C_SCRUB_PEN) || (scrub & L2C_SCRUB_EN) ){ + DBG("L2CACHE already scrubbing.\n"); + return L2CACHE_ERR_ERROR; + } + + /* Scrub line */ + l2cache_reg_scrub_line(way, index); + + DBG("L2CACHE Scrub line [%d,%d]\n",way,index); + + return L2CACHE_ERR_OK; +} + +int l2cache_writethrough(int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + int enabled; + int ret; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + /* Check that L2C is enabled */ + enabled = l2cache_ctrl_status(); + + /* Disable&Flush L2C */ + ret = l2cache_disable(flush); + if (ret < 0){ + return ret; + } + + /* Configure writethrough */ + l2cache_reg_ctrl_writep(1); + + /* Enable cache again */ + if (enabled){ + l2cache_reg_ctrl_enable(); + } + + DBG("L2CACHE now is writethrough\n"); + + return L2CACHE_ERR_OK; +} + +int l2cache_writeback(int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + int enabled; + int ret; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + /* Check that L2C is enabled */ + enabled = l2cache_ctrl_status(); + + /* Disable&Flush L2C */ + ret = l2cache_disable(flush); + if (ret < 0){ + return ret; + } + + /* Configure writeback */ + l2cache_reg_ctrl_writep(0); + + /* Enable cache again */ + if (enabled){ + l2cache_reg_ctrl_enable(); + } + + DBG("L2CACHE now is writeback\n"); + + return L2CACHE_ERR_OK; +} + +int l2cache_replacement(int options, int flush) +{ + struct l2cache_priv * priv = l2cachepriv; + int enabled; + int ret; + int way; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + /* Check that L2C is enabled */ + enabled = l2cache_ctrl_status(); + + /* Disable&Flush L2C */ + ret = l2cache_disable(flush); + if (ret < 0){ + return ret; + } + + if ( (options & 0x3) == L2CACHE_OPTIONS_REPL_MASTERIDX_IDX){ + /* Set iway */ + way = (options >> 2) & 0x3; + l2cache_reg_ctrl_iway(way); + } + + /* Configure writeback */ + l2cache_reg_ctrl_repl(options & 0x3); + + /* Enable cache again */ + if (enabled){ + l2cache_reg_ctrl_enable(); + } + + DBG("L2CACHE replacement set to %d\n", (options & 0x3)); + + return L2CACHE_ERR_OK; + +} + +int l2cache_isr_register(l2cache_isr_t isr, void * arg, int options) +{ + struct l2cache_priv *priv = l2cachepriv; + unsigned int mask; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (isr == NULL){ + DBG("L2CACHE wrong isr.\n"); + return L2CACHE_ERR_EINVAL; + } + + /* Get mask */ + mask = 0 | + ((options & L2CACHE_INTERRUPT_BACKENDERROR)? L2C_ERROR_IRQM_BCKEND:0) | + ((options & L2CACHE_INTERRUPT_WPROTHIT)? L2C_ERROR_IRQM_WPROT:0) | + ((options & L2CACHE_INTERRUPT_CORRERROR)? L2C_ERROR_IRQM_CORR:0) | + ((options & L2CACHE_INTERRUPT_UNCORRERROR)? L2C_ERROR_IRQM_UNCORR:0); + + /* Clear previous interrupts and mask them*/ + l2cache_reg_error_reset(); + l2cache_reg_error_irqmask(0); + + /* First time registering an ISR */ + if (priv->isr == NULL){ + /* Install and Enable L2CACHE interrupt handler */ + drvmgr_interrupt_register(priv->dev, 0, priv->devname, l2cache_isr, + priv); + } + + /* Install user ISR */ + priv->isr=isr; + priv->isr_arg=arg; + + /* Now it is safe to unmask interrupts */ + l2cache_reg_error_irqmask(mask); + + return L2CACHE_ERR_OK; +} + +int l2cache_isr_unregister(void) +{ + struct l2cache_priv *priv = l2cachepriv; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (priv->isr == NULL){ + DBG("L2CACHE wrong isr.\n"); + return L2CACHE_ERR_EINVAL; + } + + /* Clear previous interrupts and mask them*/ + l2cache_reg_error_reset(); + l2cache_reg_error_irqmask(0); + + /* Uninstall and disable L2CACHE interrupt handler */ + drvmgr_interrupt_unregister(priv->dev, 0, l2cache_isr, priv); + + /* Uninstall user ISR */ + priv->isr=NULL; + priv->isr_arg=NULL; + + return L2CACHE_ERR_OK; +} + +int l2cache_interrupt_unmask(int options) +{ + struct l2cache_priv *priv = l2cachepriv; + unsigned int mask, irq; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + if (priv->isr == NULL){ + DBG("L2CACHE wrong isr.\n"); + return L2CACHE_ERR_EINVAL; + } + + /* Unmask interrupts in L2CACHE */ + mask = 0 | + ((options & L2CACHE_INTERRUPT_BACKENDERROR)? L2C_ERROR_IRQM_BCKEND:0) | + ((options & L2CACHE_INTERRUPT_WPROTHIT)? L2C_ERROR_IRQM_WPROT:0) | + ((options & L2CACHE_INTERRUPT_CORRERROR)? L2C_ERROR_IRQM_CORR:0) | + ((options & L2CACHE_INTERRUPT_UNCORRERROR)? L2C_ERROR_IRQM_UNCORR:0); + + /* Clear previous interrupts*/ + l2cache_reg_error_reset(); + + /* Get previous mask */ + irq = ((l2cache_reg_error() & L2C_ERROR_IRQM) >> L2C_ERROR_IRQM_BIT); + + /* Set new mask */ + l2cache_reg_error_irqmask(irq | mask); + + return L2CACHE_ERR_OK; +} + +int l2cache_interrupt_mask(int options) +{ + struct l2cache_priv *priv = l2cachepriv; + unsigned int mask, irq; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + /* Mask interrupts in L2CACHE */ + mask = 0 | + ((options & L2CACHE_INTERRUPT_BACKENDERROR)? L2C_ERROR_IRQM_BCKEND:0) | + ((options & L2CACHE_INTERRUPT_WPROTHIT)? L2C_ERROR_IRQM_WPROT:0) | + ((options & L2CACHE_INTERRUPT_CORRERROR)? L2C_ERROR_IRQM_CORR:0) | + ((options & L2CACHE_INTERRUPT_UNCORRERROR)? L2C_ERROR_IRQM_UNCORR:0); + + /* Clear previous interrupts */ + l2cache_reg_error_reset(); + + /* Get previous mask */ + irq = ((l2cache_reg_error() & L2C_ERROR_IRQM) >> L2C_ERROR_IRQM_BIT); + + /* Set new mask */ + l2cache_reg_error_irqmask(irq & ~(mask)); + + return L2CACHE_ERR_OK; +} + +int l2cache_error_status(uint32_t * addr, uint32_t * status) +{ + struct l2cache_priv *priv = l2cachepriv; + unsigned int sts; + unsigned int erraddr; + + if (priv == NULL){ + DBG("L2CACHE not initialized.\n"); + return L2CACHE_ERR_NOINIT; + } + + /* Get error register */ + sts = priv->regs->error_status_control; + erraddr = priv->regs->error_addr; + + /* Check if an error occurred */ + if (sts & L2C_ERROR_VALID){ + /* Reset error register */ + l2cache_reg_error_reset(); + + /* Update user variables if needed */ + if (addr != NULL){ + *addr = (erraddr & ~(0x1f)); + } + + if(status != NULL){ + *status = sts; + } + + /* Return status */ + if (sts & L2C_ERROR_MULTI){ + return L2CACHE_STATUS_MULTIPLEERRORS; + }else{ + return L2CACHE_STATUS_NEWERROR; + } + }else{ + /* Return status */ + return L2CACHE_STATUS_NOERROR; + } +} diff --git a/cpukit/libdrvmgr/drvmgr_confdefs.h b/cpukit/libdrvmgr/drvmgr_confdefs.h index 7692650..465f66f 100644 --- a/cpukit/libdrvmgr/drvmgr_confdefs.h +++ b/cpukit/libdrvmgr/drvmgr_confdefs.h @@ -47,6 +47,7 @@ extern void grtc_register_drv(void); extern void pcif_register_drv(void); extern void grpci_register_drv(void); extern void mctrl_register_drv(void); +extern void l2cache_register_drv(void); extern void grpci2_register_drv(void); extern void spictrl_register_drv(void); extern void i2cmst_register_drv(void); @@ -135,6 +136,9 @@ drvmgr_drv_reg_func drvmgr_drivers[] = { #ifdef CONFIGURE_DRIVER_AMBAPP_MCTRL mctrl_register_drv, #endif +#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_L2CACHE + l2cache_register_drv, +#endif #ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_SPICTRL spictrl_register_drv, #endif -- 2.7.4 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel