Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Broadcom specific AMBA
  3 * Broadcom MIPS32 74K core driver
  4 *
  5 * Copyright 2009, Broadcom Corporation
  6 * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
  7 * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
  8 * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
  9 *
 10 * Licensed under the GNU/GPL. See COPYING for details.
 11 */
 12
 13#include "bcma_private.h"
 14
 15#include <linux/bcma/bcma.h>
 16
 17#include <linux/serial.h>
 18#include <linux/serial_core.h>
 19#include <linux/serial_reg.h>
 20#include <linux/time.h>
 21
 22/* The 47162a0 hangs when reading MIPS DMP registers registers */
 23static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
 24{
 25	return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
 26	       dev->id.id == BCMA_CORE_MIPS_74K;
 27}
 28
 29/* The 5357b0 hangs when reading USB20H DMP registers */
 30static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
 31{
 32	return (dev->bus->chipinfo.id == 0x5357 ||
 33		dev->bus->chipinfo.id == 0x4749) &&
 34	       dev->bus->chipinfo.pkg == 11 &&
 35	       dev->id.id == BCMA_CORE_USB20_HOST;
 36}
 37
 38static inline u32 mips_read32(struct bcma_drv_mips *mcore,
 39			      u16 offset)
 40{
 41	return bcma_read32(mcore->core, offset);
 42}
 43
 44static inline void mips_write32(struct bcma_drv_mips *mcore,
 45				u16 offset,
 46				u32 value)
 47{
 48	bcma_write32(mcore->core, offset, value);
 49}
 50
 51static const u32 ipsflag_irq_mask[] = {
 52	0,
 53	BCMA_MIPS_IPSFLAG_IRQ1,
 54	BCMA_MIPS_IPSFLAG_IRQ2,
 55	BCMA_MIPS_IPSFLAG_IRQ3,
 56	BCMA_MIPS_IPSFLAG_IRQ4,
 57};
 58
 59static const u32 ipsflag_irq_shift[] = {
 60	0,
 61	BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
 62	BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
 63	BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
 64	BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
 65};
 66
 67static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
 68{
 69	u32 flag;
 70
 71	if (bcma_core_mips_bcm47162a0_quirk(dev))
 72		return dev->core_index;
 73	if (bcma_core_mips_bcm5357b0_quirk(dev))
 74		return dev->core_index;
 75	flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
 76
 77	return flag & 0x1F;
 78}
 79
 80/* Get the MIPS IRQ assignment for a specified device.
 81 * If unassigned, 0 is returned.
 82 */
 83unsigned int bcma_core_mips_irq(struct bcma_device *dev)
 84{
 85	struct bcma_device *mdev = dev->bus->drv_mips.core;
 86	u32 irqflag;
 87	unsigned int irq;
 88
 89	irqflag = bcma_core_mips_irqflag(dev);
 90
 91	for (irq = 1; irq <= 4; irq++)
 92		if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
 93		    (1 << irqflag))
 94			return irq;
 95
 96	return 0;
 97}
 98EXPORT_SYMBOL(bcma_core_mips_irq);
 99
