]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/arm/at91/at91_pmc.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / arm / at91 / at91_pmc.c
1 /*-
2  * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include "opt_at91.h"
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.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/at91rm92reg.h>
48
49 #include <arm/at91/at91_pmcreg.h>
50 #include <arm/at91/at91_pmcvar.h>
51
52 static struct at91_pmc_softc {
53         bus_space_tag_t         sc_st;
54         bus_space_handle_t      sc_sh;
55         struct resource *mem_res;       /* Memory resource */
56         device_t                dev;
57         unsigned int            main_clock_hz;
58         uint32_t                pllb_init;
59 } *pmc_softc;
60
61 static void at91_pmc_set_pllb_mode(struct at91_pmc_clock *, int);
62 static void at91_pmc_set_sys_mode(struct at91_pmc_clock *, int);
63 static void at91_pmc_set_periph_mode(struct at91_pmc_clock *, int);
64
65 static struct at91_pmc_clock slck = {
66         .name = "slck",         // 32,768 Hz slow clock
67         .hz = 32768,
68         .refcnt = 1,
69         .id = 0,
70         .primary = 1,
71 };
72
73 static struct at91_pmc_clock main_ck = {
74         .name = "main",         // Main clock
75         .refcnt = 0,
76         .id = 1,
77         .primary = 1,
78         .pmc_mask = PMC_IER_MOSCS,
79 };
80
81 static struct at91_pmc_clock plla = {
82         .name = "plla",         // PLLA Clock, used for CPU clocking
83         .parent = &main_ck,
84         .refcnt = 1,
85         .id = 0,
86         .primary = 1,
87         .pll = 1,
88         .pmc_mask = PMC_IER_LOCKA,
89 };
90
91 static struct at91_pmc_clock pllb = {
92         .name = "pllb",         // PLLB Clock, used for USB functions
93         .parent = &main_ck,
94         .refcnt = 0,
95         .id = 0,
96         .primary = 1,
97         .pll = 1,
98         .pmc_mask = PMC_IER_LOCKB,
99         .set_mode = &at91_pmc_set_pllb_mode,
100 };
101
102 static struct at91_pmc_clock udpck = {
103         .name = "udpck",
104         .parent = &pllb,
105         .pmc_mask = PMC_SCER_UDP,
106         .set_mode = at91_pmc_set_sys_mode
107 };
108
109 static struct at91_pmc_clock uhpck = {
110         .name = "uhpck",
111         .parent = &pllb,
112         .pmc_mask = PMC_SCER_UHP,
113         .set_mode = at91_pmc_set_sys_mode
114 };
115
116 static struct at91_pmc_clock mck = {
117         .name = "mck",
118         .pmc_mask = PMC_IER_MCKRDY,
119         .refcnt = 0,
120 };
121
122 static struct at91_pmc_clock udc_clk = {
123         .name = "udc_clk",
124         .parent = &mck,
125         .pmc_mask = 1 << AT91RM92_IRQ_UDP,
126         .set_mode = &at91_pmc_set_periph_mode
127 };
128
129 static struct at91_pmc_clock ohci_clk = {
130         .name = "ohci_clk",
131         .parent = &mck,
132         .pmc_mask = 1 << AT91RM92_IRQ_UHP,
133         .set_mode = &at91_pmc_set_periph_mode
134 };
135
136 static struct at91_pmc_clock *const clock_list[] = {
137         &slck,
138         &main_ck,
139         &plla,
140         &pllb,
141         &udpck,
142         &uhpck,
143         &mck,
144         &udc_clk,
145         &ohci_clk
146 };
147
148 #if !defined(AT91C_MAIN_CLOCK)
149 static const unsigned int at91_mainf_tbl[] = {
150         3000000, 3276800, 3686400, 3840000, 4000000,
151         4433619, 4915200, 5000000, 5242880, 6000000,
152         6144000, 6400000, 6553600, 7159090, 7372800,
153         7864320, 8000000, 9830400, 10000000, 11059200,
154         12000000, 12288000, 13560000, 14318180, 14745600,
155         16000000, 17344700, 18432000, 20000000
156 };
157 #define MAINF_TBL_LEN   (sizeof(at91_mainf_tbl) / sizeof(*at91_mainf_tbl))
158 #endif
159
160 static inline uint32_t
161 RD4(struct at91_pmc_softc *sc, bus_size_t off)
162 {
163         return bus_read_4(sc->mem_res, off);
164 }
165
166 static inline void
167 WR4(struct at91_pmc_softc *sc, bus_size_t off, uint32_t val)
168 {
169         bus_write_4(sc->mem_res, off, val);
170 }
171
172 static void
173 at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on)
174 {
175         struct at91_pmc_softc *sc = pmc_softc;
176         uint32_t value;
177
178         if (on) {
179                 on = PMC_IER_LOCKB;
180                 value = sc->pllb_init;
181         } else {
182                 value = 0;
183         }
184         WR4(sc, CKGR_PLLBR, value);
185         while ((RD4(sc, PMC_SR) & PMC_IER_LOCKB) != on)
186                 continue;
187 }
188
189 static void
190 at91_pmc_set_sys_mode(struct at91_pmc_clock *clk, int on)
191 {
192         struct at91_pmc_softc *sc = pmc_softc;
193
194         WR4(sc, on ? PMC_SCER : PMC_SCDR, clk->pmc_mask);
195         if (on)
196                 while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) != clk->pmc_mask)
197                         continue;
198         else
199                 while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) == clk->pmc_mask)
200                         continue;
201 }
202
203 static void
204 at91_pmc_set_periph_mode(struct at91_pmc_clock *clk, int on)
205 {
206         struct at91_pmc_softc *sc = pmc_softc;
207
208         WR4(sc, on ? PMC_PCER : PMC_PCDR, clk->pmc_mask);
209         if (on)
210                 while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) != clk->pmc_mask)
211                         continue;
212         else
213                 while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) == clk->pmc_mask)
214                         continue;
215 }
216
217 struct at91_pmc_clock *
218 at91_pmc_clock_ref(const char *name)
219 {
220         int i;
221
222         for (i = 0; i < sizeof(clock_list) / sizeof(clock_list[0]); i++)
223                 if (strcmp(name, clock_list[i]->name) == 0)
224                         return (clock_list[i]);
225
226         return (NULL);
227 }
228
229 void
230 at91_pmc_clock_deref(struct at91_pmc_clock *clk)
231 {
232 }
233
234 void
235 at91_pmc_clock_enable(struct at91_pmc_clock *clk)
236 {
237         /* XXX LOCKING? XXX */
238         if (clk->parent)
239                 at91_pmc_clock_enable(clk->parent);
240         if (clk->refcnt++ == 0 && clk->set_mode)
241                 clk->set_mode(clk, 1);
242 }
243
244 void
245 at91_pmc_clock_disable(struct at91_pmc_clock *clk)
246 {
247         /* XXX LOCKING? XXX */
248         if (--clk->refcnt == 0 && clk->set_mode)
249                 clk->set_mode(clk, 0);
250         if (clk->parent)
251                 at91_pmc_clock_disable(clk->parent);
252 }
253
254 static int
255 at91_pmc_pll_rate(int freq, uint32_t reg, int is_pllb)
256 {
257         uint32_t mul, div;
258
259         div = reg & 0xff;
260         mul = (reg >> 16) & 0x7ff;
261         if (div != 0 && mul != 0) {
262                 freq /= div;
263                 freq *= mul + 1;
264         } else {
265                 freq = 0;
266         }
267         if (is_pllb && (reg & (1 << 28)))
268                 freq >>= 1;
269         return (freq);
270 }
271
272 static uint32_t
273 at91_pmc_pll_calc(uint32_t main_freq, uint32_t out_freq)
274 {
275         uint32_t i, div = 0, mul = 0, diff = 1 << 30;
276         unsigned ret = (out_freq > PMC_PLL_FAST_THRESH) ? 0xbe00 : 0x3e00; 
277
278         if (out_freq > PMC_PLL_MAX_OUT_FREQ)
279                 goto fail;
280
281         for (i = 1; i < 256; i++) {
282                 int32_t diff1;
283                 uint32_t input, mul1;
284
285                 input = main_freq / i;
286                 if (input < PMC_PLL_MIN_IN_FREQ)
287                         break;
288                 if (input > PMC_PLL_MAX_IN_FREQ)
289                         continue;
290
291                 mul1 = out_freq / input;
292                 if (mul1 > PMC_PLL_MULT_MAX)
293                         continue;
294                 if (mul1 < PMC_PLL_MULT_MIN)
295                         break;
296
297                 diff1 = out_freq - input * mul1;
298                 if (diff1 < 0)
299                         diff1 = -diff1;
300                 if (diff > diff1) {
301                         diff = diff1;
302                         div = i;
303                         mul = mul1;
304                         if (diff == 0)
305                                 break;
306                 }
307         }
308         if (diff > (out_freq >> PMC_PLL_SHIFT_TOL))
309                 goto fail;
310         return ret | ((mul - 1) << 16) | div;
311 fail:
312         return 0;
313 }
314
315 static void
316 at91_pmc_init_clock(struct at91_pmc_softc *sc, unsigned int main_clock)
317 {
318         uint32_t mckr;
319         int freq;
320
321         sc->main_clock_hz = main_clock;
322         main_ck.hz = main_clock;
323         plla.hz = at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0);
324
325         /*
326          * Initialize the usb clock.  This sets up pllb, but disables the
327          * actual clock.
328          */
329         sc->pllb_init = at91_pmc_pll_calc(main_clock, 48000000 * 2) |0x10000000;
330         pllb.hz = at91_pmc_pll_rate(main_clock, sc->pllb_init, 1);
331         WR4(sc, PMC_PCDR, (1 << AT91RM92_IRQ_UHP) | (1 << AT91RM92_IRQ_UDP));
332         WR4(sc, PMC_SCDR, PMC_SCER_UHP | PMC_SCER_UDP);
333         WR4(sc, CKGR_PLLBR, 0);
334         WR4(sc, PMC_SCER, PMC_SCER_MCKUDP);
335
336         /*
337          * MCK and PCU derive from one of the primary clocks.  Initialize
338          * this relationship.
339          */
340         mckr = RD4(sc, PMC_MCKR);
341         mck.parent = clock_list[mckr & 0x3];
342         mck.parent->refcnt++;
343         freq = mck.parent->hz / (1 << ((mckr >> 2) & 3));
344         mck.hz = freq / (1 + ((mckr >> 8) & 3));
345
346         device_printf(sc->dev,
347             "Primary: %d Hz PLLA: %d MHz CPU: %d MHz MCK: %d MHz\n",
348             sc->main_clock_hz,
349             at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0) / 1000000,
350             freq / 1000000, mck.hz / 1000000);
351         WR4(sc, PMC_SCDR, PMC_SCER_PCK0 | PMC_SCER_PCK1 | PMC_SCER_PCK2 |
352             PMC_SCER_PCK3);
353         /* XXX kludge, turn on all peripherals */
354         WR4(sc, PMC_PCER, 0xffffffff);
355         /* Disable all interrupts for PMC */
356         WR4(sc, PMC_IDR, 0xffffffff);
357 }
358
359 static void
360 at91_pmc_deactivate(device_t dev)
361 {
362         struct at91_pmc_softc *sc;
363
364         sc = device_get_softc(dev);
365         bus_generic_detach(sc->dev);
366         if (sc->mem_res)
367                 bus_release_resource(dev, SYS_RES_IOPORT,
368                     rman_get_rid(sc->mem_res), sc->mem_res);
369         sc->mem_res = 0;
370         return;
371 }
372
373 static int
374 at91_pmc_activate(device_t dev)
375 {
376         struct at91_pmc_softc *sc;
377         int rid;
378
379         sc = device_get_softc(dev);
380         rid = 0;
381         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
382             RF_ACTIVE);
383         if (sc->mem_res == NULL)
384                 goto errout;
385         return (0);
386 errout:
387         at91_pmc_deactivate(dev);
388         return (ENOMEM);
389 }
390
391 static int
392 at91_pmc_probe(device_t dev)
393 {
394
395         device_set_desc(dev, "PMC");
396         return (0);
397 }
398
399 #if !defined(AT91C_MAIN_CLOCK)
400 static unsigned int
401 at91_pmc_sense_mainf(struct at91_pmc_softc *sc)
402 {
403         unsigned int ckgr_val;
404         unsigned int diff, matchdiff;
405         int i, match;
406
407         ckgr_val = (RD4(sc, CKGR_MCFR) & CKGR_MCFR_MAINF_MASK) << 11;
408
409         /*
410          * Try to find the standard frequency that match best.
411          */
412         match = 0;
413         matchdiff = abs(ckgr_val - at91_mainf_tbl[0]);
414         for (i = 1; i < MAINF_TBL_LEN; i++) {
415                 diff = abs(ckgr_val - at91_mainf_tbl[i]);
416                 if (diff < matchdiff) {
417                         match = i;
418                         matchdiff = diff;
419                 }
420         }
421         return (at91_mainf_tbl[match]);
422 }
423 #endif
424
425 static int
426 at91_pmc_attach(device_t dev)
427 {
428         unsigned int mainf;
429         int err;
430
431         pmc_softc = device_get_softc(dev);
432         pmc_softc->dev = dev;
433         if ((err = at91_pmc_activate(dev)) != 0)
434                 return err;
435
436         /*
437          * Configure main clock frequency.
438          */
439 #if !defined(AT91C_MAIN_CLOCK)
440         mainf = at91_pmc_sense_mainf(pmc_softc);
441 #else
442         mainf = AT91C_MAIN_CLOCK;
443 #endif
444         at91_pmc_init_clock(pmc_softc, mainf);
445         return (0);
446 }
447
448 static device_method_t at91_pmc_methods[] = {
449         DEVMETHOD(device_probe, at91_pmc_probe),
450         DEVMETHOD(device_attach, at91_pmc_attach),
451         {0, 0},
452 };
453
454 static driver_t at91_pmc_driver = {
455         "at91_pmc",
456         at91_pmc_methods,
457         sizeof(struct at91_pmc_softc),
458 };
459 static devclass_t at91_pmc_devclass;
460
461 DRIVER_MODULE(at91_pmc, atmelarm, at91_pmc_driver, at91_pmc_devclass, 0, 0);