18369ae33SRafał Miłecki /*
28369ae33SRafał Miłecki * Broadcom specific AMBA
38369ae33SRafał Miłecki * Bus scanning
48369ae33SRafał Miłecki *
58369ae33SRafał Miłecki * Licensed under the GNU/GPL. See COPYING for details.
68369ae33SRafał Miłecki */
78369ae33SRafał Miłecki
88369ae33SRafał Miłecki #include "scan.h"
98369ae33SRafał Miłecki #include "bcma_private.h"
108369ae33SRafał Miłecki
118369ae33SRafał Miłecki #include <linux/bcma/bcma.h>
128369ae33SRafał Miłecki #include <linux/bcma/bcma_regs.h>
138369ae33SRafał Miłecki #include <linux/pci.h>
148369ae33SRafał Miłecki #include <linux/io.h>
158369ae33SRafał Miłecki #include <linux/dma-mapping.h>
168369ae33SRafał Miłecki #include <linux/slab.h>
178369ae33SRafał Miłecki
188369ae33SRafał Miłecki struct bcma_device_id_name {
198369ae33SRafał Miłecki u16 id;
208369ae33SRafał Miłecki const char *name;
218369ae33SRafał Miłecki };
2282a7c2bbSNathan Hintz
2382a7c2bbSNathan Hintz static const struct bcma_device_id_name bcma_arm_device_names[] = {
24e1ac4b40SRafał Miłecki { BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" },
2582a7c2bbSNathan Hintz { BCMA_CORE_ARM_1176, "ARM 1176" },
2682a7c2bbSNathan Hintz { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
2782a7c2bbSNathan Hintz { BCMA_CORE_ARM_CM3, "ARM CM3" },
2882a7c2bbSNathan Hintz };
2982a7c2bbSNathan Hintz
3082a7c2bbSNathan Hintz static const struct bcma_device_id_name bcma_bcm_device_names[] = {
318369ae33SRafał Miłecki { BCMA_CORE_OOB_ROUTER, "OOB Router" },
32d2bb2b9eSRafał Miłecki { BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" },
33d2bb2b9eSRafał Miłecki { BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" },
34d2bb2b9eSRafał Miłecki { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" },
35dc6be9f5SRafał Miłecki { BCMA_CORE_NS_PCIEG2, "PCIe Gen 2" },
36dc6be9f5SRafał Miłecki { BCMA_CORE_NS_DMA, "DMA" },
37dc6be9f5SRafał Miłecki { BCMA_CORE_NS_SDIO3, "SDIO3" },
38dc6be9f5SRafał Miłecki { BCMA_CORE_NS_USB20, "USB 2.0" },
39dc6be9f5SRafał Miłecki { BCMA_CORE_NS_USB30, "USB 3.0" },
40dc6be9f5SRafał Miłecki { BCMA_CORE_NS_A9JTAG, "ARM Cortex A9 JTAG" },
41dc6be9f5SRafał Miłecki { BCMA_CORE_NS_DDR23, "Denali DDR2/DDR3 memory controller" },
42dc6be9f5SRafał Miłecki { BCMA_CORE_NS_ROM, "ROM" },
43dc6be9f5SRafał Miłecki { BCMA_CORE_NS_NAND, "NAND flash controller" },
44dc6be9f5SRafał Miłecki { BCMA_CORE_NS_QSPI, "SPI flash controller" },
45dc6be9f5SRafał Miłecki { BCMA_CORE_NS_CHIPCOMMON_B, "Chipcommon B" },
46bb4997a1SHauke Mehrtens { BCMA_CORE_ARMCA9, "ARM Cortex A9 core (ihost)" },
47d2bb2b9eSRafał Miłecki { BCMA_CORE_AMEMC, "AMEMC (DDR)" },
48d2bb2b9eSRafał Miłecki { BCMA_CORE_ALTA, "ALTA (I2S)" },
498369ae33SRafał Miłecki { BCMA_CORE_INVALID, "Invalid" },
508369ae33SRafał Miłecki { BCMA_CORE_CHIPCOMMON, "ChipCommon" },
518369ae33SRafał Miłecki { BCMA_CORE_ILINE20, "ILine 20" },
528369ae33SRafał Miłecki { BCMA_CORE_SRAM, "SRAM" },
538369ae33SRafał Miłecki { BCMA_CORE_SDRAM, "SDRAM" },
548369ae33SRafał Miłecki { BCMA_CORE_PCI, "PCI" },
558369ae33SRafał Miłecki { BCMA_CORE_ETHERNET, "Fast Ethernet" },
568369ae33SRafał Miłecki { BCMA_CORE_V90, "V90" },
578369ae33SRafał Miłecki { BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
588369ae33SRafał Miłecki { BCMA_CORE_ADSL, "ADSL" },
598369ae33SRafał Miłecki { BCMA_CORE_ILINE100, "ILine 100" },
608369ae33SRafał Miłecki { BCMA_CORE_IPSEC, "IPSEC" },
618369ae33SRafał Miłecki { BCMA_CORE_UTOPIA, "UTOPIA" },
628369ae33SRafał Miłecki { BCMA_CORE_PCMCIA, "PCMCIA" },
638369ae33SRafał Miłecki { BCMA_CORE_INTERNAL_MEM, "Internal Memory" },
648369ae33SRafał Miłecki { BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" },
658369ae33SRafał Miłecki { BCMA_CORE_OFDM, "OFDM" },
668369ae33SRafał Miłecki { BCMA_CORE_EXTIF, "EXTIF" },
678369ae33SRafał Miłecki { BCMA_CORE_80211, "IEEE 802.11" },
688369ae33SRafał Miłecki { BCMA_CORE_PHY_A, "PHY A" },
698369ae33SRafał Miłecki { BCMA_CORE_PHY_B, "PHY B" },
708369ae33SRafał Miłecki { BCMA_CORE_PHY_G, "PHY G" },
718369ae33SRafał Miłecki { BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
728369ae33SRafał Miłecki { BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
738369ae33SRafał Miłecki { BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
748369ae33SRafał Miłecki { BCMA_CORE_USB20_DEV, "USB 2.0 Device" },
758369ae33SRafał Miłecki { BCMA_CORE_SDIO_HOST, "SDIO Host" },
768369ae33SRafał Miłecki { BCMA_CORE_ROBOSWITCH, "Roboswitch" },
778369ae33SRafał Miłecki { BCMA_CORE_PARA_ATA, "PATA" },
788369ae33SRafał Miłecki { BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" },
798369ae33SRafał Miłecki { BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" },
808369ae33SRafał Miłecki { BCMA_CORE_PCIE, "PCIe" },
818369ae33SRafał Miłecki { BCMA_CORE_PHY_N, "PHY N" },
828369ae33SRafał Miłecki { BCMA_CORE_SRAM_CTL, "SRAM Controller" },
838369ae33SRafał Miłecki { BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
848369ae33SRafał Miłecki { BCMA_CORE_PHY_LP, "PHY LP" },
858369ae33SRafał Miłecki { BCMA_CORE_PMU, "PMU" },
868369ae33SRafał Miłecki { BCMA_CORE_PHY_SSN, "PHY SSN" },
878369ae33SRafał Miłecki { BCMA_CORE_SDIO_DEV, "SDIO Device" },
888369ae33SRafał Miłecki { BCMA_CORE_PHY_HT, "PHY HT" },
898369ae33SRafał Miłecki { BCMA_CORE_MAC_GBIT, "GBit MAC" },
908369ae33SRafał Miłecki { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
918369ae33SRafał Miłecki { BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
928369ae33SRafał Miłecki { BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" },
938369ae33SRafał Miłecki { BCMA_CORE_SHARED_COMMON, "Common Shared" },
948369ae33SRafał Miłecki { BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" },
958369ae33SRafał Miłecki { BCMA_CORE_SPI_HOST, "SPI Host" },
968369ae33SRafał Miłecki { BCMA_CORE_I2S, "I2S" },
978369ae33SRafał Miłecki { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
988369ae33SRafał Miłecki { BCMA_CORE_SHIM, "SHIM" },
99d4988d4cSRafał Miłecki { BCMA_CORE_PCIE2, "PCIe Gen2" },
100d4988d4cSRafał Miłecki { BCMA_CORE_ARM_CR4, "ARM CR4" },
1017267bcdaSRafał Miłecki { BCMA_CORE_GCI, "GCI" },
1027267bcdaSRafał Miłecki { BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
1037267bcdaSRafał Miłecki { BCMA_CORE_ARM_CA7, "ARM CA7" },
1048369ae33SRafał Miłecki { BCMA_CORE_DEFAULT, "Default" },
1058369ae33SRafał Miłecki };
1068369ae33SRafał Miłecki
10782a7c2bbSNathan Hintz static const struct bcma_device_id_name bcma_mips_device_names[] = {
10882a7c2bbSNathan Hintz { BCMA_CORE_MIPS, "MIPS" },
10982a7c2bbSNathan Hintz { BCMA_CORE_MIPS_3302, "MIPS 3302" },
11082a7c2bbSNathan Hintz { BCMA_CORE_MIPS_74K, "MIPS 74K" },
11182a7c2bbSNathan Hintz };
11282a7c2bbSNathan Hintz
bcma_device_name(const struct bcma_device_id * id)11382a7c2bbSNathan Hintz static const char *bcma_device_name(const struct bcma_device_id *id)
11482a7c2bbSNathan Hintz {
11582a7c2bbSNathan Hintz const struct bcma_device_id_name *names;
11682a7c2bbSNathan Hintz int size, i;
11782a7c2bbSNathan Hintz
11882a7c2bbSNathan Hintz /* search manufacturer specific names */
11982a7c2bbSNathan Hintz switch (id->manuf) {
12082a7c2bbSNathan Hintz case BCMA_MANUF_ARM:
12182a7c2bbSNathan Hintz names = bcma_arm_device_names;
12282a7c2bbSNathan Hintz size = ARRAY_SIZE(bcma_arm_device_names);
12382a7c2bbSNathan Hintz break;
12482a7c2bbSNathan Hintz case BCMA_MANUF_BCM:
12582a7c2bbSNathan Hintz names = bcma_bcm_device_names;
12682a7c2bbSNathan Hintz size = ARRAY_SIZE(bcma_bcm_device_names);
12782a7c2bbSNathan Hintz break;
12882a7c2bbSNathan Hintz case BCMA_MANUF_MIPS:
12982a7c2bbSNathan Hintz names = bcma_mips_device_names;
13082a7c2bbSNathan Hintz size = ARRAY_SIZE(bcma_mips_device_names);
13182a7c2bbSNathan Hintz break;
13282a7c2bbSNathan Hintz default:
13382a7c2bbSNathan Hintz return "UNKNOWN";
1348369ae33SRafał Miłecki }
13582a7c2bbSNathan Hintz
13682a7c2bbSNathan Hintz for (i = 0; i < size; i++) {
13782a7c2bbSNathan Hintz if (names[i].id == id->id)
13882a7c2bbSNathan Hintz return names[i].name;
1398369ae33SRafał Miłecki }
14082a7c2bbSNathan Hintz
1418369ae33SRafał Miłecki return "UNKNOWN";
1428369ae33SRafał Miłecki }
1438369ae33SRafał Miłecki
bcma_scan_read32(struct bcma_bus * bus,u16 offset)144*9fc8048cSZenghui Yu static u32 bcma_scan_read32(struct bcma_bus *bus, u16 offset)
1458369ae33SRafał Miłecki {
1468369ae33SRafał Miłecki return readl(bus->mmio + offset);
1478369ae33SRafał Miłecki }
1488369ae33SRafał Miłecki
bcma_scan_switch_core(struct bcma_bus * bus,u32 addr)1498369ae33SRafał Miłecki static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
1508369ae33SRafał Miłecki {
1518369ae33SRafał Miłecki if (bus->hosttype == BCMA_HOSTTYPE_PCI)
1528369ae33SRafał Miłecki pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN,
1538369ae33SRafał Miłecki addr);
1548369ae33SRafał Miłecki }
1558369ae33SRafał Miłecki
bcma_erom_get_ent(struct bcma_bus * bus,u32 __iomem ** eromptr)1560b8d6e59SHauke Mehrtens static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 __iomem **eromptr)
1578369ae33SRafał Miłecki {
1588369ae33SRafał Miłecki u32 ent = readl(*eromptr);
1598369ae33SRafał Miłecki (*eromptr)++;
1608369ae33SRafał Miłecki return ent;
1618369ae33SRafał Miłecki }
1628369ae33SRafał Miłecki
bcma_erom_push_ent(u32 __iomem ** eromptr)1630b8d6e59SHauke Mehrtens static void bcma_erom_push_ent(u32 __iomem **eromptr)
1648369ae33SRafał Miłecki {
1658369ae33SRafał Miłecki (*eromptr)--;
1668369ae33SRafał Miłecki }
1678369ae33SRafał Miłecki
bcma_erom_get_ci(struct bcma_bus * bus,u32 __iomem ** eromptr)1680b8d6e59SHauke Mehrtens static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 __iomem **eromptr)
1698369ae33SRafał Miłecki {
1708369ae33SRafał Miłecki u32 ent = bcma_erom_get_ent(bus, eromptr);
1718369ae33SRafał Miłecki if (!(ent & SCAN_ER_VALID))
1728369ae33SRafał Miłecki return -ENOENT;
1738369ae33SRafał Miłecki if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI)
1748369ae33SRafał Miłecki return -ENOENT;
1758369ae33SRafał Miłecki return ent;
1768369ae33SRafał Miłecki }
1778369ae33SRafał Miłecki
bcma_erom_is_end(struct bcma_bus * bus,u32 __iomem ** eromptr)1780b8d6e59SHauke Mehrtens static bool bcma_erom_is_end(struct bcma_bus *bus, u32 __iomem **eromptr)
1798369ae33SRafał Miłecki {
1808369ae33SRafał Miłecki u32 ent = bcma_erom_get_ent(bus, eromptr);
1818369ae33SRafał Miłecki bcma_erom_push_ent(eromptr);
1828369ae33SRafał Miłecki return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
1838369ae33SRafał Miłecki }
1848369ae33SRafał Miłecki
bcma_erom_is_bridge(struct bcma_bus * bus,u32 __iomem ** eromptr)1850b8d6e59SHauke Mehrtens static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 __iomem **eromptr)
1868369ae33SRafał Miłecki {
1878369ae33SRafał Miłecki u32 ent = bcma_erom_get_ent(bus, eromptr);
1888369ae33SRafał Miłecki bcma_erom_push_ent(eromptr);
1898369ae33SRafał Miłecki return (((ent & SCAN_ER_VALID)) &&
1908369ae33SRafał Miłecki ((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) &&
1918369ae33SRafał Miłecki ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
1928369ae33SRafał Miłecki }
1938369ae33SRafał Miłecki
bcma_erom_skip_component(struct bcma_bus * bus,u32 __iomem ** eromptr)1940b8d6e59SHauke Mehrtens static void bcma_erom_skip_component(struct bcma_bus *bus, u32 __iomem **eromptr)
1958369ae33SRafał Miłecki {
1968369ae33SRafał Miłecki u32 ent;
1978369ae33SRafał Miłecki while (1) {
1988369ae33SRafał Miłecki ent = bcma_erom_get_ent(bus, eromptr);
1998369ae33SRafał Miłecki if ((ent & SCAN_ER_VALID) &&
2008369ae33SRafał Miłecki ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI))
2018369ae33SRafał Miłecki break;
2028369ae33SRafał Miłecki if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID))
2038369ae33SRafał Miłecki break;
2048369ae33SRafał Miłecki }
2058369ae33SRafał Miłecki bcma_erom_push_ent(eromptr);
2068369ae33SRafał Miłecki }
2078369ae33SRafał Miłecki
bcma_erom_get_mst_port(struct bcma_bus * bus,u32 __iomem ** eromptr)2080b8d6e59SHauke Mehrtens static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
2098369ae33SRafał Miłecki {
2108369ae33SRafał Miłecki u32 ent = bcma_erom_get_ent(bus, eromptr);
2118369ae33SRafał Miłecki if (!(ent & SCAN_ER_VALID))
2128369ae33SRafał Miłecki return -ENOENT;
2138369ae33SRafał Miłecki if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP)
2148369ae33SRafał Miłecki return -ENOENT;
2158369ae33SRafał Miłecki return ent;
2168369ae33SRafał Miłecki }
2178369ae33SRafał Miłecki
bcma_erom_get_addr_desc(struct bcma_bus * bus,u32 __iomem ** eromptr,u32 type,u8 port)218fd4edf19SHauke Mehrtens static u32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
2198369ae33SRafał Miłecki u32 type, u8 port)
2208369ae33SRafał Miłecki {
22192d26d1aSZheng Yongjun u32 addrl;
2228369ae33SRafał Miłecki u32 size;
2238369ae33SRafał Miłecki
2248369ae33SRafał Miłecki u32 ent = bcma_erom_get_ent(bus, eromptr);
2258369ae33SRafał Miłecki if ((!(ent & SCAN_ER_VALID)) ||
2268369ae33SRafał Miłecki ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) ||
2278369ae33SRafał Miłecki ((ent & SCAN_ADDR_TYPE) != type) ||
2288369ae33SRafał Miłecki (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
2298369ae33SRafał Miłecki bcma_erom_push_ent(eromptr);
230fd4edf19SHauke Mehrtens return (u32)-EINVAL;
2318369ae33SRafał Miłecki }
2328369ae33SRafał Miłecki
2338369ae33SRafał Miłecki addrl = ent & SCAN_ADDR_ADDR;
2348369ae33SRafał Miłecki if (ent & SCAN_ADDR_AG32)
23592d26d1aSZheng Yongjun bcma_erom_get_ent(bus, eromptr);
2368369ae33SRafał Miłecki
2378369ae33SRafał Miłecki if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) {
2388369ae33SRafał Miłecki size = bcma_erom_get_ent(bus, eromptr);
2398369ae33SRafał Miłecki if (size & SCAN_SIZE_SG32)
24092d26d1aSZheng Yongjun bcma_erom_get_ent(bus, eromptr);
241f4279393Syu kuai }
2428369ae33SRafał Miłecki
2438369ae33SRafał Miłecki return addrl;
2448369ae33SRafał Miłecki }
2458369ae33SRafał Miłecki
bcma_find_core_by_index(struct bcma_bus * bus,u16 index)246517f43e5SHauke Mehrtens static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
247517f43e5SHauke Mehrtens u16 index)
248517f43e5SHauke Mehrtens {
249517f43e5SHauke Mehrtens struct bcma_device *core;
250517f43e5SHauke Mehrtens
251517f43e5SHauke Mehrtens list_for_each_entry(core, &bus->cores, list) {
252517f43e5SHauke Mehrtens if (core->core_index == index)
253517f43e5SHauke Mehrtens return core;
254517f43e5SHauke Mehrtens }
255517f43e5SHauke Mehrtens return NULL;
256517f43e5SHauke Mehrtens }
257517f43e5SHauke Mehrtens
bcma_find_core_reverse(struct bcma_bus * bus,u16 coreid)2585f2d6171SHauke Mehrtens static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 coreid)
2595f2d6171SHauke Mehrtens {
2605f2d6171SHauke Mehrtens struct bcma_device *core;
2615f2d6171SHauke Mehrtens
2625f2d6171SHauke Mehrtens list_for_each_entry_reverse(core, &bus->cores, list) {
2635f2d6171SHauke Mehrtens if (core->id.id == coreid)
2645f2d6171SHauke Mehrtens return core;
2655f2d6171SHauke Mehrtens }
2665f2d6171SHauke Mehrtens return NULL;
2675f2d6171SHauke Mehrtens }
2685f2d6171SHauke Mehrtens
269aaa2ced1SHauke Mehrtens #define IS_ERR_VALUE_U32(x) ((x) >= (u32)-MAX_ERRNO)
270aaa2ced1SHauke Mehrtens
bcma_get_next_core(struct bcma_bus * bus,u32 __iomem ** eromptr,struct bcma_device_id * match,int core_num,struct bcma_device * core)271982eee67SHauke Mehrtens static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
272517f43e5SHauke Mehrtens struct bcma_device_id *match, int core_num,
273982eee67SHauke Mehrtens struct bcma_device *core)
274982eee67SHauke Mehrtens {
275fd4edf19SHauke Mehrtens u32 tmp;
27623a2f39cSHauke Mehrtens u8 i, j, k;
277982eee67SHauke Mehrtens s32 cia, cib;
278982eee67SHauke Mehrtens u8 ports[2], wrappers[2];
279982eee67SHauke Mehrtens
280982eee67SHauke Mehrtens /* get CIs */
281982eee67SHauke Mehrtens cia = bcma_erom_get_ci(bus, eromptr);
282982eee67SHauke Mehrtens if (cia < 0) {
283982eee67SHauke Mehrtens bcma_erom_push_ent(eromptr);
284982eee67SHauke Mehrtens if (bcma_erom_is_end(bus, eromptr))
285982eee67SHauke Mehrtens return -ESPIPE;
286982eee67SHauke Mehrtens return -EILSEQ;
287982eee67SHauke Mehrtens }
288982eee67SHauke Mehrtens cib = bcma_erom_get_ci(bus, eromptr);
289982eee67SHauke Mehrtens if (cib < 0)
290982eee67SHauke Mehrtens return -EILSEQ;
291982eee67SHauke Mehrtens
292982eee67SHauke Mehrtens /* parse CIs */
293982eee67SHauke Mehrtens core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
294982eee67SHauke Mehrtens core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
295982eee67SHauke Mehrtens core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
296982eee67SHauke Mehrtens ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
297982eee67SHauke Mehrtens ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
298982eee67SHauke Mehrtens wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
299982eee67SHauke Mehrtens wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
300982eee67SHauke Mehrtens core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
301982eee67SHauke Mehrtens
302982eee67SHauke Mehrtens if (((core->id.manuf == BCMA_MANUF_ARM) &&
303982eee67SHauke Mehrtens (core->id.id == 0xFFF)) ||
304982eee67SHauke Mehrtens (ports[1] == 0)) {
305982eee67SHauke Mehrtens bcma_erom_skip_component(bus, eromptr);
306982eee67SHauke Mehrtens return -ENXIO;
307982eee67SHauke Mehrtens }
308982eee67SHauke Mehrtens
309982eee67SHauke Mehrtens /* check if component is a core at all */
310982eee67SHauke Mehrtens if (wrappers[0] + wrappers[1] == 0) {
311e1ac4b40SRafał Miłecki /* Some specific cores don't need wrappers */
312e1ac4b40SRafał Miłecki switch (core->id.id) {
313e1ac4b40SRafał Miłecki case BCMA_CORE_4706_MAC_GBIT_COMMON:
3141716bcf3SHauke Mehrtens case BCMA_CORE_NS_CHIPCOMMON_B:
3150c06f5d4SRafał Miłecki case BCMA_CORE_PMU:
3160c06f5d4SRafał Miłecki case BCMA_CORE_GCI:
317e1ac4b40SRafał Miłecki /* Not used yet: case BCMA_CORE_OOB_ROUTER: */
318e1ac4b40SRafał Miłecki break;
319e1ac4b40SRafał Miłecki default:
320982eee67SHauke Mehrtens bcma_erom_skip_component(bus, eromptr);
321982eee67SHauke Mehrtens return -ENXIO;
322982eee67SHauke Mehrtens }
323e1ac4b40SRafał Miłecki }
324982eee67SHauke Mehrtens
325982eee67SHauke Mehrtens if (bcma_erom_is_bridge(bus, eromptr)) {
326982eee67SHauke Mehrtens bcma_erom_skip_component(bus, eromptr);
327982eee67SHauke Mehrtens return -ENXIO;
328982eee67SHauke Mehrtens }
329982eee67SHauke Mehrtens
330517f43e5SHauke Mehrtens if (bcma_find_core_by_index(bus, core_num)) {
331517f43e5SHauke Mehrtens bcma_erom_skip_component(bus, eromptr);
332517f43e5SHauke Mehrtens return -ENODEV;
333517f43e5SHauke Mehrtens }
334517f43e5SHauke Mehrtens
335517f43e5SHauke Mehrtens if (match && ((match->manuf != BCMA_ANY_MANUF &&
336517f43e5SHauke Mehrtens match->manuf != core->id.manuf) ||
337517f43e5SHauke Mehrtens (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
338517f43e5SHauke Mehrtens (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
339517f43e5SHauke Mehrtens (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
340517f43e5SHauke Mehrtens )) {
341517f43e5SHauke Mehrtens bcma_erom_skip_component(bus, eromptr);
342517f43e5SHauke Mehrtens return -ENODEV;
343517f43e5SHauke Mehrtens }
344517f43e5SHauke Mehrtens
345982eee67SHauke Mehrtens /* get & parse master ports */
346982eee67SHauke Mehrtens for (i = 0; i < ports[0]; i++) {
3474e0d8cc1SDan Carpenter s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
348982eee67SHauke Mehrtens if (mst_port_d < 0)
349982eee67SHauke Mehrtens return -EILSEQ;
350982eee67SHauke Mehrtens }
351982eee67SHauke Mehrtens
352e167d9fbSHauke Mehrtens /* First Slave Address Descriptor should be port 0:
353e167d9fbSHauke Mehrtens * the main register space for the core
354e167d9fbSHauke Mehrtens */
355e167d9fbSHauke Mehrtens tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
356aaa2ced1SHauke Mehrtens if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
357e167d9fbSHauke Mehrtens /* Try again to see if it is a bridge */
358e167d9fbSHauke Mehrtens tmp = bcma_erom_get_addr_desc(bus, eromptr,
359e167d9fbSHauke Mehrtens SCAN_ADDR_TYPE_BRIDGE, 0);
360aaa2ced1SHauke Mehrtens if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
361e167d9fbSHauke Mehrtens return -EILSEQ;
362e167d9fbSHauke Mehrtens } else {
3633d9d8af3SRafał Miłecki bcma_info(bus, "Bridge found\n");
364e167d9fbSHauke Mehrtens return -ENXIO;
365e167d9fbSHauke Mehrtens }
366e167d9fbSHauke Mehrtens }
367e167d9fbSHauke Mehrtens core->addr = tmp;
368e167d9fbSHauke Mehrtens
369982eee67SHauke Mehrtens /* get & parse slave ports */
37023a2f39cSHauke Mehrtens k = 0;
371982eee67SHauke Mehrtens for (i = 0; i < ports[1]; i++) {
372982eee67SHauke Mehrtens for (j = 0; ; j++) {
373982eee67SHauke Mehrtens tmp = bcma_erom_get_addr_desc(bus, eromptr,
374982eee67SHauke Mehrtens SCAN_ADDR_TYPE_SLAVE, i);
375aaa2ced1SHauke Mehrtens if (IS_ERR_VALUE_U32(tmp)) {
376982eee67SHauke Mehrtens /* no more entries for port _i_ */
377982eee67SHauke Mehrtens /* pr_debug("erom: slave port %d "
378982eee67SHauke Mehrtens * "has %d descriptors\n", i, j); */
379982eee67SHauke Mehrtens break;
38023a2f39cSHauke Mehrtens } else if (k < ARRAY_SIZE(core->addr_s)) {
38123a2f39cSHauke Mehrtens core->addr_s[k] = tmp;
38223a2f39cSHauke Mehrtens k++;
383982eee67SHauke Mehrtens }
384982eee67SHauke Mehrtens }
385982eee67SHauke Mehrtens }
386982eee67SHauke Mehrtens
387982eee67SHauke Mehrtens /* get & parse master wrappers */
388982eee67SHauke Mehrtens for (i = 0; i < wrappers[0]; i++) {
389982eee67SHauke Mehrtens for (j = 0; ; j++) {
390982eee67SHauke Mehrtens tmp = bcma_erom_get_addr_desc(bus, eromptr,
391982eee67SHauke Mehrtens SCAN_ADDR_TYPE_MWRAP, i);
392aaa2ced1SHauke Mehrtens if (IS_ERR_VALUE_U32(tmp)) {
393982eee67SHauke Mehrtens /* no more entries for port _i_ */
394982eee67SHauke Mehrtens /* pr_debug("erom: master wrapper %d "
395982eee67SHauke Mehrtens * "has %d descriptors\n", i, j); */
396982eee67SHauke Mehrtens break;
397982eee67SHauke Mehrtens } else {
398982eee67SHauke Mehrtens if (i == 0 && j == 0)
399982eee67SHauke Mehrtens core->wrap = tmp;
400982eee67SHauke Mehrtens }
401982eee67SHauke Mehrtens }
402982eee67SHauke Mehrtens }
403982eee67SHauke Mehrtens
404982eee67SHauke Mehrtens /* get & parse slave wrappers */
405982eee67SHauke Mehrtens for (i = 0; i < wrappers[1]; i++) {
406982eee67SHauke Mehrtens u8 hack = (ports[1] == 1) ? 0 : 1;
407982eee67SHauke Mehrtens for (j = 0; ; j++) {
408982eee67SHauke Mehrtens tmp = bcma_erom_get_addr_desc(bus, eromptr,
409982eee67SHauke Mehrtens SCAN_ADDR_TYPE_SWRAP, i + hack);
410aaa2ced1SHauke Mehrtens if (IS_ERR_VALUE_U32(tmp)) {
411982eee67SHauke Mehrtens /* no more entries for port _i_ */
412982eee67SHauke Mehrtens /* pr_debug("erom: master wrapper %d "
413982eee67SHauke Mehrtens * has %d descriptors\n", i, j); */
414982eee67SHauke Mehrtens break;
415982eee67SHauke Mehrtens } else {
416982eee67SHauke Mehrtens if (wrappers[0] == 0 && !i && !j)
417982eee67SHauke Mehrtens core->wrap = tmp;
418982eee67SHauke Mehrtens }
419982eee67SHauke Mehrtens }
420982eee67SHauke Mehrtens }
421ecd177c2SHauke Mehrtens if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
4224bdc0d67SChristoph Hellwig core->io_addr = ioremap(core->addr, BCMA_CORE_SIZE);
423ecd177c2SHauke Mehrtens if (!core->io_addr)
424ecd177c2SHauke Mehrtens return -ENOMEM;
425ecf47e9bSHauke Mehrtens if (core->wrap) {
4264bdc0d67SChristoph Hellwig core->io_wrap = ioremap(core->wrap,
427ecf47e9bSHauke Mehrtens BCMA_CORE_SIZE);
428ecd177c2SHauke Mehrtens if (!core->io_wrap) {
429ecd177c2SHauke Mehrtens iounmap(core->io_addr);
430ecd177c2SHauke Mehrtens return -ENOMEM;
431ecd177c2SHauke Mehrtens }
432ecd177c2SHauke Mehrtens }
433ecf47e9bSHauke Mehrtens }
434982eee67SHauke Mehrtens return 0;
435982eee67SHauke Mehrtens }
436982eee67SHauke Mehrtens
bcma_detect_chip(struct bcma_bus * bus)437799038eaSRafał Miłecki void bcma_detect_chip(struct bcma_bus *bus)
4388369ae33SRafał Miłecki {
4398369ae33SRafał Miłecki s32 tmp;
440f0d4724bSHauke Mehrtens struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
441fbf01990SRafał Miłecki char chip_id[8];
4428369ae33SRafał Miłecki
4438369ae33SRafał Miłecki bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
4448369ae33SRafał Miłecki
445*9fc8048cSZenghui Yu tmp = bcma_scan_read32(bus, BCMA_CC_ID);
446f0d4724bSHauke Mehrtens chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
447f0d4724bSHauke Mehrtens chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
448f0d4724bSHauke Mehrtens chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
449fbf01990SRafał Miłecki
450fbf01990SRafał Miłecki snprintf(chip_id, ARRAY_SIZE(chip_id),
451fbf01990SRafał Miłecki (chipinfo->id > 0x9999) ? "%d" : "0x%04X", chipinfo->id);
452fbf01990SRafał Miłecki bcma_info(bus, "Found chip with id %s, rev 0x%02X and package 0x%02X\n",
453fbf01990SRafał Miłecki chip_id, chipinfo->rev, chipinfo->pkg);
45467a5c29eSHauke Mehrtens }
45567a5c29eSHauke Mehrtens
bcma_bus_scan(struct bcma_bus * bus)45667a5c29eSHauke Mehrtens int bcma_bus_scan(struct bcma_bus *bus)
45767a5c29eSHauke Mehrtens {
45867a5c29eSHauke Mehrtens u32 erombase;
45967a5c29eSHauke Mehrtens u32 __iomem *eromptr, *eromend;
46067a5c29eSHauke Mehrtens
461517f43e5SHauke Mehrtens int err, core_num = 0;
46267a5c29eSHauke Mehrtens
463c5ed1df7SRafał Miłecki /* Skip if bus was already scanned (e.g. during early register) */
464c5ed1df7SRafał Miłecki if (bus->nr_cores)
465c5ed1df7SRafał Miłecki return 0;
466c5ed1df7SRafał Miłecki
467*9fc8048cSZenghui Yu erombase = bcma_scan_read32(bus, BCMA_CC_EROM);
468ecd177c2SHauke Mehrtens if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
4694bdc0d67SChristoph Hellwig eromptr = ioremap(erombase, BCMA_CORE_SIZE);
470ecd177c2SHauke Mehrtens if (!eromptr)
471ecd177c2SHauke Mehrtens return -ENOMEM;
472ecd177c2SHauke Mehrtens } else {
4738369ae33SRafał Miłecki eromptr = bus->mmio;
474ecd177c2SHauke Mehrtens }
475ecd177c2SHauke Mehrtens
4768369ae33SRafał Miłecki eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
4778369ae33SRafał Miłecki
4788369ae33SRafał Miłecki bcma_scan_switch_core(bus, erombase);
4798369ae33SRafał Miłecki
4808369ae33SRafał Miłecki while (eromptr < eromend) {
4815f2d6171SHauke Mehrtens struct bcma_device *other_core;
4828369ae33SRafał Miłecki struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
4839dbf5f55SHauke Mehrtens if (!core) {
4849dbf5f55SHauke Mehrtens err = -ENOMEM;
4859dbf5f55SHauke Mehrtens goto out;
4869dbf5f55SHauke Mehrtens }
4878369ae33SRafał Miłecki INIT_LIST_HEAD(&core->list);
4888369ae33SRafał Miłecki core->bus = bus;
4898369ae33SRafał Miłecki
490517f43e5SHauke Mehrtens err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
491f9721ed2SJesper Juhl if (err < 0) {
492f9721ed2SJesper Juhl kfree(core);
493517f43e5SHauke Mehrtens if (err == -ENODEV) {
494517f43e5SHauke Mehrtens core_num++;
495517f43e5SHauke Mehrtens continue;
496f9721ed2SJesper Juhl } else if (err == -ENXIO) {
4978369ae33SRafał Miłecki continue;
498f9721ed2SJesper Juhl } else if (err == -ESPIPE) {
4998369ae33SRafał Miłecki break;
500f9721ed2SJesper Juhl }
5019dbf5f55SHauke Mehrtens goto out;
502f9721ed2SJesper Juhl }
5038369ae33SRafał Miłecki
504517f43e5SHauke Mehrtens core->core_index = core_num++;
505517f43e5SHauke Mehrtens bus->nr_cores++;
5065f2d6171SHauke Mehrtens other_core = bcma_find_core_reverse(bus, core->id.id);
5075f2d6171SHauke Mehrtens core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
508ab54bc84SRafał Miłecki bcma_prepare_core(bus, core);
509517f43e5SHauke Mehrtens
5103d9d8af3SRafał Miłecki bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
511517f43e5SHauke Mehrtens core->core_index, bcma_device_name(&core->id),
5128369ae33SRafał Miłecki core->id.manuf, core->id.id, core->id.rev,
5138369ae33SRafał Miłecki core->id.class);
5148369ae33SRafał Miłecki
515c334e25cSRafał Miłecki list_add_tail(&core->list, &bus->cores);
5168369ae33SRafał Miłecki }
5178369ae33SRafał Miłecki
5189dbf5f55SHauke Mehrtens err = 0;
5199dbf5f55SHauke Mehrtens out:
520ecd177c2SHauke Mehrtens if (bus->hosttype == BCMA_HOSTTYPE_SOC)
521ecd177c2SHauke Mehrtens iounmap(eromptr);
522ecd177c2SHauke Mehrtens
5239dbf5f55SHauke Mehrtens return err;
5248369ae33SRafał Miłecki }
525