162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Broadcom specific AMBA 362306a36Sopenharmony_ci * Bus subsystem 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "bcma_private.h" 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/mmc/sdio_func.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci#include <linux/bcma/bcma.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/of_address.h> 1662306a36Sopenharmony_ci#include <linux/of_irq.h> 1762306a36Sopenharmony_ci#include <linux/of_device.h> 1862306a36Sopenharmony_ci#include <linux/of_platform.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciMODULE_DESCRIPTION("Broadcom's specific AMBA driver"); 2162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* contains the number the next bus should get. */ 2462306a36Sopenharmony_cistatic unsigned int bcma_bus_next_num; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* bcma_buses_mutex locks the bcma_bus_next_num */ 2762306a36Sopenharmony_cistatic DEFINE_MUTEX(bcma_buses_mutex); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int bcma_bus_match(struct device *dev, struct device_driver *drv); 3062306a36Sopenharmony_cistatic int bcma_device_probe(struct device *dev); 3162306a36Sopenharmony_cistatic void bcma_device_remove(struct device *dev); 3262306a36Sopenharmony_cistatic int bcma_device_uevent(const struct device *dev, struct kobj_uevent_env *env); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct bcma_device *core = container_of(dev, struct bcma_device, dev); 3762306a36Sopenharmony_ci return sprintf(buf, "0x%03X\n", core->id.manuf); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(manuf); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct bcma_device *core = container_of(dev, struct bcma_device, dev); 4462306a36Sopenharmony_ci return sprintf(buf, "0x%03X\n", core->id.id); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(id); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct bcma_device *core = container_of(dev, struct bcma_device, dev); 5162306a36Sopenharmony_ci return sprintf(buf, "0x%02X\n", core->id.rev); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(rev); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct bcma_device *core = container_of(dev, struct bcma_device, dev); 5862306a36Sopenharmony_ci return sprintf(buf, "0x%X\n", core->id.class); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(class); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic struct attribute *bcma_device_attrs[] = { 6362306a36Sopenharmony_ci &dev_attr_manuf.attr, 6462306a36Sopenharmony_ci &dev_attr_id.attr, 6562306a36Sopenharmony_ci &dev_attr_rev.attr, 6662306a36Sopenharmony_ci &dev_attr_class.attr, 6762306a36Sopenharmony_ci NULL, 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ciATTRIBUTE_GROUPS(bcma_device); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic struct bus_type bcma_bus_type = { 7262306a36Sopenharmony_ci .name = "bcma", 7362306a36Sopenharmony_ci .match = bcma_bus_match, 7462306a36Sopenharmony_ci .probe = bcma_device_probe, 7562306a36Sopenharmony_ci .remove = bcma_device_remove, 7662306a36Sopenharmony_ci .uevent = bcma_device_uevent, 7762306a36Sopenharmony_ci .dev_groups = bcma_device_groups, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic u16 bcma_cc_core_id(struct bcma_bus *bus) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) 8362306a36Sopenharmony_ci return BCMA_CORE_4706_CHIPCOMMON; 8462306a36Sopenharmony_ci return BCMA_CORE_CHIPCOMMON; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid, 8862306a36Sopenharmony_ci u8 unit) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct bcma_device *core; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci list_for_each_entry(core, &bus->cores, list) { 9362306a36Sopenharmony_ci if (core->id.id == coreid && core->core_unit == unit) 9462306a36Sopenharmony_ci return core; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci return NULL; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_find_core_unit); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cibool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value, 10162306a36Sopenharmony_ci int timeout) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci unsigned long deadline = jiffies + timeout; 10462306a36Sopenharmony_ci u32 val; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci do { 10762306a36Sopenharmony_ci val = bcma_read32(core, reg); 10862306a36Sopenharmony_ci if ((val & mask) == value) 10962306a36Sopenharmony_ci return true; 11062306a36Sopenharmony_ci cpu_relax(); 11162306a36Sopenharmony_ci udelay(10); 11262306a36Sopenharmony_ci } while (!time_after_eq(jiffies, deadline)); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return false; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic void bcma_release_core_dev(struct device *dev) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct bcma_device *core = container_of(dev, struct bcma_device, dev); 12262306a36Sopenharmony_ci if (core->io_addr) 12362306a36Sopenharmony_ci iounmap(core->io_addr); 12462306a36Sopenharmony_ci if (core->io_wrap) 12562306a36Sopenharmony_ci iounmap(core->io_wrap); 12662306a36Sopenharmony_ci kfree(core); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic bool bcma_is_core_needed_early(u16 core_id) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci switch (core_id) { 13262306a36Sopenharmony_ci case BCMA_CORE_NS_NAND: 13362306a36Sopenharmony_ci case BCMA_CORE_NS_QSPI: 13462306a36Sopenharmony_ci return true; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return false; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic struct device_node *bcma_of_find_child_device(struct device *parent, 14162306a36Sopenharmony_ci struct bcma_device *core) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct device_node *node; 14462306a36Sopenharmony_ci int ret; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!parent->of_node) 14762306a36Sopenharmony_ci return NULL; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci for_each_child_of_node(parent->of_node, node) { 15062306a36Sopenharmony_ci struct resource res; 15162306a36Sopenharmony_ci ret = of_address_to_resource(node, 0, &res); 15262306a36Sopenharmony_ci if (ret) 15362306a36Sopenharmony_ci continue; 15462306a36Sopenharmony_ci if (res.start == core->addr) 15562306a36Sopenharmony_ci return node; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci return NULL; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic int bcma_of_irq_parse(struct device *parent, 16162306a36Sopenharmony_ci struct bcma_device *core, 16262306a36Sopenharmony_ci struct of_phandle_args *out_irq, int num) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci __be32 laddr[1]; 16562306a36Sopenharmony_ci int rc; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (core->dev.of_node) { 16862306a36Sopenharmony_ci rc = of_irq_parse_one(core->dev.of_node, num, out_irq); 16962306a36Sopenharmony_ci if (!rc) 17062306a36Sopenharmony_ci return rc; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci out_irq->np = parent->of_node; 17462306a36Sopenharmony_ci out_irq->args_count = 1; 17562306a36Sopenharmony_ci out_irq->args[0] = num; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci laddr[0] = cpu_to_be32(core->addr); 17862306a36Sopenharmony_ci return of_irq_parse_raw(laddr, out_irq); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic unsigned int bcma_of_get_irq(struct device *parent, 18262306a36Sopenharmony_ci struct bcma_device *core, int num) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct of_phandle_args out_irq; 18562306a36Sopenharmony_ci int ret; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_OF_IRQ) || !parent->of_node) 18862306a36Sopenharmony_ci return 0; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ret = bcma_of_irq_parse(parent, core, &out_irq, num); 19162306a36Sopenharmony_ci if (ret) { 19262306a36Sopenharmony_ci bcma_debug(core->bus, "bcma_of_get_irq() failed with rc=%d\n", 19362306a36Sopenharmony_ci ret); 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return irq_create_of_mapping(&out_irq); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic void bcma_of_fill_device(struct device *parent, 20162306a36Sopenharmony_ci struct bcma_device *core) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct device_node *node; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci node = bcma_of_find_child_device(parent, core); 20662306a36Sopenharmony_ci if (node) 20762306a36Sopenharmony_ci core->dev.of_node = node; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci core->irq = bcma_of_get_irq(parent, core, 0); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci of_dma_configure(&core->dev, node, false); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ciunsigned int bcma_core_irq(struct bcma_device *core, int num) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct bcma_bus *bus = core->bus; 21762306a36Sopenharmony_ci unsigned int mips_irq; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci switch (bus->hosttype) { 22062306a36Sopenharmony_ci case BCMA_HOSTTYPE_PCI: 22162306a36Sopenharmony_ci return bus->host_pci->irq; 22262306a36Sopenharmony_ci case BCMA_HOSTTYPE_SOC: 22362306a36Sopenharmony_ci if (bus->drv_mips.core && num == 0) { 22462306a36Sopenharmony_ci mips_irq = bcma_core_mips_irq(core); 22562306a36Sopenharmony_ci return mips_irq <= 4 ? mips_irq + 2 : 0; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci if (bus->dev) 22862306a36Sopenharmony_ci return bcma_of_get_irq(bus->dev, core, num); 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci case BCMA_HOSTTYPE_SDIO: 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ciEXPORT_SYMBOL(bcma_core_irq); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_civoid bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci device_initialize(&core->dev); 24162306a36Sopenharmony_ci core->dev.release = bcma_release_core_dev; 24262306a36Sopenharmony_ci core->dev.bus = &bcma_bus_type; 24362306a36Sopenharmony_ci dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index); 24462306a36Sopenharmony_ci core->dev.parent = bus->dev; 24562306a36Sopenharmony_ci if (bus->dev) 24662306a36Sopenharmony_ci bcma_of_fill_device(bus->dev, core); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci switch (bus->hosttype) { 24962306a36Sopenharmony_ci case BCMA_HOSTTYPE_PCI: 25062306a36Sopenharmony_ci core->dma_dev = bus->dev; 25162306a36Sopenharmony_ci core->irq = bus->host_pci->irq; 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci case BCMA_HOSTTYPE_SOC: 25462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_OF) && bus->dev) { 25562306a36Sopenharmony_ci core->dma_dev = bus->dev; 25662306a36Sopenharmony_ci } else { 25762306a36Sopenharmony_ci core->dev.dma_mask = &core->dev.coherent_dma_mask; 25862306a36Sopenharmony_ci core->dma_dev = &core->dev; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci case BCMA_HOSTTYPE_SDIO: 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_civoid bcma_init_bus(struct bcma_bus *bus) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci mutex_lock(&bcma_buses_mutex); 26962306a36Sopenharmony_ci bus->num = bcma_bus_next_num++; 27062306a36Sopenharmony_ci mutex_unlock(&bcma_buses_mutex); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci INIT_LIST_HEAD(&bus->cores); 27362306a36Sopenharmony_ci bus->nr_cores = 0; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci bcma_detect_chip(bus); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci int err; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci err = device_add(&core->dev); 28362306a36Sopenharmony_ci if (err) { 28462306a36Sopenharmony_ci bcma_err(bus, "Could not register dev for core 0x%03X\n", 28562306a36Sopenharmony_ci core->id.id); 28662306a36Sopenharmony_ci return; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci core->dev_registered = true; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int bcma_register_devices(struct bcma_bus *bus) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct bcma_device *core; 29462306a36Sopenharmony_ci int err; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci list_for_each_entry(core, &bus->cores, list) { 29762306a36Sopenharmony_ci /* We support that core ourselves */ 29862306a36Sopenharmony_ci switch (core->id.id) { 29962306a36Sopenharmony_ci case BCMA_CORE_4706_CHIPCOMMON: 30062306a36Sopenharmony_ci case BCMA_CORE_CHIPCOMMON: 30162306a36Sopenharmony_ci case BCMA_CORE_NS_CHIPCOMMON_B: 30262306a36Sopenharmony_ci case BCMA_CORE_PCI: 30362306a36Sopenharmony_ci case BCMA_CORE_PCIE: 30462306a36Sopenharmony_ci case BCMA_CORE_PCIE2: 30562306a36Sopenharmony_ci case BCMA_CORE_MIPS_74K: 30662306a36Sopenharmony_ci case BCMA_CORE_4706_MAC_GBIT_COMMON: 30762306a36Sopenharmony_ci continue; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* Early cores were already registered */ 31162306a36Sopenharmony_ci if (bcma_is_core_needed_early(core->id.id)) 31262306a36Sopenharmony_ci continue; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Only first GMAC core on BCM4706 is connected and working */ 31562306a36Sopenharmony_ci if (core->id.id == BCMA_CORE_4706_MAC_GBIT && 31662306a36Sopenharmony_ci core->core_unit > 0) 31762306a36Sopenharmony_ci continue; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci bcma_register_core(bus, core); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci#ifdef CONFIG_BCMA_PFLASH 32362306a36Sopenharmony_ci if (bus->drv_cc.pflash.present) { 32462306a36Sopenharmony_ci err = platform_device_register(&bcma_pflash_dev); 32562306a36Sopenharmony_ci if (err) 32662306a36Sopenharmony_ci bcma_err(bus, "Error registering parallel flash\n"); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci#endif 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci#ifdef CONFIG_BCMA_SFLASH 33162306a36Sopenharmony_ci if (bus->drv_cc.sflash.present) { 33262306a36Sopenharmony_ci err = platform_device_register(&bcma_sflash_dev); 33362306a36Sopenharmony_ci if (err) 33462306a36Sopenharmony_ci bcma_err(bus, "Error registering serial flash\n"); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci#endif 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci#ifdef CONFIG_BCMA_NFLASH 33962306a36Sopenharmony_ci if (bus->drv_cc.nflash.present) { 34062306a36Sopenharmony_ci err = platform_device_register(&bcma_nflash_dev); 34162306a36Sopenharmony_ci if (err) 34262306a36Sopenharmony_ci bcma_err(bus, "Error registering NAND flash\n"); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci#endif 34562306a36Sopenharmony_ci err = bcma_gpio_init(&bus->drv_cc); 34662306a36Sopenharmony_ci if (err == -ENOTSUPP) 34762306a36Sopenharmony_ci bcma_debug(bus, "GPIO driver not activated\n"); 34862306a36Sopenharmony_ci else if (err) { 34962306a36Sopenharmony_ci bcma_err(bus, "Error registering GPIO driver: %i\n", err); 35062306a36Sopenharmony_ci return err; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (bus->hosttype == BCMA_HOSTTYPE_SOC) { 35462306a36Sopenharmony_ci err = bcma_chipco_watchdog_register(&bus->drv_cc); 35562306a36Sopenharmony_ci if (err) 35662306a36Sopenharmony_ci bcma_err(bus, "Error registering watchdog driver\n"); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_civoid bcma_unregister_cores(struct bcma_bus *bus) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct bcma_device *core, *tmp; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci list_for_each_entry_safe(core, tmp, &bus->cores, list) { 36762306a36Sopenharmony_ci if (!core->dev_registered) 36862306a36Sopenharmony_ci continue; 36962306a36Sopenharmony_ci list_del(&core->list); 37062306a36Sopenharmony_ci device_unregister(&core->dev); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci if (bus->hosttype == BCMA_HOSTTYPE_SOC) 37362306a36Sopenharmony_ci platform_device_unregister(bus->drv_cc.watchdog); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Now no one uses internally-handled cores, we can free them */ 37662306a36Sopenharmony_ci list_for_each_entry_safe(core, tmp, &bus->cores, list) { 37762306a36Sopenharmony_ci list_del(&core->list); 37862306a36Sopenharmony_ci put_device(&core->dev); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ciint bcma_bus_register(struct bcma_bus *bus) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci int err; 38562306a36Sopenharmony_ci struct bcma_device *core; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* Scan for devices (cores) */ 38862306a36Sopenharmony_ci err = bcma_bus_scan(bus); 38962306a36Sopenharmony_ci if (err) { 39062306a36Sopenharmony_ci bcma_err(bus, "Failed to scan: %d\n", err); 39162306a36Sopenharmony_ci return err; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* Early init CC core */ 39562306a36Sopenharmony_ci core = bcma_find_core(bus, bcma_cc_core_id(bus)); 39662306a36Sopenharmony_ci if (core) { 39762306a36Sopenharmony_ci bus->drv_cc.core = core; 39862306a36Sopenharmony_ci bcma_core_chipcommon_early_init(&bus->drv_cc); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Early init PCIE core */ 40262306a36Sopenharmony_ci core = bcma_find_core(bus, BCMA_CORE_PCIE); 40362306a36Sopenharmony_ci if (core) { 40462306a36Sopenharmony_ci bus->drv_pci[0].core = core; 40562306a36Sopenharmony_ci bcma_core_pci_early_init(&bus->drv_pci[0]); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (bus->dev) 40962306a36Sopenharmony_ci of_platform_default_populate(bus->dev->of_node, NULL, bus->dev); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* Cores providing flash access go before SPROM init */ 41262306a36Sopenharmony_ci list_for_each_entry(core, &bus->cores, list) { 41362306a36Sopenharmony_ci if (bcma_is_core_needed_early(core->id.id)) 41462306a36Sopenharmony_ci bcma_register_core(bus, core); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* Try to get SPROM */ 41862306a36Sopenharmony_ci err = bcma_sprom_get(bus); 41962306a36Sopenharmony_ci if (err == -ENOENT) { 42062306a36Sopenharmony_ci bcma_err(bus, "No SPROM available\n"); 42162306a36Sopenharmony_ci } else if (err) 42262306a36Sopenharmony_ci bcma_err(bus, "Failed to get SPROM: %d\n", err); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* Init CC core */ 42562306a36Sopenharmony_ci core = bcma_find_core(bus, bcma_cc_core_id(bus)); 42662306a36Sopenharmony_ci if (core) { 42762306a36Sopenharmony_ci bus->drv_cc.core = core; 42862306a36Sopenharmony_ci bcma_core_chipcommon_init(&bus->drv_cc); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* Init CC core */ 43262306a36Sopenharmony_ci core = bcma_find_core(bus, BCMA_CORE_NS_CHIPCOMMON_B); 43362306a36Sopenharmony_ci if (core) { 43462306a36Sopenharmony_ci bus->drv_cc_b.core = core; 43562306a36Sopenharmony_ci bcma_core_chipcommon_b_init(&bus->drv_cc_b); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Init MIPS core */ 43962306a36Sopenharmony_ci core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); 44062306a36Sopenharmony_ci if (core) { 44162306a36Sopenharmony_ci bus->drv_mips.core = core; 44262306a36Sopenharmony_ci bcma_core_mips_init(&bus->drv_mips); 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* Init PCIE core */ 44662306a36Sopenharmony_ci core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 0); 44762306a36Sopenharmony_ci if (core) { 44862306a36Sopenharmony_ci bus->drv_pci[0].core = core; 44962306a36Sopenharmony_ci bcma_core_pci_init(&bus->drv_pci[0]); 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* Init PCIE core */ 45362306a36Sopenharmony_ci core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1); 45462306a36Sopenharmony_ci if (core) { 45562306a36Sopenharmony_ci bus->drv_pci[1].core = core; 45662306a36Sopenharmony_ci bcma_core_pci_init(&bus->drv_pci[1]); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* Init PCIe Gen 2 core */ 46062306a36Sopenharmony_ci core = bcma_find_core_unit(bus, BCMA_CORE_PCIE2, 0); 46162306a36Sopenharmony_ci if (core) { 46262306a36Sopenharmony_ci bus->drv_pcie2.core = core; 46362306a36Sopenharmony_ci bcma_core_pcie2_init(&bus->drv_pcie2); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Init GBIT MAC COMMON core */ 46762306a36Sopenharmony_ci core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); 46862306a36Sopenharmony_ci if (core) { 46962306a36Sopenharmony_ci bus->drv_gmac_cmn.core = core; 47062306a36Sopenharmony_ci bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* Register found cores */ 47462306a36Sopenharmony_ci bcma_register_devices(bus); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci bcma_info(bus, "Bus registered\n"); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_civoid bcma_bus_unregister(struct bcma_bus *bus) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci int err; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci err = bcma_gpio_unregister(&bus->drv_cc); 48662306a36Sopenharmony_ci if (err == -EBUSY) 48762306a36Sopenharmony_ci bcma_err(bus, "Some GPIOs are still in use.\n"); 48862306a36Sopenharmony_ci else if (err) 48962306a36Sopenharmony_ci bcma_err(bus, "Can not unregister GPIO driver: %i\n", err); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci bcma_core_chipcommon_b_free(&bus->drv_cc_b); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci bcma_unregister_cores(bus); 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci/* 49762306a36Sopenharmony_ci * This is a special version of bus registration function designed for SoCs. 49862306a36Sopenharmony_ci * It scans bus and performs basic initialization of main cores only. 49962306a36Sopenharmony_ci * Please note it requires memory allocation, however it won't try to sleep. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ciint __init bcma_bus_early_register(struct bcma_bus *bus) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci int err; 50462306a36Sopenharmony_ci struct bcma_device *core; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* Scan for devices (cores) */ 50762306a36Sopenharmony_ci err = bcma_bus_scan(bus); 50862306a36Sopenharmony_ci if (err) { 50962306a36Sopenharmony_ci bcma_err(bus, "Failed to scan bus: %d\n", err); 51062306a36Sopenharmony_ci return -1; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* Early init CC core */ 51462306a36Sopenharmony_ci core = bcma_find_core(bus, bcma_cc_core_id(bus)); 51562306a36Sopenharmony_ci if (core) { 51662306a36Sopenharmony_ci bus->drv_cc.core = core; 51762306a36Sopenharmony_ci bcma_core_chipcommon_early_init(&bus->drv_cc); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Early init MIPS core */ 52162306a36Sopenharmony_ci core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); 52262306a36Sopenharmony_ci if (core) { 52362306a36Sopenharmony_ci bus->drv_mips.core = core; 52462306a36Sopenharmony_ci bcma_core_mips_early_init(&bus->drv_mips); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci bcma_info(bus, "Early bus registered\n"); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci#ifdef CONFIG_PM 53362306a36Sopenharmony_ciint bcma_bus_suspend(struct bcma_bus *bus) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci struct bcma_device *core; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci list_for_each_entry(core, &bus->cores, list) { 53862306a36Sopenharmony_ci struct device_driver *drv = core->dev.driver; 53962306a36Sopenharmony_ci if (drv) { 54062306a36Sopenharmony_ci struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv); 54162306a36Sopenharmony_ci if (adrv->suspend) 54262306a36Sopenharmony_ci adrv->suspend(core); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ciint bcma_bus_resume(struct bcma_bus *bus) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct bcma_device *core; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Init CC core */ 55362306a36Sopenharmony_ci if (bus->drv_cc.core) { 55462306a36Sopenharmony_ci bus->drv_cc.setup_done = false; 55562306a36Sopenharmony_ci bcma_core_chipcommon_init(&bus->drv_cc); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci list_for_each_entry(core, &bus->cores, list) { 55962306a36Sopenharmony_ci struct device_driver *drv = core->dev.driver; 56062306a36Sopenharmony_ci if (drv) { 56162306a36Sopenharmony_ci struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv); 56262306a36Sopenharmony_ci if (adrv->resume) 56362306a36Sopenharmony_ci adrv->resume(core); 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci#endif 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ciint __bcma_driver_register(struct bcma_driver *drv, struct module *owner) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci drv->drv.name = drv->name; 57462306a36Sopenharmony_ci drv->drv.bus = &bcma_bus_type; 57562306a36Sopenharmony_ci drv->drv.owner = owner; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return driver_register(&drv->drv); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__bcma_driver_register); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_civoid bcma_driver_unregister(struct bcma_driver *drv) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci driver_unregister(&drv->drv); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_driver_unregister); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic int bcma_bus_match(struct device *dev, struct device_driver *drv) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct bcma_device *core = container_of(dev, struct bcma_device, dev); 59062306a36Sopenharmony_ci struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv); 59162306a36Sopenharmony_ci const struct bcma_device_id *cid = &core->id; 59262306a36Sopenharmony_ci const struct bcma_device_id *did; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) { 59562306a36Sopenharmony_ci if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) && 59662306a36Sopenharmony_ci (did->id == cid->id || did->id == BCMA_ANY_ID) && 59762306a36Sopenharmony_ci (did->rev == cid->rev || did->rev == BCMA_ANY_REV) && 59862306a36Sopenharmony_ci (did->class == cid->class || did->class == BCMA_ANY_CLASS)) 59962306a36Sopenharmony_ci return 1; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int bcma_device_probe(struct device *dev) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct bcma_device *core = container_of(dev, struct bcma_device, dev); 60762306a36Sopenharmony_ci struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, 60862306a36Sopenharmony_ci drv); 60962306a36Sopenharmony_ci int err = 0; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci get_device(dev); 61262306a36Sopenharmony_ci if (adrv->probe) 61362306a36Sopenharmony_ci err = adrv->probe(core); 61462306a36Sopenharmony_ci if (err) 61562306a36Sopenharmony_ci put_device(dev); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci return err; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic void bcma_device_remove(struct device *dev) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci struct bcma_device *core = container_of(dev, struct bcma_device, dev); 62362306a36Sopenharmony_ci struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, 62462306a36Sopenharmony_ci drv); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (adrv->remove) 62762306a36Sopenharmony_ci adrv->remove(core); 62862306a36Sopenharmony_ci put_device(dev); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int bcma_device_uevent(const struct device *dev, struct kobj_uevent_env *env) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci const struct bcma_device *core = container_of_const(dev, struct bcma_device, dev); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return add_uevent_var(env, 63662306a36Sopenharmony_ci "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X", 63762306a36Sopenharmony_ci core->id.manuf, core->id.id, 63862306a36Sopenharmony_ci core->id.rev, core->id.class); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic unsigned int bcma_bus_registered; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/* 64462306a36Sopenharmony_ci * If built-in, bus has to be registered early, before any driver calls 64562306a36Sopenharmony_ci * bcma_driver_register. 64662306a36Sopenharmony_ci * Otherwise registering driver would trigger BUG in driver_register. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_cistatic int __init bcma_init_bus_register(void) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci int err; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (bcma_bus_registered) 65362306a36Sopenharmony_ci return 0; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci err = bus_register(&bcma_bus_type); 65662306a36Sopenharmony_ci if (!err) 65762306a36Sopenharmony_ci bcma_bus_registered = 1; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci return err; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci#ifndef MODULE 66262306a36Sopenharmony_cifs_initcall(bcma_init_bus_register); 66362306a36Sopenharmony_ci#endif 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci/* Main initialization has to be done with SPI/mtd/NAND/SPROM available */ 66662306a36Sopenharmony_cistatic int __init bcma_modinit(void) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci int err; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci err = bcma_init_bus_register(); 67162306a36Sopenharmony_ci if (err) 67262306a36Sopenharmony_ci return err; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci err = bcma_host_soc_register_driver(); 67562306a36Sopenharmony_ci if (err) { 67662306a36Sopenharmony_ci pr_err("SoC host initialization failed\n"); 67762306a36Sopenharmony_ci err = 0; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci#ifdef CONFIG_BCMA_HOST_PCI 68062306a36Sopenharmony_ci err = bcma_host_pci_init(); 68162306a36Sopenharmony_ci if (err) { 68262306a36Sopenharmony_ci pr_err("PCI host initialization failed\n"); 68362306a36Sopenharmony_ci err = 0; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci#endif 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci return err; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_cimodule_init(bcma_modinit); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic void __exit bcma_modexit(void) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci#ifdef CONFIG_BCMA_HOST_PCI 69462306a36Sopenharmony_ci bcma_host_pci_exit(); 69562306a36Sopenharmony_ci#endif 69662306a36Sopenharmony_ci bcma_host_soc_unregister_driver(); 69762306a36Sopenharmony_ci bus_unregister(&bcma_bus_type); 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_cimodule_exit(bcma_modexit) 700