1 /*
2  * Copyright 2020-2024 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/debug.h>
12 #include <lib/mmio.h>
13 #include <plat/common/platform.h>
14 #include <platform_def.h>
15 
16 #include "xrdc_config.h"
17 
18 #define XRDC_ADDR	0x292f0000
19 #define MRC_OFFSET	0x2000
20 #define MRC_STEP	0x200
21 
22 #define XRDC_MGR_PAC_ID	  U(0)
23 #define XRDC_MGR_PAC_SLOT U(47)
24 
25 enum xrdc_comp_type {
26 	MDA_TYPE = (1 << 16),
27 	MRC_TYPE = (2 << 16),
28 	PAC_TYPE = (3 << 16),
29 	MSC_TYPE = (4 << 16),
30 };
31 
32 enum xrdc_pd_type {
33 	XRDC_AD_PD,
34 	XRDC_HIFI_PD,
35 	XRDC_AV_PD,
36 };
37 
38 #define XRDC_TYPE_MASK (0x7 << 16)
39 #define XRDC_ID_MASK 0xFFFF
40 #define XRDC_ID(id) ((id) & XRDC_ID_MASK)
41 
42 typedef bool (*xrdc_check_func)(enum xrdc_comp_type type, uint16_t id);
43 
44 /* Access below XRDC needs enable PS 8
45  * and HIFI clocks and release HIFI firstly
46  */
47 uint32_t hifi_xrdc_list[] = {
48 	(MDA_TYPE | XRDC_ID(9)),
49 	(MRC_TYPE | XRDC_ID(7)),
50 	(MRC_TYPE | XRDC_ID(9)),
51 	(MRC_TYPE | XRDC_ID(11)),
52 };
53 
54 /* Access below XRDC needs enable PS 16 firstly */
55 uint32_t av_periph_xrdc_list[] = {
56 	(MDA_TYPE | XRDC_ID(10)),
57 	(MDA_TYPE | XRDC_ID(11)),
58 	(MDA_TYPE | XRDC_ID(12)),
59 	(MDA_TYPE | XRDC_ID(13)),
60 	(MDA_TYPE | XRDC_ID(14)),
61 	(MDA_TYPE | XRDC_ID(15)),
62 	(MDA_TYPE | XRDC_ID(16)),
63 
64 	(PAC_TYPE | XRDC_ID(2)),
65 
66 	(MRC_TYPE | XRDC_ID(6)),
67 	(MRC_TYPE | XRDC_ID(8)),
68 	(MRC_TYPE | XRDC_ID(10)),
69 
70 	(MSC_TYPE | XRDC_ID(1)),
71 	(MSC_TYPE | XRDC_ID(2)),
72 };
73 
74 uint32_t imx8ulp_pac_slots[] = {
75 	61, 23, 53
76 };
77 
78 uint32_t imx8ulp_msc_slots[] = {
79 	2, 1, 7
80 };
81 
xrdc_config_mrc_w0_w1(uint32_t mrc_con,uint32_t region,uint32_t w0,uint32_t size)82 static int xrdc_config_mrc_w0_w1(uint32_t mrc_con, uint32_t region, uint32_t w0, uint32_t size)
83 {
84 
85 	uint32_t w0_addr, w1_addr;
86 
87 	w0_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20;
88 	w1_addr = w0_addr + 4;
89 
90 	if ((size % 32) != 0) {
91 		return -EINVAL;
92 	}
93 
94 	mmio_write_32(w0_addr, w0 & ~0x1f);
95 	mmio_write_32(w1_addr, w0 + size - 1);
96 
97 	return 0;
98 }
99 
xrdc_config_mrc_w2(uint32_t mrc_con,uint32_t region,uint32_t dxsel_all)100 static int xrdc_config_mrc_w2(uint32_t mrc_con, uint32_t region, uint32_t dxsel_all)
101 {
102 	uint32_t w2_addr;
103 
104 	w2_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0x8;
105 
106 	mmio_write_32(w2_addr, dxsel_all);
107 
108 	return 0;
109 }
110 
xrdc_config_mrc_w3_w4(uint32_t mrc_con,uint32_t region,uint32_t w3,uint32_t w4)111 static int xrdc_config_mrc_w3_w4(uint32_t mrc_con, uint32_t region, uint32_t w3, uint32_t w4)
112 {
113 	uint32_t w3_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0xC;
114 	uint32_t w4_addr = w3_addr + 4;
115 
116 	mmio_write_32(w3_addr, w3);
117 	mmio_write_32(w4_addr, w4);
118 
119 	return 0;
120 }
121 
xrdc_config_pac(uint32_t pac,uint32_t index,uint32_t dxacp)122 static int xrdc_config_pac(uint32_t pac, uint32_t index, uint32_t dxacp)
123 {
124 	uint32_t w0_addr;
125 	uint32_t val;
126 
127 	if (pac > 2U) {
128 		return -EINVAL;
129 	}
130 
131 	/* Skip the PAC slot for XRDC MGR, use Sentinel configuration */
132 	if (pac == XRDC_MGR_PAC_ID && index == XRDC_MGR_PAC_SLOT) {
133 		return 0;
134 	}
135 
136 	w0_addr = XRDC_ADDR + 0x1000 + 0x400 * pac + 0x8 * index;
137 
138 	mmio_write_32(w0_addr, dxacp);
139 
140 	val = mmio_read_32(w0_addr + 4);
141 	mmio_write_32(w0_addr + 4, val | BIT_32(31));
142 
143 	return 0;
144 }
145 
xrdc_config_msc(uint32_t msc,uint32_t index,uint32_t dxacp)146 static int xrdc_config_msc(uint32_t msc, uint32_t index, uint32_t dxacp)
147 {
148 	uint32_t w0_addr;
149 	uint32_t val;
150 
151 	if (msc > 2) {
152 		return -EINVAL;
153 	}
154 
155 	w0_addr = XRDC_ADDR + 0x4000 + 0x400 * msc + 0x8 * index;
156 
157 	mmio_write_32(w0_addr, dxacp);
158 
159 	val = mmio_read_32(w0_addr + 4);
160 	mmio_write_32(w0_addr + 4, val | BIT_32(31));
161 
162 	return 0;
163 }
164 
xrdc_config_mda(uint32_t mda_con,uint32_t dom,enum xrdc_mda_sa sa)165 static int xrdc_config_mda(uint32_t mda_con, uint32_t dom, enum xrdc_mda_sa sa)
166 {
167 	uint32_t w0_addr;
168 	uint32_t val;
169 
170 	w0_addr = XRDC_ADDR + 0x800 + mda_con * 0x20;
171 
172 	val = mmio_read_32(w0_addr);
173 
174 	if (val & BIT_32(29)) {
175 		mmio_write_32(w0_addr, (val & (~0xFF)) | dom |
176 			      BIT_32(31) | 0x20 | ((sa & 0x3) << 6));
177 	} else {
178 		mmio_write_32(w0_addr, dom | BIT_32(31));
179 		mmio_write_32(w0_addr + 0x4, dom | BIT_32(31));
180 	}
181 
182 	return 0;
183 }
184 
xrdc_check_pd(enum xrdc_comp_type type,uint16_t id,enum xrdc_pd_type pd)185 static bool xrdc_check_pd(enum xrdc_comp_type type,
186 			  uint16_t id, enum xrdc_pd_type pd)
187 {
188 	unsigned int i, size;
189 	uint32_t item = type | XRDC_ID(id);
190 	uint32_t *list;
191 
192 	if (pd == XRDC_HIFI_PD) {
193 		size = ARRAY_SIZE(hifi_xrdc_list);
194 		list = hifi_xrdc_list;
195 	} else if (pd == XRDC_AV_PD) {
196 		size = ARRAY_SIZE(av_periph_xrdc_list);
197 		list = av_periph_xrdc_list;
198 	} else {
199 		return false;
200 	}
201 
202 	for (i = 0U; i < size; i++) {
203 		if (item == list[i]) {
204 			return true;
205 		}
206 	}
207 
208 	return false;
209 }
210 
xrdc_check_lpav(enum xrdc_comp_type type,uint16_t id)211 static bool xrdc_check_lpav(enum xrdc_comp_type type, uint16_t id)
212 {
213 	return xrdc_check_pd(type, id, XRDC_AV_PD);
214 }
215 
xrdc_check_hifi(enum xrdc_comp_type type,uint16_t id)216 static bool xrdc_check_hifi(enum xrdc_comp_type type, uint16_t id)
217 {
218 	return xrdc_check_pd(type, id, XRDC_HIFI_PD);
219 }
220 
xrdc_check_ad(enum xrdc_comp_type type,uint16_t id)221 static bool xrdc_check_ad(enum xrdc_comp_type type, uint16_t id)
222 {
223 	return (!xrdc_check_pd(type, id, XRDC_HIFI_PD) &&
224 			!xrdc_check_pd(type, id, XRDC_AV_PD));
225 }
226 
xrdc_apply_config(xrdc_check_func check_func)227 static int xrdc_apply_config(xrdc_check_func check_func)
228 {
229 	unsigned int i, j;
230 	uint32_t val;
231 
232 	for (i = 0U; i < ARRAY_SIZE(imx8ulp_mda); i++) {
233 		if (check_func(MDA_TYPE, imx8ulp_mda[i].mda_id)) {
234 			xrdc_config_mda(imx8ulp_mda[i].mda_id,
235 					imx8ulp_mda[i].did, imx8ulp_mda[i].sa);
236 		}
237 	}
238 
239 	for (i = 0U; i < ARRAY_SIZE(imx8ulp_mrc); i++) {
240 		if (check_func(MRC_TYPE, imx8ulp_mrc[i].mrc_id)) {
241 			xrdc_config_mrc_w0_w1(imx8ulp_mrc[i].mrc_id,
242 					      imx8ulp_mrc[i].region_id,
243 					      imx8ulp_mrc[i].region_start,
244 					      imx8ulp_mrc[i].region_size);
245 
246 			val = 0;
247 			for (j = 0U; j < DID_MAX; j++) {
248 				val |= imx8ulp_mrc[i].dsel[j] << (3 * j);
249 			}
250 
251 			xrdc_config_mrc_w2(imx8ulp_mrc[i].mrc_id, imx8ulp_mrc[i].region_id, val);
252 			xrdc_config_mrc_w3_w4(imx8ulp_mrc[i].mrc_id, imx8ulp_mrc[i].region_id,
253 				0, imx8ulp_mrc[i].accset[0] | (imx8ulp_mrc[i].accset[1] << 16) | BIT_32(31));
254 		}
255 	}
256 
257 	for (i = 0U; i < ARRAY_SIZE(imx8ulp_pdac); i++) {
258 		if (check_func(PAC_TYPE, imx8ulp_pdac[i].pac_msc_id)) {
259 			val = 0;
260 			for (j = 0U; j < DID_MAX; j++) {
261 				val |= imx8ulp_pdac[i].dsel[j] << (3 * j);
262 			}
263 
264 			if (imx8ulp_pdac[i].slot_id == PAC_SLOT_ALL) {
265 				/* Apply to all slots*/
266 				for (j = 0U; j < imx8ulp_pac_slots[imx8ulp_pdac[i].pac_msc_id]; j++) {
267 					xrdc_config_pac(imx8ulp_pdac[i].pac_msc_id, j, val);
268 				}
269 			} else {
270 				if (imx8ulp_pdac[i].slot_id >= imx8ulp_pac_slots[imx8ulp_pdac[i].pac_msc_id]) {
271 					return -EINVAL;
272 				}
273 
274 				xrdc_config_pac(imx8ulp_pdac[i].pac_msc_id, imx8ulp_pdac[i].slot_id, val);
275 			}
276 		}
277 	}
278 
279 	for (i = 0U; i < ARRAY_SIZE(imx8ulp_msc); i++) {
280 		if (check_func(MSC_TYPE, imx8ulp_msc[i].pac_msc_id)) {
281 			val = 0;
282 			for (j = 0U; j < DID_MAX; j++) {
283 				val |= imx8ulp_msc[i].dsel[j] << (3 * j);
284 			}
285 
286 			if (imx8ulp_msc[i].slot_id == MSC_SLOT_ALL) {
287 				/* Apply to all slots*/
288 				for (j = 0U; j < imx8ulp_msc_slots[imx8ulp_msc[i].pac_msc_id]; j++) {
289 					xrdc_config_msc(imx8ulp_msc[i].pac_msc_id, j, val);
290 				}
291 			} else {
292 				if (imx8ulp_msc[i].slot_id >= imx8ulp_msc_slots[imx8ulp_msc[i].pac_msc_id]) {
293 					return -EINVAL;
294 				}
295 
296 				xrdc_config_msc(imx8ulp_msc[i].pac_msc_id, imx8ulp_msc[i].slot_id, val);
297 			}
298 		}
299 	}
300 
301 	return 0;
302 }
303 
xrdc_apply_lpav_config(void)304 int xrdc_apply_lpav_config(void)
305 {
306 	/* Configure PAC2 to allow to access PCC5 */
307 	xrdc_config_pac(2, 39, 0xe00000);
308 
309 	/* Enable the eDMA2 MP clock for MDA16 access */
310 	mmio_write_32(IMX_PCC5_BASE + 0x0, 0xc0000000);
311 	return xrdc_apply_config(xrdc_check_lpav);
312 }
313 
xrdc_apply_hifi_config(void)314 int xrdc_apply_hifi_config(void)
315 {
316 	return xrdc_apply_config(xrdc_check_hifi);
317 }
318 
xrdc_apply_apd_config(void)319 int xrdc_apply_apd_config(void)
320 {
321 	return xrdc_apply_config(xrdc_check_ad);
322 }
323 
xrdc_enable(void)324 void xrdc_enable(void)
325 {
326 	mmio_write_32(XRDC_ADDR, BIT(14) | BIT(15) | BIT(0));
327 }
328