| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 1 | /* | 
 | 2 |  * Broadcom specific AMBA | 
 | 3 |  * Bus scanning | 
 | 4 |  * | 
 | 5 |  * Licensed under the GNU/GPL. See COPYING for details. | 
 | 6 |  */ | 
 | 7 |  | 
 | 8 | #include "scan.h" | 
 | 9 | #include "bcma_private.h" | 
 | 10 |  | 
 | 11 | #include <linux/bcma/bcma.h> | 
 | 12 | #include <linux/bcma/bcma_regs.h> | 
 | 13 | #include <linux/pci.h> | 
 | 14 | #include <linux/io.h> | 
 | 15 | #include <linux/dma-mapping.h> | 
 | 16 | #include <linux/slab.h> | 
 | 17 |  | 
 | 18 | struct bcma_device_id_name { | 
 | 19 | 	u16 id; | 
 | 20 | 	const char *name; | 
 | 21 | }; | 
 | 22 | struct bcma_device_id_name bcma_device_names[] = { | 
 | 23 | 	{ BCMA_CORE_OOB_ROUTER, "OOB Router" }, | 
 | 24 | 	{ BCMA_CORE_INVALID, "Invalid" }, | 
 | 25 | 	{ BCMA_CORE_CHIPCOMMON, "ChipCommon" }, | 
 | 26 | 	{ BCMA_CORE_ILINE20, "ILine 20" }, | 
 | 27 | 	{ BCMA_CORE_SRAM, "SRAM" }, | 
 | 28 | 	{ BCMA_CORE_SDRAM, "SDRAM" }, | 
 | 29 | 	{ BCMA_CORE_PCI, "PCI" }, | 
 | 30 | 	{ BCMA_CORE_MIPS, "MIPS" }, | 
 | 31 | 	{ BCMA_CORE_ETHERNET, "Fast Ethernet" }, | 
 | 32 | 	{ BCMA_CORE_V90, "V90" }, | 
 | 33 | 	{ BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" }, | 
 | 34 | 	{ BCMA_CORE_ADSL, "ADSL" }, | 
 | 35 | 	{ BCMA_CORE_ILINE100, "ILine 100" }, | 
 | 36 | 	{ BCMA_CORE_IPSEC, "IPSEC" }, | 
 | 37 | 	{ BCMA_CORE_UTOPIA, "UTOPIA" }, | 
 | 38 | 	{ BCMA_CORE_PCMCIA, "PCMCIA" }, | 
 | 39 | 	{ BCMA_CORE_INTERNAL_MEM, "Internal Memory" }, | 
 | 40 | 	{ BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" }, | 
 | 41 | 	{ BCMA_CORE_OFDM, "OFDM" }, | 
 | 42 | 	{ BCMA_CORE_EXTIF, "EXTIF" }, | 
 | 43 | 	{ BCMA_CORE_80211, "IEEE 802.11" }, | 
 | 44 | 	{ BCMA_CORE_PHY_A, "PHY A" }, | 
 | 45 | 	{ BCMA_CORE_PHY_B, "PHY B" }, | 
 | 46 | 	{ BCMA_CORE_PHY_G, "PHY G" }, | 
 | 47 | 	{ BCMA_CORE_MIPS_3302, "MIPS 3302" }, | 
 | 48 | 	{ BCMA_CORE_USB11_HOST, "USB 1.1 Host" }, | 
 | 49 | 	{ BCMA_CORE_USB11_DEV, "USB 1.1 Device" }, | 
 | 50 | 	{ BCMA_CORE_USB20_HOST, "USB 2.0 Host" }, | 
 | 51 | 	{ BCMA_CORE_USB20_DEV, "USB 2.0 Device" }, | 
 | 52 | 	{ BCMA_CORE_SDIO_HOST, "SDIO Host" }, | 
 | 53 | 	{ BCMA_CORE_ROBOSWITCH, "Roboswitch" }, | 
 | 54 | 	{ BCMA_CORE_PARA_ATA, "PATA" }, | 
 | 55 | 	{ BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" }, | 
 | 56 | 	{ BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" }, | 
 | 57 | 	{ BCMA_CORE_PCIE, "PCIe" }, | 
 | 58 | 	{ BCMA_CORE_PHY_N, "PHY N" }, | 
 | 59 | 	{ BCMA_CORE_SRAM_CTL, "SRAM Controller" }, | 
 | 60 | 	{ BCMA_CORE_MINI_MACPHY, "Mini MACPHY" }, | 
 | 61 | 	{ BCMA_CORE_ARM_1176, "ARM 1176" }, | 
 | 62 | 	{ BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" }, | 
 | 63 | 	{ BCMA_CORE_PHY_LP, "PHY LP" }, | 
 | 64 | 	{ BCMA_CORE_PMU, "PMU" }, | 
 | 65 | 	{ BCMA_CORE_PHY_SSN, "PHY SSN" }, | 
 | 66 | 	{ BCMA_CORE_SDIO_DEV, "SDIO Device" }, | 
 | 67 | 	{ BCMA_CORE_ARM_CM3, "ARM CM3" }, | 
 | 68 | 	{ BCMA_CORE_PHY_HT, "PHY HT" }, | 
 | 69 | 	{ BCMA_CORE_MIPS_74K, "MIPS 74K" }, | 
 | 70 | 	{ BCMA_CORE_MAC_GBIT, "GBit MAC" }, | 
 | 71 | 	{ BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" }, | 
 | 72 | 	{ BCMA_CORE_PCIE_RC, "PCIe Root Complex" }, | 
 | 73 | 	{ BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" }, | 
 | 74 | 	{ BCMA_CORE_SHARED_COMMON, "Common Shared" }, | 
 | 75 | 	{ BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" }, | 
 | 76 | 	{ BCMA_CORE_SPI_HOST, "SPI Host" }, | 
 | 77 | 	{ BCMA_CORE_I2S, "I2S" }, | 
 | 78 | 	{ BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" }, | 
 | 79 | 	{ BCMA_CORE_SHIM, "SHIM" }, | 
 | 80 | 	{ BCMA_CORE_DEFAULT, "Default" }, | 
 | 81 | }; | 
 | 82 | const char *bcma_device_name(struct bcma_device_id *id) | 
 | 83 | { | 
 | 84 | 	int i; | 
 | 85 |  | 
 | 86 | 	if (id->manuf == BCMA_MANUF_BCM) { | 
 | 87 | 		for (i = 0; i < ARRAY_SIZE(bcma_device_names); i++) { | 
 | 88 | 			if (bcma_device_names[i].id == id->id) | 
 | 89 | 				return bcma_device_names[i].name; | 
 | 90 | 		} | 
 | 91 | 	} | 
 | 92 | 	return "UNKNOWN"; | 
 | 93 | } | 
 | 94 |  | 
 | 95 | static u32 bcma_scan_read32(struct bcma_bus *bus, u8 current_coreidx, | 
 | 96 | 		       u16 offset) | 
 | 97 | { | 
 | 98 | 	return readl(bus->mmio + offset); | 
 | 99 | } | 
 | 100 |  | 
 | 101 | static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr) | 
 | 102 | { | 
 | 103 | 	if (bus->hosttype == BCMA_HOSTTYPE_PCI) | 
 | 104 | 		pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN, | 
 | 105 | 				       addr); | 
 | 106 | } | 
 | 107 |  | 
 | 108 | static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr) | 
 | 109 | { | 
 | 110 | 	u32 ent = readl(*eromptr); | 
 | 111 | 	(*eromptr)++; | 
 | 112 | 	return ent; | 
 | 113 | } | 
 | 114 |  | 
 | 115 | static void bcma_erom_push_ent(u32 **eromptr) | 
 | 116 | { | 
 | 117 | 	(*eromptr)--; | 
 | 118 | } | 
 | 119 |  | 
 | 120 | static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr) | 
 | 121 | { | 
 | 122 | 	u32 ent = bcma_erom_get_ent(bus, eromptr); | 
 | 123 | 	if (!(ent & SCAN_ER_VALID)) | 
 | 124 | 		return -ENOENT; | 
 | 125 | 	if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI) | 
 | 126 | 		return -ENOENT; | 
 | 127 | 	return ent; | 
 | 128 | } | 
 | 129 |  | 
 | 130 | static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr) | 
 | 131 | { | 
 | 132 | 	u32 ent = bcma_erom_get_ent(bus, eromptr); | 
 | 133 | 	bcma_erom_push_ent(eromptr); | 
 | 134 | 	return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID)); | 
 | 135 | } | 
 | 136 |  | 
 | 137 | static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr) | 
 | 138 | { | 
 | 139 | 	u32 ent = bcma_erom_get_ent(bus, eromptr); | 
 | 140 | 	bcma_erom_push_ent(eromptr); | 
 | 141 | 	return (((ent & SCAN_ER_VALID)) && | 
 | 142 | 		((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) && | 
 | 143 | 		((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE)); | 
 | 144 | } | 
 | 145 |  | 
 | 146 | static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr) | 
 | 147 | { | 
 | 148 | 	u32 ent; | 
 | 149 | 	while (1) { | 
 | 150 | 		ent = bcma_erom_get_ent(bus, eromptr); | 
 | 151 | 		if ((ent & SCAN_ER_VALID) && | 
 | 152 | 		    ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI)) | 
 | 153 | 			break; | 
 | 154 | 		if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID)) | 
 | 155 | 			break; | 
 | 156 | 	} | 
 | 157 | 	bcma_erom_push_ent(eromptr); | 
 | 158 | } | 
 | 159 |  | 
 | 160 | static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr) | 
 | 161 | { | 
 | 162 | 	u32 ent = bcma_erom_get_ent(bus, eromptr); | 
 | 163 | 	if (!(ent & SCAN_ER_VALID)) | 
 | 164 | 		return -ENOENT; | 
 | 165 | 	if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP) | 
 | 166 | 		return -ENOENT; | 
 | 167 | 	return ent; | 
 | 168 | } | 
 | 169 |  | 
 | 170 | static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr, | 
 | 171 | 				  u32 type, u8 port) | 
 | 172 | { | 
 | 173 | 	u32 addrl, addrh, sizel, sizeh = 0; | 
 | 174 | 	u32 size; | 
 | 175 |  | 
 | 176 | 	u32 ent = bcma_erom_get_ent(bus, eromptr); | 
 | 177 | 	if ((!(ent & SCAN_ER_VALID)) || | 
 | 178 | 	    ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) || | 
 | 179 | 	    ((ent & SCAN_ADDR_TYPE) != type) || | 
 | 180 | 	    (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) { | 
 | 181 | 		bcma_erom_push_ent(eromptr); | 
 | 182 | 		return -EINVAL; | 
 | 183 | 	} | 
 | 184 |  | 
 | 185 | 	addrl = ent & SCAN_ADDR_ADDR; | 
 | 186 | 	if (ent & SCAN_ADDR_AG32) | 
 | 187 | 		addrh = bcma_erom_get_ent(bus, eromptr); | 
 | 188 | 	else | 
 | 189 | 		addrh = 0; | 
 | 190 |  | 
 | 191 | 	if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) { | 
 | 192 | 		size = bcma_erom_get_ent(bus, eromptr); | 
 | 193 | 		sizel = size & SCAN_SIZE_SZ; | 
 | 194 | 		if (size & SCAN_SIZE_SG32) | 
 | 195 | 			sizeh = bcma_erom_get_ent(bus, eromptr); | 
 | 196 | 	} else | 
 | 197 | 		sizel = SCAN_ADDR_SZ_BASE << | 
 | 198 | 				((ent & SCAN_ADDR_SZ) >> SCAN_ADDR_SZ_SHIFT); | 
 | 199 |  | 
 | 200 | 	return addrl; | 
 | 201 | } | 
 | 202 |  | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 203 | static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus, | 
 | 204 | 						   u16 index) | 
 | 205 | { | 
 | 206 | 	struct bcma_device *core; | 
 | 207 |  | 
 | 208 | 	list_for_each_entry(core, &bus->cores, list) { | 
 | 209 | 		if (core->core_index == index) | 
 | 210 | 			return core; | 
 | 211 | 	} | 
 | 212 | 	return NULL; | 
 | 213 | } | 
 | 214 |  | 
