]>
Commit | Line | Data |
---|---|---|
21e0534a HM |
1 | /* |
2 | * Broadcom specific AMBA | |
3 | * Broadcom MIPS32 74K core driver | |
4 | * | |
5 | * Copyright 2009, Broadcom Corporation | |
6 | * Copyright 2006, 2007, Michael Buesch <[email protected]> | |
7 | * Copyright 2010, Bernhard Loos <[email protected]> | |
8 | * Copyright 2011, Hauke Mehrtens <[email protected]> | |
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 */ | |
23 | static 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 */ | |
30 | static 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 | ||
38 | static inline u32 mips_read32(struct bcma_drv_mips *mcore, | |
39 | u16 offset) | |
40 | { | |
41 | return bcma_read32(mcore->core, offset); | |
42 | } | |
43 | ||
44 | static 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 | ||
51 | static 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 | ||
59 | static 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 | ||
67 | static 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 | */ | |
83 | unsigned 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 | } | |
98 | EXPORT_SYMBOL(bcma_core_mips_irq); | |
99 | ||
100 | static 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 | ||
150 | static 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 | ||
160 | static 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 | ||
908debc8 HM |
169 | u32 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 | } | |
179 | EXPORT_SYMBOL(bcma_cpu_clock); | |
180 | ||
21e0534a HM |
181 | static 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 | ||
206 | void 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 | ||
e3afe0e5 | 253 | bcma_chipco_serial_init(&bus->drv_cc); |
21e0534a HM |
254 | bcma_core_mips_flash_detect(mcore); |
255 | mcore->setup_done = true; | |
256 | } |