1 /*
2  * Copyright (c) 2011 Aeroflex Gaisler
3  *
4  * BSD license:
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 
26 #include <asm-leon/leon.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 /*#define DEBUG_CONFIG*/
32 
33 /* Structure containing address to devices found on the Amba Plug&Play bus */
34 amba_confarea_type amba_conf;
35 
36 /* Pointers to Interrupt Controller configuration registers */
37 volatile LEON3_IrqCtrl_Regs_Map *LEON3_IrqCtrl_Regs = 0;
38 volatile LEON3_GpTimer_Regs_Map *LEON3_GpTimer_Regs = 0;
39 unsigned long LEON3_GpTimer_Irq = 0;
40 
41 unsigned long
amba_find_apbslv_addr(unsigned long vendor,unsigned long device,unsigned long * irq)42 amba_find_apbslv_addr (unsigned long vendor, unsigned long device,
43 		       unsigned long *irq)
44 {
45   unsigned int i, conf, iobar;
46   for (i = 0; i < amba_conf.apbslv.devnr; i++)
47     {
48       conf = amba_get_confword (amba_conf.apbslv, i, 0);
49       if ((amba_vendor (conf) == vendor) && (amba_device (conf) == device))
50 	{
51 	  if (irq)
52 	    {
53 	      *irq = amba_irq (conf);
54 	    }
55 	  iobar = amba_apb_get_membar (amba_conf.apbslv, i);
56 	  return amba_iobar_start (amba_conf.apbslv.apbmst[i], iobar);
57 	}
58     }
59   return 0;
60 }
61 
62 #define amba_insert_device(tab, address) do {				\
63     if (LEON3_BYPASS_LOAD_PA(address)) {				\
64       (tab)->addr[(tab)->devnr] = (address);				\
65       (tab)->devnr ++;							\
66     }									\
67   } while(0)
68 
69 #define amba_insert_apb_device(tab, address, apbmst, idx) do {		\
70     if (*(address)) {							\
71       (tab)->addr[(tab)->devnr] = (address);				\
72       (tab)->apbmst[(tab)->devnr] = (apbmst);				\
73       (tab)->apbmstidx[(tab)->devnr] = (idx);				\
74       (tab)->devnr ++;							\
75     }									\
76   } while(0)
77 
78 /*
79  *  Used to scan system bus. Probes for AHB masters, AHB slaves and
80  *  APB slaves. Addresses to configuration areas of the AHB masters,
81  *  AHB slaves, APB slaves and APB master are storeds in
82  *  amba_ahb_masters, amba_ahb_slaves and amba.
83  */
84 
85 int amba_init_done = 0;
86 
87 void
amba_init(void)88 amba_init (void)
89 {
90   unsigned int *cfg_area;	/* address to configuration area */
91   unsigned int mbar, conf, apbmst;
92   int i, j, idx = 0;
93 
94   if (amba_init_done)
95     {
96       return;
97     }
98   amba_init_done = 1;
99 
100   memset (&amba_conf, 0, sizeof (amba_conf));
101   /*amba_conf.ahbmst.devnr = 0; amba_conf.ahbslv.devnr = 0; amba_conf.apbslv.devnr = 0; */
102 
103   cfg_area = (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA);
104 
105   for (i = 0; i < LEON3_AHB_MASTERS; i++)
106     {
107       amba_insert_device (&amba_conf.ahbmst, cfg_area);
108       cfg_area += LEON3_AHB_CONF_WORDS;
109     }
110 
111   cfg_area =
112     (unsigned int *) (LEON3_IO_AREA | LEON3_CONF_AREA |
113 		      LEON3_AHB_SLAVE_CONF_AREA);
114   for (i = 0; i < LEON3_AHB_SLAVES; i++)
115     {
116       amba_insert_device (&amba_conf.ahbslv, cfg_area);
117       cfg_area += LEON3_AHB_CONF_WORDS;
118     }
119 
120   for (i = 0; i < amba_conf.ahbslv.devnr; i++)
121     {
122       conf = amba_get_confword (amba_conf.ahbslv, i, 0);
123       mbar = amba_ahb_get_membar (amba_conf.ahbslv, i, 0);
124       if ((amba_vendor (conf) == VENDOR_GAISLER)
125 	  && (amba_device (conf) == GAISLER_APBMST))
126 	{
127 	  int k;
128 	  /*amba_conf.apbmst = */ apbmst = amba_membar_start (mbar);
129 	  cfg_area = (unsigned int *) (apbmst | LEON3_CONF_AREA);
130 
131 	  for (j = amba_conf.apbslv.devnr, k = 0;
132 	       j < AMBA_MAXAPB_DEVS && k < AMBA_MAXAPB_DEVS_PERBUS; j++, k++)
133 	    {
134 	      amba_insert_apb_device (&amba_conf.apbslv, cfg_area, apbmst,
135 				      idx);
136 	      cfg_area += LEON3_APB_CONF_WORDS;
137 	    }
138 	  idx++;
139 	}
140     }
141 
142   /* Find LEON3 Interrupt controler */
143   LEON3_IrqCtrl_Regs = (volatile LEON3_IrqCtrl_Regs_Map *)
144     amba_find_apbslv_addr (VENDOR_GAISLER, GAISLER_IRQMP, 0);
145   LEON3_GpTimer_Regs = (volatile LEON3_GpTimer_Regs_Map *)
146     amba_find_apbslv_addr (VENDOR_GAISLER, GAISLER_GPTIMER,
147 			   &LEON3_GpTimer_Irq);
148   if (LEON3_IrqCtrl_Regs)
149     {
150       LEON3_BYPASS_STORE_PA (&(LEON3_IrqCtrl_Regs->mask[0]), 0);
151     }
152 }
153