Add the sekelton of support for the Power Management Controller.
This commit is contained in:
parent
72ec44a573
commit
c44fe487c2
419
sys/arm/at91/at91_pmc.c
Normal file
419
sys/arm/at91/at91_pmc.c
Normal file
@ -0,0 +1,419 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 M. Warner Losh. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/timetc.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/resource.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/intr.h>
|
||||
#include <arm/at91/at91rm92reg.h>
|
||||
|
||||
#include <arm/at91/at91_pmcreg.h>
|
||||
#include <arm/at91/at91_pmcvar.h>
|
||||
|
||||
static struct at91_pmc_softc {
|
||||
bus_space_tag_t sc_st;
|
||||
bus_space_handle_t sc_sh;
|
||||
struct resource *mem_res; /* Memory resource */
|
||||
device_t dev;
|
||||
int main_clock_hz;
|
||||
uint32_t pllb_init;
|
||||
} *pmc_softc;
|
||||
|
||||
static void at91_pmc_set_pllb_mode(struct at91_pmc_clock *, int);
|
||||
static void at91_pmc_set_sys_mode(struct at91_pmc_clock *, int);
|
||||
static void at91_pmc_set_periph_mode(struct at91_pmc_clock *, int);
|
||||
|
||||
static struct at91_pmc_clock slck = {
|
||||
.name = "slck", // 32,768 Hz slow clock
|
||||
.hz = 32768,
|
||||
.refcnt = 1,
|
||||
.id = 0,
|
||||
.primary = 1,
|
||||
};
|
||||
|
||||
static struct at91_pmc_clock main_ck = {
|
||||
.name = "main", // Main clock
|
||||
.refcnt = 0,
|
||||
.id = 1,
|
||||
.primary = 1,
|
||||
.pmc_mask = PMC_IER_MOSCS,
|
||||
};
|
||||
|
||||
static struct at91_pmc_clock plla = {
|
||||
.name = "plla", // PLLA Clock, used for CPU clocking
|
||||
.parent = &main_ck,
|
||||
.refcnt = 1,
|
||||
.id = 0,
|
||||
.primary = 1,
|
||||
.pll = 1,
|
||||
.pmc_mask = PMC_IER_LOCKA,
|
||||
};
|
||||
|
||||
static struct at91_pmc_clock pllb = {
|
||||
.name = "pllb", // PLLB Clock, used for USB functions
|
||||
.parent = &main_ck,
|
||||
.refcnt = 0,
|
||||
.id = 0,
|
||||
.primary = 1,
|
||||
.pll = 1,
|
||||
.pmc_mask = PMC_IER_LOCKB,
|
||||
.set_mode = &at91_pmc_set_pllb_mode,
|
||||
};
|
||||
|
||||
static struct at91_pmc_clock udpck = {
|
||||
.name = "udpck",
|
||||
.parent = &pllb,
|
||||
.pmc_mask = PMC_SCER_UDP,
|
||||
.set_mode = at91_pmc_set_sys_mode
|
||||
};
|
||||
|
||||
static struct at91_pmc_clock uhpck = {
|
||||
.name = "uhpck",
|
||||
.parent = &pllb,
|
||||
.pmc_mask = PMC_SCER_UHP,
|
||||
.set_mode = at91_pmc_set_sys_mode
|
||||
};
|
||||
|
||||
static struct at91_pmc_clock mck = {
|
||||
.name = "mck",
|
||||
.pmc_mask = PMC_IER_MCKRDY,
|
||||
.refcnt = 0,
|
||||
};
|
||||
|
||||
static struct at91_pmc_clock udc_clk = {
|
||||
.name = "udc_clk",
|
||||
.parent = &mck,
|
||||
.pmc_mask = 1 << AT91RM92_IRQ_UDP,
|
||||
.set_mode = &at91_pmc_set_periph_mode
|
||||
};
|
||||
|
||||
static struct at91_pmc_clock ohci_clk = {
|
||||
.name = "ohci_clk",
|
||||
.parent = &mck,
|
||||
.pmc_mask = 1 << AT91RM92_IRQ_UDP,
|
||||
.set_mode = &at91_pmc_set_periph_mode
|
||||
};
|
||||
|
||||
static struct at91_pmc_clock *const clock_list[] = {
|
||||
&slck,
|
||||
&main_ck,
|
||||
&plla,
|
||||
&pllb,
|
||||
&udpck,
|
||||
&uhpck,
|
||||
&mck,
|
||||
&udc_clk,
|
||||
&ohci_clk
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
RD4(struct at91_pmc_softc *sc, bus_size_t off)
|
||||
{
|
||||
return bus_read_4(sc->mem_res, off);
|
||||
}
|
||||
|
||||
static inline void
|
||||
WR4(struct at91_pmc_softc *sc, bus_size_t off, uint32_t val)
|
||||
{
|
||||
bus_write_4(sc->mem_res, off, val);
|
||||
}
|
||||
|
||||
static void
|
||||
at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on)
|
||||
{
|
||||
struct at91_pmc_softc *sc = pmc_softc;
|
||||
uint32_t value;
|
||||
|
||||
printf("Turning PLLB %#x %s\n", sc->pllb_init, on ? "on" : "off");
|
||||
if (on) {
|
||||
on = PMC_IER_LOCKB;
|
||||
value = sc->pllb_init;
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
WR4(sc, CKGR_PLLBR, value);
|
||||
while ((RD4(sc, PMC_SR) & PMC_IER_LOCKB) != on)
|
||||
continue;
|
||||
printf("Done!\n");
|
||||
}
|
||||
|
||||
static void
|
||||
at91_pmc_set_sys_mode(struct at91_pmc_clock *clk, int on)
|
||||
{
|
||||
struct at91_pmc_softc *sc = pmc_softc;
|
||||
|
||||
printf("Turning SC %#x %s\n", clk->pmc_mask, on ? "on" : "off");
|
||||
WR4(sc, on ? PMC_SCER : PMC_SCDR, clk->pmc_mask);
|
||||
if (on)
|
||||
while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) != clk->pmc_mask)
|
||||
continue;
|
||||
else
|
||||
while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) == clk->pmc_mask)
|
||||
continue;
|
||||
printf("Done SCSR is now: %#x!\n", RD4(sc, PMC_SCSR));
|
||||
}
|
||||
|
||||
static void
|
||||
at91_pmc_set_periph_mode(struct at91_pmc_clock *clk, int on)
|
||||
{
|
||||
struct at91_pmc_softc *sc = pmc_softc;
|
||||
|
||||
printf("Turning PC %#x %s\n", clk->pmc_mask, on ? "on" : "off");
|
||||
WR4(sc, on ? PMC_PCER : PMC_PCDR, clk->pmc_mask);
|
||||
if (on)
|
||||
while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) != clk->pmc_mask)
|
||||
continue;
|
||||
else
|
||||
while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) == clk->pmc_mask)
|
||||
continue;
|
||||
printf("Done PCSR is now: %#x!\n", RD4(sc, PMC_PCSR));
|
||||
}
|
||||
|
||||
struct at91_pmc_clock *
|
||||
at91_pmc_clock_ref(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(clock_list) / sizeof(clock_list[0]); i++)
|
||||
if (strcmp(name, clock_list[i]->name) == 0)
|
||||
return (clock_list[i]);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
at91_pmc_clock_deref(struct at91_pmc_clock *clk)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
at91_pmc_clock_enable(struct at91_pmc_clock *clk)
|
||||
{
|
||||
/* XXX LOCKING? XXX */
|
||||
printf("Enable %s\n", clk->name);
|
||||
if (clk->parent)
|
||||
at91_pmc_clock_enable(clk->parent);
|
||||
if (clk->refcnt++ == 0 && clk->set_mode)
|
||||
clk->set_mode(clk, 1);
|
||||
}
|
||||
|
||||
void
|
||||
at91_pmc_clock_disable(struct at91_pmc_clock *clk)
|
||||
{
|
||||
/* XXX LOCKING? XXX */
|
||||
if (--clk->refcnt == 0 && clk->set_mode)
|
||||
clk->set_mode(clk, 0);
|
||||
if (clk->parent)
|
||||
at91_pmc_clock_disable(clk->parent);
|
||||
}
|
||||
|
||||
static int
|
||||
at91_pmc_pll_rate(int freq, uint32_t reg, int is_pllb)
|
||||
{
|
||||
uint32_t mul, div;
|
||||
|
||||
div = reg & 0xff;
|
||||
mul = (reg >> 16) & 0x7ff;
|
||||
if (div != 0 && mul != 0) {
|
||||
freq /= div;
|
||||
freq *= mul + 1;
|
||||
} else {
|
||||
freq = 0;
|
||||
}
|
||||
if (is_pllb && (reg & (1 << 28)))
|
||||
freq >>= 1;
|
||||
return (freq);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
at91_pmc_pll_calc(uint32_t main_freq, uint32_t out_freq)
|
||||
{
|
||||
uint32_t i, div = 0, mul = 0, diff = 1 << 30;
|
||||
unsigned ret = (out_freq > PMC_PLL_FAST_THRESH) ? 0xbe00 : 0x3e00;
|
||||
|
||||
if (out_freq > PMC_PLL_MAX_OUT_FREQ)
|
||||
goto fail;
|
||||
|
||||
for (i = 1; i < 256; i++) {
|
||||
int32_t diff1;
|
||||
uint32_t input, mul1;
|
||||
|
||||
input = main_freq / i;
|
||||
if (input < PMC_PLL_MIN_IN_FREQ)
|
||||
break;
|
||||
if (input > PMC_PLL_MAX_IN_FREQ)
|
||||
continue;
|
||||
|
||||
mul1 = out_freq / input;
|
||||
if (mul1 > PMC_PLL_MULT_MAX)
|
||||
continue;
|
||||
if (mul1 < PMC_PLL_MULT_MIN)
|
||||
break;
|
||||
|
||||
diff1 = out_freq - input * mul1;
|
||||
if (diff1 < 0)
|
||||
diff1 = -diff1;
|
||||
if (diff > diff1) {
|
||||
diff = diff1;
|
||||
div = i;
|
||||
mul = mul1;
|
||||
if (diff == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (diff > (out_freq >> PMC_PLL_SHIFT_TOL))
|
||||
goto fail;
|
||||
return ret | ((mul - 1) << 16) | div;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
at91_pmc_init_clock(struct at91_pmc_softc *sc, int main_clock)
|
||||
{
|
||||
uint32_t mckr;
|
||||
int freq;
|
||||
|
||||
sc->main_clock_hz = main_clock;
|
||||
main_ck.hz = main_clock;
|
||||
plla.hz = at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0);
|
||||
|
||||
/*
|
||||
* Initialize the usb clock. This sets up pllb, but disables the
|
||||
* actual clock.
|
||||
*/
|
||||
sc->pllb_init = at91_pmc_pll_calc(main_clock, 48000000 * 2) |0x10000000;
|
||||
pllb.hz = at91_pmc_pll_rate(main_clock, sc->pllb_init, 1);
|
||||
WR4(sc, PMC_PCDR, (1 << AT91RM92_IRQ_UHP) | (1 << AT91RM92_IRQ_UDP));
|
||||
WR4(sc, PMC_SCDR, PMC_SCER_UHP | PMC_SCER_UDP);
|
||||
WR4(sc, CKGR_PLLBR, 0);
|
||||
WR4(sc, PMC_SCER, PMC_SCER_MCKUDP);
|
||||
|
||||
/*
|
||||
* MCK and PCU derive from one of the primary clocks. Initialize
|
||||
* this relationship.
|
||||
*/
|
||||
mckr = RD4(sc, PMC_MCKR);
|
||||
mck.parent = clock_list[mckr & 0x3];
|
||||
mck.parent->refcnt++;
|
||||
freq = mck.parent->hz;
|
||||
freq /= 1 << ((mckr >> 2) & 3);
|
||||
mck.hz = freq / (1 + ((mckr >> 8) & 3));
|
||||
|
||||
device_printf(sc->dev,
|
||||
"main clock: %d Hz PLLA: %d MHz CPU: %d MHz main %d MHz\n",
|
||||
sc->main_clock_hz,
|
||||
at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0) / 1000000,
|
||||
freq / 1000000, mck.hz / 1000000);
|
||||
WR4(sc, PMC_SCDR, PMC_SCER_PCK0 | PMC_SCER_PCK1 | PMC_SCER_PCK2 |
|
||||
PMC_SCER_PCK3);
|
||||
/* XXX kludge, turn on all peripherals */
|
||||
WR4(sc, PMC_PCER, 0xffffffff);
|
||||
/* Disable all interrupts for PMC */
|
||||
WR4(sc, PMC_IDR, 0xffffffff);
|
||||
}
|
||||
|
||||
static void
|
||||
at91_pmc_deactivate(device_t dev)
|
||||
{
|
||||
struct at91_pmc_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
bus_generic_detach(sc->dev);
|
||||
if (sc->mem_res)
|
||||
bus_release_resource(dev, SYS_RES_IOPORT,
|
||||
rman_get_rid(sc->mem_res), sc->mem_res);
|
||||
sc->mem_res = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
at91_pmc_activate(device_t dev)
|
||||
{
|
||||
struct at91_pmc_softc *sc;
|
||||
int rid;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
rid = 0;
|
||||
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
||||
RF_ACTIVE);
|
||||
if (sc->mem_res == NULL)
|
||||
goto errout;
|
||||
return (0);
|
||||
errout:
|
||||
at91_pmc_deactivate(dev);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
static int
|
||||
at91_pmc_probe(device_t dev)
|
||||
{
|
||||
|
||||
device_set_desc(dev, "PMC");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
at91_pmc_attach(device_t dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
pmc_softc = device_get_softc(dev);
|
||||
pmc_softc->dev = dev;
|
||||
if ((err = at91_pmc_activate(dev)) != 0)
|
||||
return err;
|
||||
at91_pmc_init_clock(pmc_softc, 10000000);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t at91_pmc_methods[] = {
|
||||
DEVMETHOD(device_probe, at91_pmc_probe),
|
||||
DEVMETHOD(device_attach, at91_pmc_attach),
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static driver_t at91_pmc_driver = {
|
||||
"at91_pmc",
|
||||
at91_pmc_methods,
|
||||
sizeof(struct at91_pmc_softc),
|
||||
};
|
||||
static devclass_t at91_pmc_devclass;
|
||||
|
||||
DRIVER_MODULE(at91_pmc, atmelarm, at91_pmc_driver, at91_pmc_devclass, 0, 0);
|
120
sys/arm/at91/at91_pmcreg.h
Normal file
120
sys/arm/at91/at91_pmcreg.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*-
|
||||
* Copyright (c) 2005 M. Warner Losh. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#ifndef ARM_AT91_AT91_PMCREG_H
|
||||
#define ARM_AT91_AT91_PMCREG_H
|
||||
|
||||
/* Registers */
|
||||
#define PMC_SCER 0x00 /* System Clock Enable Register */
|
||||
#define PMC_SCDR 0x04 /* System Clock Disable Register */
|
||||
#define PMC_SCSR 0x08 /* System Clock Status Register */
|
||||
/* 0x0c reserved */
|
||||
#define PMC_PCER 0x10 /* Peripheral Clock Enable Register */
|
||||
#define PMC_PCDR 0x14 /* Peripheral Clock Disable Register */
|
||||
#define PMC_PCSR 0x18 /* Peripheral Clock Status Register */
|
||||
/* 0x1c reserved */
|
||||
#define CKGR_MOR 0x20 /* Main Oscillator Register */
|
||||
#define CKGR_MCFR 0x24 /* Main Clock Frequency Register */
|
||||
#define CKGR_PLLAR 0x28 /* PLL A Register */
|
||||
#define CKGR_PLLBR 0x2c /* PLL B Register */
|
||||
#define PMC_MCKR 0x30 /* Master Clock Register */
|
||||
/* 0x34 reserved */
|
||||
/* 0x38 reserved */
|
||||
/* 0x3c reserved */
|
||||
#define PMC_PCK0 0x40 /* Programmable Clock 0 Register */
|
||||
#define PMC_PCK1 0x44 /* Programmable Clock 1 Register */
|
||||
#define PMC_PCK2 0x48 /* Programmable Clock 2 Register */
|
||||
#define PMC_PCK3 0x4c /* Programmable Clock 3 Register */
|
||||
/* 0x50 reserved */
|
||||
/* 0x54 reserved */
|
||||
/* 0x58 reserved */
|
||||
/* 0x5c reserved */
|
||||
#define PMC_IER 0x60 /* Interrupt Enable Register */
|
||||
#define PMC_IDR 0x64 /* Interrupt Disable Register */
|
||||
#define PMC_SR 0x68 /* Status Register */
|
||||
#define PMC_IMR 0x6c /* Interrupt Mask Register */
|
||||
|
||||
/* PMC System Clock Enable Register */
|
||||
/* PMC System Clock Disable Register */
|
||||
/* PMC System Clock StatusRegister */
|
||||
#define PMC_SCER_PCK (1UL << 0) /* PCK: Processor Clock Enable */
|
||||
#define PMC_SCER_UDP (1UL << 1) /* UDP: USB Device Port Clock Enable */
|
||||
#define PMC_SCER_MCKUDP (1UL << 2) /* MCKUDP: Master disable susp/res */
|
||||
#define PMC_SCER_UHP (1UL << 4) /* UHP: USB Host Port Clock Enable */
|
||||
#define PMC_SCER_PCK0 (1UL << 8) /* PCK0: Programmable Clock out en */
|
||||
#define PMC_SCER_PCK1 (1UL << 10) /* PCK1: Programmable Clock out en */
|
||||
#define PMC_SCER_PCK2 (1UL << 11) /* PCK2: Programmable Clock out en */
|
||||
#define PMC_SCER_PCK3 (1UL << 12) /* PCK3: Programmable Clock out en */
|
||||
|
||||
/* PMC Peripheral Clock Enable Register */
|
||||
/* PMC Peripheral Clock Disable Register */
|
||||
/* PMC Peripheral Clock Status Register */
|
||||
/* Each bit here is 1 << peripheral number to enable/disable/status */
|
||||
|
||||
/* PMC Clock Generator Main Oscillator Register */
|
||||
#define CKGR_MOR_MOSCEN (1UL << 0) /* MOSCEN: Main Oscillator Enable */
|
||||
#define CKGR_MOR_OSCBYPASS (1UL << 1) /* Oscillator Bypass */
|
||||
#define CKGR_MOR_OSCOUNT(x) (x << 8) /* Main Oscillator Start-up Time */
|
||||
|
||||
/* PMC Clock Generator Main Clock Frequency Register */
|
||||
#define CKGR_MCFR_MAINRDY (1UL << 16) /* Main Clock Ready */
|
||||
#define CKGR_MCFR_MAINF_MASK 0xfffful /* Main Clock Frequency */
|
||||
|
||||
/* PMC Interrupt Enable Register */
|
||||
/* PMC Interrupt Disable Register */
|
||||
/* PMC Status Register */
|
||||
/* PMC Interrupt Mask Register */
|
||||
#define PMC_IER_MOSCS (1UL << 0) /* Main Oscillator Status */
|
||||
#define PMC_IER_LOCKA (1UL << 1) /* PLL A Locked */
|
||||
#define PMC_IER_LOCKB (1UL << 2) /* PLL B Locked */
|
||||
#define PMC_IER_MCKRDY (1UL << 3) /* Master Clock Status */
|
||||
#define PMC_IER_PCK0RDY (1UL << 8) /* Programmable Clock 0 Ready */
|
||||
#define PMC_IER_PCK1RDY (1UL << 9) /* Programmable Clock 1 Ready */
|
||||
#define PMC_IER_PCK2RDY (1UL << 10) /* Programmable Clock 2 Ready */
|
||||
#define PMC_IER_PCK3RDY (1UL << 11) /* Programmable Clock 3 Ready */
|
||||
|
||||
/*
|
||||
* PLL input frequency spec sheet says it must be between 1MHz and 32MHz,
|
||||
* but it works down as low as 100kHz, a frequency necessary for some
|
||||
* output frequencies to work.
|
||||
*/
|
||||
#define PMC_PLL_MIN_IN_FREQ 100000
|
||||
#define PMC_PLL_MAX_IN_FREQ 32000000
|
||||
|
||||
/*
|
||||
* PLL Max output frequency is 240MHz. The errata says 180MHz is the max
|
||||
* for some revisions of this part. Be more permissive and optimistic.
|
||||
*/
|
||||
#define PMC_PLL_MAX_OUT_FREQ 240000000
|
||||
|
||||
#define PMC_PLL_MULT_MIN 2
|
||||
#define PMC_PLL_MULT_MAX 2048
|
||||
|
||||
#define PMC_PLL_SHIFT_TOL 5 /* Allow errors 1 part in 32 */
|
||||
|
||||
#define PMC_PLL_FAST_THRESH 155000000
|
||||
|
||||
#endif /* ARM_AT91_AT91_PMCREG_H */
|
49
sys/arm/at91/at91_pmcvar.h
Normal file
49
sys/arm/at91/at91_pmcvar.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*-
|
||||
* Copyright (c) 2005 M. Warner Losh. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#ifndef ARM_AT91_AT91_PMCVAR_H
|
||||
#define ARM_AT91_AT91_PMCVAR_H
|
||||
|
||||
struct at91_pmc_clock
|
||||
{
|
||||
const char *name;
|
||||
uint32_t hz;
|
||||
struct at91_pmc_clock *parent;
|
||||
uint32_t pmc_mask;
|
||||
void (*set_mode)(struct at91_pmc_clock *, int);
|
||||
uint32_t refcnt;
|
||||
unsigned id:2;
|
||||
unsigned primary:1;
|
||||
unsigned pll:1;
|
||||
unsigned programmable:1;
|
||||
};
|
||||
|
||||
struct at91_pmc_clock *at91_pmc_clock_ref(const char *name);
|
||||
void at91_pmc_clock_deref(struct at91_pmc_clock *);
|
||||
void at91_pmc_clock_enable(struct at91_pmc_clock *);
|
||||
void at91_pmc_clock_disable(struct at91_pmc_clock *);
|
||||
|
||||
#endif /* ARM_AT91_AT91_PMCVAR_H */
|
Loading…
Reference in New Issue
Block a user