diff options
| author | Hauke Mehrtens <hauke@hauke-m.de> | 2012-02-27 18:56:10 -0500 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2012-03-05 15:20:50 -0500 |
| commit | a027237a56f7d519eee5749cfb720e568d0bb0b6 (patch) | |
| tree | 0d408171f47086b66330a844701747d8aa0e37fc | |
| parent | 1c9351cf2180924c91bb85e5ba607f24a3d875b1 (diff) | |
bcma: add support for sprom not found on the device
On SoCs the sprom is stored in the nvram in a special partition on the
flash chip. The nvram contains the sprom for the main bus, but
sometimes also for a pci devices using bcma. This patch makes it
possible for the arch code to register a function to fetch the needed
sprom from the nvram and provide it to the bcma code.
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | drivers/bcma/sprom.c | 77 | ||||
| -rw-r--r-- | include/linux/bcma/bcma.h | 6 |
2 files changed, 75 insertions, 8 deletions
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index ca7752510d5b..916ae255ff64 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | * Broadcom specific AMBA | 2 | * Broadcom specific AMBA |
| 3 | * SPROM reading | 3 | * SPROM reading |
| 4 | * | 4 | * |
| 5 | * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de> | ||
| 6 | * | ||
| 5 | * Licensed under the GNU/GPL. See COPYING for details. | 7 | * Licensed under the GNU/GPL. See COPYING for details. |
| 6 | */ | 8 | */ |
| 7 | 9 | ||
| @@ -14,6 +16,45 @@ | |||
| 14 | #include <linux/dma-mapping.h> | 16 | #include <linux/dma-mapping.h> |
| 15 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 16 | 18 | ||
| 19 | static int(*get_fallback_sprom)(struct bcma_bus *dev, struct ssb_sprom *out); | ||
| 20 | |||
| 21 | /** | ||
| 22 | * bcma_arch_register_fallback_sprom - Registers a method providing a | ||
| 23 | * fallback SPROM if no SPROM is found. | ||
| 24 | * | ||
| 25 | * @sprom_callback: The callback function. | ||
| 26 | * | ||
| 27 | * With this function the architecture implementation may register a | ||
| 28 | * callback handler which fills the SPROM data structure. The fallback is | ||
| 29 | * used for PCI based BCMA devices, where no valid SPROM can be found | ||
| 30 | * in the shadow registers and to provide the SPROM for SoCs where BCMA is | ||
| 31 | * to controll the system bus. | ||
| 32 | * | ||
| 33 | * This function is useful for weird architectures that have a half-assed | ||
| 34 | * BCMA device hardwired to their PCI bus. | ||
| 35 | * | ||
| 36 | * This function is available for architecture code, only. So it is not | ||
| 37 | * exported. | ||
| 38 | */ | ||
| 39 | int bcma_arch_register_fallback_sprom(int (*sprom_callback)(struct bcma_bus *bus, | ||
| 40 | struct ssb_sprom *out)) | ||
| 41 | { | ||
| 42 | if (get_fallback_sprom) | ||
| 43 | return -EEXIST; | ||
| 44 | get_fallback_sprom = sprom_callback; | ||
| 45 | |||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus, | ||
| 50 | struct ssb_sprom *out) | ||
| 51 | { | ||
| 52 | if (!get_fallback_sprom) | ||
| 53 | return -ENOENT; | ||
| 54 | |||
| 55 | return get_fallback_sprom(bus, out); | ||
| 56 | } | ||
| 57 | |||
| 17 | /************************************************** | 58 | /************************************************** |
| 18 | * R/W ops. | 59 | * R/W ops. |
| 19 | **************************************************/ | 60 | **************************************************/ |
| @@ -246,23 +287,43 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) | |||
| 246 | SSB_SROM8_FEM_ANTSWLUT_SHIFT); | 287 | SSB_SROM8_FEM_ANTSWLUT_SHIFT); |
| 247 | } | 288 | } |
| 248 | 289 | ||
| 290 | static bool bcma_is_sprom_available(struct bcma_bus *bus) | ||
| 291 | { | ||
| 292 | u32 sromctrl; | ||
| 293 | |||
| 294 | if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM)) | ||
| 295 | return false; | ||
| 296 | |||
| 297 | if (bus->drv_cc.core->id.rev >= 32) { | ||
| 298 | sromctrl = bcma_read32(bus->drv_cc.core, BCMA_CC_SROM_CONTROL); | ||
| 299 | return sromctrl & BCMA_CC_SROM_CONTROL_PRESENT; | ||
| 300 | } | ||
| 301 | return true; | ||
| 302 | } | ||
| 303 | |||
| 249 | int bcma_sprom_get(struct bcma_bus *bus) | 304 | int bcma_sprom_get(struct bcma_bus *bus) |
| 250 | { | 305 | { |
| 251 | u16 offset; | 306 | u16 offset; |
| 252 | u16 *sprom; | 307 | u16 *sprom; |
| 253 | u32 sromctrl; | ||
| 254 | int err = 0; | 308 | int err = 0; |
| 255 | 309 | ||
| 256 | if (!bus->drv_cc.core) | 310 | if (!bus->drv_cc.core) |
| 257 | return -EOPNOTSUPP; | 311 | return -EOPNOTSUPP; |
| 258 | 312 | ||
| 259 | if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM)) | 313 | if (!bcma_is_sprom_available(bus)) { |
| 260 | return -ENOENT; | 314 | /* |
| 261 | 315 | * Maybe there is no SPROM on the device? | |
| 262 | if (bus->drv_cc.core->id.rev >= 32) { | 316 | * Now we ask the arch code if there is some sprom |
| 263 | sromctrl = bcma_read32(bus->drv_cc.core, BCMA_CC_SROM_CONTROL); | 317 | * available for this device in some other storage. |
| 264 | if (!(sromctrl & BCMA_CC_SROM_CONTROL_PRESENT)) | 318 | */ |
| 265 | return -ENOENT; | 319 | err = bcma_fill_sprom_with_fallback(bus, &bus->sprom); |
| 320 | if (err) { | ||
| 321 | pr_warn("Using fallback SPROM failed (err %d)\n", err); | ||
| 322 | } else { | ||
| 323 | pr_debug("Using SPROM revision %d provided by" | ||
| 324 | " platform.\n", bus->sprom.revision); | ||
| 325 | return 0; | ||
| 326 | } | ||
| 266 | } | 327 | } |
| 267 | 328 | ||
| 268 | sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), | 329 | sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), |
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 46bbd088c4ad..5af9a075498f 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h | |||
| @@ -176,6 +176,12 @@ int __bcma_driver_register(struct bcma_driver *drv, struct module *owner); | |||
| 176 | 176 | ||
| 177 | extern void bcma_driver_unregister(struct bcma_driver *drv); | 177 | extern void bcma_driver_unregister(struct bcma_driver *drv); |
| 178 | 178 | ||
| 179 | /* Set a fallback SPROM. | ||
| 180 | * See kdoc at the function definition for complete documentation. */ | ||
| 181 | extern int bcma_arch_register_fallback_sprom( | ||
| 182 | int (*sprom_callback)(struct bcma_bus *bus, | ||
| 183 | struct ssb_sprom *out)); | ||
| 184 | |||
| 179 | struct bcma_bus { | 185 | struct bcma_bus { |
| 180 | /* The MMIO area. */ | 186 | /* The MMIO area. */ |
| 181 | void __iomem *mmio; | 187 | void __iomem *mmio; |
