Date: Fri, 24 Feb 2006 01:29:51 GMT From: Warner Losh <imp@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 92309 for review Message-ID: <200602240129.k1O1Tpu2043925@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=92309 Change 92309 by imp@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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200602240129.k1O1Tpu2043925>