linux/drivers/bcma/main.c
<<
>>
Prefs
   1/*
   2 * Broadcom specific AMBA
   3 * Bus subsystem
   4 *
   5 * Licensed under the GNU/GPL. See COPYING for details.
   6 */
   7
   8#include "bcma_private.h"
   9#include <linux/module.h>
  10#include <linux/platform_device.h>
  11#include <linux/bcma/bcma.h>
  12#include <linux/slab.h>
  13
  14MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
  15MODULE_LICENSE("GPL");
  16
  17/* contains the number the next bus should get. */
  18static unsigned int bcma_bus_next_num = 0;
  19
  20/* bcma_buses_mutex locks the bcma_bus_next_num */
  21static DEFINE_MUTEX(bcma_buses_mutex);
  22
  23static int bcma_bus_match(struct device *dev, struct device_driver *drv);
  24static int bcma_device_probe(struct device *dev);
  25static int bcma_device_remove(struct device *dev);
  26static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
  27
  28static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
  29{
  30        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  31        return sprintf(buf, "0x%03X\n", core->id.manuf);
  32}
  33static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
  34{
  35        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  36        return sprintf(buf, "0x%03X\n", core->id.id);
  37}
  38static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf)
  39{
  40        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  41        return sprintf(buf, "0x%02X\n", core->id.rev);
  42}
  43static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf)
  44{
  45        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  46        return sprintf(buf, "0x%X\n", core->id.class);
  47}
  48static struct device_attribute bcma_device_attrs[] = {
  49        __ATTR_RO(manuf),
  50        __ATTR_RO(id),
  51        __ATTR_RO(rev),
  52        __ATTR_RO(class),
  53        __ATTR_NULL,
  54};
  55
  56static struct bus_type bcma_bus_type = {
  57        .name           = "bcma",
  58        .match          = bcma_bus_match,
  59        .probe          = bcma_device_probe,
  60        .remove         = bcma_device_remove,
  61        .uevent         = bcma_device_uevent,
  62        .dev_attrs      = bcma_device_attrs,
  63};
  64
  65static u16 bcma_cc_core_id(struct bcma_bus *bus)
  66{
  67        if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
  68                return BCMA_CORE_4706_CHIPCOMMON;
  69        return BCMA_CORE_CHIPCOMMON;
  70}
  71
  72struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
  73{
  74        struct bcma_device *core;
  75
  76        list_for_each_entry(core, &bus->cores, list) {
  77                if (core->id.id == coreid)
  78                        return core;
  79        }
  80        return NULL;
  81}
  82EXPORT_SYMBOL_GPL(bcma_find_core);
  83
  84static void bcma_release_core_dev(struct device *dev)
  85{
  86        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  87        if (core->io_addr)
  88                iounmap(core->io_addr);
  89        if (core->io_wrap)
  90                iounmap(core->io_wrap);
  91        kfree(core);
  92}
  93
  94static int bcma_register_cores(struct bcma_bus *bus)
  95{
  96        struct bcma_device *core;
  97        int err, dev_id = 0;
  98
  99        list_for_each_entry(core, &bus->cores, list) {
 100                /* We support that cores ourself */
 101                switch (core->id.id) {
 102                case BCMA_CORE_4706_CHIPCOMMON:
 103                case BCMA_CORE_CHIPCOMMON:
 104                case BCMA_CORE_PCI:
 105                case BCMA_CORE_PCIE:
 106                case BCMA_CORE_MIPS_74K:
 107                case BCMA_CORE_4706_MAC_GBIT_COMMON:
 108                        continue;
 109                }
 110
 111                core->dev.release = bcma_release_core_dev;
 112                core->dev.bus = &bcma_bus_type;
 113                dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
 114
 115                switch (bus->hosttype) {
 116                case BCMA_HOSTTYPE_PCI:
 117                        core->dev.parent = &bus->host_pci->dev;
 118                        core->dma_dev = &bus->host_pci->dev;
 119                        core->irq = bus->host_pci->irq;
 120                        break;
 121                case BCMA_HOSTTYPE_SOC:
 122                        core->dev.dma_mask = &core->dev.coherent_dma_mask;
 123                        core->dma_dev = &core->dev;
 124                        break;
 125                case BCMA_HOSTTYPE_SDIO:
 126                        break;
 127                }
 128
 129                err = device_register(&core->dev);
 130                if (err) {
 131                        bcma_err(bus,
 132                                 "Could not register dev for core 0x%03X\n",
 133                                 core->id.id);
 134                        continue;
 135                }
 136                core->dev_registered = true;
 137                dev_id++;
 138        }
 139
 140#ifdef CONFIG_BCMA_SFLASH
 141        if (bus->drv_cc.sflash.present) {
 142                err = platform_device_register(&bcma_sflash_dev);
 143                if (err)
 144                        bcma_err(bus, "Error registering serial flash\n");
 145        }
 146#endif
 147
 148#ifdef CONFIG_BCMA_NFLASH
 149        if (bus->drv_cc.nflash.present) {
 150                err = platform_device_register(&bcma_nflash_dev);
 151                if (err)
 152                        bcma_err(bus, "Error registering NAND flash\n");
 153        }
 154#endif
 155
 156        return 0;
 157}
 158
 159static void bcma_unregister_cores(struct bcma_bus *bus)
 160{
 161        struct bcma_device *core, *tmp;
 162
 163        list_for_each_entry_safe(core, tmp, &bus->cores, list) {
 164                list_del(&core->list);
 165                if (core->dev_registered)
 166                        device_unregister(&core->dev);
 167        }
 168}
 169
 170int __devinit bcma_bus_register(struct bcma_bus *bus)
 171{
 172        int err;
 173        struct bcma_device *core;
 174
 175        mutex_lock(&bcma_buses_mutex);
 176        bus->num = bcma_bus_next_num++;
 177        mutex_unlock(&bcma_buses_mutex);
 178
 179        /* Scan for devices (cores) */
 180        err = bcma_bus_scan(bus);
 181        if (err) {
 182                bcma_err(bus, "Failed to scan: %d\n", err);
 183                return -1;
 184        }
 185
 186        /* Init CC core */
 187        core = bcma_find_core(bus, bcma_cc_core_id(bus));
 188        if (core) {
 189                bus->drv_cc.core = core;
 190                bcma_core_chipcommon_init(&bus->drv_cc);
 191        }
 192
 193        /* Init MIPS core */
 194        core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 195        if (core) {
 196                bus->drv_mips.core = core;
 197                bcma_core_mips_init(&bus->drv_mips);
 198        }
 199
 200        /* Init PCIE core */
 201        core = bcma_find_core(bus, BCMA_CORE_PCIE);
 202        if (core) {
 203                bus->drv_pci.core = core;
 204                bcma_core_pci_init(&bus->drv_pci);
 205        }
 206
 207        /* Init GBIT MAC COMMON core */
 208        core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
 209        if (core) {
 210                bus->drv_gmac_cmn.core = core;
 211                bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
 212        }
 213
 214        /* Try to get SPROM */
 215        err = bcma_sprom_get(bus);
 216        if (err == -ENOENT) {
 217                bcma_err(bus, "No SPROM available\n");
 218        } else if (err)
 219                bcma_err(bus, "Failed to get SPROM: %d\n", err);
 220
 221        /* Register found cores */
 222        bcma_register_cores(bus);
 223
 224        bcma_info(bus, "Bus registered\n");
 225
 226        return 0;
 227}
 228
 229void bcma_bus_unregister(struct bcma_bus *bus)
 230{
 231        struct bcma_device *cores[3];
 232
 233        cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 234        cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
 235        cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
 236
 237        bcma_unregister_cores(bus);
 238
 239        kfree(cores[2]);
 240        kfree(cores[1]);
 241        kfree(cores[0]);
 242}
 243
 244int __init bcma_bus_early_register(struct bcma_bus *bus,
 245                                   struct bcma_device *core_cc,
 246                                   struct bcma_device *core_mips)
 247{
 248        int err;
 249        struct bcma_device *core;
 250        struct bcma_device_id match;
 251
 252        bcma_init_bus(bus);
 253
 254        match.manuf = BCMA_MANUF_BCM;
 255        match.id = bcma_cc_core_id(bus);
 256        match.class = BCMA_CL_SIM;
 257        match.rev = BCMA_ANY_REV;
 258
 259        /* Scan for chip common core */
 260        err = bcma_bus_scan_early(bus, &match, core_cc);
 261        if (err) {
 262                bcma_err(bus, "Failed to scan for common core: %d\n", err);
 263                return -1;
 264        }
 265
 266        match.manuf = BCMA_MANUF_MIPS;
 267        match.id = BCMA_CORE_MIPS_74K;
 268        match.class = BCMA_CL_SIM;
 269        match.rev = BCMA_ANY_REV;
 270
 271        /* Scan for mips core */
 272        err = bcma_bus_scan_early(bus, &match, core_mips);
 273        if (err) {
 274                bcma_err(bus, "Failed to scan for mips core: %d\n", err);
 275                return -1;
 276        }
 277
 278        /* Init CC core */
 279        core = bcma_find_core(bus, bcma_cc_core_id(bus));
 280        if (core) {
 281                bus->drv_cc.core = core;
 282                bcma_core_chipcommon_init(&bus->drv_cc);
 283        }
 284
 285        /* Init MIPS core */
 286        core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 287        if (core) {
 288                bus->drv_mips.core = core;
 289                bcma_core_mips_init(&bus->drv_mips);
 290        }
 291
 292        bcma_info(bus, "Early bus registered\n");
 293
 294        return 0;
 295}
 296
 297#ifdef CONFIG_PM
 298int bcma_bus_suspend(struct bcma_bus *bus)
 299{
 300        struct bcma_device *core;
 301
 302        list_for_each_entry(core, &bus->cores, list) {
 303                struct device_driver *drv = core->dev.driver;
 304                if (drv) {
 305                        struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
 306                        if (adrv->suspend)
 307                                adrv->suspend(core);
 308                }
 309        }
 310        return 0;
 311}
 312
 313int bcma_bus_resume(struct bcma_bus *bus)
 314{
 315        struct bcma_device *core;
 316
 317        /* Init CC core */
 318        if (bus->drv_cc.core) {
 319                bus->drv_cc.setup_done = false;
 320                bcma_core_chipcommon_init(&bus->drv_cc);
 321        }
 322
 323        list_for_each_entry(core, &bus->cores, list) {
 324                struct device_driver *drv = core->dev.driver;
 325                if (drv) {
 326                        struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
 327                        if (adrv->resume)
 328                                adrv->resume(core);
 329                }
 330        }
 331
 332        return 0;
 333}
 334#endif
 335
 336int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 337{
 338        drv->drv.name = drv->name;
 339        drv->drv.bus = &bcma_bus_type;
 340        drv->drv.owner = owner;
 341
 342        return driver_register(&drv->drv);
 343}
 344EXPORT_SYMBOL_GPL(__bcma_driver_register);
 345
 346void bcma_driver_unregister(struct bcma_driver *drv)
 347{
 348        driver_unregister(&drv->drv);
 349}
 350EXPORT_SYMBOL_GPL(bcma_driver_unregister);
 351
 352static int bcma_bus_match(struct device *dev, struct device_driver *drv)
 353{
 354        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 355        struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
 356        const struct bcma_device_id *cid = &core->id;
 357        const struct bcma_device_id *did;
 358
 359        for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) {
 360            if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) &&
 361                (did->id == cid->id || did->id == BCMA_ANY_ID) &&
 362                (did->rev == cid->rev || did->rev == BCMA_ANY_REV) &&
 363                (did->class == cid->class || did->class == BCMA_ANY_CLASS))
 364                        return 1;
 365        }
 366        return 0;
 367}
 368
 369static int bcma_device_probe(struct device *dev)
 370{
 371        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 372        struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
 373                                               drv);
 374        int err = 0;
 375
 376        if (adrv->probe)
 377                err = adrv->probe(core);
 378
 379        return err;
 380}
 381
 382static int bcma_device_remove(struct device *dev)
 383{
 384        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 385        struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
 386                                               drv);
 387
 388        if (adrv->remove)
 389                adrv->remove(core);
 390
 391        return 0;
 392}
 393
 394static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 395{
 396        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 397
 398        return add_uevent_var(env,
 399                              "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
 400                              core->id.manuf, core->id.id,
 401                              core->id.rev, core->id.class);
 402}
 403
 404static int __init bcma_modinit(void)
 405{
 406        int err;
 407
 408        err = bus_register(&bcma_bus_type);
 409        if (err)
 410                return err;
 411
 412#ifdef CONFIG_BCMA_HOST_PCI
 413        err = bcma_host_pci_init();
 414        if (err) {
 415                pr_err("PCI host initialization failed\n");
 416                err = 0;
 417        }
 418#endif
 419
 420        return err;
 421}
 422fs_initcall(bcma_modinit);
 423
 424static void __exit bcma_modexit(void)
 425{
 426#ifdef CONFIG_BCMA_HOST_PCI
 427        bcma_host_pci_exit();
 428#endif
 429        bus_unregister(&bcma_bus_type);
 430}
 431module_exit(bcma_modexit)
 432
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.