1 | /* |
2 | * Sonics Silicon Backplane |
3 | * Broadcom MIPS core driver |
4 | * |
5 | * Copyright 2005, Broadcom Corporation |
6 | * Copyright 2006, 2007, Michael Buesch <m@bues.ch> |
7 | * |
8 | * Licensed under the GNU/GPL. See COPYING for details. |
9 | */ |
10 | |
11 | #include "ssb_private.h" |
12 | |
13 | #include <linux/ssb/ssb.h> |
14 | |
15 | #include <linux/mtd/physmap.h> |
16 | #include <linux/serial.h> |
17 | #include <linux/serial_core.h> |
18 | #include <linux/serial_reg.h> |
19 | #include <linux/time.h> |
20 | #ifdef CONFIG_BCM47XX |
21 | #include <linux/bcm47xx_nvram.h> |
22 | #endif |
23 | |
24 | static const char * const part_probes[] = { "bcm47xxpart" , NULL }; |
25 | |
26 | static struct physmap_flash_data ssb_pflash_data = { |
27 | .part_probe_types = part_probes, |
28 | }; |
29 | |
30 | static struct resource ssb_pflash_resource = { |
31 | .name = "ssb_pflash" , |
32 | .flags = IORESOURCE_MEM, |
33 | }; |
34 | |
35 | struct platform_device ssb_pflash_dev = { |
36 | .name = "physmap-flash" , |
37 | .dev = { |
38 | .platform_data = &ssb_pflash_data, |
39 | }, |
40 | .resource = &ssb_pflash_resource, |
41 | .num_resources = 1, |
42 | }; |
43 | |
44 | static inline u32 mips_read32(struct ssb_mipscore *mcore, |
45 | u16 offset) |
46 | { |
47 | return ssb_read32(dev: mcore->dev, offset); |
48 | } |
49 | |
50 | static inline void mips_write32(struct ssb_mipscore *mcore, |
51 | u16 offset, |
52 | u32 value) |
53 | { |
54 | ssb_write32(dev: mcore->dev, offset, value); |
55 | } |
56 | |
57 | static const u32 ipsflag_irq_mask[] = { |
58 | 0, |
59 | SSB_IPSFLAG_IRQ1, |
60 | SSB_IPSFLAG_IRQ2, |
61 | SSB_IPSFLAG_IRQ3, |
62 | SSB_IPSFLAG_IRQ4, |
63 | }; |
64 | |
65 | static const u32 ipsflag_irq_shift[] = { |
66 | 0, |
67 | SSB_IPSFLAG_IRQ1_SHIFT, |
68 | SSB_IPSFLAG_IRQ2_SHIFT, |
69 | SSB_IPSFLAG_IRQ3_SHIFT, |
70 | SSB_IPSFLAG_IRQ4_SHIFT, |
71 | }; |
72 | |
73 | static inline u32 ssb_irqflag(struct ssb_device *dev) |
74 | { |
75 | u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG); |
76 | if (tpsflag) |
77 | return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG; |
78 | else |
79 | /* not irq supported */ |
80 | return 0x3f; |
81 | } |
82 | |
83 | static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag) |
84 | { |
85 | struct ssb_bus *bus = rdev->bus; |
86 | int i; |
87 | for (i = 0; i < bus->nr_devices; i++) { |
88 | struct ssb_device *dev; |
89 | dev = &(bus->devices[i]); |
90 | if (ssb_irqflag(dev) == irqflag) |
91 | return dev; |
92 | } |
93 | return NULL; |
94 | } |
95 | |
96 | /* Get the MIPS IRQ assignment for a specified device. |
97 | * If unassigned, 0 is returned. |
98 | * If disabled, 5 is returned. |
99 | * If not supported, 6 is returned. |
100 | */ |
101 | unsigned int ssb_mips_irq(struct ssb_device *dev) |
102 | { |
103 | struct ssb_bus *bus = dev->bus; |
104 | struct ssb_device *mdev = bus->mipscore.dev; |
105 | u32 irqflag; |
106 | u32 ipsflag; |
107 | u32 tmp; |
108 | unsigned int irq; |
109 | |
110 | irqflag = ssb_irqflag(dev); |
111 | if (irqflag == 0x3f) |
112 | return 6; |
113 | ipsflag = ssb_read32(dev: bus->mipscore.dev, SSB_IPSFLAG); |
114 | for (irq = 1; irq <= 4; irq++) { |
115 | tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]); |
116 | if (tmp == irqflag) |
117 | break; |
118 | } |
119 | if (irq == 5) { |
120 | if ((1 << irqflag) & ssb_read32(dev: mdev, SSB_INTVEC)) |
121 | irq = 0; |
122 | } |
123 | |
124 | return irq; |
125 | } |
126 | |
127 | static void clear_irq(struct ssb_bus *bus, unsigned int irq) |
128 | { |
129 | struct ssb_device *dev = bus->mipscore.dev; |
130 | |
131 | /* Clear the IRQ in the MIPScore backplane registers */ |
132 | if (irq == 0) { |
133 | ssb_write32(dev, SSB_INTVEC, value: 0); |
134 | } else { |
135 | ssb_write32(dev, SSB_IPSFLAG, |
136 | value: ssb_read32(dev, SSB_IPSFLAG) | |
137 | ipsflag_irq_mask[irq]); |
138 | } |
139 | } |
140 | |
141 | static void set_irq(struct ssb_device *dev, unsigned int irq) |
142 | { |
143 | unsigned int oldirq = ssb_mips_irq(dev); |
144 | struct ssb_bus *bus = dev->bus; |
145 | struct ssb_device *mdev = bus->mipscore.dev; |
146 | u32 irqflag = ssb_irqflag(dev); |
147 | |
148 | BUG_ON(oldirq == 6); |
149 | |
150 | dev->irq = irq + 2; |
151 | |
152 | /* clear the old irq */ |
153 | if (oldirq == 0) |
154 | ssb_write32(dev: mdev, SSB_INTVEC, value: (~(1 << irqflag) & ssb_read32(dev: mdev, SSB_INTVEC))); |
155 | else if (oldirq != 5) |
156 | clear_irq(bus, irq: oldirq); |
157 | |
158 | /* assign the new one */ |
159 | if (irq == 0) { |
160 | ssb_write32(dev: mdev, SSB_INTVEC, value: ((1 << irqflag) | ssb_read32(dev: mdev, SSB_INTVEC))); |
161 | } else { |
162 | u32 ipsflag = ssb_read32(dev: mdev, SSB_IPSFLAG); |
163 | if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) { |
164 | u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]; |
165 | struct ssb_device *olddev = find_device(rdev: dev, irqflag: oldipsflag); |
166 | if (olddev) |
167 | set_irq(dev: olddev, irq: 0); |
168 | } |
169 | irqflag <<= ipsflag_irq_shift[irq]; |
170 | irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]); |
171 | ssb_write32(dev: mdev, SSB_IPSFLAG, value: irqflag); |
172 | } |
173 | dev_dbg(dev->dev, "set_irq: core 0x%04x, irq %d => %d\n" , |
174 | dev->id.coreid, oldirq+2, irq+2); |
175 | } |
176 | |
177 | static void print_irq(struct ssb_device *dev, unsigned int irq) |
178 | { |
179 | static const char *irq_name[] = {"2(S)" , "3" , "4" , "5" , "6" , "D" , "I" }; |
180 | dev_dbg(dev->dev, |
181 | "core 0x%04x, irq : %s%s %s%s %s%s %s%s %s%s %s%s %s%s\n" , |
182 | dev->id.coreid, |
183 | irq_name[0], irq == 0 ? "*" : " " , |
184 | irq_name[1], irq == 1 ? "*" : " " , |
185 | irq_name[2], irq == 2 ? "*" : " " , |
186 | irq_name[3], irq == 3 ? "*" : " " , |
187 | irq_name[4], irq == 4 ? "*" : " " , |
188 | irq_name[5], irq == 5 ? "*" : " " , |
189 | irq_name[6], irq == 6 ? "*" : " " ); |
190 | } |
191 | |
192 | static void dump_irq(struct ssb_bus *bus) |
193 | { |
194 | int i; |
195 | for (i = 0; i < bus->nr_devices; i++) { |
196 | struct ssb_device *dev; |
197 | dev = &(bus->devices[i]); |
198 | print_irq(dev, irq: ssb_mips_irq(dev)); |
199 | } |
200 | } |
201 | |
202 | static void ssb_mips_serial_init(struct ssb_mipscore *mcore) |
203 | { |
204 | struct ssb_bus *bus = mcore->dev->bus; |
205 | |
206 | if (ssb_extif_available(extif: &bus->extif)) |
207 | mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); |
208 | else if (ssb_chipco_available(cc: &bus->chipco)) |
209 | mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports); |
210 | else |
211 | mcore->nr_serial_ports = 0; |
212 | } |
213 | |
214 | static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) |
215 | { |
216 | struct ssb_bus *bus = mcore->dev->bus; |
217 | struct ssb_sflash *sflash = &mcore->sflash; |
218 | struct ssb_pflash *pflash = &mcore->pflash; |
219 | |
220 | /* When there is no chipcommon on the bus there is 4MB flash */ |
221 | if (!ssb_chipco_available(cc: &bus->chipco)) { |
222 | pflash->present = true; |
223 | pflash->buswidth = 2; |
224 | pflash->window = SSB_FLASH1; |
225 | pflash->window_size = SSB_FLASH1_SZ; |
226 | goto ssb_pflash; |
227 | } |
228 | |
229 | /* There is ChipCommon, so use it to read info about flash */ |
230 | switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) { |
231 | case SSB_CHIPCO_FLASHT_STSER: |
232 | case SSB_CHIPCO_FLASHT_ATSER: |
233 | dev_dbg(mcore->dev->dev, "Found serial flash\n" ); |
234 | ssb_sflash_init(cc: &bus->chipco); |
235 | break; |
236 | case SSB_CHIPCO_FLASHT_PARA: |
237 | dev_dbg(mcore->dev->dev, "Found parallel flash\n" ); |
238 | pflash->present = true; |
239 | pflash->window = SSB_FLASH2; |
240 | pflash->window_size = SSB_FLASH2_SZ; |
241 | if ((ssb_read32(dev: bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) |
242 | & SSB_CHIPCO_CFG_DS16) == 0) |
243 | pflash->buswidth = 1; |
244 | else |
245 | pflash->buswidth = 2; |
246 | break; |
247 | } |
248 | |
249 | ssb_pflash: |
250 | if (sflash->present) { |
251 | #ifdef CONFIG_BCM47XX |
252 | bcm47xx_nvram_init_from_mem(sflash->window, sflash->size); |
253 | #endif |
254 | } else if (pflash->present) { |
255 | #ifdef CONFIG_BCM47XX |
256 | bcm47xx_nvram_init_from_mem(pflash->window, pflash->window_size); |
257 | #endif |
258 | |
259 | ssb_pflash_data.width = pflash->buswidth; |
260 | ssb_pflash_resource.start = pflash->window; |
261 | ssb_pflash_resource.end = pflash->window + pflash->window_size; |
262 | } |
263 | } |
264 | |
265 | u32 ssb_cpu_clock(struct ssb_mipscore *mcore) |
266 | { |
267 | struct ssb_bus *bus = mcore->dev->bus; |
268 | u32 pll_type, n, m, rate = 0; |
269 | |
270 | if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU) |
271 | return ssb_pmu_get_cpu_clock(cc: &bus->chipco); |
272 | |
273 | if (ssb_extif_available(extif: &bus->extif)) { |
274 | ssb_extif_get_clockcontrol(extif: &bus->extif, plltype: &pll_type, n: &n, m: &m); |
275 | } else if (ssb_chipco_available(cc: &bus->chipco)) { |
276 | ssb_chipco_get_clockcpu(cc: &bus->chipco, plltype: &pll_type, n: &n, m: &m); |
277 | } else |
278 | return 0; |
279 | |
280 | if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) { |
281 | rate = 200000000; |
282 | } else { |
283 | rate = ssb_calc_clock_rate(plltype: pll_type, n, m); |
284 | } |
285 | |
286 | if (pll_type == SSB_PLLTYPE_6) { |
287 | rate *= 2; |
288 | } |
289 | |
290 | return rate; |
291 | } |
292 | |
293 | void ssb_mipscore_init(struct ssb_mipscore *mcore) |
294 | { |
295 | struct ssb_bus *bus; |
296 | struct ssb_device *dev; |
297 | unsigned long hz, ns; |
298 | unsigned int irq, i; |
299 | |
300 | if (!mcore->dev) |
301 | return; /* We don't have a MIPS core */ |
302 | |
303 | dev_dbg(mcore->dev->dev, "Initializing MIPS core...\n" ); |
304 | |
305 | bus = mcore->dev->bus; |
306 | hz = ssb_clockspeed(bus); |
307 | if (!hz) |
308 | hz = 100000000; |
309 | ns = 1000000000 / hz; |
310 | |
311 | if (ssb_extif_available(extif: &bus->extif)) |
312 | ssb_extif_timing_init(extif: &bus->extif, ns); |
313 | else if (ssb_chipco_available(cc: &bus->chipco)) |
314 | ssb_chipco_timing_init(cc: &bus->chipco, ns_per_cycle: ns); |
315 | |
316 | /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ |
317 | for (irq = 2, i = 0; i < bus->nr_devices; i++) { |
318 | int mips_irq; |
319 | dev = &(bus->devices[i]); |
320 | mips_irq = ssb_mips_irq(dev); |
321 | if (mips_irq > 4) |
322 | dev->irq = 0; |
323 | else |
324 | dev->irq = mips_irq + 2; |
325 | if (dev->irq > 5) |
326 | continue; |
327 | switch (dev->id.coreid) { |
328 | case SSB_DEV_USB11_HOST: |
329 | /* shouldn't need a separate irq line for non-4710, most of them have a proper |
330 | * external usb controller on the pci */ |
331 | if ((bus->chip_id == 0x4710) && (irq <= 4)) { |
332 | set_irq(dev, irq: irq++); |
333 | } |
334 | break; |
335 | case SSB_DEV_PCI: |
336 | case SSB_DEV_ETHERNET: |
337 | case SSB_DEV_ETHERNET_GBIT: |
338 | case SSB_DEV_80211: |
339 | case SSB_DEV_USB20_HOST: |
340 | /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ |
341 | if (irq <= 4) { |
342 | set_irq(dev, irq: irq++); |
343 | break; |
344 | } |
345 | fallthrough; |
346 | case SSB_DEV_EXTIF: |
347 | set_irq(dev, irq: 0); |
348 | break; |
349 | } |
350 | } |
351 | dev_dbg(mcore->dev->dev, "after irq reconfiguration\n" ); |
352 | dump_irq(bus); |
353 | |
354 | ssb_mips_serial_init(mcore); |
355 | ssb_mips_flash_detect(mcore); |
356 | } |
357 | |