| Hauke Mehrtens | 982eee6 | 2011-07-23 01:20:05 +0200 | [diff] [blame] | 215 | static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 216 | 			      struct bcma_device_id *match, int core_num, | 
| Hauke Mehrtens | 982eee6 | 2011-07-23 01:20:05 +0200 | [diff] [blame] | 217 | 			      struct bcma_device *core) | 
 | 218 | { | 
 | 219 | 	s32 tmp; | 
 | 220 | 	u8 i, j; | 
 | 221 | 	s32 cia, cib; | 
 | 222 | 	u8 ports[2], wrappers[2]; | 
 | 223 |  | 
 | 224 | 	/* get CIs */ | 
 | 225 | 	cia = bcma_erom_get_ci(bus, eromptr); | 
 | 226 | 	if (cia < 0) { | 
 | 227 | 		bcma_erom_push_ent(eromptr); | 
 | 228 | 		if (bcma_erom_is_end(bus, eromptr)) | 
 | 229 | 			return -ESPIPE; | 
 | 230 | 		return -EILSEQ; | 
 | 231 | 	} | 
 | 232 | 	cib = bcma_erom_get_ci(bus, eromptr); | 
 | 233 | 	if (cib < 0) | 
 | 234 | 		return -EILSEQ; | 
 | 235 |  | 
 | 236 | 	/* parse CIs */ | 
 | 237 | 	core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; | 
 | 238 | 	core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; | 
 | 239 | 	core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; | 
 | 240 | 	ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; | 
 | 241 | 	ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; | 
 | 242 | 	wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; | 
 | 243 | 	wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; | 
 | 244 | 	core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; | 
 | 245 |  | 
 | 246 | 	if (((core->id.manuf == BCMA_MANUF_ARM) && | 
 | 247 | 	     (core->id.id == 0xFFF)) || | 
 | 248 | 	    (ports[1] == 0)) { | 
 | 249 | 		bcma_erom_skip_component(bus, eromptr); | 
 | 250 | 		return -ENXIO; | 
 | 251 | 	} | 
 | 252 |  | 
 | 253 | 	/* check if component is a core at all */ | 
 | 254 | 	if (wrappers[0] + wrappers[1] == 0) { | 
 | 255 | 		/* we could save addrl of the router | 
 | 256 | 		if (cid == BCMA_CORE_OOB_ROUTER) | 
 | 257 | 		 */ | 
 | 258 | 		bcma_erom_skip_component(bus, eromptr); | 
 | 259 | 		return -ENXIO; | 
 | 260 | 	} | 
 | 261 |  | 
 | 262 | 	if (bcma_erom_is_bridge(bus, eromptr)) { | 
 | 263 | 		bcma_erom_skip_component(bus, eromptr); | 
 | 264 | 		return -ENXIO; | 
 | 265 | 	} | 
 | 266 |  | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 267 | 	if (bcma_find_core_by_index(bus, core_num)) { | 
 | 268 | 		bcma_erom_skip_component(bus, eromptr); | 
 | 269 | 		return -ENODEV; | 
 | 270 | 	} | 
 | 271 |  | 
 | 272 | 	if (match && ((match->manuf != BCMA_ANY_MANUF && | 
 | 273 | 	      match->manuf != core->id.manuf) || | 
 | 274 | 	     (match->id != BCMA_ANY_ID && match->id != core->id.id) || | 
 | 275 | 	     (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) || | 
 | 276 | 	     (match->class != BCMA_ANY_CLASS && match->class != core->id.class) | 
 | 277 | 	    )) { | 
 | 278 | 		bcma_erom_skip_component(bus, eromptr); | 
 | 279 | 		return -ENODEV; | 
 | 280 | 	} | 
 | 281 |  | 
| Hauke Mehrtens | 982eee6 | 2011-07-23 01:20:05 +0200 | [diff] [blame] | 282 | 	/* get & parse master ports */ | 
 | 283 | 	for (i = 0; i < ports[0]; i++) { | 
| Dan Carpenter | 4e0d8cc | 2011-08-23 22:15:35 +0300 | [diff] [blame] | 284 | 		s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr); | 
| Hauke Mehrtens | 982eee6 | 2011-07-23 01:20:05 +0200 | [diff] [blame] | 285 | 		if (mst_port_d < 0) | 
 | 286 | 			return -EILSEQ; | 
 | 287 | 	} | 
 | 288 |  | 
 | 289 | 	/* get & parse slave ports */ | 
 | 290 | 	for (i = 0; i < ports[1]; i++) { | 
 | 291 | 		for (j = 0; ; j++) { | 
 | 292 | 			tmp = bcma_erom_get_addr_desc(bus, eromptr, | 
 | 293 | 				SCAN_ADDR_TYPE_SLAVE, i); | 
 | 294 | 			if (tmp < 0) { | 
 | 295 | 				/* no more entries for port _i_ */ | 
 | 296 | 				/* pr_debug("erom: slave port %d " | 
 | 297 | 				 * "has %d descriptors\n", i, j); */ | 
 | 298 | 				break; | 
 | 299 | 			} else { | 
 | 300 | 				if (i == 0 && j == 0) | 
 | 301 | 					core->addr = tmp; | 
 | 302 | 			} | 
 | 303 | 		} | 
 | 304 | 	} | 
 | 305 |  | 
 | 306 | 	/* get & parse master wrappers */ | 
 | 307 | 	for (i = 0; i < wrappers[0]; i++) { | 
 | 308 | 		for (j = 0; ; j++) { | 
 | 309 | 			tmp = bcma_erom_get_addr_desc(bus, eromptr, | 
 | 310 | 				SCAN_ADDR_TYPE_MWRAP, i); | 
 | 311 | 			if (tmp < 0) { | 
 | 312 | 				/* no more entries for port _i_ */ | 
 | 313 | 				/* pr_debug("erom: master wrapper %d " | 
 | 314 | 				 * "has %d descriptors\n", i, j); */ | 
 | 315 | 				break; | 
 | 316 | 			} else { | 
 | 317 | 				if (i == 0 && j == 0) | 
 | 318 | 					core->wrap = tmp; | 
 | 319 | 			} | 
 | 320 | 		} | 
 | 321 | 	} | 
 | 322 |  | 
 | 323 | 	/* get & parse slave wrappers */ | 
 | 324 | 	for (i = 0; i < wrappers[1]; i++) { | 
 | 325 | 		u8 hack = (ports[1] == 1) ? 0 : 1; | 
 | 326 | 		for (j = 0; ; j++) { | 
 | 327 | 			tmp = bcma_erom_get_addr_desc(bus, eromptr, | 
 | 328 | 				SCAN_ADDR_TYPE_SWRAP, i + hack); | 
 | 329 | 			if (tmp < 0) { | 
 | 330 | 				/* no more entries for port _i_ */ | 
 | 331 | 				/* pr_debug("erom: master wrapper %d " | 
 | 332 | 				 * has %d descriptors\n", i, j); */ | 
 | 333 | 				break; | 
 | 334 | 			} else { | 
 | 335 | 				if (wrappers[0] == 0 && !i && !j) | 
 | 336 | 					core->wrap = tmp; | 
 | 337 | 			} | 
 | 338 | 		} | 
 | 339 | 	} | 
