]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
f698e9f3 AB |
2 | /* |
3 | * FSL PAMU driver | |
4 | * | |
5 | * Copyright 2012-2016 Freescale Semiconductor, Inc. | |
f698e9f3 AB |
6 | */ |
7 | ||
d678a59d | 8 | #include <common.h> |
f7ae49fc | 9 | #include <log.h> |
cd93d625 | 10 | #include <linux/bitops.h> |
f698e9f3 AB |
11 | #include <linux/log2.h> |
12 | #include <malloc.h> | |
13 | #include <asm/fsl_pamu.h> | |
14 | ||
15 | struct paace *ppaact; | |
16 | struct paace *sec; | |
17 | unsigned long fspi; | |
18 | ||
19 | static inline int __ilog2_roundup_64(uint64_t val) | |
20 | { | |
21 | if ((val & (val - 1)) == 0) | |
22 | return __ilog2_u64(val); | |
23 | else | |
24 | return __ilog2_u64(val) + 1; | |
25 | } | |
26 | ||
27 | ||
28 | static inline int count_lsb_zeroes(unsigned long val) | |
29 | { | |
30 | return ffs(val) - 1; | |
31 | } | |
32 | ||
33 | static unsigned int map_addrspace_size_to_wse(uint64_t addrspace_size) | |
34 | { | |
35 | /* window size is 2^(WSE+1) bytes */ | |
36 | return count_lsb_zeroes(addrspace_size >> PAMU_PAGE_SHIFT) + | |
37 | PAMU_PAGE_SHIFT - 1; | |
38 | } | |
39 | ||
40 | static unsigned int map_subwindow_cnt_to_wce(uint32_t subwindow_cnt) | |
41 | { | |
42 | /* window count is 2^(WCE+1) bytes */ | |
43 | return count_lsb_zeroes(subwindow_cnt) - 1; | |
44 | } | |
45 | ||
46 | static void pamu_setup_default_xfer_to_host_ppaace(struct paace *ppaace) | |
47 | { | |
48 | set_bf(ppaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_PRIMARY); | |
49 | set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR, | |
50 | PAACE_M_COHERENCE_REQ); | |
51 | } | |
52 | ||
53 | static void pamu_setup_default_xfer_to_host_spaace(struct paace *spaace) | |
54 | { | |
55 | set_bf(spaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_SECONDARY); | |
56 | set_bf(spaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR, | |
57 | PAACE_M_COHERENCE_REQ); | |
58 | } | |
59 | ||
60 | /** Sets up PPAACE entry for specified liodn | |
61 | * | |
62 | * @param[in] liodn Logical IO device number | |
63 | * @param[in] win_addr starting address of DSA window | |
64 | * @param[in] win-size size of DSA window | |
65 | * @param[in] omi Operation mapping index -- if ~omi == 0 then omi | |
66 | not defined | |
67 | * @param[in] stashid cache stash id for associated cpu -- if ~stashid == 0 | |
68 | then stashid not defined | |
69 | * @param[in] snoopid snoop id for hardware coherency -- if ~snoopid == 0 | |
70 | then snoopid not defined | |
71 | * @param[in] subwin_cnt number of sub-windows | |
72 | * | |
185f812c | 73 | * Return: Returns 0 upon success else error code < 0 returned |
f698e9f3 AB |
74 | */ |
75 | static int pamu_config_ppaace(uint32_t liodn, uint64_t win_addr, | |
76 | uint64_t win_size, uint32_t omi, | |
77 | uint32_t snoopid, uint32_t stashid, | |
78 | uint32_t subwin_cnt) | |
79 | { | |
80 | struct paace *ppaace; | |
81 | ||
82 | if ((win_size & (win_size - 1)) || win_size < PAMU_PAGE_SIZE) | |
83 | return -1; | |
84 | ||
85 | if (win_addr & (win_size - 1)) | |
86 | return -2; | |
87 | ||
88 | if (liodn > NUM_PPAACT_ENTRIES) { | |
89 | printf("Entries in PPACT not sufficient\n"); | |
90 | return -3; | |
91 | } | |
92 | ||
93 | ppaace = &ppaact[liodn]; | |
94 | ||
95 | /* window size is 2^(WSE+1) bytes */ | |
96 | set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, | |
97 | map_addrspace_size_to_wse(win_size)); | |
98 | ||
99 | pamu_setup_default_xfer_to_host_ppaace(ppaace); | |
100 | ||
101 | if (sizeof(phys_addr_t) > 4) | |
102 | ppaace->wbah = (u64)win_addr >> (PAMU_PAGE_SHIFT + 20); | |
103 | else | |
104 | ppaace->wbah = 0; | |
105 | ||
106 | set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, | |
107 | (win_addr >> PAMU_PAGE_SHIFT)); | |
108 | ||
109 | /* set up operation mapping if it's configured */ | |
110 | if (omi < OME_NUMBER_ENTRIES) { | |
111 | set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED); | |
112 | ppaace->op_encode.index_ot.omi = omi; | |
113 | } else if (~omi != 0) { | |
114 | return -3; | |
115 | } | |
116 | ||
117 | /* configure stash id */ | |
118 | if (~stashid != 0) | |
119 | set_bf(ppaace->impl_attr, PAACE_IA_CID, stashid); | |
120 | ||
121 | /* configure snoop id */ | |
122 | if (~snoopid != 0) | |
123 | ppaace->domain_attr.to_host.snpid = snoopid; | |
124 | ||
125 | if (subwin_cnt) { | |
126 | /* window count is 2^(WCE+1) bytes */ | |
127 | set_bf(ppaace->impl_attr, PAACE_IA_WCE, | |
128 | map_subwindow_cnt_to_wce(subwin_cnt)); | |
129 | set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0x1); | |
130 | ppaace->fspi = fspi; | |
131 | fspi = fspi + DEFAULT_NUM_SUBWINDOWS - 1; | |
132 | } else { | |
133 | set_bf(ppaace->addr_bitfields, PAACE_AF_AP, PAACE_AP_PERMS_ALL); | |
134 | } | |
135 | ||
5c229985 | 136 | sync(); |
f698e9f3 AB |
137 | /* Mark the ppace entry valid */ |
138 | ppaace->addr_bitfields |= PAACE_V_VALID; | |
5c229985 | 139 | sync(); |
f698e9f3 AB |
140 | |
141 | return 0; | |
142 | } | |
143 | ||
144 | static int pamu_config_spaace(uint32_t liodn, | |
145 | uint64_t subwin_size, uint64_t subwin_addr, uint64_t size, | |
146 | uint32_t omi, uint32_t snoopid, uint32_t stashid) | |
147 | { | |
148 | struct paace *paace; | |
149 | /* Align start addr of subwin to subwindoe size */ | |
150 | uint64_t sec_addr = subwin_addr & ~(subwin_size - 1); | |
151 | uint64_t end_addr = subwin_addr + size; | |
152 | int size_shift = __ilog2_u64(subwin_size); | |
153 | uint64_t win_size = 0; | |
154 | uint32_t index, swse; | |
155 | unsigned long fspi_idx; | |
156 | ||
157 | /* Recalculate the size */ | |
158 | size = end_addr - sec_addr; | |
159 | ||
160 | if (!subwin_size) | |
161 | return -1; | |
162 | ||
163 | if (liodn > NUM_PPAACT_ENTRIES) { | |
164 | printf("LIODN No programmed %d > no. of PPAACT entries %d\n", | |
165 | liodn, NUM_PPAACT_ENTRIES); | |
166 | return -1; | |
167 | } | |
168 | ||
169 | while (sec_addr < end_addr) { | |
170 | debug("sec_addr < end_addr is %llx < %llx\n", sec_addr, | |
171 | end_addr); | |
172 | paace = &ppaact[liodn]; | |
173 | if (!paace) | |
174 | return -1; | |
175 | fspi_idx = paace->fspi; | |
176 | ||
177 | /* Calculating the win_size here as if we map in index 0, | |
178 | paace entry woudl need to be programmed for SWSE */ | |
179 | win_size = end_addr - sec_addr; | |
180 | win_size = 1 << __ilog2_roundup_64(win_size); | |
181 | ||
182 | if (win_size > subwin_size) | |
183 | win_size = subwin_size; | |
184 | else if (win_size < PAMU_PAGE_SIZE) | |
185 | win_size = PAMU_PAGE_SIZE; | |
186 | ||
187 | debug("win_size is %llx\n", win_size); | |
188 | ||
189 | swse = map_addrspace_size_to_wse(win_size); | |
190 | index = sec_addr >> size_shift; | |
191 | ||
192 | if (index == 0) { | |
193 | set_bf(paace->win_bitfields, PAACE_WIN_SWSE, swse); | |
194 | set_bf(paace->addr_bitfields, PAACE_AF_AP, | |
195 | PAACE_AP_PERMS_ALL); | |
196 | sec_addr += subwin_size; | |
197 | continue; | |
198 | } | |
199 | ||
200 | paace = sec + fspi_idx + index - 1; | |
201 | ||
202 | debug("SPAACT:Writing at location %p, index %d\n", paace, | |
203 | index); | |
204 | ||
205 | pamu_setup_default_xfer_to_host_spaace(paace); | |
206 | set_bf(paace->addr_bitfields, SPAACE_AF_LIODN, liodn); | |
207 | set_bf(paace->addr_bitfields, PAACE_AF_AP, PAACE_AP_PERMS_ALL); | |
208 | ||
209 | /* configure snoop id */ | |
210 | if (~snoopid != 0) | |
211 | paace->domain_attr.to_host.snpid = snoopid; | |
212 | ||
213 | if (paace->addr_bitfields & PAACE_V_VALID) { | |
214 | debug("Reached overlap condition\n"); | |
215 | debug("%d < %d\n", get_bf(paace->win_bitfields, | |
216 | PAACE_WIN_SWSE), swse); | |
217 | if (get_bf(paace->win_bitfields, PAACE_WIN_SWSE) < swse) | |
218 | set_bf(paace->win_bitfields, PAACE_WIN_SWSE, | |
219 | swse); | |
220 | } else { | |
221 | set_bf(paace->win_bitfields, PAACE_WIN_SWSE, swse); | |
222 | } | |
223 | ||
224 | paace->addr_bitfields |= PAACE_V_VALID; | |
225 | sec_addr += subwin_size; | |
226 | } | |
227 | ||
228 | return 0; | |
229 | } | |
230 | ||
231 | int pamu_init(void) | |
232 | { | |
65cc0e2a | 233 | u32 base_addr = CFG_SYS_PAMU_ADDR; |
f698e9f3 AB |
234 | struct ccsr_pamu *regs; |
235 | u32 i = 0; | |
236 | u64 ppaact_phys, ppaact_lim, ppaact_size; | |
237 | u64 spaact_phys, spaact_lim, spaact_size; | |
238 | ||
239 | ppaact_size = sizeof(struct paace) * NUM_PPAACT_ENTRIES; | |
240 | spaact_size = sizeof(struct paace) * NUM_SPAACT_ENTRIES; | |
241 | ||
242 | /* Allocate space for Primary PAACT Table */ | |
6e7df1d1 TR |
243 | #if (defined(CONFIG_SPL_BUILD) && defined(CFG_SPL_PPAACT_ADDR)) |
244 | ppaact = (void *)CFG_SPL_PPAACT_ADDR; | |
8f01397b | 245 | #else |
f698e9f3 AB |
246 | ppaact = memalign(PAMU_TABLE_ALIGNMENT, ppaact_size); |
247 | if (!ppaact) | |
248 | return -1; | |
8f01397b | 249 | #endif |
f698e9f3 AB |
250 | memset(ppaact, 0, ppaact_size); |
251 | ||
252 | /* Allocate space for Secondary PAACT Table */ | |
6e7df1d1 TR |
253 | #if (defined(CONFIG_SPL_BUILD) && defined(CFG_SPL_SPAACT_ADDR)) |
254 | sec = (void *)CFG_SPL_SPAACT_ADDR; | |
8f01397b | 255 | #else |
f698e9f3 AB |
256 | sec = memalign(PAMU_TABLE_ALIGNMENT, spaact_size); |
257 | if (!sec) | |
258 | return -1; | |
8f01397b | 259 | #endif |
f698e9f3 AB |
260 | memset(sec, 0, spaact_size); |
261 | ||
262 | ppaact_phys = virt_to_phys((void *)ppaact); | |
263 | ppaact_lim = ppaact_phys + ppaact_size; | |
264 | ||
265 | spaact_phys = (uint64_t)virt_to_phys((void *)sec); | |
266 | spaact_lim = spaact_phys + spaact_size; | |
267 | ||
268 | /* Configure all PAMU's */ | |
6e7df1d1 | 269 | for (i = 0; i < CFG_NUM_PAMU; i++) { |
f698e9f3 AB |
270 | regs = (struct ccsr_pamu *)base_addr; |
271 | ||
272 | out_be32(®s->ppbah, ppaact_phys >> 32); | |
273 | out_be32(®s->ppbal, (uint32_t)ppaact_phys); | |
274 | ||
275 | out_be32(®s->pplah, (ppaact_lim) >> 32); | |
276 | out_be32(®s->pplal, (uint32_t)ppaact_lim); | |
277 | ||
278 | if (sec != NULL) { | |
279 | out_be32(®s->spbah, spaact_phys >> 32); | |
280 | out_be32(®s->spbal, (uint32_t)spaact_phys); | |
281 | out_be32(®s->splah, spaact_lim >> 32); | |
282 | out_be32(®s->splal, (uint32_t)spaact_lim); | |
283 | } | |
5c229985 | 284 | sync(); |
f698e9f3 AB |
285 | |
286 | base_addr += PAMU_OFFSET; | |
287 | } | |
288 | ||
289 | return 0; | |
290 | } | |
291 | ||
292 | void pamu_enable(void) | |
293 | { | |
294 | u32 i = 0; | |
65cc0e2a | 295 | u32 base_addr = CFG_SYS_PAMU_ADDR; |
6e7df1d1 | 296 | for (i = 0; i < CFG_NUM_PAMU; i++) { |
f698e9f3 AB |
297 | setbits_be32((void *)base_addr + PAMU_PCR_OFFSET, |
298 | PAMU_PCR_PE); | |
5c229985 | 299 | sync(); |
f698e9f3 AB |
300 | base_addr += PAMU_OFFSET; |
301 | } | |
302 | } | |
303 | ||
304 | void pamu_reset(void) | |
305 | { | |
306 | u32 i = 0; | |
65cc0e2a | 307 | u32 base_addr = CFG_SYS_PAMU_ADDR; |
f698e9f3 AB |
308 | struct ccsr_pamu *regs; |
309 | ||
6e7df1d1 | 310 | for (i = 0; i < CFG_NUM_PAMU; i++) { |
f698e9f3 AB |
311 | regs = (struct ccsr_pamu *)base_addr; |
312 | /* Clear PPAACT Base register */ | |
313 | out_be32(®s->ppbah, 0); | |
314 | out_be32(®s->ppbal, 0); | |
315 | out_be32(®s->pplah, 0); | |
316 | out_be32(®s->pplal, 0); | |
317 | out_be32(®s->spbah, 0); | |
318 | out_be32(®s->spbal, 0); | |
319 | out_be32(®s->splah, 0); | |
320 | out_be32(®s->splal, 0); | |
321 | ||
322 | clrbits_be32((void *)regs + PAMU_PCR_OFFSET, PAMU_PCR_PE); | |
5c229985 | 323 | sync(); |
f698e9f3 AB |
324 | base_addr += PAMU_OFFSET; |
325 | } | |
326 | } | |
327 | ||
328 | void pamu_disable(void) | |
329 | { | |
330 | u32 i = 0; | |
65cc0e2a | 331 | u32 base_addr = CFG_SYS_PAMU_ADDR; |
f698e9f3 AB |
332 | |
333 | ||
6e7df1d1 | 334 | for (i = 0; i < CFG_NUM_PAMU; i++) { |
f698e9f3 | 335 | clrbits_be32((void *)base_addr + PAMU_PCR_OFFSET, PAMU_PCR_PE); |
5c229985 | 336 | sync(); |
f698e9f3 AB |
337 | base_addr += PAMU_OFFSET; |
338 | } | |
339 | } | |
340 | ||
341 | ||
342 | static uint64_t find_max(uint64_t arr[], int num) | |
343 | { | |
344 | int i = 0; | |
345 | int max = 0; | |
346 | for (i = 1 ; i < num; i++) | |
347 | if (arr[max] < arr[i]) | |
348 | max = i; | |
349 | ||
350 | return arr[max]; | |
351 | } | |
352 | ||
353 | static uint64_t find_min(uint64_t arr[], int num) | |
354 | { | |
355 | int i = 0; | |
356 | int min = 0; | |
357 | for (i = 1 ; i < num; i++) | |
358 | if (arr[min] > arr[i]) | |
359 | min = i; | |
360 | ||
361 | return arr[min]; | |
362 | } | |
363 | ||
364 | static uint32_t get_win_cnt(uint64_t size) | |
365 | { | |
366 | uint32_t win_cnt = DEFAULT_NUM_SUBWINDOWS; | |
367 | ||
368 | while (win_cnt && (size/win_cnt) < PAMU_PAGE_SIZE) | |
369 | win_cnt >>= 1; | |
370 | ||
371 | return win_cnt; | |
372 | } | |
373 | ||
374 | int config_pamu(struct pamu_addr_tbl *tbl, int num_entries, uint32_t liodn) | |
375 | { | |
376 | int i = 0; | |
377 | int ret = 0; | |
378 | uint32_t num_sec_windows = 0; | |
379 | uint32_t num_windows = 0; | |
380 | uint64_t min_addr, max_addr; | |
381 | uint64_t size; | |
382 | uint64_t subwin_size; | |
383 | int sizebit; | |
384 | ||
385 | min_addr = find_min(tbl->start_addr, num_entries); | |
386 | max_addr = find_max(tbl->end_addr, num_entries); | |
387 | size = max_addr - min_addr + 1; | |
388 | ||
389 | if (!size) | |
390 | return -1; | |
391 | ||
392 | sizebit = __ilog2_roundup_64(size); | |
43d1d391 | 393 | size = 1ull << sizebit; |
f698e9f3 AB |
394 | debug("min start_addr is %llx\n", min_addr); |
395 | debug("max end_addr is %llx\n", max_addr); | |
396 | debug("size found is %llx\n", size); | |
397 | ||
398 | if (size < PAMU_PAGE_SIZE) | |
399 | size = PAMU_PAGE_SIZE; | |
400 | ||
401 | while (1) { | |
402 | min_addr = min_addr & ~(size - 1); | |
403 | if (min_addr + size > max_addr) | |
404 | break; | |
405 | size <<= 1; | |
406 | if (!size) | |
407 | return -1; | |
408 | } | |
409 | debug("PAACT :Base addr is %llx\n", min_addr); | |
410 | debug("PAACT : Size is %llx\n", size); | |
411 | num_windows = get_win_cnt(size); | |
412 | /* For a single window, no spaact entries are required | |
413 | * sec_sub_window count = 0 */ | |
414 | if (num_windows > 1) | |
415 | num_sec_windows = num_windows; | |
416 | else | |
417 | num_sec_windows = 0; | |
418 | ||
419 | ret = pamu_config_ppaace(liodn, min_addr, | |
420 | size , -1, -1, -1, num_sec_windows); | |
421 | ||
422 | if (ret < 0) | |
423 | return ret; | |
424 | ||
425 | debug("configured ppace\n"); | |
426 | ||
427 | if (num_sec_windows) { | |
428 | subwin_size = size >> count_lsb_zeroes(num_sec_windows); | |
429 | debug("subwin_size is %llx\n", subwin_size); | |
430 | ||
431 | for (i = 0; i < num_entries; i++) { | |
432 | ret = pamu_config_spaace(liodn, | |
433 | subwin_size, tbl->start_addr[i] - min_addr, | |
434 | tbl->size[i], -1, -1, -1); | |
435 | ||
436 | if (ret < 0) | |
437 | return ret; | |
438 | } | |
439 | } | |
440 | ||
441 | return ret; | |
442 | } |