Date: Mon, 22 Jan 2018 07:10:30 +0000 (UTC) From: Poul-Henning Kamp <phk@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r328257 - in head/sys: arm/broadcom/bcm2835 dts/arm modules Message-ID: <201801220710.w0M7AUm9091853@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@peach.ne.jp> + * 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); + } + + 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@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201801220710.w0M7AUm9091853>