diff options
Diffstat (limited to 'drivers/ssb')
-rw-r--r-- | drivers/ssb/Kconfig | 117 | ||||
-rw-r--r-- | drivers/ssb/Makefile | 18 | ||||
-rw-r--r-- | drivers/ssb/b43_pci_bridge.c | 46 | ||||
-rw-r--r-- | drivers/ssb/driver_chipcommon.c | 446 | ||||
-rw-r--r-- | drivers/ssb/driver_extif.c | 129 | ||||
-rw-r--r-- | drivers/ssb/driver_mipscore.c | 223 | ||||
-rw-r--r-- | drivers/ssb/driver_pcicore.c | 576 | ||||
-rw-r--r-- | drivers/ssb/main.c | 1162 | ||||
-rw-r--r-- | drivers/ssb/pci.c | 740 | ||||
-rw-r--r-- | drivers/ssb/pcihost_wrapper.c | 104 | ||||
-rw-r--r-- | drivers/ssb/pcmcia.c | 271 | ||||
-rw-r--r-- | drivers/ssb/scan.c | 413 | ||||
-rw-r--r-- | drivers/ssb/ssb_private.h | 136 |
13 files changed, 4381 insertions, 0 deletions
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig new file mode 100644 index 000000000000..b4a5e5e9d9fc --- /dev/null +++ b/drivers/ssb/Kconfig | |||
@@ -0,0 +1,117 @@ | |||
1 | menu "Sonics Silicon Backplane" | ||
2 | |||
3 | config SSB_POSSIBLE | ||
4 | bool | ||
5 | depends on HAS_IOMEM | ||
6 | default y | ||
7 | |||
8 | config SSB | ||
9 | tristate "Sonics Silicon Backplane support" | ||
10 | depends on SSB_POSSIBLE | ||
11 | help | ||
12 | Support for the Sonics Silicon Backplane bus. | ||
13 | You only need to enable this option, if you are | ||
14 | configuring a kernel for an embedded system with | ||
15 | this bus. | ||
16 | It will be auto-selected if needed in other | ||
17 | environments. | ||
18 | |||
19 | The module will be called ssb. | ||
20 | |||
21 | If unsure, say N. | ||
22 | |||
23 | config SSB_PCIHOST_POSSIBLE | ||
24 | bool | ||
25 | depends on SSB && PCI | ||
26 | default y | ||
27 | |||
28 | config SSB_PCIHOST | ||
29 | bool "Support for SSB on PCI-bus host" | ||
30 | depends on SSB_PCIHOST_POSSIBLE | ||
31 | default y | ||
32 | help | ||
33 | Support for a Sonics Silicon Backplane on top | ||
34 | of a PCI device. | ||
35 | |||
36 | If unsure, say Y | ||
37 | |||
38 | config SSB_PCMCIAHOST_POSSIBLE | ||
39 | bool | ||
40 | depends on SSB && PCMCIA && EXPERIMENTAL | ||
41 | default y | ||
42 | |||
43 | config SSB_PCMCIAHOST | ||
44 | bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)" | ||
45 | depends on SSB_PCMCIAHOST_POSSIBLE | ||
46 | help | ||
47 | Support for a Sonics Silicon Backplane on top | ||
48 | of a PCMCIA device. | ||
49 | |||
50 | If unsure, say N | ||
51 | |||
52 | config SSB_SILENT | ||
53 | bool "No SSB kernel messages" | ||
54 | depends on SSB && EMBEDDED | ||
55 | help | ||
56 | This option turns off all Sonics Silicon Backplane printks. | ||
57 | Note that you won't be able to identify problems, once | ||
58 | messages are turned off. | ||
59 | This might only be desired for production kernels on | ||
60 | embedded devices to reduce the kernel size. | ||
61 | |||
62 | Say N | ||
63 | |||
64 | config SSB_DEBUG | ||
65 | bool "SSB debugging" | ||
66 | depends on SSB && !SSB_SILENT | ||
67 | help | ||
68 | This turns on additional runtime checks and debugging | ||
69 | messages. Turn this on for SSB troubleshooting. | ||
70 | |||
71 | If unsure, say N | ||
72 | |||
73 | config SSB_SERIAL | ||
74 | bool | ||
75 | depends on SSB | ||
76 | # ChipCommon and ExtIf serial support routines. | ||
77 | |||
78 | config SSB_DRIVER_PCICORE_POSSIBLE | ||
79 | bool | ||
80 | depends on SSB_PCIHOST | ||
81 | default y | ||
82 | |||
83 | config SSB_DRIVER_PCICORE | ||
84 | bool "SSB PCI core driver" | ||
85 | depends on SSB_DRIVER_PCICORE_POSSIBLE | ||
86 | help | ||
87 | Driver for the Sonics Silicon Backplane attached | ||
88 | Broadcom PCI core. | ||
89 | |||
90 | If unsure, say Y | ||
91 | |||
92 | config SSB_PCICORE_HOSTMODE | ||
93 | bool "Hostmode support for SSB PCI core (EXPERIMENTAL)" | ||
94 | depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && EXPERIMENTAL | ||
95 | help | ||
96 | PCIcore hostmode operation (external PCI bus). | ||
97 | |||
98 | config SSB_DRIVER_MIPS | ||
99 | bool "SSB Broadcom MIPS core driver (EXPERIMENTAL)" | ||
100 | depends on SSB && MIPS && EXPERIMENTAL | ||
101 | select SSB_SERIAL | ||
102 | help | ||
103 | Driver for the Sonics Silicon Backplane attached | ||
104 | Broadcom MIPS core. | ||
105 | |||
106 | If unsure, say N | ||
107 | |||
108 | config SSB_DRIVER_EXTIF | ||
109 | bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)" | ||
110 | depends on SSB_DRIVER_MIPS && EXPERIMENTAL | ||
111 | help | ||
112 | Driver for the Sonics Silicon Backplane attached | ||
113 | Broadcom EXTIF core. | ||
114 | |||
115 | If unsure, say N | ||
116 | |||
117 | endmenu | ||
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile new file mode 100644 index 000000000000..7be397595805 --- /dev/null +++ b/drivers/ssb/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | # core | ||
2 | ssb-y += main.o scan.o | ||
3 | |||
4 | # host support | ||
5 | ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o | ||
6 | ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o | ||
7 | |||
8 | # built-in drivers | ||
9 | ssb-y += driver_chipcommon.o | ||
10 | ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o | ||
11 | ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o | ||
12 | ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o | ||
13 | |||
14 | # b43 pci-ssb-bridge driver | ||
15 | # Not strictly a part of SSB, but kept here for convenience | ||
16 | ssb-$(CONFIG_SSB_PCIHOST) += b43_pci_bridge.o | ||
17 | |||
18 | obj-$(CONFIG_SSB) += ssb.o | ||
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c new file mode 100644 index 000000000000..fa3bd292f5f7 --- /dev/null +++ b/drivers/ssb/b43_pci_bridge.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Broadcom 43xx PCI-SSB bridge module | ||
3 | * | ||
4 | * This technically is a seperate PCI driver module, but | ||
5 | * because of its small size we include it in the SSB core | ||
6 | * instead of creating a standalone module. | ||
7 | * | ||
8 | * Copyright 2007 Michael Buesch <mb@bu3sch.de> | ||
9 | * | ||
10 | * Licensed under the GNU/GPL. See COPYING for details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/pci.h> | ||
14 | #include <linux/ssb/ssb.h> | ||
15 | |||
16 | |||
17 | static const struct pci_device_id b43_pci_bridge_tbl[] = { | ||
18 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) }, | ||
19 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) }, | ||
20 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) }, | ||
21 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) }, | ||
22 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) }, | ||
23 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) }, | ||
24 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) }, | ||
25 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) }, | ||
26 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) }, | ||
27 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) }, | ||
28 | { 0, }, | ||
29 | }; | ||
30 | MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl); | ||
31 | |||
32 | static struct pci_driver b43_pci_bridge_driver = { | ||
33 | .name = "b43-pci-bridge", | ||
34 | .id_table = b43_pci_bridge_tbl, | ||
35 | }; | ||
36 | |||
37 | |||
38 | int __init b43_pci_ssb_bridge_init(void) | ||
39 | { | ||
40 | return ssb_pcihost_register(&b43_pci_bridge_driver); | ||
41 | } | ||
42 | |||
43 | void __exit b43_pci_ssb_bridge_exit(void) | ||
44 | { | ||
45 | ssb_pcihost_unregister(&b43_pci_bridge_driver); | ||
46 | } | ||
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c new file mode 100644 index 000000000000..a890544e8fba --- /dev/null +++ b/drivers/ssb/driver_chipcommon.c | |||
@@ -0,0 +1,446 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * Broadcom ChipCommon core driver | ||
4 | * | ||
5 | * Copyright 2005, Broadcom Corporation | ||
6 | * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> | ||
7 | * | ||
8 | * Licensed under the GNU/GPL. See COPYING for details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/ssb/ssb.h> | ||
12 | #include <linux/ssb/ssb_regs.h> | ||
13 | #include <linux/pci.h> | ||
14 | |||
15 | #include "ssb_private.h" | ||
16 | |||
17 | |||
18 | /* Clock sources */ | ||
19 | enum ssb_clksrc { | ||
20 | /* PCI clock */ | ||
21 | SSB_CHIPCO_CLKSRC_PCI, | ||
22 | /* Crystal slow clock oscillator */ | ||
23 | SSB_CHIPCO_CLKSRC_XTALOS, | ||
24 | /* Low power oscillator */ | ||
25 | SSB_CHIPCO_CLKSRC_LOPWROS, | ||
26 | }; | ||
27 | |||
28 | |||
29 | static inline u32 chipco_read32(struct ssb_chipcommon *cc, | ||
30 | u16 offset) | ||
31 | { | ||
32 | return ssb_read32(cc->dev, offset); | ||
33 | } | ||
34 | |||
35 | static inline void chipco_write32(struct ssb_chipcommon *cc, | ||
36 | u16 offset, | ||
37 | u32 value) | ||
38 | { | ||
39 | ssb_write32(cc->dev, offset, value); | ||
40 | } | ||
41 | |||
42 | static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, | ||
43 | u32 mask, u32 value) | ||
44 | { | ||
45 | value &= mask; | ||
46 | value |= chipco_read32(cc, offset) & ~mask; | ||
47 | chipco_write32(cc, offset, value); | ||
48 | } | ||
49 | |||
50 | void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, | ||
51 | enum ssb_clkmode mode) | ||
52 | { | ||
53 | struct ssb_device *ccdev = cc->dev; | ||
54 | struct ssb_bus *bus; | ||
55 | u32 tmp; | ||
56 | |||
57 | if (!ccdev) | ||
58 | return; | ||
59 | bus = ccdev->bus; | ||
60 | /* chipcommon cores prior to rev6 don't support dynamic clock control */ | ||
61 | if (ccdev->id.revision < 6) | ||
62 | return; | ||
63 | /* chipcommon cores rev10 are a whole new ball game */ | ||
64 | if (ccdev->id.revision >= 10) | ||
65 | return; | ||
66 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) | ||
67 | return; | ||
68 | |||
69 | switch (mode) { | ||
70 | case SSB_CLKMODE_SLOW: | ||
71 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); | ||
72 | tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW; | ||
73 | chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); | ||
74 | break; | ||
75 | case SSB_CLKMODE_FAST: | ||
76 | ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ | ||
77 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); | ||
78 | tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; | ||
79 | tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; | ||
80 | chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); | ||
81 | break; | ||
82 | case SSB_CLKMODE_DYNAMIC: | ||
83 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); | ||
84 | tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; | ||
85 | tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; | ||
86 | tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; | ||
87 | if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) | ||
88 | tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; | ||
89 | chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); | ||
90 | |||
91 | /* for dynamic control, we have to release our xtal_pu "force on" */ | ||
92 | if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) | ||
93 | ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); | ||
94 | break; | ||
95 | default: | ||
96 | SSB_WARN_ON(1); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | /* Get the Slow Clock Source */ | ||
101 | static enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc) | ||
102 | { | ||
103 | struct ssb_bus *bus = cc->dev->bus; | ||
104 | u32 uninitialized_var(tmp); | ||
105 | |||
106 | if (cc->dev->id.revision < 6) { | ||
107 | if (bus->bustype == SSB_BUSTYPE_SSB || | ||
108 | bus->bustype == SSB_BUSTYPE_PCMCIA) | ||
109 | return SSB_CHIPCO_CLKSRC_XTALOS; | ||
110 | if (bus->bustype == SSB_BUSTYPE_PCI) { | ||
111 | pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp); | ||
112 | if (tmp & 0x10) | ||
113 | return SSB_CHIPCO_CLKSRC_PCI; | ||
114 | return SSB_CHIPCO_CLKSRC_XTALOS; | ||
115 | } | ||
116 | } | ||
117 | if (cc->dev->id.revision < 10) { | ||
118 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); | ||
119 | tmp &= 0x7; | ||
120 | if (tmp == 0) | ||
121 | return SSB_CHIPCO_CLKSRC_LOPWROS; | ||
122 | if (tmp == 1) | ||
123 | return SSB_CHIPCO_CLKSRC_XTALOS; | ||
124 | if (tmp == 2) | ||
125 | return SSB_CHIPCO_CLKSRC_PCI; | ||
126 | } | ||
127 | |||
128 | return SSB_CHIPCO_CLKSRC_XTALOS; | ||
129 | } | ||
130 | |||
131 | /* Get maximum or minimum (depending on get_max flag) slowclock frequency. */ | ||
132 | static int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max) | ||
133 | { | ||
134 | int uninitialized_var(limit); | ||
135 | enum ssb_clksrc clocksrc; | ||
136 | int divisor = 1; | ||
137 | u32 tmp; | ||
138 | |||
139 | clocksrc = chipco_pctl_get_slowclksrc(cc); | ||
140 | if (cc->dev->id.revision < 6) { | ||
141 | switch (clocksrc) { | ||
142 | case SSB_CHIPCO_CLKSRC_PCI: | ||
143 | divisor = 64; | ||
144 | break; | ||
145 | case SSB_CHIPCO_CLKSRC_XTALOS: | ||
146 | divisor = 32; | ||
147 | break; | ||
148 | default: | ||
149 | SSB_WARN_ON(1); | ||
150 | } | ||
151 | } else if (cc->dev->id.revision < 10) { | ||
152 | switch (clocksrc) { | ||
153 | case SSB_CHIPCO_CLKSRC_LOPWROS: | ||
154 | break; | ||
155 | case SSB_CHIPCO_CLKSRC_XTALOS: | ||
156 | case SSB_CHIPCO_CLKSRC_PCI: | ||
157 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); | ||
158 | divisor = (tmp >> 16) + 1; | ||
159 | divisor *= 4; | ||
160 | break; | ||
161 | } | ||
162 | } else { | ||
163 | tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL); | ||
164 | divisor = (tmp >> 16) + 1; | ||
165 | divisor *= 4; | ||
166 | } | ||
167 | |||
168 | switch (clocksrc) { | ||
169 | case SSB_CHIPCO_CLKSRC_LOPWROS: | ||
170 | if (get_max) | ||
171 | limit = 43000; | ||
172 | else | ||
173 | limit = 25000; | ||
174 | break; | ||
175 | case SSB_CHIPCO_CLKSRC_XTALOS: | ||
176 | if (get_max) | ||
177 | limit = 20200000; | ||
178 | else | ||
179 | limit = 19800000; | ||
180 | break; | ||
181 | case SSB_CHIPCO_CLKSRC_PCI: | ||
182 | if (get_max) | ||
183 | limit = 34000000; | ||
184 | else | ||
185 | limit = 25000000; | ||
186 | break; | ||
187 | } | ||
188 | limit /= divisor; | ||
189 | |||
190 | return limit; | ||
191 | } | ||
192 | |||
193 | static void chipco_powercontrol_init(struct ssb_chipcommon *cc) | ||
194 | { | ||
195 | struct ssb_bus *bus = cc->dev->bus; | ||
196 | |||
197 | if (bus->chip_id == 0x4321) { | ||
198 | if (bus->chip_rev == 0) | ||
199 | chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4); | ||
200 | else if (bus->chip_rev == 1) | ||
201 | chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4); | ||
202 | } | ||
203 | |||
204 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) | ||
205 | return; | ||
206 | |||
207 | if (cc->dev->id.revision >= 10) { | ||
208 | /* Set Idle Power clock rate to 1Mhz */ | ||
209 | chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, | ||
210 | (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & | ||
211 | 0x0000FFFF) | 0x00040000); | ||
212 | } else { | ||
213 | int maxfreq; | ||
214 | |||
215 | maxfreq = chipco_pctl_clockfreqlimit(cc, 1); | ||
216 | chipco_write32(cc, SSB_CHIPCO_PLLONDELAY, | ||
217 | (maxfreq * 150 + 999999) / 1000000); | ||
218 | chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY, | ||
219 | (maxfreq * 15 + 999999) / 1000000); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | static void calc_fast_powerup_delay(struct ssb_chipcommon *cc) | ||
224 | { | ||
225 | struct ssb_bus *bus = cc->dev->bus; | ||
226 | int minfreq; | ||
227 | unsigned int tmp; | ||
228 | u32 pll_on_delay; | ||
229 | |||
230 | if (bus->bustype != SSB_BUSTYPE_PCI) | ||
231 | return; | ||
232 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) | ||
233 | return; | ||
234 | |||
235 | minfreq = chipco_pctl_clockfreqlimit(cc, 0); | ||
236 | pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY); | ||
237 | tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; | ||
238 | SSB_WARN_ON(tmp & ~0xFFFF); | ||
239 | |||
240 | cc->fast_pwrup_delay = tmp; | ||
241 | } | ||
242 | |||
243 | void ssb_chipcommon_init(struct ssb_chipcommon *cc) | ||
244 | { | ||
245 | if (!cc->dev) | ||
246 | return; /* We don't have a ChipCommon */ | ||
247 | chipco_powercontrol_init(cc); | ||
248 | ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); | ||
249 | calc_fast_powerup_delay(cc); | ||
250 | } | ||
251 | |||
252 | void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state) | ||
253 | { | ||
254 | if (!cc->dev) | ||
255 | return; | ||
256 | ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); | ||
257 | } | ||
258 | |||
259 | void ssb_chipco_resume(struct ssb_chipcommon *cc) | ||
260 | { | ||
261 | if (!cc->dev) | ||
262 | return; | ||
263 | chipco_powercontrol_init(cc); | ||
264 | ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); | ||
265 | } | ||
266 | |||
267 | /* Get the processor clock */ | ||
268 | void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, | ||
269 | u32 *plltype, u32 *n, u32 *m) | ||
270 | { | ||
271 | *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); | ||
272 | *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); | ||
273 | switch (*plltype) { | ||
274 | case SSB_PLLTYPE_2: | ||
275 | case SSB_PLLTYPE_4: | ||
276 | case SSB_PLLTYPE_6: | ||
277 | case SSB_PLLTYPE_7: | ||
278 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); | ||
279 | break; | ||
280 | case SSB_PLLTYPE_3: | ||
281 | /* 5350 uses m2 to control mips */ | ||
282 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); | ||
283 | break; | ||
284 | default: | ||
285 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | /* Get the bus clock */ | ||
291 | void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, | ||
292 | u32 *plltype, u32 *n, u32 *m) | ||
293 | { | ||
294 | *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); | ||
295 | *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); | ||
296 | switch (*plltype) { | ||
297 | case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ | ||
298 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); | ||
299 | break; | ||
300 | case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ | ||
301 | if (cc->dev->bus->chip_id != 0x5365) { | ||
302 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); | ||
303 | break; | ||
304 | } | ||
305 | /* Fallthough */ | ||
306 | default: | ||
307 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | void ssb_chipco_timing_init(struct ssb_chipcommon *cc, | ||
312 | unsigned long ns) | ||
313 | { | ||
314 | struct ssb_device *dev = cc->dev; | ||
315 | struct ssb_bus *bus = dev->bus; | ||
316 | u32 tmp; | ||
317 | |||
318 | /* set register for external IO to control LED. */ | ||
319 | chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11); | ||
320 | tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ | ||
321 | tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 40ns */ | ||
322 | tmp |= DIV_ROUND_UP(240, ns); /* Waitcount-0 = 240ns */ | ||
323 | chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ | ||
324 | |||
325 | /* Set timing for the flash */ | ||
326 | tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT; /* Waitcount-3 = 10nS */ | ||
327 | tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT; /* Waitcount-1 = 10nS */ | ||
328 | tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120nS */ | ||
329 | if ((bus->chip_id == 0x5365) || | ||
330 | (dev->id.revision < 9)) | ||
331 | chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp); | ||
332 | if ((bus->chip_id == 0x5365) || | ||
333 | (dev->id.revision < 9) || | ||
334 | ((bus->chip_id == 0x5350) && (bus->chip_rev == 0))) | ||
335 | chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp); | ||
336 | |||
337 | if (bus->chip_id == 0x5350) { | ||
338 | /* Enable EXTIF */ | ||
339 | tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ | ||
340 | tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; /* Waitcount-2 = 20ns */ | ||
341 | tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */ | ||
342 | tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120ns */ | ||
343 | chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ | ||
344 | } | ||
345 | } | ||
346 | |||
347 | /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ | ||
348 | void | ||
349 | ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) | ||
350 | { | ||
351 | /* instant NMI */ | ||
352 | chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); | ||
353 | } | ||
354 | |||
355 | u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) | ||
356 | { | ||
357 | return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; | ||
358 | } | ||
359 | |||
360 | void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) | ||
361 | { | ||
362 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); | ||
363 | } | ||
364 | |||
365 | void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) | ||
366 | { | ||
367 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); | ||
368 | } | ||
369 | |||
370 | #ifdef CONFIG_SSB_SERIAL | ||
371 | int ssb_chipco_serial_init(struct ssb_chipcommon *cc, | ||
372 | struct ssb_serial_port *ports) | ||
373 | { | ||
374 | struct ssb_bus *bus = cc->dev->bus; | ||
375 | int nr_ports = 0; | ||
376 | u32 plltype; | ||
377 | unsigned int irq; | ||
378 | u32 baud_base, div; | ||
379 | u32 i, n; | ||
380 | |||
381 | plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); | ||
382 | irq = ssb_mips_irq(cc->dev); | ||
383 | |||
384 | if (plltype == SSB_PLLTYPE_1) { | ||
385 | /* PLL clock */ | ||
386 | baud_base = ssb_calc_clock_rate(plltype, | ||
387 | chipco_read32(cc, SSB_CHIPCO_CLOCK_N), | ||
388 | chipco_read32(cc, SSB_CHIPCO_CLOCK_M2)); | ||
389 | div = 1; | ||
390 | } else { | ||
391 | if (cc->dev->id.revision >= 11) { | ||
392 | /* Fixed ALP clock */ | ||
393 | baud_base = 20000000; | ||
394 | div = 1; | ||
395 | /* Set the override bit so we don't divide it */ | ||
396 | chipco_write32(cc, SSB_CHIPCO_CORECTL, | ||
397 | SSB_CHIPCO_CORECTL_UARTCLK0); | ||
398 | } else if (cc->dev->id.revision >= 3) { | ||
399 | /* Internal backplane clock */ | ||
400 | baud_base = ssb_clockspeed(bus); | ||
401 | div = chipco_read32(cc, SSB_CHIPCO_CLKDIV) | ||
402 | & SSB_CHIPCO_CLKDIV_UART; | ||
403 | } else { | ||
404 | /* Fixed internal backplane clock */ | ||
405 | baud_base = 88000000; | ||
406 | div = 48; | ||
407 | } | ||
408 | |||
409 | /* Clock source depends on strapping if UartClkOverride is unset */ | ||
410 | if ((cc->dev->id.revision > 0) && | ||
411 | !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) { | ||
412 | if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) == | ||
413 | SSB_CHIPCO_CAP_UARTCLK_INT) { | ||
414 | /* Internal divided backplane clock */ | ||
415 | baud_base /= div; | ||
416 | } else { | ||
417 | /* Assume external clock of 1.8432 MHz */ | ||
418 | baud_base = 1843200; | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /* Determine the registers of the UARTs */ | ||
424 | n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART); | ||
425 | for (i = 0; i < n; i++) { | ||
426 | void __iomem *cc_mmio; | ||
427 | void __iomem *uart_regs; | ||
428 | |||
429 | cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE); | ||
430 | uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA; | ||
431 | /* Offset changed at after rev 0 */ | ||
432 | if (cc->dev->id.revision == 0) | ||
433 | uart_regs += (i * 8); | ||
434 | else | ||
435 | uart_regs += (i * 256); | ||
436 | |||
437 | nr_ports++; | ||
438 | ports[i].regs = uart_regs; | ||
439 | ports[i].irq = irq; | ||
440 | ports[i].baud_base = baud_base; | ||
441 | ports[i].reg_shift = 0; | ||
442 | } | ||
443 | |||
444 | return nr_ports; | ||
445 | } | ||
446 | #endif /* CONFIG_SSB_SERIAL */ | ||
diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c new file mode 100644 index 000000000000..fe55eb8b038a --- /dev/null +++ b/drivers/ssb/driver_extif.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * Broadcom EXTIF core driver | ||
4 | * | ||
5 | * Copyright 2005, Broadcom Corporation | ||
6 | * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> | ||
7 | * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org> | ||
8 | * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net> | ||
9 | * | ||
10 | * Licensed under the GNU/GPL. See COPYING for details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/serial.h> | ||
14 | #include <linux/serial_core.h> | ||
15 | #include <linux/serial_reg.h> | ||
16 | |||
17 | #include "ssb_private.h" | ||
18 | |||
19 | |||
20 | static inline u32 extif_read32(struct ssb_extif *extif, u16 offset) | ||
21 | { | ||
22 | return ssb_read32(extif->dev, offset); | ||
23 | } | ||
24 | |||
25 | static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value) | ||
26 | { | ||
27 | ssb_write32(extif->dev, offset, value); | ||
28 | } | ||
29 | |||
30 | static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset, | ||
31 | u32 mask, u32 value) | ||
32 | { | ||
33 | value &= mask; | ||
34 | value |= extif_read32(extif, offset) & ~mask; | ||
35 | extif_write32(extif, offset, value); | ||
36 | } | ||
37 | |||
38 | #ifdef CONFIG_SSB_SERIAL | ||
39 | static bool serial_exists(u8 *regs) | ||
40 | { | ||
41 | u8 save_mcr, msr = 0; | ||
42 | |||
43 | if (regs) { | ||
44 | save_mcr = regs[UART_MCR]; | ||
45 | regs[UART_MCR] = (UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS); | ||
46 | msr = regs[UART_MSR] & (UART_MSR_DCD | UART_MSR_RI | ||
47 | | UART_MSR_CTS | UART_MSR_DSR); | ||
48 | regs[UART_MCR] = save_mcr; | ||
49 | } | ||
50 | return (msr == (UART_MSR_DCD | UART_MSR_CTS)); | ||
51 | } | ||
52 | |||
53 | int ssb_extif_serial_init(struct ssb_extif *extif, struct ssb_serial_port *ports) | ||
54 | { | ||
55 | u32 i, nr_ports = 0; | ||
56 | |||
57 | /* Disable GPIO interrupt initially */ | ||
58 | extif_write32(extif, SSB_EXTIF_GPIO_INTPOL, 0); | ||
59 | extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 0); | ||
60 | |||
61 | for (i = 0; i < 2; i++) { | ||
62 | void __iomem *uart_regs; | ||
63 | |||
64 | uart_regs = ioremap_nocache(SSB_EUART, 16); | ||
65 | if (uart_regs) { | ||
66 | uart_regs += (i * 8); | ||
67 | |||
68 | if (serial_exists(uart_regs) && ports) { | ||
69 | extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 2); | ||
70 | |||
71 | nr_ports++; | ||
72 | ports[i].regs = uart_regs; | ||
73 | ports[i].irq = 2; | ||
74 | ports[i].baud_base = 13500000; | ||
75 | ports[i].reg_shift = 0; | ||
76 | } | ||
77 | iounmap(uart_regs); | ||
78 | } | ||
79 | } | ||
80 | return nr_ports; | ||
81 | } | ||
82 | #endif /* CONFIG_SSB_SERIAL */ | ||
83 | |||
84 | void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns) | ||
85 | { | ||
86 | u32 tmp; | ||
87 | |||
88 | /* Initialize extif so we can get to the LEDs and external UART */ | ||
89 | extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN); | ||
90 | |||
91 | /* Set timing for the flash */ | ||
92 | tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; | ||
93 | tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; | ||
94 | tmp |= DIV_ROUND_UP(120, ns); | ||
95 | extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); | ||
96 | |||
97 | /* Set programmable interface timing for external uart */ | ||
98 | tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; | ||
99 | tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; | ||
100 | tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; | ||
101 | tmp |= DIV_ROUND_UP(120, ns); | ||
102 | extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); | ||
103 | } | ||
104 | |||
105 | void ssb_extif_get_clockcontrol(struct ssb_extif *extif, | ||
106 | u32 *pll_type, u32 *n, u32 *m) | ||
107 | { | ||
108 | *pll_type = SSB_PLLTYPE_1; | ||
109 | *n = extif_read32(extif, SSB_EXTIF_CLOCK_N); | ||
110 | *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); | ||
111 | } | ||
112 | |||
113 | u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) | ||
114 | { | ||
115 | return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; | ||
116 | } | ||
117 | |||
118 | void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) | ||
119 | { | ||
120 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), | ||
121 | mask, value); | ||
122 | } | ||
123 | |||
124 | void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) | ||
125 | { | ||
126 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), | ||
127 | mask, value); | ||
128 | } | ||
129 | |||
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c new file mode 100644 index 000000000000..ab8691a32580 --- /dev/null +++ b/drivers/ssb/driver_mipscore.c | |||
@@ -0,0 +1,223 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * Broadcom MIPS core driver | ||
4 | * | ||
5 | * Copyright 2005, Broadcom Corporation | ||
6 | * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> | ||
7 | * | ||
8 | * Licensed under the GNU/GPL. See COPYING for details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/ssb/ssb.h> | ||
12 | |||
13 | #include <linux/serial.h> | ||
14 | #include <linux/serial_core.h> | ||
15 | #include <linux/serial_reg.h> | ||
16 | #include <linux/time.h> | ||
17 | |||
18 | #include "ssb_private.h" | ||
19 | |||
20 | |||
21 | static inline u32 mips_read32(struct ssb_mipscore *mcore, | ||
22 | u16 offset) | ||
23 | { | ||
24 | return ssb_read32(mcore->dev, offset); | ||
25 | } | ||
26 | |||
27 | static inline void mips_write32(struct ssb_mipscore *mcore, | ||
28 | u16 offset, | ||
29 | u32 value) | ||
30 | { | ||
31 | ssb_write32(mcore->dev, offset, value); | ||
32 | } | ||
33 | |||
34 | static const u32 ipsflag_irq_mask[] = { | ||
35 | 0, | ||
36 | SSB_IPSFLAG_IRQ1, | ||
37 | SSB_IPSFLAG_IRQ2, | ||
38 | SSB_IPSFLAG_IRQ3, | ||
39 | SSB_IPSFLAG_IRQ4, | ||
40 | }; | ||
41 | |||
42 | static const u32 ipsflag_irq_shift[] = { | ||
43 | 0, | ||
44 | SSB_IPSFLAG_IRQ1_SHIFT, | ||
45 | SSB_IPSFLAG_IRQ2_SHIFT, | ||
46 | SSB_IPSFLAG_IRQ3_SHIFT, | ||
47 | SSB_IPSFLAG_IRQ4_SHIFT, | ||
48 | }; | ||
49 | |||
50 | static inline u32 ssb_irqflag(struct ssb_device *dev) | ||
51 | { | ||
52 | return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG; | ||
53 | } | ||
54 | |||
55 | /* Get the MIPS IRQ assignment for a specified device. | ||
56 | * If unassigned, 0 is returned. | ||
57 | */ | ||
58 | unsigned int ssb_mips_irq(struct ssb_device *dev) | ||
59 | { | ||
60 | struct ssb_bus *bus = dev->bus; | ||
61 | u32 irqflag; | ||
62 | u32 ipsflag; | ||
63 | u32 tmp; | ||
64 | unsigned int irq; | ||
65 | |||
66 | irqflag = ssb_irqflag(dev); | ||
67 | ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG); | ||
68 | for (irq = 1; irq <= 4; irq++) { | ||
69 | tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]); | ||
70 | if (tmp == irqflag) | ||
71 | break; | ||
72 | } | ||
73 | if (irq == 5) | ||
74 | irq = 0; | ||
75 | |||
76 | return irq; | ||
77 | } | ||
78 | |||
79 | static void clear_irq(struct ssb_bus *bus, unsigned int irq) | ||
80 | { | ||
81 | struct ssb_device *dev = bus->mipscore.dev; | ||
82 | |||
83 | /* Clear the IRQ in the MIPScore backplane registers */ | ||
84 | if (irq == 0) { | ||
85 | ssb_write32(dev, SSB_INTVEC, 0); | ||
86 | } else { | ||
87 | ssb_write32(dev, SSB_IPSFLAG, | ||
88 | ssb_read32(dev, SSB_IPSFLAG) | | ||
89 | ipsflag_irq_mask[irq]); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static void set_irq(struct ssb_device *dev, unsigned int irq) | ||
94 | { | ||
95 | unsigned int oldirq = ssb_mips_irq(dev); | ||
96 | struct ssb_bus *bus = dev->bus; | ||
97 | struct ssb_device *mdev = bus->mipscore.dev; | ||
98 | u32 irqflag = ssb_irqflag(dev); | ||
99 | |||
100 | dev->irq = irq + 2; | ||
101 | |||
102 | ssb_dprintk(KERN_INFO PFX | ||
103 | "set_irq: core 0x%04x, irq %d => %d\n", | ||
104 | dev->id.coreid, oldirq, irq); | ||
105 | /* clear the old irq */ | ||
106 | if (oldirq == 0) | ||
107 | ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))); | ||
108 | else | ||
109 | clear_irq(bus, oldirq); | ||
110 | |||
111 | /* assign the new one */ | ||
112 | if (irq == 0) | ||
113 | ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))); | ||
114 | |||
115 | irqflag <<= ipsflag_irq_shift[irq]; | ||
116 | irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]); | ||
117 | ssb_write32(mdev, SSB_IPSFLAG, irqflag); | ||
118 | } | ||
119 | |||
120 | static void ssb_mips_serial_init(struct ssb_mipscore *mcore) | ||
121 | { | ||
122 | struct ssb_bus *bus = mcore->dev->bus; | ||
123 | |||
124 | if (bus->extif.dev) | ||
125 | mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); | ||
126 | else if (bus->chipco.dev) | ||
127 | mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports); | ||
128 | else | ||
129 | mcore->nr_serial_ports = 0; | ||
130 | } | ||
131 | |||
132 | static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) | ||
133 | { | ||
134 | struct ssb_bus *bus = mcore->dev->bus; | ||
135 | |||
136 | mcore->flash_buswidth = 2; | ||
137 | if (bus->chipco.dev) { | ||
138 | mcore->flash_window = 0x1c000000; | ||
139 | mcore->flash_window_size = 0x02000000; | ||
140 | if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) | ||
141 | & SSB_CHIPCO_CFG_DS16) == 0) | ||
142 | mcore->flash_buswidth = 1; | ||
143 | } else { | ||
144 | mcore->flash_window = 0x1fc00000; | ||
145 | mcore->flash_window_size = 0x00400000; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | u32 ssb_cpu_clock(struct ssb_mipscore *mcore) | ||
150 | { | ||
151 | struct ssb_bus *bus = mcore->dev->bus; | ||
152 | u32 pll_type, n, m, rate = 0; | ||
153 | |||
154 | if (bus->extif.dev) { | ||
155 | ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); | ||
156 | } else if (bus->chipco.dev) { | ||
157 | ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m); | ||
158 | } else | ||
159 | return 0; | ||
160 | |||
161 | if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) { | ||
162 | rate = 200000000; | ||
163 | } else { | ||
164 | rate = ssb_calc_clock_rate(pll_type, n, m); | ||
165 | } | ||
166 | |||
167 | if (pll_type == SSB_PLLTYPE_6) { | ||
168 | rate *= 2; | ||
169 | } | ||
170 | |||
171 | return rate; | ||
172 | } | ||
173 | |||
174 | void ssb_mipscore_init(struct ssb_mipscore *mcore) | ||
175 | { | ||
176 | struct ssb_bus *bus = mcore->dev->bus; | ||
177 | struct ssb_device *dev; | ||
178 | unsigned long hz, ns; | ||
179 | unsigned int irq, i; | ||
180 | |||
181 | if (!mcore->dev) | ||
182 | return; /* We don't have a MIPS core */ | ||
183 | |||
184 | ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n"); | ||
185 | |||
186 | hz = ssb_clockspeed(bus); | ||
187 | if (!hz) | ||
188 | hz = 100000000; | ||
189 | ns = 1000000000 / hz; | ||
190 | |||
191 | if (bus->extif.dev) | ||
192 | ssb_extif_timing_init(&bus->extif, ns); | ||
193 | else if (bus->chipco.dev) | ||
194 | ssb_chipco_timing_init(&bus->chipco, ns); | ||
195 | |||
196 | /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ | ||
197 | for (irq = 2, i = 0; i < bus->nr_devices; i++) { | ||
198 | dev = &(bus->devices[i]); | ||
199 | dev->irq = ssb_mips_irq(dev) + 2; | ||
200 | switch (dev->id.coreid) { | ||
201 | case SSB_DEV_USB11_HOST: | ||
202 | /* shouldn't need a separate irq line for non-4710, most of them have a proper | ||
203 | * external usb controller on the pci */ | ||
204 | if ((bus->chip_id == 0x4710) && (irq <= 4)) { | ||
205 | set_irq(dev, irq++); | ||
206 | break; | ||
207 | } | ||
208 | /* fallthrough */ | ||
209 | case SSB_DEV_PCI: | ||
210 | case SSB_DEV_ETHERNET: | ||
211 | case SSB_DEV_80211: | ||
212 | case SSB_DEV_USB20_HOST: | ||
213 | /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ | ||
214 | if (irq <= 4) { | ||
215 | set_irq(dev, irq++); | ||
216 | break; | ||
217 | } | ||
218 | } | ||
219 | } | ||
220 | |||
221 | ssb_mips_serial_init(mcore); | ||
222 | ssb_mips_flash_detect(mcore); | ||
223 | } | ||
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c new file mode 100644 index 000000000000..2faaa906d5d6 --- /dev/null +++ b/drivers/ssb/driver_pcicore.c | |||
@@ -0,0 +1,576 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * Broadcom PCI-core driver | ||
4 | * | ||
5 | * Copyright 2005, Broadcom Corporation | ||
6 | * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> | ||
7 | * | ||
8 | * Licensed under the GNU/GPL. See COPYING for details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/ssb/ssb.h> | ||
12 | #include <linux/pci.h> | ||
13 | #include <linux/delay.h> | ||
14 | |||
15 | #include "ssb_private.h" | ||
16 | |||
17 | |||
18 | static inline | ||
19 | u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) | ||
20 | { | ||
21 | return ssb_read32(pc->dev, offset); | ||
22 | } | ||
23 | |||
24 | static inline | ||
25 | void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value) | ||
26 | { | ||
27 | ssb_write32(pc->dev, offset, value); | ||
28 | } | ||
29 | |||
30 | /************************************************** | ||
31 | * Code for hostmode operation. | ||
32 | **************************************************/ | ||
33 | |||
34 | #ifdef CONFIG_SSB_PCICORE_HOSTMODE | ||
35 | |||
36 | #include <asm/paccess.h> | ||
37 | /* Probe a 32bit value on the bus and catch bus exceptions. | ||
38 | * Returns nonzero on a bus exception. | ||
39 | * This is MIPS specific */ | ||
40 | #define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr))) | ||
41 | |||
42 | /* Assume one-hot slot wiring */ | ||
43 | #define SSB_PCI_SLOT_MAX 16 | ||
44 | |||
45 | /* Global lock is OK, as we won't have more than one extpci anyway. */ | ||
46 | static DEFINE_SPINLOCK(cfgspace_lock); | ||
47 | /* Core to access the external PCI config space. Can only have one. */ | ||
48 | static struct ssb_pcicore *extpci_core; | ||
49 | |||
50 | static u32 ssb_pcicore_pcibus_iobase = 0x100; | ||
51 | static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; | ||
52 | |||
53 | int pcibios_plat_dev_init(struct pci_dev *d) | ||
54 | { | ||
55 | struct resource *res; | ||
56 | int pos, size; | ||
57 | u32 *base; | ||
58 | |||
59 | ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", | ||
60 | pci_name(d)); | ||
61 | |||
62 | /* Fix up resource bases */ | ||
63 | for (pos = 0; pos < 6; pos++) { | ||
64 | res = &d->resource[pos]; | ||
65 | if (res->flags & IORESOURCE_IO) | ||
66 | base = &ssb_pcicore_pcibus_iobase; | ||
67 | else | ||
68 | base = &ssb_pcicore_pcibus_membase; | ||
69 | if (res->end) { | ||
70 | size = res->end - res->start + 1; | ||
71 | if (*base & (size - 1)) | ||
72 | *base = (*base + size) & ~(size - 1); | ||
73 | res->start = *base; | ||
74 | res->end = res->start + size - 1; | ||
75 | *base += size; | ||
76 | pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); | ||
77 | } | ||
78 | /* Fix up PCI bridge BAR0 only */ | ||
79 | if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) | ||
80 | break; | ||
81 | } | ||
82 | /* Fix up interrupt lines */ | ||
83 | d->irq = ssb_mips_irq(extpci_core->dev) + 2; | ||
84 | pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static void __init ssb_fixup_pcibridge(struct pci_dev *dev) | ||
90 | { | ||
91 | if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) | ||
92 | return; | ||
93 | |||
94 | ssb_printk(KERN_INFO "PCI: fixing up bridge\n"); | ||
95 | |||
96 | /* Enable PCI bridge bus mastering and memory space */ | ||
97 | pci_set_master(dev); | ||
98 | pcibios_enable_device(dev, ~0); | ||
99 | |||
100 | /* Enable PCI bridge BAR1 prefetch and burst */ | ||
101 | pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); | ||
102 | |||
103 | /* Make sure our latency is high enough to handle the devices behind us */ | ||
104 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); | ||
105 | } | ||
106 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); | ||
107 | |||
108 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
109 | { | ||
110 | return ssb_mips_irq(extpci_core->dev) + 2; | ||
111 | } | ||
112 | |||
113 | static u32 get_cfgspace_addr(struct ssb_pcicore *pc, | ||
114 | unsigned int bus, unsigned int dev, | ||
115 | unsigned int func, unsigned int off) | ||
116 | { | ||
117 | u32 addr = 0; | ||
118 | u32 tmp; | ||
119 | |||
120 | if (unlikely(pc->cardbusmode && dev > 1)) | ||
121 | goto out; | ||
122 | if (bus == 0) { | ||
123 | /* Type 0 transaction */ | ||
124 | if (unlikely(dev >= SSB_PCI_SLOT_MAX)) | ||
125 | goto out; | ||
126 | /* Slide the window */ | ||
127 | tmp = SSB_PCICORE_SBTOPCI_CFG0; | ||
128 | tmp |= ((1 << (dev + 16)) & SSB_PCICORE_SBTOPCI1_MASK); | ||
129 | pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, tmp); | ||
130 | /* Calculate the address */ | ||
131 | addr = SSB_PCI_CFG; | ||
132 | addr |= ((1 << (dev + 16)) & ~SSB_PCICORE_SBTOPCI1_MASK); | ||
133 | addr |= (func << 8); | ||
134 | addr |= (off & ~3); | ||
135 | } else { | ||
136 | /* Type 1 transaction */ | ||
137 | pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, | ||
138 | SSB_PCICORE_SBTOPCI_CFG1); | ||
139 | /* Calculate the address */ | ||
140 | addr = SSB_PCI_CFG; | ||
141 | addr |= (bus << 16); | ||
142 | addr |= (dev << 11); | ||
143 | addr |= (func << 8); | ||
144 | addr |= (off & ~3); | ||
145 | } | ||
146 | out: | ||
147 | return addr; | ||
148 | } | ||
149 | |||
150 | static int ssb_extpci_read_config(struct ssb_pcicore *pc, | ||
151 | unsigned int bus, unsigned int dev, | ||
152 | unsigned int func, unsigned int off, | ||
153 | void *buf, int len) | ||
154 | { | ||
155 | int err = -EINVAL; | ||
156 | u32 addr, val; | ||
157 | void __iomem *mmio; | ||
158 | |||
159 | SSB_WARN_ON(!pc->hostmode); | ||
160 | if (unlikely(len != 1 && len != 2 && len != 4)) | ||
161 | goto out; | ||
162 | addr = get_cfgspace_addr(pc, bus, dev, func, off); | ||
163 | if (unlikely(!addr)) | ||
164 | goto out; | ||
165 | err = -ENOMEM; | ||
166 | mmio = ioremap_nocache(addr, len); | ||
167 | if (!mmio) | ||
168 | goto out; | ||
169 | |||
170 | if (mips_busprobe32(val, mmio)) { | ||
171 | val = 0xffffffff; | ||
172 | goto unmap; | ||
173 | } | ||
174 | |||
175 | val = readl(mmio); | ||
176 | val >>= (8 * (off & 3)); | ||
177 | |||
178 | switch (len) { | ||
179 | case 1: | ||
180 | *((u8 *)buf) = (u8)val; | ||
181 | break; | ||
182 | case 2: | ||
183 | *((u16 *)buf) = (u16)val; | ||
184 | break; | ||
185 | case 4: | ||
186 | *((u32 *)buf) = (u32)val; | ||
187 | break; | ||
188 | } | ||
189 | err = 0; | ||
190 | unmap: | ||
191 | iounmap(mmio); | ||
192 | out: | ||
193 | return err; | ||
194 | } | ||
195 | |||
196 | static int ssb_extpci_write_config(struct ssb_pcicore *pc, | ||
197 | unsigned int bus, unsigned int dev, | ||
198 | unsigned int func, unsigned int off, | ||
199 | const void *buf, int len) | ||
200 | { | ||
201 | int err = -EINVAL; | ||
202 | u32 addr, val = 0; | ||
203 | void __iomem *mmio; | ||
204 | |||
205 | SSB_WARN_ON(!pc->hostmode); | ||
206 | if (unlikely(len != 1 && len != 2 && len != 4)) | ||
207 | goto out; | ||
208 | addr = get_cfgspace_addr(pc, bus, dev, func, off); | ||
209 | if (unlikely(!addr)) | ||
210 | goto out; | ||
211 | err = -ENOMEM; | ||
212 | mmio = ioremap_nocache(addr, len); | ||
213 | if (!mmio) | ||
214 | goto out; | ||
215 | |||
216 | if (mips_busprobe32(val, mmio)) { | ||
217 | val = 0xffffffff; | ||
218 | goto unmap; | ||
219 | } | ||
220 | |||
221 | switch (len) { | ||
222 | case 1: | ||
223 | val = readl(mmio); | ||
224 | val &= ~(0xFF << (8 * (off & 3))); | ||
225 | val |= *((const u8 *)buf) << (8 * (off & 3)); | ||
226 | break; | ||
227 | case 2: | ||
228 | val = readl(mmio); | ||
229 | val &= ~(0xFFFF << (8 * (off & 3))); | ||
230 | val |= *((const u16 *)buf) << (8 * (off & 3)); | ||
231 | break; | ||
232 | case 4: | ||
233 | val = *((const u32 *)buf); | ||
234 | break; | ||
235 | } | ||
236 | writel(val, mmio); | ||
237 | |||
238 | err = 0; | ||
239 | unmap: | ||
240 | iounmap(mmio); | ||
241 | out: | ||
242 | return err; | ||
243 | } | ||
244 | |||
245 | static int ssb_pcicore_read_config(struct pci_bus *bus, unsigned int devfn, | ||
246 | int reg, int size, u32 *val) | ||
247 | { | ||
248 | unsigned long flags; | ||
249 | int err; | ||
250 | |||
251 | spin_lock_irqsave(&cfgspace_lock, flags); | ||
252 | err = ssb_extpci_read_config(extpci_core, bus->number, PCI_SLOT(devfn), | ||
253 | PCI_FUNC(devfn), reg, val, size); | ||
254 | spin_unlock_irqrestore(&cfgspace_lock, flags); | ||
255 | |||
256 | return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; | ||
257 | } | ||
258 | |||
259 | static int ssb_pcicore_write_config(struct pci_bus *bus, unsigned int devfn, | ||
260 | int reg, int size, u32 val) | ||
261 | { | ||
262 | unsigned long flags; | ||
263 | int err; | ||
264 | |||
265 | spin_lock_irqsave(&cfgspace_lock, flags); | ||
266 | err = ssb_extpci_write_config(extpci_core, bus->number, PCI_SLOT(devfn), | ||
267 | PCI_FUNC(devfn), reg, &val, size); | ||
268 | spin_unlock_irqrestore(&cfgspace_lock, flags); | ||
269 | |||
270 | return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; | ||
271 | } | ||
272 | |||
273 | static struct pci_ops ssb_pcicore_pciops = { | ||
274 | .read = ssb_pcicore_read_config, | ||
275 | .write = ssb_pcicore_write_config, | ||
276 | }; | ||
277 | |||
278 | static struct resource ssb_pcicore_mem_resource = { | ||
279 | .name = "SSB PCIcore external memory", | ||
280 | .start = SSB_PCI_DMA, | ||
281 | .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1, | ||
282 | .flags = IORESOURCE_MEM, | ||
283 | }; | ||
284 | |||
285 | static struct resource ssb_pcicore_io_resource = { | ||
286 | .name = "SSB PCIcore external I/O", | ||
287 | .start = 0x100, | ||
288 | .end = 0x7FF, | ||
289 | .flags = IORESOURCE_IO, | ||
290 | }; | ||
291 | |||
292 | static struct pci_controller ssb_pcicore_controller = { | ||
293 | .pci_ops = &ssb_pcicore_pciops, | ||
294 | .io_resource = &ssb_pcicore_io_resource, | ||
295 | .mem_resource = &ssb_pcicore_mem_resource, | ||
296 | .mem_offset = 0x24000000, | ||
297 | }; | ||
298 | |||
299 | static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) | ||
300 | { | ||
301 | u32 val; | ||
302 | |||
303 | if (WARN_ON(extpci_core)) | ||
304 | return; | ||
305 | extpci_core = pc; | ||
306 | |||
307 | ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n"); | ||
308 | /* Reset devices on the external PCI bus */ | ||
309 | val = SSB_PCICORE_CTL_RST_OE; | ||
310 | val |= SSB_PCICORE_CTL_CLK_OE; | ||
311 | pcicore_write32(pc, SSB_PCICORE_CTL, val); | ||
312 | val |= SSB_PCICORE_CTL_CLK; /* Clock on */ | ||
313 | pcicore_write32(pc, SSB_PCICORE_CTL, val); | ||
314 | udelay(150); /* Assertion time demanded by the PCI standard */ | ||
315 | val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */ | ||
316 | pcicore_write32(pc, SSB_PCICORE_CTL, val); | ||
317 | val = SSB_PCICORE_ARBCTL_INTERN; | ||
318 | pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); | ||
319 | udelay(1); /* Assertion time demanded by the PCI standard */ | ||
320 | |||
321 | /*TODO cardbus mode */ | ||
322 | |||
323 | /* 64MB I/O window */ | ||
324 | pcicore_write32(pc, SSB_PCICORE_SBTOPCI0, | ||
325 | SSB_PCICORE_SBTOPCI_IO); | ||
326 | /* 64MB config space */ | ||
327 | pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, | ||
328 | SSB_PCICORE_SBTOPCI_CFG0); | ||
329 | /* 1GB memory window */ | ||
330 | pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, | ||
331 | SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA); | ||
332 | |||
333 | /* Enable PCI bridge BAR0 prefetch and burst */ | ||
334 | val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; | ||
335 | ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2); | ||
336 | /* Clear error conditions */ | ||
337 | val = 0; | ||
338 | ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2); | ||
339 | |||
340 | /* Enable PCI interrupts */ | ||
341 | pcicore_write32(pc, SSB_PCICORE_IMASK, | ||
342 | SSB_PCICORE_IMASK_INTA); | ||
343 | |||
344 | /* Ok, ready to run, register it to the system. | ||
345 | * The following needs change, if we want to port hostmode | ||
346 | * to non-MIPS platform. */ | ||
347 | set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000)); | ||
348 | /* Give some time to the PCI controller to configure itself with the new | ||
349 | * values. Not waiting at this point causes crashes of the machine. */ | ||
350 | mdelay(10); | ||
351 | register_pci_controller(&ssb_pcicore_controller); | ||
352 | } | ||
353 | |||
354 | static int pcicore_is_in_hostmode(struct ssb_pcicore *pc) | ||
355 | { | ||
356 | struct ssb_bus *bus = pc->dev->bus; | ||
357 | u16 chipid_top; | ||
358 | u32 tmp; | ||
359 | |||
360 | chipid_top = (bus->chip_id & 0xFF00); | ||
361 | if (chipid_top != 0x4700 && | ||
362 | chipid_top != 0x5300) | ||
363 | return 0; | ||
364 | |||
365 | if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI) | ||
366 | return 0; | ||
367 | |||
368 | /* The 200-pin BCM4712 package does not bond out PCI. Even when | ||
369 | * PCI is bonded out, some boards may leave the pins floating. */ | ||
370 | if (bus->chip_id == 0x4712) { | ||
371 | if (bus->chip_package == SSB_CHIPPACK_BCM4712S) | ||
372 | return 0; | ||
373 | if (bus->chip_package == SSB_CHIPPACK_BCM4712M) | ||
374 | return 0; | ||
375 | } | ||
376 | if (bus->chip_id == 0x5350) | ||
377 | return 0; | ||
378 | |||
379 | return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE))); | ||
380 | } | ||
381 | #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ | ||
382 | |||
383 | |||
384 | /************************************************** | ||
385 | * Generic and Clientmode operation code. | ||
386 | **************************************************/ | ||
387 | |||
388 | static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) | ||
389 | { | ||
390 | /* Disable PCI interrupts. */ | ||
391 | ssb_write32(pc->dev, SSB_INTVEC, 0); | ||
392 | } | ||
393 | |||
394 | void ssb_pcicore_init(struct ssb_pcicore *pc) | ||
395 | { | ||
396 | struct ssb_device *dev = pc->dev; | ||
397 | struct ssb_bus *bus; | ||
398 | |||
399 | if (!dev) | ||
400 | return; | ||
401 | bus = dev->bus; | ||
402 | if (!ssb_device_is_enabled(dev)) | ||
403 | ssb_device_enable(dev, 0); | ||
404 | |||
405 | #ifdef CONFIG_SSB_PCICORE_HOSTMODE | ||
406 | pc->hostmode = pcicore_is_in_hostmode(pc); | ||
407 | if (pc->hostmode) | ||
408 | ssb_pcicore_init_hostmode(pc); | ||
409 | #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ | ||
410 | if (!pc->hostmode) | ||
411 | ssb_pcicore_init_clientmode(pc); | ||
412 | } | ||
413 | |||
414 | static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) | ||
415 | { | ||
416 | pcicore_write32(pc, 0x130, address); | ||
417 | return pcicore_read32(pc, 0x134); | ||
418 | } | ||
419 | |||
420 | static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data) | ||
421 | { | ||
422 | pcicore_write32(pc, 0x130, address); | ||
423 | pcicore_write32(pc, 0x134, data); | ||
424 | } | ||
425 | |||
426 | static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, | ||
427 | u8 address, u16 data) | ||
428 | { | ||
429 | const u16 mdio_control = 0x128; | ||
430 | const u16 mdio_data = 0x12C; | ||
431 | u32 v; | ||
432 | int i; | ||
433 | |||
434 | v = 0x80; /* Enable Preamble Sequence */ | ||
435 | v |= 0x2; /* MDIO Clock Divisor */ | ||
436 | pcicore_write32(pc, mdio_control, v); | ||
437 | |||
438 | v = (1 << 30); /* Start of Transaction */ | ||
439 | v |= (1 << 28); /* Write Transaction */ | ||
440 | v |= (1 << 17); /* Turnaround */ | ||
441 | v |= (u32)device << 22; | ||
442 | v |= (u32)address << 18; | ||
443 | v |= data; | ||
444 | pcicore_write32(pc, mdio_data, v); | ||
445 | /* Wait for the device to complete the transaction */ | ||
446 | udelay(10); | ||
447 | for (i = 0; i < 10; i++) { | ||
448 | v = pcicore_read32(pc, mdio_control); | ||
449 | if (v & 0x100 /* Trans complete */) | ||
450 | break; | ||
451 | msleep(1); | ||
452 | } | ||
453 | pcicore_write32(pc, mdio_control, 0); | ||
454 | } | ||
455 | |||
456 | static void ssb_broadcast_value(struct ssb_device *dev, | ||
457 | u32 address, u32 data) | ||
458 | { | ||
459 | /* This is used for both, PCI and ChipCommon core, so be careful. */ | ||
460 | BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR); | ||
461 | BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA); | ||
462 | |||
463 | ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address); | ||
464 | ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */ | ||
465 | ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data); | ||
466 | ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */ | ||
467 | } | ||
468 | |||
469 | static void ssb_commit_settings(struct ssb_bus *bus) | ||
470 | { | ||
471 | struct ssb_device *dev; | ||
472 | |||
473 | dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; | ||
474 | if (WARN_ON(!dev)) | ||
475 | return; | ||
476 | /* This forces an update of the cached registers. */ | ||
477 | ssb_broadcast_value(dev, 0xFD8, 0); | ||
478 | } | ||
479 | |||
480 | int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, | ||
481 | struct ssb_device *dev) | ||
482 | { | ||
483 | struct ssb_device *pdev = pc->dev; | ||
484 | struct ssb_bus *bus; | ||
485 | int err = 0; | ||
486 | u32 tmp; | ||
487 | |||
488 | might_sleep(); | ||
489 | |||
490 | if (!pdev) | ||
491 | goto out; | ||
492 | bus = pdev->bus; | ||
493 | |||
494 | /* Enable interrupts for this device. */ | ||
495 | if (bus->host_pci && | ||
496 | ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) { | ||
497 | u32 coremask; | ||
498 | |||
499 | /* Calculate the "coremask" for the device. */ | ||
500 | coremask = (1 << dev->core_index); | ||
501 | |||
502 | err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp); | ||
503 | if (err) | ||
504 | goto out; | ||
505 | tmp |= coremask << 8; | ||
506 | err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp); | ||
507 | if (err) | ||
508 | goto out; | ||
509 | } else { | ||
510 | u32 intvec; | ||
511 | |||
512 | intvec = ssb_read32(pdev, SSB_INTVEC); | ||
513 | if ((bus->chip_id & 0xFF00) == 0x4400) { | ||
514 | /* Workaround: On the BCM44XX the BPFLAG routing | ||
515 | * bit is wrong. Use a hardcoded constant. */ | ||
516 | intvec |= 0x00000002; | ||
517 | } else { | ||
518 | tmp = ssb_read32(dev, SSB_TPSFLAG); | ||
519 | tmp &= SSB_TPSFLAG_BPFLAG; | ||
520 | intvec |= tmp; | ||
521 | } | ||
522 | ssb_write32(pdev, SSB_INTVEC, intvec); | ||
523 | } | ||
524 | |||
525 | /* Setup PCIcore operation. */ | ||
526 | if (pc->setup_done) | ||
527 | goto out; | ||
528 | if (pdev->id.coreid == SSB_DEV_PCI) { | ||
529 | tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); | ||
530 | tmp |= SSB_PCICORE_SBTOPCI_PREF; | ||
531 | tmp |= SSB_PCICORE_SBTOPCI_BURST; | ||
532 | pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); | ||
533 | |||
534 | if (pdev->id.revision < 5) { | ||
535 | tmp = ssb_read32(pdev, SSB_IMCFGLO); | ||
536 | tmp &= ~SSB_IMCFGLO_SERTO; | ||
537 | tmp |= 2; | ||
538 | tmp &= ~SSB_IMCFGLO_REQTO; | ||
539 | tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; | ||
540 | ssb_write32(pdev, SSB_IMCFGLO, tmp); | ||
541 | ssb_commit_settings(bus); | ||
542 | } else if (pdev->id.revision >= 11) { | ||
543 | tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); | ||
544 | tmp |= SSB_PCICORE_SBTOPCI_MRM; | ||
545 | pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); | ||
546 | } | ||
547 | } else { | ||
548 | WARN_ON(pdev->id.coreid != SSB_DEV_PCIE); | ||
549 | //TODO: Better make defines for all these magic PCIE values. | ||
550 | if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { | ||
551 | /* TLP Workaround register. */ | ||
552 | tmp = ssb_pcie_read(pc, 0x4); | ||
553 | tmp |= 0x8; | ||
554 | ssb_pcie_write(pc, 0x4, tmp); | ||
555 | } | ||
556 | if (pdev->id.revision == 0) { | ||
557 | const u8 serdes_rx_device = 0x1F; | ||
558 | |||
559 | ssb_pcie_mdio_write(pc, serdes_rx_device, | ||
560 | 2 /* Timer */, 0x8128); | ||
561 | ssb_pcie_mdio_write(pc, serdes_rx_device, | ||
562 | 6 /* CDR */, 0x0100); | ||
563 | ssb_pcie_mdio_write(pc, serdes_rx_device, | ||
564 | 7 /* CDR BW */, 0x1466); | ||
565 | } else if (pdev->id.revision == 1) { | ||
566 | /* DLLP Link Control register. */ | ||
567 | tmp = ssb_pcie_read(pc, 0x100); | ||
568 | tmp |= 0x40; | ||
569 | ssb_pcie_write(pc, 0x100, tmp); | ||
570 | } | ||
571 | } | ||
572 | pc->setup_done = 1; | ||
573 | out: | ||
574 | return err; | ||
575 | } | ||
576 | EXPORT_SYMBOL(ssb_pcicore_dev_irqvecs_enable); | ||
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c new file mode 100644 index 000000000000..74d5182db4b2 --- /dev/null +++ b/drivers/ssb/main.c | |||
@@ -0,0 +1,1162 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * Subsystem core | ||
4 | * | ||
5 | * Copyright 2005, Broadcom Corporation | ||
6 | * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> | ||
7 | * | ||
8 | * Licensed under the GNU/GPL. See COPYING for details. | ||
9 | */ | ||
10 | |||
11 | #include "ssb_private.h" | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/ssb/ssb.h> | ||
15 | #include <linux/ssb/ssb_regs.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include <linux/pci.h> | ||
18 | |||
19 | #include <pcmcia/cs_types.h> | ||
20 | #include <pcmcia/cs.h> | ||
21 | #include <pcmcia/cistpl.h> | ||
22 | #include <pcmcia/ds.h> | ||
23 | |||
24 | |||
25 | MODULE_DESCRIPTION("Sonics Silicon Backplane driver"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | |||
29 | /* Temporary list of yet-to-be-attached buses */ | ||
30 | static LIST_HEAD(attach_queue); | ||
31 | /* List if running buses */ | ||
32 | static LIST_HEAD(buses); | ||
33 | /* Software ID counter */ | ||
34 | static unsigned int next_busnumber; | ||
35 | /* buses_mutes locks the two buslists and the next_busnumber. | ||
36 | * Don't lock this directly, but use ssb_buses_[un]lock() below. */ | ||
37 | static DEFINE_MUTEX(buses_mutex); | ||
38 | |||
39 | /* There are differences in the codeflow, if the bus is | ||
40 | * initialized from early boot, as various needed services | ||
41 | * are not available early. This is a mechanism to delay | ||
42 | * these initializations to after early boot has finished. | ||
43 | * It's also used to avoid mutex locking, as that's not | ||
44 | * available and needed early. */ | ||
45 | static bool ssb_is_early_boot = 1; | ||
46 | |||
47 | static void ssb_buses_lock(void); | ||
48 | static void ssb_buses_unlock(void); | ||
49 | |||
50 | |||
51 | #ifdef CONFIG_SSB_PCIHOST | ||
52 | struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev) | ||
53 | { | ||
54 | struct ssb_bus *bus; | ||
55 | |||
56 | ssb_buses_lock(); | ||
57 | list_for_each_entry(bus, &buses, list) { | ||
58 | if (bus->bustype == SSB_BUSTYPE_PCI && | ||
59 | bus->host_pci == pdev) | ||
60 | goto found; | ||
61 | } | ||
62 | bus = NULL; | ||
63 | found: | ||
64 | ssb_buses_unlock(); | ||
65 | |||
66 | return bus; | ||
67 | } | ||
68 | #endif /* CONFIG_SSB_PCIHOST */ | ||
69 | |||
70 | static struct ssb_device *ssb_device_get(struct ssb_device *dev) | ||
71 | { | ||
72 | if (dev) | ||
73 | get_device(dev->dev); | ||
74 | return dev; | ||
75 | } | ||
76 | |||
77 | static void ssb_device_put(struct ssb_device *dev) | ||
78 | { | ||
79 | if (dev) | ||
80 | put_device(dev->dev); | ||
81 | } | ||
82 | |||
83 | static int ssb_bus_resume(struct ssb_bus *bus) | ||
84 | { | ||
85 | int err; | ||
86 | |||
87 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); | ||
88 | err = ssb_pcmcia_init(bus); | ||
89 | if (err) { | ||
90 | /* No need to disable XTAL, as we don't have one on PCMCIA. */ | ||
91 | return err; | ||
92 | } | ||
93 | ssb_chipco_resume(&bus->chipco); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int ssb_device_resume(struct device *dev) | ||
99 | { | ||
100 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | ||
101 | struct ssb_driver *ssb_drv; | ||
102 | struct ssb_bus *bus; | ||
103 | int err = 0; | ||
104 | |||
105 | bus = ssb_dev->bus; | ||
106 | if (bus->suspend_cnt == bus->nr_devices) { | ||
107 | err = ssb_bus_resume(bus); | ||
108 | if (err) | ||
109 | return err; | ||
110 | } | ||
111 | bus->suspend_cnt--; | ||
112 | if (dev->driver) { | ||
113 | ssb_drv = drv_to_ssb_drv(dev->driver); | ||
114 | if (ssb_drv && ssb_drv->resume) | ||
115 | err = ssb_drv->resume(ssb_dev); | ||
116 | if (err) | ||
117 | goto out; | ||
118 | } | ||
119 | out: | ||
120 | return err; | ||
121 | } | ||
122 | |||
123 | static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) | ||
124 | { | ||
125 | ssb_chipco_suspend(&bus->chipco, state); | ||
126 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | ||
127 | |||
128 | /* Reset HW state information in memory, so that HW is | ||
129 | * completely reinitialized on resume. */ | ||
130 | bus->mapped_device = NULL; | ||
131 | #ifdef CONFIG_SSB_DRIVER_PCICORE | ||
132 | bus->pcicore.setup_done = 0; | ||
133 | #endif | ||
134 | #ifdef CONFIG_SSB_DEBUG | ||
135 | bus->powered_up = 0; | ||
136 | #endif | ||
137 | } | ||
138 | |||
139 | static int ssb_device_suspend(struct device *dev, pm_message_t state) | ||
140 | { | ||
141 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | ||
142 | struct ssb_driver *ssb_drv; | ||
143 | struct ssb_bus *bus; | ||
144 | int err = 0; | ||
145 | |||
146 | if (dev->driver) { | ||
147 | ssb_drv = drv_to_ssb_drv(dev->driver); | ||
148 | if (ssb_drv && ssb_drv->suspend) | ||
149 | err = ssb_drv->suspend(ssb_dev, state); | ||
150 | if (err) | ||
151 | goto out; | ||
152 | } | ||
153 | |||
154 | bus = ssb_dev->bus; | ||
155 | bus->suspend_cnt++; | ||
156 | if (bus->suspend_cnt == bus->nr_devices) { | ||
157 | /* All devices suspended. Shutdown the bus. */ | ||
158 | ssb_bus_suspend(bus, state); | ||
159 | } | ||
160 | |||
161 | out: | ||
162 | return err; | ||
163 | } | ||
164 | |||
165 | #ifdef CONFIG_SSB_PCIHOST | ||
166 | int ssb_devices_freeze(struct ssb_bus *bus) | ||
167 | { | ||
168 | struct ssb_device *dev; | ||
169 | struct ssb_driver *drv; | ||
170 | int err = 0; | ||
171 | int i; | ||
172 | pm_message_t state = PMSG_FREEZE; | ||
173 | |||
174 | /* First check that we are capable to freeze all devices. */ | ||
175 | for (i = 0; i < bus->nr_devices; i++) { | ||
176 | dev = &(bus->devices[i]); | ||
177 | if (!dev->dev || | ||
178 | !dev->dev->driver || | ||
179 | !device_is_registered(dev->dev)) | ||
180 | continue; | ||
181 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
182 | if (!drv) | ||
183 | continue; | ||
184 | if (!drv->suspend) { | ||
185 | /* Nope, can't suspend this one. */ | ||
186 | return -EOPNOTSUPP; | ||
187 | } | ||
188 | } | ||
189 | /* Now suspend all devices */ | ||
190 | for (i = 0; i < bus->nr_devices; i++) { | ||
191 | dev = &(bus->devices[i]); | ||
192 | if (!dev->dev || | ||
193 | !dev->dev->driver || | ||
194 | !device_is_registered(dev->dev)) | ||
195 | continue; | ||
196 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
197 | if (!drv) | ||
198 | continue; | ||
199 | err = drv->suspend(dev, state); | ||
200 | if (err) { | ||
201 | ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n", | ||
202 | dev->dev->bus_id); | ||
203 | goto err_unwind; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | err_unwind: | ||
209 | for (i--; i >= 0; i--) { | ||
210 | dev = &(bus->devices[i]); | ||
211 | if (!dev->dev || | ||
212 | !dev->dev->driver || | ||
213 | !device_is_registered(dev->dev)) | ||
214 | continue; | ||
215 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
216 | if (!drv) | ||
217 | continue; | ||
218 | if (drv->resume) | ||
219 | drv->resume(dev); | ||
220 | } | ||
221 | return err; | ||
222 | } | ||
223 | |||
224 | int ssb_devices_thaw(struct ssb_bus *bus) | ||
225 | { | ||
226 | struct ssb_device *dev; | ||
227 | struct ssb_driver *drv; | ||
228 | int err; | ||
229 | int i; | ||
230 | |||
231 | for (i = 0; i < bus->nr_devices; i++) { | ||
232 | dev = &(bus->devices[i]); | ||
233 | if (!dev->dev || | ||
234 | !dev->dev->driver || | ||
235 | !device_is_registered(dev->dev)) | ||
236 | continue; | ||
237 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
238 | if (!drv) | ||
239 | continue; | ||
240 | if (SSB_WARN_ON(!drv->resume)) | ||
241 | continue; | ||
242 | err = drv->resume(dev); | ||
243 | if (err) { | ||
244 | ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", | ||
245 | dev->dev->bus_id); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | #endif /* CONFIG_SSB_PCIHOST */ | ||
252 | |||
253 | static void ssb_device_shutdown(struct device *dev) | ||
254 | { | ||
255 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | ||
256 | struct ssb_driver *ssb_drv; | ||
257 | |||
258 | if (!dev->driver) | ||
259 | return; | ||
260 | ssb_drv = drv_to_ssb_drv(dev->driver); | ||
261 | if (ssb_drv && ssb_drv->shutdown) | ||
262 | ssb_drv->shutdown(ssb_dev); | ||
263 | } | ||
264 | |||
265 | static int ssb_device_remove(struct device *dev) | ||
266 | { | ||
267 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | ||
268 | struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver); | ||
269 | |||
270 | if (ssb_drv && ssb_drv->remove) | ||
271 | ssb_drv->remove(ssb_dev); | ||
272 | ssb_device_put(ssb_dev); | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int ssb_device_probe(struct device *dev) | ||
278 | { | ||
279 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | ||
280 | struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver); | ||
281 | int err = 0; | ||
282 | |||
283 | ssb_device_get(ssb_dev); | ||
284 | if (ssb_drv && ssb_drv->probe) | ||
285 | err = ssb_drv->probe(ssb_dev, &ssb_dev->id); | ||
286 | if (err) | ||
287 | ssb_device_put(ssb_dev); | ||
288 | |||
289 | return err; | ||
290 | } | ||
291 | |||
292 | static int ssb_match_devid(const struct ssb_device_id *tabid, | ||
293 | const struct ssb_device_id *devid) | ||
294 | { | ||
295 | if ((tabid->vendor != devid->vendor) && | ||
296 | tabid->vendor != SSB_ANY_VENDOR) | ||
297 | return 0; | ||
298 | if ((tabid->coreid != devid->coreid) && | ||
299 | tabid->coreid != SSB_ANY_ID) | ||
300 | return 0; | ||
301 | if ((tabid->revision != devid->revision) && | ||
302 | tabid->revision != SSB_ANY_REV) | ||
303 | return 0; | ||
304 | return 1; | ||
305 | } | ||
306 | |||
307 | static int ssb_bus_match(struct device *dev, struct device_driver *drv) | ||
308 | { | ||
309 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | ||
310 | struct ssb_driver *ssb_drv = drv_to_ssb_drv(drv); | ||
311 | const struct ssb_device_id *id; | ||
312 | |||
313 | for (id = ssb_drv->id_table; | ||
314 | id->vendor || id->coreid || id->revision; | ||
315 | id++) { | ||
316 | if (ssb_match_devid(id, &ssb_dev->id)) | ||
317 | return 1; /* found */ | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int ssb_device_uevent(struct device *dev, char **envp, int num_envp, | ||
324 | char *buffer, int buffer_size) | ||
325 | { | ||
326 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | ||
327 | int ret, i = 0, length = 0; | ||
328 | |||
329 | if (!dev) | ||
330 | return -ENODEV; | ||
331 | |||
332 | ret = add_uevent_var(envp, num_envp, &i, | ||
333 | buffer, buffer_size, &length, | ||
334 | "MODALIAS=ssb:v%04Xid%04Xrev%02X", | ||
335 | ssb_dev->id.vendor, ssb_dev->id.coreid, | ||
336 | ssb_dev->id.revision); | ||
337 | envp[i] = NULL; | ||
338 | |||
339 | return ret; | ||
340 | } | ||
341 | |||
342 | static struct bus_type ssb_bustype = { | ||
343 | .name = "ssb", | ||
344 | .match = ssb_bus_match, | ||
345 | .probe = ssb_device_probe, | ||
346 | .remove = ssb_device_remove, | ||
347 | .shutdown = ssb_device_shutdown, | ||
348 | .suspend = ssb_device_suspend, | ||
349 | .resume = ssb_device_resume, | ||
350 | .uevent = ssb_device_uevent, | ||
351 | }; | ||
352 | |||
353 | static void ssb_buses_lock(void) | ||
354 | { | ||
355 | /* See the comment at the ssb_is_early_boot definition */ | ||
356 | if (!ssb_is_early_boot) | ||
357 | mutex_lock(&buses_mutex); | ||
358 | } | ||
359 | |||
360 | static void ssb_buses_unlock(void) | ||
361 | { | ||
362 | /* See the comment at the ssb_is_early_boot definition */ | ||
363 | if (!ssb_is_early_boot) | ||
364 | mutex_unlock(&buses_mutex); | ||
365 | } | ||
366 | |||
367 | static void ssb_devices_unregister(struct ssb_bus *bus) | ||
368 | { | ||
369 | struct ssb_device *sdev; | ||
370 | int i; | ||
371 | |||
372 | for (i = bus->nr_devices - 1; i >= 0; i--) { | ||
373 | sdev = &(bus->devices[i]); | ||
374 | if (sdev->dev) | ||
375 | device_unregister(sdev->dev); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | void ssb_bus_unregister(struct ssb_bus *bus) | ||
380 | { | ||
381 | ssb_buses_lock(); | ||
382 | ssb_devices_unregister(bus); | ||
383 | list_del(&bus->list); | ||
384 | ssb_buses_unlock(); | ||
385 | |||
386 | /* ssb_pcmcia_exit(bus); */ | ||
387 | ssb_pci_exit(bus); | ||
388 | ssb_iounmap(bus); | ||
389 | } | ||
390 | EXPORT_SYMBOL(ssb_bus_unregister); | ||
391 | |||
392 | static void ssb_release_dev(struct device *dev) | ||
393 | { | ||
394 | struct __ssb_dev_wrapper *devwrap; | ||
395 | |||
396 | devwrap = container_of(dev, struct __ssb_dev_wrapper, dev); | ||
397 | kfree(devwrap); | ||
398 | } | ||
399 | |||
400 | static int ssb_devices_register(struct ssb_bus *bus) | ||
401 | { | ||
402 | struct ssb_device *sdev; | ||
403 | struct device *dev; | ||
404 | struct __ssb_dev_wrapper *devwrap; | ||
405 | int i, err = 0; | ||
406 | int dev_idx = 0; | ||
407 | |||
408 | for (i = 0; i < bus->nr_devices; i++) { | ||
409 | sdev = &(bus->devices[i]); | ||
410 | |||
411 | /* We don't register SSB-system devices to the kernel, | ||
412 | * as the drivers for them are built into SSB. */ | ||
413 | switch (sdev->id.coreid) { | ||
414 | case SSB_DEV_CHIPCOMMON: | ||
415 | case SSB_DEV_PCI: | ||
416 | case SSB_DEV_PCIE: | ||
417 | case SSB_DEV_PCMCIA: | ||
418 | case SSB_DEV_MIPS: | ||
419 | case SSB_DEV_MIPS_3302: | ||
420 | case SSB_DEV_EXTIF: | ||
421 | continue; | ||
422 | } | ||
423 | |||
424 | devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL); | ||
425 | if (!devwrap) { | ||
426 | ssb_printk(KERN_ERR PFX | ||
427 | "Could not allocate device\n"); | ||
428 | err = -ENOMEM; | ||
429 | goto error; | ||
430 | } | ||
431 | dev = &devwrap->dev; | ||
432 | devwrap->sdev = sdev; | ||
433 | |||
434 | dev->release = ssb_release_dev; | ||
435 | dev->bus = &ssb_bustype; | ||
436 | snprintf(dev->bus_id, sizeof(dev->bus_id), | ||
437 | "ssb%u:%d", bus->busnumber, dev_idx); | ||
438 | |||
439 | switch (bus->bustype) { | ||
440 | case SSB_BUSTYPE_PCI: | ||
441 | #ifdef CONFIG_SSB_PCIHOST | ||
442 | sdev->irq = bus->host_pci->irq; | ||
443 | dev->parent = &bus->host_pci->dev; | ||
444 | #endif | ||
445 | break; | ||
446 | case SSB_BUSTYPE_PCMCIA: | ||
447 | #ifdef CONFIG_SSB_PCMCIAHOST | ||
448 | dev->parent = &bus->host_pcmcia->dev; | ||
449 | #endif | ||
450 | break; | ||
451 | case SSB_BUSTYPE_SSB: | ||
452 | break; | ||
453 | } | ||
454 | |||
455 | sdev->dev = dev; | ||
456 | err = device_register(dev); | ||
457 | if (err) { | ||
458 | ssb_printk(KERN_ERR PFX | ||
459 | "Could not register %s\n", | ||
460 | dev->bus_id); | ||
461 | /* Set dev to NULL to not unregister | ||
462 | * dev on error unwinding. */ | ||
463 | sdev->dev = NULL; | ||
464 | kfree(devwrap); | ||
465 | goto error; | ||
466 | } | ||
467 | dev_idx++; | ||
468 | } | ||
469 | |||
470 | return 0; | ||
471 | error: | ||
472 | /* Unwind the already registered devices. */ | ||
473 | ssb_devices_unregister(bus); | ||
474 | return err; | ||
475 | } | ||
476 | |||
477 | /* Needs ssb_buses_lock() */ | ||
478 | static int ssb_attach_queued_buses(void) | ||
479 | { | ||
480 | struct ssb_bus *bus, *n; | ||
481 | int err = 0; | ||
482 | int drop_them_all = 0; | ||
483 | |||
484 | list_for_each_entry_safe(bus, n, &attach_queue, list) { | ||
485 | if (drop_them_all) { | ||
486 | list_del(&bus->list); | ||
487 | continue; | ||
488 | } | ||
489 | /* Can't init the PCIcore in ssb_bus_register(), as that | ||
490 | * is too early in boot for embedded systems | ||
491 | * (no udelay() available). So do it here in attach stage. | ||
492 | */ | ||
493 | err = ssb_bus_powerup(bus, 0); | ||
494 | if (err) | ||
495 | goto error; | ||
496 | ssb_pcicore_init(&bus->pcicore); | ||
497 | ssb_bus_may_powerdown(bus); | ||
498 | |||
499 | err = ssb_devices_register(bus); | ||
500 | error: | ||
501 | if (err) { | ||
502 | drop_them_all = 1; | ||
503 | list_del(&bus->list); | ||
504 | continue; | ||
505 | } | ||
506 | list_move_tail(&bus->list, &buses); | ||
507 | } | ||
508 | |||
509 | return err; | ||
510 | } | ||
511 | |||
512 | static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset) | ||
513 | { | ||
514 | struct ssb_bus *bus = dev->bus; | ||
515 | |||
516 | offset += dev->core_index * SSB_CORE_SIZE; | ||
517 | return readw(bus->mmio + offset); | ||
518 | } | ||
519 | |||
520 | static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset) | ||
521 | { | ||
522 | struct ssb_bus *bus = dev->bus; | ||
523 | |||
524 | offset += dev->core_index * SSB_CORE_SIZE; | ||
525 | return readl(bus->mmio + offset); | ||
526 | } | ||
527 | |||
528 | static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value) | ||
529 | { | ||
530 | struct ssb_bus *bus = dev->bus; | ||
531 | |||
532 | offset += dev->core_index * SSB_CORE_SIZE; | ||
533 | writew(value, bus->mmio + offset); | ||
534 | } | ||
535 | |||
536 | static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) | ||
537 | { | ||
538 | struct ssb_bus *bus = dev->bus; | ||
539 | |||
540 | offset += dev->core_index * SSB_CORE_SIZE; | ||
541 | writel(value, bus->mmio + offset); | ||
542 | } | ||
543 | |||
544 | /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ | ||
545 | static const struct ssb_bus_ops ssb_ssb_ops = { | ||
546 | .read16 = ssb_ssb_read16, | ||
547 | .read32 = ssb_ssb_read32, | ||
548 | .write16 = ssb_ssb_write16, | ||
549 | .write32 = ssb_ssb_write32, | ||
550 | }; | ||
551 | |||
552 | static int ssb_fetch_invariants(struct ssb_bus *bus, | ||
553 | ssb_invariants_func_t get_invariants) | ||
554 | { | ||
555 | struct ssb_init_invariants iv; | ||
556 | int err; | ||
557 | |||
558 | memset(&iv, 0, sizeof(iv)); | ||
559 | err = get_invariants(bus, &iv); | ||
560 | if (err) | ||
561 | goto out; | ||
562 | memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo)); | ||
563 | memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom)); | ||
564 | out: | ||
565 | return err; | ||
566 | } | ||
567 | |||
568 | static int ssb_bus_register(struct ssb_bus *bus, | ||
569 | ssb_invariants_func_t get_invariants, | ||
570 | unsigned long baseaddr) | ||
571 | { | ||
572 | int err; | ||
573 | |||
574 | spin_lock_init(&bus->bar_lock); | ||
575 | INIT_LIST_HEAD(&bus->list); | ||
576 | |||
577 | /* Powerup the bus */ | ||
578 | err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); | ||
579 | if (err) | ||
580 | goto out; | ||
581 | ssb_buses_lock(); | ||
582 | bus->busnumber = next_busnumber; | ||
583 | /* Scan for devices (cores) */ | ||
584 | err = ssb_bus_scan(bus, baseaddr); | ||
585 | if (err) | ||
586 | goto err_disable_xtal; | ||
587 | |||
588 | /* Init PCI-host device (if any) */ | ||
589 | err = ssb_pci_init(bus); | ||
590 | if (err) | ||
591 | goto err_unmap; | ||
592 | /* Init PCMCIA-host device (if any) */ | ||
593 | err = ssb_pcmcia_init(bus); | ||
594 | if (err) | ||
595 | goto err_pci_exit; | ||
596 | |||
597 | /* Initialize basic system devices (if available) */ | ||
598 | err = ssb_bus_powerup(bus, 0); | ||
599 | if (err) | ||
600 | goto err_pcmcia_exit; | ||
601 | ssb_chipcommon_init(&bus->chipco); | ||
602 | ssb_mipscore_init(&bus->mipscore); | ||
603 | err = ssb_fetch_invariants(bus, get_invariants); | ||
604 | if (err) { | ||
605 | ssb_bus_may_powerdown(bus); | ||
606 | goto err_pcmcia_exit; | ||
607 | } | ||
608 | ssb_bus_may_powerdown(bus); | ||
609 | |||
610 | /* Queue it for attach. | ||
611 | * See the comment at the ssb_is_early_boot definition. */ | ||
612 | list_add_tail(&bus->list, &attach_queue); | ||
613 | if (!ssb_is_early_boot) { | ||
614 | /* This is not early boot, so we must attach the bus now */ | ||
615 | err = ssb_attach_queued_buses(); | ||
616 | if (err) | ||
617 | goto err_dequeue; | ||
618 | } | ||
619 | next_busnumber++; | ||
620 | ssb_buses_unlock(); | ||
621 | |||
622 | out: | ||
623 | return err; | ||
624 | |||
625 | err_dequeue: | ||
626 | list_del(&bus->list); | ||
627 | err_pcmcia_exit: | ||
628 | /* ssb_pcmcia_exit(bus); */ | ||
629 | err_pci_exit: | ||
630 | ssb_pci_exit(bus); | ||
631 | err_unmap: | ||
632 | ssb_iounmap(bus); | ||
633 | err_disable_xtal: | ||
634 | ssb_buses_unlock(); | ||
635 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | ||
636 | return err; | ||
637 | } | ||
638 | |||
639 | #ifdef CONFIG_SSB_PCIHOST | ||
640 | int ssb_bus_pcibus_register(struct ssb_bus *bus, | ||
641 | struct pci_dev *host_pci) | ||
642 | { | ||
643 | int err; | ||
644 | |||
645 | bus->bustype = SSB_BUSTYPE_PCI; | ||
646 | bus->host_pci = host_pci; | ||
647 | bus->ops = &ssb_pci_ops; | ||
648 | |||
649 | err = ssb_bus_register(bus, ssb_pci_get_invariants, 0); | ||
650 | if (!err) { | ||
651 | ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " | ||
652 | "PCI device %s\n", host_pci->dev.bus_id); | ||
653 | } | ||
654 | |||
655 | return err; | ||
656 | } | ||
657 | EXPORT_SYMBOL(ssb_bus_pcibus_register); | ||
658 | #endif /* CONFIG_SSB_PCIHOST */ | ||
659 | |||
660 | #ifdef CONFIG_SSB_PCMCIAHOST | ||
661 | int ssb_bus_pcmciabus_register(struct ssb_bus *bus, | ||
662 | struct pcmcia_device *pcmcia_dev, | ||
663 | unsigned long baseaddr) | ||
664 | { | ||
665 | int err; | ||
666 | |||
667 | bus->bustype = SSB_BUSTYPE_PCMCIA; | ||
668 | bus->host_pcmcia = pcmcia_dev; | ||
669 | bus->ops = &ssb_pcmcia_ops; | ||
670 | |||
671 | err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr); | ||
672 | if (!err) { | ||
673 | ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " | ||
674 | "PCMCIA device %s\n", pcmcia_dev->devname); | ||
675 | } | ||
676 | |||
677 | return err; | ||
678 | } | ||
679 | EXPORT_SYMBOL(ssb_bus_pcmciabus_register); | ||
680 | #endif /* CONFIG_SSB_PCMCIAHOST */ | ||
681 | |||
682 | int ssb_bus_ssbbus_register(struct ssb_bus *bus, | ||
683 | unsigned long baseaddr, | ||
684 | ssb_invariants_func_t get_invariants) | ||
685 | { | ||
686 | int err; | ||
687 | |||
688 | bus->bustype = SSB_BUSTYPE_SSB; | ||
689 | bus->ops = &ssb_ssb_ops; | ||
690 | |||
691 | err = ssb_bus_register(bus, get_invariants, baseaddr); | ||
692 | if (!err) { | ||
693 | ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at " | ||
694 | "address 0x%08lX\n", baseaddr); | ||
695 | } | ||
696 | |||
697 | return err; | ||
698 | } | ||
699 | |||
700 | int __ssb_driver_register(struct ssb_driver *drv, struct module *owner) | ||
701 | { | ||
702 | drv->drv.name = drv->name; | ||
703 | drv->drv.bus = &ssb_bustype; | ||
704 | drv->drv.owner = owner; | ||
705 | |||
706 | return driver_register(&drv->drv); | ||
707 | } | ||
708 | EXPORT_SYMBOL(__ssb_driver_register); | ||
709 | |||
710 | void ssb_driver_unregister(struct ssb_driver *drv) | ||
711 | { | ||
712 | driver_unregister(&drv->drv); | ||
713 | } | ||
714 | EXPORT_SYMBOL(ssb_driver_unregister); | ||
715 | |||
716 | void ssb_set_devtypedata(struct ssb_device *dev, void *data) | ||
717 | { | ||
718 | struct ssb_bus *bus = dev->bus; | ||
719 | struct ssb_device *ent; | ||
720 | int i; | ||
721 | |||
722 | for (i = 0; i < bus->nr_devices; i++) { | ||
723 | ent = &(bus->devices[i]); | ||
724 | if (ent->id.vendor != dev->id.vendor) | ||
725 | continue; | ||
726 | if (ent->id.coreid != dev->id.coreid) | ||
727 | continue; | ||
728 | |||
729 | ent->devtypedata = data; | ||
730 | } | ||
731 | } | ||
732 | EXPORT_SYMBOL(ssb_set_devtypedata); | ||
733 | |||
734 | static u32 clkfactor_f6_resolve(u32 v) | ||
735 | { | ||
736 | /* map the magic values */ | ||
737 | switch (v) { | ||
738 | case SSB_CHIPCO_CLK_F6_2: | ||
739 | return 2; | ||
740 | case SSB_CHIPCO_CLK_F6_3: | ||
741 | return 3; | ||
742 | case SSB_CHIPCO_CLK_F6_4: | ||
743 | return 4; | ||
744 | case SSB_CHIPCO_CLK_F6_5: | ||
745 | return 5; | ||
746 | case SSB_CHIPCO_CLK_F6_6: | ||
747 | return 6; | ||
748 | case SSB_CHIPCO_CLK_F6_7: | ||
749 | return 7; | ||
750 | } | ||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | /* Calculate the speed the backplane would run at a given set of clockcontrol values */ | ||
755 | u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m) | ||
756 | { | ||
757 | u32 n1, n2, clock, m1, m2, m3, mc; | ||
758 | |||
759 | n1 = (n & SSB_CHIPCO_CLK_N1); | ||
760 | n2 = ((n & SSB_CHIPCO_CLK_N2) >> SSB_CHIPCO_CLK_N2_SHIFT); | ||
761 | |||
762 | switch (plltype) { | ||
763 | case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ | ||
764 | if (m & SSB_CHIPCO_CLK_T6_MMASK) | ||
765 | return SSB_CHIPCO_CLK_T6_M0; | ||
766 | return SSB_CHIPCO_CLK_T6_M1; | ||
767 | case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ | ||
768 | case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ | ||
769 | case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ | ||
770 | case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ | ||
771 | n1 = clkfactor_f6_resolve(n1); | ||
772 | n2 += SSB_CHIPCO_CLK_F5_BIAS; | ||
773 | break; | ||
774 | case SSB_PLLTYPE_2: /* 48Mhz, 4 dividers */ | ||
775 | n1 += SSB_CHIPCO_CLK_T2_BIAS; | ||
776 | n2 += SSB_CHIPCO_CLK_T2_BIAS; | ||
777 | SSB_WARN_ON(!((n1 >= 2) && (n1 <= 7))); | ||
778 | SSB_WARN_ON(!((n2 >= 5) && (n2 <= 23))); | ||
779 | break; | ||
780 | case SSB_PLLTYPE_5: /* 25Mhz, 4 dividers */ | ||
781 | return 100000000; | ||
782 | default: | ||
783 | SSB_WARN_ON(1); | ||
784 | } | ||
785 | |||
786 | switch (plltype) { | ||
787 | case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ | ||
788 | case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ | ||
789 | clock = SSB_CHIPCO_CLK_BASE2 * n1 * n2; | ||
790 | break; | ||
791 | default: | ||
792 | clock = SSB_CHIPCO_CLK_BASE1 * n1 * n2; | ||
793 | } | ||
794 | if (!clock) | ||
795 | return 0; | ||
796 | |||
797 | m1 = (m & SSB_CHIPCO_CLK_M1); | ||
798 | m2 = ((m & SSB_CHIPCO_CLK_M2) >> SSB_CHIPCO_CLK_M2_SHIFT); | ||
799 | m3 = ((m & SSB_CHIPCO_CLK_M3) >> SSB_CHIPCO_CLK_M3_SHIFT); | ||
800 | mc = ((m & SSB_CHIPCO_CLK_MC) >> SSB_CHIPCO_CLK_MC_SHIFT); | ||
801 | |||
802 | switch (plltype) { | ||
803 | case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ | ||
804 | case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ | ||
805 | case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ | ||
806 | case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ | ||
807 | m1 = clkfactor_f6_resolve(m1); | ||
808 | if ((plltype == SSB_PLLTYPE_1) || | ||
809 | (plltype == SSB_PLLTYPE_3)) | ||
810 | m2 += SSB_CHIPCO_CLK_F5_BIAS; | ||
811 | else | ||
812 | m2 = clkfactor_f6_resolve(m2); | ||
813 | m3 = clkfactor_f6_resolve(m3); | ||
814 | |||
815 | switch (mc) { | ||
816 | case SSB_CHIPCO_CLK_MC_BYPASS: | ||
817 | return clock; | ||
818 | case SSB_CHIPCO_CLK_MC_M1: | ||
819 | return (clock / m1); | ||
820 | case SSB_CHIPCO_CLK_MC_M1M2: | ||
821 | return (clock / (m1 * m2)); | ||
822 | case SSB_CHIPCO_CLK_MC_M1M2M3: | ||
823 | return (clock / (m1 * m2 * m3)); | ||
824 | case SSB_CHIPCO_CLK_MC_M1M3: | ||
825 | return (clock / (m1 * m3)); | ||
826 | } | ||
827 | return 0; | ||
828 | case SSB_PLLTYPE_2: | ||
829 | m1 += SSB_CHIPCO_CLK_T2_BIAS; | ||
830 | m2 += SSB_CHIPCO_CLK_T2M2_BIAS; | ||
831 | m3 += SSB_CHIPCO_CLK_T2_BIAS; | ||
832 | SSB_WARN_ON(!((m1 >= 2) && (m1 <= 7))); | ||
833 | SSB_WARN_ON(!((m2 >= 3) && (m2 <= 10))); | ||
834 | SSB_WARN_ON(!((m3 >= 2) && (m3 <= 7))); | ||
835 | |||
836 | if (!(mc & SSB_CHIPCO_CLK_T2MC_M1BYP)) | ||
837 | clock /= m1; | ||
838 | if (!(mc & SSB_CHIPCO_CLK_T2MC_M2BYP)) | ||
839 | clock /= m2; | ||
840 | if (!(mc & SSB_CHIPCO_CLK_T2MC_M3BYP)) | ||
841 | clock /= m3; | ||
842 | return clock; | ||
843 | default: | ||
844 | SSB_WARN_ON(1); | ||
845 | } | ||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | /* Get the current speed the backplane is running at */ | ||
850 | u32 ssb_clockspeed(struct ssb_bus *bus) | ||
851 | { | ||
852 | u32 rate; | ||
853 | u32 plltype; | ||
854 | u32 clkctl_n, clkctl_m; | ||
855 | |||
856 | if (ssb_extif_available(&bus->extif)) | ||
857 | ssb_extif_get_clockcontrol(&bus->extif, &plltype, | ||
858 | &clkctl_n, &clkctl_m); | ||
859 | else if (bus->chipco.dev) | ||
860 | ssb_chipco_get_clockcontrol(&bus->chipco, &plltype, | ||
861 | &clkctl_n, &clkctl_m); | ||
862 | else | ||
863 | return 0; | ||
864 | |||
865 | if (bus->chip_id == 0x5365) { | ||
866 | rate = 100000000; | ||
867 | } else { | ||
868 | rate = ssb_calc_clock_rate(plltype, clkctl_n, clkctl_m); | ||
869 | if (plltype == SSB_PLLTYPE_3) /* 25Mhz, 2 dividers */ | ||
870 | rate /= 2; | ||
871 | } | ||
872 | |||
873 | return rate; | ||
874 | } | ||
875 | EXPORT_SYMBOL(ssb_clockspeed); | ||
876 | |||
877 | static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) | ||
878 | { | ||
879 | /* The REJECT bit changed position in TMSLOW between | ||
880 | * Backplane revisions. */ | ||
881 | switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) { | ||
882 | case SSB_IDLOW_SSBREV_22: | ||
883 | return SSB_TMSLOW_REJECT_22; | ||
884 | case SSB_IDLOW_SSBREV_23: | ||
885 | return SSB_TMSLOW_REJECT_23; | ||
886 | default: | ||
887 | WARN_ON(1); | ||
888 | } | ||
889 | return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); | ||
890 | } | ||
891 | |||
892 | int ssb_device_is_enabled(struct ssb_device *dev) | ||
893 | { | ||
894 | u32 val; | ||
895 | u32 reject; | ||
896 | |||
897 | reject = ssb_tmslow_reject_bitmask(dev); | ||
898 | val = ssb_read32(dev, SSB_TMSLOW); | ||
899 | val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject; | ||
900 | |||
901 | return (val == SSB_TMSLOW_CLOCK); | ||
902 | } | ||
903 | EXPORT_SYMBOL(ssb_device_is_enabled); | ||
904 | |||
905 | static void ssb_flush_tmslow(struct ssb_device *dev) | ||
906 | { | ||
907 | /* Make _really_ sure the device has finished the TMSLOW | ||
908 | * register write transaction, as we risk running into | ||
909 | * a machine check exception otherwise. | ||
910 | * Do this by reading the register back to commit the | ||
911 | * PCI write and delay an additional usec for the device | ||
912 | * to react to the change. */ | ||
913 | ssb_read32(dev, SSB_TMSLOW); | ||
914 | udelay(1); | ||
915 | } | ||
916 | |||
917 | void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags) | ||
918 | { | ||
919 | u32 val; | ||
920 | |||
921 | ssb_device_disable(dev, core_specific_flags); | ||
922 | ssb_write32(dev, SSB_TMSLOW, | ||
923 | SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK | | ||
924 | SSB_TMSLOW_FGC | core_specific_flags); | ||
925 | ssb_flush_tmslow(dev); | ||
926 | |||
927 | /* Clear SERR if set. This is a hw bug workaround. */ | ||
928 | if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_SERR) | ||
929 | ssb_write32(dev, SSB_TMSHIGH, 0); | ||
930 | |||
931 | val = ssb_read32(dev, SSB_IMSTATE); | ||
932 | if (val & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) { | ||
933 | val &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO); | ||
934 | ssb_write32(dev, SSB_IMSTATE, val); | ||
935 | } | ||
936 | |||
937 | ssb_write32(dev, SSB_TMSLOW, | ||
938 | SSB_TMSLOW_CLOCK | SSB_TMSLOW_FGC | | ||
939 | core_specific_flags); | ||
940 | ssb_flush_tmslow(dev); | ||
941 | |||
942 | ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_CLOCK | | ||
943 | core_specific_flags); | ||
944 | ssb_flush_tmslow(dev); | ||
945 | } | ||
946 | EXPORT_SYMBOL(ssb_device_enable); | ||
947 | |||
948 | /* Wait for a bit in a register to get set or unset. | ||
949 | * timeout is in units of ten-microseconds */ | ||
950 | static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask, | ||
951 | int timeout, int set) | ||
952 | { | ||
953 | int i; | ||
954 | u32 val; | ||
955 | |||
956 | for (i = 0; i < timeout; i++) { | ||
957 | val = ssb_read32(dev, reg); | ||
958 | if (set) { | ||
959 | if (val & bitmask) | ||
960 | return 0; | ||
961 | } else { | ||
962 | if (!(val & bitmask)) | ||
963 | return 0; | ||
964 | } | ||
965 | udelay(10); | ||
966 | } | ||
967 | printk(KERN_ERR PFX "Timeout waiting for bitmask %08X on " | ||
968 | "register %04X to %s.\n", | ||
969 | bitmask, reg, (set ? "set" : "clear")); | ||
970 | |||
971 | return -ETIMEDOUT; | ||
972 | } | ||
973 | |||
974 | void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags) | ||
975 | { | ||
976 | u32 reject; | ||
977 | |||
978 | if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET) | ||
979 | return; | ||
980 | |||
981 | reject = ssb_tmslow_reject_bitmask(dev); | ||
982 | ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK); | ||
983 | ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1); | ||
984 | ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0); | ||
985 | ssb_write32(dev, SSB_TMSLOW, | ||
986 | SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | | ||
987 | reject | SSB_TMSLOW_RESET | | ||
988 | core_specific_flags); | ||
989 | ssb_flush_tmslow(dev); | ||
990 | |||
991 | ssb_write32(dev, SSB_TMSLOW, | ||
992 | reject | SSB_TMSLOW_RESET | | ||
993 | core_specific_flags); | ||
994 | ssb_flush_tmslow(dev); | ||
995 | } | ||
996 | EXPORT_SYMBOL(ssb_device_disable); | ||
997 | |||
998 | u32 ssb_dma_translation(struct ssb_device *dev) | ||
999 | { | ||
1000 | switch (dev->bus->bustype) { | ||
1001 | case SSB_BUSTYPE_SSB: | ||
1002 | return 0; | ||
1003 | case SSB_BUSTYPE_PCI: | ||
1004 | case SSB_BUSTYPE_PCMCIA: | ||
1005 | return SSB_PCI_DMA; | ||
1006 | } | ||
1007 | return 0; | ||
1008 | } | ||
1009 | EXPORT_SYMBOL(ssb_dma_translation); | ||
1010 | |||
1011 | int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask) | ||
1012 | { | ||
1013 | struct device *dev = ssb_dev->dev; | ||
1014 | |||
1015 | #ifdef CONFIG_SSB_PCIHOST | ||
1016 | if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI && | ||
1017 | !dma_supported(dev, mask)) | ||
1018 | return -EIO; | ||
1019 | #endif | ||
1020 | dev->coherent_dma_mask = mask; | ||
1021 | dev->dma_mask = &dev->coherent_dma_mask; | ||
1022 | |||
1023 | return 0; | ||
1024 | } | ||
1025 | EXPORT_SYMBOL(ssb_dma_set_mask); | ||
1026 | |||
1027 | int ssb_bus_may_powerdown(struct ssb_bus *bus) | ||
1028 | { | ||
1029 | struct ssb_chipcommon *cc; | ||
1030 | int err = 0; | ||
1031 | |||
1032 | /* On buses where more than one core may be working | ||
1033 | * at a time, we must not powerdown stuff if there are | ||
1034 | * still cores that may want to run. */ | ||
1035 | if (bus->bustype == SSB_BUSTYPE_SSB) | ||
1036 | goto out; | ||
1037 | |||
1038 | cc = &bus->chipco; | ||
1039 | ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); | ||
1040 | err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | ||
1041 | if (err) | ||
1042 | goto error; | ||
1043 | out: | ||
1044 | #ifdef CONFIG_SSB_DEBUG | ||
1045 | bus->powered_up = 0; | ||
1046 | #endif | ||
1047 | return err; | ||
1048 | error: | ||
1049 | ssb_printk(KERN_ERR PFX "Bus powerdown failed\n"); | ||
1050 | goto out; | ||
1051 | } | ||
1052 | EXPORT_SYMBOL(ssb_bus_may_powerdown); | ||
1053 | |||
1054 | int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) | ||
1055 | { | ||
1056 | struct ssb_chipcommon *cc; | ||
1057 | int err; | ||
1058 | enum ssb_clkmode mode; | ||
1059 | |||
1060 | err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); | ||
1061 | if (err) | ||
1062 | goto error; | ||
1063 | cc = &bus->chipco; | ||
1064 | mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; | ||
1065 | ssb_chipco_set_clockmode(cc, mode); | ||
1066 | |||
1067 | #ifdef CONFIG_SSB_DEBUG | ||
1068 | bus->powered_up = 1; | ||
1069 | #endif | ||
1070 | return 0; | ||
1071 | error: | ||
1072 | ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); | ||
1073 | return err; | ||
1074 | } | ||
1075 | EXPORT_SYMBOL(ssb_bus_powerup); | ||
1076 | |||
1077 | u32 ssb_admatch_base(u32 adm) | ||
1078 | { | ||
1079 | u32 base = 0; | ||
1080 | |||
1081 | switch (adm & SSB_ADM_TYPE) { | ||
1082 | case SSB_ADM_TYPE0: | ||
1083 | base = (adm & SSB_ADM_BASE0); | ||
1084 | break; | ||
1085 | case SSB_ADM_TYPE1: | ||
1086 | SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ | ||
1087 | base = (adm & SSB_ADM_BASE1); | ||
1088 | break; | ||
1089 | case SSB_ADM_TYPE2: | ||
1090 | SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ | ||
1091 | base = (adm & SSB_ADM_BASE2); | ||
1092 | break; | ||
1093 | default: | ||
1094 | SSB_WARN_ON(1); | ||
1095 | } | ||
1096 | |||
1097 | return base; | ||
1098 | } | ||
1099 | EXPORT_SYMBOL(ssb_admatch_base); | ||
1100 | |||
1101 | u32 ssb_admatch_size(u32 adm) | ||
1102 | { | ||
1103 | u32 size = 0; | ||
1104 | |||
1105 | switch (adm & SSB_ADM_TYPE) { | ||
1106 | case SSB_ADM_TYPE0: | ||
1107 | size = ((adm & SSB_ADM_SZ0) >> SSB_ADM_SZ0_SHIFT); | ||
1108 | break; | ||
1109 | case SSB_ADM_TYPE1: | ||
1110 | SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ | ||
1111 | size = ((adm & SSB_ADM_SZ1) >> SSB_ADM_SZ1_SHIFT); | ||
1112 | break; | ||
1113 | case SSB_ADM_TYPE2: | ||
1114 | SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ | ||
1115 | size = ((adm & SSB_ADM_SZ2) >> SSB_ADM_SZ2_SHIFT); | ||
1116 | break; | ||
1117 | default: | ||
1118 | SSB_WARN_ON(1); | ||
1119 | } | ||
1120 | size = (1 << (size + 1)); | ||
1121 | |||
1122 | return size; | ||
1123 | } | ||
1124 | EXPORT_SYMBOL(ssb_admatch_size); | ||
1125 | |||
1126 | static int __init ssb_modinit(void) | ||
1127 | { | ||
1128 | int err; | ||
1129 | |||
1130 | /* See the comment at the ssb_is_early_boot definition */ | ||
1131 | ssb_is_early_boot = 0; | ||
1132 | err = bus_register(&ssb_bustype); | ||
1133 | if (err) | ||
1134 | return err; | ||
1135 | |||
1136 | /* Maybe we already registered some buses at early boot. | ||
1137 | * Check for this and attach them | ||
1138 | */ | ||
1139 | ssb_buses_lock(); | ||
1140 | err = ssb_attach_queued_buses(); | ||
1141 | ssb_buses_unlock(); | ||
1142 | if (err) | ||
1143 | bus_unregister(&ssb_bustype); | ||
1144 | |||
1145 | err = b43_pci_ssb_bridge_init(); | ||
1146 | if (err) { | ||
1147 | ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " | ||
1148 | "initialization failed"); | ||
1149 | /* don't fail SSB init because of this */ | ||
1150 | err = 0; | ||
1151 | } | ||
1152 | |||
1153 | return err; | ||
1154 | } | ||
1155 | subsys_initcall(ssb_modinit); | ||
1156 | |||
1157 | static void __exit ssb_modexit(void) | ||
1158 | { | ||
1159 | b43_pci_ssb_bridge_exit(); | ||
1160 | bus_unregister(&ssb_bustype); | ||
1161 | } | ||
1162 | module_exit(ssb_modexit) | ||
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c new file mode 100644 index 000000000000..3d23ca4befe3 --- /dev/null +++ b/drivers/ssb/pci.c | |||
@@ -0,0 +1,740 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane PCI-Hostbus related functions. | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de> | ||
5 | * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> | ||
6 | * Copyright (C) 2005 Stefano Brivio <st3@riseup.net> | ||
7 | * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> | ||
8 | * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> | ||
9 | * | ||
10 | * Derived from the Broadcom 4400 device driver. | ||
11 | * Copyright (C) 2002 David S. Miller (davem@redhat.com) | ||
12 | * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) | ||
13 | * Copyright (C) 2006 Broadcom Corporation. | ||
14 | * | ||
15 | * Licensed under the GNU/GPL. See COPYING for details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/ssb/ssb.h> | ||
19 | #include <linux/ssb/ssb_regs.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/delay.h> | ||
22 | |||
23 | #include "ssb_private.h" | ||
24 | |||
25 | |||
26 | /* Define the following to 1 to enable a printk on each coreswitch. */ | ||
27 | #define SSB_VERBOSE_PCICORESWITCH_DEBUG 0 | ||
28 | |||
29 | |||
30 | /* Lowlevel coreswitching */ | ||
31 | int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx) | ||
32 | { | ||
33 | int err; | ||
34 | int attempts = 0; | ||
35 | u32 cur_core; | ||
36 | |||
37 | while (1) { | ||
38 | err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN, | ||
39 | (coreidx * SSB_CORE_SIZE) | ||
40 | + SSB_ENUM_BASE); | ||
41 | if (err) | ||
42 | goto error; | ||
43 | err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN, | ||
44 | &cur_core); | ||
45 | if (err) | ||
46 | goto error; | ||
47 | cur_core = (cur_core - SSB_ENUM_BASE) | ||
48 | / SSB_CORE_SIZE; | ||
49 | if (cur_core == coreidx) | ||
50 | break; | ||
51 | |||
52 | if (attempts++ > SSB_BAR0_MAX_RETRIES) | ||
53 | goto error; | ||
54 | udelay(10); | ||
55 | } | ||
56 | return 0; | ||
57 | error: | ||
58 | ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx); | ||
59 | return -ENODEV; | ||
60 | } | ||
61 | |||
62 | int ssb_pci_switch_core(struct ssb_bus *bus, | ||
63 | struct ssb_device *dev) | ||
64 | { | ||
65 | int err; | ||
66 | unsigned long flags; | ||
67 | |||
68 | #if SSB_VERBOSE_PCICORESWITCH_DEBUG | ||
69 | ssb_printk(KERN_INFO PFX | ||
70 | "Switching to %s core, index %d\n", | ||
71 | ssb_core_name(dev->id.coreid), | ||
72 | dev->core_index); | ||
73 | #endif | ||
74 | |||
75 | spin_lock_irqsave(&bus->bar_lock, flags); | ||
76 | err = ssb_pci_switch_coreidx(bus, dev->core_index); | ||
77 | if (!err) | ||
78 | bus->mapped_device = dev; | ||
79 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
80 | |||
81 | return err; | ||
82 | } | ||
83 | |||
84 | /* Enable/disable the on board crystal oscillator and/or PLL. */ | ||
85 | int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on) | ||
86 | { | ||
87 | int err; | ||
88 | u32 in, out, outenable; | ||
89 | u16 pci_status; | ||
90 | |||
91 | if (bus->bustype != SSB_BUSTYPE_PCI) | ||
92 | return 0; | ||
93 | |||
94 | err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in); | ||
95 | if (err) | ||
96 | goto err_pci; | ||
97 | err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out); | ||
98 | if (err) | ||
99 | goto err_pci; | ||
100 | err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable); | ||
101 | if (err) | ||
102 | goto err_pci; | ||
103 | |||
104 | outenable |= what; | ||
105 | |||
106 | if (turn_on) { | ||
107 | /* Avoid glitching the clock if GPRS is already using it. | ||
108 | * We can't actually read the state of the PLLPD so we infer it | ||
109 | * by the value of XTAL_PU which *is* readable via gpioin. | ||
110 | */ | ||
111 | if (!(in & SSB_GPIO_XTAL)) { | ||
112 | if (what & SSB_GPIO_XTAL) { | ||
113 | /* Turn the crystal on */ | ||
114 | out |= SSB_GPIO_XTAL; | ||
115 | if (what & SSB_GPIO_PLL) | ||
116 | out |= SSB_GPIO_PLL; | ||
117 | err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); | ||
118 | if (err) | ||
119 | goto err_pci; | ||
120 | err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, | ||
121 | outenable); | ||
122 | if (err) | ||
123 | goto err_pci; | ||
124 | msleep(1); | ||
125 | } | ||
126 | if (what & SSB_GPIO_PLL) { | ||
127 | /* Turn the PLL on */ | ||
128 | out &= ~SSB_GPIO_PLL; | ||
129 | err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); | ||
130 | if (err) | ||
131 | goto err_pci; | ||
132 | msleep(5); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status); | ||
137 | if (err) | ||
138 | goto err_pci; | ||
139 | pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT; | ||
140 | err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status); | ||
141 | if (err) | ||
142 | goto err_pci; | ||
143 | } else { | ||
144 | if (what & SSB_GPIO_XTAL) { | ||
145 | /* Turn the crystal off */ | ||
146 | out &= ~SSB_GPIO_XTAL; | ||
147 | } | ||
148 | if (what & SSB_GPIO_PLL) { | ||
149 | /* Turn the PLL off */ | ||
150 | out |= SSB_GPIO_PLL; | ||
151 | } | ||
152 | err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); | ||
153 | if (err) | ||
154 | goto err_pci; | ||
155 | err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable); | ||
156 | if (err) | ||
157 | goto err_pci; | ||
158 | } | ||
159 | |||
160 | out: | ||
161 | return err; | ||
162 | |||
163 | err_pci: | ||
164 | printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n"); | ||
165 | err = -EBUSY; | ||
166 | goto out; | ||
167 | } | ||
168 | |||
169 | /* Get the word-offset for a SSB_SPROM_XXX define. */ | ||
170 | #define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16)) | ||
171 | /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ | ||
172 | #define SPEX(_outvar, _offset, _mask, _shift) \ | ||
173 | out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) | ||
174 | |||
175 | static inline u8 ssb_crc8(u8 crc, u8 data) | ||
176 | { | ||
177 | /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */ | ||
178 | static const u8 t[] = { | ||
179 | 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, | ||
180 | 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, | ||
181 | 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, | ||
182 | 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, | ||
183 | 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, | ||
184 | 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, | ||
185 | 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, | ||
186 | 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, | ||
187 | 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, | ||
188 | 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, | ||
189 | 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, | ||
190 | 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, | ||
191 | 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, | ||
192 | 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, | ||
193 | 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, | ||
194 | 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, | ||
195 | 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, | ||
196 | 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, | ||
197 | 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, | ||
198 | 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, | ||
199 | 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, | ||
200 | 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, | ||
201 | 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, | ||
202 | 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, | ||
203 | 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, | ||
204 | 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, | ||
205 | 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, | ||
206 | 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, | ||
207 | 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, | ||
208 | 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, | ||
209 | 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, | ||
210 | 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, | ||
211 | }; | ||
212 | return t[crc ^ data]; | ||
213 | } | ||
214 | |||
215 | static u8 ssb_sprom_crc(const u16 *sprom) | ||
216 | { | ||
217 | int word; | ||
218 | u8 crc = 0xFF; | ||
219 | |||
220 | for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) { | ||
221 | crc = ssb_crc8(crc, sprom[word] & 0x00FF); | ||
222 | crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8); | ||
223 | } | ||
224 | crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF); | ||
225 | crc ^= 0xFF; | ||
226 | |||
227 | return crc; | ||
228 | } | ||
229 | |||
230 | static int sprom_check_crc(const u16 *sprom) | ||
231 | { | ||
232 | u8 crc; | ||
233 | u8 expected_crc; | ||
234 | u16 tmp; | ||
235 | |||
236 | crc = ssb_sprom_crc(sprom); | ||
237 | tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC; | ||
238 | expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; | ||
239 | if (crc != expected_crc) | ||
240 | return -EPROTO; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static void sprom_do_read(struct ssb_bus *bus, u16 *sprom) | ||
246 | { | ||
247 | int i; | ||
248 | |||
249 | for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) | ||
250 | sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2)); | ||
251 | } | ||
252 | |||
253 | static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) | ||
254 | { | ||
255 | struct pci_dev *pdev = bus->host_pci; | ||
256 | int i, err; | ||
257 | u32 spromctl; | ||
258 | |||
259 | ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); | ||
260 | err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); | ||
261 | if (err) | ||
262 | goto err_ctlreg; | ||
263 | spromctl |= SSB_SPROMCTL_WE; | ||
264 | err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); | ||
265 | if (err) | ||
266 | goto err_ctlreg; | ||
267 | ssb_printk(KERN_NOTICE PFX "[ 0%%"); | ||
268 | msleep(500); | ||
269 | for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { | ||
270 | if (i == SSB_SPROMSIZE_WORDS / 4) | ||
271 | ssb_printk("25%%"); | ||
272 | else if (i == SSB_SPROMSIZE_WORDS / 2) | ||
273 | ssb_printk("50%%"); | ||
274 | else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3) | ||
275 | ssb_printk("75%%"); | ||
276 | else if (i % 2) | ||
277 | ssb_printk("."); | ||
278 | writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2)); | ||
279 | mmiowb(); | ||
280 | msleep(20); | ||
281 | } | ||
282 | err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); | ||
283 | if (err) | ||
284 | goto err_ctlreg; | ||
285 | spromctl &= ~SSB_SPROMCTL_WE; | ||
286 | err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); | ||
287 | if (err) | ||
288 | goto err_ctlreg; | ||
289 | msleep(500); | ||
290 | ssb_printk("100%% ]\n"); | ||
291 | ssb_printk(KERN_NOTICE PFX "SPROM written.\n"); | ||
292 | |||
293 | return 0; | ||
294 | err_ctlreg: | ||
295 | ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n"); | ||
296 | return err; | ||
297 | } | ||
298 | |||
299 | static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) | ||
300 | { | ||
301 | int i; | ||
302 | u16 v; | ||
303 | |||
304 | SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0); | ||
305 | SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0); | ||
306 | SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0); | ||
307 | for (i = 0; i < 3; i++) { | ||
308 | v = in[SPOFF(SSB_SPROM1_IL0MAC) + i]; | ||
309 | *(((u16 *)out->il0mac) + i) = cpu_to_be16(v); | ||
310 | } | ||
311 | for (i = 0; i < 3; i++) { | ||
312 | v = in[SPOFF(SSB_SPROM1_ET0MAC) + i]; | ||
313 | *(((u16 *)out->et0mac) + i) = cpu_to_be16(v); | ||
314 | } | ||
315 | for (i = 0; i < 3; i++) { | ||
316 | v = in[SPOFF(SSB_SPROM1_ET1MAC) + i]; | ||
317 | *(((u16 *)out->et1mac) + i) = cpu_to_be16(v); | ||
318 | } | ||
319 | SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); | ||
320 | SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, | ||
321 | SSB_SPROM1_ETHPHY_ET1A_SHIFT); | ||
322 | SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); | ||
323 | SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); | ||
324 | SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); | ||
325 | SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, | ||
326 | SSB_SPROM1_BINF_CCODE_SHIFT); | ||
327 | SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, | ||
328 | SSB_SPROM1_BINF_ANTA_SHIFT); | ||
329 | SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, | ||
330 | SSB_SPROM1_BINF_ANTBG_SHIFT); | ||
331 | SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0); | ||
332 | SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0); | ||
333 | SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0); | ||
334 | SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0); | ||
335 | SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0); | ||
336 | SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0); | ||
337 | SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0); | ||
338 | SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1, | ||
339 | SSB_SPROM1_GPIOA_P1_SHIFT); | ||
340 | SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0); | ||
341 | SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3, | ||
342 | SSB_SPROM1_GPIOB_P3_SHIFT); | ||
343 | SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, | ||
344 | SSB_SPROM1_MAXPWR_A_SHIFT); | ||
345 | SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0); | ||
346 | SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, | ||
347 | SSB_SPROM1_ITSSI_A_SHIFT); | ||
348 | SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); | ||
349 | SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); | ||
350 | SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0); | ||
351 | SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG, | ||
352 | SSB_SPROM1_AGAIN_BG_SHIFT); | ||
353 | for (i = 0; i < 4; i++) { | ||
354 | v = in[SPOFF(SSB_SPROM1_OEM) + i]; | ||
355 | *(((u16 *)out->oem) + i) = cpu_to_le16(v); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in) | ||
360 | { | ||
361 | int i; | ||
362 | u16 v; | ||
363 | |||
364 | SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); | ||
365 | SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0); | ||
366 | SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO, | ||
367 | SSB_SPROM2_MAXP_A_LO_SHIFT); | ||
368 | SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0); | ||
369 | SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0); | ||
370 | SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0); | ||
371 | SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0); | ||
372 | SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0); | ||
373 | SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0); | ||
374 | SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); | ||
375 | for (i = 0; i < 4; i++) { | ||
376 | v = in[SPOFF(SSB_SPROM2_CCODE) + i]; | ||
377 | *(((u16 *)out->country_str) + i) = cpu_to_le16(v); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in) | ||
382 | { | ||
383 | out->ofdmapo = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8; | ||
384 | out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8; | ||
385 | out->ofdmapo <<= 16; | ||
386 | out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8; | ||
387 | out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8; | ||
388 | |||
389 | out->ofdmalpo = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8; | ||
390 | out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8; | ||
391 | out->ofdmalpo <<= 16; | ||
392 | out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8; | ||
393 | out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8; | ||
394 | |||
395 | out->ofdmahpo = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8; | ||
396 | out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8; | ||
397 | out->ofdmahpo <<= 16; | ||
398 | out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8; | ||
399 | out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8; | ||
400 | |||
401 | SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON, | ||
402 | SSB_SPROM3_GPIOLDC_ON_SHIFT); | ||
403 | SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF, | ||
404 | SSB_SPROM3_GPIOLDC_OFF_SHIFT); | ||
405 | SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0); | ||
406 | SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M, | ||
407 | SSB_SPROM3_CCKPO_2M_SHIFT); | ||
408 | SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M, | ||
409 | SSB_SPROM3_CCKPO_55M_SHIFT); | ||
410 | SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M, | ||
411 | SSB_SPROM3_CCKPO_11M_SHIFT); | ||
412 | |||
413 | out->ofdmgpo = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8; | ||
414 | out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8; | ||
415 | out->ofdmgpo <<= 16; | ||
416 | out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8; | ||
417 | out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8; | ||
418 | } | ||
419 | |||
420 | static int sprom_extract(struct ssb_bus *bus, | ||
421 | struct ssb_sprom *out, const u16 *in) | ||
422 | { | ||
423 | memset(out, 0, sizeof(*out)); | ||
424 | |||
425 | SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0); | ||
426 | SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC, | ||
427 | SSB_SPROM_REVISION_CRC_SHIFT); | ||
428 | |||
429 | if ((bus->chip_id & 0xFF00) == 0x4400) { | ||
430 | /* Workaround: The BCM44XX chip has a stupid revision | ||
431 | * number stored in the SPROM. | ||
432 | * Always extract r1. */ | ||
433 | sprom_extract_r1(&out->r1, in); | ||
434 | } else { | ||
435 | if (out->revision == 0) | ||
436 | goto unsupported; | ||
437 | if (out->revision >= 1 && out->revision <= 3) | ||
438 | sprom_extract_r1(&out->r1, in); | ||
439 | if (out->revision >= 2 && out->revision <= 3) | ||
440 | sprom_extract_r2(&out->r2, in); | ||
441 | if (out->revision == 3) | ||
442 | sprom_extract_r3(&out->r3, in); | ||
443 | if (out->revision >= 4) | ||
444 | goto unsupported; | ||
445 | } | ||
446 | |||
447 | return 0; | ||
448 | unsupported: | ||
449 | ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d " | ||
450 | "detected. Will extract v1\n", out->revision); | ||
451 | sprom_extract_r1(&out->r1, in); | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int ssb_pci_sprom_get(struct ssb_bus *bus, | ||
456 | struct ssb_sprom *sprom) | ||
457 | { | ||
458 | int err = -ENOMEM; | ||
459 | u16 *buf; | ||
460 | |||
461 | buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); | ||
462 | if (!buf) | ||
463 | goto out; | ||
464 | sprom_do_read(bus, buf); | ||
465 | err = sprom_check_crc(buf); | ||
466 | if (err) { | ||
467 | ssb_printk(KERN_WARNING PFX | ||
468 | "WARNING: Invalid SPROM CRC (corrupt SPROM)\n"); | ||
469 | } | ||
470 | err = sprom_extract(bus, sprom, buf); | ||
471 | |||
472 | kfree(buf); | ||
473 | out: | ||
474 | return err; | ||
475 | } | ||
476 | |||
477 | static void ssb_pci_get_boardinfo(struct ssb_bus *bus, | ||
478 | struct ssb_boardinfo *bi) | ||
479 | { | ||
480 | pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID, | ||
481 | &bi->vendor); | ||
482 | pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID, | ||
483 | &bi->type); | ||
484 | pci_read_config_word(bus->host_pci, PCI_REVISION_ID, | ||
485 | &bi->rev); | ||
486 | } | ||
487 | |||
488 | int ssb_pci_get_invariants(struct ssb_bus *bus, | ||
489 | struct ssb_init_invariants *iv) | ||
490 | { | ||
491 | int err; | ||
492 | |||
493 | err = ssb_pci_sprom_get(bus, &iv->sprom); | ||
494 | if (err) | ||
495 | goto out; | ||
496 | ssb_pci_get_boardinfo(bus, &iv->boardinfo); | ||
497 | |||
498 | out: | ||
499 | return err; | ||
500 | } | ||
501 | |||
502 | #ifdef CONFIG_SSB_DEBUG | ||
503 | static int ssb_pci_assert_buspower(struct ssb_bus *bus) | ||
504 | { | ||
505 | if (likely(bus->powered_up)) | ||
506 | return 0; | ||
507 | |||
508 | printk(KERN_ERR PFX "FATAL ERROR: Bus powered down " | ||
509 | "while accessing PCI MMIO space\n"); | ||
510 | if (bus->power_warn_count <= 10) { | ||
511 | bus->power_warn_count++; | ||
512 | dump_stack(); | ||
513 | } | ||
514 | |||
515 | return -ENODEV; | ||
516 | } | ||
517 | #else /* DEBUG */ | ||
518 | static inline int ssb_pci_assert_buspower(struct ssb_bus *bus) | ||
519 | { | ||
520 | return 0; | ||
521 | } | ||
522 | #endif /* DEBUG */ | ||
523 | |||
524 | static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) | ||
525 | { | ||
526 | struct ssb_bus *bus = dev->bus; | ||
527 | |||
528 | if (unlikely(ssb_pci_assert_buspower(bus))) | ||
529 | return 0xFFFF; | ||
530 | if (unlikely(bus->mapped_device != dev)) { | ||
531 | if (unlikely(ssb_pci_switch_core(bus, dev))) | ||
532 | return 0xFFFF; | ||
533 | } | ||
534 | return readw(bus->mmio + offset); | ||
535 | } | ||
536 | |||
537 | static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) | ||
538 | { | ||
539 | struct ssb_bus *bus = dev->bus; | ||
540 | |||
541 | if (unlikely(ssb_pci_assert_buspower(bus))) | ||
542 | return 0xFFFFFFFF; | ||
543 | if (unlikely(bus->mapped_device != dev)) { | ||
544 | if (unlikely(ssb_pci_switch_core(bus, dev))) | ||
545 | return 0xFFFFFFFF; | ||
546 | } | ||
547 | return readl(bus->mmio + offset); | ||
548 | } | ||
549 | |||
550 | static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) | ||
551 | { | ||
552 | struct ssb_bus *bus = dev->bus; | ||
553 | |||
554 | if (unlikely(ssb_pci_assert_buspower(bus))) | ||
555 | return; | ||
556 | if (unlikely(bus->mapped_device != dev)) { | ||
557 | if (unlikely(ssb_pci_switch_core(bus, dev))) | ||
558 | return; | ||
559 | } | ||
560 | writew(value, bus->mmio + offset); | ||
561 | } | ||
562 | |||
563 | static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) | ||
564 | { | ||
565 | struct ssb_bus *bus = dev->bus; | ||
566 | |||
567 | if (unlikely(ssb_pci_assert_buspower(bus))) | ||
568 | return; | ||
569 | if (unlikely(bus->mapped_device != dev)) { | ||
570 | if (unlikely(ssb_pci_switch_core(bus, dev))) | ||
571 | return; | ||
572 | } | ||
573 | writel(value, bus->mmio + offset); | ||
574 | } | ||
575 | |||
576 | /* Not "static", as it's used in main.c */ | ||
577 | const struct ssb_bus_ops ssb_pci_ops = { | ||
578 | .read16 = ssb_pci_read16, | ||
579 | .read32 = ssb_pci_read32, | ||
580 | .write16 = ssb_pci_write16, | ||
581 | .write32 = ssb_pci_write32, | ||
582 | }; | ||
583 | |||
584 | static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) | ||
585 | { | ||
586 | int i, pos = 0; | ||
587 | |||
588 | for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { | ||
589 | pos += snprintf(buf + pos, buf_len - pos - 1, | ||
590 | "%04X", swab16(sprom[i]) & 0xFFFF); | ||
591 | } | ||
592 | pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); | ||
593 | |||
594 | return pos + 1; | ||
595 | } | ||
596 | |||
597 | static int hex2sprom(u16 *sprom, const char *dump, size_t len) | ||
598 | { | ||
599 | char tmp[5] = { 0 }; | ||
600 | int cnt = 0; | ||
601 | unsigned long parsed; | ||
602 | |||
603 | if (len < SSB_SPROMSIZE_BYTES * 2) | ||
604 | return -EINVAL; | ||
605 | |||
606 | while (cnt < SSB_SPROMSIZE_WORDS) { | ||
607 | memcpy(tmp, dump, 4); | ||
608 | dump += 4; | ||
609 | parsed = simple_strtoul(tmp, NULL, 16); | ||
610 | sprom[cnt++] = swab16((u16)parsed); | ||
611 | } | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, | ||
617 | struct device_attribute *attr, | ||
618 | char *buf) | ||
619 | { | ||
620 | struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); | ||
621 | struct ssb_bus *bus; | ||
622 | u16 *sprom; | ||
623 | int err = -ENODEV; | ||
624 | ssize_t count = 0; | ||
625 | |||
626 | bus = ssb_pci_dev_to_bus(pdev); | ||
627 | if (!bus) | ||
628 | goto out; | ||
629 | err = -ENOMEM; | ||
630 | sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); | ||
631 | if (!sprom) | ||
632 | goto out; | ||
633 | |||
634 | /* Use interruptible locking, as the SPROM write might | ||
635 | * be holding the lock for several seconds. So allow userspace | ||
636 | * to cancel operation. */ | ||
637 | err = -ERESTARTSYS; | ||
638 | if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) | ||
639 | goto out_kfree; | ||
640 | sprom_do_read(bus, sprom); | ||
641 | mutex_unlock(&bus->pci_sprom_mutex); | ||
642 | |||
643 | count = sprom2hex(sprom, buf, PAGE_SIZE); | ||
644 | err = 0; | ||
645 | |||
646 | out_kfree: | ||
647 | kfree(sprom); | ||
648 | out: | ||
649 | return err ? err : count; | ||
650 | } | ||
651 | |||
652 | static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, | ||
653 | struct device_attribute *attr, | ||
654 | const char *buf, size_t count) | ||
655 | { | ||
656 | struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); | ||
657 | struct ssb_bus *bus; | ||
658 | u16 *sprom; | ||
659 | int res = 0, err = -ENODEV; | ||
660 | |||
661 | bus = ssb_pci_dev_to_bus(pdev); | ||
662 | if (!bus) | ||
663 | goto out; | ||
664 | err = -ENOMEM; | ||
665 | sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); | ||
666 | if (!sprom) | ||
667 | goto out; | ||
668 | err = hex2sprom(sprom, buf, count); | ||
669 | if (err) { | ||
670 | err = -EINVAL; | ||
671 | goto out_kfree; | ||
672 | } | ||
673 | err = sprom_check_crc(sprom); | ||
674 | if (err) { | ||
675 | err = -EINVAL; | ||
676 | goto out_kfree; | ||
677 | } | ||
678 | |||
679 | /* Use interruptible locking, as the SPROM write might | ||
680 | * be holding the lock for several seconds. So allow userspace | ||
681 | * to cancel operation. */ | ||
682 | err = -ERESTARTSYS; | ||
683 | if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) | ||
684 | goto out_kfree; | ||
685 | err = ssb_devices_freeze(bus); | ||
686 | if (err == -EOPNOTSUPP) { | ||
687 | ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. " | ||
688 | "No suspend support. Is CONFIG_PM enabled?\n"); | ||
689 | goto out_unlock; | ||
690 | } | ||
691 | if (err) { | ||
692 | ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); | ||
693 | goto out_unlock; | ||
694 | } | ||
695 | res = sprom_do_write(bus, sprom); | ||
696 | err = ssb_devices_thaw(bus); | ||
697 | if (err) | ||
698 | ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); | ||
699 | out_unlock: | ||
700 | mutex_unlock(&bus->pci_sprom_mutex); | ||
701 | out_kfree: | ||
702 | kfree(sprom); | ||
703 | out: | ||
704 | if (res) | ||
705 | return res; | ||
706 | return err ? err : count; | ||
707 | } | ||
708 | |||
709 | static DEVICE_ATTR(ssb_sprom, 0600, | ||
710 | ssb_pci_attr_sprom_show, | ||
711 | ssb_pci_attr_sprom_store); | ||
712 | |||
713 | void ssb_pci_exit(struct ssb_bus *bus) | ||
714 | { | ||
715 | struct pci_dev *pdev; | ||
716 | |||
717 | if (bus->bustype != SSB_BUSTYPE_PCI) | ||
718 | return; | ||
719 | |||
720 | pdev = bus->host_pci; | ||
721 | device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); | ||
722 | } | ||
723 | |||
724 | int ssb_pci_init(struct ssb_bus *bus) | ||
725 | { | ||
726 | struct pci_dev *pdev; | ||
727 | int err; | ||
728 | |||
729 | if (bus->bustype != SSB_BUSTYPE_PCI) | ||
730 | return 0; | ||
731 | |||
732 | pdev = bus->host_pci; | ||
733 | mutex_init(&bus->pci_sprom_mutex); | ||
734 | err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); | ||
735 | if (err) | ||
736 | goto out; | ||
737 | |||
738 | out: | ||
739 | return err; | ||
740 | } | ||
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c new file mode 100644 index 000000000000..82a10abef640 --- /dev/null +++ b/drivers/ssb/pcihost_wrapper.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * PCI Hostdevice wrapper | ||
4 | * | ||
5 | * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> | ||
6 | * Copyright (c) 2005 Stefano Brivio <st3@riseup.net> | ||
7 | * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> | ||
8 | * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> | ||
9 | * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de> | ||
10 | * | ||
11 | * Licensed under the GNU/GPL. See COPYING for details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/pci.h> | ||
15 | #include <linux/ssb/ssb.h> | ||
16 | |||
17 | |||
18 | #ifdef CONFIG_PM | ||
19 | static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) | ||
20 | { | ||
21 | pci_save_state(dev); | ||
22 | pci_disable_device(dev); | ||
23 | pci_set_power_state(dev, pci_choose_state(dev, state)); | ||
24 | |||
25 | return 0; | ||
26 | } | ||
27 | |||
28 | static int ssb_pcihost_resume(struct pci_dev *dev) | ||
29 | { | ||
30 | int err; | ||
31 | |||
32 | pci_set_power_state(dev, 0); | ||
33 | err = pci_enable_device(dev); | ||
34 | if (err) | ||
35 | return err; | ||
36 | pci_restore_state(dev); | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | #else /* CONFIG_PM */ | ||
41 | # define ssb_pcihost_suspend NULL | ||
42 | # define ssb_pcihost_resume NULL | ||
43 | #endif /* CONFIG_PM */ | ||
44 | |||
45 | static int ssb_pcihost_probe(struct pci_dev *dev, | ||
46 | const struct pci_device_id *id) | ||
47 | { | ||
48 | struct ssb_bus *ssb; | ||
49 | int err = -ENOMEM; | ||
50 | const char *name; | ||
51 | |||
52 | ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); | ||
53 | if (!ssb) | ||
54 | goto out; | ||
55 | err = pci_enable_device(dev); | ||
56 | if (err) | ||
57 | goto err_kfree_ssb; | ||
58 | name = dev->dev.bus_id; | ||
59 | if (dev->driver && dev->driver->name) | ||
60 | name = dev->driver->name; | ||
61 | err = pci_request_regions(dev, name); | ||
62 | if (err) | ||
63 | goto err_pci_disable; | ||
64 | pci_set_master(dev); | ||
65 | |||
66 | err = ssb_bus_pcibus_register(ssb, dev); | ||
67 | if (err) | ||
68 | goto err_pci_release_regions; | ||
69 | |||
70 | pci_set_drvdata(dev, ssb); | ||
71 | |||
72 | out: | ||
73 | return err; | ||
74 | |||
75 | err_pci_release_regions: | ||
76 | pci_release_regions(dev); | ||
77 | err_pci_disable: | ||
78 | pci_disable_device(dev); | ||
79 | err_kfree_ssb: | ||
80 | kfree(ssb); | ||
81 | return err; | ||
82 | } | ||
83 | |||
84 | static void ssb_pcihost_remove(struct pci_dev *dev) | ||
85 | { | ||
86 | struct ssb_bus *ssb = pci_get_drvdata(dev); | ||
87 | |||
88 | ssb_bus_unregister(ssb); | ||
89 | pci_release_regions(dev); | ||
90 | pci_disable_device(dev); | ||
91 | kfree(ssb); | ||
92 | pci_set_drvdata(dev, NULL); | ||
93 | } | ||
94 | |||
95 | int ssb_pcihost_register(struct pci_driver *driver) | ||
96 | { | ||
97 | driver->probe = ssb_pcihost_probe; | ||
98 | driver->remove = ssb_pcihost_remove; | ||
99 | driver->suspend = ssb_pcihost_suspend; | ||
100 | driver->resume = ssb_pcihost_resume; | ||
101 | |||
102 | return pci_register_driver(driver); | ||
103 | } | ||
104 | EXPORT_SYMBOL(ssb_pcihost_register); | ||
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c new file mode 100644 index 000000000000..7c773603b402 --- /dev/null +++ b/drivers/ssb/pcmcia.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * PCMCIA-Hostbus related functions | ||
4 | * | ||
5 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
6 | * Copyright 2007 Michael Buesch <mb@bu3sch.de> | ||
7 | * | ||
8 | * Licensed under the GNU/GPL. See COPYING for details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/ssb/ssb.h> | ||
12 | #include <linux/delay.h> | ||
13 | |||
14 | #include <pcmcia/cs_types.h> | ||
15 | #include <pcmcia/cs.h> | ||
16 | #include <pcmcia/cistpl.h> | ||
17 | #include <pcmcia/ciscode.h> | ||
18 | #include <pcmcia/ds.h> | ||
19 | #include <pcmcia/cisreg.h> | ||
20 | |||
21 | #include "ssb_private.h" | ||
22 | |||
23 | |||
24 | /* Define the following to 1 to enable a printk on each coreswitch. */ | ||
25 | #define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0 | ||
26 | |||
27 | |||
28 | int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, | ||
29 | u8 coreidx) | ||
30 | { | ||
31 | struct pcmcia_device *pdev = bus->host_pcmcia; | ||
32 | int err; | ||
33 | int attempts = 0; | ||
34 | u32 cur_core; | ||
35 | conf_reg_t reg; | ||
36 | u32 addr; | ||
37 | u32 read_addr; | ||
38 | |||
39 | addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; | ||
40 | while (1) { | ||
41 | reg.Action = CS_WRITE; | ||
42 | reg.Offset = 0x2E; | ||
43 | reg.Value = (addr & 0x0000F000) >> 12; | ||
44 | err = pcmcia_access_configuration_register(pdev, ®); | ||
45 | if (err != CS_SUCCESS) | ||
46 | goto error; | ||
47 | reg.Offset = 0x30; | ||
48 | reg.Value = (addr & 0x00FF0000) >> 16; | ||
49 | err = pcmcia_access_configuration_register(pdev, ®); | ||
50 | if (err != CS_SUCCESS) | ||
51 | goto error; | ||
52 | reg.Offset = 0x32; | ||
53 | reg.Value = (addr & 0xFF000000) >> 24; | ||
54 | err = pcmcia_access_configuration_register(pdev, ®); | ||
55 | if (err != CS_SUCCESS) | ||
56 | goto error; | ||
57 | |||
58 | read_addr = 0; | ||
59 | |||
60 | reg.Action = CS_READ; | ||
61 | reg.Offset = 0x2E; | ||
62 | err = pcmcia_access_configuration_register(pdev, ®); | ||
63 | if (err != CS_SUCCESS) | ||
64 | goto error; | ||
65 | read_addr |= (reg.Value & 0xF) << 12; | ||
66 | reg.Offset = 0x30; | ||
67 | err = pcmcia_access_configuration_register(pdev, ®); | ||
68 | if (err != CS_SUCCESS) | ||
69 | goto error; | ||
70 | read_addr |= reg.Value << 16; | ||
71 | reg.Offset = 0x32; | ||
72 | err = pcmcia_access_configuration_register(pdev, ®); | ||
73 | if (err != CS_SUCCESS) | ||
74 | goto error; | ||
75 | read_addr |= reg.Value << 24; | ||
76 | |||
77 | cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE; | ||
78 | if (cur_core == coreidx) | ||
79 | break; | ||
80 | |||
81 | if (attempts++ > SSB_BAR0_MAX_RETRIES) | ||
82 | goto error; | ||
83 | udelay(10); | ||
84 | } | ||
85 | |||
86 | return 0; | ||
87 | error: | ||
88 | ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx); | ||
89 | return -ENODEV; | ||
90 | } | ||
91 | |||
92 | int ssb_pcmcia_switch_core(struct ssb_bus *bus, | ||
93 | struct ssb_device *dev) | ||
94 | { | ||
95 | int err; | ||
96 | unsigned long flags; | ||
97 | |||
98 | #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG | ||
99 | ssb_printk(KERN_INFO PFX | ||
100 | "Switching to %s core, index %d\n", | ||
101 | ssb_core_name(dev->id.coreid), | ||
102 | dev->core_index); | ||
103 | #endif | ||
104 | |||
105 | spin_lock_irqsave(&bus->bar_lock, flags); | ||
106 | err = ssb_pcmcia_switch_coreidx(bus, dev->core_index); | ||
107 | if (!err) | ||
108 | bus->mapped_device = dev; | ||
109 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
110 | |||
111 | return err; | ||
112 | } | ||
113 | |||
114 | int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) | ||
115 | { | ||
116 | int attempts = 0; | ||
117 | unsigned long flags; | ||
118 | conf_reg_t reg; | ||
119 | int res, err = 0; | ||
120 | |||
121 | SSB_WARN_ON((seg != 0) && (seg != 1)); | ||
122 | reg.Offset = 0x34; | ||
123 | reg.Function = 0; | ||
124 | spin_lock_irqsave(&bus->bar_lock, flags); | ||
125 | while (1) { | ||
126 | reg.Action = CS_WRITE; | ||
127 | reg.Value = seg; | ||
128 | res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); | ||
129 | if (unlikely(res != CS_SUCCESS)) | ||
130 | goto error; | ||
131 | reg.Value = 0xFF; | ||
132 | reg.Action = CS_READ; | ||
133 | res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); | ||
134 | if (unlikely(res != CS_SUCCESS)) | ||
135 | goto error; | ||
136 | |||
137 | if (reg.Value == seg) | ||
138 | break; | ||
139 | |||
140 | if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES)) | ||
141 | goto error; | ||
142 | udelay(10); | ||
143 | } | ||
144 | bus->mapped_pcmcia_seg = seg; | ||
145 | out_unlock: | ||
146 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
147 | return err; | ||
148 | error: | ||
149 | ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n"); | ||
150 | err = -ENODEV; | ||
151 | goto out_unlock; | ||
152 | } | ||
153 | |||
154 | /* These are the main device register access functions. | ||
155 | * do_select_core is inline to have the likely hotpath inline. | ||
156 | * All unlikely codepaths are out-of-line. */ | ||
157 | static inline int do_select_core(struct ssb_bus *bus, | ||
158 | struct ssb_device *dev, | ||
159 | u16 *offset) | ||
160 | { | ||
161 | int err; | ||
162 | u8 need_seg = (*offset >= 0x800) ? 1 : 0; | ||
163 | |||
164 | if (unlikely(dev != bus->mapped_device)) { | ||
165 | err = ssb_pcmcia_switch_core(bus, dev); | ||
166 | if (unlikely(err)) | ||
167 | return err; | ||
168 | } | ||
169 | if (unlikely(need_seg != bus->mapped_pcmcia_seg)) { | ||
170 | err = ssb_pcmcia_switch_segment(bus, need_seg); | ||
171 | if (unlikely(err)) | ||
172 | return err; | ||
173 | } | ||
174 | if (need_seg == 1) | ||
175 | *offset -= 0x800; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) | ||
181 | { | ||
182 | struct ssb_bus *bus = dev->bus; | ||
183 | u16 x; | ||
184 | |||
185 | if (unlikely(do_select_core(bus, dev, &offset))) | ||
186 | return 0xFFFF; | ||
187 | x = readw(bus->mmio + offset); | ||
188 | |||
189 | return x; | ||
190 | } | ||
191 | |||
192 | static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) | ||
193 | { | ||
194 | struct ssb_bus *bus = dev->bus; | ||
195 | u32 x; | ||
196 | |||
197 | if (unlikely(do_select_core(bus, dev, &offset))) | ||
198 | return 0xFFFFFFFF; | ||
199 | x = readl(bus->mmio + offset); | ||
200 | |||
201 | return x; | ||
202 | } | ||
203 | |||
204 | static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) | ||
205 | { | ||
206 | struct ssb_bus *bus = dev->bus; | ||
207 | |||
208 | if (unlikely(do_select_core(bus, dev, &offset))) | ||
209 | return; | ||
210 | writew(value, bus->mmio + offset); | ||
211 | } | ||
212 | |||
213 | static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) | ||
214 | { | ||
215 | struct ssb_bus *bus = dev->bus; | ||
216 | |||
217 | if (unlikely(do_select_core(bus, dev, &offset))) | ||
218 | return; | ||
219 | readw(bus->mmio + offset); | ||
220 | writew(value >> 16, bus->mmio + offset + 2); | ||
221 | readw(bus->mmio + offset); | ||
222 | writew(value, bus->mmio + offset); | ||
223 | } | ||
224 | |||
225 | /* Not "static", as it's used in main.c */ | ||
226 | const struct ssb_bus_ops ssb_pcmcia_ops = { | ||
227 | .read16 = ssb_pcmcia_read16, | ||
228 | .read32 = ssb_pcmcia_read32, | ||
229 | .write16 = ssb_pcmcia_write16, | ||
230 | .write32 = ssb_pcmcia_write32, | ||
231 | }; | ||
232 | |||
233 | int ssb_pcmcia_get_invariants(struct ssb_bus *bus, | ||
234 | struct ssb_init_invariants *iv) | ||
235 | { | ||
236 | //TODO | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | int ssb_pcmcia_init(struct ssb_bus *bus) | ||
241 | { | ||
242 | conf_reg_t reg; | ||
243 | int err; | ||
244 | |||
245 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) | ||
246 | return 0; | ||
247 | |||
248 | /* Switch segment to a known state and sync | ||
249 | * bus->mapped_pcmcia_seg with hardware state. */ | ||
250 | ssb_pcmcia_switch_segment(bus, 0); | ||
251 | |||
252 | /* Init IRQ routing */ | ||
253 | reg.Action = CS_READ; | ||
254 | reg.Function = 0; | ||
255 | if (bus->chip_id == 0x4306) | ||
256 | reg.Offset = 0x00; | ||
257 | else | ||
258 | reg.Offset = 0x80; | ||
259 | err = pcmcia_access_configuration_register(bus->host_pcmcia, ®); | ||
260 | if (err != CS_SUCCESS) | ||
261 | goto error; | ||
262 | reg.Action = CS_WRITE; | ||
263 | reg.Value |= 0x04 | 0x01; | ||
264 | err = pcmcia_access_configuration_register(bus->host_pcmcia, ®); | ||
265 | if (err != CS_SUCCESS) | ||
266 | goto error; | ||
267 | |||
268 | return 0; | ||
269 | error: | ||
270 | return -ENODEV; | ||
271 | } | ||
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c new file mode 100644 index 000000000000..96258c60919d --- /dev/null +++ b/drivers/ssb/scan.c | |||
@@ -0,0 +1,413 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * Bus scanning | ||
4 | * | ||
5 | * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de> | ||
6 | * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> | ||
7 | * Copyright (C) 2005 Stefano Brivio <st3@riseup.net> | ||
8 | * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> | ||
9 | * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> | ||
10 | * Copyright (C) 2006 Broadcom Corporation. | ||
11 | * | ||
12 | * Licensed under the GNU/GPL. See COPYING for details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/ssb/ssb.h> | ||
16 | #include <linux/ssb/ssb_regs.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <linux/io.h> | ||
19 | |||
20 | #include <pcmcia/cs_types.h> | ||
21 | #include <pcmcia/cs.h> | ||
22 | #include <pcmcia/cistpl.h> | ||
23 | #include <pcmcia/ds.h> | ||
24 | |||
25 | #include "ssb_private.h" | ||
26 | |||
27 | |||
28 | const char *ssb_core_name(u16 coreid) | ||
29 | { | ||
30 | switch (coreid) { | ||
31 | case SSB_DEV_CHIPCOMMON: | ||
32 | return "ChipCommon"; | ||
33 | case SSB_DEV_ILINE20: | ||
34 | return "ILine 20"; | ||
35 | case SSB_DEV_SDRAM: | ||
36 | return "SDRAM"; | ||
37 | case SSB_DEV_PCI: | ||
38 | return "PCI"; | ||
39 | case SSB_DEV_MIPS: | ||
40 | return "MIPS"; | ||
41 | case SSB_DEV_ETHERNET: | ||
42 | return "Fast Ethernet"; | ||
43 | case SSB_DEV_V90: | ||
44 | return "V90"; | ||
45 | case SSB_DEV_USB11_HOSTDEV: | ||
46 | return "USB 1.1 Hostdev"; | ||
47 | case SSB_DEV_ADSL: | ||
48 | return "ADSL"; | ||
49 | case SSB_DEV_ILINE100: | ||
50 | return "ILine 100"; | ||
51 | case SSB_DEV_IPSEC: | ||
52 | return "IPSEC"; | ||
53 | case SSB_DEV_PCMCIA: | ||
54 | return "PCMCIA"; | ||
55 | case SSB_DEV_INTERNAL_MEM: | ||
56 | return "Internal Memory"; | ||
57 | case SSB_DEV_MEMC_SDRAM: | ||
58 | return "MEMC SDRAM"; | ||
59 | case SSB_DEV_EXTIF: | ||
60 | return "EXTIF"; | ||
61 | case SSB_DEV_80211: | ||
62 | return "IEEE 802.11"; | ||
63 | case SSB_DEV_MIPS_3302: | ||
64 | return "MIPS 3302"; | ||
65 | case SSB_DEV_USB11_HOST: | ||
66 | return "USB 1.1 Host"; | ||
67 | case SSB_DEV_USB11_DEV: | ||
68 | return "USB 1.1 Device"; | ||
69 | case SSB_DEV_USB20_HOST: | ||
70 | return "USB 2.0 Host"; | ||
71 | case SSB_DEV_USB20_DEV: | ||
72 | return "USB 2.0 Device"; | ||
73 | case SSB_DEV_SDIO_HOST: | ||
74 | return "SDIO Host"; | ||
75 | case SSB_DEV_ROBOSWITCH: | ||
76 | return "Roboswitch"; | ||
77 | case SSB_DEV_PARA_ATA: | ||
78 | return "PATA"; | ||
79 | case SSB_DEV_SATA_XORDMA: | ||
80 | return "SATA XOR-DMA"; | ||
81 | case SSB_DEV_ETHERNET_GBIT: | ||
82 | return "GBit Ethernet"; | ||
83 | case SSB_DEV_PCIE: | ||
84 | return "PCI-E"; | ||
85 | case SSB_DEV_MIMO_PHY: | ||
86 | return "MIMO PHY"; | ||
87 | case SSB_DEV_SRAM_CTRLR: | ||
88 | return "SRAM Controller"; | ||
89 | case SSB_DEV_MINI_MACPHY: | ||
90 | return "Mini MACPHY"; | ||
91 | case SSB_DEV_ARM_1176: | ||
92 | return "ARM 1176"; | ||
93 | case SSB_DEV_ARM_7TDMI: | ||
94 | return "ARM 7TDMI"; | ||
95 | } | ||
96 | return "UNKNOWN"; | ||
97 | } | ||
98 | |||
99 | static u16 pcidev_to_chipid(struct pci_dev *pci_dev) | ||
100 | { | ||
101 | u16 chipid_fallback = 0; | ||
102 | |||
103 | switch (pci_dev->device) { | ||
104 | case 0x4301: | ||
105 | chipid_fallback = 0x4301; | ||
106 | break; | ||
107 | case 0x4305 ... 0x4307: | ||
108 | chipid_fallback = 0x4307; | ||
109 | break; | ||
110 | case 0x4403: | ||
111 | chipid_fallback = 0x4402; | ||
112 | break; | ||
113 | case 0x4610 ... 0x4615: | ||
114 | chipid_fallback = 0x4610; | ||
115 | break; | ||
116 | case 0x4710 ... 0x4715: | ||
117 | chipid_fallback = 0x4710; | ||
118 | break; | ||
119 | case 0x4320 ... 0x4325: | ||
120 | chipid_fallback = 0x4309; | ||
121 | break; | ||
122 | case PCI_DEVICE_ID_BCM4401: | ||
123 | case PCI_DEVICE_ID_BCM4401B0: | ||
124 | case PCI_DEVICE_ID_BCM4401B1: | ||
125 | chipid_fallback = 0x4401; | ||
126 | break; | ||
127 | default: | ||
128 | ssb_printk(KERN_ERR PFX | ||
129 | "PCI-ID not in fallback list\n"); | ||
130 | } | ||
131 | |||
132 | return chipid_fallback; | ||
133 | } | ||
134 | |||
135 | static u8 chipid_to_nrcores(u16 chipid) | ||
136 | { | ||
137 | switch (chipid) { | ||
138 | case 0x5365: | ||
139 | return 7; | ||
140 | case 0x4306: | ||
141 | return 6; | ||
142 | case 0x4310: | ||
143 | return 8; | ||
144 | case 0x4307: | ||
145 | case 0x4301: | ||
146 | return 5; | ||
147 | case 0x4401: | ||
148 | case 0x4402: | ||
149 | return 3; | ||
150 | case 0x4710: | ||
151 | case 0x4610: | ||
152 | case 0x4704: | ||
153 | return 9; | ||
154 | default: | ||
155 | ssb_printk(KERN_ERR PFX | ||
156 | "CHIPID not in nrcores fallback list\n"); | ||
157 | } | ||
158 | |||
159 | return 1; | ||
160 | } | ||
161 | |||
162 | static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx, | ||
163 | u16 offset) | ||
164 | { | ||
165 | switch (bus->bustype) { | ||
166 | case SSB_BUSTYPE_SSB: | ||
167 | offset += current_coreidx * SSB_CORE_SIZE; | ||
168 | break; | ||
169 | case SSB_BUSTYPE_PCI: | ||
170 | break; | ||
171 | case SSB_BUSTYPE_PCMCIA: | ||
172 | if (offset >= 0x800) { | ||
173 | ssb_pcmcia_switch_segment(bus, 1); | ||
174 | offset -= 0x800; | ||
175 | } else | ||
176 | ssb_pcmcia_switch_segment(bus, 0); | ||
177 | break; | ||
178 | } | ||
179 | return readl(bus->mmio + offset); | ||
180 | } | ||
181 | |||
182 | static int scan_switchcore(struct ssb_bus *bus, u8 coreidx) | ||
183 | { | ||
184 | switch (bus->bustype) { | ||
185 | case SSB_BUSTYPE_SSB: | ||
186 | break; | ||
187 | case SSB_BUSTYPE_PCI: | ||
188 | return ssb_pci_switch_coreidx(bus, coreidx); | ||
189 | case SSB_BUSTYPE_PCMCIA: | ||
190 | return ssb_pcmcia_switch_coreidx(bus, coreidx); | ||
191 | } | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | void ssb_iounmap(struct ssb_bus *bus) | ||
196 | { | ||
197 | switch (bus->bustype) { | ||
198 | case SSB_BUSTYPE_SSB: | ||
199 | case SSB_BUSTYPE_PCMCIA: | ||
200 | iounmap(bus->mmio); | ||
201 | break; | ||
202 | case SSB_BUSTYPE_PCI: | ||
203 | #ifdef CONFIG_SSB_PCIHOST | ||
204 | pci_iounmap(bus->host_pci, bus->mmio); | ||
205 | #else | ||
206 | SSB_BUG_ON(1); /* Can't reach this code. */ | ||
207 | #endif | ||
208 | break; | ||
209 | } | ||
210 | bus->mmio = NULL; | ||
211 | bus->mapped_device = NULL; | ||
212 | } | ||
213 | |||
214 | static void __iomem *ssb_ioremap(struct ssb_bus *bus, | ||
215 | unsigned long baseaddr) | ||
216 | { | ||
217 | void __iomem *mmio = NULL; | ||
218 | |||
219 | switch (bus->bustype) { | ||
220 | case SSB_BUSTYPE_SSB: | ||
221 | /* Only map the first core for now. */ | ||
222 | /* fallthrough... */ | ||
223 | case SSB_BUSTYPE_PCMCIA: | ||
224 | mmio = ioremap(baseaddr, SSB_CORE_SIZE); | ||
225 | break; | ||
226 | case SSB_BUSTYPE_PCI: | ||
227 | #ifdef CONFIG_SSB_PCIHOST | ||
228 | mmio = pci_iomap(bus->host_pci, 0, ~0UL); | ||
229 | #else | ||
230 | SSB_BUG_ON(1); /* Can't reach this code. */ | ||
231 | #endif | ||
232 | break; | ||
233 | } | ||
234 | |||
235 | return mmio; | ||
236 | } | ||
237 | |||
238 | static int we_support_multiple_80211_cores(struct ssb_bus *bus) | ||
239 | { | ||
240 | /* More than one 802.11 core is only supported by special chips. | ||
241 | * There are chips with two 802.11 cores, but with dangling | ||
242 | * pins on the second core. Be careful and reject them here. | ||
243 | */ | ||
244 | |||
245 | #ifdef CONFIG_SSB_PCIHOST | ||
246 | if (bus->bustype == SSB_BUSTYPE_PCI) { | ||
247 | if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM && | ||
248 | bus->host_pci->device == 0x4324) | ||
249 | return 1; | ||
250 | } | ||
251 | #endif /* CONFIG_SSB_PCIHOST */ | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | int ssb_bus_scan(struct ssb_bus *bus, | ||
256 | unsigned long baseaddr) | ||
257 | { | ||
258 | int err = -ENOMEM; | ||
259 | void __iomem *mmio; | ||
260 | u32 idhi, cc, rev, tmp; | ||
261 | int dev_i, i; | ||
262 | struct ssb_device *dev; | ||
263 | int nr_80211_cores = 0; | ||
264 | |||
265 | mmio = ssb_ioremap(bus, baseaddr); | ||
266 | if (!mmio) | ||
267 | goto out; | ||
268 | bus->mmio = mmio; | ||
269 | |||
270 | err = scan_switchcore(bus, 0); /* Switch to first core */ | ||
271 | if (err) | ||
272 | goto err_unmap; | ||
273 | |||
274 | idhi = scan_read32(bus, 0, SSB_IDHIGH); | ||
275 | cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; | ||
276 | rev = (idhi & SSB_IDHIGH_RCLO); | ||
277 | rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT; | ||
278 | |||
279 | bus->nr_devices = 0; | ||
280 | if (cc == SSB_DEV_CHIPCOMMON) { | ||
281 | tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID); | ||
282 | |||
283 | bus->chip_id = (tmp & SSB_CHIPCO_IDMASK); | ||
284 | bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >> | ||
285 | SSB_CHIPCO_REVSHIFT; | ||
286 | bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >> | ||
287 | SSB_CHIPCO_PACKSHIFT; | ||
288 | if (rev >= 4) { | ||
289 | bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >> | ||
290 | SSB_CHIPCO_NRCORESSHIFT; | ||
291 | } | ||
292 | tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP); | ||
293 | bus->chipco.capabilities = tmp; | ||
294 | } else { | ||
295 | if (bus->bustype == SSB_BUSTYPE_PCI) { | ||
296 | bus->chip_id = pcidev_to_chipid(bus->host_pci); | ||
297 | pci_read_config_word(bus->host_pci, PCI_REVISION_ID, | ||
298 | &bus->chip_rev); | ||
299 | bus->chip_package = 0; | ||
300 | } else { | ||
301 | bus->chip_id = 0x4710; | ||
302 | bus->chip_rev = 0; | ||
303 | bus->chip_package = 0; | ||
304 | } | ||
305 | } | ||
306 | if (!bus->nr_devices) | ||
307 | bus->nr_devices = chipid_to_nrcores(bus->chip_id); | ||
308 | if (bus->nr_devices > ARRAY_SIZE(bus->devices)) { | ||
309 | ssb_printk(KERN_ERR PFX | ||
310 | "More than %d ssb cores found (%d)\n", | ||
311 | SSB_MAX_NR_CORES, bus->nr_devices); | ||
312 | goto err_unmap; | ||
313 | } | ||
314 | if (bus->bustype == SSB_BUSTYPE_SSB) { | ||
315 | /* Now that we know the number of cores, | ||
316 | * remap the whole IO space for all cores. | ||
317 | */ | ||
318 | err = -ENOMEM; | ||
319 | iounmap(mmio); | ||
320 | mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices); | ||
321 | if (!mmio) | ||
322 | goto out; | ||
323 | bus->mmio = mmio; | ||
324 | } | ||
325 | |||
326 | /* Fetch basic information about each core/device */ | ||
327 | for (i = 0, dev_i = 0; i < bus->nr_devices; i++) { | ||
328 | err = scan_switchcore(bus, i); | ||
329 | if (err) | ||
330 | goto err_unmap; | ||
331 | dev = &(bus->devices[dev_i]); | ||
332 | |||
333 | idhi = scan_read32(bus, i, SSB_IDHIGH); | ||
334 | dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; | ||
335 | dev->id.revision = (idhi & SSB_IDHIGH_RCLO); | ||
336 | dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT; | ||
337 | dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT; | ||
338 | dev->core_index = i; | ||
339 | dev->bus = bus; | ||
340 | dev->ops = bus->ops; | ||
341 | |||
342 | ssb_dprintk(KERN_INFO PFX | ||
343 | "Core %d found: %s " | ||
344 | "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n", | ||
345 | i, ssb_core_name(dev->id.coreid), | ||
346 | dev->id.coreid, dev->id.revision, dev->id.vendor); | ||
347 | |||
348 | switch (dev->id.coreid) { | ||
349 | case SSB_DEV_80211: | ||
350 | nr_80211_cores++; | ||
351 | if (nr_80211_cores > 1) { | ||
352 | if (!we_support_multiple_80211_cores(bus)) { | ||
353 | ssb_dprintk(KERN_INFO PFX "Ignoring additional " | ||
354 | "802.11 core\n"); | ||
355 | continue; | ||
356 | } | ||
357 | } | ||
358 | break; | ||
359 | case SSB_DEV_EXTIF: | ||
360 | #ifdef CONFIG_SSB_DRIVER_EXTIF | ||
361 | if (bus->extif.dev) { | ||
362 | ssb_printk(KERN_WARNING PFX | ||
363 | "WARNING: Multiple EXTIFs found\n"); | ||
364 | break; | ||
365 | } | ||
366 | bus->extif.dev = dev; | ||
367 | #endif /* CONFIG_SSB_DRIVER_EXTIF */ | ||
368 | break; | ||
369 | case SSB_DEV_CHIPCOMMON: | ||
370 | if (bus->chipco.dev) { | ||
371 | ssb_printk(KERN_WARNING PFX | ||
372 | "WARNING: Multiple ChipCommon found\n"); | ||
373 | break; | ||
374 | } | ||
375 | bus->chipco.dev = dev; | ||
376 | break; | ||
377 | case SSB_DEV_MIPS: | ||
378 | case SSB_DEV_MIPS_3302: | ||
379 | #ifdef CONFIG_SSB_DRIVER_MIPS | ||
380 | if (bus->mipscore.dev) { | ||
381 | ssb_printk(KERN_WARNING PFX | ||
382 | "WARNING: Multiple MIPS cores found\n"); | ||
383 | break; | ||
384 | } | ||
385 | bus->mipscore.dev = dev; | ||
386 | #endif /* CONFIG_SSB_DRIVER_MIPS */ | ||
387 | break; | ||
388 | case SSB_DEV_PCI: | ||
389 | case SSB_DEV_PCIE: | ||
390 | #ifdef CONFIG_SSB_DRIVER_PCICORE | ||
391 | if (bus->pcicore.dev) { | ||
392 | ssb_printk(KERN_WARNING PFX | ||
393 | "WARNING: Multiple PCI(E) cores found\n"); | ||
394 | break; | ||
395 | } | ||
396 | bus->pcicore.dev = dev; | ||
397 | #endif /* CONFIG_SSB_DRIVER_PCICORE */ | ||
398 | break; | ||
399 | default: | ||
400 | break; | ||
401 | } | ||
402 | |||
403 | dev_i++; | ||
404 | } | ||
405 | bus->nr_devices = dev_i; | ||
406 | |||
407 | err = 0; | ||
408 | out: | ||
409 | return err; | ||
410 | err_unmap: | ||
411 | ssb_iounmap(bus); | ||
412 | goto out; | ||
413 | } | ||
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h new file mode 100644 index 000000000000..a789364264a6 --- /dev/null +++ b/drivers/ssb/ssb_private.h | |||
@@ -0,0 +1,136 @@ | |||
1 | #ifndef LINUX_SSB_PRIVATE_H_ | ||
2 | #define LINUX_SSB_PRIVATE_H_ | ||
3 | |||
4 | #include <linux/ssb/ssb.h> | ||
5 | #include <linux/types.h> | ||
6 | |||
7 | |||
8 | #define PFX "ssb: " | ||
9 | |||
10 | #ifdef CONFIG_SSB_SILENT | ||
11 | # define ssb_printk(fmt, x...) do { /* nothing */ } while (0) | ||
12 | #else | ||
13 | # define ssb_printk printk | ||
14 | #endif /* CONFIG_SSB_SILENT */ | ||
15 | |||
16 | /* dprintk: Debugging printk; vanishes for non-debug compilation */ | ||
17 | #ifdef CONFIG_SSB_DEBUG | ||
18 | # define ssb_dprintk(fmt, x...) ssb_printk(fmt , ##x) | ||
19 | #else | ||
20 | # define ssb_dprintk(fmt, x...) do { /* nothing */ } while (0) | ||
21 | #endif | ||
22 | |||
23 | #ifdef CONFIG_SSB_DEBUG | ||
24 | # define SSB_WARN_ON(x) WARN_ON(x) | ||
25 | # define SSB_BUG_ON(x) BUG_ON(x) | ||
26 | #else | ||
27 | static inline int __ssb_do_nothing(int x) { return x; } | ||
28 | # define SSB_WARN_ON(x) __ssb_do_nothing(unlikely(!!(x))) | ||
29 | # define SSB_BUG_ON(x) __ssb_do_nothing(unlikely(!!(x))) | ||
30 | #endif | ||
31 | |||
32 | |||
33 | /* pci.c */ | ||
34 | #ifdef CONFIG_SSB_PCIHOST | ||
35 | extern int ssb_pci_switch_core(struct ssb_bus *bus, | ||
36 | struct ssb_device *dev); | ||
37 | extern int ssb_pci_switch_coreidx(struct ssb_bus *bus, | ||
38 | u8 coreidx); | ||
39 | extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what, | ||
40 | int turn_on); | ||
41 | extern int ssb_pci_get_invariants(struct ssb_bus *bus, | ||
42 | struct ssb_init_invariants *iv); | ||
43 | extern void ssb_pci_exit(struct ssb_bus *bus); | ||
44 | extern int ssb_pci_init(struct ssb_bus *bus); | ||
45 | extern const struct ssb_bus_ops ssb_pci_ops; | ||
46 | |||
47 | #else /* CONFIG_SSB_PCIHOST */ | ||
48 | |||
49 | static inline int ssb_pci_switch_core(struct ssb_bus *bus, | ||
50 | struct ssb_device *dev) | ||
51 | { | ||
52 | return 0; | ||
53 | } | ||
54 | static inline int ssb_pci_switch_coreidx(struct ssb_bus *bus, | ||
55 | u8 coreidx) | ||
56 | { | ||
57 | return 0; | ||
58 | } | ||
59 | static inline int ssb_pci_xtal(struct ssb_bus *bus, u32 what, | ||
60 | int turn_on) | ||
61 | { | ||
62 | return 0; | ||
63 | } | ||
64 | static inline void ssb_pci_exit(struct ssb_bus *bus) | ||
65 | { | ||
66 | } | ||
67 | static inline int ssb_pci_init(struct ssb_bus *bus) | ||
68 | { | ||
69 | return 0; | ||
70 | } | ||
71 | #endif /* CONFIG_SSB_PCIHOST */ | ||
72 | |||
73 | |||
74 | /* pcmcia.c */ | ||
75 | #ifdef CONFIG_SSB_PCMCIAHOST | ||
76 | extern int ssb_pcmcia_switch_core(struct ssb_bus *bus, | ||
77 | struct ssb_device *dev); | ||
78 | extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, | ||
79 | u8 coreidx); | ||
80 | extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus, | ||
81 | u8 seg); | ||
82 | extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, | ||
83 | struct ssb_init_invariants *iv); | ||
84 | extern int ssb_pcmcia_init(struct ssb_bus *bus); | ||
85 | extern const struct ssb_bus_ops ssb_pcmcia_ops; | ||
86 | #else /* CONFIG_SSB_PCMCIAHOST */ | ||
87 | static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus, | ||
88 | struct ssb_device *dev) | ||
89 | { | ||
90 | return 0; | ||
91 | } | ||
92 | static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, | ||
93 | u8 coreidx) | ||
94 | { | ||
95 | return 0; | ||
96 | } | ||
97 | static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus, | ||
98 | u8 seg) | ||
99 | { | ||
100 | return 0; | ||
101 | } | ||
102 | static inline int ssb_pcmcia_init(struct ssb_bus *bus) | ||
103 | { | ||
104 | return 0; | ||
105 | } | ||
106 | #endif /* CONFIG_SSB_PCMCIAHOST */ | ||
107 | |||
108 | |||
109 | /* scan.c */ | ||
110 | extern const char *ssb_core_name(u16 coreid); | ||
111 | extern int ssb_bus_scan(struct ssb_bus *bus, | ||
112 | unsigned long baseaddr); | ||
113 | extern void ssb_iounmap(struct ssb_bus *ssb); | ||
114 | |||
115 | |||
116 | /* core.c */ | ||
117 | extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); | ||
118 | extern int ssb_devices_freeze(struct ssb_bus *bus); | ||
119 | extern int ssb_devices_thaw(struct ssb_bus *bus); | ||
120 | extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); | ||
121 | |||
122 | /* b43_pci_bridge.c */ | ||
123 | #ifdef CONFIG_SSB_PCIHOST | ||
124 | extern int __init b43_pci_ssb_bridge_init(void); | ||
125 | extern void __exit b43_pci_ssb_bridge_exit(void); | ||
126 | #else /* CONFIG_SSB_PCIHOST */ | ||
127 | static inline int b43_pci_ssb_bridge_init(void) | ||
128 | { | ||
129 | return 0; | ||
130 | } | ||
131 | static inline void b43_pci_ssb_bridge_exit(void) | ||
132 | { | ||
133 | } | ||
134 | #endif /* CONFIG_SSB_PCIHOST */ | ||
135 | |||
136 | #endif /* LINUX_SSB_PRIVATE_H_ */ | ||