100static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
101{
102	unsigned int oldirq = bcma_core_mips_irq(dev);
103	struct bcma_bus *bus = dev->bus;
104	struct bcma_device *mdev = bus->drv_mips.core;
105	u32 irqflag;
106
107	irqflag = bcma_core_mips_irqflag(dev);
108	BUG_ON(oldirq == 6);
109
110	dev->irq = irq + 2;
111
112	/* clear the old irq */
113	if (oldirq == 0)
114		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
115			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
116			    ~(1 << irqflag));
117	else
118		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
119
120	/* assign the new one */
121	if (irq == 0) {
122		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
123			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
124			    (1 << irqflag));
125	} else {
126		u32 oldirqflag = bcma_read32(mdev,
127					     BCMA_MIPS_MIPS74K_INTMASK(irq));
128		if (oldirqflag) {
129			struct bcma_device *core;
130
131			/* backplane irq line is in use, find out who uses
132			 * it and set user to irq 0
133			 */
134			list_for_each_entry_reverse(core, &bus->cores, list) {
135				if ((1 << bcma_core_mips_irqflag(core)) ==
136				    oldirqflag) {
137					bcma_core_mips_set_irq(core, 0);
138					break;
139				}
140			}
141		}
142		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
143			     1 << irqflag);
144	}
145
146	pr_info("set_irq: core 0x%04x, irq %d => %d\n",
147		dev->id.id, oldirq + 2, irq + 2);
148}
149
150static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
151{
152	int i;
153	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
154	printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
155	for (i = 0; i <= 6; i++)
156		printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
157	printk("\n");
158}
159
160static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
161{
162	struct bcma_device *core;
163
164	list_for_each_entry_reverse(core, &bus->cores, list) {
165		bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
166	}
167}
168
169u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
170{
171	struct bcma_bus *bus = mcore->core->bus;
172
173	if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
174		return bcma_pmu_get_clockcpu(&bus->drv_cc);
175
176	pr_err("No PMU available, need this to get the cpu clock\n");
177	return 0;
178}
179EXPORT_SYMBOL(bcma_cpu_clock);
180
181static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
182{
183	struct bcma_bus *bus = mcore->core->bus;
184
185	switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
186	case BCMA_CC_FLASHT_STSER:
187	case BCMA_CC_FLASHT_ATSER:
188		pr_err("Serial flash not supported.\n");
189		break;
190	case BCMA_CC_FLASHT_PARA:
191		pr_info("found parallel flash.\n");
192		bus->drv_cc.pflash.window = 0x1c000000;
193		bus->drv_cc.pflash.window_size = 0x02000000;
194
195		if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
196		     BCMA_CC_FLASH_CFG_DS) == 0)
197			bus->drv_cc.pflash.buswidth = 1;
198		else
199			bus->drv_cc.pflash.buswidth = 2;
200		break;
201	default:
202		pr_err("flash not supported.\n");
203	}
204}
205
206void bcma_core_mips_init(struct bcma_drv_mips *mcore)
207{
208	struct bcma_bus *bus;
209	struct bcma_device *core;
210	bus = mcore->core->bus;
211
212	pr_info("Initializing MIPS core...\n");
213
214	if (!mcore->setup_done)
215		mcore->assigned_irqs = 1;
216
217	/* Assign IRQs to all cores on the bus */
218	list_for_each_entry_reverse(core, &bus->cores, list) {
219		int mips_irq;
220		if (core->irq)
221			continue;
222
223		mips_irq = bcma_core_mips_irq(core);
224		if (mips_irq > 4)
225			core->irq = 0;
226		else
227			core->irq = mips_irq + 2;
228		if (core->irq > 5)
229			continue;
230		switch (core->id.id) {
231		case BCMA_CORE_PCI:
232		case BCMA_CORE_PCIE:
233		case BCMA_CORE_ETHERNET:
234		case BCMA_CORE_ETHERNET_GBIT:
235		case BCMA_CORE_MAC_GBIT:
236		case BCMA_CORE_80211:
237		case BCMA_CORE_USB20_HOST:
238			/* These devices get their own IRQ line if available,
239			 * the rest goes on IRQ0
240			 */
241			if (mcore->assigned_irqs <= 4)
242				bcma_core_mips_set_irq(core,
243						       mcore->assigned_irqs++);
244			break;
245		}
246	}
247	pr_info("IRQ reconfiguration done\n");
248	bcma_core_mips_dump_irq(bus);
249
250	if (mcore->setup_done)
251		return;
252
253	bcma_chipco_serial_init(&bus->drv_cc);
254	bcma_core_mips_flash_detect(mcore);
255	mcore->setup_done = true;
256}