[PATCH 20/31] nds32: L2 cache support

From: Greentime Hu
Date: Wed Nov 08 2017 - 01:21:06 EST


From: Greentime Hu <greentime@xxxxxxxxxxxxx>

Signed-off-by: Vincent Chen <vincentc@xxxxxxxxxxxxx>
Signed-off-by: Greentime Hu <greentime@xxxxxxxxxxxxx>
---
arch/nds32/include/asm/l2_cache.h | 158 +++++++++++++++++++++++++++++++++++++
arch/nds32/kernel/atl2c.c | 77 ++++++++++++++++++
2 files changed, 235 insertions(+)
create mode 100644 arch/nds32/include/asm/l2_cache.h
create mode 100644 arch/nds32/kernel/atl2c.c

diff --git a/arch/nds32/include/asm/l2_cache.h b/arch/nds32/include/asm/l2_cache.h
new file mode 100644
index 0000000..b8530bd
--- /dev/null
+++ b/arch/nds32/include/asm/l2_cache.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef L2_CACHE_H
+#define L2_CACHE_H
+
+/* This is defined for head.S to use due to device tree is not yet built. */
+#define L2CC_PA_BASE 0x90F00000
+
+/* CCTL_CMD_OP */
+#define L2_CA_CONF_OFF 0x0
+#define L2_IF_CONF_OFF 0x4
+#define L2CC_SETUP_OFF 0x8
+#define L2CC_PROT_OFF 0xC
+#define L2CC_CTRL_OFF 0x10
+#define L2_INT_EN_OFF 0x20
+#define L2_STA_OFF 0x24
+#define RDERR_ADDR_OFF 0x28
+#define WRERR_ADDR_OFF 0x2c
+#define EVDPTERR_ADDR_OFF 0x30
+#define IMPL3ERR_ADDR_OFF 0x34
+#define L2_CNT0_CTRL_OFF 0x40
+#define L2_EVNT_CNT0_OFF 0x44
+#define L2_CNT1_CTRL_OFF 0x48
+#define L2_EVNT_CNT1_OFF 0x4c
+#define L2_CCTL_CMD_OFF 0x60
+#define L2_CCTL_STATUS_OFF 0x64
+#define L2_LINE_TAG_OFF 0x68
+#define L2_LINE_DPT_OFF 0x70
+
+#define CCTL_CMD_L2_IX_INVAL 0x0
+#define CCTL_CMD_L2_PA_INVAL 0x1
+#define CCTL_CMD_L2_IX_WB 0x2
+#define CCTL_CMD_L2_PA_WB 0x3
+#define CCTL_CMD_L2_PA_WBINVAL 0x5
+#define CCTL_CMD_L2_SYNC 0xa
+
+/* CCTL_CMD_TYPE */
+#define CCTL_SINGLE_CMD 0
+#define CCTL_BLOCK_CMD 0x10
+#define CCTL_ALL_CMD 0x10
+
+/******************************************************************************
+ * L2_CA_CONF (Cache architecture configuration)
+ *****************************************************************************/
+#define L2_CA_CONF_offL2SET 0
+#define L2_CA_CONF_offL2WAY 4
+#define L2_CA_CONF_offL2CLSZ 8
+#define L2_CA_CONF_offL2DW 11
+#define L2_CA_CONF_offL2PT 14
+#define L2_CA_CONF_offL2VER 16
+
+#define L2_CA_CONF_mskL2SET (0xFUL << L2_CA_CONF_offL2SET)
+#define L2_CA_CONF_mskL2WAY (0xFUL << L2_CA_CONF_offL2WAY)
+#define L2_CA_CONF_mskL2CLSZ (0x7UL << L2_CA_CONF_offL2CLSZ)
+#define L2_CA_CONF_mskL2DW (0x7UL << L2_CA_CONF_offL2DW)
+#define L2_CA_CONF_mskL2PT (0x3UL << L2_CA_CONF_offL2PT)
+#define L2_CA_CONF_mskL2VER (0xFFFFUL << L2_CA_CONF_offL2VER)
+
+/******************************************************************************
+ * L2CC_SETUP (L2CC Setup register)
+ *****************************************************************************/
+#define L2CC_SETUP_offPART 0
+#define L2CC_SETUP_mskPART (0x3UL << L2CC_SETUP_offPART)
+#define L2CC_SETUP_offDDLATC 4
+#define L2CC_SETUP_mskDDLATC (0x3UL << L2CC_SETUP_offDDLATC)
+#define L2CC_SETUP_offTDLATC 8
+#define L2CC_SETUP_mskTDLATC (0x3UL << L2CC_SETUP_offTDLATC)
+
+/******************************************************************************
+ * L2CC_PROT (L2CC Protect register)
+ *****************************************************************************/
+#define L2CC_PROT_offMRWEN 31
+#define L2CC_PROT_mskMRWEN (0x1UL << L2CC_PROT_offMRWEN)
+
+/******************************************************************************
+ * L2_CCTL_STATUS_Mn (The L2CCTL command working status for Master n)
+ *****************************************************************************/
+#define L2CC_CTRL_offEN 31
+#define L2CC_CTRL_mskEN (0x1UL << L2CC_CTRL_offEN)
+
+/******************************************************************************
+ * L2_CCTL_STATUS_Mn (The L2CCTL command working status for Master n)
+ *****************************************************************************/
+#define L2_CCTL_STATUS_offCMD_COMP 31
+#define L2_CCTL_STATUS_mskCMD_COMP (0x1 << L2_CCTL_STATUS_offCMD_COMP)
+
+#ifndef __ASSEMBLY__
+extern void __iomem *atl2c_base;
+
+#include <linux/smp.h>
+#include <asm/io.h>
+#include <asm/bitfield.h>
+
+#define L2C_R_REG(offset) __raw_readl(atl2c_base + offset)
+#define L2C_W_REG(offset, value) __raw_writel(value, atl2c_base + offset)
+
+#define L2_CMD_RDY() \
+ do{;}while((L2C_R_REG(L2_CCTL_STATUS_OFF) & L2_CCTL_STATUS_mskCMD_COMP) == 0)
+
+static inline unsigned long L2_CACHE_SET(void)
+{
+ return 64 << ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2SET) >>
+ L2_CA_CONF_offL2SET);
+}
+
+static inline unsigned long L2_CACHE_WAY(void)
+{
+ return 1 +
+ ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2WAY) >>
+ L2_CA_CONF_offL2WAY);
+}
+
+static inline unsigned long L2_CACHE_LINE_SIZE(void)
+{
+
+ return 4 << ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2CLSZ) >>
+ L2_CA_CONF_offL2CLSZ);
+}
+
+static inline unsigned long GET_L2CC_CTRL_CPU(unsigned long cpu)
+{
+ if (cpu == smp_processor_id())
+ return L2C_R_REG(L2CC_CTRL_OFF);
+ return L2C_R_REG(L2CC_CTRL_OFF + (cpu << 8));
+}
+
+static inline void SET_L2CC_CTRL_CPU(unsigned long cpu, unsigned long val)
+{
+ if (cpu == smp_processor_id())
+ L2C_W_REG(L2CC_CTRL_OFF, val);
+ else
+ L2C_W_REG(L2CC_CTRL_OFF + (cpu << 8), val);
+}
+
+static inline unsigned long GET_L2CC_STATUS_CPU(unsigned long cpu)
+{
+ if (cpu == smp_processor_id())
+ return L2C_R_REG(L2_CCTL_STATUS_OFF);
+ return L2C_R_REG(L2_CCTL_STATUS_OFF + (cpu << 8));
+}
+
+#endif
+
+#endif
diff --git a/arch/nds32/kernel/atl2c.c b/arch/nds32/kernel/atl2c.c
new file mode 100644
index 0000000..dd87fc9
--- /dev/null
+++ b/arch/nds32/kernel/atl2c.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2005-2017 Andes Technology Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <asm/l2_cache.h>
+
+void __iomem *atl2c_base;
+static const struct of_device_id atl2c_ids[] __initconst = {
+ {.compatible = "andestech,atl2c",}
+};
+
+static int __init atl2c_of_init(void)
+{
+ struct device_node *np;
+ struct resource res;
+ unsigned long tmp = 0;
+ unsigned long l2set, l2way, l2clsz;
+
+ if (!(__nds32__mfsr(NDS32_SR_MSC_CFG) & MSC_CFG_mskL2C))
+ return -ENODEV;
+
+ np = of_find_matching_node(NULL, atl2c_ids);
+ if (!np)
+ return -ENODEV;
+
+ if (of_address_to_resource(np, 0, &res))
+ return -ENODEV;
+
+ atl2c_base = ioremap(res.start, resource_size(&res));
+ if (!atl2c_base)
+ return -ENOMEM;
+
+ l2set =
+ 64 << ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2SET) >>
+ L2_CA_CONF_offL2SET);
+ l2way =
+ 1 +
+ ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2WAY) >>
+ L2_CA_CONF_offL2WAY);
+ l2clsz =
+ 4 << ((L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2CLSZ) >>
+ L2_CA_CONF_offL2CLSZ);
+ pr_info("L2:%luKB/%luS/%luW/%luB\n",
+ l2set * l2way * l2clsz / 1024, l2set, l2way, l2clsz);
+
+ tmp = L2C_R_REG(L2CC_PROT_OFF);
+ tmp &= ~L2CC_PROT_mskMRWEN;
+ L2C_W_REG(L2CC_PROT_OFF, tmp);
+
+ tmp = L2C_R_REG(L2CC_SETUP_OFF);
+ tmp &= ~L2CC_SETUP_mskPART;
+ L2C_W_REG(L2CC_SETUP_OFF, tmp);
+
+ tmp = L2C_R_REG(L2CC_CTRL_OFF);
+ tmp |= L2CC_CTRL_mskEN;
+ L2C_W_REG(L2CC_CTRL_OFF, tmp);
+
+ return 0;
+}
+
+subsys_initcall(atl2c_of_init);
--
1.7.9.5