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