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