blob: 8cdb28459a36685bf0716af6b0b7003358e064cf [file] [log] [blame]
Ye Li62185922022-07-26 16:40:54 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022 NXP
4 */
5
Ye Li62185922022-07-26 16:40:54 +08006#include <log.h>
Tom Rinidec7ea02024-05-20 13:35:03 -06007#include <linux/errno.h>
Ye Li62185922022-07-26 16:40:54 +08008#include <asm/io.h>
9#include <asm/types.h>
10#include <asm/arch/imx-regs.h>
11#include <asm/arch/sys_proto.h>
12#include <div64.h>
Peng Fand5c31832023-06-15 18:09:05 +080013#include <asm/mach-imx/ele_api.h>
Ye Li62185922022-07-26 16:40:54 +080014#include <asm/mach-imx/mu_hal.h>
15
16#define DID_NUM 16
17#define MBC_MAX_NUM 4
18#define MRC_MAX_NUM 2
19#define MBC_NUM(HWCFG) (((HWCFG) >> 16) & 0xF)
20#define MRC_NUM(HWCFG) (((HWCFG) >> 24) & 0x1F)
21
22struct mbc_mem_dom {
23 u32 mem_glbcfg[4];
24 u32 nse_blk_index;
25 u32 nse_blk_set;
26 u32 nse_blk_clr;
27 u32 nsr_blk_clr_all;
28 u32 memn_glbac[8];
29 /* The upper only existed in the beginning of each MBC */
30 u32 mem0_blk_cfg_w[64];
31 u32 mem0_blk_nse_w[16];
32 u32 mem1_blk_cfg_w[8];
33 u32 mem1_blk_nse_w[2];
34 u32 mem2_blk_cfg_w[8];
35 u32 mem2_blk_nse_w[2];
36 u32 mem3_blk_cfg_w[8];
37 u32 mem3_blk_nse_w[2];/*0x1F0, 0x1F4 */
38 u32 reserved[2];
39};
40
41struct mrc_rgn_dom {
42 u32 mrc_glbcfg[4];
43 u32 nse_rgn_indirect;
44 u32 nse_rgn_set;
45 u32 nse_rgn_clr;
46 u32 nse_rgn_clr_all;
47 u32 memn_glbac[8];
48 /* The upper only existed in the beginning of each MRC */
49 u32 rgn_desc_words[16][2]; /* 16 regions at max, 2 words per region */
50 u32 rgn_nse;
51 u32 reserved2[15];
52};
53
54struct mda_inst {
55 u32 mda_w[8];
56};
57
58struct trdc_mgr {
59 u32 trdc_cr;
60 u32 res0[59];
61 u32 trdc_hwcfg0;
62 u32 trdc_hwcfg1;
63 u32 res1[450];
64 struct mda_inst mda[8];
65 u32 res2[15808];
66};
67
68struct trdc_mbc {
69 struct mbc_mem_dom mem_dom[DID_NUM];
70};
71
72struct trdc_mrc {
73 struct mrc_rgn_dom mrc_dom[DID_NUM];
74};
75
76int trdc_mda_set_cpu(ulong trdc_reg, u32 mda_inst, u32 mda_reg, u8 sa, u8 dids,
77 u8 did, u8 pe, u8 pidm, u8 pid)
78{
79 struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
80 u32 *mda_w = &trdc_base->mda[mda_inst].mda_w[mda_reg];
81 u32 val = readl(mda_w);
82
83 if (val & BIT(29)) /* non-cpu */
84 return -EINVAL;
85
86 val = BIT(31) | ((pid & 0x3f) << 16) | ((pidm & 0x3f) << 8) |
87 ((pe & 0x3) << 6) | ((sa & 0x3) << 14) | ((dids & 0x3) << 4) |
88 (did & 0xf);
89
90 writel(val, mda_w);
91
92 return 0;
93}
94
95int trdc_mda_set_noncpu(ulong trdc_reg, u32 mda_inst, u32 mda_reg,
96 bool did_bypass, u8 sa, u8 pa, u8 did)
97{
98 struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
99 u32 *mda_w = &trdc_base->mda[mda_inst].mda_w[mda_reg];
100 u32 val = readl(mda_w);
101
102 if (!(val & BIT(29))) /* cpu */
103 return -EINVAL;
104
105 val = BIT(31) | ((sa & 0x3) << 6) | ((pa & 0x3) << 4) | (did & 0xf);
106 if (did_bypass)
107 val |= BIT(8);
108
109 writel(val, mda_w);
110
111 return 0;
112}
113
114static ulong trdc_get_mbc_base(ulong trdc_reg, u32 mbc_x)
115{
116 struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
117 u32 mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
118
119 if (mbc_x >= mbc_num)
120 return 0;
121
122 return trdc_reg + 0x10000 + 0x2000 * mbc_x;
123}
124
125static ulong trdc_get_mrc_base(ulong trdc_reg, u32 mrc_x)
126{
127 struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
128 u32 mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
129 u32 mrc_num = MRC_NUM(trdc_base->trdc_hwcfg0);
130
131 if (mrc_x >= mrc_num)
132 return 0;
133
134 return trdc_reg + 0x10000 + 0x2000 * mbc_num + 0x1000 * mrc_x;
135}
136
137int trdc_mbc_set_control(ulong trdc_reg, u32 mbc_x, u32 glbac_id, u32 glbac_val)
138{
139 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
140 struct mbc_mem_dom *mbc_dom;
141
142 if (mbc_base == 0 || glbac_id >= 8)
143 return -EINVAL;
144
145 /* only first dom has the glbac */
146 mbc_dom = &mbc_base->mem_dom[0];
147
148 debug("mbc 0x%lx\n", (ulong)mbc_dom);
149
150 writel(glbac_val, &mbc_dom->memn_glbac[glbac_id]);
151
152 return 0;
153}
154
155int trdc_mbc_blk_config(ulong trdc_reg, u32 mbc_x, u32 dom_x, u32 mem_x,
156 u32 blk_x, bool sec_access, u32 glbac_id)
157{
158 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
159 struct mbc_mem_dom *mbc_dom;
160 u32 *cfg_w, *nse_w;
161 u32 index, offset, val;
162
163 if (mbc_base == 0 || glbac_id >= 8)
164 return -EINVAL;
165
166 mbc_dom = &mbc_base->mem_dom[dom_x];
167
168 debug("mbc 0x%lx\n", (ulong)mbc_dom);
169
170 switch (mem_x) {
171 case 0:
172 cfg_w = &mbc_dom->mem0_blk_cfg_w[blk_x / 8];
173 nse_w = &mbc_dom->mem0_blk_nse_w[blk_x / 32];
174 break;
175 case 1:
176 cfg_w = &mbc_dom->mem1_blk_cfg_w[blk_x / 8];
177 nse_w = &mbc_dom->mem1_blk_nse_w[blk_x / 32];
178 break;
179 case 2:
180 cfg_w = &mbc_dom->mem2_blk_cfg_w[blk_x / 8];
181 nse_w = &mbc_dom->mem2_blk_nse_w[blk_x / 32];
182 break;
183 case 3:
184 cfg_w = &mbc_dom->mem3_blk_cfg_w[blk_x / 8];
185 nse_w = &mbc_dom->mem3_blk_nse_w[blk_x / 32];
186 break;
187 default:
188 return -EINVAL;
189 };
190
191 index = blk_x % 8;
192 offset = index * 4;
193
194 val = readl((void __iomem *)cfg_w);
195
196 val &= ~(0xFU << offset);
197
198 /* MBC0-3
Peng Fand5c31832023-06-15 18:09:05 +0800199 * Global 0, 0x7777 secure pri/user read/write/execute, ELE has already set it.
Ye Li62185922022-07-26 16:40:54 +0800200 * So select MBC0_MEMN_GLBAC0
201 */
202 if (sec_access) {
203 val |= ((0x0 | (glbac_id & 0x7)) << offset);
204 writel(val, (void __iomem *)cfg_w);
205 } else {
206 val |= ((0x8 | (glbac_id & 0x7)) << offset); /* nse bit set */
207 writel(val, (void __iomem *)cfg_w);
208 }
209
210 return 0;
211}
212
213int trdc_mrc_set_control(ulong trdc_reg, u32 mrc_x, u32 glbac_id, u32 glbac_val)
214{
215 struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x);
216 struct mrc_rgn_dom *mrc_dom;
217
218 if (mrc_base == 0 || glbac_id >= 8)
219 return -EINVAL;
220
221 /* only first dom has the glbac */
222 mrc_dom = &mrc_base->mrc_dom[0];
223
224 debug("mrc_dom 0x%lx\n", (ulong)mrc_dom);
225
226 writel(glbac_val, &mrc_dom->memn_glbac[glbac_id]);
227
228 return 0;
229}
230
231int trdc_mrc_region_config(ulong trdc_reg, u32 mrc_x, u32 dom_x, u32 addr_start,
232 u32 addr_end, bool sec_access, u32 glbac_id)
233{
234 struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x);
235 struct mrc_rgn_dom *mrc_dom;
236 u32 *desc_w;
237 u32 start, end;
238 u32 i, free = 8;
239 bool vld, hit = false;
240
241 if (mrc_base == 0 || glbac_id >= 8)
242 return -EINVAL;
243
244 mrc_dom = &mrc_base->mrc_dom[dom_x];
245
246 addr_start &= ~0x3fff;
247 addr_end &= ~0x3fff;
248
249 debug("mrc_dom 0x%lx\n", (ulong)mrc_dom);
250
251 for (i = 0; i < 8; i++) {
252 desc_w = &mrc_dom->rgn_desc_words[i][0];
253
254 debug("desc_w 0x%lx\n", (ulong)desc_w);
255
256 start = readl((void __iomem *)desc_w) & (~0x3fff);
257 end = readl((void __iomem *)(desc_w + 1));
258 vld = end & 0x1;
259 end = end & (~0x3fff);
260
261 if (start == 0 && end == 0 && !vld && free >= 8)
262 free = i;
263
264 /* Check all the region descriptors, even overlap */
265 if (addr_start >= end || addr_end <= start || !vld)
266 continue;
267
268 /* MRC0,1
Peng Fand5c31832023-06-15 18:09:05 +0800269 * Global 0, 0x7777 secure pri/user read/write/execute, ELE has already set it.
Ye Li62185922022-07-26 16:40:54 +0800270 * So select MRCx_MEMN_GLBAC0
271 */
272 if (sec_access) {
273 writel(start | (glbac_id & 0x7), (void __iomem *)desc_w);
274 writel(end | 0x1, (void __iomem *)(desc_w + 1));
275 } else {
276 writel(start | (glbac_id & 0x7), (void __iomem *)desc_w);
277 writel(end | 0x1 | 0x10, (void __iomem *)(desc_w + 1));
278 }
279
280 if (addr_start >= start && addr_end <= end)
281 hit = true;
282 }
283
284 if (!hit) {
285 if (free >= 8)
286 return -EFAULT;
287
288 desc_w = &mrc_dom->rgn_desc_words[free][0];
289
290 debug("free desc_w 0x%lx\n", (ulong)desc_w);
291 debug("[0x%x] [0x%x]\n", addr_start | (glbac_id & 0x7), addr_end | 0x1);
292
293 if (sec_access) {
294 writel(addr_start | (glbac_id & 0x7), (void __iomem *)desc_w);
295 writel(addr_end | 0x1, (void __iomem *)(desc_w + 1));
296 } else {
297 writel(addr_start | (glbac_id & 0x7), (void __iomem *)desc_w);
298 writel((addr_end | 0x1 | 0x10), (void __iomem *)(desc_w + 1));
299 }
300 }
301
302 return 0;
303}
304
305bool trdc_mrc_enabled(ulong trdc_base)
306{
307 return (!!(readl((void __iomem *)trdc_base) & 0x8000));
308}
309
310bool trdc_mbc_enabled(ulong trdc_base)
311{
312 return (!!(readl((void __iomem *)trdc_base) & 0x4000));
313}
314
315int release_rdc(u8 xrdc)
316{
317 ulong s_mu_base = 0x47520000UL;
Peng Fand5c31832023-06-15 18:09:05 +0800318 struct ele_msg msg;
Ye Li62185922022-07-26 16:40:54 +0800319 int ret;
320 u32 rdc_id;
321
322 switch (xrdc) {
323 case 0:
324 rdc_id = 0x74;
325 break;
326 case 1:
327 rdc_id = 0x78;
328 break;
329 case 2:
330 rdc_id = 0x82;
331 break;
332 case 3:
333 rdc_id = 0x86;
334 break;
335 default:
336 return -EINVAL;
337 }
338
Peng Fand5c31832023-06-15 18:09:05 +0800339 msg.version = ELE_VERSION;
340 msg.tag = ELE_CMD_TAG;
Ye Li62185922022-07-26 16:40:54 +0800341 msg.size = 2;
Ye Liebb2be52023-01-30 18:39:53 +0800342 msg.command = ELE_RELEASE_RDC_REQ;
Ye Li62185922022-07-26 16:40:54 +0800343 msg.data[0] = (rdc_id << 8) | 0x2; /* A55 */
344
345 mu_hal_init(s_mu_base);
346 mu_hal_sendmsg(s_mu_base, 0, *((u32 *)&msg));
347 mu_hal_sendmsg(s_mu_base, 1, msg.data[0]);
348
349 ret = mu_hal_receivemsg(s_mu_base, 0, (u32 *)&msg);
350 if (!ret) {
351 ret = mu_hal_receivemsg(s_mu_base, 1, &msg.data[0]);
352 if (!ret) {
353 if ((msg.data[0] & 0xff) == 0xd6)
354 return 0;
355 }
356
357 return -EIO;
358 }
359
360 return ret;
361}
362
363void trdc_early_init(void)
364{
365 int ret = 0, i;
366
367 ret |= release_rdc(0);
368 ret |= release_rdc(2);
369 ret |= release_rdc(1);
370 ret |= release_rdc(3);
371
372 if (!ret) {
373 /* Set OCRAM to RWX for secure, when OEM_CLOSE, the image is RX only */
374 trdc_mbc_set_control(0x49010000, 3, 0, 0x7700);
375
376 for (i = 0; i < 40; i++)
377 trdc_mbc_blk_config(0x49010000, 3, 3, 0, i, true, 0);
378
379 for (i = 0; i < 40; i++)
380 trdc_mbc_blk_config(0x49010000, 3, 3, 1, i, true, 0);
381
382 for (i = 0; i < 40; i++)
383 trdc_mbc_blk_config(0x49010000, 3, 0, 0, i, true, 0);
384
385 for (i = 0; i < 40; i++)
386 trdc_mbc_blk_config(0x49010000, 3, 0, 1, i, true, 0);
387 }
388}
389
390void trdc_init(void)
391{
392 /* TRDC mega */
393 if (trdc_mrc_enabled(0x49010000)) {
394 /* DDR */
395 trdc_mrc_set_control(0x49010000, 0, 0, 0x7777);
396
Peng Fand5c31832023-06-15 18:09:05 +0800397 /* ELE */
Ye Li62185922022-07-26 16:40:54 +0800398 trdc_mrc_region_config(0x49010000, 0, 0, 0x80000000, 0xFFFFFFFF, false, 0);
399
400 /* MTR */
401 trdc_mrc_region_config(0x49010000, 0, 1, 0x80000000, 0xFFFFFFFF, false, 0);
402
403 /* M33 */
404 trdc_mrc_region_config(0x49010000, 0, 2, 0x80000000, 0xFFFFFFFF, false, 0);
405
406 /* A55*/
407 trdc_mrc_region_config(0x49010000, 0, 3, 0x80000000, 0xFFFFFFFF, false, 0);
408
409 /* For USDHC1 to DDR, USDHC1 is default force to non-secure */
410 trdc_mrc_region_config(0x49010000, 0, 5, 0x80000000, 0xFFFFFFFF, false, 0);
411
412 /* For USDHC2 to DDR, USDHC2 is default force to non-secure */
413 trdc_mrc_region_config(0x49010000, 0, 6, 0x80000000, 0xFFFFFFFF, false, 0);
414
415 /* eDMA */
416 trdc_mrc_region_config(0x49010000, 0, 7, 0x80000000, 0xFFFFFFFF, false, 0);
417
418 /*CoreSight, TestPort*/
419 trdc_mrc_region_config(0x49010000, 0, 8, 0x80000000, 0xFFFFFFFF, false, 0);
420
421 /* DAP */
422 trdc_mrc_region_config(0x49010000, 0, 9, 0x80000000, 0xFFFFFFFF, false, 0);
423
424 /*SoC masters */
425 trdc_mrc_region_config(0x49010000, 0, 10, 0x80000000, 0xFFFFFFFF, false, 0);
426
427 /*USB*/
428 trdc_mrc_region_config(0x49010000, 0, 11, 0x80000000, 0xFFFFFFFF, false, 0);
429 }
430}
431
432#if DEBUG
433int trdc_mbc_control_dump(ulong trdc_reg, u32 mbc_x, u32 glbac_id)
434{
435 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
436 struct mbc_mem_dom *mbc_dom;
437
438 if (mbc_base == 0 || glbac_id >= 8)
439 return -EINVAL;
440
441 /* only first dom has the glbac */
442 mbc_dom = &mbc_base->mem_dom[0];
443
444 printf("mbc_dom %u glbac %u: 0x%x\n",
445 mbc_x, glbac_id, readl(&mbc_dom->memn_glbac[glbac_id]));
446
447 return 0;
448}
449
450int trdc_mbc_mem_dump(ulong trdc_reg, u32 mbc_x, u32 dom_x, u32 mem_x, u32 word)
451{
452 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
453 struct mbc_mem_dom *mbc_dom;
454 u32 *cfg_w;
455
456 if (mbc_base == 0)
457 return -EINVAL;
458
459 mbc_dom = &mbc_base->mem_dom[dom_x];
460
461 switch (mem_x) {
462 case 0:
463 cfg_w = &mbc_dom->mem0_blk_cfg_w[word];
464 break;
465 case 1:
466 cfg_w = &mbc_dom->mem1_blk_cfg_w[word];
467 break;
468 case 2:
469 cfg_w = &mbc_dom->mem2_blk_cfg_w[word];
470 break;
471 case 3:
472 cfg_w = &mbc_dom->mem3_blk_cfg_w[word];
473 break;
474 default:
475 return -EINVAL;
476 };
477
478 printf("mbc_dom %u dom %u mem %u word %u: 0x%x\n",
479 mbc_x, dom_x, mem_x, word, readl((void __iomem *)cfg_w));
480
481 return 0;
482}
483
484int trdc_mrc_control_dump(ulong trdc_reg, u32 mrc_x, u32 glbac_id)
485{
486 struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x);
487 struct mrc_rgn_dom *mrc_dom;
488
489 if (mrc_base == 0 || glbac_id >= 8)
490 return -EINVAL;
491
492 /* only first dom has the glbac */
493 mrc_dom = &mrc_base->mrc_dom[0];
494
495 printf("mrc_dom %u glbac %u: 0x%x\n",
496 mrc_x, glbac_id, readl(&mrc_dom->memn_glbac[glbac_id]));
497
498 return 0;
499}
500
501void trdc_dump(void)
502{
503 u32 i;
504
505 printf("TRDC AONMIX MBC\n");
506
507 trdc_mbc_control_dump(0x44270000, 0, 0);
508 trdc_mbc_control_dump(0x44270000, 1, 0);
509
510 for (i = 0; i < 11; i++)
511 trdc_mbc_mem_dump(0x44270000, 0, 3, 0, i);
512 for (i = 0; i < 1; i++)
513 trdc_mbc_mem_dump(0x44270000, 0, 3, 1, i);
514
515 for (i = 0; i < 4; i++)
516 trdc_mbc_mem_dump(0x44270000, 1, 3, 0, i);
517 for (i = 0; i < 4; i++)
518 trdc_mbc_mem_dump(0x44270000, 1, 3, 1, i);
519
520 printf("TRDC WAKEUP MBC\n");
521
522 trdc_mbc_control_dump(0x42460000, 0, 0);
523 trdc_mbc_control_dump(0x42460000, 1, 0);
524
525 for (i = 0; i < 15; i++)
526 trdc_mbc_mem_dump(0x42460000, 0, 3, 0, i);
527
528 trdc_mbc_mem_dump(0x42460000, 0, 3, 1, 0);
529 trdc_mbc_mem_dump(0x42460000, 0, 3, 2, 0);
530
531 for (i = 0; i < 2; i++)
532 trdc_mbc_mem_dump(0x42460000, 1, 3, 0, i);
533
534 trdc_mbc_mem_dump(0x42460000, 1, 3, 1, 0);
535 trdc_mbc_mem_dump(0x42460000, 1, 3, 2, 0);
536 trdc_mbc_mem_dump(0x42460000, 1, 3, 3, 0);
537
538 printf("TRDC NICMIX MBC\n");
539
540 trdc_mbc_control_dump(0x49010000, 0, 0);
541 trdc_mbc_control_dump(0x49010000, 1, 0);
542 trdc_mbc_control_dump(0x49010000, 2, 0);
543 trdc_mbc_control_dump(0x49010000, 3, 0);
544
545 for (i = 0; i < 7; i++)
546 trdc_mbc_mem_dump(0x49010000, 0, 3, 0, i);
547
548 for (i = 0; i < 2; i++)
549 trdc_mbc_mem_dump(0x49010000, 0, 3, 1, i);
550
551 for (i = 0; i < 5; i++)
552 trdc_mbc_mem_dump(0x49010000, 0, 3, 2, i);
553
554 for (i = 0; i < 6; i++)
555 trdc_mbc_mem_dump(0x49010000, 0, 3, 3, i);
556
557 for (i = 0; i < 1; i++)
558 trdc_mbc_mem_dump(0x49010000, 1, 3, 0, i);
559
560 for (i = 0; i < 1; i++)
561 trdc_mbc_mem_dump(0x49010000, 1, 3, 1, i);
562
563 for (i = 0; i < 3; i++)
564 trdc_mbc_mem_dump(0x49010000, 1, 3, 2, i);
565
566 for (i = 0; i < 3; i++)
567 trdc_mbc_mem_dump(0x49010000, 1, 3, 3, i);
568
569 for (i = 0; i < 2; i++)
570 trdc_mbc_mem_dump(0x49010000, 2, 3, 0, i);
571
572 for (i = 0; i < 2; i++)
573 trdc_mbc_mem_dump(0x49010000, 2, 3, 1, i);
574
575 for (i = 0; i < 5; i++)
576 trdc_mbc_mem_dump(0x49010000, 3, 3, 0, i);
577
578 for (i = 0; i < 5; i++)
579 trdc_mbc_mem_dump(0x49010000, 3, 3, 1, i);
580}
581#endif