]>
Commit | Line | Data |
---|---|---|
83d40dfd | 1 | /* |
b8cdd014 | 2 | * Copyright 2008-2011 Freescale Semiconductor, Inc. |
83d40dfd KG |
3 | * |
4 | * (C) Copyright 2000 | |
5 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
6 | * | |
7 | * See file CREDITS for list of people who contributed to this | |
8 | * project. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public License as | |
12 | * published by the Free Software Foundation; either version 2 of | |
13 | * the License, or (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | * MA 02111-1307 USA | |
24 | */ | |
25 | ||
26 | #include <common.h> | |
76396751 | 27 | #include <linux/compiler.h> |
83d40dfd KG |
28 | #include <asm/fsl_law.h> |
29 | #include <asm/io.h> | |
30 | ||
f060054d KG |
31 | DECLARE_GLOBAL_DATA_PTR; |
32 | ||
243be8e2 | 33 | #define FSL_HW_NUM_LAWS CONFIG_SYS_FSL_NUM_LAWS |
83d40dfd | 34 | |
418ec858 | 35 | #ifdef CONFIG_FSL_CORENET |
e71755f8 BB |
36 | #define LAW_BASE (CONFIG_SYS_FSL_CORENET_CCM_ADDR) |
37 | #define LAWAR_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawar) | |
38 | #define LAWBARH_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarh) | |
39 | #define LAWBARL_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarl) | |
40 | #define LAWBAR_SHIFT 0 | |
41 | #else | |
42 | #define LAW_BASE (CONFIG_SYS_IMMR + 0xc08) | |
43 | #define LAWAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x + 2) | |
44 | #define LAWBAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x) | |
45 | #define LAWBAR_SHIFT 12 | |
46 | #endif | |
418ec858 | 47 | |
418ec858 | 48 | |
e71755f8 | 49 | static inline phys_addr_t get_law_base_addr(int idx) |
418ec858 | 50 | { |
e71755f8 BB |
51 | #ifdef CONFIG_FSL_CORENET |
52 | return (phys_addr_t) | |
53 | ((u64)in_be32(LAWBARH_ADDR(idx)) << 32) | | |
54 | in_be32(LAWBARL_ADDR(idx)); | |
55 | #else | |
56 | return (phys_addr_t)in_be32(LAWBAR_ADDR(idx)) << LAWBAR_SHIFT; | |
57 | #endif | |
418ec858 KG |
58 | } |
59 | ||
e71755f8 | 60 | static inline void set_law_base_addr(int idx, phys_addr_t addr) |
418ec858 | 61 | { |
e71755f8 BB |
62 | #ifdef CONFIG_FSL_CORENET |
63 | out_be32(LAWBARL_ADDR(idx), addr & 0xffffffff); | |
64 | out_be32(LAWBARH_ADDR(idx), (u64)addr >> 32); | |
418ec858 | 65 | #else |
e71755f8 BB |
66 | out_be32(LAWBAR_ADDR(idx), addr >> LAWBAR_SHIFT); |
67 | #endif | |
68 | } | |
69 | ||
83d40dfd KG |
70 | void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id) |
71 | { | |
f060054d KG |
72 | gd->used_laws |= (1 << idx); |
73 | ||
e71755f8 BB |
74 | out_be32(LAWAR_ADDR(idx), 0); |
75 | set_law_base_addr(idx, addr); | |
76 | out_be32(LAWAR_ADDR(idx), LAW_EN | ((u32)id << 20) | (u32)sz); | |
83d40dfd | 77 | |
74c5dfd8 | 78 | /* Read back so that we sync the writes */ |
e71755f8 | 79 | in_be32(LAWAR_ADDR(idx)); |
83d40dfd KG |
80 | } |
81 | ||
418ec858 KG |
82 | void disable_law(u8 idx) |
83 | { | |
418ec858 KG |
84 | gd->used_laws &= ~(1 << idx); |
85 | ||
e71755f8 BB |
86 | out_be32(LAWAR_ADDR(idx), 0); |
87 | set_law_base_addr(idx, 0); | |
418ec858 KG |
88 | |
89 | /* Read back so that we sync the writes */ | |
e71755f8 | 90 | in_be32(LAWAR_ADDR(idx)); |
418ec858 KG |
91 | |
92 | return; | |
93 | } | |
94 | ||
24b17d8a | 95 | #ifndef CONFIG_NAND_SPL |
418ec858 KG |
96 | static int get_law_entry(u8 i, struct law_entry *e) |
97 | { | |
e71755f8 | 98 | u32 lawar; |
418ec858 | 99 | |
e71755f8 | 100 | lawar = in_be32(LAWAR_ADDR(i)); |
418ec858 | 101 | |
e71755f8 | 102 | if (!(lawar & LAW_EN)) |
418ec858 KG |
103 | return 0; |
104 | ||
e71755f8 BB |
105 | e->addr = get_law_base_addr(i); |
106 | e->size = lawar & 0x3f; | |
107 | e->trgt_id = (lawar >> 20) & 0xff; | |
418ec858 KG |
108 | |
109 | return 1; | |
110 | } | |
111 | #endif | |
112 | ||
f060054d KG |
113 | int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id) |
114 | { | |
115 | u32 idx = ffz(gd->used_laws); | |
116 | ||
117 | if (idx >= FSL_HW_NUM_LAWS) | |
118 | return -1; | |
119 | ||
120 | set_law(idx, addr, sz, id); | |
ba04f701 KG |
121 | |
122 | return idx; | |
123 | } | |
124 | ||
7da53351 | 125 | #ifndef CONFIG_NAND_SPL |
ba04f701 KG |
126 | int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id) |
127 | { | |
128 | u32 idx; | |
129 | ||
130 | /* we have no LAWs free */ | |
131 | if (gd->used_laws == -1) | |
132 | return -1; | |
133 | ||
134 | /* grab the last free law */ | |
135 | idx = __ilog2(~(gd->used_laws)); | |
136 | ||
137 | if (idx >= FSL_HW_NUM_LAWS) | |
138 | return -1; | |
139 | ||
140 | set_law(idx, addr, sz, id); | |
f060054d KG |
141 | |
142 | return idx; | |
143 | } | |
144 | ||
418ec858 | 145 | struct law_entry find_law(phys_addr_t addr) |
83d40dfd | 146 | { |
418ec858 KG |
147 | struct law_entry entry; |
148 | int i; | |
83d40dfd | 149 | |
418ec858 KG |
150 | entry.index = -1; |
151 | entry.addr = 0; | |
152 | entry.size = 0; | |
153 | entry.trgt_id = 0; | |
f060054d | 154 | |
418ec858 KG |
155 | for (i = 0; i < FSL_HW_NUM_LAWS; i++) { |
156 | u64 upper; | |
83d40dfd | 157 | |
418ec858 KG |
158 | if (!get_law_entry(i, &entry)) |
159 | continue; | |
160 | ||
161 | upper = entry.addr + (2ull << entry.size); | |
162 | if ((addr >= entry.addr) && (addr < upper)) { | |
163 | entry.index = i; | |
164 | break; | |
165 | } | |
166 | } | |
167 | ||
168 | return entry; | |
83d40dfd KG |
169 | } |
170 | ||
ddcebcb6 BB |
171 | void print_laws(void) |
172 | { | |
ddcebcb6 | 173 | int i; |
e71755f8 | 174 | u32 lawar; |
ddcebcb6 BB |
175 | |
176 | printf("\nLocal Access Window Configuration\n"); | |
e71755f8 BB |
177 | for (i = 0; i < FSL_HW_NUM_LAWS; i++) { |
178 | lawar = in_be32(LAWAR_ADDR(i)); | |
11a3de46 BB |
179 | #ifdef CONFIG_FSL_CORENET |
180 | printf("LAWBARH%02d: 0x%08x LAWBARL%02d: 0x%08x", | |
181 | i, in_be32(LAWBARH_ADDR(i)), | |
182 | i, in_be32(LAWBARL_ADDR(i))); | |
183 | #else | |
e71755f8 | 184 | printf("LAWBAR%02d: 0x%08x", i, in_be32(LAWBAR_ADDR(i))); |
11a3de46 | 185 | #endif |
8e29ebab | 186 | printf(" LAWAR%02d: 0x%08x\n", i, lawar); |
e71755f8 BB |
187 | printf("\t(EN: %d TGT: 0x%02x SIZE: ", |
188 | (lawar & LAW_EN) ? 1 : 0, (lawar >> 20) & 0xff); | |
189 | print_size(lawar_size(lawar), ")\n"); | |
ddcebcb6 BB |
190 | } |
191 | ||
192 | return; | |
193 | } | |
194 | ||
f784e32b KG |
195 | /* use up to 2 LAWs for DDR, used the last available LAWs */ |
196 | int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id) | |
197 | { | |
198 | u64 start_align, law_sz; | |
199 | int law_sz_enc; | |
200 | ||
201 | if (start == 0) | |
202 | start_align = 1ull << (LAW_SIZE_32G + 1); | |
203 | else | |
204 | start_align = 1ull << (ffs64(start) - 1); | |
205 | law_sz = min(start_align, sz); | |
206 | law_sz_enc = __ilog2_u64(law_sz) - 1; | |
207 | ||
208 | if (set_last_law(start, law_sz_enc, id) < 0) | |
209 | return -1; | |
210 | ||
e6a6789f KG |
211 | /* recalculate size based on what was actually covered by the law */ |
212 | law_sz = 1ull << __ilog2_u64(law_sz); | |
213 | ||
f784e32b KG |
214 | /* do we still have anything to map */ |
215 | sz = sz - law_sz; | |
216 | if (sz) { | |
217 | start += law_sz; | |
218 | ||
219 | start_align = 1ull << (ffs64(start) - 1); | |
220 | law_sz = min(start_align, sz); | |
221 | law_sz_enc = __ilog2_u64(law_sz) - 1; | |
222 | ||
223 | if (set_last_law(start, law_sz_enc, id) < 0) | |
224 | return -1; | |
225 | } else { | |
226 | return 0; | |
227 | } | |
228 | ||
229 | /* do we still have anything to map */ | |
230 | sz = sz - law_sz; | |
231 | if (sz) | |
232 | return 1; | |
233 | ||
234 | return 0; | |
235 | } | |
7da53351 | 236 | #endif |
f784e32b | 237 | |
83d40dfd KG |
238 | void init_laws(void) |
239 | { | |
240 | int i; | |
83d40dfd | 241 | |
418ec858 | 242 | #if FSL_HW_NUM_LAWS < 32 |
f060054d | 243 | gd->used_laws = ~((1 << FSL_HW_NUM_LAWS) - 1); |
418ec858 KG |
244 | #elif FSL_HW_NUM_LAWS == 32 |
245 | gd->used_laws = 0; | |
246 | #else | |
247 | #error FSL_HW_NUM_LAWS can not be greater than 32 w/o code changes | |
248 | #endif | |
83d40dfd | 249 | |
cd6881b5 | 250 | /* |
76396751 KG |
251 | * Any LAWs that were set up before we booted assume they are meant to |
252 | * be around and mark them used. | |
253 | */ | |
254 | for (i = 0; i < FSL_HW_NUM_LAWS; i++) { | |
255 | u32 lawar = in_be32(LAWAR_ADDR(i)); | |
cd6881b5 | 256 | |
76396751 KG |
257 | if (lawar & LAW_EN) |
258 | gd->used_laws |= (1 << i); | |
259 | } | |
260 | ||
261 | #if defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) | |
262 | /* | |
263 | * in NAND boot we've already parsed the law_table and setup those LAWs | |
264 | * so don't do it again. | |
265 | */ | |
266 | return; | |
267 | #endif | |
268 | ||
f060054d KG |
269 | for (i = 0; i < num_law_entries; i++) { |
270 | if (law_table[i].index == -1) | |
271 | set_next_law(law_table[i].addr, law_table[i].size, | |
272 | law_table[i].trgt_id); | |
273 | else | |
274 | set_law(law_table[i].index, law_table[i].addr, | |
275 | law_table[i].size, law_table[i].trgt_id); | |
83d40dfd KG |
276 | } |
277 | ||
278 | return ; | |
279 | } |