blob: 65890769ac333d641f03e7e1500959d7014a3e8e [file] [log] [blame]
Kumar Gala95fd2f62008-01-16 01:13:58 -06001/*
Kumar Gala16a276e2010-03-30 23:06:53 -05002 * Copyright 2008-2010 Freescale Semiconductor, Inc.
Kumar Gala95fd2f62008-01-16 01:13:58 -06003 *
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
Kumar Gala75639e02008-06-11 00:44:10 -050030DECLARE_GLOBAL_DATA_PTR;
31
Kumar Gala75639e02008-06-11 00:44:10 -050032/* 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) || \
Haiying Wangc9849132009-03-27 17:02:44 -040037 defined(CONFIG_MPC8568) || defined(CONFIG_MPC8569) || \
Kumar Gala75639e02008-06-11 00:44:10 -050038 defined(CONFIG_MPC8641) || defined(CONFIG_MPC8610)
39#define FSL_HW_NUM_LAWS 10
Srikanth Srinivasana864f322009-01-21 17:17:33 -060040#elif defined(CONFIG_MPC8536) || defined(CONFIG_MPC8572) || \
Poonam Aggrwal13e21b12009-08-20 18:57:45 +053041 defined(CONFIG_P1011) || defined(CONFIG_P1020) || \
Kumar Gala16a276e2010-03-30 23:06:53 -050042 defined(CONFIG_P1012) || defined(CONFIG_P1021) || \
43 defined(CONFIG_P1013) || defined(CONFIG_P1022) || \
Poonam Aggrwal13e21b12009-08-20 18:57:45 +053044 defined(CONFIG_P2010) || defined(CONFIG_P2020)
Kumar Gala75639e02008-06-11 00:44:10 -050045#define FSL_HW_NUM_LAWS 12
Kumar Galaf2134b82010-01-27 10:26:46 -060046#elif defined(CONFIG_PPC_P3041) || defined(CONFIG_PPC_P4080) || \
47 defined(CONFIG_PPC_P5020)
Kumar Galabb5409c2009-03-19 02:39:17 -050048#define FSL_HW_NUM_LAWS 32
Kumar Gala75639e02008-06-11 00:44:10 -050049#else
50#error FSL_HW_NUM_LAWS not defined for this platform
51#endif
Kumar Gala95fd2f62008-01-16 01:13:58 -060052
Kumar Gala65e6c322009-03-19 02:32:23 -050053#ifdef CONFIG_FSL_CORENET
Becky Bruceeb891f02010-06-17 11:37:23 -050054#define LAW_BASE (CONFIG_SYS_FSL_CORENET_CCM_ADDR)
55#define LAWAR_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawar)
56#define LAWBARH_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarh)
57#define LAWBARL_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarl)
58#define LAWBAR_SHIFT 0
59#else
60#define LAW_BASE (CONFIG_SYS_IMMR + 0xc08)
61#define LAWAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x + 2)
62#define LAWBAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x)
63#define LAWBAR_SHIFT 12
64#endif
Kumar Gala65e6c322009-03-19 02:32:23 -050065
Kumar Gala65e6c322009-03-19 02:32:23 -050066
Becky Bruceeb891f02010-06-17 11:37:23 -050067static inline phys_addr_t get_law_base_addr(int idx)
Kumar Gala65e6c322009-03-19 02:32:23 -050068{
Becky Bruceeb891f02010-06-17 11:37:23 -050069#ifdef CONFIG_FSL_CORENET
70 return (phys_addr_t)
71 ((u64)in_be32(LAWBARH_ADDR(idx)) << 32) |
72 in_be32(LAWBARL_ADDR(idx));
73#else
74 return (phys_addr_t)in_be32(LAWBAR_ADDR(idx)) << LAWBAR_SHIFT;
75#endif
Kumar Gala65e6c322009-03-19 02:32:23 -050076}
77
Becky Bruceeb891f02010-06-17 11:37:23 -050078static inline void set_law_base_addr(int idx, phys_addr_t addr)
Kumar Gala65e6c322009-03-19 02:32:23 -050079{
Becky Bruceeb891f02010-06-17 11:37:23 -050080#ifdef CONFIG_FSL_CORENET
81 out_be32(LAWBARL_ADDR(idx), addr & 0xffffffff);
82 out_be32(LAWBARH_ADDR(idx), (u64)addr >> 32);
Kumar Gala65e6c322009-03-19 02:32:23 -050083#else
Becky Bruceeb891f02010-06-17 11:37:23 -050084 out_be32(LAWBAR_ADDR(idx), addr >> LAWBAR_SHIFT);
85#endif
86}
87
Kumar Gala65e6c322009-03-19 02:32:23 -050088void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
89{
Kumar Gala75639e02008-06-11 00:44:10 -050090 gd->used_laws |= (1 << idx);
91
Becky Bruceeb891f02010-06-17 11:37:23 -050092 out_be32(LAWAR_ADDR(idx), 0);
93 set_law_base_addr(idx, addr);
94 out_be32(LAWAR_ADDR(idx), LAW_EN | ((u32)id << 20) | (u32)sz);
Kumar Gala95fd2f62008-01-16 01:13:58 -060095
Timur Tabi52fa71f2009-09-04 17:05:24 -050096 /* Read back so that we sync the writes */
Becky Bruceeb891f02010-06-17 11:37:23 -050097 in_be32(LAWAR_ADDR(idx));
Kumar Gala95fd2f62008-01-16 01:13:58 -060098}
99
Kumar Gala65e6c322009-03-19 02:32:23 -0500100void disable_law(u8 idx)
101{
Kumar Gala65e6c322009-03-19 02:32:23 -0500102 gd->used_laws &= ~(1 << idx);
103
Becky Bruceeb891f02010-06-17 11:37:23 -0500104 out_be32(LAWAR_ADDR(idx), 0);
105 set_law_base_addr(idx, 0);
Kumar Gala65e6c322009-03-19 02:32:23 -0500106
107 /* Read back so that we sync the writes */
Becky Bruceeb891f02010-06-17 11:37:23 -0500108 in_be32(LAWAR_ADDR(idx));
Kumar Gala65e6c322009-03-19 02:32:23 -0500109
110 return;
111}
112
Kumar Gala93f53812009-09-30 08:39:44 -0500113#ifndef CONFIG_NAND_SPL
Kumar Gala65e6c322009-03-19 02:32:23 -0500114static int get_law_entry(u8 i, struct law_entry *e)
115{
Becky Bruceeb891f02010-06-17 11:37:23 -0500116 u32 lawar;
Kumar Gala65e6c322009-03-19 02:32:23 -0500117
Becky Bruceeb891f02010-06-17 11:37:23 -0500118 lawar = in_be32(LAWAR_ADDR(i));
Kumar Gala65e6c322009-03-19 02:32:23 -0500119
Becky Bruceeb891f02010-06-17 11:37:23 -0500120 if (!(lawar & LAW_EN))
Kumar Gala65e6c322009-03-19 02:32:23 -0500121 return 0;
122
Becky Bruceeb891f02010-06-17 11:37:23 -0500123 e->addr = get_law_base_addr(i);
124 e->size = lawar & 0x3f;
125 e->trgt_id = (lawar >> 20) & 0xff;
Kumar Gala65e6c322009-03-19 02:32:23 -0500126
127 return 1;
128}
129#endif
130
Kumar Gala75639e02008-06-11 00:44:10 -0500131int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
132{
133 u32 idx = ffz(gd->used_laws);
134
135 if (idx >= FSL_HW_NUM_LAWS)
136 return -1;
137
138 set_law(idx, addr, sz, id);
139
140 return idx;
141}
142
Mingkai Hu0255cd72009-09-11 14:19:10 +0800143#ifndef CONFIG_NAND_SPL
Kumar Galaa9abb002008-06-10 16:16:02 -0500144int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
145{
146 u32 idx;
147
148 /* we have no LAWs free */
149 if (gd->used_laws == -1)
150 return -1;
151
152 /* grab the last free law */
153 idx = __ilog2(~(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
Kumar Gala65e6c322009-03-19 02:32:23 -0500163struct law_entry find_law(phys_addr_t addr)
Kumar Gala95fd2f62008-01-16 01:13:58 -0600164{
Kumar Gala65e6c322009-03-19 02:32:23 -0500165 struct law_entry entry;
166 int i;
Kumar Gala95fd2f62008-01-16 01:13:58 -0600167
Kumar Gala65e6c322009-03-19 02:32:23 -0500168 entry.index = -1;
169 entry.addr = 0;
170 entry.size = 0;
171 entry.trgt_id = 0;
Kumar Gala75639e02008-06-11 00:44:10 -0500172
Kumar Gala65e6c322009-03-19 02:32:23 -0500173 for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
174 u64 upper;
Kumar Gala95fd2f62008-01-16 01:13:58 -0600175
Kumar Gala65e6c322009-03-19 02:32:23 -0500176 if (!get_law_entry(i, &entry))
177 continue;
178
179 upper = entry.addr + (2ull << entry.size);
180 if ((addr >= entry.addr) && (addr < upper)) {
181 entry.index = i;
182 break;
183 }
184 }
185
186 return entry;
Kumar Gala95fd2f62008-01-16 01:13:58 -0600187}
188
Becky Bruce2a15f752008-01-23 16:31:05 -0600189void print_laws(void)
190{
Becky Bruce2a15f752008-01-23 16:31:05 -0600191 int i;
Becky Bruceeb891f02010-06-17 11:37:23 -0500192 u32 lawar;
Becky Bruce2a15f752008-01-23 16:31:05 -0600193
194 printf("\nLocal Access Window Configuration\n");
Becky Bruceeb891f02010-06-17 11:37:23 -0500195 for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
196 lawar = in_be32(LAWAR_ADDR(i));
Becky Bruced58f8d52010-06-17 11:37:24 -0500197#ifdef CONFIG_FSL_CORENET
198 printf("LAWBARH%02d: 0x%08x LAWBARL%02d: 0x%08x",
199 i, in_be32(LAWBARH_ADDR(i)),
200 i, in_be32(LAWBARL_ADDR(i)));
201#else
Becky Bruceeb891f02010-06-17 11:37:23 -0500202 printf("LAWBAR%02d: 0x%08x", i, in_be32(LAWBAR_ADDR(i)));
Becky Bruced58f8d52010-06-17 11:37:24 -0500203#endif
Becky Bruceeb891f02010-06-17 11:37:23 -0500204 printf(" LAWAR0x%02d: 0x%08x\n", i, lawar);
205 printf("\t(EN: %d TGT: 0x%02x SIZE: ",
206 (lawar & LAW_EN) ? 1 : 0, (lawar >> 20) & 0xff);
207 print_size(lawar_size(lawar), ")\n");
Becky Bruce2a15f752008-01-23 16:31:05 -0600208 }
209
210 return;
211}
212
Kumar Gala61ed0532008-08-26 15:01:28 -0500213/* use up to 2 LAWs for DDR, used the last available LAWs */
214int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
215{
216 u64 start_align, law_sz;
217 int law_sz_enc;
218
219 if (start == 0)
220 start_align = 1ull << (LAW_SIZE_32G + 1);
221 else
222 start_align = 1ull << (ffs64(start) - 1);
223 law_sz = min(start_align, sz);
224 law_sz_enc = __ilog2_u64(law_sz) - 1;
225
226 if (set_last_law(start, law_sz_enc, id) < 0)
227 return -1;
228
Kumar Gala894cc882009-04-04 10:21:02 -0500229 /* recalculate size based on what was actually covered by the law */
230 law_sz = 1ull << __ilog2_u64(law_sz);
231
Kumar Gala61ed0532008-08-26 15:01:28 -0500232 /* do we still have anything to map */
233 sz = sz - law_sz;
234 if (sz) {
235 start += law_sz;
236
237 start_align = 1ull << (ffs64(start) - 1);
238 law_sz = min(start_align, sz);
239 law_sz_enc = __ilog2_u64(law_sz) - 1;
240
241 if (set_last_law(start, law_sz_enc, id) < 0)
242 return -1;
243 } else {
244 return 0;
245 }
246
247 /* do we still have anything to map */
248 sz = sz - law_sz;
249 if (sz)
250 return 1;
251
252 return 0;
253}
Mingkai Hu0255cd72009-09-11 14:19:10 +0800254#endif
Kumar Gala61ed0532008-08-26 15:01:28 -0500255
Kumar Gala95fd2f62008-01-16 01:13:58 -0600256void init_laws(void)
257{
258 int i;
Kumar Gala95fd2f62008-01-16 01:13:58 -0600259
Kumar Gala65e6c322009-03-19 02:32:23 -0500260#if FSL_HW_NUM_LAWS < 32
Kumar Gala75639e02008-06-11 00:44:10 -0500261 gd->used_laws = ~((1 << FSL_HW_NUM_LAWS) - 1);
Kumar Gala65e6c322009-03-19 02:32:23 -0500262#elif FSL_HW_NUM_LAWS == 32
263 gd->used_laws = 0;
264#else
265#error FSL_HW_NUM_LAWS can not be greater than 32 w/o code changes
266#endif
Kumar Gala95fd2f62008-01-16 01:13:58 -0600267
Kumar Gala75639e02008-06-11 00:44:10 -0500268 for (i = 0; i < num_law_entries; i++) {
269 if (law_table[i].index == -1)
270 set_next_law(law_table[i].addr, law_table[i].size,
271 law_table[i].trgt_id);
272 else
273 set_law(law_table[i].index, law_table[i].addr,
274 law_table[i].size, law_table[i].trgt_id);
Kumar Gala95fd2f62008-01-16 01:13:58 -0600275 }
276
277 return ;
278}