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 | 3 | ||||
-rw-r--r-- | drivers/bcma/driver_chipcommon.c | 54 | ||||
-rw-r--r-- | drivers/bcma/driver_chipcommon_pmu.c | 192 | ||||
-rw-r--r-- | drivers/bcma/driver_mips.c | 256 | ||||
-rw-r--r-- | drivers/bcma/driver_pci.c | 17 | ||||
-rw-r--r-- | drivers/bcma/host_pci.c | 1 | ||||
-rw-r--r-- | drivers/bcma/host_soc.c | 183 | ||||
-rw-r--r-- | drivers/bcma/main.c | 71 | ||||
-rw-r--r-- | drivers/bcma/scan.c | 348 | ||||
-rw-r--r-- | drivers/bcma/sprom.c | 15 |
13 files changed, 1047 insertions, 124 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..893f6e0c759f 100644 --- a/drivers/bcma/core.c +++ b/drivers/bcma/core.c | |||
@@ -6,6 +6,7 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include "bcma_private.h" | 8 | #include "bcma_private.h" |
9 | #include <linux/export.h> | ||
9 | #include <linux/bcma/bcma.h> | 10 | #include <linux/bcma/bcma.h> |
10 | 11 | ||
11 | bool bcma_core_is_enabled(struct bcma_device *core) | 12 | bool bcma_core_is_enabled(struct bcma_device *core) |
@@ -110,6 +111,8 @@ EXPORT_SYMBOL_GPL(bcma_core_pll_ctl); | |||
110 | u32 bcma_core_dma_translation(struct bcma_device *core) | 111 | u32 bcma_core_dma_translation(struct bcma_device *core) |
111 | { | 112 | { |
112 | switch (core->bus->hosttype) { | 113 | switch (core->bus->hosttype) { |
114 | case BCMA_HOSTTYPE_SOC: | ||
115 | return 0; | ||
113 | case BCMA_HOSTTYPE_PCI: | 116 | case BCMA_HOSTTYPE_PCI: |
114 | if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64) | 117 | if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64) |
115 | return BCMA_DMA_TRANSLATION_DMA64_CMT; | 118 | return BCMA_DMA_TRANSLATION_DMA64_CMT; |
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 851e05bc948a..e9f1b3fd252c 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include "bcma_private.h" | 11 | #include "bcma_private.h" |
12 | #include <linux/export.h> | ||
12 | #include <linux/bcma/bcma.h> | 13 | #include <linux/bcma/bcma.h> |
13 | 14 | ||
14 | static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, | 15 | static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, |
@@ -26,6 +27,9 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) | |||
26 | u32 leddc_on = 10; | 27 | u32 leddc_on = 10; |
27 | u32 leddc_off = 90; | 28 | u32 leddc_off = 90; |
28 | 29 | ||
30 | if (cc->setup_done) | ||
31 | return; | ||
32 | |||
29 | if (cc->core->id.rev >= 11) | 33 | if (cc->core->id.rev >= 11) |
30 | cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); | 34 | cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); |
31 | cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); | 35 | cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); |
@@ -52,6 +56,8 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) | |||
52 | ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | | 56 | ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | |
53 | (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); | 57 | (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); |
54 | } | 58 | } |
59 | |||
60 | cc->setup_done = true; | ||
55 | } | 61 | } |
56 | 62 | ||
57 | /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ | 63 | /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ |
@@ -101,3 +107,51 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value) | |||
101 | { | 107 | { |
102 | return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); | 108 | return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); |
103 | } | 109 | } |
110 | |||
111 | #ifdef CONFIG_BCMA_DRIVER_MIPS | ||
112 | void bcma_chipco_serial_init(struct bcma_drv_cc *cc) | ||
113 | { | ||
114 | unsigned int irq; | ||
115 | u32 baud_base; | ||
116 | u32 i; | ||
117 | unsigned int ccrev = cc->core->id.rev; | ||
118 | struct bcma_serial_port *ports = cc->serial_ports; | ||
119 | |||
120 | if (ccrev >= 11 && ccrev != 15) { | ||
121 | /* Fixed ALP clock */ | ||
122 | baud_base = bcma_pmu_alp_clock(cc); | ||
123 | if (ccrev >= 21) { | ||
124 | /* Turn off UART clock before switching clocksource. */ | ||
125 | bcma_cc_write32(cc, BCMA_CC_CORECTL, | ||
126 | bcma_cc_read32(cc, BCMA_CC_CORECTL) | ||
127 | & ~BCMA_CC_CORECTL_UARTCLKEN); | ||
128 | } | ||
129 | /* Set the override bit so we don't divide it */ | ||
130 | bcma_cc_write32(cc, BCMA_CC_CORECTL, | ||
131 | bcma_cc_read32(cc, BCMA_CC_CORECTL) | ||
132 | | BCMA_CC_CORECTL_UARTCLK0); | ||
133 | if (ccrev >= 21) { | ||
134 | /* Re-enable the UART clock. */ | ||
135 | bcma_cc_write32(cc, BCMA_CC_CORECTL, | ||
136 | bcma_cc_read32(cc, BCMA_CC_CORECTL) | ||
137 | | BCMA_CC_CORECTL_UARTCLKEN); | ||
138 | } | ||
139 | } else { | ||
140 | pr_err("serial not supported on this device ccrev: 0x%x\n", | ||
141 | ccrev); | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | irq = bcma_core_mips_irq(cc->core); | ||
146 | |||
147 | /* Determine the registers of the UARTs */ | ||
148 | cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); | ||
149 | for (i = 0; i < cc->nr_serial_ports; i++) { | ||
150 | ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA + | ||
151 | (i * 256); | ||
152 | ports[i].irq = irq; | ||
153 | ports[i].baud_base = baud_base; | ||
154 | ports[i].reg_shift = 0; | ||
155 | } | ||
156 | } | ||
157 | #endif /* CONFIG_BCMA_DRIVER_MIPS */ | ||
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index fcc63db0ce75..800163c8c2e7 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c | |||
@@ -9,22 +9,50 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include "bcma_private.h" | 11 | #include "bcma_private.h" |
12 | #include <linux/export.h> | ||
12 | #include <linux/bcma/bcma.h> | 13 | #include <linux/bcma/bcma.h> |
13 | 14 | ||
14 | static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, | 15 | static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset) |
15 | u32 offset, u32 mask, u32 set) | ||
16 | { | 16 | { |
17 | u32 value; | 17 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); |
18 | bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); | ||
19 | return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA); | ||
20 | } | ||
18 | 21 | ||
19 | bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); | 22 | void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value) |
23 | { | ||
24 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); | ||
25 | bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); | ||
26 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value); | ||
27 | } | ||
28 | EXPORT_SYMBOL_GPL(bcma_chipco_pll_write); | ||
29 | |||
30 | void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, | ||
31 | u32 set) | ||
32 | { | ||
33 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); | ||
34 | bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); | ||
35 | bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set); | ||
36 | } | ||
37 | EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset); | ||
38 | |||
39 | void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, | ||
40 | u32 offset, u32 mask, u32 set) | ||
41 | { | ||
20 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset); | 42 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset); |
21 | bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); | 43 | bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); |
22 | value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); | 44 | bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set); |
23 | value &= mask; | 45 | } |
24 | value |= set; | 46 | EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset); |
25 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value); | 47 | |
26 | bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); | 48 | void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, |
49 | u32 set) | ||
50 | { | ||
51 | bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset); | ||
52 | bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR); | ||
53 | bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set); | ||
27 | } | 54 | } |
55 | EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset); | ||
28 | 56 | ||
29 | static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) | 57 | static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) |
30 | { | 58 | { |
@@ -83,6 +111,24 @@ void bcma_pmu_swreg_init(struct bcma_drv_cc *cc) | |||
83 | } | 111 | } |
84 | } | 112 | } |
85 | 113 | ||
114 | /* Disable to allow reading SPROM. Don't know the adventages of enabling it. */ | ||
115 | void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable) | ||
116 | { | ||
117 | struct bcma_bus *bus = cc->core->bus; | ||
118 | u32 val; | ||
119 | |||
120 | val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL); | ||
121 | if (enable) { | ||
122 | val |= BCMA_CHIPCTL_4331_EXTPA_EN; | ||
123 | if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11) | ||
124 | val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; | ||
125 | } else { | ||
126 | val &= ~BCMA_CHIPCTL_4331_EXTPA_EN; | ||
127 | val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; | ||
128 | } | ||
129 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val); | ||
130 | } | ||
131 | |||
86 | void bcma_pmu_workarounds(struct bcma_drv_cc *cc) | 132 | void bcma_pmu_workarounds(struct bcma_drv_cc *cc) |
87 | { | 133 | { |
88 | struct bcma_bus *bus = cc->core->bus; | 134 | struct bcma_bus *bus = cc->core->bus; |
@@ -92,7 +138,7 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc) | |||
92 | bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); | 138 | bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); |
93 | break; | 139 | break; |
94 | case 0x4331: | 140 | case 0x4331: |
95 | pr_err("Enabling Ext PA lines not implemented\n"); | 141 | /* BCM4331 workaround is SPROM-related, we put it in sprom.c */ |
96 | break; | 142 | break; |
97 | case 43224: | 143 | case 43224: |
98 | if (bus->chipinfo.rev == 0) { | 144 | if (bus->chipinfo.rev == 0) { |
@@ -136,3 +182,129 @@ void bcma_pmu_init(struct bcma_drv_cc *cc) | |||
136 | bcma_pmu_swreg_init(cc); | 182 | bcma_pmu_swreg_init(cc); |
137 | bcma_pmu_workarounds(cc); | 183 | bcma_pmu_workarounds(cc); |
138 | } | 184 | } |
185 | |||
186 | u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc) | ||
187 | { | ||
188 | struct bcma_bus *bus = cc->core->bus; | ||
189 | |||
190 | switch (bus->chipinfo.id) { | ||
191 | case 0x4716: | ||
192 | case 0x4748: | ||
193 | case 47162: | ||
194 | case 0x4313: | ||
195 | case 0x5357: | ||
196 | case 0x4749: | ||
197 | case 53572: | ||
198 | /* always 20Mhz */ | ||
199 | return 20000 * 1000; | ||
200 | case 0x5356: | ||
201 | case 0x5300: | ||
202 | /* always 25Mhz */ | ||
203 | return 25000 * 1000; | ||
204 | default: | ||
205 | pr_warn("No ALP clock specified for %04X device, " | ||
206 | "pmu rev. %d, using default %d Hz\n", | ||
207 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK); | ||
208 | } | ||
209 | return BCMA_CC_PMU_ALP_CLOCK; | ||
210 | } | ||
211 | |||
212 | /* Find the output of the "m" pll divider given pll controls that start with | ||
213 | * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc. | ||
214 | */ | ||
215 | static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) | ||
216 | { | ||
217 | u32 tmp, div, ndiv, p1, p2, fc; | ||
218 | struct bcma_bus *bus = cc->core->bus; | ||
219 | |||
220 | BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0)); | ||
221 | |||
222 | BUG_ON(!m || m > 4); | ||
223 | |||
224 | if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) { | ||
225 | /* Detect failure in clock setting */ | ||
226 | tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); | ||
227 | if (tmp & 0x40000) | ||
228 | return 133 * 1000000; | ||
229 | } | ||
230 | |||
231 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF); | ||
232 | p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT; | ||
233 | p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT; | ||
234 | |||
235 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF); | ||
236 | div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) & | ||
237 | BCMA_CC_PPL_MDIV_MASK; | ||
238 | |||
239 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF); | ||
240 | ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT; | ||
241 | |||
242 | /* Do calculation in Mhz */ | ||
243 | fc = bcma_pmu_alp_clock(cc) / 1000000; | ||
244 | fc = (p1 * ndiv * fc) / p2; | ||
245 | |||
246 | /* Return clock in Hertz */ | ||
247 | return (fc / div) * 1000000; | ||
248 | } | ||
249 | |||
250 | /* query bus clock frequency for PMU-enabled chipcommon */ | ||
251 | u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc) | ||
252 | { | ||
253 | struct bcma_bus *bus = cc->core->bus; | ||
254 | |||
255 | switch (bus->chipinfo.id) { | ||
256 | case 0x4716: | ||
257 | case 0x4748: | ||
258 | case 47162: | ||
259 | return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, | ||
260 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
261 | case 0x5356: | ||
262 | return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0, | ||
263 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
264 | case 0x5357: | ||
265 | case 0x4749: | ||
266 | return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0, | ||
267 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
268 | case 0x5300: | ||
269 | return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0, | ||
270 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
271 | case 53572: | ||
272 | return 75000000; | ||
273 | default: | ||
274 | pr_warn("No backplane clock specified for %04X device, " | ||
275 | "pmu rev. %d, using default %d Hz\n", | ||
276 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK); | ||
277 | } | ||
278 | return BCMA_CC_PMU_HT_CLOCK; | ||
279 | } | ||
280 | |||
281 | /* query cpu clock frequency for PMU-enabled chipcommon */ | ||
282 | u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc) | ||
283 | { | ||
284 | struct bcma_bus *bus = cc->core->bus; | ||
285 | |||
286 | if (bus->chipinfo.id == 53572) | ||
287 | return 300000000; | ||
288 | |||
289 | if (cc->pmu.rev >= 5) { | ||
290 | u32 pll; | ||
291 | switch (bus->chipinfo.id) { | ||
292 | case 0x5356: | ||
293 | pll = BCMA_CC_PMU5356_MAINPLL_PLL0; | ||
294 | break; | ||
295 | case 0x5357: | ||
296 | case 0x4749: | ||
297 | pll = BCMA_CC_PMU5357_MAINPLL_PLL0; | ||
298 | break; | ||
299 | default: | ||
300 | pll = BCMA_CC_PMU4716_MAINPLL_PLL0; | ||
301 | break; | ||
302 | } | ||
303 | |||
304 | /* TODO: if (bus->chipinfo.id == 0x5300) | ||
305 | return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */ | ||
306 | return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU); | ||
307 | } | ||
308 | |||
309 | return bcma_pmu_get_clockcontrol(cc); | ||
310 | } | ||
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..4fde6254f04e 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include "bcma_private.h" | 11 | #include "bcma_private.h" |
12 | #include <linux/export.h> | ||
12 | #include <linux/bcma/bcma.h> | 13 | #include <linux/bcma/bcma.h> |
13 | 14 | ||
14 | /************************************************** | 15 | /************************************************** |
@@ -173,7 +174,7 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) | |||
173 | return false; | 174 | return false; |
174 | 175 | ||
175 | #ifdef CONFIG_SSB_DRIVER_PCICORE | 176 | #ifdef CONFIG_SSB_DRIVER_PCICORE |
176 | if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI) | 177 | if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI) |
177 | return false; | 178 | return false; |
178 | #endif /* CONFIG_SSB_DRIVER_PCICORE */ | 179 | #endif /* CONFIG_SSB_DRIVER_PCICORE */ |
179 | 180 | ||
@@ -189,6 +190,9 @@ static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) | |||
189 | 190 | ||
190 | void bcma_core_pci_init(struct bcma_drv_pci *pc) | 191 | void bcma_core_pci_init(struct bcma_drv_pci *pc) |
191 | { | 192 | { |
193 | if (pc->setup_done) | ||
194 | return; | ||
195 | |||
192 | if (bcma_core_pci_is_in_hostmode(pc)) { | 196 | if (bcma_core_pci_is_in_hostmode(pc)) { |
193 | #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE | 197 | #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE |
194 | bcma_core_pci_hostmode_init(pc); | 198 | bcma_core_pci_hostmode_init(pc); |
@@ -198,6 +202,8 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc) | |||
198 | } else { | 202 | } else { |
199 | bcma_core_pci_clientmode_init(pc); | 203 | bcma_core_pci_clientmode_init(pc); |
200 | } | 204 | } |
205 | |||
206 | pc->setup_done = true; | ||
201 | } | 207 | } |
202 | 208 | ||
203 | int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, | 209 | int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, |
@@ -205,7 +211,14 @@ int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, | |||
205 | { | 211 | { |
206 | struct pci_dev *pdev = pc->core->bus->host_pci; | 212 | struct pci_dev *pdev = pc->core->bus->host_pci; |
207 | u32 coremask, tmp; | 213 | u32 coremask, tmp; |
208 | int err; | 214 | int err = 0; |
215 | |||
216 | if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) { | ||
217 | /* This bcma device is not on a PCI host-bus. So the IRQs are | ||
218 | * not routed through the PCI core. | ||
219 | * So we must not enable routing through the PCI core. */ | ||
220 | goto out; | ||
221 | } | ||
209 | 222 | ||
210 | err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); | 223 | err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); |
211 | if (err) | 224 | if (err) |
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index ac4bc626c149..1b51d8b7ac80 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
10 | #include <linux/bcma/bcma.h> | 10 | #include <linux/bcma/bcma.h> |
11 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
12 | #include <linux/module.h> | ||
12 | 13 | ||
13 | static void bcma_host_pci_switch_core(struct bcma_device *core) | 14 | static void bcma_host_pci_switch_core(struct bcma_device *core) |
14 | { | 15 | { |
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 73b7b1a18fab..70c84b951098 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c | |||
@@ -6,6 +6,7 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include "bcma_private.h" | 8 | #include "bcma_private.h" |
9 | #include <linux/module.h> | ||
9 | #include <linux/bcma/bcma.h> | 10 | #include <linux/bcma/bcma.h> |
10 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
11 | 12 | ||
@@ -68,6 +69,10 @@ static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) | |||
68 | static void bcma_release_core_dev(struct device *dev) | 69 | static void bcma_release_core_dev(struct device *dev) |
69 | { | 70 | { |
70 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); | 71 | struct bcma_device *core = container_of(dev, struct bcma_device, dev); |
72 | if (core->io_addr) | ||
73 | iounmap(core->io_addr); | ||
74 | if (core->io_wrap) | ||
75 | iounmap(core->io_wrap); | ||
71 | kfree(core); | 76 | kfree(core); |
72 | } | 77 | } |
73 | 78 | ||
@@ -82,6 +87,7 @@ static int bcma_register_cores(struct bcma_bus *bus) | |||
82 | case BCMA_CORE_CHIPCOMMON: | 87 | case BCMA_CORE_CHIPCOMMON: |
83 | case BCMA_CORE_PCI: | 88 | case BCMA_CORE_PCI: |
84 | case BCMA_CORE_PCIE: | 89 | case BCMA_CORE_PCIE: |
90 | case BCMA_CORE_MIPS_74K: | ||
85 | continue; | 91 | continue; |
86 | } | 92 | } |
87 | 93 | ||
@@ -95,7 +101,10 @@ static int bcma_register_cores(struct bcma_bus *bus) | |||
95 | core->dma_dev = &bus->host_pci->dev; | 101 | core->dma_dev = &bus->host_pci->dev; |
96 | core->irq = bus->host_pci->irq; | 102 | core->irq = bus->host_pci->irq; |
97 | break; | 103 | break; |
98 | case BCMA_HOSTTYPE_NONE: | 104 | case BCMA_HOSTTYPE_SOC: |
105 | core->dev.dma_mask = &core->dev.coherent_dma_mask; | ||
106 | core->dma_dev = &core->dev; | ||
107 | break; | ||
99 | case BCMA_HOSTTYPE_SDIO: | 108 | case BCMA_HOSTTYPE_SDIO: |
100 | break; | 109 | break; |
101 | } | 110 | } |
@@ -142,6 +151,13 @@ int bcma_bus_register(struct bcma_bus *bus) | |||
142 | bcma_core_chipcommon_init(&bus->drv_cc); | 151 | bcma_core_chipcommon_init(&bus->drv_cc); |
143 | } | 152 | } |
144 | 153 | ||
154 | /* Init MIPS core */ | ||
155 | core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); | ||
156 | if (core) { | ||
157 | bus->drv_mips.core = core; | ||
158 | bcma_core_mips_init(&bus->drv_mips); | ||
159 | } | ||
160 | |||
145 | /* Init PCIE core */ | 161 | /* Init PCIE core */ |
146 | core = bcma_find_core(bus, BCMA_CORE_PCIE); | 162 | core = bcma_find_core(bus, BCMA_CORE_PCIE); |
147 | if (core) { | 163 | if (core) { |
@@ -171,6 +187,59 @@ void bcma_bus_unregister(struct bcma_bus *bus) | |||
171 | bcma_unregister_cores(bus); | 187 | bcma_unregister_cores(bus); |
172 | } | 188 | } |
173 | 189 | ||
190 | int __init bcma_bus_early_register(struct bcma_bus *bus, | ||
191 | struct bcma_device *core_cc, | ||
192 | struct bcma_device *core_mips) | ||
193 | { | ||
194 | int err; | ||
195 | struct bcma_device *core; | ||
196 | struct bcma_device_id match; | ||
197 | |||
198 | bcma_init_bus(bus); | ||
199 | |||
200 | match.manuf = BCMA_MANUF_BCM; | ||
201 | match.id = BCMA_CORE_CHIPCOMMON; | ||
202 | match.class = BCMA_CL_SIM; | ||
203 | match.rev = BCMA_ANY_REV; | ||
204 | |||
205 | /* Scan for chip common core */ | ||
206 | err = bcma_bus_scan_early(bus, &match, core_cc); | ||
207 | if (err) { | ||
208 | pr_err("Failed to scan for common core: %d\n", err); | ||
209 | return -1; | ||
210 | } | ||
211 | |||
212 | match.manuf = BCMA_MANUF_MIPS; | ||
213 | match.id = BCMA_CORE_MIPS_74K; | ||
214 | match.class = BCMA_CL_SIM; | ||
215 | match.rev = BCMA_ANY_REV; | ||
216 | |||
217 | /* Scan for mips core */ | ||
218 | err = bcma_bus_scan_early(bus, &match, core_mips); | ||
219 | if (err) { | ||
220 | pr_err("Failed to scan for mips core: %d\n", err); | ||
221 | return -1; | ||
222 | } | ||
223 | |||
224 | /* Init CC core */ | ||
225 | core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); | ||
226 | if (core) { | ||
227 | bus->drv_cc.core = core; | ||
228 | bcma_core_chipcommon_init(&bus->drv_cc); | ||
229 | } | ||
230 | |||
231 | /* Init MIPS core */ | ||
232 | core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); | ||
233 | if (core) { | ||
234 | bus->drv_mips.core = core; | ||
235 | bcma_core_mips_init(&bus->drv_mips); | ||
236 | } | ||
237 | |||
238 | pr_info("Early bus registered\n"); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
174 | int __bcma_driver_register(struct bcma_driver *drv, struct module *owner) | 243 | int __bcma_driver_register(struct bcma_driver *drv, struct module *owner) |
175 | { | 244 | { |
176 | drv->drv.name = drv->name; | 245 | drv->drv.name = drv->name; |
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 40d7dcce8933..cad994857683 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 | s32 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 | } |
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 8b5b7856abe3..d7292390d236 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c | |||
@@ -133,6 +133,15 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) | |||
133 | v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i]; | 133 | v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i]; |
134 | *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v); | 134 | *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v); |
135 | } | 135 | } |
136 | |||
137 | bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)]; | ||
138 | |||
139 | bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)]; | ||
140 | bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)]; | ||
141 | bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)]; | ||
142 | bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)]; | ||
143 | |||
144 | bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)]; | ||
136 | } | 145 | } |
137 | 146 | ||
138 | int bcma_sprom_get(struct bcma_bus *bus) | 147 | int bcma_sprom_get(struct bcma_bus *bus) |
@@ -152,6 +161,9 @@ int bcma_sprom_get(struct bcma_bus *bus) | |||
152 | if (!sprom) | 161 | if (!sprom) |
153 | return -ENOMEM; | 162 | return -ENOMEM; |
154 | 163 | ||
164 | if (bus->chipinfo.id == 0x4331) | ||
165 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); | ||
166 | |||
155 | /* Most cards have SPROM moved by additional offset 0x30 (48 dwords). | 167 | /* Most cards have SPROM moved by additional offset 0x30 (48 dwords). |
156 | * According to brcm80211 this applies to cards with PCIe rev >= 6 | 168 | * According to brcm80211 this applies to cards with PCIe rev >= 6 |
157 | * TODO: understand this condition and use it */ | 169 | * TODO: understand this condition and use it */ |
@@ -159,6 +171,9 @@ int bcma_sprom_get(struct bcma_bus *bus) | |||
159 | BCMA_CC_SPROM_PCIE6; | 171 | BCMA_CC_SPROM_PCIE6; |
160 | bcma_sprom_read(bus, offset, sprom); | 172 | bcma_sprom_read(bus, offset, sprom); |
161 | 173 | ||
174 | if (bus->chipinfo.id == 0x4331) | ||
175 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); | ||
176 | |||
162 | err = bcma_sprom_valid(sprom); | 177 | err = bcma_sprom_valid(sprom); |
163 | if (err) | 178 | if (err) |
164 | goto out; | 179 | goto out; |