Commit fec7ddc1907c1c86be6849de0fab7466b79cd834

Authored by Ley Foon Tan
Committed by Marek Vasut
1 parent b4a20cb300

cache: Add Arteris Ncore cache coherent unit driver

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>

Showing 3 changed files with 173 additions and 0 deletions Side-by-side Diff

drivers/cache/Kconfig
... ... @@ -31,5 +31,13 @@
31 31 It will configure tag and data ram timing control from the
32 32 device tree and enable L2 cache.
33 33  
  34 +config NCORE_CACHE
  35 + bool "Arteris Ncore cache coherent unit driver"
  36 + select CACHE
  37 + help
  38 + This driver is for the Arteris Ncore cache coherent unit (CCU)
  39 + controller. The driver initializes cache directories and coherent
  40 + agent interfaces.
  41 +
34 42 endmenu
drivers/cache/Makefile
... ... @@ -2,5 +2,6 @@
2 2 obj-$(CONFIG_$(SPL_TPL_)CACHE) += cache-uclass.o
3 3 obj-$(CONFIG_SANDBOX) += sandbox_cache.o
4 4 obj-$(CONFIG_L2X0_CACHE) += cache-l2x0.o
  5 +obj-$(CONFIG_NCORE_CACHE) += cache-ncore.o
