1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2021 NXP
4  */
5 
6 #include <common.h>
7 #include <asm/io.h>
8 #include <asm/types.h>
9 #include <asm/arch/imx-regs.h>
10 #include <asm/arch/sys_proto.h>
11 #include <asm/arch/mu_hal.h>
12 #include <asm/arch/s400_api.h>
13 #include <asm/arch/rdc.h>
14 #include <div64.h>
15 
16 #define XRDC_ADDR	0x292f0000
17 #define MRC_OFFSET	0x2000
18 #define MRC_STEP	0x200
19 
20 #define SP(X)		((X) << 9)
21 #define SU(X)		((X) << 6)
22 #define NP(X)		((X) << 3)
23 #define NU(X)		((X) << 0)
24 
25 #define RWX		7
26 #define RW		6
27 #define R		4
28 #define X		1
29 
30 #define D7SEL_CODE	(SP(RW) | SU(RW) | NP(RWX) | NU(RWX))
31 #define D6SEL_CODE	(SP(RW) | SU(RW) | NP(RWX))
32 #define D5SEL_CODE	(SP(RW) | SU(RWX))
33 #define D4SEL_CODE	SP(RWX)
34 #define D3SEL_CODE	(SP(X) | SU(X) | NP(X) | NU(X))
35 #define D0SEL_CODE	0
36 
37 #define D7SEL_DAT	(SP(RW) | SU(RW) | NP(RW) | NU(RW))
38 #define D6SEL_DAT	(SP(RW) | SU(RW) | NP(RW))
39 #define D5SEL_DAT	(SP(RW) | SU(RW) | NP(R) | NU(R))
40 #define D4SEL_DAT	(SP(RW) | SU(RW))
41 #define D3SEL_DAT	SP(RW)
42 
43 struct mbc_mem_dom {
44 	u32 mem_glbcfg[4];
45 	u32 nse_blk_index;
46 	u32 nse_blk_set;
47 	u32 nse_blk_clr;
48 	u32 nsr_blk_clr_all;
49 	u32 memn_glbac[8];
50 	/* The upper only existed in the beginning of each MBC */
51 	u32 mem0_blk_cfg_w[64];
52 	u32 mem0_blk_nse_w[16];
53 	u32 mem1_blk_cfg_w[8];
54 	u32 mem1_blk_nse_w[2];
55 	u32 mem2_blk_cfg_w[8];
56 	u32 mem2_blk_nse_w[2];
57 	u32 mem3_blk_cfg_w[8];
58 	u32 mem3_blk_nse_w[2];/*0x1F0, 0x1F4 */
59 	u32 reserved[2];
60 };
61 
62 struct mrc_rgn_dom {
63 	u32 mrc_glbcfg[4];
64 	u32 nse_rgn_indirect;
65 	u32 nse_rgn_set;
66 	u32 nse_rgn_clr;
67 	u32 nse_rgn_clr_all;
68 	u32 memn_glbac[8];
69 	/* The upper only existed in the beginning of each MRC */
70 	u32 rgn_desc_words[8][2]; /* 8 regions, 2 words per region */
71 	u32 reserved[16];
72 	u32	rgn_nse;
73 	u32 reserved2[15];
74 };
75 
76 struct trdc {
77 	u8 res0[0x1000];
78 	struct mbc_mem_dom mem_dom[4][8];
79 	struct mrc_rgn_dom mrc_dom[2][8];
80 };
81 
82 union dxsel_perm {
83 	struct {
84 		u8 dx;
85 		u8 perm;
86 	};
87 
88 	u32 dom_perm;
89 };
90 
xrdc_config_mrc_dx_perm(u32 mrc_con,u32 region,u32 dom,u32 dxsel)91 int xrdc_config_mrc_dx_perm(u32 mrc_con, u32 region, u32 dom, u32 dxsel)
92 {
93 	ulong w2_addr;
94 	u32 val = 0;
95 
96 	w2_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0x8;
97 
98 	val = (readl(w2_addr) & (~(7 << (3 * dom)))) | (dxsel << (3 * dom));
99 	writel(val, w2_addr);
100 
101 	return 0;
102 }
103 
xrdc_config_mrc_w0_w1(u32 mrc_con,u32 region,u32 w0,u32 size)104 int xrdc_config_mrc_w0_w1(u32 mrc_con, u32 region, u32 w0, u32 size)
105 {
106 	ulong w0_addr, w1_addr;
107 
108 	w0_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20;
109 	w1_addr = w0_addr + 4;
110 
111 	if ((size % 32) != 0)
112 		return -EINVAL;
113 
114 	writel(w0 & ~0x1f, w0_addr);
115 	writel(w0 + size - 1, w1_addr);
116 
117 	return 0;
118 }
119 
xrdc_config_mrc_w3_w4(u32 mrc_con,u32 region,u32 w3,u32 w4)120 int xrdc_config_mrc_w3_w4(u32 mrc_con, u32 region, u32 w3, u32 w4)
121 {
122 	ulong w3_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0xC;
123 	ulong w4_addr = w3_addr + 4;
124 
125 	writel(w3, w3_addr);
126 	writel(w4, w4_addr);
127 
128 	return 0;
129 }
130 
xrdc_config_pdac_openacc(u32 bridge,u32 index)131 int xrdc_config_pdac_openacc(u32 bridge, u32 index)
132 {
133 	ulong w0_addr;
134 	u32 val;
135 
136 	switch (bridge) {
137 	case 3:
138 		w0_addr = XRDC_ADDR + 0x1000 + 0x8 * index;
139 		break;
140 	case 4:
141 		w0_addr = XRDC_ADDR + 0x1400 + 0x8 * index;
142 		break;
143 	case 5:
144 		w0_addr = XRDC_ADDR + 0x1800 + 0x8 * index;
145 		break;
146 	default:
147 		return -EINVAL;
148 	}
149 	writel(0xffffff, w0_addr);
150 
151 	val = readl(w0_addr + 4);
152 	writel(val | BIT(31), w0_addr + 4);
153 
154 	return 0;
155 }
156 
xrdc_config_pdac(u32 bridge,u32 index,u32 dom,u32 perm)157 int xrdc_config_pdac(u32 bridge, u32 index, u32 dom, u32 perm)
158 {
159 	ulong w0_addr;
160 	u32 val;
161 
162 	switch (bridge) {
163 	case 3:
164 		w0_addr = XRDC_ADDR + 0x1000 + 0x8 * index;
165 		break;
166 	case 4:
167 		w0_addr = XRDC_ADDR + 0x1400 + 0x8 * index;
168 		break;
169 	case 5:
170 		w0_addr = XRDC_ADDR + 0x1800 + 0x8 * index;
171 		break;
172 	default:
173 		return -EINVAL;
174 	}
175 	val = readl(w0_addr);
176 	writel((val & ~(0x7 << (dom * 3))) | (perm << (dom * 3)), w0_addr);
177 
178 	val = readl(w0_addr + 4);
179 	writel(val | BIT(31), w0_addr + 4);
180 
181 	return 0;
182 }
183 
release_rdc(enum rdc_type type)184 int release_rdc(enum rdc_type type)
185 {
186 	ulong s_mu_base = 0x27020000UL;
187 	struct imx8ulp_s400_msg msg;
188 	int ret;
189 	u32 rdc_id = (type == RDC_XRDC) ? 0x78 : 0x74;
190 
191 	msg.version = AHAB_VERSION;
192 	msg.tag = AHAB_CMD_TAG;
193 	msg.size = 2;
194 	msg.command = AHAB_RELEASE_RDC_REQ_CID;
195 	msg.data[0] = (rdc_id << 8) | 0x2; /* A35 XRDC */
196 
197 	mu_hal_init(s_mu_base);
198 	mu_hal_sendmsg(s_mu_base, 0, *((u32 *)&msg));
199 	mu_hal_sendmsg(s_mu_base, 1, msg.data[0]);
200 
201 	ret = mu_hal_receivemsg(s_mu_base, 0, (u32 *)&msg);
202 	if (!ret) {
203 		ret = mu_hal_receivemsg(s_mu_base, 1, &msg.data[0]);
204 		if (!ret) {
205 			if ((msg.data[0] & 0xff) == 0xd6)
206 				return 0;
207 		}
208 
209 		return -EIO;
210 	}
211 
212 	return ret;
213 }
214 
xrdc_mrc_region_set_access(int mrc_index,u32 addr,u32 access)215 void xrdc_mrc_region_set_access(int mrc_index, u32 addr, u32 access)
216 {
217 	ulong xrdc_base = 0x292f0000, off;
218 	u32 mrgd[5];
219 	u8 mrcfg, j, region_num;
220 	u8 dsel;
221 
222 	mrcfg = readb(xrdc_base + 0x140 + mrc_index);
223 	region_num = mrcfg & 0x1f;
224 
225 	for (j = 0; j < region_num; j++) {
226 		off = 0x2000 + mrc_index * 0x200 + j * 0x20;
227 
228 		mrgd[0] = readl(xrdc_base + off);
229 		mrgd[1] = readl(xrdc_base + off + 4);
230 		mrgd[2] = readl(xrdc_base + off + 8);
231 		mrgd[3] = readl(xrdc_base + off + 0xc);
232 		mrgd[4] = readl(xrdc_base + off + 0x10);
233 
234 		debug("MRC [%u][%u]\n", mrc_index, j);
235 		debug("0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
236 		      mrgd[0], mrgd[1], mrgd[2], mrgd[3], mrgd[4]);
237 
238 		/* hit */
239 		if (addr >= mrgd[0] && addr <= mrgd[1]) {
240 			/* find domain 7 DSEL */
241 			dsel = (mrgd[2] >> 21) & 0x7;
242 			if (dsel == 1) {
243 				mrgd[4] &= ~0xFFF;
244 				mrgd[4] |= (access & 0xFFF);
245 			} else if (dsel == 2) {
246 				mrgd[4] &= ~0xFFF0000;
247 				mrgd[4] |= ((access & 0xFFF) << 16);
248 			}
249 
250 			/* not handle other cases, since S400 only set ACCESS1 and 2 */
251 			writel(mrgd[4], xrdc_base + off + 0x10);
252 			return;
253 		}
254 	}
255 }
256 
xrdc_init_mda(void)257 void xrdc_init_mda(void)
258 {
259 	ulong xrdc_base = XRDC_ADDR, off;
260 	u32 i = 0;
261 
262 	/* Set MDA3-5 for PXP, ENET, CAAM to DID 1*/
263 	for (i = 3; i <= 5; i++) {
264 		off = 0x800 + i * 0x20;
265 		writel(0x200000A1, xrdc_base + off);
266 		writel(0xA00000A1, xrdc_base + off);
267 	}
268 
269 	/* Set MDA10 -15 to DID 3 for video */
270 	for (i = 10; i <= 15; i++) {
271 		off = 0x800 + i * 0x20;
272 		writel(0x200000A3, xrdc_base + off);
273 		writel(0xA00000A3, xrdc_base + off);
274 	}
275 }
276 
xrdc_init_mrc(void)277 void xrdc_init_mrc(void)
278 {
279 	/* The MRC8 is for SRAM1 */
280 	xrdc_config_mrc_w0_w1(8, 0, 0x21000000, 0x10000);
281 	/* Allow for all domains: So domain 2/3 (HIFI DSP/LPAV) is ok to access */
282 	xrdc_config_mrc_dx_perm(8, 0, 0, 1);
283 	xrdc_config_mrc_dx_perm(8, 0, 1, 1);
284 	xrdc_config_mrc_dx_perm(8, 0, 2, 1);
285 	xrdc_config_mrc_dx_perm(8, 0, 3, 1);
286 	xrdc_config_mrc_dx_perm(8, 0, 4, 1);
287 	xrdc_config_mrc_dx_perm(8, 0, 5, 1);
288 	xrdc_config_mrc_dx_perm(8, 0, 6, 1);
289 	xrdc_config_mrc_dx_perm(8, 0, 7, 1);
290 	xrdc_config_mrc_w3_w4(8, 0, 0x0, 0x80000FFF);
291 
292 	/* The MRC6 is for video modules to ddr */
293 	xrdc_config_mrc_w0_w1(6, 0, 0x80000000, 0x80000000);
294 	xrdc_config_mrc_dx_perm(6, 0, 3, 1); /* allow for domain 3 video */
295 	xrdc_config_mrc_w3_w4(6, 0, 0x0, 0x80000FFF);
296 }
297 
trdc_mbc_set_access(u32 mbc_x,u32 dom_x,u32 mem_x,u32 blk_x,bool sec_access)298 int trdc_mbc_set_access(u32 mbc_x, u32 dom_x, u32 mem_x, u32 blk_x, bool sec_access)
299 {
300 	struct trdc *trdc_base = (struct trdc *)0x28031000U;
301 	struct mbc_mem_dom *mbc_dom;
302 	u32 *cfg_w, *nse_w;
303 	u32 index, offset, val;
304 
305 	mbc_dom = &trdc_base->mem_dom[mbc_x][dom_x];
306 
307 	switch (mem_x) {
308 	case 0:
309 		cfg_w = &mbc_dom->mem0_blk_cfg_w[blk_x / 8];
310 		nse_w = &mbc_dom->mem0_blk_nse_w[blk_x / 32];
311 		break;
312 	case 1:
313 		cfg_w = &mbc_dom->mem1_blk_cfg_w[blk_x / 8];
314 		nse_w = &mbc_dom->mem1_blk_nse_w[blk_x / 32];
315 		break;
316 	case 2:
317 		cfg_w = &mbc_dom->mem2_blk_cfg_w[blk_x / 8];
318 		nse_w = &mbc_dom->mem2_blk_nse_w[blk_x / 32];
319 		break;
320 	case 3:
321 		cfg_w = &mbc_dom->mem3_blk_cfg_w[blk_x / 8];
322 		nse_w = &mbc_dom->mem3_blk_nse_w[blk_x / 32];
323 		break;
324 	default:
325 		return -EINVAL;
326 	};
327 
328 	index = blk_x % 8;
329 	offset = index * 4;
330 
331 	val = readl((void __iomem *)cfg_w);
332 
333 	val &= ~(0xFU << offset);
334 
335 	/* MBC0-3
336 	 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
337 	 *  So select MBC0_MEMN_GLBAC0
338 	 */
339 	if (sec_access) {
340 		val |= (0x0 << offset);
341 		writel(val, (void __iomem *)cfg_w);
342 	} else {
343 		val |= (0x8 << offset); /* nse bit set */
344 		writel(val, (void __iomem *)cfg_w);
345 	}
346 
347 	return 0;
348 }
349 
trdc_mrc_region_set_access(u32 mrc_x,u32 dom_x,u32 addr_start,u32 addr_end,bool sec_access)350 int trdc_mrc_region_set_access(u32 mrc_x, u32 dom_x, u32 addr_start, u32 addr_end, bool sec_access)
351 {
352 	struct trdc *trdc_base = (struct trdc *)0x28031000U;
353 	struct mrc_rgn_dom *mrc_dom;
354 	u32 *desc_w;
355 	u32 start, end;
356 	u32 i, free = 8;
357 	bool vld, hit = false;
358 
359 	mrc_dom = &trdc_base->mrc_dom[mrc_x][dom_x];
360 
361 	for (i = 0; i < 8; i++) {
362 		desc_w = &mrc_dom->rgn_desc_words[i][0];
363 
364 		start = readl((void __iomem *)desc_w) & 0xfff;
365 		end = readl((void __iomem *)(desc_w + 1));
366 		vld = end & 0x1;
367 		end = end & 0xfff;
368 
369 		if (start == 0 && end == 0 && !vld && free >= 8)
370 			free = i;
371 
372 		/* Check all the region descriptors, even overlap */
373 		if (addr_start >= end || addr_end <= start || !vld)
374 			continue;
375 
376 		/* MRC0,1
377 		 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
378 		 *  So select MRCx_MEMN_GLBAC0
379 		 */
380 		if (sec_access) {
381 			writel(start, (void __iomem *)desc_w);
382 			writel(end | 0x1, (void __iomem *)(desc_w + 1));
383 		} else {
384 			writel(start, (void __iomem *)desc_w);
385 			writel((end | 0x1 | 0x10), (void __iomem *)(desc_w + 1));
386 		}
387 
388 		if (addr_start >= start && addr_end <= end)
389 			hit = true;
390 	}
391 
392 	if (!hit) {
393 		if (free >= 8)
394 			return -EFAULT;
395 
396 		desc_w = &mrc_dom->rgn_desc_words[free][0];
397 
398 		addr_start &= ~0xfff;
399 		addr_end &= ~0xfff;
400 
401 		if (sec_access) {
402 			writel(addr_start, (void __iomem *)desc_w);
403 			writel(addr_end | 0x1, (void __iomem *)(desc_w + 1));
404 		} else {
405 			writel(addr_start, (void __iomem *)desc_w);
406 			writel((addr_end | 0x1 | 0x10), (void __iomem *)(desc_w + 1));
407 		}
408 	}
409 
410 	return 0;
411 }
412