]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/misc/fsl_law.c
ppc/p4080: Add support for CoreNet style platform LAWs
[karo-tx-uboot.git] / drivers / misc / fsl_law.c
1 /*
2  * Copyright 2008-2009 Freescale Semiconductor, Inc.
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>
27 #include <asm/fsl_law.h>
28 #include <asm/io.h>
29
30 DECLARE_GLOBAL_DATA_PTR;
31
32 /* number of LAWs in the hw implementation */
33 #if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
34     defined(CONFIG_MPC8560) || defined(CONFIG_MPC8555)
35 #define FSL_HW_NUM_LAWS 8
36 #elif defined(CONFIG_MPC8548) || defined(CONFIG_MPC8544) || \
37       defined(CONFIG_MPC8568) || defined(CONFIG_MPC8569) || \
38       defined(CONFIG_MPC8641) || defined(CONFIG_MPC8610)
39 #define FSL_HW_NUM_LAWS 10
40 #elif defined(CONFIG_MPC8536) || defined(CONFIG_MPC8572) || \
41       defined(CONFIG_P1011) || defined(CONFIG_P1020) || \
42       defined(CONFIG_P2010) || defined(CONFIG_P2020)
43 #define FSL_HW_NUM_LAWS 12
44 #else
45 #error FSL_HW_NUM_LAWS not defined for this platform
46 #endif
47
48 #ifdef CONFIG_FSL_CORENET
49 void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
50 {
51         volatile ccsr_local_t *ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
52
53         gd->used_laws |= (1 << idx);
54
55         out_be32(&ccm->law[idx].lawar, 0);
56         out_be32(&ccm->law[idx].lawbarh, ((u64)addr >> 32));
57         out_be32(&ccm->law[idx].lawbarl, addr & 0xffffffff);
58         out_be32(&ccm->law[idx].lawar, LAW_EN | ((u32)id << 20) | (u32)sz);
59
60         /* Read back so that we sync the writes */
61         in_be32(&ccm->law[idx].lawar);
62 }
63
64 void disable_law(u8 idx)
65 {
66         volatile ccsr_local_t *ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
67
68         gd->used_laws &= ~(1 << idx);
69
70         out_be32(&ccm->law[idx].lawar, 0);
71         out_be32(&ccm->law[idx].lawbarh, 0);
72         out_be32(&ccm->law[idx].lawbarl, 0);
73
74         /* Read back so that we sync the writes */
75         in_be32(&ccm->law[idx].lawar);
76
77         return;
78 }
79
80 static int get_law_entry(u8 i, struct law_entry *e)
81 {
82         volatile ccsr_local_t *ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
83         u32 lawar;
84
85         lawar = in_be32(&ccm->law[i].lawar);
86
87         if (!(lawar & LAW_EN))
88                 return 0;
89
90         e->addr = ((u64)in_be32(&ccm->law[i].lawbarh) << 32) |
91                         in_be32(&ccm->law[i].lawbarl);
92         e->size = lawar & 0x3f;
93         e->trgt_id = (lawar >> 20) & 0xff;
94
95         return 1;
96 }
97 #else
98 void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
99 {
100         volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
101         volatile u32 *lawbar = base + 8 * idx;
102         volatile u32 *lawar = base + 8 * idx + 2;
103
104         gd->used_laws |= (1 << idx);
105
106         out_be32(lawar, 0);
107         out_be32(lawbar, addr >> 12);
108         out_be32(lawar, LAW_EN | ((u32)id << 20) | (u32)sz);
109
110         /* Read back so that we sync the writes */
111         in_be32(lawar);
112 }
113
114 void disable_law(u8 idx)
115 {
116         volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
117         volatile u32 *lawbar = base + 8 * idx;
118         volatile u32 *lawar = base + 8 * idx + 2;
119
120         gd->used_laws &= ~(1 << idx);
121
122         out_be32(lawar, 0);
123         out_be32(lawbar, 0);
124
125         /* Read back so that we sync the writes */
126         in_be32(lawar);
127
128         return;
129 }
130
131 static int get_law_entry(u8 i, struct law_entry *e)
132 {
133         volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
134         volatile u32 *lawbar = base + 8 * i;
135         volatile u32 *lawar = base + 8 * i + 2;
136         u32 temp;
137
138         temp = in_be32(lawar);
139
140         if (!(temp & LAW_EN))
141                 return 0;
142
143         e->addr = (u64)in_be32(lawbar) << 12;
144         e->size = temp & 0x3f;
145         e->trgt_id = (temp >> 20) & 0xff;
146
147         return 1;
148 }
149 #endif
150
151 int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
152 {
153         u32 idx = ffz(gd->used_laws);
154
155         if (idx >= FSL_HW_NUM_LAWS)
156                 return -1;
157
158         set_law(idx, addr, sz, id);
159
160         return idx;
161 }
162
163 #ifndef CONFIG_NAND_SPL
164 int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
165 {
166         u32 idx;
167
168         /* we have no LAWs free */
169         if (gd->used_laws == -1)
170                 return -1;
171
172         /* grab the last free law */
173         idx = __ilog2(~(gd->used_laws));
174
175         if (idx >= FSL_HW_NUM_LAWS)
176                 return -1;
177
178         set_law(idx, addr, sz, id);
179
180         return idx;
181 }
182
183 struct law_entry find_law(phys_addr_t addr)
184 {
185         struct law_entry entry;
186         int i;
187
188         entry.index = -1;
189         entry.addr = 0;
190         entry.size = 0;
191         entry.trgt_id = 0;
192
193         for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
194                 u64 upper;
195
196                 if (!get_law_entry(i, &entry))
197                         continue;
198
199                 upper = entry.addr + (2ull << entry.size);
200                 if ((addr >= entry.addr) && (addr < upper)) {
201                         entry.index = i;
202                         break;
203                 }
204         }
205
206         return entry;
207 }
208
209 void print_laws(void)
210 {
211         volatile u32 *base = (volatile u32 *)(CONFIG_SYS_IMMR + 0xc08);
212         volatile u32 *lawbar = base;
213         volatile u32 *lawar = base + 2;
214         int i;
215
216         printf("\nLocal Access Window Configuration\n");
217         for(i = 0; i < FSL_HW_NUM_LAWS; i++) {
218                 printf("\tLAWBAR%d : 0x%08x, LAWAR%d : 0x%08x\n",
219                        i, in_be32(lawbar), i, in_be32(lawar));
220                 lawbar += 8;
221                 lawar += 8;
222         }
223
224         return;
225 }
226
227 /* use up to 2 LAWs for DDR, used the last available LAWs */
228 int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
229 {
230         u64 start_align, law_sz;
231         int law_sz_enc;
232
233         if (start == 0)
234                 start_align = 1ull << (LAW_SIZE_32G + 1);
235         else
236                 start_align = 1ull << (ffs64(start) - 1);
237         law_sz = min(start_align, sz);
238         law_sz_enc = __ilog2_u64(law_sz) - 1;
239
240         if (set_last_law(start, law_sz_enc, id) < 0)
241                 return -1;
242
243         /* recalculate size based on what was actually covered by the law */
244         law_sz = 1ull << __ilog2_u64(law_sz);
245
246         /* do we still have anything to map */
247         sz = sz - law_sz;
248         if (sz) {
249                 start += law_sz;
250
251                 start_align = 1ull << (ffs64(start) - 1);
252                 law_sz = min(start_align, sz);
253                 law_sz_enc = __ilog2_u64(law_sz) - 1;
254
255                 if (set_last_law(start, law_sz_enc, id) < 0)
256                         return -1;
257         } else {
258                 return 0;
259         }
260
261         /* do we still have anything to map */
262         sz = sz - law_sz;
263         if (sz)
264                 return 1;
265
266         return 0;
267 }
268 #endif
269
270 void init_laws(void)
271 {
272         int i;
273
274 #if FSL_HW_NUM_LAWS < 32
275         gd->used_laws = ~((1 << FSL_HW_NUM_LAWS) - 1);
276 #elif FSL_HW_NUM_LAWS == 32
277         gd->used_laws = 0;
278 #else
279 #error FSL_HW_NUM_LAWS can not be greater than 32 w/o code changes
280 #endif
281
282         for (i = 0; i < num_law_entries; i++) {
283                 if (law_table[i].index == -1)
284                         set_next_law(law_table[i].addr, law_table[i].size,
285                                         law_table[i].trgt_id);
286                 else
287                         set_law(law_table[i].index, law_table[i].addr,
288                                 law_table[i].size, law_table[i].trgt_id);
289         }
290
291         return ;
292 }