5 6 obj-$(CONFIG_V5L2_CACHE) += cache-v5l2.o
drivers/cache/cache-ncore.c
  1 +// SPDX-License-Identifier: GPL-2.0
  2 +/*
  3 + * Copyright (C) 2019 Intel Corporation <www.intel.com>
  4 + *
  5 + */
  6 +#include <dm.h>
  7 +#include <wait_bit.h>
  8 +
  9 +#include <asm/io.h>
  10 +
  11 +/* Directory */
  12 +#define DIRUSFER 0x80010
  13 +#define DIRUCASER0 0x80040
  14 +#define DIRUSFMCR 0x80080
  15 +#define DIRUSFMAR 0x80084
  16 +
  17 +#define DIRUSFMCR_SFID_SHIFT 16
  18 +
  19 +/* Coherent cache agent interface */
  20 +#define CAIUIDR 0x00ffc
  21 +
  22 +#define CAIUIDR_CA_GET(v) (((v) & 0x00008000) >> 15)
  23 +#define CAIUIDR_TYPE_GET(v) (((v) & 0x000f0000) >> 16)
  24 +#define CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT 0
  25 +#define CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT 1
  26 +
  27 +/* Coherent subsystem */
  28 +#define CSADSER0 0xff040
  29 +#define CSUIDR 0xffff8
  30 +#define CSIDR 0xffffc
  31 +
  32 +#define CSUIDR_NUMCAIUS_GET(v) (((v) & 0x0000007f) >> 0)
  33 +#define CSUIDR_NUMDIRUS_GET(v) (((v) & 0x003f0000) >> 16)
  34 +#define CSUIDR_NUMCMIUS_GET(v) (((v) & 0x3f000000) >> 24)
  35 +
  36 +#define CSIDR_NUMSFS_GET(v) (((v) & 0x007c0000) >> 18)
  37 +
  38 +#define DIR_REG_SZ 0x1000
  39 +#define CAIU_REG_SZ 0x1000
  40 +
  41 +#define CCU_DIR_REG_ADDR(base, reg, dir) \
  42 + ((base) + (reg) + ((dir) * DIR_REG_SZ))
  43 +
  44 +/* OCRAM firewall register */
  45 +#define OCRAM_FW_01 0x100204
  46 +#define OCRAM_SECURE_REGIONS 4
  47 +
  48 +#define OCRAM_PRIVILEGED_MASK BIT(29)
  49 +#define OCRAM_SECURE_MASK BIT(30)
  50 +
  51 +static void ncore_ccu_init_dirs(void __iomem *base)
  52 +{
  53 + ulong i, f;
  54 + int ret;
  55 + u32 num_of_dirs;
  56 + u32 num_of_snoop_filters;
  57 + u32 reg;
  58 +
  59 + num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR));
  60 + num_of_snoop_filters =
  61 + CSIDR_NUMSFS_GET(readl(base + CSIDR)) + 1;
  62 +
  63 + /* Initialize each snoop filter in each directory */
  64 + for (f = 0; f < num_of_snoop_filters; f++) {
  65 + reg = f << DIRUSFMCR_SFID_SHIFT;
  66 + for (i = 0; i < num_of_dirs; i++) {
  67 + /* Initialize all entries */
  68 + writel(reg, CCU_DIR_REG_ADDR(base, DIRUSFMCR, i));
  69 +
  70 + /* Poll snoop filter maintenance operation active
  71 + * bit become 0.
  72 + */
  73 + ret = wait_for_bit_le32((const void *)
  74 + CCU_DIR_REG_ADDR(base,
  75 + DIRUSFMAR, i),
  76 + BIT(0), false, 1000, false);
  77 + if (ret) {
  78 + puts("CCU: Directory initialization failed!\n");
  79 + hang();
  80 + }
  81 +
  82 + /* Enable snoop filter, a bit per snoop filter */
  83 + setbits_le32((ulong)CCU_DIR_REG_ADDR(base, DIRUSFER, i),
  84 + BIT(f));
  85 + }
  86 + }
  87 +}
  88 +
  89 +static void ncore_ccu_init_coh_agent(void __iomem *base)
  90 +{
  91 + u32 num_of_coh_agent_intf;
  92 + u32 num_of_dirs;
  93 + u32 reg;
  94 + u32 type;
  95 + u32 i, dir;
  96 +
  97 + num_of_coh_agent_intf =
  98 + CSUIDR_NUMCAIUS_GET(readl(base + CSUIDR));
  99 + num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR));
  100 +
  101 + for (i = 0; i < num_of_coh_agent_intf; i++) {
  102 + reg = readl(base + CAIUIDR + (i * CAIU_REG_SZ));
  103 + if (CAIUIDR_CA_GET(reg)) {
  104 + /* Caching agent bit is enabled, enable caching agent
  105 + * snoop in each directory
  106 + */
  107 + for (dir = 0; dir < num_of_dirs; dir++) {
  108 + setbits_le32((ulong)
  109 + CCU_DIR_REG_ADDR(base, DIRUCASER0,
  110 + dir),
  111 + BIT(i));
  112 + }
  113 + }
  114 +
  115 + type = CAIUIDR_TYPE_GET(reg);
  116 + if (type == CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT ||
  117 + type == CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT) {
  118 + /* DVM support is enabled, enable ACE DVM snoop*/
  119 + setbits_le32((ulong)(base + CSADSER0),
  120 + BIT(i));
  121 + }
  122 + }
  123 +}
  124 +
  125 +static void ocram_bypass_firewall(void __iomem *base)
  126 +{
  127 + int i;
  128 +
  129 + for (i = 0; i < OCRAM_SECURE_REGIONS; i++) {
  130 + clrbits_le32(base + OCRAM_FW_01 + (i * sizeof(u32)),
  131 + OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
  132 + }
  133 +}
  134 +
  135 +static int ncore_ccu_probe(struct udevice *dev)
  136 +{
  137 + void __iomem *base;
  138 + fdt_addr_t addr;
  139 +
  140 + addr = dev_read_addr(dev);
  141 + if (addr == FDT_ADDR_T_NONE)
  142 + return -EINVAL;
  143 +
  144 + base = (void __iomem *)addr;
  145 +
  146 + ncore_ccu_init_dirs(base);
  147 + ncore_ccu_init_coh_agent(base);
  148 + ocram_bypass_firewall(base);
  149 +
  150 + return 0;
  151 +}
  152 +
  153 +static const struct udevice_id ncore_ccu_ids[] = {
  154 + { .compatible = "arteris,ncore-ccu" },
  155 + {}
  156 +};
  157 +
  158 +U_BOOT_DRIVER(ncore_ccu) = {
  159 + .name = "ncore_ccu",
  160 + .id = UCLASS_CACHE,
  161 + .of_match = ncore_ccu_ids,
  162 + .probe = ncore_ccu_probe,
  163 + .flags = DM_FLAG_PRE_RELOC,
  164 +};