xref: /openbmc/u-boot/arch/powerpc/cpu/mpc8xxx/law.c (revision a7da6f8c)
1 /*
2  * Copyright 2008-2011 Freescale Semiconductor, Inc.
3  *
4  * (C) Copyright 2000
5  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6  *
7  * SPDX-License-Identifier:	GPL-2.0+
8  */
9 
10 #include <common.h>
11 #include <linux/compiler.h>
12 #include <asm/fsl_law.h>
13 #include <asm/io.h>
14 #include <linux/log2.h>
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 #define FSL_HW_NUM_LAWS CONFIG_SYS_FSL_NUM_LAWS
19 
20 #ifdef CONFIG_FSL_CORENET
21 #define LAW_BASE (CONFIG_SYS_FSL_CORENET_CCM_ADDR)
22 #define LAWAR_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawar)
23 #define LAWBARH_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarh)
24 #define LAWBARL_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarl)
25 #define LAWBAR_SHIFT 0
26 #else
27 #define LAW_BASE (CONFIG_SYS_IMMR + 0xc08)
28 #define LAWAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x + 2)
29 #define LAWBAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x)
30 #define LAWBAR_SHIFT 12
31 #endif
32 
33 
34 static inline phys_addr_t get_law_base_addr(int idx)
35 {
36 #ifdef CONFIG_FSL_CORENET
37 	return (phys_addr_t)
38 		((u64)in_be32(LAWBARH_ADDR(idx)) << 32) |
39 		in_be32(LAWBARL_ADDR(idx));
40 #else
41 	return (phys_addr_t)in_be32(LAWBAR_ADDR(idx)) << LAWBAR_SHIFT;
42 #endif
43 }
44 
45 static inline void set_law_base_addr(int idx, phys_addr_t addr)
46 {
47 #ifdef CONFIG_FSL_CORENET
48 	out_be32(LAWBARL_ADDR(idx), addr & 0xffffffff);
49 	out_be32(LAWBARH_ADDR(idx), (u64)addr >> 32);
50 #else
51 	out_be32(LAWBAR_ADDR(idx), addr >> LAWBAR_SHIFT);
52 #endif
53 }
54 
55 void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
56 {
57 	gd->arch.used_laws |= (1 << idx);
58 
59 	out_be32(LAWAR_ADDR(idx), 0);
60 	set_law_base_addr(idx, addr);
61 	out_be32(LAWAR_ADDR(idx), LAW_EN | ((u32)id << 20) | (u32)sz);
62 
63 	/* Read back so that we sync the writes */
64 	in_be32(LAWAR_ADDR(idx));
65 }
66 
67 void disable_law(u8 idx)
68 {
69 	gd->arch.used_laws &= ~(1 << idx);
70 
71 	out_be32(LAWAR_ADDR(idx), 0);
72 	set_law_base_addr(idx, 0);
73 
74 	/* Read back so that we sync the writes */
75 	in_be32(LAWAR_ADDR(idx));
76 
77 	return;
78 }
79 
80 #if !defined(CONFIG_NAND_SPL) && \
81 	(!defined(CONFIG_SPL_BUILD) || !defined(CONFIG_SPL_INIT_MINIMAL))
82 static int get_law_entry(u8 i, struct law_entry *e)
83 {
84 	u32 lawar;
85 
86 	lawar = in_be32(LAWAR_ADDR(i));
87 
88 	if (!(lawar & LAW_EN))
89 		return 0;
90 
91 	e->addr = get_law_base_addr(i);
92 	e->size = lawar & 0x3f;
93 	e->trgt_id = (lawar >> 20) & 0xff;
94 
95 	return 1;
96 }
97 #endif
98 
99 int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
100 {
101 	u32 idx = ffz(gd->arch.used_laws);
102 
103 	if (idx >= FSL_HW_NUM_LAWS)
104 		return -1;
105 
106 	set_law(idx, addr, sz, id);
107 
108 	return idx;
109 }
110 
111 #if !defined(CONFIG_NAND_SPL) && \
112 	(!defined(CONFIG_SPL_BUILD) || !defined(CONFIG_SPL_INIT_MINIMAL))
113 int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
114 {
115 	u32 idx;
116 
117 	/* we have no LAWs free */
118 	if (gd->arch.used_laws == -1)
119 		return -1;
120 
121 	/* grab the last free law */
122 	idx = __ilog2(~(gd->arch.used_laws));
123 
124 	if (idx >= FSL_HW_NUM_LAWS)
125 		return -1;
126 
127 	set_law(idx, addr, sz, id);
128 
129 	return idx;
130 }
131 
132 struct law_entry find_law(phys_addr_t addr)
133 {
134 	struct law_entry entry;
135 	int i;
136 
137 	entry.index = -1;
138 	entry.addr = 0;
139 	entry.size = 0;
140 	entry.trgt_id = 0;
141 
142 	for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
143 		u64 upper;
144 
145 		if (!get_law_entry(i, &entry))
146 			continue;
147 
148 		upper = entry.addr + (2ull << entry.size);
149 		if ((addr >= entry.addr) && (addr < upper)) {
150 			entry.index = i;
151 			break;
152 		}
153 	}
154 
155 	return entry;
156 }
157 
158 void print_laws(void)
159 {
160 	int i;
161 	u32 lawar;
162 
163 	printf("\nLocal Access Window Configuration\n");
164 	for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
165 		lawar = in_be32(LAWAR_ADDR(i));
166 #ifdef CONFIG_FSL_CORENET
167 		printf("LAWBARH%02d: 0x%08x LAWBARL%02d: 0x%08x",
168 		       i, in_be32(LAWBARH_ADDR(i)),
169 		       i, in_be32(LAWBARL_ADDR(i)));
170 #else
171 		printf("LAWBAR%02d: 0x%08x", i, in_be32(LAWBAR_ADDR(i)));
172 #endif
173 		printf(" LAWAR%02d: 0x%08x\n", i, lawar);
174 		printf("\t(EN: %d TGT: 0x%02x SIZE: ",
175 		       (lawar & LAW_EN) ? 1 : 0, (lawar >> 20) & 0xff);
176 		print_size(lawar_size(lawar), ")\n");
177 	}
178 
179 	return;
180 }
181 
182 /* use up to 2 LAWs for DDR, used the last available LAWs */
183 int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
184 {
185 	u64 start_align, law_sz;
186 	int law_sz_enc;
187 
188 	if (start == 0)
189 		start_align = 1ull << (LAW_SIZE_32G + 1);
190 	else
191 		start_align = 1ull << (__ffs64(start));
192 	law_sz = min(start_align, sz);
193 	law_sz_enc = __ilog2_u64(law_sz) - 1;
194 
195 	if (set_last_law(start, law_sz_enc, id) < 0)
196 		return -1;
197 
198 	/* recalculate size based on what was actually covered by the law */
199 	law_sz = 1ull << __ilog2_u64(law_sz);
200 
201 	/* do we still have anything to map */
202 	sz = sz - law_sz;
203 	if (sz) {
204 		start += law_sz;
205 
206 		start_align = 1ull << (__ffs64(start));
207 		law_sz = min(start_align, sz);
208 		law_sz_enc = __ilog2_u64(law_sz) - 1;
209 
210 		if (set_last_law(start, law_sz_enc, id) < 0)
211 			return -1;
212 	} else {
213 		return 0;
214 	}
215 
216 	/* do we still have anything to map */
217 	sz = sz - law_sz;
218 	if (sz)
219 		return 1;
220 
221 	return 0;
222 }
223 #endif /* not SPL */
224 
225 void disable_non_ddr_laws(void)
226 {
227 	int i;
228 	int id;
229 	for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
230 		u32 lawar = in_be32(LAWAR_ADDR(i));
231 
232 		if (lawar & LAW_EN) {
233 			id = (lawar & ~LAW_EN) >> 20;
234 			switch (id) {
235 			case LAW_TRGT_IF_DDR_1:
236 			case LAW_TRGT_IF_DDR_2:
237 			case LAW_TRGT_IF_DDR_3:
238 			case LAW_TRGT_IF_DDR_4:
239 			case LAW_TRGT_IF_DDR_INTRLV:
240 			case LAW_TRGT_IF_DDR_INTLV_34:
241 			case LAW_TRGT_IF_DDR_INTLV_123:
242 			case LAW_TRGT_IF_DDR_INTLV_1234:
243 						continue;
244 			default:
245 						disable_law(i);
246 			}
247 		}
248 	}
249 }
250 
251 void init_laws(void)
252 {
253 	int i;
254 
255 #if FSL_HW_NUM_LAWS < 32
256 	gd->arch.used_laws = ~((1 << FSL_HW_NUM_LAWS) - 1);
257 #elif FSL_HW_NUM_LAWS == 32
258 	gd->arch.used_laws = 0;
259 #else
260 #error FSL_HW_NUM_LAWS can not be greater than 32 w/o code changes
261 #endif
262 
263 #if defined(CONFIG_SECURE_BOOT) && defined(CONFIG_E500) && \
264 						!defined(CONFIG_E500MC)
265 	/* ISBC (Boot ROM) creates a LAW 0 entry for non PBL platforms,
266 	 * which is not disabled before transferring the control to uboot.
267 	 * Disable the LAW 0 entry here.
268 	 */
269 	disable_law(0);
270 #endif
271 
272 #if !defined(CONFIG_SECURE_BOOT)
273 	/*
274 	 * if any non DDR LAWs has been created earlier, remove them before
275 	 * LAW table is parsed.
276 	*/
277 	disable_non_ddr_laws();
278 #endif
279 
280 	/*
281 	 * Any LAWs that were set up before we booted assume they are meant to
282 	 * be around and mark them used.
283 	 */
284 	for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
285 		u32 lawar = in_be32(LAWAR_ADDR(i));
286 
287 		if (lawar & LAW_EN)
288 			gd->arch.used_laws |= (1 << i);
289 	}
290 
291 	for (i = 0; i < num_law_entries; i++) {
292 		if (law_table[i].index == -1)
293 			set_next_law(law_table[i].addr, law_table[i].size,
294 					law_table[i].trgt_id);
295 		else
296 			set_law(law_table[i].index, law_table[i].addr,
297 				law_table[i].size, law_table[i].trgt_id);
298 	}
299 
300 #ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE
301 	/* check RCW to get which port is used for boot */
302 	ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
303 	u32 bootloc = in_be32(&gur->rcwsr[6]);
304 	/*
305 	 * in SRIO or PCIE boot we need to set specail LAWs for
306 	 * SRIO or PCIE interfaces.
307 	 */
308 	switch ((bootloc & FSL_CORENET_RCWSR6_BOOT_LOC) >> 23) {
309 	case 0x0: /* boot from PCIE1 */
310 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
311 				LAW_SIZE_1M,
312 				LAW_TRGT_IF_PCIE_1);
313 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
314 				LAW_SIZE_1M,
315 				LAW_TRGT_IF_PCIE_1);
316 		break;
317 	case 0x1: /* boot from PCIE2 */
318 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
319 				LAW_SIZE_1M,
320 				LAW_TRGT_IF_PCIE_2);
321 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
322 				LAW_SIZE_1M,
323 				LAW_TRGT_IF_PCIE_2);
324 		break;
325 	case 0x2: /* boot from PCIE3 */
326 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
327 				LAW_SIZE_1M,
328 				LAW_TRGT_IF_PCIE_3);
329 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
330 				LAW_SIZE_1M,
331 				LAW_TRGT_IF_PCIE_3);
332 		break;
333 	case 0x8: /* boot from SRIO1 */
334 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
335 				LAW_SIZE_1M,
336 				LAW_TRGT_IF_RIO_1);
337 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
338 				LAW_SIZE_1M,
339 				LAW_TRGT_IF_RIO_1);
340 		break;
341 	case 0x9: /* boot from SRIO2 */
342 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
343 				LAW_SIZE_1M,
344 				LAW_TRGT_IF_RIO_2);
345 		set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
346 				LAW_SIZE_1M,
347 				LAW_TRGT_IF_RIO_2);
348 		break;
349 	default:
350 		break;
351 	}
352 #endif
353 
354 	return ;
355 }
356