2 * Copyright (c) 2006 M. Warner Losh. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
36 #include <sys/resource.h>
38 #include <sys/timetc.h>
40 #include <machine/bus.h>
41 #include <machine/cpu.h>
42 #include <machine/cpufunc.h>
43 #include <machine/resource.h>
44 #include <machine/frame.h>
45 #include <machine/intr.h>
46 #include <arm/at91/at91rm92reg.h>
48 #include <arm/at91/at91_pmcreg.h>
49 #include <arm/at91/at91_pmcvar.h>
51 static struct at91_pmc_softc {
52 bus_space_tag_t sc_st;
53 bus_space_handle_t sc_sh;
54 struct resource *mem_res; /* Memory resource */
60 static void at91_pmc_set_pllb_mode(struct at91_pmc_clock *, int);
61 static void at91_pmc_set_sys_mode(struct at91_pmc_clock *, int);
62 static void at91_pmc_set_periph_mode(struct at91_pmc_clock *, int);
64 static struct at91_pmc_clock slck = {
65 .name = "slck", // 32,768 Hz slow clock
72 static struct at91_pmc_clock main_ck = {
73 .name = "main", // Main clock
77 .pmc_mask = PMC_IER_MOSCS,
80 static struct at91_pmc_clock plla = {
81 .name = "plla", // PLLA Clock, used for CPU clocking
87 .pmc_mask = PMC_IER_LOCKA,
90 static struct at91_pmc_clock pllb = {
91 .name = "pllb", // PLLB Clock, used for USB functions
97 .pmc_mask = PMC_IER_LOCKB,
98 .set_mode = &at91_pmc_set_pllb_mode,
101 static struct at91_pmc_clock udpck = {
104 .pmc_mask = PMC_SCER_UDP,
105 .set_mode = at91_pmc_set_sys_mode
108 static struct at91_pmc_clock uhpck = {
111 .pmc_mask = PMC_SCER_UHP,
112 .set_mode = at91_pmc_set_sys_mode
115 static struct at91_pmc_clock mck = {
117 .pmc_mask = PMC_IER_MCKRDY,
121 static struct at91_pmc_clock udc_clk = {
124 .pmc_mask = 1 << AT91RM92_IRQ_UDP,
125 .set_mode = &at91_pmc_set_periph_mode
128 static struct at91_pmc_clock ohci_clk = {
131 .pmc_mask = 1 << AT91RM92_IRQ_UDP,
132 .set_mode = &at91_pmc_set_periph_mode
135 static struct at91_pmc_clock *const clock_list[] = {
147 static inline uint32_t
148 RD4(struct at91_pmc_softc *sc, bus_size_t off)
150 return bus_read_4(sc->mem_res, off);
154 WR4(struct at91_pmc_softc *sc, bus_size_t off, uint32_t val)
156 bus_write_4(sc->mem_res, off, val);
160 at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on)
162 struct at91_pmc_softc *sc = pmc_softc;
167 value = sc->pllb_init;
171 WR4(sc, CKGR_PLLBR, value);
172 while ((RD4(sc, PMC_SR) & PMC_IER_LOCKB) != on)
177 at91_pmc_set_sys_mode(struct at91_pmc_clock *clk, int on)
179 struct at91_pmc_softc *sc = pmc_softc;
181 WR4(sc, on ? PMC_SCER : PMC_SCDR, clk->pmc_mask);
183 while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) != clk->pmc_mask)
186 while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) == clk->pmc_mask)
191 at91_pmc_set_periph_mode(struct at91_pmc_clock *clk, int on)
193 struct at91_pmc_softc *sc = pmc_softc;
195 WR4(sc, on ? PMC_PCER : PMC_PCDR, clk->pmc_mask);
197 while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) != clk->pmc_mask)
200 while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) == clk->pmc_mask)
204 struct at91_pmc_clock *
205 at91_pmc_clock_ref(const char *name)
209 for (i = 0; i < sizeof(clock_list) / sizeof(clock_list[0]); i++)
210 if (strcmp(name, clock_list[i]->name) == 0)
211 return (clock_list[i]);
217 at91_pmc_clock_deref(struct at91_pmc_clock *clk)
222 at91_pmc_clock_enable(struct at91_pmc_clock *clk)
224 /* XXX LOCKING? XXX */
226 at91_pmc_clock_enable(clk->parent);
227 if (clk->refcnt++ == 0 && clk->set_mode)
228 clk->set_mode(clk, 1);
232 at91_pmc_clock_disable(struct at91_pmc_clock *clk)
234 /* XXX LOCKING? XXX */
235 if (--clk->refcnt == 0 && clk->set_mode)
236 clk->set_mode(clk, 0);
238 at91_pmc_clock_disable(clk->parent);
242 at91_pmc_pll_rate(int freq, uint32_t reg, int is_pllb)
247 mul = (reg >> 16) & 0x7ff;
248 if (div != 0 && mul != 0) {
254 if (is_pllb && (reg & (1 << 28)))
260 at91_pmc_pll_calc(uint32_t main_freq, uint32_t out_freq)
262 uint32_t i, div = 0, mul = 0, diff = 1 << 30;
263 unsigned ret = (out_freq > PMC_PLL_FAST_THRESH) ? 0xbe00 : 0x3e00;
265 if (out_freq > PMC_PLL_MAX_OUT_FREQ)
268 for (i = 1; i < 256; i++) {
270 uint32_t input, mul1;
272 input = main_freq / i;
273 if (input < PMC_PLL_MIN_IN_FREQ)
275 if (input > PMC_PLL_MAX_IN_FREQ)
278 mul1 = out_freq / input;
279 if (mul1 > PMC_PLL_MULT_MAX)
281 if (mul1 < PMC_PLL_MULT_MIN)
284 diff1 = out_freq - input * mul1;
295 if (diff > (out_freq >> PMC_PLL_SHIFT_TOL))
297 return ret | ((mul - 1) << 16) | div;
303 at91_pmc_init_clock(struct at91_pmc_softc *sc, int main_clock)
308 sc->main_clock_hz = main_clock;
309 main_ck.hz = main_clock;
310 plla.hz = at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0);
313 * Initialize the usb clock. This sets up pllb, but disables the
316 sc->pllb_init = at91_pmc_pll_calc(main_clock, 48000000 * 2) |0x10000000;
317 pllb.hz = at91_pmc_pll_rate(main_clock, sc->pllb_init, 1);
318 WR4(sc, PMC_PCDR, (1 << AT91RM92_IRQ_UHP) | (1 << AT91RM92_IRQ_UDP));
319 WR4(sc, PMC_SCDR, PMC_SCER_UHP | PMC_SCER_UDP);
320 WR4(sc, CKGR_PLLBR, 0);
321 WR4(sc, PMC_SCER, PMC_SCER_MCKUDP);
324 * MCK and PCU derive from one of the primary clocks. Initialize
327 mckr = RD4(sc, PMC_MCKR);
328 mck.parent = clock_list[mckr & 0x3];
329 mck.parent->refcnt++;
330 freq = mck.parent->hz / (1 << ((mckr >> 2) & 3));
331 mck.hz = freq / (1 + ((mckr >> 8) & 3));
333 device_printf(sc->dev,
334 "Primary: %d Hz PLLA: %d MHz CPU: %d MHz MCK: %d MHz\n",
336 at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0) / 1000000,
337 freq / 1000000, mck.hz / 1000000);
338 WR4(sc, PMC_SCDR, PMC_SCER_PCK0 | PMC_SCER_PCK1 | PMC_SCER_PCK2 |
340 /* XXX kludge, turn on all peripherals */
341 WR4(sc, PMC_PCER, 0xffffffff);
342 /* Disable all interrupts for PMC */
343 WR4(sc, PMC_IDR, 0xffffffff);
347 at91_pmc_deactivate(device_t dev)
349 struct at91_pmc_softc *sc;
351 sc = device_get_softc(dev);
352 bus_generic_detach(sc->dev);
354 bus_release_resource(dev, SYS_RES_IOPORT,
355 rman_get_rid(sc->mem_res), sc->mem_res);
361 at91_pmc_activate(device_t dev)
363 struct at91_pmc_softc *sc;
366 sc = device_get_softc(dev);
368 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
370 if (sc->mem_res == NULL)
374 at91_pmc_deactivate(dev);
379 at91_pmc_probe(device_t dev)
382 device_set_desc(dev, "PMC");
387 at91_pmc_attach(device_t dev)
391 pmc_softc = device_get_softc(dev);
392 pmc_softc->dev = dev;
393 if ((err = at91_pmc_activate(dev)) != 0)
395 #if defined(AT91_TSC) | defined (AT91_BWCT)
396 at91_pmc_init_clock(pmc_softc, 16000000);
398 at91_pmc_init_clock(pmc_softc, 10000000);
404 static device_method_t at91_pmc_methods[] = {
405 DEVMETHOD(device_probe, at91_pmc_probe),
406 DEVMETHOD(device_attach, at91_pmc_attach),
410 static driver_t at91_pmc_driver = {
413 sizeof(struct at91_pmc_softc),
415 static devclass_t at91_pmc_devclass;
417 DRIVER_MODULE(at91_pmc, atmelarm, at91_pmc_driver, at91_pmc_devclass, 0, 0);