| Hauke Mehrtens | ecd177c | 2011-07-23 01:20:08 +0200 | [diff] [blame] | 340 | 	if (bus->hosttype == BCMA_HOSTTYPE_SOC) { | 
 | 341 | 		core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE); | 
 | 342 | 		if (!core->io_addr) | 
 | 343 | 			return -ENOMEM; | 
 | 344 | 		core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE); | 
 | 345 | 		if (!core->io_wrap) { | 
 | 346 | 			iounmap(core->io_addr); | 
 | 347 | 			return -ENOMEM; | 
 | 348 | 		} | 
 | 349 | 	} | 
| Hauke Mehrtens | 982eee6 | 2011-07-23 01:20:05 +0200 | [diff] [blame] | 350 | 	return 0; | 
 | 351 | } | 
 | 352 |  | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 353 | void bcma_init_bus(struct bcma_bus *bus) | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 354 | { | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 355 | 	s32 tmp; | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 356 |  | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 357 | 	if (bus->init_done) | 
 | 358 | 		return; | 
 | 359 |  | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 360 | 	INIT_LIST_HEAD(&bus->cores); | 
 | 361 | 	bus->nr_cores = 0; | 
 | 362 |  | 
 | 363 | 	bcma_scan_switch_core(bus, BCMA_ADDR_BASE); | 
 | 364 |  | 
 | 365 | 	tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID); | 
 | 366 | 	bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; | 
 | 367 | 	bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; | 
 | 368 | 	bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 369 | 	bus->init_done = true; | 
