diff options
Diffstat (limited to 'drivers/bcma/main.c')
| -rw-r--r-- | drivers/bcma/main.c | 208 |
1 files changed, 170 insertions, 38 deletions
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index ec31f7dd554..34ea4c588d3 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -7,12 +7,19 @@ #include "bcma_private.h" #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/bcma/bcma.h> #include <linux/slab.h> MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); MODULE_LICENSE("GPL"); +/* contains the number the next bus should get. */ +static unsigned int bcma_bus_next_num = 0; + +/* bcma_buses_mutex locks the bcma_bus_next_num */ +static DEFINE_MUTEX(bcma_buses_mutex); + static int bcma_bus_match(struct device *dev, struct device_driver *drv); static int bcma_device_probe(struct device *dev); static int bcma_device_remove(struct device *dev); @@ -23,28 +30,37 @@ static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, cha struct bcma_device *core = container_of(dev, struct bcma_device, dev); return sprintf(buf, "0x%03X\n", core->id.manuf); } +static DEVICE_ATTR_RO(manuf); + static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bcma_device *core = container_of(dev, struct bcma_device, dev); return sprintf(buf, "0x%03X\n", core->id.id); } +static DEVICE_ATTR_RO(id); + static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bcma_device *core = container_of(dev, struct bcma_device, dev); return sprintf(buf, "0x%02X\n", core->id.rev); } +static DEVICE_ATTR_RO(rev); + static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bcma_device *core = container_of(dev, struct bcma_device, dev); return sprintf(buf, "0x%X\n", core->id.class); } -static struct device_attribute bcma_device_attrs[] = { - __ATTR_RO(manuf), - __ATTR_RO(id), - __ATTR_RO(rev), - __ATTR_RO(class), - __ATTR_NULL, +static DEVICE_ATTR_RO(class); + +static struct attribute *bcma_device_attrs[] = { + &dev_attr_manuf.attr, + &dev_attr_id.attr, + &dev_attr_rev.attr, + &dev_attr_class.attr, + NULL, }; +ATTRIBUTE_GROUPS(bcma_device); static struct bus_type bcma_bus_type = { .name = "bcma", @@ -52,19 +68,47 @@ static struct bus_type bcma_bus_type = { .probe = bcma_device_probe, .remove = bcma_device_remove, .uevent = bcma_device_uevent, - .dev_attrs = bcma_device_attrs, + .dev_groups = bcma_device_groups, }; -static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) +static u16 bcma_cc_core_id(struct bcma_bus *bus) +{ + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) + return BCMA_CORE_4706_CHIPCOMMON; + return BCMA_CORE_CHIPCOMMON; +} + +struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid, + u8 unit) { struct bcma_device *core; list_for_each_entry(core, &bus->cores, list) { - if (core->id.id == coreid) + if (core->id.id == coreid && core->core_unit == unit) return core; } return NULL; } +EXPORT_SYMBOL_GPL(bcma_find_core_unit); + +bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value, + int timeout) +{ + unsigned long deadline = jiffies + timeout; + u32 val; + + do { + val = bcma_read32(core, reg); + if ((val & mask) == value) + return true; + cpu_relax(); + udelay(10); + } while (!time_after_eq(jiffies, deadline)); + + bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg); + + return false; +} static void bcma_release_core_dev(struct device *dev) { @@ -84,16 +128,23 @@ static int bcma_register_cores(struct bcma_bus *bus) list_for_each_entry(core, &bus->cores, list) { /* We support that cores ourself */ switch (core->id.id) { + case BCMA_CORE_4706_CHIPCOMMON: case BCMA_CORE_CHIPCOMMON: case BCMA_CORE_PCI: case BCMA_CORE_PCIE: case BCMA_CORE_MIPS_74K: + case BCMA_CORE_4706_MAC_GBIT_COMMON: continue; } + /* Only first GMAC core on BCM4706 is connected and working */ + if (core->id.id == BCMA_CORE_4706_MAC_GBIT && + core->core_unit > 0) + continue; + core->dev.release = bcma_release_core_dev; core->dev.bus = &bcma_bus_type; - dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id); + dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id); switch (bus->hosttype) { case BCMA_HOSTTYPE_PCI: @@ -111,25 +162,65 @@ static int bcma_register_cores(struct bcma_bus *bus) err = device_register(&core->dev); if (err) { - pr_err("Could not register dev for core 0x%03X\n", - core->id.id); + bcma_err(bus, + "Could not register dev for core 0x%03X\n", + core->id.id); + put_device(&core->dev); continue; } core->dev_registered = true; dev_id++; } +#ifdef CONFIG_BCMA_DRIVER_MIPS + if (bus->drv_cc.pflash.present) { + err = platform_device_register(&bcma_pflash_dev); + if (err) + bcma_err(bus, "Error registering parallel flash\n"); + } +#endif + +#ifdef CONFIG_BCMA_SFLASH + if (bus->drv_cc.sflash.present) { + err = platform_device_register(&bcma_sflash_dev); + if (err) + bcma_err(bus, "Error registering serial flash\n"); + } +#endif + +#ifdef CONFIG_BCMA_NFLASH + if (bus->drv_cc.nflash.present) { + err = platform_device_register(&bcma_nflash_dev); + if (err) + bcma_err(bus, "Error registering NAND flash\n"); + } +#endif + err = bcma_gpio_init(&bus->drv_cc); + if (err == -ENOTSUPP) + bcma_debug(bus, "GPIO driver not activated\n"); + else if (err) + bcma_err(bus, "Error registering GPIO driver: %i\n", err); + + if (bus->hosttype == BCMA_HOSTTYPE_SOC) { + err = bcma_chipco_watchdog_register(&bus->drv_cc); + if (err) + bcma_err(bus, "Error registering watchdog driver\n"); + } + return 0; } static void bcma_unregister_cores(struct bcma_bus *bus) { - struct bcma_device *core; + struct bcma_device *core, *tmp; - list_for_each_entry(core, &bus->cores, list) { + list_for_each_entry_safe(core, tmp, &bus->cores, list) { + list_del(&core->list); if (core->dev_registered) device_unregister(&core->dev); } + if (bus->hosttype == BCMA_HOSTTYPE_SOC) + platform_device_unregister(bus->drv_cc.watchdog); } int bcma_bus_register(struct bcma_bus *bus) @@ -137,15 +228,33 @@ int bcma_bus_register(struct bcma_bus *bus) int err; struct bcma_device *core; + mutex_lock(&bcma_buses_mutex); + bus->num = bcma_bus_next_num++; + mutex_unlock(&bcma_buses_mutex); + /* Scan for devices (cores) */ err = bcma_bus_scan(bus); if (err) { - pr_err("Failed to scan: %d\n", err); - return -1; + bcma_err(bus, "Failed to scan: %d\n", err); + return err; + } + + /* Early init CC core */ + core = bcma_find_core(bus, bcma_cc_core_id(bus)); + if (core) { + bus->drv_cc.core = core; + bcma_core_chipcommon_early_init(&bus->drv_cc); } + /* Try to get SPROM */ + err = bcma_sprom_get(bus); + if (err == -ENOENT) { + bcma_err(bus, "No SPROM available\n"); + } else if (err) + bcma_err(bus, "Failed to get SPROM: %d\n", err); + /* Init CC core */ - core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); + core = bcma_find_core(bus, bcma_cc_core_id(bus)); if (core) { bus->drv_cc.core = core; bcma_core_chipcommon_init(&bus->drv_cc); @@ -159,30 +268,54 @@ int bcma_bus_register(struct bcma_bus *bus) } /* Init PCIE core */ - core = bcma_find_core(bus, BCMA_CORE_PCIE); + core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 0); if (core) { - bus->drv_pci.core = core; - bcma_core_pci_init(&bus->drv_pci); + bus->drv_pci[0].core = core; + bcma_core_pci_init(&bus->drv_pci[0]); } - /* Try to get SPROM */ - err = bcma_sprom_get(bus); - if (err == -ENOENT) { - pr_err("No SPROM available\n"); - } else if (err) - pr_err("Failed to get SPROM: %d\n", err); + /* Init PCIE core */ + core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1); + if (core) { + bus->drv_pci[1].core = core; + bcma_core_pci_init(&bus->drv_pci[1]); + } + + /* Init GBIT MAC COMMON core */ + core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); + if (core) { + bus->drv_gmac_cmn.core = core; + bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn); + } /* Register found cores */ bcma_register_cores(bus); - pr_info("Bus registered\n"); + bcma_info(bus, "Bus registered\n"); return 0; } void bcma_bus_unregister(struct bcma_bus *bus) { + struct bcma_device *cores[3]; + int err; + + err = bcma_gpio_unregister(&bus->drv_cc); + if (err == -EBUSY) + bcma_err(bus, "Some GPIOs are still in use.\n"); + else if (err) + bcma_err(bus, "Can not unregister GPIO driver: %i\n", err); + + cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K); + cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE); + cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); + bcma_unregister_cores(bus); + + kfree(cores[2]); + kfree(cores[1]); + kfree(cores[0]); } int __init bcma_bus_early_register(struct bcma_bus *bus, @@ -196,14 +329,14 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, bcma_init_bus(bus); match.manuf = BCMA_MANUF_BCM; - match.id = BCMA_CORE_CHIPCOMMON; + match.id = bcma_cc_core_id(bus); match.class = BCMA_CL_SIM; match.rev = BCMA_ANY_REV; /* Scan for chip common core */ err = bcma_bus_scan_early(bus, &match, core_cc); if (err) { - pr_err("Failed to scan for common core: %d\n", err); + bcma_err(bus, "Failed to scan for common core: %d\n", err); return -1; } @@ -215,25 +348,25 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, /* Scan for mips core */ err = bcma_bus_scan_early(bus, &match, core_mips); if (err) { - pr_err("Failed to scan for mips core: %d\n", err); + bcma_err(bus, "Failed to scan for mips core: %d\n", err); return -1; } - /* Init CC core */ - core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); + /* Early init CC core */ + core = bcma_find_core(bus, bcma_cc_core_id(bus)); if (core) { bus->drv_cc.core = core; - bcma_core_chipcommon_init(&bus->drv_cc); + bcma_core_chipcommon_early_init(&bus->drv_cc); } - /* Init MIPS core */ + /* Early init MIPS core */ core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); if (core) { bus->drv_mips.core = core; - bcma_core_mips_init(&bus->drv_mips); + bcma_core_mips_early_init(&bus->drv_mips); } - pr_info("Early bus registered\n"); + bcma_info(bus, "Early bus registered\n"); return 0; } @@ -259,8 +392,7 @@ int bcma_bus_resume(struct bcma_bus *bus) struct bcma_device *core; /* Init CC core */ - core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); - if (core) { + if (bus->drv_cc.core) { bus->drv_cc.setup_done = false; bcma_core_chipcommon_init(&bus->drv_cc); } |
