blob: 47769cffd70a333bc80f07b98a4ecbf36e806ec1 [file] [log] [blame]
Daniel Hellstrom898cc812010-01-25 09:54:51 +01001/* GRLIB AMBA Plug&Play information scanning, relies on assembler
2 * routines.
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +01003 *
Daniel Hellstrom898cc812010-01-25 09:54:51 +01004 * (C) Copyright 2010, 2015
5 * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +01006 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02007 * SPDX-License-Identifier: GPL-2.0+
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +01008 */
9
Daniel Hellstrom898cc812010-01-25 09:54:51 +010010/* #define DEBUG */
11
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010012#include <common.h>
Daniel Hellstrom57860712010-09-20 10:00:49 +020013#include <malloc.h>
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010014#include <ambapp.h>
Daniel Hellstrom898cc812010-01-25 09:54:51 +010015#include <config.h>
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010016
Daniel Hellstrom898cc812010-01-25 09:54:51 +010017/************ C INTERFACE OF ASSEMBLER SCAN ROUTINES ************/
18struct 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;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010024};
25
Daniel Hellstrom898cc812010-01-25 09:54:51 +010026struct 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
34extern void ambapp_find_buses(unsigned int ioarea, struct ambapp_bus *abus);
35
36extern int ambapp_find_apb(struct ambapp_bus *abus, unsigned int dev_vend,
37 int index, struct ambapp_find_apb_info *result);
38
39extern 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 ************/
Francois Retief574be252015-10-29 12:58:52 +020043struct ambapp_bus ambapp_plb __section(.data);
Daniel Hellstrom898cc812010-01-25 09:54:51 +010044
45void 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 */
61void 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 */
77void 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
111int 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
125int 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
138int 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
152int 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
158int 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
164int 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
177int 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
182int 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.
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100190 *
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100191 * Defining this on a multi-bus GRLIB system may also work depending on the
192 * design.
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100193 */
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100194
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 */
206unsigned int gaisler_ahb2ahb_v1_freq(ambapp_ahbdev *ahb, unsigned int freq)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100207{
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100208 int dir;
209 unsigned char ffact;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100210
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100211 /* 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;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100215
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100216 /* Calculate frequency by dividing or
217 * multiplying system frequency
218 */
219 if (dir)
220 freq = freq * ffact;
221 else
222 freq = freq / ffact;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100223 }
224
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100225 return freq;
226}
227
228/* AHB2AHB and L2CACHE ver 2 is not supported yet. */
229unsigned 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}
Daniel Hellstrom2a2fa792008-03-26 23:00:38 +0100234#endif
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100235
236/* Return the frequency of a AHB bus identified by index found
237 * note that this is not the AHB Bus number.
238 */
239unsigned 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
Daniel Hellstrom57860712010-09-20 10:00:49 +0200261 debug(" IOAREA: 0x%08x\n", ioarea);
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100262
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;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100269 }
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100270 parent = parent - 1;
271 bridge_pnp_ofs = ioarea & 0x7e0;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100272
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100273 debug(" PARENT: %d\n", parent);
274 debug(" BRIDGE_OFS: 0x%08x\n", bridge_pnp_ofs);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100275
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100276 /* 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);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100281
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100282 debug(" IOAREA PARENT: 0x%08x\n", ioarea_parent);
283 debug(" BRIDGE PNP: 0x%p\n", ahbinfo.pnp);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100284
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100285 /* Parse the AHB information */
286 ahbinfo.ahb_bus_index = parent;
287 ambapp_ahb_parse(&ahbinfo, &ahb);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100288
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100289 debug(" BRIDGE ID: VENDOR=%d(0x%x), DEVICE=%d(0x%x)\n",
290 ahb.vendor, ahb.vendor, ahb.device, ahb.device);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100291
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100292 /* 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);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100301
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100302 debug(" NEW FREQ: %dHz\n", freq);
303 } else {
304 panic("%s: unsupported AMBA bridge\n", __func__);
305 return -1;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100306 }
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100307
308 /* Step upwards towards system top bus */
309 ahb_bus_index = parent;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100310 }
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100311#endif
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100312
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100313 debug("ambapp_bus_freq: %dHz\n", freq);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100314
Daniel Hellstrom898cc812010-01-25 09:54:51 +0100315 return freq;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100316}