]> git.sur5r.net Git - u-boot/blob - arch/sparc/cpu/leon3/ambapp.c
sparc: leon3: Added memory controller initialization using new AMBA PnP routines.
[u-boot] / arch / sparc / cpu / leon3 / ambapp.c
1 /* GRLIB AMBA Plug&Play information scanning, relies on assembler
2  * routines.
3  *
4  * (C) Copyright 2010, 2015
5  * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
6  *
7  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 /* #define DEBUG */
11
12 #include <common.h>
13 #include <ambapp.h>
14 #include <config.h>
15
16 /************ C INTERFACE OF ASSEMBLER SCAN ROUTINES ************/
17 struct ambapp_find_apb_info {
18         /* Address of APB device Plug&Play information */
19         struct ambapp_pnp_apb   *pnp;
20         /* AHB Bus index of where the APB-Master Bridge device was found */
21         int                     ahb_bus_index;
22         int                     dec_index;
23 };
24
25 struct ambapp_find_ahb_info {
26         /* Address of AHB device Plug&Play information */
27         struct ambapp_pnp_ahb   *pnp;
28         /* AHB Bus index of where the AHB device was found */
29         int                     ahb_bus_index;
30         int                     dec_index;
31 };
32
33 extern void ambapp_find_buses(unsigned int ioarea, struct ambapp_bus *abus);
34
35 extern int ambapp_find_apb(struct ambapp_bus *abus, unsigned int dev_vend,
36         int index, struct ambapp_find_apb_info *result);
37
38 extern int ambapp_find_ahb(struct ambapp_bus *abus, unsigned int dev_vend,
39         int index, int type, struct ambapp_find_ahb_info *result);
40
41 /************ C ROUTINES USED BY U-BOOT AMBA CORE DRIVERS ************/
42 struct ambapp_bus ambapp_plb;
43
44 void ambapp_bus_init(
45         unsigned int ioarea,
46         unsigned int freq,
47         struct ambapp_bus *abus)
48 {
49         int i;
50
51         ambapp_find_buses(ioarea, abus);
52         for (i = 0; i < 6; i++)
53                 if (abus->ioareas[i] == 0)
54                         break;
55         abus->buses = i;
56         abus->freq = freq;
57 }
58
59 /* Parse APB PnP Information */
60 void ambapp_apb_parse(struct ambapp_find_apb_info *info, ambapp_apbdev *dev)
61 {
62         struct ambapp_pnp_apb *apb = info->pnp;
63         unsigned int apbbase = (unsigned int)apb & 0xfff00000;
64
65         dev->vendor = amba_vendor(apb->id);
66         dev->device = amba_device(apb->id);
67         dev->irq = amba_irq(apb->id);
68         dev->ver = amba_ver(apb->id);
69         dev->address = (apbbase | (((apb->iobar & 0xfff00000) >> 12))) &
70                         (((apb->iobar & 0x0000fff0) << 4) | 0xfff00000);
71         dev->mask = amba_apb_mask(apb->iobar);
72         dev->ahb_bus_index = info->ahb_bus_index - 1;
73 }
74
75 /* Parse AHB PnP information */
76 void ambapp_ahb_parse(struct ambapp_find_ahb_info *info, ambapp_ahbdev *dev)
77 {
78         struct ambapp_pnp_ahb *ahb = info->pnp;
79         unsigned int ahbbase = (unsigned int)ahb & 0xfff00000;
80         int i, type;
81         unsigned int addr, mask, mbar;
82
83         dev->vendor = amba_vendor(ahb->id);
84         dev->device = amba_device(ahb->id);
85         dev->irq = amba_irq(ahb->id);
86         dev->ver = amba_ver(ahb->id);
87         dev->userdef[0] = ahb->custom[0];
88         dev->userdef[1] = ahb->custom[1];
89         dev->userdef[2] = ahb->custom[2];
90         dev->ahb_bus_index = info->ahb_bus_index - 1;
91         for (i = 0; i < 4; i++) {
92                 mbar = ahb->mbar[i];
93                 addr = amba_membar_start(mbar);
94                 type = amba_membar_type(mbar);
95                 if (type == AMBA_TYPE_AHBIO) {
96                         addr = amba_ahbio_adr(addr, ahbbase);
97                         mask = (((unsigned int)
98                                 (amba_membar_mask((~mbar))<<8)|0xff))+1;
99                 } else {
100                         /* AHB memory area, absolute address */
101                         mask = (~((unsigned int)
102                                 (amba_membar_mask(mbar)<<20)))+1;
103                 }
104                 dev->address[i] = addr;
105                 dev->mask[i] = mask;
106                 dev->type[i] = type;
107         }
108 }
109
110 int ambapp_apb_find(struct ambapp_bus *abus, int vendor, int device,
111         int index, ambapp_apbdev *dev)
112 {
113         unsigned int devid = AMBA_PNP_ID(vendor, device);
114         int found;
115         struct ambapp_find_apb_info apbdev;
116
117         found = ambapp_find_apb(abus, devid, index, &apbdev);
118         if (found == 1)
119                 ambapp_apb_parse(&apbdev, dev);
120
121         return found;
122 }
123
124 int ambapp_apb_count(struct ambapp_bus *abus, int vendor, int device)
125 {
126         unsigned int devid = AMBA_PNP_ID(vendor, device);
127         int found;
128         struct ambapp_find_apb_info apbdev;
129
130         found = ambapp_find_apb(abus, devid, 63, &apbdev);
131         if (found == 1)
132                 return 64;
133         else
134                 return 63 - apbdev.dec_index;
135 }
136
137 int ambapp_ahb_find(struct ambapp_bus *abus, int vendor, int device,
138         int index, ambapp_ahbdev *dev, int type)
139 {
140         int found;
141         struct ambapp_find_ahb_info ahbdev;
142         unsigned int devid = AMBA_PNP_ID(vendor, device);
143
144         found = ambapp_find_ahb(abus, devid, index, type, &ahbdev);
145         if (found == 1)
146                 ambapp_ahb_parse(&ahbdev, dev);
147
148         return found;
149 }
150
151 int ambapp_ahbmst_find(struct ambapp_bus *abus, int vendor, int device,
152         int index, ambapp_ahbdev *dev)
153 {
154         return ambapp_ahb_find(abus, vendor, device, index, dev, DEV_AHB_MST);
155 }
156
157 int ambapp_ahbslv_find(struct ambapp_bus *abus, int vendor, int device,
158         int index, ambapp_ahbdev *dev)
159 {
160         return ambapp_ahb_find(abus, vendor, device, index, dev, DEV_AHB_SLV);
161 }
162
163 int ambapp_ahb_count(struct ambapp_bus *abus, int vendor, int device, int type)
164 {
165         int found;
166         struct ambapp_find_ahb_info ahbdev;
167         unsigned int devid = AMBA_PNP_ID(vendor, device);
168
169         found = ambapp_find_ahb(abus, devid, 63, type, &ahbdev);
170         if (found == 1)
171                 return 64;
172         else
173                 return 63 - ahbdev.dec_index;
174 }
175
176 int ambapp_ahbmst_count(struct ambapp_bus *abus, int vendor, int device)
177 {
178         return ambapp_ahb_count(abus, vendor, device, DEV_AHB_MST);
179 }
180
181 int ambapp_ahbslv_count(struct ambapp_bus *abus, int vendor, int device)
182 {
183         return ambapp_ahb_count(abus, vendor, device, DEV_AHB_SLV);
184 }
185
186 /* The define CONFIG_SYS_GRLIB_SINGLE_BUS may be defined on GRLIB systems
187  * where only one AHB Bus is available - no bridges are present. This option
188  * is available only to reduce the footprint.
189  *
190  * Defining this on a multi-bus GRLIB system may also work depending on the
191  * design.
192  */
193
194 #ifndef CONFIG_SYS_GRLIB_SINGLE_BUS
195
196 /* GAISLER AHB2AHB Version 1 Bridge Definitions */
197 #define AHB2AHB_V1_FLAG_FFACT     0x0f0 /* Frequency factor against top bus */
198 #define AHB2AHB_V1_FLAG_FFACT_DIR 0x100 /* Factor direction, 0=down, 1=up */
199 #define AHB2AHB_V1_FLAG_MBUS      0x00c /* Master bus number mask */
200 #define AHB2AHB_V1_FLAG_SBUS      0x003 /* Slave bus number mask */
201
202 /* Get Parent bus frequency. Note that since we go from a "child" bus
203  * to a parent bus, the frequency factor direction is inverted.
204  */
205 unsigned int gaisler_ahb2ahb_v1_freq(ambapp_ahbdev *ahb, unsigned int freq)
206 {
207         int dir;
208         unsigned char ffact;
209
210         /* Get division/multiple factor */
211         ffact = (ahb->userdef[0] & AHB2AHB_V1_FLAG_FFACT) >> 4;
212         if (ffact != 0) {
213                 dir = ahb->userdef[0] & AHB2AHB_V1_FLAG_FFACT_DIR;
214
215                 /* Calculate frequency by dividing or
216                  * multiplying system frequency
217                  */
218                 if (dir)
219                         freq = freq * ffact;
220                 else
221                         freq = freq / ffact;
222         }
223
224         return freq;
225 }
226
227 /* AHB2AHB and L2CACHE ver 2 is not supported yet. */
228 unsigned int gaisler_ahb2ahb_v2_freq(ambapp_ahbdev *ahb, unsigned int freq)
229 {
230         panic("gaisler_ahb2ahb_v2_freq: AHB2AHB ver 2 not supported\n");
231         return -1;
232 }
233 #endif
234
235 /* Return the frequency of a AHB bus identified by index found
236  * note that this is not the AHB Bus number.
237  */
238 unsigned int ambapp_bus_freq(struct ambapp_bus *abus, int ahb_bus_index)
239 {
240         unsigned int freq = abus->freq;
241 #ifndef CONFIG_SYS_GRLIB_SINGLE_BUS
242         unsigned int ioarea, ioarea_parent, bridge_pnp_ofs;
243         struct ambapp_find_ahb_info ahbinfo;
244         ambapp_ahbdev ahb;
245         int parent;
246
247         debug("ambapp_bus_freq: get freq on bus %d\n", ahb_bus_index);
248
249         while (ahb_bus_index != 0) {
250                 debug("  BUS[0]: 0x%08x\n", abus->ioareas[0]);
251                 debug("  BUS[1]: 0x%08x\n", abus->ioareas[1]);
252                 debug("  BUS[2]: 0x%08x\n", abus->ioareas[2]);
253                 debug("  BUS[3]: 0x%08x\n", abus->ioareas[3]);
254                 debug("  BUS[4]: 0x%08x\n", abus->ioareas[4]);
255                 debug("  BUS[5]: 0x%08x\n", abus->ioareas[5]);
256
257                 /* Get I/O area of AHB bus */
258                 ioarea = abus->ioareas[ahb_bus_index];
259
260                 printf("  IOAREA: 0x%08x\n", ioarea);
261
262                 /* Get parent bus */
263                 parent = (ioarea & 0x7);
264                 if (parent == 0) {
265                         panic("%s: parent=0 indicates no parent! Stopping.\n",
266                                 __func__);
267                         return -1;
268                 }
269                 parent = parent - 1;
270                 bridge_pnp_ofs = ioarea & 0x7e0;
271
272                 debug("  PARENT: %d\n", parent);
273                 debug("  BRIDGE_OFS: 0x%08x\n", bridge_pnp_ofs);
274
275                 /* Get AHB/AHB bridge PnP address */
276                 ioarea_parent = (abus->ioareas[parent] & 0xfff00000) |
277                                 AMBA_CONF_AREA | AMBA_AHB_SLAVE_CONF_AREA;
278                 ahbinfo.pnp = (struct ambapp_pnp_ahb *)
279                                 (ioarea_parent | bridge_pnp_ofs);
280
281                 debug("  IOAREA PARENT: 0x%08x\n", ioarea_parent);
282                 debug("  BRIDGE PNP: 0x%p\n", ahbinfo.pnp);
283
284                 /* Parse the AHB information */
285                 ahbinfo.ahb_bus_index = parent;
286                 ambapp_ahb_parse(&ahbinfo, &ahb);
287
288                 debug("  BRIDGE ID: VENDOR=%d(0x%x), DEVICE=%d(0x%x)\n",
289                         ahb.vendor, ahb.vendor, ahb.device, ahb.device);
290
291                 /* Different bridges may convert frequency differently */
292                 if ((ahb.vendor == VENDOR_GAISLER) &&
293                         ((ahb.device == GAISLER_AHB2AHB) ||
294                         (ahb.device == GAISLER_L2CACHE))) {
295                         /* Get new frequency */
296                         if (ahb.ver > 1)
297                                 freq = gaisler_ahb2ahb_v2_freq(&ahb, freq);
298                         else
299                                 freq = gaisler_ahb2ahb_v1_freq(&ahb, freq);
300
301                         debug("  NEW FREQ: %dHz\n", freq);
302                 } else {
303                         panic("%s: unsupported AMBA bridge\n", __func__);
304                         return -1;
305                 }
306
307                 /* Step upwards towards system top bus */
308                 ahb_bus_index = parent;
309         }
310 #endif
311
312         debug("ambapp_bus_freq: %dHz\n", freq);
313
314         return freq;
315 }