blob: ab665852c37a561af68f60b2551ab0e85d51c4a7 [file] [log] [blame]
Jacky Baief29c152023-05-25 09:34:11 +08001/*
2 * Copyright 2022-2023 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <errno.h>
9#include <stdbool.h>
10
11#include <common/bl_common.h>
12#include <common/debug.h>
13#include <drivers/nxp/trdc/imx_trdc.h>
14#include <lib/mmio.h>
15
16
17int trdc_mda_set_cpu(uintptr_t trdc_base, uint32_t mda_inst,
18 uint32_t mda_reg, uint8_t sa, uint8_t dids,
19 uint8_t did, uint8_t pe, uint8_t pidm, uint8_t pid)
20{
21 uint32_t val = mmio_read_32(trdc_base + MDAC_W_X(mda_inst, mda_reg));
22 /* invalid: config non-cpu master with cpu config format. */
23 if ((val & MDA_DFMT) != 0U) {
24 return -EINVAL;
25 }
26
27 val = MDA_VLD | MDA_DFMT0_DID(pid) | MDA_DFMT0_PIDM(pidm) | MDA_DFMT0_PE(pe) |
28 MDA_DFMT0_SA(sa) | MDA_DFMT0_DIDS(dids) | MDA_DFMT0_DID(did);
29
30 mmio_write_32(trdc_base + MDAC_W_X(mda_inst, mda_reg), val);
31
32 return 0;
33}
34
35int trdc_mda_set_noncpu(uintptr_t trdc_base, uint32_t mda_inst,
36 bool did_bypass, uint8_t sa, uint8_t pa,
37 uint8_t did)
38{
39 uint32_t val = mmio_read_32(trdc_base + MDAC_W_X(mda_inst, 0));
40
41 /* invalid: config cpu master with non-cpu config format. */
42 if ((val & MDA_DFMT) == 0U) {
43 return -EINVAL;
44 }
45
46 val = MDA_VLD | MDA_DFMT1_SA(sa) | MDA_DFMT1_PA(pa) | MDA_DFMT1_DID(did) |
47 MDA_DFMT1_DIDB(did_bypass ? 1U : 0U);
48
49 mmio_write_32(trdc_base + MDAC_W_X(mda_inst, 0), val);
50
51 return 0;
52}
53
54static uintptr_t trdc_get_mbc_base(uintptr_t trdc_reg, uint32_t mbc_x)
55{
56 struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
57 uint32_t mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
58
59 if (mbc_x >= mbc_num) {
60 return 0U;
61 }
62
63 return trdc_reg + 0x10000 + 0x2000 * mbc_x;
64}
65
66static uintptr_t trdc_get_mrc_base(uintptr_t trdc_reg, uint32_t mrc_x)
67{
68 struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
69 uint32_t mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
70 uint32_t mrc_num = MRC_NUM(trdc_base->trdc_hwcfg0);
71
72 if (mrc_x >= mrc_num) {
73 return 0U;
74 }
75
76 return trdc_reg + 0x10000 + 0x2000 * mbc_num + 0x1000 * mrc_x;
77}
78
79uint32_t trdc_mbc_blk_num(uintptr_t trdc_reg, uint32_t mbc_x, uint32_t mem_x)
80{
81 uint32_t glbcfg;
82 struct mbc_mem_dom *mbc_dom;
83 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
84
85 if (mbc_base == NULL) {
86 return 0;
87 }
88
89 /* only first dom has the glbcfg */
90 mbc_dom = &mbc_base->mem_dom[0];
91 glbcfg = mmio_read_32((uintptr_t)&mbc_dom->mem_glbcfg[mem_x]);
92
93 return MBC_BLK_NUM(glbcfg);
94}
95
96uint32_t trdc_mrc_rgn_num(uintptr_t trdc_reg, uint32_t mrc_x)
97{
98 uint32_t glbcfg;
99 struct mrc_rgn_dom *mrc_dom;
100 struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x);
101
102 if (mrc_base == NULL) {
103 return 0;
104 }
105
106 /* only first dom has the glbcfg */
107 mrc_dom = &mrc_base->mrc_dom[0];
108 glbcfg = mmio_read_32((uintptr_t)&mrc_dom->mrc_glbcfg[0]);
109
110 return MBC_BLK_NUM(glbcfg);
111}
112
113int trdc_mbc_set_control(uintptr_t trdc_reg, uint32_t mbc_x,
114 uint32_t glbac_id, uint32_t glbac_val)
115{
116 struct mbc_mem_dom *mbc_dom;
117 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
118
119 if (mbc_base == NULL || glbac_id >= GLBAC_NUM) {
120 return -EINVAL;
121 }
122
123 /* only first dom has the glbac */
124 mbc_dom = &mbc_base->mem_dom[0];
125
126 mmio_write_32((uintptr_t)&mbc_dom->memn_glbac[glbac_id], glbac_val);
127
128 return 0;
129}
130
131int trdc_mbc_blk_config(uintptr_t trdc_reg, uint32_t mbc_x,
132 uint32_t dom_x, uint32_t mem_x, uint32_t blk_x,
133 bool sec_access, uint32_t glbac_id)
134{
135 uint32_t *cfg_w;
136 uint32_t index, offset, val;
137 struct mbc_mem_dom *mbc_dom;
138 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
139
140 if (mbc_base == NULL || glbac_id >= GLBAC_NUM) {
141 return -EINVAL;
142 }
143
144 mbc_dom = &mbc_base->mem_dom[dom_x];
145
146 switch (mem_x) {
147 case 0:
148 cfg_w = &mbc_dom->mem0_blk_cfg_w[blk_x / 8];
149 break;
150 case 1:
151 cfg_w = &mbc_dom->mem1_blk_cfg_w[blk_x / 8];
152 break;
153 case 2:
154 cfg_w = &mbc_dom->mem2_blk_cfg_w[blk_x / 8];
155 break;
156 case 3:
157 cfg_w = &mbc_dom->mem3_blk_cfg_w[blk_x / 8];
158 break;
159 default:
160 return -EINVAL;
161 };
162
163 index = blk_x % 8;
164 offset = index * 4;
165
166 val = mmio_read_32((uintptr_t)cfg_w);
167 val &= ~(0xF << offset);
168
169 /*
170 * MBC0-3
171 * Global 0, 0x7777 secure pri/user read/write/execute,
172 * S400 has already set it. So select MBC0_MEMN_GLBAC0
173 */
174 if (sec_access) {
175 val |= ((0x0 | (glbac_id & 0x7)) << offset);
176 mmio_write_32((uintptr_t)cfg_w, val);
177 } else {
178 /* nse bit set */
179 val |= ((0x8 | (glbac_id & 0x7)) << offset);
180 mmio_write_32((uintptr_t)cfg_w, val);
181 }
182
183 return 0;
184}
185
186int trdc_mrc_set_control(uintptr_t trdc_reg, uint32_t mrc_x,
187 uint32_t glbac_id, uint32_t glbac_val)
188{
189 struct mrc_rgn_dom *mrc_dom;
190 struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x);
191
192 if (mrc_base == NULL || glbac_id >= GLBAC_NUM) {
193 return -EINVAL;
194 }
195
196 /* only first dom has the glbac */
197 mrc_dom = &mrc_base->mrc_dom[0];
198
199 mmio_write_32((uintptr_t)&mrc_dom->memn_glbac[glbac_id], glbac_val);
200
201 return 0;
202}
203
204int trdc_mrc_rgn_config(uintptr_t trdc_reg, uint32_t mrc_x,
205 uint32_t dom_x, uint32_t rgn_id,
206 uint32_t addr_start, uint32_t addr_size,
207 bool sec_access, uint32_t glbac_id)
208{
209 uint32_t *desc_w;
210 uint32_t addr_end;
211 struct mrc_rgn_dom *mrc_dom;
212 struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x);
213
214 if (mrc_base == NULL || glbac_id >= GLBAC_NUM || rgn_id >= MRC_REG_ALL) {
215 return -EINVAL;
216 }
217
218 mrc_dom = &mrc_base->mrc_dom[dom_x];
219
220 addr_end = addr_start + addr_size - 1;
221 addr_start &= ~0x3fff;
222 addr_end &= ~0x3fff;
223
224 desc_w = &mrc_dom->rgn_desc_words[rgn_id][0];
225
226 if (sec_access) {
227 mmio_write_32((uintptr_t)desc_w, addr_start | (glbac_id & 0x7));
228 mmio_write_32((uintptr_t)(desc_w + 1), addr_end | 0x1);
229 } else {
230 mmio_write_32((uintptr_t)desc_w, addr_start | (glbac_id & 0x7));
231 mmio_write_32((uintptr_t)(desc_w + 1), (addr_end | 0x1 | 0x10));
232 }
233
234 return 0;
235}
236
237bool trdc_mrc_enabled(uintptr_t mrc_base)
238{
239 return (mmio_read_32(mrc_base) & BIT(15));
240}
241
242bool trdc_mbc_enabled(uintptr_t mbc_base)
243{
244 return (mmio_read_32(mbc_base) & BIT(14));
245}
246
247static bool is_trdc_mgr_slot(uintptr_t trdc_base, uint8_t mbc_id,
248 uint8_t mem_id, uint16_t blk_id)
249{
250 unsigned int i;
251
252 for (i = 0U; i < trdc_mgr_num; i++) {
253 if (trdc_mgr_blks[i].trdc_base == trdc_base) {
254 if (mbc_id == trdc_mgr_blks[i].mbc_id &&
255 mem_id == trdc_mgr_blks[i].mbc_mem_id &&
256 (blk_id == trdc_mgr_blks[i].blk_mgr ||
257 blk_id == trdc_mgr_blks[i].blk_mc)) {
258 return true;
259 }
260 }
261 }
262
263 return false;
264}
265
266/*
267 * config the TRDC MGR & MC's access policy. only the secure privilege
268 * mode SW can access it.
269 */
270void trdc_mgr_mbc_setup(struct trdc_mgr_info *mgr)
271{
272 unsigned int i;
273
274 /*
275 * If the MBC is global enabled, need to cconfigure the MBCs of
276 * TRDC MGR & MC correctly.
277 */
278 if (trdc_mbc_enabled(mgr->trdc_base)) {
279 /* ONLY secure privilige can access */
280 trdc_mbc_set_control(mgr->trdc_base, mgr->mbc_id, 7, 0x6000);
281 for (i = 0U; i < 16U; i++) {
282 trdc_mbc_blk_config(mgr->trdc_base, mgr->mbc_id, i,
283 mgr->mbc_mem_id, mgr->blk_mgr, true, 7);
284
285 trdc_mbc_blk_config(mgr->trdc_base, mgr->mbc_id, i,
286 mgr->mbc_mem_id, mgr->blk_mc, true, 7);
287 }
288 }
289}
290
291/*
292 * Set up the TRDC access policy for all the resources under
293 * the TRDC control.
294 */
295void trdc_setup(struct trdc_config_info *cfg)
296{
297 unsigned int i, j, num;
298 bool is_mgr;
299
300 /* config the MRCs */
301 if (trdc_mrc_enabled(cfg->trdc_base)) {
302 /* set global access policy */
303 for (i = 0U; i < cfg->num_mrc_glbac; i++) {
304 trdc_mrc_set_control(cfg->trdc_base,
305 cfg->mrc_glbac[i].mbc_mrc_id,
306 cfg->mrc_glbac[i].glbac_id,
307 cfg->mrc_glbac[i].glbac_val);
308 }
309
310 /* set each MRC region access policy */
311 for (i = 0U; i < cfg->num_mrc_cfg; i++) {
312 trdc_mrc_rgn_config(cfg->trdc_base, cfg->mrc_cfg[i].mrc_id,
313 cfg->mrc_cfg[i].dom_id,
314 cfg->mrc_cfg[i].region_id,
315 cfg->mrc_cfg[i].region_start,
316 cfg->mrc_cfg[i].region_size,
317 cfg->mrc_cfg[i].secure,
318 cfg->mrc_cfg[i].glbac_id);
319 }
320 }
321
322 /* config the MBCs */
323 if (trdc_mbc_enabled(cfg->trdc_base)) {
324 /* set MBC global access policy */
325 for (i = 0U; i < cfg->num_mbc_glbac; i++) {
326 trdc_mbc_set_control(cfg->trdc_base,
327 cfg->mbc_glbac[i].mbc_mrc_id,
328 cfg->mbc_glbac[i].glbac_id,
329 cfg->mbc_glbac[i].glbac_val);
330 }
331
332 for (i = 0U; i < cfg->num_mbc_cfg; i++) {
333 if (cfg->mbc_cfg[i].blk_id == MBC_BLK_ALL) {
334 num = trdc_mbc_blk_num(cfg->trdc_base,
335 cfg->mbc_cfg[i].mbc_id,
336 cfg->mbc_cfg[i].mem_id);
337
338 for (j = 0U; j < num; j++) {
339 /* Skip mgr and mc */
340 is_mgr = is_trdc_mgr_slot(cfg->trdc_base,
341 cfg->mbc_cfg[i].mbc_id,
342 cfg->mbc_cfg[i].mem_id, j);
343 if (is_mgr) {
344 continue;
345 }
346
347 trdc_mbc_blk_config(cfg->trdc_base,
348 cfg->mbc_cfg[i].mbc_id,
349 cfg->mbc_cfg[i].dom_id,
350 cfg->mbc_cfg[i].mem_id, j,
351 cfg->mbc_cfg[i].secure,
352 cfg->mbc_cfg[i].glbac_id);
353 }
354 } else {
355 trdc_mbc_blk_config(cfg->trdc_base,
356 cfg->mbc_cfg[i].mbc_id,
357 cfg->mbc_cfg[i].dom_id,
358 cfg->mbc_cfg[i].mem_id,
359 cfg->mbc_cfg[i].blk_id,
360 cfg->mbc_cfg[i].secure,
361 cfg->mbc_cfg[i].glbac_id);
362 }
363 }
364 }
365}