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