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