1 | /* |
2 | * Sonics Silicon Backplane |
3 | * Broadcom ChipCommon core driver |
4 | * |
5 | * Copyright 2005, Broadcom Corporation |
6 | * Copyright 2006, 2007, Michael Buesch <m@bues.ch> |
7 | * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de> |
8 | * |
9 | * Licensed under the GNU/GPL. See COPYING for details. |
10 | */ |
11 | |
12 | #include "ssb_private.h" |
13 | |
14 | #include <linux/ssb/ssb.h> |
15 | #include <linux/ssb/ssb_regs.h> |
16 | #include <linux/export.h> |
17 | #include <linux/pci.h> |
18 | #include <linux/bcm47xx_wdt.h> |
19 | |
20 | |
21 | /* Clock sources */ |
22 | enum ssb_clksrc { |
23 | /* PCI clock */ |
24 | SSB_CHIPCO_CLKSRC_PCI, |
25 | /* Crystal slow clock oscillator */ |
26 | SSB_CHIPCO_CLKSRC_XTALOS, |
27 | /* Low power oscillator */ |
28 | SSB_CHIPCO_CLKSRC_LOPWROS, |
29 | }; |
30 | |
31 | |
32 | static inline u32 chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, |
33 | u32 mask, u32 value) |
34 | { |
35 | value &= mask; |
36 | value |= chipco_read32(cc, offset) & ~mask; |
37 | chipco_write32(cc, offset, value); |
38 | |
39 | return value; |
40 | } |
41 | |
42 | void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, |
43 | enum ssb_clkmode mode) |
44 | { |
45 | struct ssb_device *ccdev = cc->dev; |
46 | struct ssb_bus *bus; |
47 | u32 tmp; |
48 | |
49 | if (!ccdev) |
50 | return; |
51 | bus = ccdev->bus; |
52 | |
53 | /* We support SLOW only on 6..9 */ |
54 | if (ccdev->id.revision >= 10 && mode == SSB_CLKMODE_SLOW) |
55 | mode = SSB_CLKMODE_DYNAMIC; |
56 | |
57 | if (cc->capabilities & SSB_CHIPCO_CAP_PMU) |
58 | return; /* PMU controls clockmode, separated function needed */ |
59 | WARN_ON(ccdev->id.revision >= 20); |
60 | |
61 | /* chipcommon cores prior to rev6 don't support dynamic clock control */ |
62 | if (ccdev->id.revision < 6) |
63 | return; |
64 | |
65 | /* ChipCommon cores rev10+ need testing */ |
66 | if (ccdev->id.revision >= 10) |
67 | return; |
68 | |
69 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) |
70 | return; |
71 | |
72 | switch (mode) { |
73 | case SSB_CLKMODE_SLOW: /* For revs 6..9 only */ |
74 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); |
75 | tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW; |
76 | chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); |
77 | break; |
78 | case SSB_CLKMODE_FAST: |
79 | if (ccdev->id.revision < 10) { |
80 | ssb_pci_xtal(bus, SSB_GPIO_XTAL, turn_on: 1); /* Force crystal on */ |
81 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); |
82 | tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; |
83 | tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; |
84 | chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); |
85 | } else { |
86 | chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, |
87 | (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) | |
88 | SSB_CHIPCO_SYSCLKCTL_FORCEHT)); |
89 | /* udelay(150); TODO: not available in early init */ |
90 | } |
91 | break; |
92 | case SSB_CLKMODE_DYNAMIC: |
93 | if (ccdev->id.revision < 10) { |
94 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); |
95 | tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; |
96 | tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; |
97 | tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; |
98 | if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != |
99 | SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) |
100 | tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; |
101 | chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); |
102 | |
103 | /* For dynamic control, we have to release our xtal_pu |
104 | * "force on" */ |
105 | if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) |
106 | ssb_pci_xtal(bus, SSB_GPIO_XTAL, turn_on: 0); |
107 | } else { |
108 | chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, |
109 | (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & |
110 | ~SSB_CHIPCO_SYSCLKCTL_FORCEHT)); |
111 | } |
112 | break; |
113 | default: |
114 | WARN_ON(1); |
115 | } |
116 | } |
117 | |
118 | /* Get the Slow Clock Source */ |
119 | static enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc) |
120 | { |
121 | struct ssb_bus *bus = cc->dev->bus; |
122 | u32 tmp; |
123 | |
124 | if (cc->dev->id.revision < 6) { |
125 | if (bus->bustype == SSB_BUSTYPE_SSB || |
126 | bus->bustype == SSB_BUSTYPE_PCMCIA) |
127 | return SSB_CHIPCO_CLKSRC_XTALOS; |
128 | if (bus->bustype == SSB_BUSTYPE_PCI) { |
129 | pci_read_config_dword(dev: bus->host_pci, SSB_GPIO_OUT, val: &tmp); |
130 | if (tmp & 0x10) |
131 | return SSB_CHIPCO_CLKSRC_PCI; |
132 | return SSB_CHIPCO_CLKSRC_XTALOS; |
133 | } |
134 | } |
135 | if (cc->dev->id.revision < 10) { |
136 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); |
137 | tmp &= 0x7; |
138 | if (tmp == 0) |
139 | return SSB_CHIPCO_CLKSRC_LOPWROS; |
140 | if (tmp == 1) |
141 | return SSB_CHIPCO_CLKSRC_XTALOS; |
142 | if (tmp == 2) |
143 | return SSB_CHIPCO_CLKSRC_PCI; |
144 | } |
145 | |
146 | return SSB_CHIPCO_CLKSRC_XTALOS; |
147 | } |
148 | |
149 | /* Get maximum or minimum (depending on get_max flag) slowclock frequency. */ |
150 | static int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max) |
151 | { |
152 | int limit; |
153 | enum ssb_clksrc clocksrc; |
154 | int divisor = 1; |
155 | u32 tmp; |
156 | |
157 | clocksrc = chipco_pctl_get_slowclksrc(cc); |
158 | if (cc->dev->id.revision < 6) { |
159 | switch (clocksrc) { |
160 | case SSB_CHIPCO_CLKSRC_PCI: |
161 | divisor = 64; |
162 | break; |
163 | case SSB_CHIPCO_CLKSRC_XTALOS: |
164 | divisor = 32; |
165 | break; |
166 | default: |
167 | WARN_ON(1); |
168 | } |
169 | } else if (cc->dev->id.revision < 10) { |
170 | switch (clocksrc) { |
171 | case SSB_CHIPCO_CLKSRC_LOPWROS: |
172 | break; |
173 | case SSB_CHIPCO_CLKSRC_XTALOS: |
174 | case SSB_CHIPCO_CLKSRC_PCI: |
175 | tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); |
176 | divisor = (tmp >> 16) + 1; |
177 | divisor *= 4; |
178 | break; |
179 | } |
180 | } else { |
181 | tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL); |
182 | divisor = (tmp >> 16) + 1; |
183 | divisor *= 4; |
184 | } |
185 | |
186 | switch (clocksrc) { |
187 | case SSB_CHIPCO_CLKSRC_LOPWROS: |
188 | if (get_max) |
189 | limit = 43000; |
190 | else |
191 | limit = 25000; |
192 | break; |
193 | case SSB_CHIPCO_CLKSRC_XTALOS: |
194 | if (get_max) |
195 | limit = 20200000; |
196 | else |
197 | limit = 19800000; |
198 | break; |
199 | case SSB_CHIPCO_CLKSRC_PCI: |
200 | if (get_max) |
201 | limit = 34000000; |
202 | else |
203 | limit = 25000000; |
204 | break; |
205 | } |
206 | limit /= divisor; |
207 | |
208 | return limit; |
209 | } |
210 | |
211 | static void chipco_powercontrol_init(struct ssb_chipcommon *cc) |
212 | { |
213 | struct ssb_bus *bus = cc->dev->bus; |
214 | |
215 | if (bus->chip_id == 0x4321) { |
216 | if (bus->chip_rev == 0) |
217 | chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4); |
218 | else if (bus->chip_rev == 1) |
219 | chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4); |
220 | } |
221 | |
222 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) |
223 | return; |
224 | |
225 | if (cc->dev->id.revision >= 10) { |
226 | /* Set Idle Power clock rate to 1Mhz */ |
227 | chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, |
228 | (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & |
229 | 0x0000FFFF) | 0x00040000); |
230 | } else { |
231 | int maxfreq; |
232 | |
233 | maxfreq = chipco_pctl_clockfreqlimit(cc, get_max: 1); |
234 | chipco_write32(cc, SSB_CHIPCO_PLLONDELAY, |
235 | (maxfreq * 150 + 999999) / 1000000); |
236 | chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY, |
237 | (maxfreq * 15 + 999999) / 1000000); |
238 | } |
239 | } |
240 | |
241 | /* https://bcm-v4.sipsolutions.net/802.11/PmuFastPwrupDelay */ |
242 | static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc) |
243 | { |
244 | struct ssb_bus *bus = cc->dev->bus; |
245 | |
246 | switch (bus->chip_id) { |
247 | case 0x4312: |
248 | case 0x4322: |
249 | case 0x4328: |
250 | return 7000; |
251 | case 0x4325: |
252 | /* TODO: */ |
253 | default: |
254 | return 15000; |
255 | } |
256 | } |
257 | |
258 | /* https://bcm-v4.sipsolutions.net/802.11/ClkctlFastPwrupDelay */ |
259 | static void calc_fast_powerup_delay(struct ssb_chipcommon *cc) |
260 | { |
261 | struct ssb_bus *bus = cc->dev->bus; |
262 | int minfreq; |
263 | unsigned int tmp; |
264 | u32 pll_on_delay; |
265 | |
266 | if (bus->bustype != SSB_BUSTYPE_PCI) |
267 | return; |
268 | |
269 | if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { |
270 | cc->fast_pwrup_delay = pmu_fast_powerup_delay(cc); |
271 | return; |
272 | } |
273 | |
274 | if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) |
275 | return; |
276 | |
277 | minfreq = chipco_pctl_clockfreqlimit(cc, get_max: 0); |
278 | pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY); |
279 | tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; |
280 | WARN_ON(tmp & ~0xFFFF); |
281 | |
282 | cc->fast_pwrup_delay = tmp; |
283 | } |
284 | |
285 | static u32 ssb_chipco_alp_clock(struct ssb_chipcommon *cc) |
286 | { |
287 | if (cc->capabilities & SSB_CHIPCO_CAP_PMU) |
288 | return ssb_pmu_get_alp_clock(cc); |
289 | |
290 | return 20000000; |
291 | } |
292 | |
293 | static u32 ssb_chipco_watchdog_get_max_timer(struct ssb_chipcommon *cc) |
294 | { |
295 | u32 nb; |
296 | |
297 | if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { |
298 | if (cc->dev->id.revision < 26) |
299 | nb = 16; |
300 | else |
301 | nb = (cc->dev->id.revision >= 37) ? 32 : 24; |
302 | } else { |
303 | nb = 28; |
304 | } |
305 | if (nb == 32) |
306 | return 0xffffffff; |
307 | else |
308 | return (1 << nb) - 1; |
309 | } |
310 | |
311 | u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks) |
312 | { |
313 | struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); |
314 | |
315 | if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) |
316 | return 0; |
317 | |
318 | return ssb_chipco_watchdog_timer_set(cc, ticks); |
319 | } |
320 | |
321 | u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms) |
322 | { |
323 | struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); |
324 | u32 ticks; |
325 | |
326 | if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) |
327 | return 0; |
328 | |
329 | ticks = ssb_chipco_watchdog_timer_set(cc, ticks: cc->ticks_per_ms * ms); |
330 | return ticks / cc->ticks_per_ms; |
331 | } |
332 | |
333 | static int ssb_chipco_watchdog_ticks_per_ms(struct ssb_chipcommon *cc) |
334 | { |
335 | struct ssb_bus *bus = cc->dev->bus; |
336 | |
337 | if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { |
338 | /* based on 32KHz ILP clock */ |
339 | return 32; |
340 | } else { |
341 | if (cc->dev->id.revision < 18) |
342 | return ssb_clockspeed(bus) / 1000; |
343 | else |
344 | return ssb_chipco_alp_clock(cc) / 1000; |
345 | } |
346 | } |
347 | |
348 | void ssb_chipcommon_init(struct ssb_chipcommon *cc) |
349 | { |
350 | if (!cc->dev) |
351 | return; /* We don't have a ChipCommon */ |
352 | |
353 | spin_lock_init(&cc->gpio_lock); |
354 | |
355 | if (cc->dev->id.revision >= 11) |
356 | cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); |
357 | dev_dbg(cc->dev->dev, "chipcommon status is 0x%x\n" , cc->status); |
358 | |
359 | if (cc->dev->id.revision >= 20) { |
360 | chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0); |
361 | chipco_write32(cc, SSB_CHIPCO_GPIOPULLDOWN, 0); |
362 | } |
363 | |
364 | ssb_pmu_init(cc); |
365 | chipco_powercontrol_init(cc); |
366 | ssb_chipco_set_clockmode(cc, mode: SSB_CLKMODE_FAST); |
367 | calc_fast_powerup_delay(cc); |
368 | |
369 | if (cc->dev->bus->bustype == SSB_BUSTYPE_SSB) { |
370 | cc->ticks_per_ms = ssb_chipco_watchdog_ticks_per_ms(cc); |
371 | cc->max_timer_ms = ssb_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; |
372 | } |
373 | } |
374 | |
375 | void ssb_chipco_suspend(struct ssb_chipcommon *cc) |
376 | { |
377 | if (!cc->dev) |
378 | return; |
379 | ssb_chipco_set_clockmode(cc, mode: SSB_CLKMODE_SLOW); |
380 | } |
381 | |
382 | void ssb_chipco_resume(struct ssb_chipcommon *cc) |
383 | { |
384 | if (!cc->dev) |
385 | return; |
386 | chipco_powercontrol_init(cc); |
387 | ssb_chipco_set_clockmode(cc, mode: SSB_CLKMODE_FAST); |
388 | } |
389 | |
390 | /* Get the processor clock */ |
391 | void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, |
392 | u32 *plltype, u32 *n, u32 *m) |
393 | { |
394 | *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); |
395 | *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); |
396 | switch (*plltype) { |
397 | case SSB_PLLTYPE_2: |
398 | case SSB_PLLTYPE_4: |
399 | case SSB_PLLTYPE_6: |
400 | case SSB_PLLTYPE_7: |
401 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); |
402 | break; |
403 | case SSB_PLLTYPE_3: |
404 | /* 5350 uses m2 to control mips */ |
405 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); |
406 | break; |
407 | default: |
408 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); |
409 | break; |
410 | } |
411 | } |
412 | |
413 | /* Get the bus clock */ |
414 | void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, |
415 | u32 *plltype, u32 *n, u32 *m) |
416 | { |
417 | *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); |
418 | *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); |
419 | switch (*plltype) { |
420 | case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ |
421 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); |
422 | break; |
423 | case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ |
424 | if (cc->dev->bus->chip_id != 0x5365) { |
425 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); |
426 | break; |
427 | } |
428 | fallthrough; |
429 | default: |
430 | *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); |
431 | } |
432 | } |
433 | |
434 | void ssb_chipco_timing_init(struct ssb_chipcommon *cc, |
435 | unsigned long ns) |
436 | { |
437 | struct ssb_device *dev = cc->dev; |
438 | struct ssb_bus *bus = dev->bus; |
439 | u32 tmp; |
440 | |
441 | /* set register for external IO to control LED. */ |
442 | chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11); |
443 | tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ |
444 | tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 40ns */ |
445 | tmp |= DIV_ROUND_UP(240, ns); /* Waitcount-0 = 240ns */ |
446 | chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ |
447 | |
448 | /* Set timing for the flash */ |
449 | tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT; /* Waitcount-3 = 10nS */ |
450 | tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT; /* Waitcount-1 = 10nS */ |
451 | tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120nS */ |
452 | if ((bus->chip_id == 0x5365) || |
453 | (dev->id.revision < 9)) |
454 | chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp); |
455 | if ((bus->chip_id == 0x5365) || |
456 | (dev->id.revision < 9) || |
457 | ((bus->chip_id == 0x5350) && (bus->chip_rev == 0))) |
458 | chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp); |
459 | |
460 | if (bus->chip_id == 0x5350) { |
461 | /* Enable EXTIF */ |
462 | tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ |
463 | tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; /* Waitcount-2 = 20ns */ |
464 | tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */ |
465 | tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120ns */ |
466 | chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ |
467 | } |
468 | } |
469 | |
470 | /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ |
471 | u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) |
472 | { |
473 | u32 maxt; |
474 | enum ssb_clkmode clkmode; |
475 | |
476 | maxt = ssb_chipco_watchdog_get_max_timer(cc); |
477 | if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { |
478 | if (ticks == 1) |
479 | ticks = 2; |
480 | else if (ticks > maxt) |
481 | ticks = maxt; |
482 | chipco_write32(cc, SSB_CHIPCO_PMU_WATCHDOG, ticks); |
483 | } else { |
484 | clkmode = ticks ? SSB_CLKMODE_FAST : SSB_CLKMODE_DYNAMIC; |
485 | ssb_chipco_set_clockmode(cc, mode: clkmode); |
486 | if (ticks > maxt) |
487 | ticks = maxt; |
488 | /* instant NMI */ |
489 | chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); |
490 | } |
491 | return ticks; |
492 | } |
493 | |
494 | void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value) |
495 | { |
496 | chipco_write32_masked(cc, SSB_CHIPCO_IRQMASK, mask, value); |
497 | } |
498 | |
499 | u32 ssb_chipco_irq_status(struct ssb_chipcommon *cc, u32 mask) |
500 | { |
501 | return chipco_read32(cc, SSB_CHIPCO_IRQSTAT) & mask; |
502 | } |
503 | |
504 | u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) |
505 | { |
506 | return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; |
507 | } |
508 | |
509 | u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) |
510 | { |
511 | unsigned long flags; |
512 | u32 res = 0; |
513 | |
514 | spin_lock_irqsave(&cc->gpio_lock, flags); |
515 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); |
516 | spin_unlock_irqrestore(lock: &cc->gpio_lock, flags); |
517 | |
518 | return res; |
519 | } |
520 | |
521 | u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) |
522 | { |
523 | unsigned long flags; |
524 | u32 res = 0; |
525 | |
526 | spin_lock_irqsave(&cc->gpio_lock, flags); |
527 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); |
528 | spin_unlock_irqrestore(lock: &cc->gpio_lock, flags); |
529 | |
530 | return res; |
531 | } |
532 | |
533 | u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) |
534 | { |
535 | unsigned long flags; |
536 | u32 res = 0; |
537 | |
538 | spin_lock_irqsave(&cc->gpio_lock, flags); |
539 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); |
540 | spin_unlock_irqrestore(lock: &cc->gpio_lock, flags); |
541 | |
542 | return res; |
543 | } |
544 | EXPORT_SYMBOL(ssb_chipco_gpio_control); |
545 | |
546 | u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) |
547 | { |
548 | unsigned long flags; |
549 | u32 res = 0; |
550 | |
551 | spin_lock_irqsave(&cc->gpio_lock, flags); |
552 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); |
553 | spin_unlock_irqrestore(lock: &cc->gpio_lock, flags); |
554 | |
555 | return res; |
556 | } |
557 | |
558 | u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) |
559 | { |
560 | unsigned long flags; |
561 | u32 res = 0; |
562 | |
563 | spin_lock_irqsave(&cc->gpio_lock, flags); |
564 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); |
565 | spin_unlock_irqrestore(lock: &cc->gpio_lock, flags); |
566 | |
567 | return res; |
568 | } |
569 | |
570 | u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value) |
571 | { |
572 | unsigned long flags; |
573 | u32 res = 0; |
574 | |
575 | if (cc->dev->id.revision < 20) |
576 | return 0xffffffff; |
577 | |
578 | spin_lock_irqsave(&cc->gpio_lock, flags); |
579 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value); |
580 | spin_unlock_irqrestore(lock: &cc->gpio_lock, flags); |
581 | |
582 | return res; |
583 | } |
584 | |
585 | u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value) |
586 | { |
587 | unsigned long flags; |
588 | u32 res = 0; |
589 | |
590 | if (cc->dev->id.revision < 20) |
591 | return 0xffffffff; |
592 | |
593 | spin_lock_irqsave(&cc->gpio_lock, flags); |
594 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value); |
595 | spin_unlock_irqrestore(lock: &cc->gpio_lock, flags); |
596 | |
597 | return res; |
598 | } |
599 | |
600 | #ifdef CONFIG_SSB_SERIAL |
601 | int ssb_chipco_serial_init(struct ssb_chipcommon *cc, |
602 | struct ssb_serial_port *ports) |
603 | { |
604 | struct ssb_bus *bus = cc->dev->bus; |
605 | int nr_ports = 0; |
606 | u32 plltype; |
607 | unsigned int irq; |
608 | u32 baud_base, div; |
609 | u32 i, n; |
610 | unsigned int ccrev = cc->dev->id.revision; |
611 | |
612 | plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); |
613 | irq = ssb_mips_irq(cc->dev); |
614 | |
615 | if (plltype == SSB_PLLTYPE_1) { |
616 | /* PLL clock */ |
617 | baud_base = ssb_calc_clock_rate(plltype, |
618 | chipco_read32(cc, SSB_CHIPCO_CLOCK_N), |
619 | chipco_read32(cc, SSB_CHIPCO_CLOCK_M2)); |
620 | div = 1; |
621 | } else { |
622 | if (ccrev == 20) { |
623 | /* BCM5354 uses constant 25MHz clock */ |
624 | baud_base = 25000000; |
625 | div = 48; |
626 | /* Set the override bit so we don't divide it */ |
627 | chipco_write32(cc, SSB_CHIPCO_CORECTL, |
628 | chipco_read32(cc, SSB_CHIPCO_CORECTL) |
629 | | SSB_CHIPCO_CORECTL_UARTCLK0); |
630 | } else if ((ccrev >= 11) && (ccrev != 15)) { |
631 | baud_base = ssb_chipco_alp_clock(cc); |
632 | div = 1; |
633 | if (ccrev >= 21) { |
634 | /* Turn off UART clock before switching clocksource. */ |
635 | chipco_write32(cc, SSB_CHIPCO_CORECTL, |
636 | chipco_read32(cc, SSB_CHIPCO_CORECTL) |
637 | & ~SSB_CHIPCO_CORECTL_UARTCLKEN); |
638 | } |
639 | /* Set the override bit so we don't divide it */ |
640 | chipco_write32(cc, SSB_CHIPCO_CORECTL, |
641 | chipco_read32(cc, SSB_CHIPCO_CORECTL) |
642 | | SSB_CHIPCO_CORECTL_UARTCLK0); |
643 | if (ccrev >= 21) { |
644 | /* Re-enable the UART clock. */ |
645 | chipco_write32(cc, SSB_CHIPCO_CORECTL, |
646 | chipco_read32(cc, SSB_CHIPCO_CORECTL) |
647 | | SSB_CHIPCO_CORECTL_UARTCLKEN); |
648 | } |
649 | } else if (ccrev >= 3) { |
650 | /* Internal backplane clock */ |
651 | baud_base = ssb_clockspeed(bus); |
652 | div = chipco_read32(cc, SSB_CHIPCO_CLKDIV) |
653 | & SSB_CHIPCO_CLKDIV_UART; |
654 | } else { |
655 | /* Fixed internal backplane clock */ |
656 | baud_base = 88000000; |
657 | div = 48; |
658 | } |
659 | |
660 | /* Clock source depends on strapping if UartClkOverride is unset */ |
661 | if ((ccrev > 0) && |
662 | !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) { |
663 | if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) == |
664 | SSB_CHIPCO_CAP_UARTCLK_INT) { |
665 | /* Internal divided backplane clock */ |
666 | baud_base /= div; |
667 | } else { |
668 | /* Assume external clock of 1.8432 MHz */ |
669 | baud_base = 1843200; |
670 | } |
671 | } |
672 | } |
673 | |
674 | /* Determine the registers of the UARTs */ |
675 | n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART); |
676 | for (i = 0; i < n; i++) { |
677 | void __iomem *cc_mmio; |
678 | void __iomem *uart_regs; |
679 | |
680 | cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE); |
681 | uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA; |
682 | /* Offset changed at after rev 0 */ |
683 | if (ccrev == 0) |
684 | uart_regs += (i * 8); |
685 | else |
686 | uart_regs += (i * 256); |
687 | |
688 | nr_ports++; |
689 | ports[i].regs = uart_regs; |
690 | ports[i].irq = irq; |
691 | ports[i].baud_base = baud_base; |
692 | ports[i].reg_shift = 0; |
693 | } |
694 | |
695 | return nr_ports; |
696 | } |
697 | #endif /* CONFIG_SSB_SERIAL */ |
698 | |