| Hauke Mehrtens | 67a5c29 | 2011-07-23 01:20:06 +0200 | [diff] [blame] | 370 | } | 
 | 371 |  | 
 | 372 | int bcma_bus_scan(struct bcma_bus *bus) | 
 | 373 | { | 
 | 374 | 	u32 erombase; | 
 | 375 | 	u32 __iomem *eromptr, *eromend; | 
 | 376 |  | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 377 | 	int err, core_num = 0; | 
| Hauke Mehrtens | 67a5c29 | 2011-07-23 01:20:06 +0200 | [diff] [blame] | 378 |  | 
 | 379 | 	bcma_init_bus(bus); | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 380 |  | 
 | 381 | 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); | 
| Hauke Mehrtens | ecd177c | 2011-07-23 01:20:08 +0200 | [diff] [blame] | 382 | 	if (bus->hosttype == BCMA_HOSTTYPE_SOC) { | 
 | 383 | 		eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); | 
 | 384 | 		if (!eromptr) | 
 | 385 | 			return -ENOMEM; | 
 | 386 | 	} else { | 
 | 387 | 		eromptr = bus->mmio; | 
 | 388 | 	} | 
 | 389 |  | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 390 | 	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); | 
 | 391 |  | 
 | 392 | 	bcma_scan_switch_core(bus, erombase); | 
 | 393 |  | 
 | 394 | 	while (eromptr < eromend) { | 
 | 395 | 		struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL); | 
 | 396 | 		if (!core) | 
 | 397 | 			return -ENOMEM; | 
 | 398 | 		INIT_LIST_HEAD(&core->list); | 
 | 399 | 		core->bus = bus; | 
 | 400 |  | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 401 | 		err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core); | 
 | 402 | 		if (err == -ENODEV) { | 
 | 403 | 			core_num++; | 
 | 404 | 			continue; | 
 | 405 | 		} else if (err == -ENXIO) | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 406 | 			continue; | 
