|
@@ -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,
|
|
|
+};
|