On Mon, 22 Jan 2018 07:10:30 +0000 (UTC) Poul-Henning Kamp <p...@freebsd.org> wrote:
> Author: phk > Date: Mon Jan 22 07:10:30 2018 > New Revision: 328257 > URL: https://svnweb.freebsd.org/changeset/base/328257 > > Log: > Add a skeleton Clock Manager for RPi2/3, and use that from pwm > instead of frobbing the registers directly. > > As a hack the bcm2835_pwm kmod presently ignores the 'status="disabled"' > in the RPI3 DTB, assuming that if you load the kld you probably > want the PWM to work. > > Added: > head/sys/arm/broadcom/bcm2835/bcm2835_clkman.c (contents, props changed) > head/sys/arm/broadcom/bcm2835/bcm2835_clkman.h (contents, props changed) > Modified: > head/sys/arm/broadcom/bcm2835/bcm2835_pwm.c > head/sys/dts/arm/bcm2836.dtsi > head/sys/modules/Makefile > > Added: head/sys/arm/broadcom/bcm2835/bcm2835_clkman.c > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/sys/arm/broadcom/bcm2835/bcm2835_clkman.c Mon Jan 22 07:10:30 > 2018 (r328257) > @@ -0,0 +1,212 @@ > +/*- > + * Copyright (C) 2013-2015 Daisuke Aoyama <aoy...@peach.ne.jp> Was is based on some file ? Also someone will probably complain about SDPX tag here :) > + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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/bus.h> > +#include <sys/cpu.h> > +#include <sys/kernel.h> > +#include <sys/lock.h> > +#include <sys/malloc.h> > +#include <sys/module.h> > +#include <sys/mutex.h> > +#include <sys/rman.h> > +#include <sys/sema.h> > +#include <sys/sysctl.h> > + > +#include <machine/bus.h> > +#include <machine/cpu.h> > + > +#include <dev/ofw/ofw_bus.h> > +#include <dev/ofw/ofw_bus_subr.h> > + > +#include <arm/broadcom/bcm2835/bcm2835_clkman.h> > + > +static struct ofw_compat_data compat_data[] = { > + {"brcm,bcm2835-cprman", 1}, > + {"broadcom,bcm2835-cprman", 1}, > + {NULL, 0} > +}; > + > +struct bcm2835_clkman_softc { > + device_t sc_dev; > + > + struct resource * sc_m_res; > + bus_space_tag_t sc_m_bst; > + bus_space_handle_t sc_m_bsh; > +}; > + > +#define BCM_CLKMAN_WRITE(_sc, _off, _val) \ > + bus_space_write_4(_sc->sc_m_bst, _sc->sc_m_bsh, _off, _val) > +#define BCM_CLKMAN_READ(_sc, _off) \ > + bus_space_read_4(_sc->sc_m_bst, _sc->sc_m_bsh, _off) > + > +#define W_CMCLK(_sc, unit, _val) BCM_CLKMAN_WRITE(_sc, unit, 0x5a000000 | > (_val)) > +#define R_CMCLK(_sc, unit) BCM_CLKMAN_READ(_sc, unit) > +#define W_CMDIV(_sc, unit, _val) BCM_CLKMAN_WRITE(_sc, (unit) + 4, > 0x5a000000 | (_val)) > +#define R_CMDIV(_sc, unit) BCM_CLKMAN_READ(_sc, (unit) + 4) > + > +static int > +bcm2835_clkman_probe(device_t dev) > +{ > + > + if (!ofw_bus_status_okay(dev)) > + return (ENXIO); > + > + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) > + return (ENXIO); > + > + device_set_desc(dev, "BCM283x Clock Manager"); > + > + return (BUS_PROBE_DEFAULT); > +} > + > +static int > +bcm2835_clkman_attach(device_t dev) > +{ > + struct bcm2835_clkman_softc *sc; > + int rid; > + > + if (device_get_unit(dev) != 0) { > + device_printf(dev, "only one clk manager supported\n"); > + return (ENXIO); > + } > + > + sc = device_get_softc(dev); > + sc->sc_dev = dev; > + > + rid = 0; > + sc->sc_m_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, > + RF_ACTIVE); > + if (!sc->sc_m_res) { > + device_printf(dev, "cannot allocate memory window\n"); > + return (ENXIO); > + } > + > + sc->sc_m_bst = rman_get_bustag(sc->sc_m_res); > + sc->sc_m_bsh = rman_get_bushandle(sc->sc_m_res); > + > + return (bus_generic_attach(dev)); > +} > + > +uint32_t > +bcm2835_clkman_set_frequency(device_t dev, uint32_t unit, uint32_t hz) > +{ > + struct bcm2835_clkman_softc *sc; > + int i; > + uint32_t u; > + > + sc = device_get_softc(dev); > + > + if (unit != BCM_PWM_CLKSRC) { > + device_printf(sc->sc_dev, > + "Unsupported unit 0x%x", unit); > + return (0); > + } Uhg, this is ... ugly ... The proper way will be to introduce a real clock manager exposing a clock domain and clocks using the extres/clk framework. I'm still writing manpages for thoses but in the meantime you can look at arm/nvidia and arm/allwinner/clkng (or ask me/mmel@ questions about it). > + > + W_CMCLK(sc, unit, 6); > + for (i = 0; i < 10; i++) { > + u = R_CMCLK(sc, unit); > + if (!(u&0x80)) > + break; > + DELAY(1000); > + } > + if (u & 0x80) { > + device_printf(sc->sc_dev, > + "Failed to stop clock for unit 0x%x", unit); > + return (0); > + } > + if (hz == 0) > + return (0); > + > + u = 500000000/hz; > + if (u < 4) { > + device_printf(sc->sc_dev, > + "Frequency too high for unit 0x%x (max: 125MHz)", > + unit); > + return (0); > + } > + if (u > 0xfff) { > + device_printf(sc->sc_dev, > + "Frequency too low for unit 0x%x (min: 123Hz)", > + unit); > + return (0); > + } > + hz = 500000000/u; > + W_CMDIV(sc, unit, u << 12); > + > + W_CMCLK(sc, unit, 0x16); > + for (i = 0; i < 10; i++) { > + u = R_CMCLK(sc, unit); > + if ((u&0x80)) > + break; > + DELAY(1000); > + } > + if (!(u & 0x80)) { > + device_printf(sc->sc_dev, > + "Failed to start clock for unit 0x%x", unit); > + return (0); > + } > + return (hz); > +} > + > +static int > +bcm2835_clkman_detach(device_t dev) > +{ > + struct bcm2835_clkman_softc *sc; > + > + bus_generic_detach(dev); > + > + sc = device_get_softc(dev); > + if (sc->sc_m_res) > + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_m_res); > + > + return (0); > +} > + > +static device_method_t bcm2835_clkman_methods[] = { > + /* Device interface */ > + DEVMETHOD(device_probe, bcm2835_clkman_probe), > + DEVMETHOD(device_attach, bcm2835_clkman_attach), > + DEVMETHOD(device_detach, bcm2835_clkman_detach), > + > + DEVMETHOD_END > +}; > + > +static devclass_t bcm2835_clkman_devclass; > +static driver_t bcm2835_clkman_driver = { > + "bcm2835_clkman", > + bcm2835_clkman_methods, > + sizeof(struct bcm2835_clkman_softc), > +}; > + > +DRIVER_MODULE(bcm2835_clkman, simplebus, bcm2835_clkman_driver, > + bcm2835_clkman_devclass, 0, 0); > +MODULE_VERSION(bcm2835_clkman, 1); > > Added: head/sys/arm/broadcom/bcm2835/bcm2835_clkman.h > ============================================================================== > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > +++ head/sys/arm/broadcom/bcm2835/bcm2835_clkman.h Mon Jan 22 07:10:30 > 2018 (r328257) > @@ -0,0 +1,43 @@ > +/*- > + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD > + * > + * Copyright (c) 2017 Poul-Henning Kamp <p...@freebsd.org> > + * > + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 _BCM2835_CLKMAN_H_ > +#define _BCM2835_CLKMAN_H_ > + > +// Offset into BAR0 for unit > +enum bcm2835_clksrc { > + BCM_GPIO0_CLKSRC = 0x70, > + BCM_GPIO1_CLKSRC = 0x78, > + BCM_GPIO2_CLKSRC = 0x80, > + BCM_PWM_CLKSRC = 0xa0, > +}; > + > +uint32_t bcm2835_clkman_set_frequency(device_t, uint32_t, uint32_t); > + > +#endif /* _BCM2835_CLKMAN_H_ */ > > Modified: head/sys/arm/broadcom/bcm2835/bcm2835_pwm.c > ============================================================================== > --- head/sys/arm/broadcom/bcm2835/bcm2835_pwm.c Mon Jan 22 06:00:45 > 2018 (r328256) > +++ head/sys/arm/broadcom/bcm2835/bcm2835_pwm.c Mon Jan 22 07:10:30 > 2018 (r328257) > @@ -42,12 +42,12 @@ __FBSDID("$FreeBSD$"); > > #include <machine/bus.h> > #include <machine/resource.h> > -#include <machine/intr.h> > > #include <dev/ofw/ofw_bus.h> > #include <dev/ofw/ofw_bus_subr.h> > > #include <arm/broadcom/bcm2835/bcm2835_gpio.h> > +#include <arm/broadcom/bcm2835/bcm2835_clkman.h> > > static struct ofw_compat_data compat_data[] = { > {"broadcom,bcm2835-pwm", 1}, > @@ -62,9 +62,7 @@ struct bcm_pwm_softc { > bus_space_tag_t sc_m_bst; > bus_space_handle_t sc_m_bsh; > > - struct resource * sc_clk_res; > - bus_space_tag_t sc_c_bst; > - bus_space_handle_t sc_c_bsh; > + device_t clkman; > > uint32_t freq; > uint32_t period; > @@ -91,15 +89,9 @@ struct bcm_pwm_softc { > #define W_DAT(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x14, _val) > #define R_DAT(_sc) BCM_PWM_MEM_READ(_sc, 0x14) > > -#define W_CMCLK(_sc, _val) BCM_PWM_CLK_WRITE(_sc, 0x00, 0x5a000000 | (_val)) > -#define R_CMCLK(_sc) BCM_PWM_CLK_READ(_sc, 0x00) > -#define W_CMDIV(_sc, _val) BCM_PWM_CLK_WRITE(_sc, 0x04, 0x5a000000 | (_val)) > -#define R_CMDIV(_s) BCM_PWM_CLK_READ(_sc, 0x04) > - > static int > bcm_pwm_reconf(struct bcm_pwm_softc *sc) > { > - int i; > uint32_t u; > device_t gpio; > > @@ -107,22 +99,10 @@ bcm_pwm_reconf(struct bcm_pwm_softc *sc) > W_CTL(sc, 0); > > /* Stop PWM clock */ > - W_CMCLK(sc, 6); > - for (i = 0; i < 10; i++) { > - u = R_CMCLK(sc); > - if (!(u&0x80)) > - break; > - DELAY(1000); > - } > - if (u&0x80) { > - device_printf(sc->sc_dev, "Failed to stop clock\n"); > - return(EIO); > - } > + (void)bcm2835_clkman_set_frequency(sc->clkman, BCM_PWM_CLKSRC, 0); > > - if (sc->mode == 0) { > - // XXX: GPIO cfg ? > + if (sc->mode == 0) > return (0); > - } > > /* Ask GPIO0 to set ALT0 for pin 12 */ > gpio = devclass_get_device(devclass_find("gpio"), 0); > @@ -132,32 +112,11 @@ bcm_pwm_reconf(struct bcm_pwm_softc *sc) > } > bcm_gpio_set_alternate(gpio, 12, BCM_GPIO_ALT0); > > - /* Configure divider */ > - u = 500000000/sc->freq; > - if (u < 4) { > - device_printf(sc->sc_dev, "Freq too high (max 125MHz)\n"); > - return(EINVAL); > - } > - if (u > 0xfff) { > - device_printf(sc->sc_dev, "Freq too low (min 123Hz)\n"); > - return(EINVAL); > - } > - sc->freq = 500000000/u; > - W_CMDIV(sc, u << 12); > + u = bcm2835_clkman_set_frequency(sc->clkman, BCM_PWM_CLKSRC, sc->freq); > + if (u == 0) > + return (EINVAL); > + sc->freq = u; > > - /* Start PWM clock */ > - W_CMCLK(sc, 0x16); > - for (i = 0; i < 10; i++) { > - u = R_CMCLK(sc); > - if ((u&0x80)) > - break; > - DELAY(1000); > - } > - if (!(u&0x80)) { > - device_printf(sc->sc_dev, "Failed to start clock\n"); > - return(EIO); > - } > - > /* Config PWM */ > W_RNG(sc, sc->period); > if (sc->ratio > sc->period) > @@ -266,19 +225,13 @@ bcm_pwm_reg_proc(SYSCTL_HANDLER_ARGS) > int error; > > sc = (struct bcm_pwm_softc *)arg1; > - if (arg2 & 0x100) > - reg = BCM_PWM_CLK_READ(sc, arg2 & 0xff); > - else > - reg = BCM_PWM_MEM_READ(sc, arg2 & 0xff); > + reg = BCM_PWM_MEM_READ(sc, arg2 & 0xff); > > error = sysctl_handle_int(oidp, ®, sizeof(reg), req); > if (error != 0 || req->newptr == NULL) > return (error); > > - if (arg2 & 0x100) > - BCM_PWM_CLK_WRITE(sc, arg2 & 0xff, reg); > - else > - BCM_PWM_MEM_WRITE(sc, arg2, reg); > + BCM_PWM_MEM_WRITE(sc, arg2, reg); > return (0); > } > > @@ -301,8 +254,6 @@ bcm_pwm_sysctl_init(struct bcm_pwm_softc *sc) > CTLFLAG_RW | CTLTYPE_UINT, sc, 0x##x, \ > bcm_pwm_reg_proc, "IU", "Register 0x" #x " " y); > > - RR(100, "PWMCTL") > - RR(104, "PWMDIV") > RR(24, "DAT2") > RR(20, "RNG2") > RR(18, "FIF1") > @@ -335,8 +286,12 @@ static int > bcm_pwm_probe(device_t dev) > { > > +#if 0 > + // XXX: default state is disabled in RPI3 DTB, assume for now > + // XXX: that people want the PWM to work if the KLD this module. > if (!ofw_bus_status_okay(dev)) > return (ENXIO); > +#endif > > if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) > return (ENXIO); > @@ -360,6 +315,12 @@ bcm_pwm_attach(device_t dev) > sc = device_get_softc(dev); > sc->sc_dev = dev; > > + sc->clkman = devclass_get_device(devclass_find("bcm2835_clkman"), 0); > + if (sc->clkman == NULL) { > + device_printf(dev, "cannot find Clock Manager\n"); > + return (ENXIO); > + } > + > rid = 0; > sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, > RF_ACTIVE); > @@ -371,16 +332,6 @@ bcm_pwm_attach(device_t dev) > sc->sc_m_bst = rman_get_bustag(sc->sc_mem_res); > sc->sc_m_bsh = rman_get_bushandle(sc->sc_mem_res); > > - rid = 1; > - sc->sc_clk_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, > - RF_ACTIVE); > - if (!sc->sc_clk_res) { > - device_printf(dev, "cannot allocate clock window\n"); > - return (ENXIO); > - } > - sc->sc_c_bst = rman_get_bustag(sc->sc_clk_res); > - sc->sc_c_bsh = rman_get_bushandle(sc->sc_clk_res); > - > /* Add sysctl nodes. */ > bcm_pwm_sysctl_init(sc); > > @@ -400,12 +351,10 @@ bcm_pwm_detach(device_t dev) > bus_generic_detach(dev); > > sc = device_get_softc(dev); > - sc->mode = 0; > + sc->mode = 0; > (void)bcm_pwm_reconf(sc); > if (sc->sc_mem_res) > bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); > - if (sc->sc_clk_res) > - bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_clk_res); > > return (0); > } > @@ -414,17 +363,15 @@ static phandle_t > bcm_pwm_get_node(device_t bus, device_t dev) > { > > - /* We only have one child, the SPI bus, which needs our own node. */ > return (ofw_bus_get_node(bus)); > } > > + > static device_method_t bcm_pwm_methods[] = { > /* Device interface */ > DEVMETHOD(device_probe, bcm_pwm_probe), > DEVMETHOD(device_attach, bcm_pwm_attach), > DEVMETHOD(device_detach, bcm_pwm_detach), > - > - /* ofw_bus interface */ > DEVMETHOD(ofw_bus_get_node, bcm_pwm_get_node), > > DEVMETHOD_END > @@ -439,3 +386,4 @@ static driver_t bcm_pwm_driver = { > }; > > DRIVER_MODULE(bcm2835_pwm, simplebus, bcm_pwm_driver, bcm_pwm_devclass, 0, > 0); > +MODULE_DEPEND(bcm2835_pwm, bcm2835_clkman, 1, 1, 1); > > Modified: head/sys/dts/arm/bcm2836.dtsi > ============================================================================== > --- head/sys/dts/arm/bcm2836.dtsi Mon Jan 22 06:00:45 2018 > (r328256) > +++ head/sys/dts/arm/bcm2836.dtsi Mon Jan 22 07:10:30 2018 > (r328257) > @@ -389,6 +389,11 @@ > }; > }; > > + cprman { > + compatible = "broadcom,bcm2835-cprman"; > + reg = <0x101000 0x2000>; > + }; > + > rng { > compatible = "broadcom,bcm2835-rng", > "broadcom,bcm2708-rng"; > @@ -427,7 +432,7 @@ > > pwm0 { > compatible = "broadcom,bcm2835-pwm"; > - reg = <0x20c000 0x28>,<0x1010a0 8>; > + reg = <0x20c000 0x28>; > }; > > dma: dma { > > Modified: head/sys/modules/Makefile > ============================================================================== > --- head/sys/modules/Makefile Mon Jan 22 06:00:45 2018 (r328256) > +++ head/sys/modules/Makefile Mon Jan 22 07:10:30 2018 (r328257) > @@ -60,6 +60,7 @@ SUBDIR= \ > ${_autofs} \ > ${_auxio} \ > ${_bce} \ > + ${_bcm283x_clkman} \ > ${_bcm283x_pwm} \ > bfe \ > bge \ > @@ -808,6 +809,7 @@ _cloudabi64= cloudabi64 > .endif > > .if ${MACHINE_ARCH:Marmv[67]*} != "" || ${MACHINE_CPUARCH} == "aarch64" > +_bcm283x_clkman= bcm283x_clkman > _bcm283x_pwm= bcm283x_pwm > .endif > -- Emmanuel Vadot <m...@bidouilliste.com> <m...@freebsd.org> _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"