diff options
Diffstat (limited to 'drivers/bcma')
-rw-r--r-- | drivers/bcma/Kconfig | 13 | ||||
-rw-r--r-- | drivers/bcma/Makefile | 2 | ||||
-rw-r--r-- | drivers/bcma/bcma_private.h | 16 | ||||
-rw-r--r-- | drivers/bcma/core.c | 2 | ||||
-rw-r--r-- | drivers/bcma/driver_chipcommon.c | 53 | ||||
-rw-r--r-- | drivers/bcma/driver_chipcommon_pmu.c | 133 | ||||
-rw-r--r-- | drivers/bcma/driver_mips.c | 256 | ||||
-rw-r--r-- | drivers/bcma/driver_pci.c | 16 | ||||
-rw-r--r-- | drivers/bcma/host_soc.c | 183 | ||||
-rw-r--r-- | drivers/bcma/main.c | 70 | ||||
-rw-r--r-- | drivers/bcma/scan.c | 348 |
11 files changed, 978 insertions, 114 deletions
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index ae0a02e1b808..c1172dafdffa 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig | |||
@@ -33,6 +33,19 @@ config BCMA_DRIVER_PCI_HOSTMODE | |||
33 | help | 33 | help |
34 | PCI core hostmode operation (external PCI bus). | 34 | PCI core hostmode operation (external PCI bus). |
35 | 35 | ||
36 | config BCMA_HOST_SOC | ||
37 | bool | ||
38 | depends on BCMA_DRIVER_MIPS | ||
39 | |||
40 | config BCMA_DRIVER_MIPS | ||
41 | bool "BCMA Broadcom MIPS core driver" | ||
42 | depends on BCMA && MIPS | ||
43 | help | ||
44 | Driver for the Broadcom MIPS core attached to Broadcom specific | ||
45 | Advanced Microcontroller Bus. | ||
46 | |||
47 | If unsure, say N | ||
48 | |||
36 | config BCMA_DEBUG | 49 | config BCMA_DEBUG |
37 | bool "BCMA debugging" | 50 | bool "BCMA debugging" |
38 | depends on BCMA | 51 | depends on BCMA |
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index a2161cceafb9..82de24e5340c 100644 --- a/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile | |||
@@ -2,7 +2,9 @@ bcma-y += main.o scan.o core.o sprom.o | |||
2 | bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o | 2 | bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o |
3 | bcma-y += driver_pci.o | 3 | bcma-y += driver_pci.o |
4 | bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o | 4 | bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o |
5 | bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o | ||
5 | bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o | 6 | bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o |
7 | bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o | ||
6 | obj-$(CONFIG_BCMA) += bcma.o | 8 | obj-$(CONFIG_BCMA) += bcma.o |
7 | 9 | ||
8 | ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG | 10 | ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG |
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index e02ff21835c9..30a3085d3354 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h | |||
@@ -15,13 +15,29 @@ struct bcma_bus; | |||
15 | /* main.c */ | 15 | /* main.c */ |
16 | int bcma_bus_register(struct bcma_bus *bus); | 16 | int bcma_bus_register(struct bcma_bus *bus); |
17 | void bcma_bus_unregister(struct bcma_bus *bus); | 17 | void bcma_bus_unregister(struct bcma_bus *bus); |
18 | int __init bcma_bus_early_register(struct bcma_bus *bus, | ||
19 | struct bcma_device *core_cc, | ||
20 | struct bcma_device *core_mips); | ||
18 | 21 | ||
19 | /* scan.c */ | 22 | /* scan.c */ |
20 | int bcma_bus_scan(struct bcma_bus *bus); | 23 | int bcma_bus_scan(struct bcma_bus *bus); |
24 | int __init bcma_bus_scan_early(struct bcma_bus *bus, | ||
25 | struct bcma_device_id *match, | ||
26 | struct bcma_device *core); | ||
27 | void bcma_init_bus(struct bcma_bus *bus); | ||
21 | 28 | ||
22 | /* sprom.c */ | 29 | /* sprom.c */ |
23 | int bcma_sprom_get(struct bcma_bus *bus); | 30 | int bcma_sprom_get(struct bcma_bus *bus); |
24 | 31 | ||
32 | /* driver_chipcommon.c */ | ||
33 | #ifdef CONFIG_BCMA_DRIVER_MIPS | ||
34 | void bcma_chipco_serial_init(struct bcma_drv_cc *cc); | ||
35 | #endif /* CONFIG_BCMA_DRIVER_MIPS */ | ||
36 | |||
37 | /* driver_chipcommon_pmu.c */ | ||
38 | u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc); | ||
39 | u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc); | ||
40 | |||
25 | #ifdef CONFIG_BCMA_HOST_PCI | 41 | #ifdef CONFIG_BCMA_HOST_PCI |
26 | /* host_pci.c */ | 42 | /* host_pci.c */ |
27 | extern int __init bcma_host_pci_init(void); | 43 | extern int __init bcma_host_pci_init(void); |
diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c index 4a04a49cc06d..189a97b51be9 100644 --- a/drivers/bcma/core.c +++ b/drivers/bcma/core.c | |||
@@ -110,6 +110,8 @@ EXPORT_SYMBOL_GPL(bcma_core_pll_ctl); | |||
110 | u32 bcma_core_dma_translation(struct bcma_device *core) | 110 | u32 bcma_core_dma_translation(struct bcma_device *core) |
111 | { | 111 | { |
112 | switch (core->bus->hosttype) { | 112 | switch (core->bus->hosttype) { |
113 | case BCMA_HOSTTYPE_SOC: | ||
114 | return 0; | ||
113 | case BCMA_HOSTTYPE_PCI: | 115 | case BCMA_HOSTTYPE_PCI: |
114 | if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64) | 116 | if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64) |
115 | return BCMA_DMA_TRANSLATION_DMA64_CMT; | 117 | return BCMA_DMA_TRANSLATION_DMA64_CMT; |
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 851e05bc948a..47cce9d69630 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c | |||
@@ -26,6 +26,9 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) | |||
26 | u32 leddc_on = 10; | 26 | u32 leddc_on = 10; |
27 | u32 leddc_off = 90; | 27 | u32 leddc_off = 90; |
28 | 28 | ||
29 | if (cc->setup_done) | ||
30 | return; | ||
31 | |||
29 | if (cc->core->id.rev >= 11) | 32 | if (cc->core->id.rev >= 11) |
30 | cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); | 33 | cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); |
31 | cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); | 34 | cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); |
@@ -52,6 +55,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) | |||
52 | ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | | 55 | ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | |
53 | (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); | 56 | (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); |
54 | } | 57 | } |
58 | |||
59 | cc->setup_done = true; | ||
55 | } | 60 | } |
56 | 61 | ||
57 | /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ | 62 | /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ |
@@ -101,3 +106,51 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value) | |||
101 | { | 106 | { |
102 | return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); | 107 | return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); |
103 | } | 108 | } |
109 | |||
110 | #ifdef CONFIG_BCMA_DRIVER_MIPS | ||
111 | void bcma_chipco_serial_init(struct bcma_drv_cc *cc) | ||
112 | { | ||
113 | unsigned int irq; | ||
114 | u32 baud_base; | ||
115 | u32 i; | ||
116 | unsigned int ccrev = cc->core->id.rev; | ||
117 | struct bcma_serial_port *ports = cc->serial_ports; | ||
118 | |||
119 | if (ccrev >= 11 && ccrev != 15) { | ||
120 | /* Fixed ALP clock */ | ||
121 | baud_base = bcma_pmu_alp_clock(cc); | ||
122 | if (ccrev >= 21) { | ||
123 | /* Turn off UART clock before switching clocksource. */ | ||
124 | bcma_cc_write32(cc, BCMA_CC_CORECTL, | ||
125 | bcma_cc_read32(cc, BCMA_CC_CORECTL) | ||
126 | & ~BCMA_CC_CORECTL_UARTCLKEN); | ||
127 | } | ||
128 | /* Set the override bit so we don't divide it */ | ||
129 | bcma_cc_write32(cc, BCMA_CC_CORECTL, | ||
130 | bcma_cc_read32(cc, BCMA_CC_CORECTL) | ||
131 | | BCMA_CC_CORECTL_UARTCLK0); | ||
132 | if (ccrev >= 21) { | ||
133 | /* Re-enable the UART clock. */ | ||
134 | bcma_cc_write32(cc, BCMA_CC_CORECTL, | ||
135 | bcma_cc_read32(cc, BCMA_CC_CORECTL) | ||
136 | | BCMA_CC_CORECTL_UARTCLKEN); | ||
137 | } | ||
138 | } else { | ||
139 | pr_err("serial not supported on this device ccrev: 0x%x\n", | ||
140 | ccrev); | ||
141 | return; | ||
142 | } | ||
143 | |||
144 | irq = bcma_core_mips_irq(cc->core); | ||
145 | |||
146 | /* Determine the registers of the UARTs */ | ||
147 | cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); | ||
148 | for (i = 0; i < cc->nr_serial_ports; i++) { | ||
149 | ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA + | ||
150 | (i * 256); | ||
151 | ports[i].irq = irq; | ||
152 | ports[i].baud_base = baud_base; | ||
153 | ports[i].reg_shift = 0; | ||
154 | } | ||
155 | } | ||
156 | #endif /* CONFIG_BCMA_DRIVER_MIPS */ | ||
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index fcc63db0ce75..5940c81e7e12 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c | |||
@@ -11,6 +11,13 @@ | |||
11 | #include "bcma_private.h" | 11 | #include "bcma_private.h" |
12 | #include <linux/bcma/bcma.h> | 12 | #include <linux/bcma/bcma.h> |
13 | 13 | ||
14 | static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset) | ||
15 | { | ||
16 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); | ||
17 | bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); | ||
18 | return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA); | ||
19 | } | ||
20 | |||
14 | static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, | 21 | static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, |
15 | u32 offset, u32 mask, u32 set) | 22 | u32 offset, u32 mask, u32 set) |
16 | { | 23 | { |
@@ -136,3 +143,129 @@ void bcma_pmu_init(struct bcma_drv_cc *cc) | |||
136 | bcma_pmu_swreg_init(cc); | 143 | bcma_pmu_swreg_init(cc); |
137 | bcma_pmu_workarounds(cc); | 144 | bcma_pmu_workarounds(cc); |
138 | } | 145 | } |
146 | |||
147 | u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc) | ||
148 | { | ||
149 | struct bcma_bus *bus = cc->core->bus; | ||
150 | |||
151 | switch (bus->chipinfo.id) { | ||
152 | case 0x4716: | ||
153 | case 0x4748: | ||
154 | case 47162: | ||
155 | case 0x4313: | ||
156 | case 0x5357: | ||
157 | case 0x4749: | ||
158 | case 53572: | ||
159 | /* always 20Mhz */ | ||
160 | return 20000 * 1000; | ||
161 | case 0x5356: | ||
162 | case 0x5300: | ||
163 | /* always 25Mhz */ | ||
164 | return 25000 * 1000; | ||
165 | default: | ||
166 | pr_warn("No ALP clock specified for %04X device, " | ||
167 | "pmu rev. %d, using default %d Hz\n", | ||
168 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK); | ||
169 | } | ||
170 | return BCMA_CC_PMU_ALP_CLOCK; | ||
171 | } | ||
172 | |||
173 | /* Find the output of the "m" pll divider given pll controls that start with | ||
174 | * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc. | ||
175 | */ | ||
176 | static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) | ||
177 | { | ||
178 | u32 tmp, div, ndiv, p1, p2, fc; | ||
179 | struct bcma_bus *bus = cc->core->bus; | ||
180 | |||
181 | BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0)); | ||
182 | |||
183 | BUG_ON(!m || m > 4); | ||
184 | |||
185 | if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) { | ||
186 | /* Detect failure in clock setting */ | ||
187 | tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); | ||
188 | if (tmp & 0x40000) | ||
189 | return 133 * 1000000; | ||
190 | } | ||
191 | |||
192 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF); | ||
193 | p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT; | ||
194 | p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT; | ||
195 | |||
196 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF); | ||
197 | div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) & | ||
198 | BCMA_CC_PPL_MDIV_MASK; | ||
199 | |||
200 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF); | ||
201 | ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT; | ||
202 | |||
203 | /* Do calculation in Mhz */ | ||
204 | fc = bcma_pmu_alp_clock(cc) / 1000000; | ||
205 | fc = (p1 * ndiv * fc) / p2; | ||
206 | |||
207 | /* Return clock in Hertz */ | ||
208 | return (fc / div) * 1000000; | ||
209 | } | ||
210 | |||
211 | /* query bus clock frequency for PMU-enabled chipcommon */ | ||
212 | u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc) | ||
213 | { | ||
214 | struct bcma_bus *bus = cc->core->bus; | ||
215 | |||
216 | switch (bus->chipinfo.id) { | ||
217 | case 0x4716: | ||
218 | case 0x4748: | ||
219 | case 47162: | ||
220 | return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, | ||
221 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
222 | case 0x5356: | ||
223 | return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0, | ||
224 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
225 | case 0x5357: | ||
226 | case 0x4749: | ||
227 | return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0, | ||
228 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
229 | case 0x5300: | ||
230 | return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0, | ||
231 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
232 | case 53572: | ||
233 | return 75000000; | ||
234 | default: | ||
235 | pr_warn("No backplane clock specified for %04X device, " | ||
236 | "pmu rev. %d, using default %d Hz\n", | ||
237 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK); | ||
238 | } | ||
239 | return BCMA_CC_PMU_HT_CLOCK; | ||
240 | } | ||
241 | |||
242 | /* query cpu clock frequency for PMU-enabled chipcommon */ | ||
243 | u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc) | ||
244 | { | ||
245 | struct bcma_bus *bus = cc->core->bus; | ||
246 | |||
247 | if (bus->chipinfo.id == 53572) | ||
248 | return 300000000; | ||
249 | |||
250 | if (cc->pmu.rev >= 5) { | ||
251 | u32 pll; | ||
252 | switch (bus->chipinfo.id) { | ||
253 | case 0x5356: | ||
254 | pll = BCMA_CC_PMU5356_MAINPLL_PLL0; | ||
255 | break; | ||
256 | case 0x5357: | ||
257 | case 0x4749: | ||
258 | pll = BCMA_CC_PMU5357_MAINPLL_PLL0; | ||
259 | break; | ||
260 | default: | ||
261 | pll = BCMA_CC_PMU4716_MAINPLL_PLL0; | ||
262 | break; | ||
263 | } | ||
264 | |||
265 | /* TODO: if (bus->chipinfo.id == 0x5300) | ||
266 | return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */ | ||
267 | return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU); | ||
268 | } | ||
269 | |||
270 | return bcma_pmu_get_clockcontrol(cc); | ||
271 | } | ||
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c new file mode 100644 index 000000000000..c3e9dff4224e --- /dev/null +++ b/drivers/bcma/driver_mips.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * Broadcom specific AMBA | ||
3 | * Broadcom MIPS32 74K core driver | ||
4 | * | ||
5 | * Copyright 2009, Broadcom Corporation | ||
6 | * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> | ||
7 | * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com> | ||
8 | * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de> | ||
9 | * | ||
10 | * Licensed under the GNU/GPL. See COPYING for details. | ||
11 | */ | ||
12 | |||
13 | #include "bcma_private.h" | ||
14 | |||
15 | #include <linux/bcma/bcma.h> | ||
16 | |||
17 | #include <linux/serial.h> | ||
18 | #include <linux/serial_core.h> | ||
19 | #include <linux/serial_reg.h> | ||
20 | #include <linux/time.h> | ||
21 | |||
22 | /* The 47162a0 hangs when reading MIPS DMP registers registers */ | ||
23 | static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) | ||
24 | { | ||
25 | return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 && | ||
26 | dev->id.id == BCMA_CORE_MIPS_74K; | ||
27 | } | ||
28 | |||
29 | /* The 5357b0 hangs when reading USB20H DMP registers */ | ||
30 | static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev) | ||
31 | { | ||
32 | return (dev->bus->chipinfo.id == 0x5357 || | ||
33 | dev->bus->chipinfo.id == 0x4749) && | ||
34 | dev->bus->chipinfo.pkg == 11 && | ||
35 | dev->id.id == BCMA_CORE_USB20_HOST; | ||
36 | } | ||
37 | |||
38 | static inline u32 mips_read32(struct bcma_drv_mips *mcore, | ||
39 | u16 offset) | ||
40 | { | ||
41 | return bcma_read32(mcore->core, offset); | ||
42 | } | ||
43 | |||
44 | static inline void mips_write32(struct bcma_drv_mips *mcore, | ||
45 | u16 offset, | ||
46 | u32 value) | ||
47 | { | ||
48 | bcma_write32(mcore->core, offset, value); | ||
49 | } | ||
50 | |||
51 | static const u32 ipsflag_irq_mask[] = { | ||
52 | 0, | ||
53 | BCMA_MIPS_IPSFLAG_IRQ1, | ||
54 | BCMA_MIPS_IPSFLAG_IRQ2, | ||
55 | BCMA_MIPS_IPSFLAG_IRQ3, | ||
56 | BCMA_MIPS_IPSFLAG_IRQ4, | ||
57 | }; | ||
58 | |||
59 | static const u32 ipsflag_irq_shift[] = { | ||
60 | 0, | ||
61 | BCMA_MIPS_IPSFLAG_IRQ1_SHIFT, | ||
62 | BCMA_MIPS_IPSFLAG_IRQ2_SHIFT, | ||
63 | BCMA_MIPS_IPSFLAG_IRQ3_SHIFT, | ||
64 | BCMA_MIPS_IPSFLAG_IRQ4_SHIFT, | ||
65 | }; | ||
66 | |||
67 | static u32 bcma_core_mips_irqflag(struct bcma_device *dev) | ||
68 | { | ||
69 | u32 flag; | ||
70 | |||
71 | if (bcma_core_mips_bcm47162a0_quirk(dev)) | ||
72 | return dev->core_index; | ||
73 | if (bcma_core_mips_bcm5357b0_quirk(dev)) | ||
74 | return dev->core_index; | ||
75 | flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30); | ||
76 | |||
77 | return flag & 0x1F; | ||
78 | } | ||
79 | |||
80 | /* Get the MIPS IRQ assignment for a specified device. | ||
81 | * If unassigned, 0 is returned. | ||
82 | */ | ||
83 | unsigned int bcma_core_mips_irq(struct bcma_device *dev) | ||
84 | { | ||
85 | struct bcma_device *mdev = dev->bus->drv_mips.core; | ||
86 | u32 irqflag; | ||
87 | unsigned int irq; | ||
88 | |||
89 | irqflag = bcma_core_mips_irqflag(dev); | ||
90 | |||
91 | for (irq = 1; irq <= 4; irq++) | ||
92 | if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) & | ||
93 | (1 << irqflag)) | ||
94 | return irq; | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | EXPORT_SYMBOL(bcma_core_mips_irq); | ||
99 | |||
100 | static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) | ||
101 | { | ||
102 | unsigned int oldirq = bcma_core_mips_irq(dev); | ||
103 | struct bcma_bus *bus = dev->bus; | ||
104 | struct bcma_device *mdev = bus->drv_mips.core; | ||
105 | u32 irqflag; | ||
106 | |||
107 | irqflag = bcma_core_mips_irqflag(dev); | ||
108 | BUG_ON(oldirq == 6); | ||
109 | |||
110 | dev->irq = irq + 2; | ||
111 | |||
112 | /* clear the old irq */ | ||
113 | if (oldirq == 0) | ||
114 | bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0), | ||
115 | bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) & | ||
116 | ~(1 << irqflag)); | ||
117 | else | ||
118 | bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0); | ||
119 | |||
120 | /* assign the new one */ | ||
121 | if (irq == 0) { | ||
122 | bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0), | ||
123 | bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) | | ||
124 | (1 << irqflag)); | ||
125 | } else { | ||
126 | u32 oldirqflag = bcma_read32(mdev, | ||
127 | BCMA_MIPS_MIPS74K_INTMASK(irq)); | ||
128 | if (oldirqflag) { | ||
129 | struct bcma_device *core; | ||
130 | |||
131 | /* backplane irq line is in use, find out who uses | ||
132 | * it and set user to irq 0 | ||
133 | */ | ||
134 | list_for_each_entry_reverse(core, &bus->cores, list) { | ||
135 | if ((1 << bcma_core_mips_irqflag(core)) == | ||
136 | oldirqflag) { | ||
137 | bcma_core_mips_set_irq(core, 0); | ||
138 | break; | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), | ||
143 | 1 << irqflag); | ||
144 | } | ||
145 | |||
146 | pr_info("set_irq: core 0x%04x, irq %d => %d\n", | ||
147 | dev->id.id, oldirq + 2, irq + 2); | ||
148 | } | ||
149 | |||
150 | static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq) | ||
151 | { | ||
152 | int i; | ||
153 | static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"}; | ||
154 | printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id); | ||
155 | for (i = 0; i <= 6; i++) | ||
156 | printk(" %s%s", irq_name[i], i == irq ? "*" : " "); | ||
157 | printk("\n"); | ||
158 | } | ||
159 | |||
160 | static void bcma_core_mips_dump_irq(struct bcma_bus *bus) | ||
161 | { | ||
162 | struct bcma_device *core; | ||
163 | |||
164 | list_for_each_entry_reverse(core, &bus->cores, list) { | ||
165 | bcma_core_mips_print_irq(core, bcma_core_mips_irq(core)); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | u32 bcma_cpu_clock(struct bcma_drv_mips *mcore) | ||
170 | { | ||
171 | struct bcma_bus *bus = mcore->core->bus; | ||
172 | |||
173 | if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU) | ||
174 | return bcma_pmu_get_clockcpu(&bus->drv_cc); | ||
175 | |||
176 | pr_err("No PMU available, need this to get the cpu clock\n"); | ||
177 | return 0; | ||
178 | } | ||
179 | EXPORT_SYMBOL(bcma_cpu_clock); | ||
180 | |||
181 | static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) | ||
182 | { | ||
183 | struct bcma_bus *bus = mcore->core->bus; | ||
184 | |||
185 | switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { | ||
186 | case BCMA_CC_FLASHT_STSER: | ||
187 | case BCMA_CC_FLASHT_ATSER: | ||
188 | pr_err("Serial flash not supported.\n"); | ||
189 | break; | ||
190 | case BCMA_CC_FLASHT_PARA: | ||
191 | pr_info("found parallel flash.\n"); | ||
192 | bus->drv_cc.pflash.window = 0x1c000000; | ||
193 | bus->drv_cc.pflash.window_size = 0x02000000; | ||
194 | |||
195 | if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) & | ||
196 | BCMA_CC_FLASH_CFG_DS) == 0) | ||
197 | bus->drv_cc.pflash.buswidth = 1; | ||
198 | else | ||
199 | bus->drv_cc.pflash.buswidth = 2; | ||
200 | break; | ||
201 | default: | ||
202 | pr_err("flash not supported.\n"); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | void bcma_core_mips_init(struct bcma_drv_mips *mcore) | ||
207 | { | ||
208 | struct bcma_bus *bus; | ||
209 | struct bcma_device *core; | ||
210 | bus = mcore->core->bus; | ||
211 | |||
212 | pr_info("Initializing MIPS core...\n"); | ||
213 | |||
214 | if (!mcore->setup_done) | ||
215 | mcore->assigned_irqs = 1; | ||
216 | |||
217 | /* Assign IRQs to all cores on the bus */ | ||
218 | list_for_each_entry_reverse(core, &bus->cores, list) { | ||
219 | int mips_irq; | ||
220 | if (core->irq) | ||
221 | continue; | ||
222 | |||
223 | mips_irq = bcma_core_mips_irq(core); | ||
224 | if (mips_irq > 4) | ||
225 | core->irq = 0; | ||
226 | else | ||
227 | core->irq = mips_irq + 2; | ||
228 | if (core->irq > 5) | ||
229 | continue; | ||
230 | switch (core->id.id) { | ||
231 | case BCMA_CORE_PCI: | ||
232 | case BCMA_CORE_PCIE: | ||
233 | case BCMA_CORE_ETHERNET: | ||
234 | case BCMA_CORE_ETHERNET_GBIT: | ||
235 | case BCMA_CORE_MAC_GBIT: | ||
236 | case BCMA_CORE_80211: | ||
237 | case BCMA_CORE_USB20_HOST: | ||
238 | /* These devices get their own IRQ line if available, | ||
239 | * the rest goes on IRQ0 | ||
240 | */ | ||
241 | if (mcore->assigned_irqs <= 4) | ||
242 | bcma_core_mips_set_irq(core, | ||
243 | mcore->assigned_irqs++); | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | pr_info("IRQ reconfiguration done\n"); | ||
248 | bcma_core_mips_dump_irq(bus); | ||
249 | |||
250 | if (mcore->setup_done) | ||
251 | return; | ||
252 | |||
253 | bcma_chipco_serial_init(&bus->drv_cc); | ||
254 | bcma_core_mips_flash_detect(mcore); | ||
255 | mcore->setup_done = true; | ||
256 | } | ||
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 25f3ddf33823..81f3d0a4b856 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c | |||
@@ -173,7 +173,7 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) | |||
173 | return false; | 173 | return false; |
174 | 174 | ||
175 | #ifdef CONFIG_SSB_DRIVER_PCICORE | 175 | #ifdef CONFIG_SSB_DRIVER_PCICORE |
176 | if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI) | 176 | if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI) |
177 | return false; | 177 | return false; |
178 | #endif /* CONFIG_SSB_DRIVER_PCICORE */ | 178 | #endif /* CONFIG_SSB_DRIVER_PCICORE */ |
179 | 179 | ||
@@ -189,6 +189,9 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) | |||
189 | 189 | ||
190 | void bcma_core_pci_init(struct bcma_drv_pci *pc) | 190 | void bcma_core_pci_init(struct bcma_drv_pci *pc) |
191 | { | 191 | { |
192 | if (pc->setup_done) | ||
193 | return; | ||
194 | |||
192 | if (bcma_core_pci_is_in_hostmode(pc)) { | 195 | if (bcma_core_pci_is_in_hostmode(pc)) { |
193 | #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE | 196 | #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE |
194 | bcma_core_pci_hostmode_init(pc); | 197 | bcma_core_pci_hostmode_init(pc); |
@@ -198,6 +201,8 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc) | |||
198 | } else { | 201 | } else { |
199 | bcma_core_pci_clientmode_init(pc); | 202 | bcma_core_pci_clientmode_init(pc); |
200 | } | 203 | } |
204 | |||
205 | pc->setup_done = true; | ||
201 | } | 206 | } |
202 | 207 | ||
203 | int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, | 208 | int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, |
@@ -205,7 +210,14 @@ int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, | |||
205 | { | 210 | { |
206 | struct pci_dev *pdev = pc->core->bus->host_pci; | 211 | struct pci_dev *pdev = pc->core->bus->host_pci; |
207 | u32 coremask, tmp; | 212 | u32 coremask, tmp; |
208 | int err; | 213 | int err = 0; |
214 | |||
215 | if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) { | ||
216 | /* This bcma device is not on a PCI host-bus. So the IRQs are | ||
217 | * not routed through the PCI core. | ||
218 | * So we must not enable routing through the PCI core. */ | ||
219 | goto out; | ||
220 | } | ||
209 | 221 | ||
210 | err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); | 222 | err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); |
211 | if (err) | 223 | if (err) |
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c new file mode 100644 index 000000000000..3c381fb8f9c4 --- /dev/null +++ b/drivers/bcma/host_soc.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Broadcom specific AMBA | ||
3 | * System on Chip (SoC) Host | ||
4 | * | ||
5 | * Licensed under the GNU/GPL. See COPYING for details. | ||
6 | */ | ||
7 | |||
8 | #include "bcma_private.h" | ||
9 | #include "scan.h" | ||
10 | #include <linux/bcma/bcma.h> | ||
11 | #include <linux/bcma/bcma_soc.h> | ||
12 | |||
13 | static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset) | ||
14 | { | ||
15 | return readb(core->io_addr + offset); | ||
16 | } | ||
17 | |||
18 | static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset) | ||
19 | { | ||
20 | return readw(core->io_addr + offset); | ||
21 | } | ||
22 | |||
23 | static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset) | ||
24 | { | ||
25 | return readl(core->io_addr + offset); | ||
26 | } | ||
27 | |||
28 | static void bcma_host_soc_write8(struct bcma_device *core, u16 offset, | ||
29 | u8 value) | ||
30 | { | ||
31 | writeb(value, core->io_addr + offset); | ||
32 | } | ||
33 | |||
34 | static void bcma_host_soc_write16(struct bcma_device *core, u16 offset, | ||
35 | u16 value) | ||
36 | { | ||
37 | writew(value, core->io_addr + offset); | ||
38 | } | ||
39 | |||
40 | static void bcma_host_soc_write32(struct bcma_device *core, u16 offset, | ||
41 | u32 value) | ||
42 | { | ||
43 | writel(value, core->io_addr + offset); | ||
44 | } | ||
45 | |||
46 | #ifdef CONFIG_BCMA_BLOCKIO | ||
47 | static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer, | ||
48 | size_t count, u16 offset, u8 reg_width) | ||
49 | { | ||
50 | void __iomem *addr = core->io_addr + offset; | ||
51 | |||
52 | switch (reg_width) { | ||
53 | case sizeof(u8): { | ||
54 | u8 *buf = buffer; | ||
55 | |||
56 | while (count) { | ||
57 | *buf = __raw_readb(addr); | ||
58 | buf++; | ||
59 | count--; | ||
60 | } | ||
61 | break; | ||
62 | } | ||
63 | case sizeof(u16): { | ||
64 | __le16 *buf = buffer; | ||
65 | |||
66 | WARN_ON(count & 1); | ||
67 | while (count) { | ||
68 | *buf = (__force __le16)__raw_readw(addr); | ||
69 | buf++; | ||
70 | count -= 2; | ||
71 | } | ||
72 | break; | ||
73 | } | ||
74 | case sizeof(u32): { | ||
75 | __le32 *buf = buffer; | ||
76 | |||
77 | WARN_ON(count & 3); | ||
78 | while (count) { | ||
79 | *buf = (__force __le32)__raw_readl(addr); | ||
80 | buf++; | ||
81 | count -= 4; | ||
82 | } | ||
83 | break; | ||
84 | } | ||
85 | default: | ||
86 | WARN_ON(1); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static void bcma_host_soc_block_write(struct bcma_device *core, | ||
91 | const void *buffer, | ||
92 | size_t count, u16 offset, u8 reg_width) | ||
93 | { | ||
94 | void __iomem *addr = core->io_addr + offset; | ||
95 | |||
96 | switch (reg_width) { | ||
97 | case sizeof(u8): { | ||
98 | const u8 *buf = buffer; | ||
99 | |||
100 | while (count) { | ||
101 | __raw_writeb(*buf, addr); | ||
102 | buf++; | ||
103 | count--; | ||
104 | } | ||
105 | break; | ||
106 | } | ||
107 | case sizeof(u16): { | ||
108 | const __le16 *buf = buffer; | ||
109 | |||
110 | WARN_ON(count & 1); | ||
111 | while (count) { | ||
112 | __raw_writew((__force u16)(*buf), addr); | ||
113 | buf++; | ||
114 | count -= 2; | ||
115 | } | ||
116 | break; | ||
117 | } | ||
118 | case sizeof(u32): { | ||
119 | const __le32 *buf = buffer; | ||
120 | |||
121 | WARN_ON(count & 3); | ||
122 | while (count) { | ||
123 | __raw_writel((__force u32)(*buf), addr); | ||
124 | buf++; | ||
125 | count -= 4; | ||
126 | } | ||
127 | break; | ||
128 | } | ||
129 | default: | ||
130 | WARN_ON(1); | ||
131 | } | ||
132 | } | ||
133 | #endif /* CONFIG_BCMA_BLOCKIO */ | ||
134 | |||
135 | static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset) | ||
136 | { | ||
137 | return readl(core->io_wrap + offset); | ||
138 | } | ||
139 | |||
140 | static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset, | ||
141 | u32 value) | ||
142 | { | ||
143 | writel(value, core->io_wrap + offset); | ||
144 | } | ||
145 | |||
146 | const struct bcma_host_ops bcma_host_soc_ops = { | ||
147 | .read8 = bcma_host_soc_read8, | ||
148 | .read16 = bcma_host_soc_read16, | ||
149 | .read32 = bcma_host_soc_read32, | ||
150 | .write8 = bcma_host_soc_write8, | ||
151 | .write16 = bcma_host_soc_write16, | ||
152 | .write32 = bcma_host_soc_write32, | ||
153 | #ifdef CONFIG_BCMA_BLOCKIO | ||
154 | .block_read = bcma_host_soc_block_read, | ||
155 | .block_write = bcma_host_soc_block_write, | ||
156 | #endif | ||
157 | .aread32 = bcma_host_soc_aread32, | ||
158 | .awrite32 = bcma_host_soc_awrite32, | ||
159 | }; | ||
160 | |||
161 | int __init bcma_host_soc_register(struct bcma_soc *soc) | ||
162 | { | ||
163 | struct bcma_bus *bus = &soc->bus; | ||
164 | int err; | ||
165 | |||
166 | /* iomap only first core. We have to read some register on this core | ||
167 | * to scan the bus. | ||
168 | */ | ||
169 | bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1); | ||
170 | if (!bus->mmio) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | /* Host specific */ | ||
174 | bus->hosttype = BCMA_HOSTTYPE_SOC; | ||
175 | bus->ops = &bcma_host_soc_ops; | ||
176 | |||
177 | /* Register */ | ||
178 | err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips); | ||
179 | if (err) | ||
180 | iounmap(bus->mmio); | ||
181 | |||
182 | return err; | ||
183 | } | ||
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 873e2e4ac55f..7072216a2a3f 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c | |||
@@ -66,6 +66,10 @@ static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) | |||
66 | static void bcma_release_core_dev(struct device *dev) | 66 | static void bcma_release_core_dev(struct device *dev) |
67 | { | 67 | { |
68 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | 68 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
69 | if (core->io_addr) | ||
70 | iounmap(core->io_addr); | ||
71 | if (core->io_wrap) | ||
72 | iounmap(core->io_wrap); | ||
69 | kfree(core); | 73 | kfree(core); |
70 | } | 74 | } |
71 | 75 | ||
@@ -80,6 +84,7 @@ static int bcma_register_cores(struct bcma_bus *bus) | |||
80 | case BCMA_CORE_CHIPCOMMON: | 84 | case BCMA_CORE_CHIPCOMMON: |
81 | case BCMA_CORE_PCI: | 85 | case BCMA_CORE_PCI: |
82 | case BCMA_CORE_PCIE: | 86 | case BCMA_CORE_PCIE: |
87 | case BCMA_CORE_MIPS_74K: | ||
83 | continue; | 88 | continue; |
84 | } | 89 | } |
85 | 90 | ||
@@ -93,7 +98,10 @@ static int bcma_register_cores(struct bcma_bus *bus) | |||
93 | core->dma_dev = &bus->host_pci->dev; | 98 | core->dma_dev = &bus->host_pci->dev; |
94 | core->irq = bus->host_pci->irq; | 99 | core->irq = bus->host_pci->irq; |
95 | break; | 100 | break; |
96 | case BCMA_HOSTTYPE_NONE: | 101 | case BCMA_HOSTTYPE_SOC: |
102 | core->dev.dma_mask = &core->dev.coherent_dma_mask; | ||
103 | core->dma_dev = &core->dev; | ||
104 | break; | ||
97 | case BCMA_HOSTTYPE_SDIO: | 105 | case BCMA_HOSTTYPE_SDIO: |
98 | break; | 106 | break; |
99 | } | 107 | } |
@@ -140,6 +148,13 @@ int bcma_bus_register(struct bcma_bus *bus) | |||
140 | bcma_core_chipcommon_init(&bus->drv_cc); | 148 | bcma_core_chipcommon_init(&bus->drv_cc); |
141 | } | 149 | } |
142 | 150 | ||
151 | /* Init MIPS core */ | ||
152 | core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); | ||
153 | if (core) { | ||
154 | bus->drv_mips.core = core; | ||
155 | bcma_core_mips_init(&bus->drv_mips); | ||
156 | } | ||
157 | |||
143 | /* Init PCIE core */ | 158 | /* Init PCIE core */ |
144 | core = bcma_find_core(bus, BCMA_CORE_PCIE); | 159 | core = bcma_find_core(bus, BCMA_CORE_PCIE); |
145 | if (core) { | 160 | if (core) { |
@@ -169,6 +184,59 @@ void bcma_bus_unregister(struct bcma_bus *bus) | |||
169 | bcma_unregister_cores(bus); | 184 | bcma_unregister_cores(bus); |
170 | } | 185 | } |
171 | 186 | ||
187 | int __init bcma_bus_early_register(struct bcma_bus *bus, | ||
188 | struct bcma_device *core_cc, | ||
189 | struct bcma_device *core_mips) | ||
190 | { | ||
191 | int err; | ||
192 | struct bcma_device *core; | ||
193 | struct bcma_device_id match; | ||
194 | |||
195 | bcma_init_bus(bus); | ||
196 | |||
197 | match.manuf = BCMA_MANUF_BCM; | ||
198 | match.id = BCMA_CORE_CHIPCOMMON; | ||
199 | match.class = BCMA_CL_SIM; | ||
200 | match.rev = BCMA_ANY_REV; | ||
201 | |||
202 | /* Scan for chip common core */ | ||
203 | err = bcma_bus_scan_early(bus, &match, core_cc); | ||
204 | if (err) { | ||
205 | pr_err("Failed to scan for common core: %d\n", err); | ||
206 | return -1; | ||
207 | } | ||
208 | |||
209 | match.manuf = BCMA_MANUF_MIPS; | ||
210 | match.id = BCMA_CORE_MIPS_74K; | ||
211 | match.class = BCMA_CL_SIM; | ||
212 | match.rev = BCMA_ANY_REV; | ||
213 | |||
214 | /* Scan for mips core */ | ||
215 | err = bcma_bus_scan_early(bus, &match, core_mips); | ||
216 | if (err) { | ||
217 | pr_err("Failed to scan for mips core: %d\n", err); | ||
218 | return -1; | ||
219 | } | ||
220 | |||
221 | /* Init CC core */ | ||
222 | core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); | ||
223 | if (core) { | ||
224 | bus->drv_cc.core = core; | ||
225 | bcma_core_chipcommon_init(&bus->drv_cc); | ||
226 | } | ||
227 | |||
228 | /* Init MIPS core */ | ||
229 | core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); | ||
230 | if (core) { | ||
231 | bus->drv_mips.core = core; | ||
232 | bcma_core_mips_init(&bus->drv_mips); | ||
233 | } | ||
234 | |||
235 | pr_info("Early bus registered\n"); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
172 | int __bcma_driver_register(struct bcma_driver *drv, struct module *owner) | 240 | int __bcma_driver_register(struct bcma_driver *drv, struct module *owner) |
173 | { | 241 | { |
174 | drv->drv.name = drv->name; | 242 | drv->drv.name = drv->name; |
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 40d7dcce8933..0ea390f9aa9e 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c | |||
@@ -200,18 +200,162 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr, | |||
200 | return addrl; | 200 | return addrl; |
201 | } | 201 | } |
202 | 202 | ||
203 | int bcma_bus_scan(struct bcma_bus *bus) | 203 | static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus, |
204 | u16 index) | ||
204 | { | 205 | { |
205 | u32 erombase; | 206 | struct bcma_device *core; |
206 | u32 __iomem *eromptr, *eromend; | ||
207 | 207 | ||
208 | list_for_each_entry(core, &bus->cores, list) { | ||
209 | if (core->core_index == index) | ||
210 | return core; | ||
211 | } | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, | ||
216 | struct bcma_device_id *match, int core_num, | ||
217 | struct bcma_device *core) | ||
218 | { | ||
219 | s32 tmp; | ||
220 | u8 i, j; | ||
208 | s32 cia, cib; | 221 | s32 cia, cib; |
209 | u8 ports[2], wrappers[2]; | 222 | u8 ports[2], wrappers[2]; |
210 | 223 | ||
224 | /* get CIs */ | ||
225 | cia = bcma_erom_get_ci(bus, eromptr); | ||
226 | if (cia < 0) { | ||
227 | bcma_erom_push_ent(eromptr); | ||
228 | if (bcma_erom_is_end(bus, eromptr)) | ||
229 | return -ESPIPE; | ||
230 | return -EILSEQ; | ||
231 | } | ||
232 | cib = bcma_erom_get_ci(bus, eromptr); | ||
233 | if (cib < 0) | ||
234 | return -EILSEQ; | ||
235 | |||
236 | /* parse CIs */ | ||
237 | core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; | ||
238 | core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; | ||
239 | core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; | ||
240 | ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; | ||
241 | ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; | ||
242 | wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; | ||
243 | wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; | ||
244 | core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; | ||
245 | |||
246 | if (((core->id.manuf == BCMA_MANUF_ARM) && | ||
247 | (core->id.id == 0xFFF)) || | ||
248 | (ports[1] == 0)) { | ||
249 | bcma_erom_skip_component(bus, eromptr); | ||
250 | return -ENXIO; | ||
251 | } | ||
252 | |||
253 | /* check if component is a core at all */ | ||
254 | if (wrappers[0] + wrappers[1] == 0) { | ||
255 | /* we could save addrl of the router | ||
256 | if (cid == BCMA_CORE_OOB_ROUTER) | ||
257 | */ | ||
258 | bcma_erom_skip_component(bus, eromptr); | ||
259 | return -ENXIO; | ||
260 | } | ||
261 | |||
262 | if (bcma_erom_is_bridge(bus, eromptr)) { | ||
263 | bcma_erom_skip_component(bus, eromptr); | ||
264 | return -ENXIO; | ||
265 | } | ||
266 | |||
267 | if (bcma_find_core_by_index(bus, core_num)) { | ||
268 | bcma_erom_skip_component(bus, eromptr); | ||
269 | return -ENODEV; | ||
270 | } | ||
271 | |||
272 | if (match && ((match->manuf != BCMA_ANY_MANUF && | ||
273 | match->manuf != core->id.manuf) || | ||
274 | (match->id != BCMA_ANY_ID && match->id != core->id.id) || | ||
275 | (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) || | ||
276 | (match->class != BCMA_ANY_CLASS && match->class != core->id.class) | ||
277 | )) { | ||
278 | bcma_erom_skip_component(bus, eromptr); | ||
279 | return -ENODEV; | ||
280 | } | ||
281 | |||
282 | /* get & parse master ports */ | ||
283 | for (i = 0; i < ports[0]; i++) { | ||
284 | u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr); | ||
285 | if (mst_port_d < 0) | ||
286 | return -EILSEQ; | ||
287 | } | ||
288 | |||
289 | /* get & parse slave ports */ | ||
290 | for (i = 0; i < ports[1]; i++) { | ||
291 | for (j = 0; ; j++) { | ||
292 | tmp = bcma_erom_get_addr_desc(bus, eromptr, | ||
293 | SCAN_ADDR_TYPE_SLAVE, i); | ||
294 | if (tmp < 0) { | ||
295 | /* no more entries for port _i_ */ | ||
296 | /* pr_debug("erom: slave port %d " | ||
297 | * "has %d descriptors\n", i, j); */ | ||
298 | break; | ||
299 | } else { | ||
300 | if (i == 0 && j == 0) | ||
301 | core->addr = tmp; | ||
302 | } | ||
303 | } | ||
304 | } | ||
305 | |||
306 | /* get & parse master wrappers */ | ||
307 | for (i = 0; i < wrappers[0]; i++) { | ||
308 | for (j = 0; ; j++) { | ||
309 | tmp = bcma_erom_get_addr_desc(bus, eromptr, | ||
310 | SCAN_ADDR_TYPE_MWRAP, i); | ||
311 | if (tmp < 0) { | ||
312 | /* no more entries for port _i_ */ | ||
313 | /* pr_debug("erom: master wrapper %d " | ||
314 | * "has %d descriptors\n", i, j); */ | ||
315 | break; | ||
316 | } else { | ||
317 | if (i == 0 && j == 0) | ||
318 | core->wrap = tmp; | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | |||
323 | /* get & parse slave wrappers */ | ||
324 | for (i = 0; i < wrappers[1]; i++) { | ||
325 | u8 hack = (ports[1] == 1) ? 0 : 1; | ||
326 | for (j = 0; ; j++) { | ||
327 | tmp = bcma_erom_get_addr_desc(bus, eromptr, | ||
328 | SCAN_ADDR_TYPE_SWRAP, i + hack); | ||
329 | if (tmp < 0) { | ||
330 | /* no more entries for port _i_ */ | ||
331 | /* pr_debug("erom: master wrapper %d " | ||
332 | * has %d descriptors\n", i, j); */ | ||
333 | break; | ||
334 | } else { | ||
335 | if (wrappers[0] == 0 && !i && !j) | ||
336 | core->wrap = tmp; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { | ||
341 | core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE); | ||
342 | if (!core->io_addr) | ||
343 | return -ENOMEM; | ||
344 | core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE); | ||
345 | if (!core->io_wrap) { | ||
346 | iounmap(core->io_addr); | ||
347 | return -ENOMEM; | ||
348 | } | ||
349 | } | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | void bcma_init_bus(struct bcma_bus *bus) | ||
354 | { | ||
211 | s32 tmp; | 355 | s32 tmp; |
212 | u8 i, j; | ||
213 | 356 | ||
214 | int err; | 357 | if (bus->init_done) |
358 | return; | ||
215 | 359 | ||
216 | INIT_LIST_HEAD(&bus->cores); | 360 | INIT_LIST_HEAD(&bus->cores); |
217 | bus->nr_cores = 0; | 361 | bus->nr_cores = 0; |
@@ -222,9 +366,27 @@ int bcma_bus_scan(struct bcma_bus *bus) | |||
222 | bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; | 366 | bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; |
223 | bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; | 367 | bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; |
224 | bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; | 368 | bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; |
369 | bus->init_done = true; | ||
370 | } | ||
371 | |||
372 | int bcma_bus_scan(struct bcma_bus *bus) | ||
373 | { | ||
374 | u32 erombase; | ||
375 | u32 __iomem *eromptr, *eromend; | ||
376 | |||
377 | int err, core_num = 0; | ||
378 | |||
379 | bcma_init_bus(bus); | ||
225 | 380 | ||
226 | erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); | 381 | erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); |
227 | eromptr = bus->mmio; | 382 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { |
383 | eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); | ||
384 | if (!eromptr) | ||
385 | return -ENOMEM; | ||
386 | } else { | ||
387 | eromptr = bus->mmio; | ||
388 | } | ||
389 | |||
228 | eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); | 390 | eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); |
229 | 391 | ||
230 | bcma_scan_switch_core(bus, erombase); | 392 | bcma_scan_switch_core(bus, erombase); |
@@ -236,125 +398,89 @@ int bcma_bus_scan(struct bcma_bus *bus) | |||
236 | INIT_LIST_HEAD(&core->list); | 398 | INIT_LIST_HEAD(&core->list); |
237 | core->bus = bus; | 399 | core->bus = bus; |
238 | 400 | ||
239 | /* get CIs */ | 401 | err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core); |
240 | cia = bcma_erom_get_ci(bus, &eromptr); | 402 | if (err == -ENODEV) { |
241 | if (cia < 0) { | 403 | core_num++; |
242 | bcma_erom_push_ent(&eromptr); | ||
243 | if (bcma_erom_is_end(bus, &eromptr)) | ||
244 | break; | ||
245 | err= -EILSEQ; | ||
246 | goto out; | ||
247 | } | ||
248 | cib = bcma_erom_get_ci(bus, &eromptr); | ||
249 | if (cib < 0) { | ||
250 | err= -EILSEQ; | ||
251 | goto out; | ||
252 | } | ||
253 | |||
254 | /* parse CIs */ | ||
255 | core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; | ||
256 | core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; | ||
257 | core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; | ||
258 | ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; | ||
259 | ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; | ||
260 | wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; | ||
261 | wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; | ||
262 | core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; | ||
263 | |||
264 | if (((core->id.manuf == BCMA_MANUF_ARM) && | ||
265 | (core->id.id == 0xFFF)) || | ||
266 | (ports[1] == 0)) { | ||
267 | bcma_erom_skip_component(bus, &eromptr); | ||
268 | continue; | 404 | continue; |
269 | } | 405 | } else if (err == -ENXIO) |
270 | |||
271 | /* check if component is a core at all */ | ||
272 | if (wrappers[0] + wrappers[1] == 0) { | ||
273 | /* we could save addrl of the router | ||
274 | if (cid == BCMA_CORE_OOB_ROUTER) | ||
275 | */ | ||
276 | bcma_erom_skip_component(bus, &eromptr); | ||
277 | continue; | 406 | continue; |
278 | } | 407 | else if (err == -ESPIPE) |
408 | break; | ||
409 | else if (err < 0) | ||
410 | return err; | ||
279 | 411 | ||
280 | if (bcma_erom_is_bridge(bus, &eromptr)) { | 412 | core->core_index = core_num++; |
281 | bcma_erom_skip_component(bus, &eromptr); | 413 | bus->nr_cores++; |
282 | continue; | ||
283 | } | ||
284 | 414 | ||
285 | /* get & parse master ports */ | 415 | pr_info("Core %d found: %s " |
286 | for (i = 0; i < ports[0]; i++) { | 416 | "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", |
287 | u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr); | 417 | core->core_index, bcma_device_name(&core->id), |
288 | if (mst_port_d < 0) { | 418 | core->id.manuf, core->id.id, core->id.rev, |
289 | err= -EILSEQ; | 419 | core->id.class); |
290 | goto out; | ||
291 | } | ||
292 | } | ||
293 | 420 | ||
294 | /* get & parse slave ports */ | 421 | list_add(&core->list, &bus->cores); |
295 | for (i = 0; i < ports[1]; i++) { | 422 | } |
296 | for (j = 0; ; j++) { | ||
297 | tmp = bcma_erom_get_addr_desc(bus, &eromptr, | ||
298 | SCAN_ADDR_TYPE_SLAVE, i); | ||
299 | if (tmp < 0) { | ||
300 | /* no more entries for port _i_ */ | ||
301 | /* pr_debug("erom: slave port %d " | ||
302 | * "has %d descriptors\n", i, j); */ | ||
303 | break; | ||
304 | } else { | ||
305 | if (i == 0 && j == 0) | ||
306 | core->addr = tmp; | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | 423 | ||
311 | /* get & parse master wrappers */ | 424 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) |
312 | for (i = 0; i < wrappers[0]; i++) { | 425 | iounmap(eromptr); |
313 | for (j = 0; ; j++) { | ||
314 | tmp = bcma_erom_get_addr_desc(bus, &eromptr, | ||
315 | SCAN_ADDR_TYPE_MWRAP, i); | ||
316 | if (tmp < 0) { | ||
317 | /* no more entries for port _i_ */ | ||
318 | /* pr_debug("erom: master wrapper %d " | ||
319 | * "has %d descriptors\n", i, j); */ | ||
320 | break; | ||
321 | } else { | ||
322 | if (i == 0 && j == 0) | ||
323 | core->wrap = tmp; | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | 426 | ||
328 | /* get & parse slave wrappers */ | 427 | return 0; |
329 | for (i = 0; i < wrappers[1]; i++) { | 428 | } |
330 | u8 hack = (ports[1] == 1) ? 0 : 1; | 429 | |
331 | for (j = 0; ; j++) { | 430 | int __init bcma_bus_scan_early(struct bcma_bus *bus, |
332 | tmp = bcma_erom_get_addr_desc(bus, &eromptr, | 431 | struct bcma_device_id *match, |
333 | SCAN_ADDR_TYPE_SWRAP, i + hack); | 432 | struct bcma_device *core) |
334 | if (tmp < 0) { | 433 | { |
335 | /* no more entries for port _i_ */ | 434 | u32 erombase; |
336 | /* pr_debug("erom: master wrapper %d " | 435 | u32 __iomem *eromptr, *eromend; |
337 | * has %d descriptors\n", i, j); */ | 436 | |
338 | break; | 437 | int err = -ENODEV; |
339 | } else { | 438 | int core_num = 0; |
340 | if (wrappers[0] == 0 && !i && !j) | 439 | |
341 | core->wrap = tmp; | 440 | erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); |
342 | } | 441 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) { |
343 | } | 442 | eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); |
344 | } | 443 | if (!eromptr) |
444 | return -ENOMEM; | ||
445 | } else { | ||
446 | eromptr = bus->mmio; | ||
447 | } | ||
448 | |||
449 | eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); | ||
450 | |||
451 | bcma_scan_switch_core(bus, erombase); | ||
452 | |||
453 | while (eromptr < eromend) { | ||
454 | memset(core, 0, sizeof(*core)); | ||
455 | INIT_LIST_HEAD(&core->list); | ||
456 | core->bus = bus; | ||
345 | 457 | ||
458 | err = bcma_get_next_core(bus, &eromptr, match, core_num, core); | ||
459 | if (err == -ENODEV) { | ||
460 | core_num++; | ||
461 | continue; | ||
462 | } else if (err == -ENXIO) | ||
463 | continue; | ||
464 | else if (err == -ESPIPE) | ||
465 | break; | ||
466 | else if (err < 0) | ||
467 | return err; | ||
468 | |||
469 | core->core_index = core_num++; | ||
470 | bus->nr_cores++; | ||
346 | pr_info("Core %d found: %s " | 471 | pr_info("Core %d found: %s " |
347 | "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", | 472 | "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", |
348 | bus->nr_cores, bcma_device_name(&core->id), | 473 | core->core_index, bcma_device_name(&core->id), |
349 | core->id.manuf, core->id.id, core->id.rev, | 474 | core->id.manuf, core->id.id, core->id.rev, |
350 | core->id.class); | 475 | core->id.class); |
351 | 476 | ||
352 | core->core_index = bus->nr_cores++; | ||
353 | list_add(&core->list, &bus->cores); | 477 | list_add(&core->list, &bus->cores); |
354 | continue; | 478 | err = 0; |
355 | out: | 479 | break; |
356 | return err; | ||
357 | } | 480 | } |
358 | 481 | ||
359 | return 0; | 482 | if (bus->hosttype == BCMA_HOSTTYPE_SOC) |
483 | iounmap(eromptr); | ||
484 | |||
485 | return err; | ||
360 | } | 486 | } |