cache: Add Arteris Ncore cache coherent unit driver
authorLey Foon Tan <ley.foon.tan@intel.com>
Wed, 27 Nov 2019 07:55:24 +0000 (15:55 +0800)
committerMarek Vasut <marex@denx.de>
Tue, 7 Jan 2020 13:38:33 +0000 (14:38 +0100)
Add Cache Coherency Unit (CCU) driver.
CCU is to ensures consistency of shared data between multi masters
in the system.

Driver initializes CCU's directories and coherency agent
interfaces in CCU IP.

Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
Reviewed-by: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
drivers/cache/Kconfig
drivers/cache/Makefile
drivers/cache/cache-ncore.c [new file with mode: 0644]

index 629039e7a88fb973aabe1289aebb0f4ca036ae34..1e452ad6d9f86b4fee096f47b5d86606201c6862 100644 (file)
@@ -31,4 +31,12 @@ config V5L2_CACHE
          It will configure tag and data ram timing control from the
          device tree and enable L2 cache.
 
+config NCORE_CACHE
+       bool "Arteris Ncore cache coherent unit driver"
+       select CACHE
+       help
+         This driver is for the Arteris Ncore cache coherent unit (CCU)
+         controller. The driver initializes cache directories and coherent
+         agent interfaces.
+
 endmenu
index 924217044a0e4224b43e73103b9495e1c03cd2ae..fed50be3f983a8577592be8f0b93b6cbcec30dd8 100644 (file)
@@ -2,4 +2,5 @@
 obj-$(CONFIG_$(SPL_TPL_)CACHE) += cache-uclass.o
 obj-$(CONFIG_SANDBOX) += sandbox_cache.o
 obj-$(CONFIG_L2X0_CACHE) += cache-l2x0.o
+obj-$(CONFIG_NCORE_CACHE) += cache-ncore.o
 obj-$(CONFIG_V5L2_CACHE) += cache-v5l2.o
