PERFORCE change 92309 for review
Warner Losh
imp at FreeBSD.org
Thu Feb 23 17:29:53 PST 2006
http://perforce.freebsd.org/chv.cgi?CH=92309
Change 92309 by imp at imp_Speedy on 2006/02/24 01:29:04
Export clock management functionality.
Turn on ohci clocks in its attach routine, turn them off in the detach.
Affected files ...
.. //depot/projects/arm/src/sys/arm/at91/at91_pmc.c#10 edit
.. //depot/projects/arm/src/sys/arm/at91/at91_pmcvar.h#1 add
.. //depot/projects/arm/src/sys/arm/at91/ohci_atmelarm.c#9 edit
Differences ...
==== //depot/projects/arm/src/sys/arm/at91/at91_pmc.c#10 (text+ko) ====
@@ -44,6 +44,7 @@
#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;
@@ -54,20 +55,6 @@
uint32_t pllb_init;
} *pmc_softc;
-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;
-};
-
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);
@@ -101,7 +88,7 @@
static struct at91_pmc_clock pllb = {
.name = "pllb", // PLLB Clock, used for USB functions
.parent = &main_ck,
- .refcnt = 1,
+ .refcnt = 0,
.id = 0,
.primary = 1,
.pll = 1,
@@ -170,18 +157,72 @@
static void
at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on)
{
+ struct at91_pmc_softc *sc = pmc_softc;
+ uint32_t value;
+
+ 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;
}
static void
at91_pmc_set_sys_mode(struct at91_pmc_clock *clk, int on)
{
+ struct at91_pmc_softc *sc = pmc_softc;
+
+ WR4(sc, on ? PMC_SCER : PMC_SCDR, clk->pmc_mask);
}
static void
at91_pmc_set_periph_mode(struct at91_pmc_clock *clk, int on)
{
+ struct at91_pmc_softc *sc = pmc_softc;
+
+ WR4(sc, on ? PMC_PCER : PMC_PCDR, clk->pmc_mask);
+}
+
+struct at91_pmc_clock *
+at91_pmc_clock_ref(const char *name)
+{
+ int i;
+
+ /* XXX LOCKING? XXX */
+ 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)
+{
+ 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)
+{
+ 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)
{
@@ -197,7 +238,7 @@
}
if (is_pllb && (reg & (1 << 28)))
freq >>= 1;
- return freq;
+ return (freq);
}
static uint32_t
@@ -269,7 +310,6 @@
* this relationship.
*/
mckr = RD4(sc, PMC_MCKR);
- printf("mckr is %x\n", mckr);
mck.parent = clock_list[mckr & 0x3];
mck.parent->refcnt++;
freq = mck.parent->hz;
@@ -283,8 +323,6 @@
freq / 1000000, mck.hz / 1000000);
WR4(sc, PMC_SCDR, PMC_SCER_PCK0 | PMC_SCER_PCK1 | PMC_SCER_PCK2 |
PMC_SCER_PCK3);
- /* XXX -- enable all PMC clocks */
- WR4(sc, PMC_PCER, 0xffffffff);
/* Disable all interrupts for PMC */
WR4(sc, PMC_IDR, 0xffffffff);
}
==== //depot/projects/arm/src/sys/arm/at91/ohci_atmelarm.c#9 (text+ko) ====
@@ -43,11 +43,20 @@
#include <dev/usb/ohcireg.h>
#include <dev/usb/ohcivar.h>
+#include <arm/at91/at91_pmcvar.h>
+
#define MEM_RID 0
static int ohci_atmelarm_attach(device_t dev);
static int ohci_atmelarm_detach(device_t dev);
+struct at91_ohci_softc
+{
+ struct ohci_softc sc_ohci;
+ struct at91_pmc_clock *iclk;
+ struct at91_pmc_clock *fclk;
+};
+
static int
ohci_atmelarm_probe(device_t dev)
{
@@ -58,47 +67,57 @@
static int
ohci_atmelarm_attach(device_t dev)
{
- ohci_softc_t *sc = device_get_softc(dev);
+ struct at91_ohci_softc *sc = device_get_softc(dev);
int err;
int rid;
- /* XXX need to enable clocks here, and some other stuff */
+
+ sc->iclk = at91_pmc_clock_ref("ohci_clk");
+ sc->fclk = at91_pmc_clock_ref("uhpck");
rid = MEM_RID;
- sc->io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ sc->sc_ohci.io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
- if (sc->io_res == NULL) {
+ if (sc->sc_ohci.io_res == NULL) {
err = ENOMEM;
goto error;
}
- sc->iot = rman_get_bustag(sc->io_res);
- sc->ioh = rman_get_bushandle(sc->io_res);
+ sc->sc_ohci.iot = rman_get_bustag(sc->sc_ohci.io_res);
+ sc->sc_ohci.ioh = rman_get_bushandle(sc->sc_ohci.io_res);
rid = 0;
- sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ sc->sc_ohci.irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
RF_ACTIVE);
- if (sc->irq_res == NULL) {
+ if (sc->sc_ohci.irq_res == NULL) {
err = ENOMEM;
goto error;
}
- sc->sc_bus.bdev = device_add_child(dev, "usb", -1);
- if (sc->sc_bus.bdev == NULL) {
+ sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usb", -1);
+ if (sc->sc_ohci.sc_bus.bdev == NULL) {
err = ENOMEM;
goto error;
}
- device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
+ device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus);
- err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO, ohci_intr, sc,
- &sc->ih);
+ err = bus_setup_intr(dev, sc->sc_ohci.irq_res, INTR_TYPE_BIO, ohci_intr, sc,
+ &sc->sc_ohci.ih);
if (err) {
err = ENXIO;
goto error;
}
- strlcpy(sc->sc_vendor, "Atmel", sizeof(sc->sc_vendor));
- err = ohci_init(sc);
+ strlcpy(sc->sc_ohci.sc_vendor, "Atmel", sizeof(sc->sc_ohci.sc_vendor));
+
+ /*
+ * turn on the clocks from the AT91's point of view. Keep the unit in reset.
+ */
+ at91_pmc_clock_enable(sc->iclk);
+ at91_pmc_clock_enable(sc->fclk);
+ bus_space_write_4(sc->sc_ohci.iot, sc->sc_ohci.ioh, OHCI_CONTROL, 0);
+
+ err = ohci_init(&sc->sc_ohci);
if (!err) {
- sc->sc_flags |= OHCI_SCFLG_DONEINIT;
- err = device_probe_and_attach(sc->sc_bus.bdev);
+ sc->sc_ohci.sc_flags |= OHCI_SCFLG_DONEINIT;
+ err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev);
}
error:;
@@ -112,30 +131,45 @@
static int
ohci_atmelarm_detach(device_t dev)
{
- ohci_softc_t *sc = device_get_softc(dev);
+ struct at91_ohci_softc *sc = device_get_softc(dev);
- if (sc->sc_flags & OHCI_SCFLG_DONEINIT) {
- ohci_detach(sc, 0);
- sc->sc_flags &= ~OHCI_SCFLG_DONEINIT;
+ if (sc->sc_ohci.sc_flags & OHCI_SCFLG_DONEINIT) {
+ ohci_detach(&sc->sc_ohci, 0);
+ sc->sc_ohci.sc_flags &= ~OHCI_SCFLG_DONEINIT;
}
- if (sc->ih) {
- bus_teardown_intr(dev, sc->irq_res, sc->ih);
- sc->ih = NULL;
+ /*
+ * Put the controller into reset, then disable clocks and do
+ * the MI tear down. We have to disable the clocks/hardware
+ * after we do the rest of the teardown. We also disable the
+ * clocks in the opposite order we acquire them, but that
+ * doesn't seem to be absolutely necessary. We free up the
+ * clocks after we disable them, so the system could, in
+ * theory, reuse them.
+ */
+ bus_space_write_4(sc->sc_ohci.iot, sc->sc_ohci.ioh, OHCI_CONTROL, 0);
+ at91_pmc_clock_disable(sc->fclk);
+ at91_pmc_clock_disable(sc->iclk);
+ at91_pmc_clock_deref(sc->fclk);
+ at91_pmc_clock_deref(sc->iclk);
+
+ if (sc->sc_ohci.ih) {
+ bus_teardown_intr(dev, sc->sc_ohci.irq_res, sc->sc_ohci.ih);
+ sc->sc_ohci.ih = NULL;
}
- if (sc->sc_bus.bdev) {
- device_delete_child(dev, sc->sc_bus.bdev);
- sc->sc_bus.bdev = NULL;
+ if (sc->sc_ohci.sc_bus.bdev) {
+ device_delete_child(dev, sc->sc_ohci.sc_bus.bdev);
+ sc->sc_ohci.sc_bus.bdev = NULL;
}
- if (sc->irq_res) {
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
- sc->irq_res = NULL;
+ if (sc->sc_ohci.irq_res) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.irq_res);
+ sc->sc_ohci.irq_res = NULL;
}
- if (sc->io_res) {
- bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, sc->io_res);
- sc->io_res = NULL;
- sc->iot = 0;
- sc->ioh = 0;
+ if (sc->sc_ohci.io_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, sc->sc_ohci.io_res);
+ sc->sc_ohci.io_res = NULL;
+ sc->sc_ohci.iot = 0;
+ sc->sc_ohci.ioh = 0;
}
return (0);
}
@@ -156,7 +190,7 @@
static driver_t ohci_driver = {
"ohci",
ohci_methods,
- sizeof(ohci_softc_t),
+ sizeof(struct at91_ohci_softc),
};
static devclass_t ohci_devclass;
More information about the p4-projects
mailing list