| Hauke Mehrtens | 982eee6 | 2011-07-23 01:20:05 +0200 | [diff] [blame] | 407 | 		else if (err == -ESPIPE) | 
 | 408 | 			break; | 
 | 409 | 		else if (err < 0) | 
 | 410 | 			return err; | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 411 |  | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 412 | 		core->core_index = core_num++; | 
 | 413 | 		bus->nr_cores++; | 
 | 414 |  | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 415 | 		pr_info("Core %d found: %s " | 
 | 416 | 			"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 417 | 			core->core_index, bcma_device_name(&core->id), | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 418 | 			core->id.manuf, core->id.id, core->id.rev, | 
 | 419 | 			core->id.class); | 
 | 420 |  | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 421 | 		list_add(&core->list, &bus->cores); | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 422 | 	} | 
 | 423 |  | 
| Hauke Mehrtens | ecd177c | 2011-07-23 01:20:08 +0200 | [diff] [blame] | 424 | 	if (bus->hosttype == BCMA_HOSTTYPE_SOC) | 
 | 425 | 		iounmap(eromptr); | 
 | 426 |  | 
| Rafał Miłecki | 8369ae3 | 2011-05-09 18:56:46 +0200 | [diff] [blame] | 427 | 	return 0; | 
 | 428 | } | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 429 |  | 
 | 430 | int __init bcma_bus_scan_early(struct bcma_bus *bus, | 
 | 431 | 			       struct bcma_device_id *match, | 
 | 432 | 			       struct bcma_device *core) | 
 | 433 | { | 
 | 434 | 	u32 erombase; | 
 | 435 | 	u32 __iomem *eromptr, *eromend; | 
 | 436 |  | 
| Hauke Mehrtens | ecd177c | 2011-07-23 01:20:08 +0200 | [diff] [blame] | 437 | 	int err = -ENODEV; | 
 | 438 | 	int core_num = 0; | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 439 |  | 
 | 440 | 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); | 
