svn commit: r328257 - in head/sys: arm/broadcom/bcm2835 dts/arm modules
Emmanuel Vadot
manu at bidouilliste.com
Mon Jan 22 08:46:40 UTC 2018
On Mon, 22 Jan 2018 07:10:30 +0000 (UTC)
Poul-Henning Kamp <phk at 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 <aoyama at 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 <phk at 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 <manu at bidouilliste.com> <manu at freebsd.org>
More information about the svn-src-head
mailing list