18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Sonics Silicon Backplane
38c2ecf20Sopenharmony_ci * Broadcom MIPS core driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2005, Broadcom Corporation
68c2ecf20Sopenharmony_ci * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "ssb_private.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/ssb/ssb.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/mtd/physmap.h>
168c2ecf20Sopenharmony_ci#include <linux/serial.h>
178c2ecf20Sopenharmony_ci#include <linux/serial_core.h>
188c2ecf20Sopenharmony_ci#include <linux/serial_reg.h>
198c2ecf20Sopenharmony_ci#include <linux/time.h>
208c2ecf20Sopenharmony_ci#ifdef CONFIG_BCM47XX
218c2ecf20Sopenharmony_ci#include <linux/bcm47xx_nvram.h>
228c2ecf20Sopenharmony_ci#endif
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic const char * const part_probes[] = { "bcm47xxpart", NULL };
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic struct physmap_flash_data ssb_pflash_data = {
278c2ecf20Sopenharmony_ci	.part_probe_types	= part_probes,
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic struct resource ssb_pflash_resource = {
318c2ecf20Sopenharmony_ci	.name	= "ssb_pflash",
328c2ecf20Sopenharmony_ci	.flags  = IORESOURCE_MEM,
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct platform_device ssb_pflash_dev = {
368c2ecf20Sopenharmony_ci	.name		= "physmap-flash",
378c2ecf20Sopenharmony_ci	.dev		= {
388c2ecf20Sopenharmony_ci		.platform_data  = &ssb_pflash_data,
398c2ecf20Sopenharmony_ci	},
408c2ecf20Sopenharmony_ci	.resource	= &ssb_pflash_resource,
418c2ecf20Sopenharmony_ci	.num_resources	= 1,
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline u32 mips_read32(struct ssb_mipscore *mcore,
458c2ecf20Sopenharmony_ci			      u16 offset)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	return ssb_read32(mcore->dev, offset);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic inline void mips_write32(struct ssb_mipscore *mcore,
518c2ecf20Sopenharmony_ci				u16 offset,
528c2ecf20Sopenharmony_ci				u32 value)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	ssb_write32(mcore->dev, offset, value);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic const u32 ipsflag_irq_mask[] = {
588c2ecf20Sopenharmony_ci	0,
598c2ecf20Sopenharmony_ci	SSB_IPSFLAG_IRQ1,
608c2ecf20Sopenharmony_ci	SSB_IPSFLAG_IRQ2,
618c2ecf20Sopenharmony_ci	SSB_IPSFLAG_IRQ3,
628c2ecf20Sopenharmony_ci	SSB_IPSFLAG_IRQ4,
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic const u32 ipsflag_irq_shift[] = {
668c2ecf20Sopenharmony_ci	0,
678c2ecf20Sopenharmony_ci	SSB_IPSFLAG_IRQ1_SHIFT,
688c2ecf20Sopenharmony_ci	SSB_IPSFLAG_IRQ2_SHIFT,
698c2ecf20Sopenharmony_ci	SSB_IPSFLAG_IRQ3_SHIFT,
708c2ecf20Sopenharmony_ci	SSB_IPSFLAG_IRQ4_SHIFT,
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic inline u32 ssb_irqflag(struct ssb_device *dev)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
768c2ecf20Sopenharmony_ci	if (tpsflag)
778c2ecf20Sopenharmony_ci		return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
788c2ecf20Sopenharmony_ci	else
798c2ecf20Sopenharmony_ci		/* not irq supported */
808c2ecf20Sopenharmony_ci		return 0x3f;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct ssb_bus *bus = rdev->bus;
868c2ecf20Sopenharmony_ci	int i;
878c2ecf20Sopenharmony_ci	for (i = 0; i < bus->nr_devices; i++) {
888c2ecf20Sopenharmony_ci		struct ssb_device *dev;
898c2ecf20Sopenharmony_ci		dev = &(bus->devices[i]);
908c2ecf20Sopenharmony_ci		if (ssb_irqflag(dev) == irqflag)
918c2ecf20Sopenharmony_ci			return dev;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci	return NULL;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/* Get the MIPS IRQ assignment for a specified device.
978c2ecf20Sopenharmony_ci * If unassigned, 0 is returned.
988c2ecf20Sopenharmony_ci * If disabled, 5 is returned.
998c2ecf20Sopenharmony_ci * If not supported, 6 is returned.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_ciunsigned int ssb_mips_irq(struct ssb_device *dev)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct ssb_bus *bus = dev->bus;
1048c2ecf20Sopenharmony_ci	struct ssb_device *mdev = bus->mipscore.dev;
1058c2ecf20Sopenharmony_ci	u32 irqflag;
1068c2ecf20Sopenharmony_ci	u32 ipsflag;
1078c2ecf20Sopenharmony_ci	u32 tmp;
1088c2ecf20Sopenharmony_ci	unsigned int irq;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	irqflag = ssb_irqflag(dev);
1118c2ecf20Sopenharmony_ci	if (irqflag == 0x3f)
1128c2ecf20Sopenharmony_ci		return 6;
1138c2ecf20Sopenharmony_ci	ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
1148c2ecf20Sopenharmony_ci	for (irq = 1; irq <= 4; irq++) {
1158c2ecf20Sopenharmony_ci		tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
1168c2ecf20Sopenharmony_ci		if (tmp == irqflag)
1178c2ecf20Sopenharmony_ci			break;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci	if (irq	== 5) {
1208c2ecf20Sopenharmony_ci		if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
1218c2ecf20Sopenharmony_ci			irq = 0;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return irq;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic void clear_irq(struct ssb_bus *bus, unsigned int irq)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct ssb_device *dev = bus->mipscore.dev;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* Clear the IRQ in the MIPScore backplane registers */
1328c2ecf20Sopenharmony_ci	if (irq == 0) {
1338c2ecf20Sopenharmony_ci		ssb_write32(dev, SSB_INTVEC, 0);
1348c2ecf20Sopenharmony_ci	} else {
1358c2ecf20Sopenharmony_ci		ssb_write32(dev, SSB_IPSFLAG,
1368c2ecf20Sopenharmony_ci			    ssb_read32(dev, SSB_IPSFLAG) |
1378c2ecf20Sopenharmony_ci			    ipsflag_irq_mask[irq]);
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic void set_irq(struct ssb_device *dev, unsigned int irq)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	unsigned int oldirq = ssb_mips_irq(dev);
1448c2ecf20Sopenharmony_ci	struct ssb_bus *bus = dev->bus;
1458c2ecf20Sopenharmony_ci	struct ssb_device *mdev = bus->mipscore.dev;
1468c2ecf20Sopenharmony_ci	u32 irqflag = ssb_irqflag(dev);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	BUG_ON(oldirq == 6);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	dev->irq = irq + 2;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/* clear the old irq */
1538c2ecf20Sopenharmony_ci	if (oldirq == 0)
1548c2ecf20Sopenharmony_ci		ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
1558c2ecf20Sopenharmony_ci	else if (oldirq != 5)
1568c2ecf20Sopenharmony_ci		clear_irq(bus, oldirq);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* assign the new one */
1598c2ecf20Sopenharmony_ci	if (irq == 0) {
1608c2ecf20Sopenharmony_ci		ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
1618c2ecf20Sopenharmony_ci	} else {
1628c2ecf20Sopenharmony_ci		u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
1638c2ecf20Sopenharmony_ci		if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
1648c2ecf20Sopenharmony_ci			u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
1658c2ecf20Sopenharmony_ci			struct ssb_device *olddev = find_device(dev, oldipsflag);
1668c2ecf20Sopenharmony_ci			if (olddev)
1678c2ecf20Sopenharmony_ci				set_irq(olddev, 0);
1688c2ecf20Sopenharmony_ci		}
1698c2ecf20Sopenharmony_ci		irqflag <<= ipsflag_irq_shift[irq];
1708c2ecf20Sopenharmony_ci		irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
1718c2ecf20Sopenharmony_ci		ssb_write32(mdev, SSB_IPSFLAG, irqflag);
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "set_irq: core 0x%04x, irq %d => %d\n",
1748c2ecf20Sopenharmony_ci		dev->id.coreid, oldirq+2, irq+2);
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic void print_irq(struct ssb_device *dev, unsigned int irq)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
1808c2ecf20Sopenharmony_ci	dev_dbg(dev->dev,
1818c2ecf20Sopenharmony_ci		"core 0x%04x, irq : %s%s %s%s %s%s %s%s %s%s %s%s %s%s\n",
1828c2ecf20Sopenharmony_ci		dev->id.coreid,
1838c2ecf20Sopenharmony_ci		irq_name[0], irq == 0 ? "*" : " ",
1848c2ecf20Sopenharmony_ci		irq_name[1], irq == 1 ? "*" : " ",
1858c2ecf20Sopenharmony_ci		irq_name[2], irq == 2 ? "*" : " ",
1868c2ecf20Sopenharmony_ci		irq_name[3], irq == 3 ? "*" : " ",
1878c2ecf20Sopenharmony_ci		irq_name[4], irq == 4 ? "*" : " ",
1888c2ecf20Sopenharmony_ci		irq_name[5], irq == 5 ? "*" : " ",
1898c2ecf20Sopenharmony_ci		irq_name[6], irq == 6 ? "*" : " ");
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic void dump_irq(struct ssb_bus *bus)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	int i;
1958c2ecf20Sopenharmony_ci	for (i = 0; i < bus->nr_devices; i++) {
1968c2ecf20Sopenharmony_ci		struct ssb_device *dev;
1978c2ecf20Sopenharmony_ci		dev = &(bus->devices[i]);
1988c2ecf20Sopenharmony_ci		print_irq(dev, ssb_mips_irq(dev));
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic void ssb_mips_serial_init(struct ssb_mipscore *mcore)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct ssb_bus *bus = mcore->dev->bus;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	if (ssb_extif_available(&bus->extif))
2078c2ecf20Sopenharmony_ci		mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
2088c2ecf20Sopenharmony_ci	else if (ssb_chipco_available(&bus->chipco))
2098c2ecf20Sopenharmony_ci		mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
2108c2ecf20Sopenharmony_ci	else
2118c2ecf20Sopenharmony_ci		mcore->nr_serial_ports = 0;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct ssb_bus *bus = mcore->dev->bus;
2178c2ecf20Sopenharmony_ci	struct ssb_sflash *sflash = &mcore->sflash;
2188c2ecf20Sopenharmony_ci	struct ssb_pflash *pflash = &mcore->pflash;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/* When there is no chipcommon on the bus there is 4MB flash */
2218c2ecf20Sopenharmony_ci	if (!ssb_chipco_available(&bus->chipco)) {
2228c2ecf20Sopenharmony_ci		pflash->present = true;
2238c2ecf20Sopenharmony_ci		pflash->buswidth = 2;
2248c2ecf20Sopenharmony_ci		pflash->window = SSB_FLASH1;
2258c2ecf20Sopenharmony_ci		pflash->window_size = SSB_FLASH1_SZ;
2268c2ecf20Sopenharmony_ci		goto ssb_pflash;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* There is ChipCommon, so use it to read info about flash */
2308c2ecf20Sopenharmony_ci	switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
2318c2ecf20Sopenharmony_ci	case SSB_CHIPCO_FLASHT_STSER:
2328c2ecf20Sopenharmony_ci	case SSB_CHIPCO_FLASHT_ATSER:
2338c2ecf20Sopenharmony_ci		dev_dbg(mcore->dev->dev, "Found serial flash\n");
2348c2ecf20Sopenharmony_ci		ssb_sflash_init(&bus->chipco);
2358c2ecf20Sopenharmony_ci		break;
2368c2ecf20Sopenharmony_ci	case SSB_CHIPCO_FLASHT_PARA:
2378c2ecf20Sopenharmony_ci		dev_dbg(mcore->dev->dev, "Found parallel flash\n");
2388c2ecf20Sopenharmony_ci		pflash->present = true;
2398c2ecf20Sopenharmony_ci		pflash->window = SSB_FLASH2;
2408c2ecf20Sopenharmony_ci		pflash->window_size = SSB_FLASH2_SZ;
2418c2ecf20Sopenharmony_ci		if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
2428c2ecf20Sopenharmony_ci		               & SSB_CHIPCO_CFG_DS16) == 0)
2438c2ecf20Sopenharmony_ci			pflash->buswidth = 1;
2448c2ecf20Sopenharmony_ci		else
2458c2ecf20Sopenharmony_ci			pflash->buswidth = 2;
2468c2ecf20Sopenharmony_ci		break;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cissb_pflash:
2508c2ecf20Sopenharmony_ci	if (sflash->present) {
2518c2ecf20Sopenharmony_ci#ifdef CONFIG_BCM47XX
2528c2ecf20Sopenharmony_ci		bcm47xx_nvram_init_from_mem(sflash->window, sflash->size);
2538c2ecf20Sopenharmony_ci#endif
2548c2ecf20Sopenharmony_ci	} else if (pflash->present) {
2558c2ecf20Sopenharmony_ci#ifdef CONFIG_BCM47XX
2568c2ecf20Sopenharmony_ci		bcm47xx_nvram_init_from_mem(pflash->window, pflash->window_size);
2578c2ecf20Sopenharmony_ci#endif
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci		ssb_pflash_data.width = pflash->buswidth;
2608c2ecf20Sopenharmony_ci		ssb_pflash_resource.start = pflash->window;
2618c2ecf20Sopenharmony_ci		ssb_pflash_resource.end = pflash->window + pflash->window_size;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ciu32 ssb_cpu_clock(struct ssb_mipscore *mcore)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct ssb_bus *bus = mcore->dev->bus;
2688c2ecf20Sopenharmony_ci	u32 pll_type, n, m, rate = 0;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)
2718c2ecf20Sopenharmony_ci		return ssb_pmu_get_cpu_clock(&bus->chipco);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (ssb_extif_available(&bus->extif)) {
2748c2ecf20Sopenharmony_ci		ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
2758c2ecf20Sopenharmony_ci	} else if (ssb_chipco_available(&bus->chipco)) {
2768c2ecf20Sopenharmony_ci		ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
2778c2ecf20Sopenharmony_ci	} else
2788c2ecf20Sopenharmony_ci		return 0;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
2818c2ecf20Sopenharmony_ci		rate = 200000000;
2828c2ecf20Sopenharmony_ci	} else {
2838c2ecf20Sopenharmony_ci		rate = ssb_calc_clock_rate(pll_type, n, m);
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (pll_type == SSB_PLLTYPE_6) {
2878c2ecf20Sopenharmony_ci		rate *= 2;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	return rate;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_civoid ssb_mipscore_init(struct ssb_mipscore *mcore)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct ssb_bus *bus;
2968c2ecf20Sopenharmony_ci	struct ssb_device *dev;
2978c2ecf20Sopenharmony_ci	unsigned long hz, ns;
2988c2ecf20Sopenharmony_ci	unsigned int irq, i;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (!mcore->dev)
3018c2ecf20Sopenharmony_ci		return; /* We don't have a MIPS core */
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	dev_dbg(mcore->dev->dev, "Initializing MIPS core...\n");
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	bus = mcore->dev->bus;
3068c2ecf20Sopenharmony_ci	hz = ssb_clockspeed(bus);
3078c2ecf20Sopenharmony_ci	if (!hz)
3088c2ecf20Sopenharmony_ci		hz = 100000000;
3098c2ecf20Sopenharmony_ci	ns = 1000000000 / hz;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (ssb_extif_available(&bus->extif))
3128c2ecf20Sopenharmony_ci		ssb_extif_timing_init(&bus->extif, ns);
3138c2ecf20Sopenharmony_ci	else if (ssb_chipco_available(&bus->chipco))
3148c2ecf20Sopenharmony_ci		ssb_chipco_timing_init(&bus->chipco, ns);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
3178c2ecf20Sopenharmony_ci	for (irq = 2, i = 0; i < bus->nr_devices; i++) {
3188c2ecf20Sopenharmony_ci		int mips_irq;
3198c2ecf20Sopenharmony_ci		dev = &(bus->devices[i]);
3208c2ecf20Sopenharmony_ci		mips_irq = ssb_mips_irq(dev);
3218c2ecf20Sopenharmony_ci		if (mips_irq > 4)
3228c2ecf20Sopenharmony_ci			dev->irq = 0;
3238c2ecf20Sopenharmony_ci		else
3248c2ecf20Sopenharmony_ci			dev->irq = mips_irq + 2;
3258c2ecf20Sopenharmony_ci		if (dev->irq > 5)
3268c2ecf20Sopenharmony_ci			continue;
3278c2ecf20Sopenharmony_ci		switch (dev->id.coreid) {
3288c2ecf20Sopenharmony_ci		case SSB_DEV_USB11_HOST:
3298c2ecf20Sopenharmony_ci			/* shouldn't need a separate irq line for non-4710, most of them have a proper
3308c2ecf20Sopenharmony_ci			 * external usb controller on the pci */
3318c2ecf20Sopenharmony_ci			if ((bus->chip_id == 0x4710) && (irq <= 4)) {
3328c2ecf20Sopenharmony_ci				set_irq(dev, irq++);
3338c2ecf20Sopenharmony_ci			}
3348c2ecf20Sopenharmony_ci			break;
3358c2ecf20Sopenharmony_ci		case SSB_DEV_PCI:
3368c2ecf20Sopenharmony_ci		case SSB_DEV_ETHERNET:
3378c2ecf20Sopenharmony_ci		case SSB_DEV_ETHERNET_GBIT:
3388c2ecf20Sopenharmony_ci		case SSB_DEV_80211:
3398c2ecf20Sopenharmony_ci		case SSB_DEV_USB20_HOST:
3408c2ecf20Sopenharmony_ci			/* These devices get their own IRQ line if available, the rest goes on IRQ0 */
3418c2ecf20Sopenharmony_ci			if (irq <= 4) {
3428c2ecf20Sopenharmony_ci				set_irq(dev, irq++);
3438c2ecf20Sopenharmony_ci				break;
3448c2ecf20Sopenharmony_ci			}
3458c2ecf20Sopenharmony_ci			fallthrough;
3468c2ecf20Sopenharmony_ci		case SSB_DEV_EXTIF:
3478c2ecf20Sopenharmony_ci			set_irq(dev, 0);
3488c2ecf20Sopenharmony_ci			break;
3498c2ecf20Sopenharmony_ci		}
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci	dev_dbg(mcore->dev->dev, "after irq reconfiguration\n");
3528c2ecf20Sopenharmony_ci	dump_irq(bus);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	ssb_mips_serial_init(mcore);
3558c2ecf20Sopenharmony_ci	ssb_mips_flash_detect(mcore);
3568c2ecf20Sopenharmony_ci}
357