1 /*
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 
trdc_mda_set_cpu(uintptr_t trdc_base,uint32_t mda_inst,uint32_t mda_reg,uint8_t sa,uint8_t dids,uint8_t did,uint8_t pe,uint8_t pidm,uint8_t pid)17 int 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 
trdc_mda_set_noncpu(uintptr_t trdc_base,uint32_t mda_inst,bool did_bypass,uint8_t sa,uint8_t pa,uint8_t did)35 int 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 
trdc_get_mbc_base(uintptr_t trdc_reg,uint32_t mbc_x)54 static 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 
trdc_get_mrc_base(uintptr_t trdc_reg,uint32_t mrc_x)66 static 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 
trdc_mbc_blk_num(uintptr_t trdc_reg,uint32_t mbc_x,uint32_t mem_x)79 uint32_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 
trdc_mrc_rgn_num(uintptr_t trdc_reg,uint32_t mrc_x)96 uint32_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 
trdc_mbc_set_control(uintptr_t trdc_reg,uint32_t mbc_x,uint32_t glbac_id,uint32_t glbac_val)113 int 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 
trdc_mbc_blk_config(uintptr_t trdc_reg,uint32_t mbc_x,uint32_t dom_x,uint32_t mem_x,uint32_t blk_x,bool sec_access,uint32_t glbac_id)131 int 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 
trdc_mrc_set_control(uintptr_t trdc_reg,uint32_t mrc_x,uint32_t glbac_id,uint32_t glbac_val)186 int 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 
trdc_mrc_rgn_config(uintptr_t trdc_reg,uint32_t mrc_x,uint32_t dom_x,uint32_t rgn_id,uint32_t addr_start,uint32_t addr_size,bool sec_access,uint32_t glbac_id)204 int 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 
trdc_mrc_enabled(uintptr_t mrc_base)237 bool trdc_mrc_enabled(uintptr_t mrc_base)
238 {
239 	return (mmio_read_32(mrc_base) & BIT(15));
240 }
241 
trdc_mbc_enabled(uintptr_t mbc_base)242 bool trdc_mbc_enabled(uintptr_t mbc_base)
243 {
244 	return (mmio_read_32(mbc_base) & BIT(14));
245 }
246 
is_trdc_mgr_slot(uintptr_t trdc_base,uint8_t mbc_id,uint8_t mem_id,uint16_t blk_id)247 static 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  */
trdc_mgr_mbc_setup(struct trdc_mgr_info * mgr)270 void 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  */
trdc_setup(struct trdc_config_info * cfg)295 void 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 }
366