| Hauke Mehrtens | ecd177c | 2011-07-23 01:20:08 +0200 | [diff] [blame] | 441 | 	if (bus->hosttype == BCMA_HOSTTYPE_SOC) { | 
 | 442 | 		eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); | 
 | 443 | 		if (!eromptr) | 
 | 444 | 			return -ENOMEM; | 
 | 445 | 	} else { | 
 | 446 | 		eromptr = bus->mmio; | 
 | 447 | 	} | 
 | 448 |  | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 449 | 	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); | 
 | 450 |  | 
 | 451 | 	bcma_scan_switch_core(bus, erombase); | 
 | 452 |  | 
 | 453 | 	while (eromptr < eromend) { | 
 | 454 | 		memset(core, 0, sizeof(*core)); | 
 | 455 | 		INIT_LIST_HEAD(&core->list); | 
 | 456 | 		core->bus = bus; | 
 | 457 |  | 
 | 458 | 		err = bcma_get_next_core(bus, &eromptr, match, core_num, core); | 
 | 459 | 		if (err == -ENODEV) { | 
 | 460 | 			core_num++; | 
 | 461 | 			continue; | 
 | 462 | 		} else if (err == -ENXIO) | 
 | 463 | 			continue; | 
 | 464 | 		else if (err == -ESPIPE) | 
 | 465 | 			break; | 
 | 466 | 		else if (err < 0) | 
 | 467 | 			return err; | 
 | 468 |  | 
 | 469 | 		core->core_index = core_num++; | 
 | 470 | 		bus->nr_cores++; | 
 | 471 | 		pr_info("Core %d found: %s " | 
 | 472 | 			"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", | 
 | 473 | 			core->core_index, bcma_device_name(&core->id), | 
 | 474 | 			core->id.manuf, core->id.id, core->id.rev, | 
 | 475 | 			core->id.class); | 
 | 476 |  | 
 | 477 | 		list_add(&core->list, &bus->cores); | 
| Hauke Mehrtens | ecd177c | 2011-07-23 01:20:08 +0200 | [diff] [blame] | 478 | 		err = 0; | 
 | 479 | 		break; | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 480 | 	} | 
 | 481 |  | 
| Hauke Mehrtens | ecd177c | 2011-07-23 01:20:08 +0200 | [diff] [blame] | 482 | 	if (bus->hosttype == BCMA_HOSTTYPE_SOC) | 
 | 483 | 		iounmap(eromptr); | 
 | 484 |  | 
 | 485 | 	return err; | 
| Hauke Mehrtens | 517f43e | 2011-07-23 01:20:07 +0200 | [diff] [blame] | 486 | } |