CLK: ARC: HSDK: avoid code duplication
[oweals/u-boot.git] / 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 <hang.h>
8 #include <wait_bit.h>
9
10 #include <asm/io.h>
11
12 /* Directory */
13 #define DIRUSFER                0x80010
14 #define DIRUCASER0              0x80040
15 #define DIRUSFMCR               0x80080
16 #define DIRUSFMAR               0x80084
17
18 #define DIRUSFMCR_SFID_SHIFT    16
19
20 /* Coherent cache agent interface */
21 #define CAIUIDR                 0x00ffc
22
23 #define CAIUIDR_CA_GET(v)       (((v) & 0x00008000) >> 15)
24 #define CAIUIDR_TYPE_GET(v)     (((v) & 0x000f0000) >> 16)
25 #define CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT        0
26 #define CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT    1
27
28 /* Coherent subsystem */
29 #define CSADSER0                0xff040
30 #define CSUIDR                  0xffff8
31 #define CSIDR                   0xffffc
32
33 #define CSUIDR_NUMCAIUS_GET(v)  (((v) & 0x0000007f) >> 0)
34 #define CSUIDR_NUMDIRUS_GET(v)  (((v) & 0x003f0000) >> 16)
35 #define CSUIDR_NUMCMIUS_GET(v)  (((v) & 0x3f000000) >> 24)
36
37 #define CSIDR_NUMSFS_GET(v)     (((v) & 0x007c0000) >> 18)
38
39 #define DIR_REG_SZ              0x1000
40 #define CAIU_REG_SZ             0x1000
41
42 #define CCU_DIR_REG_ADDR(base, reg, dir)        \
43                 ((base) + (reg) + ((dir) * DIR_REG_SZ))
44
45 /* OCRAM firewall register */
46 #define OCRAM_FW_01                     0x100204
47 #define OCRAM_SECURE_REGIONS            4
48
49 #define OCRAM_PRIVILEGED_MASK           BIT(29)
50 #define OCRAM_SECURE_MASK               BIT(30)
51
52 static void ncore_ccu_init_dirs(void __iomem *base)
53 {
54         ulong i, f;
55         int ret;
56         u32 num_of_dirs;
57         u32 num_of_snoop_filters;
58         u32 reg;
59
60         num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR));
61         num_of_snoop_filters =
62                 CSIDR_NUMSFS_GET(readl(base + CSIDR)) + 1;
63
64         /* Initialize each snoop filter in each directory */
65         for (f = 0; f < num_of_snoop_filters; f++) {
66                 reg = f << DIRUSFMCR_SFID_SHIFT;
67                 for (i = 0; i < num_of_dirs; i++) {
68                         /* Initialize all entries */
69                         writel(reg, CCU_DIR_REG_ADDR(base, DIRUSFMCR, i));
70
71                         /* Poll snoop filter maintenance operation active
72                          * bit become 0.
73                          */
74                         ret = wait_for_bit_le32((const void *)
75                                                 CCU_DIR_REG_ADDR(base,
76                                                                  DIRUSFMAR, i),
77                                                 BIT(0), false, 1000, false);
78                         if (ret) {
79                                 puts("CCU: Directory initialization failed!\n");
80                                 hang();
81                         }
82
83                         /* Enable snoop filter, a bit per snoop filter */
84                         setbits_le32((ulong)CCU_DIR_REG_ADDR(base, DIRUSFER, i),
85                                      BIT(f));
86                 }
87         }
88 }
89
90 static void ncore_ccu_init_coh_agent(void __iomem *base)
91 {
92         u32 num_of_coh_agent_intf;
93         u32 num_of_dirs;
94         u32 reg;
95         u32 type;
96         u32 i, dir;
97
98         num_of_coh_agent_intf =
99                 CSUIDR_NUMCAIUS_GET(readl(base + CSUIDR));
100         num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR));
101
102         for (i = 0; i < num_of_coh_agent_intf; i++) {
103                 reg = readl(base + CAIUIDR + (i * CAIU_REG_SZ));
104                 if (CAIUIDR_CA_GET(reg)) {
105                         /* Caching agent bit is enabled, enable caching agent
106                          * snoop in each directory
107                          */
108                         for (dir = 0; dir < num_of_dirs; dir++) {
109                                 setbits_le32((ulong)
110                                              CCU_DIR_REG_ADDR(base, DIRUCASER0,
111                                                               dir),
112                                              BIT(i));
113                         }
114                 }
115
116                 type = CAIUIDR_TYPE_GET(reg);
117                 if (type == CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT ||
118                     type == CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT) {
119                         /* DVM support is enabled, enable ACE DVM snoop*/
120                         setbits_le32((ulong)(base + CSADSER0),
121                                      BIT(i));
122                 }
123         }
124 }
125
126 static void ocram_bypass_firewall(void __iomem *base)
127 {
128         int i;
129
130         for (i = 0; i < OCRAM_SECURE_REGIONS; i++) {
131                 clrbits_le32(base + OCRAM_FW_01 + (i * sizeof(u32)),
132                              OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
133         }
134 }
135
136 static int ncore_ccu_probe(struct udevice *dev)
137 {
138         void __iomem *base;
139         fdt_addr_t addr;
140
141         addr = dev_read_addr(dev);
142         if (addr == FDT_ADDR_T_NONE)
143                 return -EINVAL;
144
145         base = (void __iomem *)addr;
146
147         ncore_ccu_init_dirs(base);
148         ncore_ccu_init_coh_agent(base);
149         ocram_bypass_firewall(base);
150
151         return 0;
152 }
153
154 static const struct udevice_id ncore_ccu_ids[] = {
155         { .compatible = "arteris,ncore-ccu" },
156         {}
157 };
158
159 U_BOOT_DRIVER(ncore_ccu) = {
160         .name   = "ncore_ccu",
161         .id     = UCLASS_CACHE,
162         .of_match = ncore_ccu_ids,
163         .probe  = ncore_ccu_probe,
164         .flags  = DM_FLAG_PRE_RELOC,
165 };