1 /*-
2 * Copyright (c) 2006 M. Warner Losh. All rights reserved.
3 * Copyright (c) 2010 Greg Ansley. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: releng/9.0/sys/arm/at91/at91_pmc.c 216227 2010-12-06 10:24:06Z kevlo $");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/module.h>
35 #include <sys/time.h>
36 #include <sys/bus.h>
37 #include <sys/resource.h>
38 #include <sys/rman.h>
39 #include <sys/timetc.h>
40
41 #include <machine/bus.h>
42 #include <machine/cpu.h>
43 #include <machine/cpufunc.h>
44 #include <machine/resource.h>
45 #include <machine/frame.h>
46 #include <machine/intr.h>
47 #include <arm/at91/at91reg.h>
48 #include <arm/at91/at91var.h>
49
50 #include <arm/at91/at91_pmcreg.h>
51 #include <arm/at91/at91_pmcvar.h>
52
53 static struct at91_pmc_softc {
54 bus_space_tag_t sc_st;
55 bus_space_handle_t sc_sh;
56 struct resource *mem_res; /* Memory resource */
57 device_t dev;
58 unsigned int main_clock_hz;
59 uint32_t pllb_init;
60 } *pmc_softc;
61
62 MALLOC_DECLARE(M_PMC);
63 MALLOC_DEFINE(M_PMC, "at91_pmc_clocks", "AT91 PMC Clock descriptors");
64
65 static void at91_pmc_set_pllb_mode(struct at91_pmc_clock *, int);
66 static void at91_pmc_set_sys_mode(struct at91_pmc_clock *, int);
67 static void at91_pmc_set_periph_mode(struct at91_pmc_clock *, int);
68 static void at91_pmc_clock_alias(const char *name, const char *alias);
69
70 static struct at91_pmc_clock slck = {
71 .name = "slck", // 32,768 Hz slow clock
72 .hz = 32768,
73 .refcnt = 1,
74 .id = 0,
75 .primary = 1,
76 };
77
78 /*
79 * NOTE: Clocks for "ordinary peripheral" devices e.g. spi0, udp0, uhp0 etc.
80 * are now created automatically. Only "system" clocks need be defined here.
81 */
82 static struct at91_pmc_clock main_ck = {
83 .name = "main", // Main clock
84 .refcnt = 0,
85 .id = 1,
86 .primary = 1,
87 .pmc_mask = PMC_IER_MOSCS,
88 };
89
90 static struct at91_pmc_clock plla = {
91 .name = "plla", // PLLA Clock, used for CPU clocking
92 .parent = &main_ck,
93 .refcnt = 1,
94 .id = 0,
95 .primary = 1,
96 .pll = 1,
97 .pmc_mask = PMC_IER_LOCKA,
98 };
99
100 static struct at91_pmc_clock pllb = {
101 .name = "pllb", // PLLB Clock, used for USB functions
102 .parent = &main_ck,
103 .refcnt = 0,
104 .id = 0,
105 .primary = 1,
106 .pll = 1,
107 .pmc_mask = PMC_IER_LOCKB,
108 .set_mode = &at91_pmc_set_pllb_mode,
109 };
110
111 static struct at91_pmc_clock udpck = {
112 .name = "udpck",
113 .parent = &pllb,
114 .pmc_mask = PMC_SCER_UDP,
115 .set_mode = at91_pmc_set_sys_mode
116 };
117
118 static struct at91_pmc_clock uhpck = {
119 .name = "uhpck",
120 .parent = &pllb,
121 .pmc_mask = PMC_SCER_UHP,
122 .set_mode = at91_pmc_set_sys_mode
123 };
124
125 static struct at91_pmc_clock mck = {
126 .name = "mck", // Master (Peripheral) Clock
127 .pmc_mask = PMC_IER_MCKRDY,
128 .refcnt = 0,
129 };
130
131 static struct at91_pmc_clock cpu = {
132 .name = "cpu", // CPU Clock
133 .parent = &plla,
134 .pmc_mask = PMC_SCER_PCK,
135 .refcnt = 0,
136 };
137
138 /* "+32" or the automatic peripheral clocks */
139 static struct at91_pmc_clock *clock_list[16+32] = {
140 &slck,
141 &main_ck,
142 &plla,
143 &pllb,
144 &udpck,
145 &uhpck,
146 &mck,
147 &cpu
148 };
149
150 #if !defined(AT91C_MAIN_CLOCK)
151 static const unsigned int at91_mainf_tbl[] = {
152 3000000, 3276800, 3686400, 3840000, 4000000,
153 4433619, 4915200, 5000000, 5242880, 6000000,
154 6144000, 6400000, 6553600, 7159090, 7372800,
155 7864320, 8000000, 9830400, 10000000, 11059200,
156 12000000, 12288000, 13560000, 14318180, 14745600,
157 16000000, 17344700, 18432000, 20000000
158 };
159 #define MAINF_TBL_LEN (sizeof(at91_mainf_tbl) / sizeof(*at91_mainf_tbl))
160 #endif
161
162 static inline uint32_t
163 RD4(struct at91_pmc_softc *sc, bus_size_t off)
164 {
165 return (bus_read_4(sc->mem_res, off));
166 }
167
168 static inline void
169 WR4(struct at91_pmc_softc *sc, bus_size_t off, uint32_t val)
170 {
171 bus_write_4(sc->mem_res, off, val);
172 }
173
174 void
175 at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on)
176 {
177 struct at91_pmc_softc *sc = pmc_softc;
178 uint32_t value;
179
180 if (on) {
181 on = PMC_IER_LOCKB;
182 value = sc->pllb_init;
183 } else {
184 value = 0;
185 }
186
187 /* Workaround RM9200 Errata #26 */
188 if (at91_is_rm92() &&
189 ((value ^ RD4(sc, CKGR_PLLBR)) & 0x03f0ff) != 0) {
190 WR4(sc, CKGR_PLLBR, value ^ 1);
191 while ((RD4(sc, PMC_SR) & PMC_IER_LOCKB) != on)
192 continue;
193 }
194
195 WR4(sc, CKGR_PLLBR, value);
196 while ((RD4(sc, PMC_SR) & PMC_IER_LOCKB) != on)
197 continue;
198 }
199
200 static void
201 at91_pmc_set_sys_mode(struct at91_pmc_clock *clk, int on)
202 {
203 struct at91_pmc_softc *sc = pmc_softc;
204
205 WR4(sc, on ? PMC_SCER : PMC_SCDR, clk->pmc_mask);
206 if (on)
207 while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) != clk->pmc_mask)
208 continue;
209 else
210 while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) == clk->pmc_mask)
211 continue;
212 }
213
214 static void
215 at91_pmc_set_periph_mode(struct at91_pmc_clock *clk, int on)
216 {
217 struct at91_pmc_softc *sc = pmc_softc;
218
219 WR4(sc, on ? PMC_PCER : PMC_PCDR, clk->pmc_mask);
220 if (on)
221 while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) != clk->pmc_mask)
222 continue;
223 else
224 while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) == clk->pmc_mask)
225 continue;
226 }
227
228 struct at91_pmc_clock *
229 at91_pmc_clock_add(const char *name, uint32_t irq, struct at91_pmc_clock *parent)
230 {
231 struct at91_pmc_clock *clk;
232 int i, buflen;
233
234 clk = malloc(sizeof(*clk), M_PMC, M_NOWAIT | M_ZERO);
235 if (clk == NULL)
236 goto err;
237
238 buflen = strlen(name) + 1;
239 clk->name = malloc(buflen, M_PMC, M_NOWAIT);
240 if (clk->name == NULL)
241 goto err;
242
243 strlcpy(clk->name, name, buflen);
244 clk->pmc_mask = 1 << irq;
245 clk->set_mode = &at91_pmc_set_periph_mode;
246 if (parent == NULL)
247 clk->parent = &mck;
248 else
249 clk->parent = parent;
250
251 for (i = 0; i < sizeof(clock_list) / sizeof(clock_list[0]); i++) {
252 if (clock_list[i] == NULL) {
253 clock_list[i] = clk;
254 return (clk);
255 }
256 }
257 err:
258 if (clk != NULL) {
259 if (clk->name != NULL)
260 free(clk->name, M_PMC);
261 free(clk, M_PMC);
262 }
263
264 panic("could not allocate pmc clock '%s'", name);
265 return (NULL);
266 }
267
268 static void
269 at91_pmc_clock_alias(const char *name, const char *alias)
270 {
271 struct at91_pmc_clock *clk, *alias_clk;
272
273 clk = at91_pmc_clock_ref(name);
274 if (clk)
275 alias_clk = at91_pmc_clock_add(alias, 0, clk->parent);
276
277 if (clk && alias_clk) {
278 alias_clk->hz = clk->hz;
279 alias_clk->pmc_mask = clk->pmc_mask;
280 alias_clk->set_mode = clk->set_mode;
281 }
282 }
283
284 struct at91_pmc_clock *
285 at91_pmc_clock_ref(const char *name)
286 {
287 int i;
288
289 for (i = 0; i < sizeof(clock_list) / sizeof(clock_list[0]); i++) {
290 if (clock_list[i] == NULL)
291 break;
292 if (strcmp(name, clock_list[i]->name) == 0)
293 return (clock_list[i]);
294 }
295
296 //printf("at91_pmc: Warning - did not find clock '%s'", name);
297 return (NULL);
298 }
299
300 void
301 at91_pmc_clock_deref(struct at91_pmc_clock *clk)
302 {
303 }
304
305 void
306 at91_pmc_clock_enable(struct at91_pmc_clock *clk)
307 {
308 /* XXX LOCKING? XXX */
309 if (clk->parent)
310 at91_pmc_clock_enable(clk->parent);
311 if (clk->refcnt++ == 0 && clk->set_mode)
312 clk->set_mode(clk, 1);
313 }
314
315 void
316 at91_pmc_clock_disable(struct at91_pmc_clock *clk)
317 {
318 /* XXX LOCKING? XXX */
319 if (--clk->refcnt == 0 && clk->set_mode)
320 clk->set_mode(clk, 0);
321 if (clk->parent)
322 at91_pmc_clock_disable(clk->parent);
323 }
324
325 static int
326 at91_pmc_pll_rate(struct at91_pmc_clock *clk, uint32_t reg)
327 {
328 uint32_t mul, div, freq;
329
330 freq = clk->parent->hz;
331 div = (reg >> clk->pll_div_shift) & clk->pll_div_mask;
332 mul = (reg >> clk->pll_mul_shift) & clk->pll_mul_mask;
333
334 // printf("pll = (%d / %d) * %d = %d\n",
335 // freq, div ,mul + 1, (freq/div) * (mul+1));
336
337 if (div != 0 && mul != 0) {
338 freq /= div;
339 freq *= mul + 1;
340 } else {
341 freq = 0;
342 }
343 clk->hz = freq;
344
345
346 return (freq);
347 }
348
349 static uint32_t
350 at91_pmc_pll_calc(struct at91_pmc_clock *clk, uint32_t out_freq)
351 {
352 uint32_t i, div = 0, mul = 0, diff = 1 << 30;
353
354 unsigned ret = 0x3e00;
355
356 if (out_freq > clk->pll_max_out)
357 goto fail;
358
359 for (i = 1; i < 256; i++) {
360 int32_t diff1;
361 uint32_t input, mul1;
362
363 input = clk->parent->hz / i;
364 if (input < clk->pll_min_in)
365 break;
366 if (input > clk->pll_max_in)
367 continue;
368
369 mul1 = out_freq / input;
370 if (mul1 > (clk->pll_mul_mask + 1))
371 continue;
372 if (mul1 == 0)
373 break;
374
375 diff1 = out_freq - input * mul1;
376 if (diff1 < 0)
377 diff1 = -diff1;
378 if (diff > diff1) {
379 diff = diff1;
380 div = i;
381 mul = mul1;
382 if (diff == 0)
383 break;
384 }
385 }
386 if (diff > (out_freq >> PMC_PLL_SHIFT_TOL))
387 goto fail;
388
389 if (clk->set_outb != NULL)
390 ret |= clk->set_outb(out_freq);
391
392 return (ret |
393 ((mul - 1) << clk->pll_mul_shift) |
394 (div << clk->pll_div_shift));
395 fail:
396 return (0);
397 }
398
399 static void
400 at91_pmc_init_clock(struct at91_pmc_softc *sc, unsigned int main_clock)
401 {
402 uint32_t mckr;
403 uint32_t mdiv;
404
405 if (at91_is_sam9()) {
406 uhpck.pmc_mask = PMC_SCER_UHP_SAM9;
407 udpck.pmc_mask = PMC_SCER_UDP_SAM9;
408 }
409 mckr = RD4(sc, PMC_MCKR);
410 sc->main_clock_hz = main_clock;
411 main_ck.hz = main_clock;
412
413 at91_pmc_pll_rate(&plla, RD4(sc, CKGR_PLLAR));
414
415 if (at91_cpu_is(AT91_CPU_SAM9G45) && (mckr & PMC_MCKR_PLLADIV2))
416 plla.hz /= 2;
417
418 /*
419 * Initialize the usb clock. This sets up pllb, but disables the
420 * actual clock.
421 */
422 sc->pllb_init = at91_pmc_pll_calc(&pllb, 48000000 * 2) | 0x10000000;
423 at91_pmc_pll_rate(&pllb, sc->pllb_init);
424
425 #if 0
426 /* Turn off USB clocks */
427 at91_pmc_set_periph_mode(&ohci_clk, 0);
428 at91_pmc_set_periph_mode(&udc_clk, 0);
429 #endif
430
431 if (at91_is_rm92()) {
432 WR4(sc, PMC_SCDR, PMC_SCER_UHP | PMC_SCER_UDP);
433 WR4(sc, PMC_SCER, PMC_SCER_MCKUDP);
434 } else {
435 WR4(sc, PMC_SCDR, PMC_SCER_UHP_SAM9 | PMC_SCER_UDP_SAM9);
436 }
437 WR4(sc, CKGR_PLLBR, 0);
438
439 /*
440 * MCK and PCU derive from one of the primary clocks. Initialize
441 * this relationship.
442 */
443 mck.parent = clock_list[mckr & 0x3];
444 mck.parent->refcnt++;
445
446 cpu.hz =
447 mck.hz = mck.parent->hz /
448 (1 << ((mckr & PMC_MCKR_PRES_MASK) >> 2));
449
450 mdiv = (mckr & PMC_MCKR_MDIV_MASK) >> 8;
451 if (at91_is_sam9()) {
452 if (mdiv > 0)
453 mck.hz /= mdiv * 2;
454 } else
455 mck.hz /= (1 + mdiv);
456
457 /* Only found on SAM9G20 */
458 if (at91_cpu_is(AT91_CPU_SAM9G20))
459 cpu.hz /= (mckr & PMC_MCKR_PDIV) ? 2 : 1;
460
461 at91_master_clock = mck.hz;
462
463 device_printf(sc->dev,
464 "Primary: %d Hz PLLA: %d MHz CPU: %d MHz MCK: %d MHz\n",
465 sc->main_clock_hz,
466 plla.hz / 1000000,
467 cpu.hz / 1000000, mck.hz / 1000000);
468
469 /* Turn off "Progamable" clocks */
470 WR4(sc, PMC_SCDR, PMC_SCER_PCK0 | PMC_SCER_PCK1 | PMC_SCER_PCK2 |
471 PMC_SCER_PCK3);
472
473 /* XXX kludge, turn on all peripherals */
474 WR4(sc, PMC_PCER, 0xffffffff);
475
476 /* Disable all interrupts for PMC */
477 WR4(sc, PMC_IDR, 0xffffffff);
478 }
479
480 static void
481 at91_pmc_deactivate(device_t dev)
482 {
483 struct at91_pmc_softc *sc;
484
485 sc = device_get_softc(dev);
486 bus_generic_detach(sc->dev);
487 if (sc->mem_res)
488 bus_release_resource(dev, SYS_RES_IOPORT,
489 rman_get_rid(sc->mem_res), sc->mem_res);
490 sc->mem_res = 0;
491 return;
492 }
493
494 static int
495 at91_pmc_activate(device_t dev)
496 {
497 struct at91_pmc_softc *sc;
498 int rid;
499
500 sc = device_get_softc(dev);
501 rid = 0;
502 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
503 RF_ACTIVE);
504 if (sc->mem_res == NULL)
505 goto errout;
506 return (0);
507 errout:
508 at91_pmc_deactivate(dev);
509 return (ENOMEM);
510 }
511
512 static int
513 at91_pmc_probe(device_t dev)
514 {
515
516 device_set_desc(dev, "PMC");
517 return (0);
518 }
519
520 #if !defined(AT91C_MAIN_CLOCK)
521 static unsigned int
522 at91_pmc_sense_mainf(struct at91_pmc_softc *sc)
523 {
524 unsigned int ckgr_val;
525 unsigned int diff, matchdiff;
526 int i, match;
527
528 ckgr_val = (RD4(sc, CKGR_MCFR) & CKGR_MCFR_MAINF_MASK) << 11;
529
530 /*
531 * Try to find the standard frequency that match best.
532 */
533 match = 0;
534 matchdiff = abs(ckgr_val - at91_mainf_tbl[0]);
535 for (i = 1; i < MAINF_TBL_LEN; i++) {
536 diff = abs(ckgr_val - at91_mainf_tbl[i]);
537 if (diff < matchdiff) {
538 match = i;
539 matchdiff = diff;
540 }
541 }
542 return (at91_mainf_tbl[match]);
543 }
544 #endif
545
546 static int
547 at91_pmc_attach(device_t dev)
548 {
549 unsigned int mainf;
550 int err;
551
552 pmc_softc = device_get_softc(dev);
553 pmc_softc->dev = dev;
554 if ((err = at91_pmc_activate(dev)) != 0)
555 return (err);
556
557 /*
558 * Configure main clock frequency.
559 */
560 #if !defined(AT91C_MAIN_CLOCK)
561 mainf = at91_pmc_sense_mainf(pmc_softc);
562 #else
563 mainf = AT91C_MAIN_CLOCK;
564 #endif
565 at91_pmc_init_clock(pmc_softc, mainf);
566
567 /* These clocks refrenced by "special" names */
568 at91_pmc_clock_alias("ohci0", "ohci_clk");
569 at91_pmc_clock_alias("udp0", "udp_clk");
570
571 return (0);
572 }
573
574 static device_method_t at91_pmc_methods[] = {
575 DEVMETHOD(device_probe, at91_pmc_probe),
576 DEVMETHOD(device_attach, at91_pmc_attach),
577 {0, 0},
578 };
579
580 static driver_t at91_pmc_driver = {
581 "at91_pmc",
582 at91_pmc_methods,
583 sizeof(struct at91_pmc_softc),
584 };
585 static devclass_t at91_pmc_devclass;
586
587 DRIVER_MODULE(at91_pmc, atmelarm, at91_pmc_driver, at91_pmc_devclass, 0, 0);
Cache object: afa703d7bf709aebbe692f78ca4f7fa8
|