1 /* GRLIB AMBA Plug&Play information scanning, relies on assembler
4 * (C) Copyright 2010, 2015
5 * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
7 * SPDX-License-Identifier: GPL-2.0+
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 */
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 */
34 extern void ambapp_find_buses(unsigned int ioarea
, struct ambapp_bus
*abus
);
36 extern int ambapp_find_apb(struct ambapp_bus
*abus
, unsigned int dev_vend
,
37 int index
, struct ambapp_find_apb_info
*result
);
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
);
42 /************ C ROUTINES USED BY U-BOOT AMBA CORE DRIVERS ************/
43 struct ambapp_bus ambapp_plb
;
48 struct ambapp_bus
*abus
)
52 ambapp_find_buses(ioarea
, abus
);
53 for (i
= 0; i
< 6; i
++)
54 if (abus
->ioareas
[i
] == 0)
60 /* Parse APB PnP Information */
61 void ambapp_apb_parse(struct ambapp_find_apb_info
*info
, ambapp_apbdev
*dev
)
63 struct ambapp_pnp_apb
*apb
= info
->pnp
;
64 unsigned int apbbase
= (unsigned int)apb
& 0xfff00000;
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;
76 /* Parse AHB PnP information */
77 void ambapp_ahb_parse(struct ambapp_find_ahb_info
*info
, ambapp_ahbdev
*dev
)
79 struct ambapp_pnp_ahb
*ahb
= info
->pnp
;
80 unsigned int ahbbase
= (unsigned int)ahb
& 0xfff00000;
82 unsigned int addr
, mask
, mbar
;
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
++) {
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;
101 /* AHB memory area, absolute address */
102 mask
= (~((unsigned int)
103 (amba_membar_mask(mbar
)<<20)))+1;
105 dev
->address
[i
] = addr
;
111 int ambapp_apb_find(struct ambapp_bus
*abus
, int vendor
, int device
,
112 int index
, ambapp_apbdev
*dev
)
114 unsigned int devid
= AMBA_PNP_ID(vendor
, device
);
116 struct ambapp_find_apb_info apbdev
;
118 found
= ambapp_find_apb(abus
, devid
, index
, &apbdev
);
120 ambapp_apb_parse(&apbdev
, dev
);
125 int ambapp_apb_count(struct ambapp_bus
*abus
, int vendor
, int device
)
127 unsigned int devid
= AMBA_PNP_ID(vendor
, device
);
129 struct ambapp_find_apb_info apbdev
;
131 found
= ambapp_find_apb(abus
, devid
, 63, &apbdev
);
135 return 63 - apbdev
.dec_index
;
138 int ambapp_ahb_find(struct ambapp_bus
*abus
, int vendor
, int device
,
139 int index
, ambapp_ahbdev
*dev
, int type
)
142 struct ambapp_find_ahb_info ahbdev
;
143 unsigned int devid
= AMBA_PNP_ID(vendor
, device
);
145 found
= ambapp_find_ahb(abus
, devid
, index
, type
, &ahbdev
);
147 ambapp_ahb_parse(&ahbdev
, dev
);
152 int ambapp_ahbmst_find(struct ambapp_bus
*abus
, int vendor
, int device
,
153 int index
, ambapp_ahbdev
*dev
)
155 return ambapp_ahb_find(abus
, vendor
, device
, index
, dev
, DEV_AHB_MST
);
158 int ambapp_ahbslv_find(struct ambapp_bus
*abus
, int vendor
, int device
,
159 int index
, ambapp_ahbdev
*dev
)
161 return ambapp_ahb_find(abus
, vendor
, device
, index
, dev
, DEV_AHB_SLV
);
164 int ambapp_ahb_count(struct ambapp_bus
*abus
, int vendor
, int device
, int type
)
167 struct ambapp_find_ahb_info ahbdev
;
168 unsigned int devid
= AMBA_PNP_ID(vendor
, device
);
170 found
= ambapp_find_ahb(abus
, devid
, 63, type
, &ahbdev
);
174 return 63 - ahbdev
.dec_index
;
177 int ambapp_ahbmst_count(struct ambapp_bus
*abus
, int vendor
, int device
)
179 return ambapp_ahb_count(abus
, vendor
, device
, DEV_AHB_MST
);
182 int ambapp_ahbslv_count(struct ambapp_bus
*abus
, int vendor
, int device
)
184 return ambapp_ahb_count(abus
, vendor
, device
, DEV_AHB_SLV
);
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.
191 * Defining this on a multi-bus GRLIB system may also work depending on the
195 #ifndef CONFIG_SYS_GRLIB_SINGLE_BUS
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 */
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.
206 unsigned int gaisler_ahb2ahb_v1_freq(ambapp_ahbdev
*ahb
, unsigned int freq
)
211 /* Get division/multiple factor */
212 ffact
= (ahb
->userdef
[0] & AHB2AHB_V1_FLAG_FFACT
) >> 4;
214 dir
= ahb
->userdef
[0] & AHB2AHB_V1_FLAG_FFACT_DIR
;
216 /* Calculate frequency by dividing or
217 * multiplying system frequency
228 /* AHB2AHB and L2CACHE ver 2 is not supported yet. */
229 unsigned int gaisler_ahb2ahb_v2_freq(ambapp_ahbdev
*ahb
, unsigned int freq
)
231 panic("gaisler_ahb2ahb_v2_freq: AHB2AHB ver 2 not supported\n");
236 /* Return the frequency of a AHB bus identified by index found
237 * note that this is not the AHB Bus number.
239 unsigned int ambapp_bus_freq(struct ambapp_bus
*abus
, int ahb_bus_index
)
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
;
248 debug("ambapp_bus_freq: get freq on bus %d\n", ahb_bus_index
);
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]);
258 /* Get I/O area of AHB bus */
259 ioarea
= abus
->ioareas
[ahb_bus_index
];
261 debug(" IOAREA: 0x%08x\n", ioarea
);
264 parent
= (ioarea
& 0x7);
266 panic("%s: parent=0 indicates no parent! Stopping.\n",
271 bridge_pnp_ofs
= ioarea
& 0x7e0;
273 debug(" PARENT: %d\n", parent
);
274 debug(" BRIDGE_OFS: 0x%08x\n", bridge_pnp_ofs
);
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
);
282 debug(" IOAREA PARENT: 0x%08x\n", ioarea_parent
);
283 debug(" BRIDGE PNP: 0x%p\n", ahbinfo
.pnp
);
285 /* Parse the AHB information */
286 ahbinfo
.ahb_bus_index
= parent
;
287 ambapp_ahb_parse(&ahbinfo
, &ahb
);
289 debug(" BRIDGE ID: VENDOR=%d(0x%x), DEVICE=%d(0x%x)\n",
290 ahb
.vendor
, ahb
.vendor
, ahb
.device
, ahb
.device
);
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 */
298 freq
= gaisler_ahb2ahb_v2_freq(&ahb
, freq
);
300 freq
= gaisler_ahb2ahb_v1_freq(&ahb
, freq
);
302 debug(" NEW FREQ: %dHz\n", freq
);
304 panic("%s: unsupported AMBA bridge\n", __func__
);
308 /* Step upwards towards system top bus */
309 ahb_bus_index
= parent
;
313 debug("ambapp_bus_freq: %dHz\n", freq
);