18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Sonics Silicon Backplane
38c2ecf20Sopenharmony_ci * Bus scanning
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
68c2ecf20Sopenharmony_ci * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
78c2ecf20Sopenharmony_ci * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
88c2ecf20Sopenharmony_ci * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
98c2ecf20Sopenharmony_ci * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
108c2ecf20Sopenharmony_ci * Copyright (C) 2006 Broadcom Corporation.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details.
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "ssb_private.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/ssb/ssb.h>
188c2ecf20Sopenharmony_ci#include <linux/ssb/ssb_regs.h>
198c2ecf20Sopenharmony_ci#include <linux/pci.h>
208c2ecf20Sopenharmony_ci#include <linux/io.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <pcmcia/cistpl.h>
238c2ecf20Sopenharmony_ci#include <pcmcia/ds.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ciconst char *ssb_core_name(u16 coreid)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	switch (coreid) {
298c2ecf20Sopenharmony_ci	case SSB_DEV_CHIPCOMMON:
308c2ecf20Sopenharmony_ci		return "ChipCommon";
318c2ecf20Sopenharmony_ci	case SSB_DEV_ILINE20:
328c2ecf20Sopenharmony_ci		return "ILine 20";
338c2ecf20Sopenharmony_ci	case SSB_DEV_SDRAM:
348c2ecf20Sopenharmony_ci		return "SDRAM";
358c2ecf20Sopenharmony_ci	case SSB_DEV_PCI:
368c2ecf20Sopenharmony_ci		return "PCI";
378c2ecf20Sopenharmony_ci	case SSB_DEV_MIPS:
388c2ecf20Sopenharmony_ci		return "MIPS";
398c2ecf20Sopenharmony_ci	case SSB_DEV_ETHERNET:
408c2ecf20Sopenharmony_ci		return "Fast Ethernet";
418c2ecf20Sopenharmony_ci	case SSB_DEV_V90:
428c2ecf20Sopenharmony_ci		return "V90";
438c2ecf20Sopenharmony_ci	case SSB_DEV_USB11_HOSTDEV:
448c2ecf20Sopenharmony_ci		return "USB 1.1 Hostdev";
458c2ecf20Sopenharmony_ci	case SSB_DEV_ADSL:
468c2ecf20Sopenharmony_ci		return "ADSL";
478c2ecf20Sopenharmony_ci	case SSB_DEV_ILINE100:
488c2ecf20Sopenharmony_ci		return "ILine 100";
498c2ecf20Sopenharmony_ci	case SSB_DEV_IPSEC:
508c2ecf20Sopenharmony_ci		return "IPSEC";
518c2ecf20Sopenharmony_ci	case SSB_DEV_PCMCIA:
528c2ecf20Sopenharmony_ci		return "PCMCIA";
538c2ecf20Sopenharmony_ci	case SSB_DEV_INTERNAL_MEM:
548c2ecf20Sopenharmony_ci		return "Internal Memory";
558c2ecf20Sopenharmony_ci	case SSB_DEV_MEMC_SDRAM:
568c2ecf20Sopenharmony_ci		return "MEMC SDRAM";
578c2ecf20Sopenharmony_ci	case SSB_DEV_EXTIF:
588c2ecf20Sopenharmony_ci		return "EXTIF";
598c2ecf20Sopenharmony_ci	case SSB_DEV_80211:
608c2ecf20Sopenharmony_ci		return "IEEE 802.11";
618c2ecf20Sopenharmony_ci	case SSB_DEV_MIPS_3302:
628c2ecf20Sopenharmony_ci		return "MIPS 3302";
638c2ecf20Sopenharmony_ci	case SSB_DEV_USB11_HOST:
648c2ecf20Sopenharmony_ci		return "USB 1.1 Host";
658c2ecf20Sopenharmony_ci	case SSB_DEV_USB11_DEV:
668c2ecf20Sopenharmony_ci		return "USB 1.1 Device";
678c2ecf20Sopenharmony_ci	case SSB_DEV_USB20_HOST:
688c2ecf20Sopenharmony_ci		return "USB 2.0 Host";
698c2ecf20Sopenharmony_ci	case SSB_DEV_USB20_DEV:
708c2ecf20Sopenharmony_ci		return "USB 2.0 Device";
718c2ecf20Sopenharmony_ci	case SSB_DEV_SDIO_HOST:
728c2ecf20Sopenharmony_ci		return "SDIO Host";
738c2ecf20Sopenharmony_ci	case SSB_DEV_ROBOSWITCH:
748c2ecf20Sopenharmony_ci		return "Roboswitch";
758c2ecf20Sopenharmony_ci	case SSB_DEV_PARA_ATA:
768c2ecf20Sopenharmony_ci		return "PATA";
778c2ecf20Sopenharmony_ci	case SSB_DEV_SATA_XORDMA:
788c2ecf20Sopenharmony_ci		return "SATA XOR-DMA";
798c2ecf20Sopenharmony_ci	case SSB_DEV_ETHERNET_GBIT:
808c2ecf20Sopenharmony_ci		return "GBit Ethernet";
818c2ecf20Sopenharmony_ci	case SSB_DEV_PCIE:
828c2ecf20Sopenharmony_ci		return "PCI-E";
838c2ecf20Sopenharmony_ci	case SSB_DEV_MIMO_PHY:
848c2ecf20Sopenharmony_ci		return "MIMO PHY";
858c2ecf20Sopenharmony_ci	case SSB_DEV_SRAM_CTRLR:
868c2ecf20Sopenharmony_ci		return "SRAM Controller";
878c2ecf20Sopenharmony_ci	case SSB_DEV_MINI_MACPHY:
888c2ecf20Sopenharmony_ci		return "Mini MACPHY";
898c2ecf20Sopenharmony_ci	case SSB_DEV_ARM_1176:
908c2ecf20Sopenharmony_ci		return "ARM 1176";
918c2ecf20Sopenharmony_ci	case SSB_DEV_ARM_7TDMI:
928c2ecf20Sopenharmony_ci		return "ARM 7TDMI";
938c2ecf20Sopenharmony_ci	case SSB_DEV_ARM_CM3:
948c2ecf20Sopenharmony_ci		return "ARM Cortex M3";
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci	return "UNKNOWN";
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic u16 pcidev_to_chipid(struct pci_dev *pci_dev)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	u16 chipid_fallback = 0;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	switch (pci_dev->device) {
1048c2ecf20Sopenharmony_ci	case 0x4301:
1058c2ecf20Sopenharmony_ci		chipid_fallback = 0x4301;
1068c2ecf20Sopenharmony_ci		break;
1078c2ecf20Sopenharmony_ci	case 0x4305 ... 0x4307:
1088c2ecf20Sopenharmony_ci		chipid_fallback = 0x4307;
1098c2ecf20Sopenharmony_ci		break;
1108c2ecf20Sopenharmony_ci	case 0x4403:
1118c2ecf20Sopenharmony_ci		chipid_fallback = 0x4402;
1128c2ecf20Sopenharmony_ci		break;
1138c2ecf20Sopenharmony_ci	case 0x4610 ... 0x4615:
1148c2ecf20Sopenharmony_ci		chipid_fallback = 0x4610;
1158c2ecf20Sopenharmony_ci		break;
1168c2ecf20Sopenharmony_ci	case 0x4710 ... 0x4715:
1178c2ecf20Sopenharmony_ci		chipid_fallback = 0x4710;
1188c2ecf20Sopenharmony_ci		break;
1198c2ecf20Sopenharmony_ci	case 0x4320 ... 0x4325:
1208c2ecf20Sopenharmony_ci		chipid_fallback = 0x4309;
1218c2ecf20Sopenharmony_ci		break;
1228c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_BCM4401:
1238c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_BCM4401B0:
1248c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_BCM4401B1:
1258c2ecf20Sopenharmony_ci		chipid_fallback = 0x4401;
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci	default:
1288c2ecf20Sopenharmony_ci		dev_err(&pci_dev->dev, "PCI-ID not in fallback list\n");
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return chipid_fallback;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic u8 chipid_to_nrcores(u16 chipid)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	switch (chipid) {
1378c2ecf20Sopenharmony_ci	case 0x5365:
1388c2ecf20Sopenharmony_ci		return 7;
1398c2ecf20Sopenharmony_ci	case 0x4306:
1408c2ecf20Sopenharmony_ci		return 6;
1418c2ecf20Sopenharmony_ci	case 0x4310:
1428c2ecf20Sopenharmony_ci		return 8;
1438c2ecf20Sopenharmony_ci	case 0x4307:
1448c2ecf20Sopenharmony_ci	case 0x4301:
1458c2ecf20Sopenharmony_ci		return 5;
1468c2ecf20Sopenharmony_ci	case 0x4401:
1478c2ecf20Sopenharmony_ci	case 0x4402:
1488c2ecf20Sopenharmony_ci		return 3;
1498c2ecf20Sopenharmony_ci	case 0x4710:
1508c2ecf20Sopenharmony_ci	case 0x4610:
1518c2ecf20Sopenharmony_ci	case 0x4704:
1528c2ecf20Sopenharmony_ci		return 9;
1538c2ecf20Sopenharmony_ci	default:
1548c2ecf20Sopenharmony_ci		pr_err("CHIPID not in nrcores fallback list\n");
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	return 1;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
1618c2ecf20Sopenharmony_ci		       u16 offset)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	u32 lo, hi;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	switch (bus->bustype) {
1668c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_SSB:
1678c2ecf20Sopenharmony_ci		offset += current_coreidx * SSB_CORE_SIZE;
1688c2ecf20Sopenharmony_ci		break;
1698c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_PCI:
1708c2ecf20Sopenharmony_ci		break;
1718c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_PCMCIA:
1728c2ecf20Sopenharmony_ci		if (offset >= 0x800) {
1738c2ecf20Sopenharmony_ci			ssb_pcmcia_switch_segment(bus, 1);
1748c2ecf20Sopenharmony_ci			offset -= 0x800;
1758c2ecf20Sopenharmony_ci		} else
1768c2ecf20Sopenharmony_ci			ssb_pcmcia_switch_segment(bus, 0);
1778c2ecf20Sopenharmony_ci		lo = readw(bus->mmio + offset);
1788c2ecf20Sopenharmony_ci		hi = readw(bus->mmio + offset + 2);
1798c2ecf20Sopenharmony_ci		return lo | (hi << 16);
1808c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_SDIO:
1818c2ecf20Sopenharmony_ci		offset += current_coreidx * SSB_CORE_SIZE;
1828c2ecf20Sopenharmony_ci		return ssb_sdio_scan_read32(bus, offset);
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci	return readl(bus->mmio + offset);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int scan_switchcore(struct ssb_bus *bus, u8 coreidx)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	switch (bus->bustype) {
1908c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_SSB:
1918c2ecf20Sopenharmony_ci		break;
1928c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_PCI:
1938c2ecf20Sopenharmony_ci		return ssb_pci_switch_coreidx(bus, coreidx);
1948c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_PCMCIA:
1958c2ecf20Sopenharmony_ci		return ssb_pcmcia_switch_coreidx(bus, coreidx);
1968c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_SDIO:
1978c2ecf20Sopenharmony_ci		return ssb_sdio_scan_switch_coreidx(bus, coreidx);
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_civoid ssb_iounmap(struct ssb_bus *bus)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	switch (bus->bustype) {
2058c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_SSB:
2068c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_PCMCIA:
2078c2ecf20Sopenharmony_ci		iounmap(bus->mmio);
2088c2ecf20Sopenharmony_ci		break;
2098c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_PCI:
2108c2ecf20Sopenharmony_ci#ifdef CONFIG_SSB_PCIHOST
2118c2ecf20Sopenharmony_ci		pci_iounmap(bus->host_pci, bus->mmio);
2128c2ecf20Sopenharmony_ci#else
2138c2ecf20Sopenharmony_ci		WARN_ON(1); /* Can't reach this code. */
2148c2ecf20Sopenharmony_ci#endif
2158c2ecf20Sopenharmony_ci		break;
2168c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_SDIO:
2178c2ecf20Sopenharmony_ci		break;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci	bus->mmio = NULL;
2208c2ecf20Sopenharmony_ci	bus->mapped_device = NULL;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic void __iomem *ssb_ioremap(struct ssb_bus *bus,
2248c2ecf20Sopenharmony_ci				 unsigned long baseaddr)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	void __iomem *mmio = NULL;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	switch (bus->bustype) {
2298c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_SSB:
2308c2ecf20Sopenharmony_ci		/* Only map the first core for now. */
2318c2ecf20Sopenharmony_ci		fallthrough;
2328c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_PCMCIA:
2338c2ecf20Sopenharmony_ci		mmio = ioremap(baseaddr, SSB_CORE_SIZE);
2348c2ecf20Sopenharmony_ci		break;
2358c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_PCI:
2368c2ecf20Sopenharmony_ci#ifdef CONFIG_SSB_PCIHOST
2378c2ecf20Sopenharmony_ci		mmio = pci_iomap(bus->host_pci, 0, ~0UL);
2388c2ecf20Sopenharmony_ci#else
2398c2ecf20Sopenharmony_ci		WARN_ON(1); /* Can't reach this code. */
2408c2ecf20Sopenharmony_ci#endif
2418c2ecf20Sopenharmony_ci		break;
2428c2ecf20Sopenharmony_ci	case SSB_BUSTYPE_SDIO:
2438c2ecf20Sopenharmony_ci		/* Nothing to ioremap in the SDIO case, just fake it */
2448c2ecf20Sopenharmony_ci		mmio = (void __iomem *)baseaddr;
2458c2ecf20Sopenharmony_ci		break;
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return mmio;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic int we_support_multiple_80211_cores(struct ssb_bus *bus)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	/* More than one 802.11 core is only supported by special chips.
2548c2ecf20Sopenharmony_ci	 * There are chips with two 802.11 cores, but with dangling
2558c2ecf20Sopenharmony_ci	 * pins on the second core. Be careful and reject them here.
2568c2ecf20Sopenharmony_ci	 */
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci#ifdef CONFIG_SSB_PCIHOST
2598c2ecf20Sopenharmony_ci	if (bus->bustype == SSB_BUSTYPE_PCI) {
2608c2ecf20Sopenharmony_ci		if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
2618c2ecf20Sopenharmony_ci		    ((bus->host_pci->device == 0x4313) ||
2628c2ecf20Sopenharmony_ci		     (bus->host_pci->device == 0x431A) ||
2638c2ecf20Sopenharmony_ci		     (bus->host_pci->device == 0x4321) ||
2648c2ecf20Sopenharmony_ci		     (bus->host_pci->device == 0x4324)))
2658c2ecf20Sopenharmony_ci			return 1;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci#endif /* CONFIG_SSB_PCIHOST */
2688c2ecf20Sopenharmony_ci	return 0;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ciint ssb_bus_scan(struct ssb_bus *bus,
2728c2ecf20Sopenharmony_ci		 unsigned long baseaddr)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	int err = -ENOMEM;
2758c2ecf20Sopenharmony_ci	void __iomem *mmio;
2768c2ecf20Sopenharmony_ci	u32 idhi, cc, rev, tmp;
2778c2ecf20Sopenharmony_ci	int dev_i, i;
2788c2ecf20Sopenharmony_ci	struct ssb_device *dev;
2798c2ecf20Sopenharmony_ci	int nr_80211_cores = 0;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	mmio = ssb_ioremap(bus, baseaddr);
2828c2ecf20Sopenharmony_ci	if (!mmio)
2838c2ecf20Sopenharmony_ci		goto out;
2848c2ecf20Sopenharmony_ci	bus->mmio = mmio;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	err = scan_switchcore(bus, 0); /* Switch to first core */
2878c2ecf20Sopenharmony_ci	if (err)
2888c2ecf20Sopenharmony_ci		goto err_unmap;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	idhi = scan_read32(bus, 0, SSB_IDHIGH);
2918c2ecf20Sopenharmony_ci	cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
2928c2ecf20Sopenharmony_ci	rev = (idhi & SSB_IDHIGH_RCLO);
2938c2ecf20Sopenharmony_ci	rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	bus->nr_devices = 0;
2968c2ecf20Sopenharmony_ci	if (cc == SSB_DEV_CHIPCOMMON) {
2978c2ecf20Sopenharmony_ci		tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
3008c2ecf20Sopenharmony_ci		bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >>
3018c2ecf20Sopenharmony_ci				SSB_CHIPCO_REVSHIFT;
3028c2ecf20Sopenharmony_ci		bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
3038c2ecf20Sopenharmony_ci				    SSB_CHIPCO_PACKSHIFT;
3048c2ecf20Sopenharmony_ci		if (rev >= 4) {
3058c2ecf20Sopenharmony_ci			bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
3068c2ecf20Sopenharmony_ci					  SSB_CHIPCO_NRCORESSHIFT;
3078c2ecf20Sopenharmony_ci		}
3088c2ecf20Sopenharmony_ci		tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
3098c2ecf20Sopenharmony_ci		bus->chipco.capabilities = tmp;
3108c2ecf20Sopenharmony_ci	} else {
3118c2ecf20Sopenharmony_ci		if (bus->bustype == SSB_BUSTYPE_PCI) {
3128c2ecf20Sopenharmony_ci			bus->chip_id = pcidev_to_chipid(bus->host_pci);
3138c2ecf20Sopenharmony_ci			bus->chip_rev = bus->host_pci->revision;
3148c2ecf20Sopenharmony_ci			bus->chip_package = 0;
3158c2ecf20Sopenharmony_ci		} else {
3168c2ecf20Sopenharmony_ci			bus->chip_id = 0x4710;
3178c2ecf20Sopenharmony_ci			bus->chip_rev = 0;
3188c2ecf20Sopenharmony_ci			bus->chip_package = 0;
3198c2ecf20Sopenharmony_ci		}
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci	pr_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
3228c2ecf20Sopenharmony_ci		bus->chip_id, bus->chip_rev, bus->chip_package);
3238c2ecf20Sopenharmony_ci	if (!bus->nr_devices)
3248c2ecf20Sopenharmony_ci		bus->nr_devices = chipid_to_nrcores(bus->chip_id);
3258c2ecf20Sopenharmony_ci	if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
3268c2ecf20Sopenharmony_ci		pr_err("More than %d ssb cores found (%d)\n",
3278c2ecf20Sopenharmony_ci		       SSB_MAX_NR_CORES, bus->nr_devices);
3288c2ecf20Sopenharmony_ci		err = -EINVAL;
3298c2ecf20Sopenharmony_ci		goto err_unmap;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci	if (bus->bustype == SSB_BUSTYPE_SSB) {
3328c2ecf20Sopenharmony_ci		/* Now that we know the number of cores,
3338c2ecf20Sopenharmony_ci		 * remap the whole IO space for all cores.
3348c2ecf20Sopenharmony_ci		 */
3358c2ecf20Sopenharmony_ci		err = -ENOMEM;
3368c2ecf20Sopenharmony_ci		iounmap(mmio);
3378c2ecf20Sopenharmony_ci		mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
3388c2ecf20Sopenharmony_ci		if (!mmio)
3398c2ecf20Sopenharmony_ci			goto out;
3408c2ecf20Sopenharmony_ci		bus->mmio = mmio;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	/* Fetch basic information about each core/device */
3448c2ecf20Sopenharmony_ci	for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
3458c2ecf20Sopenharmony_ci		err = scan_switchcore(bus, i);
3468c2ecf20Sopenharmony_ci		if (err)
3478c2ecf20Sopenharmony_ci			goto err_unmap;
3488c2ecf20Sopenharmony_ci		dev = &(bus->devices[dev_i]);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		idhi = scan_read32(bus, i, SSB_IDHIGH);
3518c2ecf20Sopenharmony_ci		dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
3528c2ecf20Sopenharmony_ci		dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
3538c2ecf20Sopenharmony_ci		dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
3548c2ecf20Sopenharmony_ci		dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
3558c2ecf20Sopenharmony_ci		dev->core_index = i;
3568c2ecf20Sopenharmony_ci		dev->bus = bus;
3578c2ecf20Sopenharmony_ci		dev->ops = bus->ops;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		pr_debug("Core %d found: %s (cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
3608c2ecf20Sopenharmony_ci			 i, ssb_core_name(dev->id.coreid),
3618c2ecf20Sopenharmony_ci			 dev->id.coreid, dev->id.revision, dev->id.vendor);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		switch (dev->id.coreid) {
3648c2ecf20Sopenharmony_ci		case SSB_DEV_80211:
3658c2ecf20Sopenharmony_ci			nr_80211_cores++;
3668c2ecf20Sopenharmony_ci			if (nr_80211_cores > 1) {
3678c2ecf20Sopenharmony_ci				if (!we_support_multiple_80211_cores(bus)) {
3688c2ecf20Sopenharmony_ci					pr_debug("Ignoring additional 802.11 core\n");
3698c2ecf20Sopenharmony_ci					continue;
3708c2ecf20Sopenharmony_ci				}
3718c2ecf20Sopenharmony_ci			}
3728c2ecf20Sopenharmony_ci			break;
3738c2ecf20Sopenharmony_ci		case SSB_DEV_EXTIF:
3748c2ecf20Sopenharmony_ci#ifdef CONFIG_SSB_DRIVER_EXTIF
3758c2ecf20Sopenharmony_ci			if (bus->extif.dev) {
3768c2ecf20Sopenharmony_ci				pr_warn("WARNING: Multiple EXTIFs found\n");
3778c2ecf20Sopenharmony_ci				break;
3788c2ecf20Sopenharmony_ci			}
3798c2ecf20Sopenharmony_ci			bus->extif.dev = dev;
3808c2ecf20Sopenharmony_ci#endif /* CONFIG_SSB_DRIVER_EXTIF */
3818c2ecf20Sopenharmony_ci			break;
3828c2ecf20Sopenharmony_ci		case SSB_DEV_CHIPCOMMON:
3838c2ecf20Sopenharmony_ci			if (bus->chipco.dev) {
3848c2ecf20Sopenharmony_ci				pr_warn("WARNING: Multiple ChipCommon found\n");
3858c2ecf20Sopenharmony_ci				break;
3868c2ecf20Sopenharmony_ci			}
3878c2ecf20Sopenharmony_ci			bus->chipco.dev = dev;
3888c2ecf20Sopenharmony_ci			break;
3898c2ecf20Sopenharmony_ci		case SSB_DEV_MIPS:
3908c2ecf20Sopenharmony_ci		case SSB_DEV_MIPS_3302:
3918c2ecf20Sopenharmony_ci#ifdef CONFIG_SSB_DRIVER_MIPS
3928c2ecf20Sopenharmony_ci			if (bus->mipscore.dev) {
3938c2ecf20Sopenharmony_ci				pr_warn("WARNING: Multiple MIPS cores found\n");
3948c2ecf20Sopenharmony_ci				break;
3958c2ecf20Sopenharmony_ci			}
3968c2ecf20Sopenharmony_ci			bus->mipscore.dev = dev;
3978c2ecf20Sopenharmony_ci#endif /* CONFIG_SSB_DRIVER_MIPS */
3988c2ecf20Sopenharmony_ci			break;
3998c2ecf20Sopenharmony_ci		case SSB_DEV_PCI:
4008c2ecf20Sopenharmony_ci		case SSB_DEV_PCIE:
4018c2ecf20Sopenharmony_ci#ifdef CONFIG_SSB_DRIVER_PCICORE
4028c2ecf20Sopenharmony_ci			if (bus->bustype == SSB_BUSTYPE_PCI) {
4038c2ecf20Sopenharmony_ci				/* Ignore PCI cores on PCI-E cards.
4048c2ecf20Sopenharmony_ci				 * Ignore PCI-E cores on PCI cards.
4058c2ecf20Sopenharmony_ci				 */
4068c2ecf20Sopenharmony_ci				if (dev->id.coreid == SSB_DEV_PCI) {
4078c2ecf20Sopenharmony_ci					if (pci_is_pcie(bus->host_pci))
4088c2ecf20Sopenharmony_ci						continue;
4098c2ecf20Sopenharmony_ci				} else {
4108c2ecf20Sopenharmony_ci					if (!pci_is_pcie(bus->host_pci))
4118c2ecf20Sopenharmony_ci						continue;
4128c2ecf20Sopenharmony_ci				}
4138c2ecf20Sopenharmony_ci			}
4148c2ecf20Sopenharmony_ci			if (bus->pcicore.dev) {
4158c2ecf20Sopenharmony_ci				pr_warn("WARNING: Multiple PCI(E) cores found\n");
4168c2ecf20Sopenharmony_ci				break;
4178c2ecf20Sopenharmony_ci			}
4188c2ecf20Sopenharmony_ci			bus->pcicore.dev = dev;
4198c2ecf20Sopenharmony_ci#endif /* CONFIG_SSB_DRIVER_PCICORE */
4208c2ecf20Sopenharmony_ci			break;
4218c2ecf20Sopenharmony_ci		case SSB_DEV_ETHERNET:
4228c2ecf20Sopenharmony_ci			if (bus->bustype == SSB_BUSTYPE_PCI) {
4238c2ecf20Sopenharmony_ci				if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
4248c2ecf20Sopenharmony_ci				    (bus->host_pci->device & 0xFF00) == 0x4300) {
4258c2ecf20Sopenharmony_ci					/* This is a dangling ethernet core on a
4268c2ecf20Sopenharmony_ci					 * wireless device. Ignore it.
4278c2ecf20Sopenharmony_ci					 */
4288c2ecf20Sopenharmony_ci					continue;
4298c2ecf20Sopenharmony_ci				}
4308c2ecf20Sopenharmony_ci			}
4318c2ecf20Sopenharmony_ci			break;
4328c2ecf20Sopenharmony_ci		default:
4338c2ecf20Sopenharmony_ci			break;
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		dev_i++;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci	bus->nr_devices = dev_i;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	err = 0;
4418c2ecf20Sopenharmony_ciout:
4428c2ecf20Sopenharmony_ci	return err;
4438c2ecf20Sopenharmony_cierr_unmap:
4448c2ecf20Sopenharmony_ci	ssb_iounmap(bus);
4458c2ecf20Sopenharmony_ci	goto out;
4468c2ecf20Sopenharmony_ci}
447