diff --git a/drivers/cache/cache-ncore.c b/drivers/cache/cache-ncore.c
new file mode 100644 (file)
index 0000000..e3aca36
--- /dev/null
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Intel Corporation <www.intel.com>
+ *
+ */
+#include <dm.h>
+#include <wait_bit.h>
+
+#include <asm/io.h>
+
+/* Directory */
+#define DIRUSFER               0x80010
+#define DIRUCASER0             0x80040
+#define DIRUSFMCR              0x80080
+#define DIRUSFMAR              0x80084
+
+#define DIRUSFMCR_SFID_SHIFT   16
+
+/* Coherent cache agent interface */
+#define CAIUIDR                        0x00ffc
+
+#define CAIUIDR_CA_GET(v)      (((v) & 0x00008000) >> 15)
+#define CAIUIDR_TYPE_GET(v)    (((v) & 0x000f0000) >> 16)
+#define CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT       0
+#define CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT   1
+
+/* Coherent subsystem */
+#define CSADSER0               0xff040
+#define CSUIDR                 0xffff8
+#define CSIDR                  0xffffc
+
+#define CSUIDR_NUMCAIUS_GET(v) (((v) & 0x0000007f) >> 0)
+#define CSUIDR_NUMDIRUS_GET(v) (((v) & 0x003f0000) >> 16)
+#define CSUIDR_NUMCMIUS_GET(v) (((v) & 0x3f000000) >> 24)
+
+#define CSIDR_NUMSFS_GET(v)    (((v) & 0x007c0000) >> 18)
+
+#define DIR_REG_SZ             0x1000
+#define CAIU_REG_SZ            0x1000
+
+#define CCU_DIR_REG_ADDR(base, reg, dir)       \
+               ((base) + (reg) + ((dir) * DIR_REG_SZ))
+
+/* OCRAM firewall register */
+#define OCRAM_FW_01                    0x100204
+#define OCRAM_SECURE_REGIONS           4
+
+#define OCRAM_PRIVILEGED_MASK          BIT(29)
+#define OCRAM_SECURE_MASK              BIT(30)
+
+static void ncore_ccu_init_dirs(void __iomem *base)
+{
+       ulong i, f;
+       int ret;
+       u32 num_of_dirs;
+       u32 num_of_snoop_filters;
+       u32 reg;
+
+       num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR));
+       num_of_snoop_filters =
+               CSIDR_NUMSFS_GET(readl(base + CSIDR)) + 1;
+
+       /* Initialize each snoop filter in each directory */
+       for (f = 0; f < num_of_snoop_filters; f++) {
+               reg = f << DIRUSFMCR_SFID_SHIFT;
+               for (i = 0; i < num_of_dirs; i++) {
+                       /* Initialize all entries */
+                       writel(reg, CCU_DIR_REG_ADDR(base, DIRUSFMCR, i));
+
+                       /* Poll snoop filter maintenance operation active
+                        * bit become 0.
+                        */
+                       ret = wait_for_bit_le32((const void *)
+                                               CCU_DIR_REG_ADDR(base,
+                                                                DIRUSFMAR, i),
+                                               BIT(0), false, 1000, false);
+                       if (ret) {
+                               puts("CCU: Directory initialization failed!\n");
+                               hang();
+                       }
+
+                       /* Enable snoop filter, a bit per snoop filter */
+                       setbits_le32((ulong)CCU_DIR_REG_ADDR(base, DIRUSFER, i),
+                                    BIT(f));
+               }
+       }
+}
+
+static void ncore_ccu_init_coh_agent(void __iomem *base)
+{
+       u32 num_of_coh_agent_intf;
+       u32 num_of_dirs;
+       u32 reg;
+       u32 type;
+       u32 i, dir;
+
+       num_of_coh_agent_intf =
+               CSUIDR_NUMCAIUS_GET(readl(base + CSUIDR));
+       num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR));
+
+       for (i = 0; i < num_of_coh_agent_intf; i++) {
+               reg = readl(base + CAIUIDR + (i * CAIU_REG_SZ));
+               if (CAIUIDR_CA_GET(reg)) {
+                       /* Caching agent bit is enabled, enable caching agent
+                        * snoop in each directory
+                        */
+                       for (dir = 0; dir < num_of_dirs; dir++) {
+                               setbits_le32((ulong)
+                                            CCU_DIR_REG_ADDR(base, DIRUCASER0,
+                                                             dir),
+                                            BIT(i));
+                       }
+               }
+
+               type = CAIUIDR_TYPE_GET(reg);
+               if (type == CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT ||
+                   type == CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT) {
+                       /* DVM support is enabled, enable ACE DVM snoop*/
+                       setbits_le32((ulong)(base + CSADSER0),
+                                    BIT(i));
+               }
+       }
+}
+
+static void ocram_bypass_firewall(void __iomem *base)
+{
+       int i;
+
+       for (i = 0; i < OCRAM_SECURE_REGIONS; i++) {
+               clrbits_le32(base + OCRAM_FW_01 + (i * sizeof(u32)),
+                            OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
+       }
+}
+
+static int ncore_ccu_probe(struct udevice *dev)
+{
+       void __iomem *base;
+       fdt_addr_t addr;
+
+       addr = dev_read_addr(dev);
+       if (addr == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       base = (void __iomem *)addr;
+
+       ncore_ccu_init_dirs(base);
+       ncore_ccu_init_coh_agent(base);
+       ocram_bypass_firewall(base);
+
+       return 0;
+}
+
+static const struct udevice_id ncore_ccu_ids[] = {
+       { .compatible = "arteris,ncore-ccu" },
+       {}
+};
+
+U_BOOT_DRIVER(ncore_ccu) = {
+       .name   = "ncore_ccu",
+       .id     = UCLASS_CACHE,
+       .of_match = ncore_ccu_ids,
+       .probe  = ncore_ccu_probe,
+       .flags  = DM_FLAG_PRE_RELOC,
+};