18369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki/*
28369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki * Broadcom specific AMBA
38369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki * Bus scanning
48369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki *
58369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki * Licensed under the GNU/GPL. See COPYING for details.
68369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki */
78369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
88369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki#include "scan.h"
98369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki#include "bcma_private.h"
108369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
118369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki#include <linux/bcma/bcma.h>
128369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki#include <linux/bcma/bcma_regs.h>
138369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki#include <linux/pci.h>
148369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki#include <linux/io.h>
158369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki#include <linux/dma-mapping.h>
168369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki#include <linux/slab.h>
178369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
188369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłeckistruct bcma_device_id_name {
198369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u16 id;
208369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	const char *name;
218369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki};
2282a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz
2382a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintzstatic const struct bcma_device_id_name bcma_arm_device_names[] = {
24e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki	{ BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" },
2582a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	{ BCMA_CORE_ARM_1176, "ARM 1176" },
2682a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	{ BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
2782a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	{ BCMA_CORE_ARM_CM3, "ARM CM3" },
2882a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz};
2982a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz
3082a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintzstatic const struct bcma_device_id_name bcma_bcm_device_names[] = {
318369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_OOB_ROUTER, "OOB Router" },
32d2bb2b9e9161d221badafae063d0c62b41bf3078Rafał Miłecki	{ BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" },
33d2bb2b9e9161d221badafae063d0c62b41bf3078Rafał Miłecki	{ BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" },
34d2bb2b9e9161d221badafae063d0c62b41bf3078Rafał Miłecki	{ BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" },
35dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_PCIEG2, "PCIe Gen 2" },
36dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_DMA, "DMA" },
37dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_SDIO3, "SDIO3" },
38dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_USB20, "USB 2.0" },
39dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_USB30, "USB 3.0" },
40dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_A9JTAG, "ARM Cortex A9 JTAG" },
41dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_DDR23, "Denali DDR2/DDR3 memory controller" },
42dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_ROM, "ROM" },
43dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_NAND, "NAND flash controller" },
44dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_QSPI, "SPI flash controller" },
45dc6be9f54a4ecb0a09765d1f515ed947d86b7528Rafał Miłecki	{ BCMA_CORE_NS_CHIPCOMMON_B, "Chipcommon B" },
46bb4997a1afbff61084b243d62aaaf23ea38a290eHauke Mehrtens	{ BCMA_CORE_ARMCA9, "ARM Cortex A9 core (ihost)" },
47d2bb2b9e9161d221badafae063d0c62b41bf3078Rafał Miłecki	{ BCMA_CORE_AMEMC, "AMEMC (DDR)" },
48d2bb2b9e9161d221badafae063d0c62b41bf3078Rafał Miłecki	{ BCMA_CORE_ALTA, "ALTA (I2S)" },
498369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_INVALID, "Invalid" },
508369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_CHIPCOMMON, "ChipCommon" },
518369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_ILINE20, "ILine 20" },
528369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SRAM, "SRAM" },
538369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SDRAM, "SDRAM" },
548369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PCI, "PCI" },
558369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_ETHERNET, "Fast Ethernet" },
568369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_V90, "V90" },
578369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
588369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_ADSL, "ADSL" },
598369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_ILINE100, "ILine 100" },
608369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_IPSEC, "IPSEC" },
618369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_UTOPIA, "UTOPIA" },
628369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PCMCIA, "PCMCIA" },
638369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_INTERNAL_MEM, "Internal Memory" },
648369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" },
658369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_OFDM, "OFDM" },
668369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_EXTIF, "EXTIF" },
678369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_80211, "IEEE 802.11" },
688369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PHY_A, "PHY A" },
698369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PHY_B, "PHY B" },
708369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PHY_G, "PHY G" },
718369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
728369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
738369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
748369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_USB20_DEV, "USB 2.0 Device" },
758369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SDIO_HOST, "SDIO Host" },
768369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_ROBOSWITCH, "Roboswitch" },
778369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PARA_ATA, "PATA" },
788369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" },
798369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" },
808369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PCIE, "PCIe" },
818369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PHY_N, "PHY N" },
828369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SRAM_CTL, "SRAM Controller" },
838369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
848369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PHY_LP, "PHY LP" },
858369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PMU, "PMU" },
868369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PHY_SSN, "PHY SSN" },
878369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SDIO_DEV, "SDIO Device" },
888369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PHY_HT, "PHY HT" },
898369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_MAC_GBIT, "GBit MAC" },
908369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
918369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
928369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" },
938369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SHARED_COMMON, "Common Shared" },
948369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" },
958369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SPI_HOST, "SPI Host" },
968369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_I2S, "I2S" },
978369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
988369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_SHIM, "SHIM" },
99d4988d4c733ba0b61cb372edd3d1992d26dd10d3Rafał Miłecki	{ BCMA_CORE_PCIE2, "PCIe Gen2" },
100d4988d4c733ba0b61cb372edd3d1992d26dd10d3Rafał Miłecki	{ BCMA_CORE_ARM_CR4, "ARM CR4" },
1018369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	{ BCMA_CORE_DEFAULT, "Default" },
1028369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki};
10382a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz
10482a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintzstatic const struct bcma_device_id_name bcma_mips_device_names[] = {
10582a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	{ BCMA_CORE_MIPS, "MIPS" },
10682a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	{ BCMA_CORE_MIPS_3302, "MIPS 3302" },
10782a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	{ BCMA_CORE_MIPS_74K, "MIPS 74K" },
10882a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz};
10982a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz
11082a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintzstatic const char *bcma_device_name(const struct bcma_device_id *id)
1118369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
11282a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	const struct bcma_device_id_name *names;
11382a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	int size, i;
1148369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
11582a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	/* search manufacturer specific names */
11682a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	switch (id->manuf) {
11782a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	case BCMA_MANUF_ARM:
11882a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		names = bcma_arm_device_names;
11982a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		size = ARRAY_SIZE(bcma_arm_device_names);
12082a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		break;
12182a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	case BCMA_MANUF_BCM:
12282a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		names = bcma_bcm_device_names;
12382a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		size = ARRAY_SIZE(bcma_bcm_device_names);
12482a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		break;
12582a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	case BCMA_MANUF_MIPS:
12682a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		names = bcma_mips_device_names;
12782a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		size = ARRAY_SIZE(bcma_mips_device_names);
12882a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		break;
12982a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	default:
13082a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		return "UNKNOWN";
1318369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	}
13282a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz
13382a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	for (i = 0; i < size; i++) {
13482a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz		if (names[i].id == id->id)
13582a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz			return names[i].name;
13682a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz	}
13782a7c2bb5f57fd9f610f9e6d7c532033bebfa0ccNathan Hintz
1388369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	return "UNKNOWN";
1398369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
1408369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
1418369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłeckistatic u32 bcma_scan_read32(struct bcma_bus *bus, u8 current_coreidx,
1428369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		       u16 offset)
1438369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
1448369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	return readl(bus->mmio + offset);
1458369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
1468369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
1478369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłeckistatic void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
1488369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
1498369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	if (bus->hosttype == BCMA_HOSTTYPE_PCI)
1508369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN,
1518369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki				       addr);
1528369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
1538369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
1540b8d6e59a128f4fecce9ea3cddc1872a60a29402Hauke Mehrtensstatic u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 __iomem **eromptr)
1558369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
1568369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u32 ent = readl(*eromptr);
1578369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	(*eromptr)++;
1588369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	return ent;
1598369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
1608369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
1610b8d6e59a128f4fecce9ea3cddc1872a60a29402Hauke Mehrtensstatic void bcma_erom_push_ent(u32 __iomem **eromptr)
1628369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
1638369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	(*eromptr)--;
1648369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
1658369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
1660b8d6e59a128f4fecce9ea3cddc1872a60a29402Hauke Mehrtensstatic s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 __iomem **eromptr)
1678369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
1688369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u32 ent = bcma_erom_get_ent(bus, eromptr);
1698369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	if (!(ent & SCAN_ER_VALID))
1708369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		return -ENOENT;
1718369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI)
1728369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		return -ENOENT;
1738369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	return ent;
1748369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
1758369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
1760b8d6e59a128f4fecce9ea3cddc1872a60a29402Hauke Mehrtensstatic bool bcma_erom_is_end(struct bcma_bus *bus, u32 __iomem **eromptr)
1778369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
1788369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u32 ent = bcma_erom_get_ent(bus, eromptr);
1798369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	bcma_erom_push_ent(eromptr);
1808369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
1818369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
1828369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
1830b8d6e59a128f4fecce9ea3cddc1872a60a29402Hauke Mehrtensstatic bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 __iomem **eromptr)
1848369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
1858369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u32 ent = bcma_erom_get_ent(bus, eromptr);
1868369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	bcma_erom_push_ent(eromptr);
1878369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	return (((ent & SCAN_ER_VALID)) &&
1888369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) &&
1898369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
1908369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
1918369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
1920b8d6e59a128f4fecce9ea3cddc1872a60a29402Hauke Mehrtensstatic void bcma_erom_skip_component(struct bcma_bus *bus, u32 __iomem **eromptr)
1938369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
1948369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u32 ent;
1958369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	while (1) {
1968369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		ent = bcma_erom_get_ent(bus, eromptr);
1978369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		if ((ent & SCAN_ER_VALID) &&
1988369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		    ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI))
1998369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki			break;
2008369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID))
2018369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki			break;
2028369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	}
2038369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	bcma_erom_push_ent(eromptr);
2048369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
2058369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
2060b8d6e59a128f4fecce9ea3cddc1872a60a29402Hauke Mehrtensstatic s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
2078369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
2088369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u32 ent = bcma_erom_get_ent(bus, eromptr);
2098369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	if (!(ent & SCAN_ER_VALID))
2108369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		return -ENOENT;
2118369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP)
2128369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		return -ENOENT;
2138369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	return ent;
2148369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
2158369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
216fd4edf197544bae1c77d84bad354aa7ce1d08ce1Hauke Mehrtensstatic u32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
2178369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki				  u32 type, u8 port)
2188369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
2198369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u32 addrl, addrh, sizel, sizeh = 0;
2208369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u32 size;
2218369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
2228369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	u32 ent = bcma_erom_get_ent(bus, eromptr);
2238369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	if ((!(ent & SCAN_ER_VALID)) ||
2248369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	    ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) ||
2258369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	    ((ent & SCAN_ADDR_TYPE) != type) ||
2268369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	    (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
2278369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		bcma_erom_push_ent(eromptr);
228fd4edf197544bae1c77d84bad354aa7ce1d08ce1Hauke Mehrtens		return (u32)-EINVAL;
2298369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	}
2308369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
2318369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	addrl = ent & SCAN_ADDR_ADDR;
2328369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	if (ent & SCAN_ADDR_AG32)
2338369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		addrh = bcma_erom_get_ent(bus, eromptr);
2348369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	else
2358369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		addrh = 0;
2368369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
2378369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) {
2388369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		size = bcma_erom_get_ent(bus, eromptr);
2398369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		sizel = size & SCAN_SIZE_SZ;
2408369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		if (size & SCAN_SIZE_SG32)
2418369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki			sizeh = bcma_erom_get_ent(bus, eromptr);
2428369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	} else
2438369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		sizel = SCAN_ADDR_SZ_BASE <<
2448369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki				((ent & SCAN_ADDR_SZ) >> SCAN_ADDR_SZ_SHIFT);
2458369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
2468369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	return addrl;
2478369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
2488369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
249517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtensstatic struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
250517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens						   u16 index)
251517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens{
252517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	struct bcma_device *core;
253517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
254517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	list_for_each_entry(core, &bus->cores, list) {
255517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		if (core->core_index == index)
256517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens			return core;
257517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	}
258517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	return NULL;
259517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens}
260517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
2615f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtensstatic struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 coreid)
2625f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens{
2635f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens	struct bcma_device *core;
2645f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens
2655f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens	list_for_each_entry_reverse(core, &bus->cores, list) {
2665f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens		if (core->id.id == coreid)
2675f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens			return core;
2685f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens	}
2695f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens	return NULL;
2705f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens}
2715f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens
272aaa2ced15ad8dca8048666c9f70736424d696a6bHauke Mehrtens#define IS_ERR_VALUE_U32(x) ((x) >= (u32)-MAX_ERRNO)
273aaa2ced15ad8dca8048666c9f70736424d696a6bHauke Mehrtens
274982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtensstatic int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
275517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens			      struct bcma_device_id *match, int core_num,
276982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			      struct bcma_device *core)
277982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens{
278fd4edf197544bae1c77d84bad354aa7ce1d08ce1Hauke Mehrtens	u32 tmp;
27923a2f39c8f4035eade7f226eb7ada30c78d9eee3Hauke Mehrtens	u8 i, j, k;
280982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	s32 cia, cib;
281982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	u8 ports[2], wrappers[2];
282982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
283982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	/* get CIs */
284982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	cia = bcma_erom_get_ci(bus, eromptr);
285982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	if (cia < 0) {
286982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		bcma_erom_push_ent(eromptr);
287982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		if (bcma_erom_is_end(bus, eromptr))
288982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			return -ESPIPE;
289982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		return -EILSEQ;
290982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	}
291982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	cib = bcma_erom_get_ci(bus, eromptr);
292982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	if (cib < 0)
293982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		return -EILSEQ;
294982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
295982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	/* parse CIs */
296982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
297982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
298982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
299982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
300982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
301982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
302982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
303982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
304982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
305982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	if (((core->id.manuf == BCMA_MANUF_ARM) &&
306982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	     (core->id.id == 0xFFF)) ||
307982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	    (ports[1] == 0)) {
308982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		bcma_erom_skip_component(bus, eromptr);
309982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		return -ENXIO;
310982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	}
311982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
312982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	/* check if component is a core at all */
313982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	if (wrappers[0] + wrappers[1] == 0) {
314e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki		/* Some specific cores don't need wrappers */
315e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki		switch (core->id.id) {
316e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki		case BCMA_CORE_4706_MAC_GBIT_COMMON:
3171716bcf3f76fe71e98d4851a3eb73ea3d93d4773Hauke Mehrtens		case BCMA_CORE_NS_CHIPCOMMON_B:
318e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki		/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
319e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki			break;
320e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki		default:
321e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki			bcma_erom_skip_component(bus, eromptr);
322e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki			return -ENXIO;
323e1ac4b409037b128f9a3eca3b3ab5dbbb71a7e6fRafał Miłecki		}
324982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	}
325982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
326982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	if (bcma_erom_is_bridge(bus, eromptr)) {
327982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		bcma_erom_skip_component(bus, eromptr);
328982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		return -ENXIO;
329982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	}
330982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
331517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	if (bcma_find_core_by_index(bus, core_num)) {
332517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		bcma_erom_skip_component(bus, eromptr);
333517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		return -ENODEV;
334517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	}
335517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
336517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	if (match && ((match->manuf != BCMA_ANY_MANUF &&
337517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	      match->manuf != core->id.manuf) ||
338517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	     (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
339517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	     (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
340517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	     (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
341517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	    )) {
342517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		bcma_erom_skip_component(bus, eromptr);
343517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		return -ENODEV;
344517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	}
345517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
346982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	/* get & parse master ports */
347982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	for (i = 0; i < ports[0]; i++) {
3484e0d8cc1006b889909a87f824943bad9a56358e8Dan Carpenter		s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
349982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		if (mst_port_d < 0)
350982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			return -EILSEQ;
351982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	}
352982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
353e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens	/* First Slave Address Descriptor should be port 0:
354e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens	 * the main register space for the core
355e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens	 */
356e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens	tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
357aaa2ced15ad8dca8048666c9f70736424d696a6bHauke Mehrtens	if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
358e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens		/* Try again to see if it is a bridge */
359e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens		tmp = bcma_erom_get_addr_desc(bus, eromptr,
360e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens					      SCAN_ADDR_TYPE_BRIDGE, 0);
361aaa2ced15ad8dca8048666c9f70736424d696a6bHauke Mehrtens		if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
362e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens			return -EILSEQ;
363e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens		} else {
3643d9d8af330a891f141db420115238f01e4c6ece7Rafał Miłecki			bcma_info(bus, "Bridge found\n");
365e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens			return -ENXIO;
366e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens		}
367e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens	}
368e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens	core->addr = tmp;
369e167d9fbb881c030f93563fd364c8a0b8c5cd6d3Hauke Mehrtens
370982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	/* get & parse slave ports */
37123a2f39c8f4035eade7f226eb7ada30c78d9eee3Hauke Mehrtens	k = 0;
372982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	for (i = 0; i < ports[1]; i++) {
373982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		for (j = 0; ; j++) {
374982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			tmp = bcma_erom_get_addr_desc(bus, eromptr,
375982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				SCAN_ADDR_TYPE_SLAVE, i);
376aaa2ced15ad8dca8048666c9f70736424d696a6bHauke Mehrtens			if (IS_ERR_VALUE_U32(tmp)) {
377982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				/* no more entries for port _i_ */
378982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				/* pr_debug("erom: slave port %d "
379982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				 * "has %d descriptors\n", i, j); */
380982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				break;
38123a2f39c8f4035eade7f226eb7ada30c78d9eee3Hauke Mehrtens			} else if (k < ARRAY_SIZE(core->addr_s)) {
38223a2f39c8f4035eade7f226eb7ada30c78d9eee3Hauke Mehrtens				core->addr_s[k] = tmp;
38323a2f39c8f4035eade7f226eb7ada30c78d9eee3Hauke Mehrtens				k++;
384982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			}
385982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		}
386982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	}
387982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
388982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	/* get & parse master wrappers */
389982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	for (i = 0; i < wrappers[0]; i++) {
390982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		for (j = 0; ; j++) {
391982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			tmp = bcma_erom_get_addr_desc(bus, eromptr,
392982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				SCAN_ADDR_TYPE_MWRAP, i);
393aaa2ced15ad8dca8048666c9f70736424d696a6bHauke Mehrtens			if (IS_ERR_VALUE_U32(tmp)) {
394982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				/* no more entries for port _i_ */
395982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				/* pr_debug("erom: master wrapper %d "
396982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				 * "has %d descriptors\n", i, j); */
397982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				break;
398982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			} else {
399982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				if (i == 0 && j == 0)
400982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens					core->wrap = tmp;
401982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			}
402982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		}
403982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	}
404982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
405982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	/* get & parse slave wrappers */
406982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	for (i = 0; i < wrappers[1]; i++) {
407982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		u8 hack = (ports[1] == 1) ? 0 : 1;
408982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		for (j = 0; ; j++) {
409982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			tmp = bcma_erom_get_addr_desc(bus, eromptr,
410982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				SCAN_ADDR_TYPE_SWRAP, i + hack);
411aaa2ced15ad8dca8048666c9f70736424d696a6bHauke Mehrtens			if (IS_ERR_VALUE_U32(tmp)) {
412982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				/* no more entries for port _i_ */
413982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				/* pr_debug("erom: master wrapper %d "
414982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				 * has %d descriptors\n", i, j); */
415982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				break;
416982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			} else {
417982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens				if (wrappers[0] == 0 && !i && !j)
418982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens					core->wrap = tmp;
419982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens			}
420982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens		}
421982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	}
422ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
423ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
424ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		if (!core->io_addr)
425ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens			return -ENOMEM;
426ecf47e9bb796558423fa87b43a8fe55f086ca56eHauke Mehrtens		if (core->wrap) {
427ecf47e9bb796558423fa87b43a8fe55f086ca56eHauke Mehrtens			core->io_wrap = ioremap_nocache(core->wrap,
428ecf47e9bb796558423fa87b43a8fe55f086ca56eHauke Mehrtens							BCMA_CORE_SIZE);
429ecf47e9bb796558423fa87b43a8fe55f086ca56eHauke Mehrtens			if (!core->io_wrap) {
430ecf47e9bb796558423fa87b43a8fe55f086ca56eHauke Mehrtens				iounmap(core->io_addr);
431ecf47e9bb796558423fa87b43a8fe55f086ca56eHauke Mehrtens				return -ENOMEM;
432ecf47e9bb796558423fa87b43a8fe55f086ca56eHauke Mehrtens			}
433ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		}
434ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	}
435982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens	return 0;
436982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens}
437982eee67dd703a37edc3532b85e3a4122b5eb90bHauke Mehrtens
438517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtensvoid bcma_init_bus(struct bcma_bus *bus)
4398369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki{
4408369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	s32 tmp;
441f0d4724b2a663089d21e19933ca591d842b63230Hauke Mehrtens	struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
442fbf019909173c683d85f7f63b0a33746bf5e4a02Rafał Miłecki	char chip_id[8];
4438369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
4448369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	INIT_LIST_HEAD(&bus->cores);
4458369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	bus->nr_cores = 0;
4468369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
4478369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
4488369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
4498369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
450f0d4724b2a663089d21e19933ca591d842b63230Hauke Mehrtens	chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
451f0d4724b2a663089d21e19933ca591d842b63230Hauke Mehrtens	chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
452f0d4724b2a663089d21e19933ca591d842b63230Hauke Mehrtens	chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
453fbf019909173c683d85f7f63b0a33746bf5e4a02Rafał Miłecki
454fbf019909173c683d85f7f63b0a33746bf5e4a02Rafał Miłecki	snprintf(chip_id, ARRAY_SIZE(chip_id),
455fbf019909173c683d85f7f63b0a33746bf5e4a02Rafał Miłecki		 (chipinfo->id > 0x9999) ? "%d" : "0x%04X", chipinfo->id);
456fbf019909173c683d85f7f63b0a33746bf5e4a02Rafał Miłecki	bcma_info(bus, "Found chip with id %s, rev 0x%02X and package 0x%02X\n",
457fbf019909173c683d85f7f63b0a33746bf5e4a02Rafał Miłecki		  chip_id, chipinfo->rev, chipinfo->pkg);
45867a5c29e1623edda5ff3f0355af533e72a245ad9Hauke Mehrtens}
45967a5c29e1623edda5ff3f0355af533e72a245ad9Hauke Mehrtens
46067a5c29e1623edda5ff3f0355af533e72a245ad9Hauke Mehrtensint bcma_bus_scan(struct bcma_bus *bus)
46167a5c29e1623edda5ff3f0355af533e72a245ad9Hauke Mehrtens{
46267a5c29e1623edda5ff3f0355af533e72a245ad9Hauke Mehrtens	u32 erombase;
46367a5c29e1623edda5ff3f0355af533e72a245ad9Hauke Mehrtens	u32 __iomem *eromptr, *eromend;
46467a5c29e1623edda5ff3f0355af533e72a245ad9Hauke Mehrtens
465517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	int err, core_num = 0;
46667a5c29e1623edda5ff3f0355af533e72a245ad9Hauke Mehrtens
4678369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
468ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
469ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
470ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		if (!eromptr)
471ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens			return -ENOMEM;
472ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	} else {
473ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		eromptr = bus->mmio;
474ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	}
475ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens
4768369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
4778369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
4788369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	bcma_scan_switch_core(bus, erombase);
4798369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
4808369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	while (eromptr < eromend) {
4815f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens		struct bcma_device *other_core;
4828369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
4839dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtens		if (!core) {
4849dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtens			err = -ENOMEM;
4859dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtens			goto out;
4869dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtens		}
4878369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		INIT_LIST_HEAD(&core->list);
4888369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki		core->bus = bus;
4898369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
490517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
491f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl		if (err < 0) {
492f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl			kfree(core);
493f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl			if (err == -ENODEV) {
494f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl				core_num++;
495f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl				continue;
496f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl			} else if (err == -ENXIO) {
497f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl				continue;
498f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl			} else if (err == -ESPIPE) {
499f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl				break;
500f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl			}
5019dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtens			goto out;
502f9721ed2707661af75a414d09cdcd71f99a13f62Jesper Juhl		}
5038369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
504517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		core->core_index = core_num++;
505517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		bus->nr_cores++;
5065f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens		other_core = bcma_find_core_reverse(bus, core->id.id);
5075f2d6171e1e70584b9819771443485750453fd16Hauke Mehrtens		core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
508517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
5093d9d8af330a891f141db420115238f01e4c6ece7Rafał Miłecki		bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
5103d9d8af330a891f141db420115238f01e4c6ece7Rafał Miłecki			  core->core_index, bcma_device_name(&core->id),
5113d9d8af330a891f141db420115238f01e4c6ece7Rafał Miłecki			  core->id.manuf, core->id.id, core->id.rev,
5123d9d8af330a891f141db420115238f01e4c6ece7Rafał Miłecki			  core->id.class);
5138369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
514c334e25c9f3a95f2bd6b79fedc5170f17245b1c7Rafał Miłecki		list_add_tail(&core->list, &bus->cores);
5158369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki	}
5168369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki
5179dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtens	err = 0;
5189dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtensout:
519ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
520ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		iounmap(eromptr);
521ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens
5229dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtens	return err;
5238369ae33b705222aa05ab53c7d6b4458f4ed161bRafał Miłecki}
524517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
525517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtensint __init bcma_bus_scan_early(struct bcma_bus *bus,
526517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens			       struct bcma_device_id *match,
527517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens			       struct bcma_device *core)
528517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens{
529517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	u32 erombase;
530517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	u32 __iomem *eromptr, *eromend;
531517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
532ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	int err = -ENODEV;
533ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	int core_num = 0;
534517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
535517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
536ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
537ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
538ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		if (!eromptr)
539ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens			return -ENOMEM;
540ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	} else {
541ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		eromptr = bus->mmio;
542ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	}
543ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens
544517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
545517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
546517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	bcma_scan_switch_core(bus, erombase);
547517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
548517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	while (eromptr < eromend) {
549517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		memset(core, 0, sizeof(*core));
550517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		INIT_LIST_HEAD(&core->list);
551517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		core->bus = bus;
552517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
553517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
554517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		if (err == -ENODEV) {
555517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens			core_num++;
556517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens			continue;
557517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		} else if (err == -ENXIO)
558517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens			continue;
559517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		else if (err == -ESPIPE)
560517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens			break;
561517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		else if (err < 0)
5629dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtens			goto out;
563517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
564517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		core->core_index = core_num++;
565517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens		bus->nr_cores++;
5663d9d8af330a891f141db420115238f01e4c6ece7Rafał Miłecki		bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
5673d9d8af330a891f141db420115238f01e4c6ece7Rafał Miłecki			  core->core_index, bcma_device_name(&core->id),
5683d9d8af330a891f141db420115238f01e4c6ece7Rafał Miłecki			  core->id.manuf, core->id.id, core->id.rev,
5693d9d8af330a891f141db420115238f01e4c6ece7Rafał Miłecki			  core->id.class);
570517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
571c334e25c9f3a95f2bd6b79fedc5170f17245b1c7Rafał Miłecki		list_add_tail(&core->list, &bus->cores);
572ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		err = 0;
573ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		break;
574517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens	}
575517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens
5769dbf5f55f8d35ff9aedc75267f4e4042aaf89755Hauke Mehrtensout:
577ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
578ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens		iounmap(eromptr);
579ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens
580ecd177c21640e92b059a71139f5850243a8f0942Hauke Mehrtens	return err;
581517f43e5a922d51ac960424de4f72676fe6a7390Hauke Mehrtens}
582