xref: /linux/drivers/bcma/driver_mips.c (revision 4b132aacb0768ac1e652cf517097ea6f237214b9)
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 #ifdef CONFIG_BCM47XX
22 #include <linux/bcm47xx_nvram.h>
23 #endif
24 
25 enum bcma_boot_dev {
26 	BCMA_BOOT_DEV_UNK = 0,
27 	BCMA_BOOT_DEV_ROM,
28 	BCMA_BOOT_DEV_PARALLEL,
29 	BCMA_BOOT_DEV_SERIAL,
30 	BCMA_BOOT_DEV_NAND,
31 };
32 
33 /* The 47162a0 hangs when reading MIPS DMP registers */
34 static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
35 {
36 	return dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM47162 &&
37 	       dev->bus->chipinfo.rev == 0 && dev->id.id == BCMA_CORE_MIPS_74K;
38 }
39 
40 /* The 5357b0 hangs when reading USB20H DMP registers */
41 static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
42 {
43 	return (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 ||
44 		dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) &&
45 	       dev->bus->chipinfo.pkg == 11 &&
46 	       dev->id.id == BCMA_CORE_USB20_HOST;
47 }
48 
49 static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
50 {
51 	u32 flag;
52 
53 	if (bcma_core_mips_bcm47162a0_quirk(dev))
54 		return dev->core_index;
55 	if (bcma_core_mips_bcm5357b0_quirk(dev))
56 		return dev->core_index;
57 	flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
58 
59 	if (flag)
60 		return flag & 0x1F;
61 	else
62 		return 0x3f;
63 }
64 
65 /* Get the MIPS IRQ assignment for a specified device.
66  * If unassigned, 0 is returned.
67  * If disabled, 5 is returned.
68  * If not supported, 6 is returned.
69  */
70 unsigned int bcma_core_mips_irq(struct bcma_device *dev)
71 {
72 	struct bcma_device *mdev = dev->bus->drv_mips.core;
73 	u32 irqflag;
74 	unsigned int irq;
75 
76 	irqflag = bcma_core_mips_irqflag(dev);
77 	if (irqflag == 0x3f)
78 		return 6;
79 
80 	for (irq = 0; irq <= 4; irq++)
81 		if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
82 		    (1 << irqflag))
83 			return irq;
84 
85 	return 5;
86 }
87 
88 static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
89 {
90 	unsigned int oldirq = bcma_core_mips_irq(dev);
91 	struct bcma_bus *bus = dev->bus;
92 	struct bcma_device *mdev = bus->drv_mips.core;
93 	u32 irqflag;
94 
95 	irqflag = bcma_core_mips_irqflag(dev);
96 	BUG_ON(oldirq == 6);
97 
98 	dev->irq = irq + 2;
99 
100 	/* clear the old irq */
101 	if (oldirq == 0)
102 		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
103 			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
104 			    ~(1 << irqflag));
105 	else if (oldirq != 5)
106 		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
107 
108 	/* assign the new one */
109 	if (irq == 0) {
110 		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
111 			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
112 			    (1 << irqflag));
113 	} else {
114 		u32 irqinitmask = bcma_read32(mdev,
115 					      BCMA_MIPS_MIPS74K_INTMASK(irq));
116 		if (irqinitmask) {
117 			struct bcma_device *core;
118 
119 			/* backplane irq line is in use, find out who uses
120 			 * it and set user to irq 0
121 			 */
122 			list_for_each_entry(core, &bus->cores, list) {
123 				if ((1 << bcma_core_mips_irqflag(core)) ==
124 				    irqinitmask) {
125 					bcma_core_mips_set_irq(core, 0);
126 					break;
127 				}
128 			}
129 		}
130 		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
131 			     1 << irqflag);
132 	}
133 
134 	bcma_debug(bus, "set_irq: core 0x%04x, irq %d => %d\n",
135 		   dev->id.id, oldirq <= 4 ? oldirq + 2 : 0, irq + 2);
136 }
137 
138 static void bcma_core_mips_set_irq_name(struct bcma_bus *bus, unsigned int irq,
139 					u16 coreid, u8 unit)
140 {
141 	struct bcma_device *core;
142 
143 	core = bcma_find_core_unit(bus, coreid, unit);
144 	if (!core) {
145 		bcma_warn(bus,
146 			  "Can not find core (id: 0x%x, unit %i) for IRQ configuration.\n",
147 			  coreid, unit);
148 		return;
149 	}
150 
151 	bcma_core_mips_set_irq(core, irq);
152 }
153 
154 static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
155 {
156 	int i;
157 	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
158 	char interrupts[25];
159 	char *ints = interrupts;
160 
161 	for (i = 0; i < ARRAY_SIZE(irq_name); i++)
162 		ints += sprintf(ints, " %s%c",
163 				irq_name[i], i == irq ? '*' : ' ');
164 
165 	bcma_debug(dev->bus, "core 0x%04x, irq:%s\n", dev->id.id, interrupts);
166 }
167 
168 static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
169 {
170 	struct bcma_device *core;
171 
172 	list_for_each_entry(core, &bus->cores, list) {
173 		bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
174 	}
175 }
176 
177 u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
178 {
179 	struct bcma_bus *bus = mcore->core->bus;
180 
181 	if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
182 		return bcma_pmu_get_cpu_clock(&bus->drv_cc);
183 
184 	bcma_err(bus, "No PMU available, need this to get the cpu clock\n");
185 	return 0;
186 }
187 EXPORT_SYMBOL(bcma_cpu_clock);
188 
189 static enum bcma_boot_dev bcma_boot_dev(struct bcma_bus *bus)
190 {
191 	struct bcma_drv_cc *cc = &bus->drv_cc;
192 	u8 cc_rev = cc->core->id.rev;
193 
194 	if (cc_rev == 42) {
195 		struct bcma_device *core;
196 
197 		core = bcma_find_core(bus, BCMA_CORE_NS_ROM);
198 		if (core) {
199 			switch (bcma_aread32(core, BCMA_IOST) &
200 				BCMA_NS_ROM_IOST_BOOT_DEV_MASK) {
201 			case BCMA_NS_ROM_IOST_BOOT_DEV_NOR:
202 				return BCMA_BOOT_DEV_SERIAL;
203 			case BCMA_NS_ROM_IOST_BOOT_DEV_NAND:
204 				return BCMA_BOOT_DEV_NAND;
205 			case BCMA_NS_ROM_IOST_BOOT_DEV_ROM:
206 			default:
207 				return BCMA_BOOT_DEV_ROM;
208 			}
209 		}
210 	} else {
211 		if (cc_rev == 38) {
212 			if (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT)
213 				return BCMA_BOOT_DEV_NAND;
214 			else if (cc->status & BIT(5))
215 				return BCMA_BOOT_DEV_ROM;
216 		}
217 
218 		if ((cc->capabilities & BCMA_CC_CAP_FLASHT) ==
219 		    BCMA_CC_FLASHT_PARA)
220 			return BCMA_BOOT_DEV_PARALLEL;
221 		else
222 			return BCMA_BOOT_DEV_SERIAL;
223 	}
224 
225 	return BCMA_BOOT_DEV_SERIAL;
226 }
227 
228 static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
229 {
230 	struct bcma_bus *bus = mcore->core->bus;
231 	enum bcma_boot_dev boot_dev;
232 
233 	/* Determine flash type this SoC boots from */
234 	boot_dev = bcma_boot_dev(bus);
235 	switch (boot_dev) {
236 	case BCMA_BOOT_DEV_PARALLEL:
237 	case BCMA_BOOT_DEV_SERIAL:
238 #ifdef CONFIG_BCM47XX
239 		bcm47xx_nvram_init_from_mem(BCMA_SOC_FLASH2,
240 					    BCMA_SOC_FLASH2_SZ);
241 #endif
242 		break;
243 	case BCMA_BOOT_DEV_NAND:
244 #ifdef CONFIG_BCM47XX
245 		bcm47xx_nvram_init_from_mem(BCMA_SOC_FLASH1,
246 					    BCMA_SOC_FLASH1_SZ);
247 #endif
248 		break;
249 	default:
250 		break;
251 	}
252 }
253 
254 void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
255 {
256 	struct bcma_bus *bus = mcore->core->bus;
257 
258 	if (mcore->early_setup_done)
259 		return;
260 
261 	bcma_chipco_serial_init(&bus->drv_cc);
262 	bcma_core_mips_nvram_init(mcore);
263 
264 	mcore->early_setup_done = true;
265 }
266 
267 static void bcma_fix_i2s_irqflag(struct bcma_bus *bus)
268 {
269 	struct bcma_device *cpu, *pcie, *i2s;
270 
271 	/* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK)
272 	 * (IRQ flags > 7 are ignored when setting the interrupt masks)
273 	 */
274 	if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4716 &&
275 	    bus->chipinfo.id != BCMA_CHIP_ID_BCM4748)
276 		return;
277 
278 	cpu = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
279 	pcie = bcma_find_core(bus, BCMA_CORE_PCIE);
280 	i2s = bcma_find_core(bus, BCMA_CORE_I2S);
281 	if (cpu && pcie && i2s &&
282 	    bcma_aread32(cpu, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
283 	    bcma_aread32(pcie, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
284 	    bcma_aread32(i2s, BCMA_MIPS_OOBSELOUTA30) == 0x88) {
285 		bcma_awrite32(cpu, BCMA_MIPS_OOBSELINA74, 0x07060504);
286 		bcma_awrite32(pcie, BCMA_MIPS_OOBSELINA74, 0x07060504);
287 		bcma_awrite32(i2s, BCMA_MIPS_OOBSELOUTA30, 0x87);
288 		bcma_debug(bus,
289 			   "Moved i2s interrupt to oob line 7 instead of 8\n");
290 	}
291 }
292 
293 void bcma_core_mips_init(struct bcma_drv_mips *mcore)
294 {
295 	struct bcma_bus *bus;
296 	struct bcma_device *core;
297 	bus = mcore->core->bus;
298 
299 	if (mcore->setup_done)
300 		return;
301 
302 	bcma_debug(bus, "Initializing MIPS core...\n");
303 
304 	bcma_core_mips_early_init(mcore);
305 
306 	bcma_fix_i2s_irqflag(bus);
307 
308 	switch (bus->chipinfo.id) {
309 	case BCMA_CHIP_ID_BCM4716:
310 	case BCMA_CHIP_ID_BCM4748:
311 		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
312 		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
313 		bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
314 		bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_PCIE, 0);
315 		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
316 		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
317 		break;
318 	case BCMA_CHIP_ID_BCM5356:
319 	case BCMA_CHIP_ID_BCM47162:
320 	case BCMA_CHIP_ID_BCM53572:
321 		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
322 		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
323 		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
324 		break;
325 	case BCMA_CHIP_ID_BCM5357:
326 	case BCMA_CHIP_ID_BCM4749:
327 		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
328 		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
329 		bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
330 		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
331 		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
332 		break;
333 	case BCMA_CHIP_ID_BCM4706:
334 		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_PCIE, 0);
335 		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_4706_MAC_GBIT,
336 					    0);
337 		bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_PCIE, 1);
338 		bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_USB20_HOST, 0);
339 		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_4706_CHIPCOMMON,
340 					    0);
341 		break;
342 	default:
343 		list_for_each_entry(core, &bus->cores, list) {
344 			core->irq = bcma_core_irq(core, 0);
345 		}
346 		bcma_err(bus,
347 			 "Unknown device (0x%x) found, can not configure IRQs\n",
348 			 bus->chipinfo.id);
349 	}
350 	bcma_debug(bus, "IRQ reconfiguration done\n");
351 	bcma_core_mips_dump_irq(bus);
352 
353 	mcore->setup_done = true;
354 }
355