161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/*
261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Sonics Silicon Backplane
361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Broadcom MIPS core driver
461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch *
561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Copyright 2005, Broadcom Corporation
6eb032b9837a958e21ca000358a5bde5e17192ddbMichael Buesch * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch *
861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * Licensed under the GNU/GPL. See COPYING for details.
961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch */
1061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
1161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/ssb/ssb.h>
1261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
1361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/serial.h>
1461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/serial_core.h>
1561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/serial_reg.h>
1661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include <linux/time.h>
1761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
1861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch#include "ssb_private.h"
1961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
2061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
2161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic inline u32 mips_read32(struct ssb_mipscore *mcore,
2261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			      u16 offset)
2361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
2461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return ssb_read32(mcore->dev, offset);
2561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
2661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
2761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic inline void mips_write32(struct ssb_mipscore *mcore,
2861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				u16 offset,
2961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				u32 value)
3061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
3161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_write32(mcore->dev, offset, value);
3261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
3361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
3461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic const u32 ipsflag_irq_mask[] = {
3561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	0,
3661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	SSB_IPSFLAG_IRQ1,
3761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	SSB_IPSFLAG_IRQ2,
3861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	SSB_IPSFLAG_IRQ3,
3961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	SSB_IPSFLAG_IRQ4,
4061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch};
4161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
4261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic const u32 ipsflag_irq_shift[] = {
4361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	0,
4461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	SSB_IPSFLAG_IRQ1_SHIFT,
4561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	SSB_IPSFLAG_IRQ2_SHIFT,
4661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	SSB_IPSFLAG_IRQ3_SHIFT,
4761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	SSB_IPSFLAG_IRQ4_SHIFT,
4861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch};
4961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
5061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic inline u32 ssb_irqflag(struct ssb_device *dev)
5161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
52ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
53ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	if (tpsflag)
54ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
55ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	else
56ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		/* not irq supported */
57ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		return 0x3f;
58ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET}
59ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET
60ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTETstatic struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
61ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET{
62ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	struct ssb_bus *bus = rdev->bus;
63ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	int i;
64ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	for (i = 0; i < bus->nr_devices; i++) {
65ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		struct ssb_device *dev;
66ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		dev = &(bus->devices[i]);
67ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		if (ssb_irqflag(dev) == irqflag)
68ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET			return dev;
69ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	}
70ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	return NULL;
7161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
7261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
7361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch/* Get the MIPS IRQ assignment for a specified device.
7461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch * If unassigned, 0 is returned.
75ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET * If disabled, 5 is returned.
76ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET * If not supported, 6 is returned.
7761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch */
7861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschunsigned int ssb_mips_irq(struct ssb_device *dev)
7961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
8061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus = dev->bus;
81ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	struct ssb_device *mdev = bus->mipscore.dev;
8261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u32 irqflag;
8361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u32 ipsflag;
8461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u32 tmp;
8561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	unsigned int irq;
8661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
8761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	irqflag = ssb_irqflag(dev);
88ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	if (irqflag == 0x3f)
89ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		return 6;
9061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
9161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	for (irq = 1; irq <= 4; irq++) {
9261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
9361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if (tmp == irqflag)
9461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			break;
9561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
96ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	if (irq	== 5) {
97ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
98ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET			irq = 0;
99ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	}
10061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
10161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return irq;
10261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
10361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
10461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic void clear_irq(struct ssb_bus *bus, unsigned int irq)
10561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
10661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_device *dev = bus->mipscore.dev;
10761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
10861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	/* Clear the IRQ in the MIPScore backplane registers */
10961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (irq == 0) {
11061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		ssb_write32(dev, SSB_INTVEC, 0);
11161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	} else {
11261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		ssb_write32(dev, SSB_IPSFLAG,
11361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			    ssb_read32(dev, SSB_IPSFLAG) |
11461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			    ipsflag_irq_mask[irq]);
11561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
11661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
11761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
11861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic void set_irq(struct ssb_device *dev, unsigned int irq)
11961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
12061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	unsigned int oldirq = ssb_mips_irq(dev);
12161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus = dev->bus;
12261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_device *mdev = bus->mipscore.dev;
12361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u32 irqflag = ssb_irqflag(dev);
12461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
125ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	BUG_ON(oldirq == 6);
126ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET
12761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	dev->irq = irq + 2;
12861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
12961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	/* clear the old irq */
13061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (oldirq == 0)
13161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
132ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	else if (oldirq != 5)
13361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		clear_irq(bus, oldirq);
13461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
13561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	/* assign the new one */
1362633da237ba29875294f8680ebece5900ccdcc05Michael Buesch	if (irq == 0) {
1372633da237ba29875294f8680ebece5900ccdcc05Michael Buesch		ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
1382633da237ba29875294f8680ebece5900ccdcc05Michael Buesch	} else {
139ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
140ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
141ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET			u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
142ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET			struct ssb_device *olddev = find_device(dev, oldipsflag);
143ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET			if (olddev)
144ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET				set_irq(olddev, 0);
145ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		}
1462633da237ba29875294f8680ebece5900ccdcc05Michael Buesch		irqflag <<= ipsflag_irq_shift[irq];
147ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
1482633da237ba29875294f8680ebece5900ccdcc05Michael Buesch		ssb_write32(mdev, SSB_IPSFLAG, irqflag);
1492633da237ba29875294f8680ebece5900ccdcc05Michael Buesch	}
150ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	ssb_dprintk(KERN_INFO PFX
151ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		    "set_irq: core 0x%04x, irq %d => %d\n",
152ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		    dev->id.coreid, oldirq+2, irq+2);
153ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET}
154ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET
155ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTETstatic void print_irq(struct ssb_device *dev, unsigned int irq)
156ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET{
157ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	int i;
158ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
159ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	ssb_dprintk(KERN_INFO PFX
160ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		"core 0x%04x, irq :", dev->id.coreid);
161ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	for (i = 0; i <= 6; i++) {
162ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
163ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	}
164ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	ssb_dprintk("\n");
165ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET}
166ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET
167ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTETstatic void dump_irq(struct ssb_bus *bus)
168ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET{
169ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	int i;
170ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	for (i = 0; i < bus->nr_devices; i++) {
171ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		struct ssb_device *dev;
172ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		dev = &(bus->devices[i]);
173ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		print_irq(dev, ssb_mips_irq(dev));
174ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	}
17561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
17661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
17761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic void ssb_mips_serial_init(struct ssb_mipscore *mcore)
17861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
17961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus = mcore->dev->bus;
18061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
18161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (bus->extif.dev)
18261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
18361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	else if (bus->chipco.dev)
18461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
18561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	else
18661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		mcore->nr_serial_ports = 0;
18761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
18861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
18961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschstatic void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
19061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
19161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus = mcore->dev->bus;
19261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
19361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	mcore->flash_buswidth = 2;
19461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (bus->chipco.dev) {
19561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		mcore->flash_window = 0x1c000000;
19661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		mcore->flash_window_size = 0x02000000;
19761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
19861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		               & SSB_CHIPCO_CFG_DS16) == 0)
19961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			mcore->flash_buswidth = 1;
20061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	} else {
20161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		mcore->flash_window = 0x1fc00000;
20261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		mcore->flash_window_size = 0x00400000;
20361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
20461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
20561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
20661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschu32 ssb_cpu_clock(struct ssb_mipscore *mcore)
20761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
20861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_bus *bus = mcore->dev->bus;
20961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	u32 pll_type, n, m, rate = 0;
21061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
211d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens	if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)
212d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens		return ssb_pmu_get_cpu_clock(&bus->chipco);
213d486a5b4996d2fffd10098725781f2c5690774bcHauke Mehrtens
21461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (bus->extif.dev) {
21561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
21661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	} else if (bus->chipco.dev) {
21761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
21861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	} else
21961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return 0;
22061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
22161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
22261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		rate = 200000000;
22361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	} else {
22461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		rate = ssb_calc_clock_rate(pll_type, n, m);
22561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
22661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
22761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (pll_type == SSB_PLLTYPE_6) {
22861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		rate *= 2;
22961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
23061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
23161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	return rate;
23261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
23361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
23461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Bueschvoid ssb_mipscore_init(struct ssb_mipscore *mcore)
23561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch{
2367007d00caca268e1ba2bcaa6bed4a6456a96884bFelix Fietkau	struct ssb_bus *bus;
23761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	struct ssb_device *dev;
23861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	unsigned long hz, ns;
23961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	unsigned int irq, i;
24061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
24161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (!mcore->dev)
24261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		return; /* We don't have a MIPS core */
24361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
24461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
24561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
2467007d00caca268e1ba2bcaa6bed4a6456a96884bFelix Fietkau	bus = mcore->dev->bus;
24761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	hz = ssb_clockspeed(bus);
24861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (!hz)
24961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		hz = 100000000;
25061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ns = 1000000000 / hz;
25161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
25261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	if (bus->extif.dev)
25361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		ssb_extif_timing_init(&bus->extif, ns);
25461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	else if (bus->chipco.dev)
25561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		ssb_chipco_timing_init(&bus->chipco, ns);
25661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
25761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	/* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
25861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	for (irq = 2, i = 0; i < bus->nr_devices; i++) {
259ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		int mips_irq;
26061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		dev = &(bus->devices[i]);
261ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		mips_irq = ssb_mips_irq(dev);
262ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		if (mips_irq > 4)
263ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET			dev->irq = 0;
264ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		else
265ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET			dev->irq = mips_irq + 2;
266ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET		if (dev->irq > 5)
267ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET			continue;
26861e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		switch (dev->id.coreid) {
26961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		case SSB_DEV_USB11_HOST:
27061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			/* shouldn't need a separate irq line for non-4710, most of them have a proper
27161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			 * external usb controller on the pci */
27261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			if ((bus->chip_id == 0x4710) && (irq <= 4)) {
27361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				set_irq(dev, irq++);
27461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			}
275ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET			break;
27661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		case SSB_DEV_PCI:
27761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		case SSB_DEV_ETHERNET:
278aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		case SSB_DEV_ETHERNET_GBIT:
27961e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		case SSB_DEV_80211:
28061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		case SSB_DEV_USB20_HOST:
28161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			/* These devices get their own IRQ line if available, the rest goes on IRQ0 */
28261e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			if (irq <= 4) {
28361e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				set_irq(dev, irq++);
28461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch				break;
28561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch			}
28683e34f03ee9b86b49bde4707a1fe03a1837e29beJochen Friedrich			/* fallthrough */
28783e34f03ee9b86b49bde4707a1fe03a1837e29beJochen Friedrich		case SSB_DEV_EXTIF:
28883e34f03ee9b86b49bde4707a1fe03a1837e29beJochen Friedrich			set_irq(dev, 0);
28983e34f03ee9b86b49bde4707a1fe03a1837e29beJochen Friedrich			break;
29061e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch		}
29161e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	}
292ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
293ea4bbfd0048c53c24f72ef668b39f1247bc243c0Matthieu CASTET	dump_irq(bus);
29461e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch
29561e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_mips_serial_init(mcore);
29661e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch	ssb_mips_flash_detect(mcore);
29761e115a56d1aafd6e6a8a9fee8ac099a6128ac7bMichael Buesch}
298