PERFORCE change 159386 for review
Ulf Lilleengen
lulf at FreeBSD.org
Wed Mar 18 08:50:56 PDT 2009
http://perforce.freebsd.org/chv.cgi?CH=159386
Change 159386 by lulf at lulf_carrot on 2009/03/18 15:50:49
- First try at implementing the devclk interface. A devclk structure
describing each clock is added, using KOBJ to make specifying clocks
quite easily. Clocks are specified where they belong logically, in our
case within the power manager. The power manager also registers these
clocks with the devclk manager at startup. There are several ways of
constructing the clock trees, but right now, there is an oscilliator
class which handles osc0, osc1, osc32, and a pll-class which handles
the plls. Just for testing, I added one class for the pbb clock being
used by MCI.
During probing, the hints will specify which clock a device will use,
so that when a device calls devclk_enable, the bus will lookup the
appropriate clock, and call devclk_activate on the clock to activate
it. Get/set rate should behave in the same way, and will be
implemented next. Further, a clock may have a parent, so that it may
call it's parents get_rate in order to determine it's rate. Also, a
clock may have an index into the parent clock as the parent may cover
several clocks. Exactly how this will be used is not clear yet.
Affected files ...
.. //depot/projects/avr32/src/sys/avr32/avr32/at32.c#7 edit
.. //depot/projects/avr32/src/sys/avr32/avr32/at32_pm.c#3 edit
.. //depot/projects/avr32/src/sys/avr32/conf/cpu/at32ap700x.hints#3 edit
.. //depot/projects/avr32/src/sys/kern/devclk_if.m#2 edit
.. //depot/projects/avr32/src/sys/kern/subr_devclk.c#2 edit
.. //depot/projects/avr32/src/sys/sys/devclk.h#2 edit
Differences ...
==== //depot/projects/avr32/src/sys/avr32/avr32/at32.c#7 (text+ko) ====
@@ -80,7 +80,7 @@
};
struct at32_ivar {
struct resource_list resources;
- int clk_bus;
+ char clk_name[32];
int clk_index;
};
static device_method_t at32_methods[] = {
@@ -106,6 +106,7 @@
DEVMETHOD(devclk_disable, at32_clk_disable),
{0, 0},
};
+
static driver_t at32_driver = {
"at32bus",
at32_methods,
@@ -128,6 +129,9 @@
int rid;
struct at32_softc *sc = device_get_softc(dev);
+ /* Initialize devclk manager. */
+ devclk_init();
+
/* Resource list for IRQ */
/* Reserve irqs from nexus ? */
sc->sc_irq_rman.rm_type = RMAN_ARRAY;
@@ -185,9 +189,13 @@
static void
at32_hinted_child(device_t bus, const char *dname, int dunit)
{
+ /* XXX: Fetch ivar and set variables. */
device_t child;
long maddr;
int msize, irq, result;
+ const char *resval;
+ struct at32_ivar *ivar;
+
child = BUS_ADD_CHILD(bus, 0, dname, dunit);
@@ -210,6 +218,14 @@
"warning: bus_set_resource() failed\n");
}
}
+ ivar = device_get_ivars(child);
+ if (resource_string_value(dname, dunit, "clk", &resval) == 0) {
+ if (resource_int_value(dname, dunit, "clk_index",
+ &ivar->clk_index) != 0)
+ ivar->clk_index = 0; /* Default */
+ strlcpy(ivar->clk_name, resval, sizeof(ivar->clk_name));
+ }
+
}
static struct resource *
@@ -361,11 +377,19 @@
static void
at32_clk_enable(device_t dev, device_t child)
{
- /* TODO: Implement */
+ struct at32_ivar *ivar = device_get_ivars(child);
+
+ /* Only activate if it actually has a clock. */
+ if (strcmp(ivar->clk_name, "") != 0)
+ devclk_activate(ivar->clk_name, ivar->clk_index);
}
static void
at32_clk_disable(device_t dev, device_t child)
{
- /* TODO: Implement */
+ struct at32_ivar *ivar = device_get_ivars(child);
+
+ /* Only deactivate if it actually has a clock. */
+ if (strcmp(ivar->clk_name, "") != 0)
+ devclk_deactivate(ivar->clk_name, ivar->clk_index);
}
==== //depot/projects/avr32/src/sys/avr32/avr32/at32_pm.c#3 (text+ko) ====
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2009 Arnar Mar Sig
+ * Copyright (c) 2009 Ulf Lilleengen <lulf at FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,6 +38,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/kobj.h>
#include <sys/module.h>
#include <sys/time.h>
#include <sys/bus.h>
@@ -63,6 +65,13 @@
static int at32_pm_activate(device_t);
static void at32_pm_deactivate(device_t);
+static void at32_pbb_start(devclk_t, uint8_t);
+static void at32_pbb_stop(devclk_t, uint8_t);
+static void at32_pll_start(devclk_t, uint8_t);
+static void at32_pll_stop(devclk_t, uint8_t);
+static void at32_osc_start(devclk_t, uint8_t);
+static void at32_osc_stop(devclk_t, uint8_t);
+
/* Driver variables and private data */
struct at32_pm_softc {
struct resource *regs_res;
@@ -70,11 +79,13 @@
bus_space_tag_t bst;
bus_space_handle_t bsh;
};
+
static device_method_t at32_pm_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, at32_pm_probe),
DEVMETHOD(device_attach, at32_pm_attach),
DEVMETHOD(device_detach, at32_pm_detach),
+
{0, 0},
};
static driver_t at32_pm_driver = {
@@ -83,8 +94,39 @@
sizeof(struct at32_pm_softc),
};
static devclass_t at32_pm_devclass;
+
DRIVER_MODULE(at32_pm, at32bus, at32_pm_driver, at32_pm_devclass, 0, 0);
+/* Class defining our oscilliator. */
+static kobj_method_t at32_osc_methods[] = {
+ KOBJMETHOD(devclk_start, at32_osc_start),
+ KOBJMETHOD(devclk_stop, at32_osc_stop),
+/* KOBJMETHOD(devclk_set_rate, at32_osc_set_rate),
+ KOBJMETHOD(devclk_get_rate, at32_osc_get_rate),*/
+ {0, 0},
+};
+DEFINE_CLASS(at32_osc, at32_osc_methods, sizeof(struct devclk));
+
+/* Class defining our PLLs. */
+static kobj_method_t at32_pll_methods[] = {
+ KOBJMETHOD(devclk_start, at32_pll_start),
+ KOBJMETHOD(devclk_stop, at32_pll_stop),
+/* KOBJMETHOD(devclk_set_rate, at32_pll_set_rate),
+ KOBJMETHOD(devclk_get_rate, at32_pll_get_rate),*/
+ {0, 0},
+};
+DEFINE_CLASS(at32_pll, at32_pll_methods, sizeof(struct devclk));
+
+/* Class defining the PBB clock mask. */
+static kobj_method_t at32_pbb_methods[] = {
+ KOBJMETHOD(devclk_start, at32_pbb_start),
+ KOBJMETHOD(devclk_stop, at32_pbb_stop),
+/* KOBJMETHOD(devclk_set_rate, at32_pbb_set_rate),
+ KOBJMETHOD(devclk_get_rate, at32_pbb_get_rate),*/
+ {0, 0},
+};
+DEFINE_CLASS(at32_pbb, at32_pbb_methods, sizeof(struct devclk));
+
/* Code */
static int
at32_pm_probe(device_t dev)
@@ -125,12 +167,29 @@
/* Set private data and map register space */
sc->regs_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->regs_rid, 0,
~0, 0, RF_ACTIVE);
+/* sc->clock_res = bus_alloc_resource(dev, SYS_RES_CLOCK, &sc->clock_res,
+ RF_ACTIVE);*/
if (!sc->regs_res) {
goto err;
}
sc->bsh = rman_get_bushandle(sc->regs_res);
sc->bst = rman_get_bustag(sc->regs_res);
+ /* Register main clocks. */
+ //devclk_register_clock(dev, "osc32", NULL);
+ devclk_register_clock(dev, &at32_osc_class, "osc0", NULL);
+ //devclk_register_clock(dev, &sc->osc1, "osc1", NULL);
+
+ /* Register prescalers. */
+ devclk_register_clock(dev, &at32_pll_class, "pll0", "osc0");
+ //devclk_register_clock(dev, &sc->pll1, "pll1", &sc->osc0);
+
+ /* Register master device clocks. */
+ devclk_register_clock(dev, &at32_pbb_class, "pbb", "pll0");
+// devclk_register_clock(dev, &sc->cpu, "cpu", &sc->pll0);
+// devclk_register_clock(dev, &sc->hsb, "hsb", &sc->cpu);
+// devclk_register_clock(dev, &sc->pba, "pba", &sc->hsb);
+// devclk_register_clock(dev, &sc->pbb, "pbb", &sc->hsb);
return (0);
err:
@@ -151,3 +210,81 @@
/* Turn off device clock */
devclk_disable(dev);
}
+
+static void
+at32_pbb_start(devclk_t clk, uint8_t index)
+{
+ struct at32_pm_softc *sc;
+ uint32_t reg;
+
+ KASSERT(clk != NULL, ("NULL clk"));
+ KASSERT(index < 31, ("index > register width"));
+ sc = device_get_softc(clk->dev);
+ reg = RD4(AT32_PM_PBBMASK);
+ WR4(AT32_PM_PBBMASK, reg | (1 << index));
+}
+
+static void
+at32_pbb_stop(devclk_t clk, uint8_t index)
+{
+ struct at32_pm_softc *sc;
+ uint32_t reg;
+
+ KASSERT(clk != NULL, ("NULL clk"));
+ KASSERT(index < 31, ("index > register width"));
+ sc = device_get_softc(clk->dev);
+ reg = RD4(AT32_PM_PBBMASK);
+ WR4(AT32_PM_PBBMASK, reg & ~(1 << index));
+}
+
+static void
+at32_osc_start(devclk_t clk, uint8_t index)
+{
+ /* In this case, index means which oscilliator. */
+ switch (index) {
+ case 0: /* OSC0 */
+ break;
+ case 1: /* OSC1 */
+ break;
+ case 2: /* OSC32 */
+ break;
+ }
+}
+
+static void
+at32_osc_stop(devclk_t clk, uint8_t index)
+{
+ /* In this case, index means which oscilliator. */
+ switch (index) {
+ case 0: /* OSC0 */
+ break;
+ case 1: /* OSC1 */
+ break;
+ case 2: /* OSC32 */
+ break;
+ }
+}
+
+static void
+at32_pll_start(devclk_t clk, uint8_t index)
+{
+ /* Here, index means which pll. */
+ switch (index) {
+ case 0: /* PLL0. */
+ break;
+ case 1: /* PLL1. */
+ break;
+ }
+}
+
+static void
+at32_pll_stop(devclk_t clk, uint8_t index)
+{
+ /* Here, index means which pll. */
+ switch (index) {
+ case 0: /* PLL0. */
+ break;
+ case 1: /* PLL1. */
+ break;
+ }
+}
==== //depot/projects/avr32/src/sys/avr32/conf/cpu/at32ap700x.hints#3 (text+ko) ====
@@ -160,6 +160,8 @@
hint.atmel_mci.0.maddr="0xFFF02400"
hint.atmel_mci.0.msize="0x400"
hint.atmel_mci.0.irq="28"
+hint.atmel_mci.0.clk="pbb"
+hint.atmel_mci.0.clk_index="9"
hint.at32_ac97c.0.at="at32bus0"
hint.at32_ac97c.0.maddr="0xFFF02800"
==== //depot/projects/avr32/src/sys/kern/devclk_if.m#2 (text+ko) ====
@@ -54,3 +54,15 @@
device_t _dev;
device_t _child;
};
+
+# Enable a devclk
+METHOD void start {
+ devclk_t _clk;
+ uint8_t _index;
+};
+
+# Disable a devclk
+METHOD void stop {
+ devclk_t _clk;
+ uint8_t _index;
+};
==== //depot/projects/avr32/src/sys/kern/subr_devclk.c#2 (text+ko) ====
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2009 Arnar Mar Sig <antab at antab.is>
+ * Copyright (c) 2009 Ulf Lilleengen <lulf at FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,12 +31,24 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/devclk.h>
+#include <sys/queue.h>
#include "devclk_if.h"
+static devclk_list_t devclks;
+
+static devclk_t devclk_find_clock(const char *);
+
+void
+devclk_init(void)
+{
+ STAILQ_INIT(&devclks);
+}
+
uint64_t
devclk_get_rate(device_t dev)
{
@@ -73,3 +86,60 @@
DEVCLK_DISABLE(parent, dev);
}
}
+
+/**
+ * Register clock name handled by device dev, with the parent clock parent
+ */
+void
+devclk_register_clock(device_t dev, kobj_class_t cls, const char *name,
+ const char *parent)
+{
+ devclk_t clk;
+
+ clk = malloc(sizeof(*clk), M_DEVBUF, M_WAITOK | M_ZERO);
+ clk->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO);
+ clk->dev = dev;
+ strlcpy(clk->name, name, sizeof(clk->name));
+ clk->parent = ((parent == NULL) ? NULL : devclk_find_clock(parent));
+
+ /* Insert clock into list. */
+ STAILQ_INSERT_HEAD(&devclks, clk, link);
+}
+
+static devclk_t
+devclk_find_clock(const char *name)
+{
+ devclk_t clk;
+
+ KASSERT(name != NULL, ("null name"));
+ STAILQ_FOREACH(clk, &devclks, link) {
+ if (strcmp(clk->name, name) == 0)
+ return (clk);
+ }
+ return (NULL);
+}
+
+/* Start device clock name by activating index index. */
+void
+devclk_activate(const char *name, uint8_t index)
+{
+ devclk_t clk;
+
+ clk = devclk_find_clock(name);
+ if (clk == NULL)
+ return;
+ /* XXX: Enable parent too ? */
+ DEVCLK_START(clk->methods, index);
+}
+
+/* Stop device clock name by deactivating index index. */
+void
+devclk_deactivate(const char *name, uint8_t index)
+{
+ devclk_t clk;
+
+ clk = devclk_find_clock(name);
+ if (clk == NULL)
+ return;
+ DEVCLK_STOP(clk->methods, index);
+}
==== //depot/projects/avr32/src/sys/sys/devclk.h#2 (text+ko) ====
@@ -1,9 +1,23 @@
#ifndef _SYS_DEVCLK_H_
#define _SYS_DEVCLK_H_
+#ifdef _KERNEL
+
+#include <sys/kobj.h>
+struct devclk {
+ kobj_t methods;
+ device_t dev; /* Device responsible for clock. */
+ char name[32]; /* Clock name. */
+ struct devclk *parent; /* Clock we originate from. */
+ int index; /* Our index in our parent. */
+ STAILQ_ENTRY(devclk) link;
+};
+typedef struct devclk* devclk_t;
+typedef STAILQ_HEAD(, devclk) devclk_list_t;
+
#include "devclk_if.h"
-#ifdef _KERNEL
+void devclk_init(void);
/**
* Get device clock rate
@@ -25,7 +39,14 @@
*/
void devclk_disable(device_t);
+void devclk_activate(const char *, uint8_t);
+void devclk_deactivate(const char *, uint8_t);
+
+/**
+ * Add a clock to the devclk manager.
+ */
+void devclk_register_clock(device_t, kobj_class_t, const char *, const char *);
+
#endif /* _KERNEL */
#endif /* !_SYS_DEVCLK_H_ */
-
More information about the p4-projects
mailing list