Module Name: src
Committed By: mlelstv
Date: Sat Nov 21 07:41:29 UTC 2015
Modified Files:
src/sys/arch/arm/broadcom: bcm2835_obio.c bcm2835reg.h files.bcm2835
Added Files:
src/sys/arch/arm/broadcom: bcm2835_cm.c bcm2835_cm.h bcm2835_pwm.c
bcm2835_pwm.h
Log Message:
Add drivers to access the clock manager and pulse width modulator.
To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/broadcom/bcm2835_cm.c \
src/sys/arch/arm/broadcom/bcm2835_cm.h \
src/sys/arch/arm/broadcom/bcm2835_pwm.c \
src/sys/arch/arm/broadcom/bcm2835_pwm.h
cvs rdiff -u -r1.25 -r1.26 src/sys/arch/arm/broadcom/bcm2835_obio.c \
src/sys/arch/arm/broadcom/files.bcm2835
cvs rdiff -u -r1.15 -r1.16 src/sys/arch/arm/broadcom/bcm2835reg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/broadcom/bcm2835_obio.c
diff -u src/sys/arch/arm/broadcom/bcm2835_obio.c:1.25 src/sys/arch/arm/broadcom/bcm2835_obio.c:1.26
--- src/sys/arch/arm/broadcom/bcm2835_obio.c:1.25 Sun Apr 12 17:32:39 2015
+++ src/sys/arch/arm/broadcom/bcm2835_obio.c Sat Nov 21 07:41:29 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835_obio.c,v 1.25 2015/04/12 17:32:39 skrll Exp $ */
+/* $NetBSD: bcm2835_obio.c,v 1.26 2015/11/21 07:41:29 mlelstv Exp $ */
/*-
* Copyright (c) 2012, 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_obio.c,v 1.25 2015/04/12 17:32:39 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_obio.c,v 1.26 2015/11/21 07:41:29 mlelstv Exp $");
#include "locators.h"
#include "obio.h"
@@ -194,6 +194,20 @@ static const struct ambadev_locators bcm
.ad_intr = -1,
},
{
+ /* Clock Manager */
+ .ad_name = "bcmcm",
+ .ad_addr = BCM2835_CM_BASE,
+ .ad_size = BCM2835_CM_SIZE,
+ .ad_intr = -1,
+ },
+ {
+ /* PWM Controller */
+ .ad_name = "bcmpwm",
+ .ad_addr = BCM2835_PWM_BASE,
+ .ad_size = BCM2835_PWM_SIZE,
+ .ad_intr = -1,
+ },
+ {
/* Terminator */
.ad_name = NULL,
}
Index: src/sys/arch/arm/broadcom/files.bcm2835
diff -u src/sys/arch/arm/broadcom/files.bcm2835:1.25 src/sys/arch/arm/broadcom/files.bcm2835:1.26
--- src/sys/arch/arm/broadcom/files.bcm2835:1.25 Fri Mar 13 22:48:41 2015
+++ src/sys/arch/arm/broadcom/files.bcm2835 Sat Nov 21 07:41:29 2015
@@ -1,4 +1,4 @@
-# $NetBSD: files.bcm2835,v 1.25 2015/03/13 22:48:41 jmcneill Exp $
+# $NetBSD: files.bcm2835,v 1.26 2015/11/21 07:41:29 mlelstv Exp $
#
# Configuration info for Broadcom BCM2835 ARM Peripherals
#
@@ -100,3 +100,14 @@ file arch/arm/broadcom/bcm2835_vcaudio.c
device bcmgpio: gpiobus
attach bcmgpio at obio
file arch/arm/broadcom/bcm2835_gpio.c
+
+# Clock Manager (BCM2835_CM_BASE)
+device bcmcm
+attach bcmcm at obio with bcmcm_amba
+file arch/arm/broadcom/bcm2835_cm.c bcmcm needs-flag
+
+# PWM Controller (BCM2835_PWM_BASE)
+device bcmpwm
+attach bcmpwm at obio with bcmpwm_amba
+file arch/arm/broadcom/bcm2835_pwm.c bcmpwm needs-flag
+
Index: src/sys/arch/arm/broadcom/bcm2835reg.h
diff -u src/sys/arch/arm/broadcom/bcm2835reg.h:1.15 src/sys/arch/arm/broadcom/bcm2835reg.h:1.16
--- src/sys/arch/arm/broadcom/bcm2835reg.h:1.15 Sun Apr 12 17:32:39 2015
+++ src/sys/arch/arm/broadcom/bcm2835reg.h Sat Nov 21 07:41:29 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835reg.h,v 1.15 2015/04/12 17:32:39 skrll Exp $ */
+/* $NetBSD: bcm2835reg.h,v 1.16 2015/11/21 07:41:29 mlelstv Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -54,12 +54,14 @@
#define BCM2835_DMA0_BASE (BCM2835_PERIPHERALS_BASE + 0x00007000)
#define BCM2835_ARM_BASE (BCM2835_PERIPHERALS_BASE + 0x0000B000)
#define BCM2835_PM_BASE (BCM2835_PERIPHERALS_BASE + 0x00100000)
+#define BCM2835_CM_BASE (BCM2835_PERIPHERALS_BASE + 0x00101000)
#define BCM2835_RNG_BASE (BCM2835_PERIPHERALS_BASE + 0x00104000)
#define BCM2835_GPIO_BASE (BCM2835_PERIPHERALS_BASE + 0x00200000)
#define BCM2835_UART0_BASE (BCM2835_PERIPHERALS_BASE + 0x00201000)
#define BCM2835_PCM_BASE (BCM2835_PERIPHERALS_BASE + 0x00203000)
#define BCM2835_SPI0_BASE (BCM2835_PERIPHERALS_BASE + 0x00204000)
#define BCM2835_BSC0_BASE (BCM2835_PERIPHERALS_BASE + 0x00205000)
+#define BCM2835_PWM_BASE (BCM2835_PERIPHERALS_BASE + 0x0020C000)
#define BCM2835_BSCSPISLV_BASE (BCM2835_PERIPHERALS_BASE + 0x00214000)
#define BCM2835_AUX_BASE (BCM2835_PERIPHERALS_BASE + 0x00215000)
#define BCM2835_EMMC_BASE (BCM2835_PERIPHERALS_BASE + 0x00300000)
@@ -72,12 +74,14 @@
#define BCM2835_DMA0_SIZE 0x1000
#define BCM2835_ARM_SIZE 0x1000
#define BCM2835_PM_SIZE 0x1000
+#define BCM2835_CM_SIZE 0xa8
#define BCM2835_RNG_SIZE 0x1000
#define BCM2835_GPIO_SIZE 0x1000
#define BCM2835_UART0_SIZE 0x90
#define BCM2835_PCM_SIZE 0x1000
#define BCM2835_SPI0_SIZE 0x1000
#define BCM2835_BSC_SIZE 0x1000
+#define BCM2835_PWM_SIZE 0x28
#define BCM2835_AUX_SIZE 0x1000
#define BCM2835_EMMC_SIZE 0x1000
#define BCM2835_USB_SIZE 0x20000
Added files:
Index: src/sys/arch/arm/broadcom/bcm2835_cm.c
diff -u /dev/null src/sys/arch/arm/broadcom/bcm2835_cm.c:1.1
--- /dev/null Sat Nov 21 07:41:29 2015
+++ src/sys/arch/arm/broadcom/bcm2835_cm.c Sat Nov 21 07:41:29 2015
@@ -0,0 +1,239 @@
+/* $NetBSD: bcm2835_cm.c,v 1.1 2015/11/21 07:41:29 mlelstv Exp $ */
+
+/*-
+ * Copyright (c) 2015 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Michael van Elst
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Driver for BCM2835 Clock Manager
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_cm.c,v 1.1 2015/11/21 07:41:29 mlelstv Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#include <arm/broadcom/bcm2835reg.h>
+#include <arm/broadcom/bcm_amba.h>
+
+#include <arm/broadcom/bcm2835_cm.h>
+
+struct bcm2835cm_softc {
+ device_t sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+#define CM_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define CM_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
+
+static int bcmcm_match(device_t, cfdata_t, void *);
+static void bcmcm_attach(device_t, device_t, void *);
+static int bcmcm_wait(struct bcm2835cm_softc *, int, int);
+
+CFATTACH_DECL_NEW(bcmcm_amba, sizeof(struct bcm2835cm_softc),
+ bcmcm_match, bcmcm_attach, NULL, NULL);
+
+/* ARGSUSED */
+static int
+bcmcm_match(device_t parent, cfdata_t match, void *aux)
+{
+ struct amba_attach_args *aaa = aux;
+
+ if (strcmp(aaa->aaa_name, "bcmcm") != 0)
+ return 0;
+
+ if (aaa->aaa_addr != BCM2835_CM_BASE)
+ return 0;
+
+ return 1;
+}
+
+static void
+bcmcm_attach(device_t parent, device_t self, void *aux)
+{
+ struct bcm2835cm_softc *sc = device_private(self);
+ struct amba_attach_args *aaa = aux;
+
+ aprint_naive("\n");
+ aprint_normal(": CM\n");
+
+ sc->sc_dev = self;
+ sc->sc_iot = aaa->aaa_iot;
+
+ if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, BCM2835_CM_SIZE, 0,
+ &sc->sc_ioh)) {
+ aprint_error_dev(sc->sc_dev, "unable to map device\n");
+ goto fail0;
+ }
+
+ /* Success! */
+
+fail0: return;
+}
+
+static int
+bcmcm_wait(struct bcm2835cm_softc *sc, int ctlreg, int onoff)
+{
+ int i;
+ uint32_t r;
+
+ for (i=0; i<100; ++i) {
+ r = CM_READ(sc, ctlreg);
+ if (((r & CM_CTL_BUSY) != 0) == onoff)
+ break;
+ delay(10);
+ }
+ if (i >= 100) {
+ device_printf(sc->sc_dev, "busy (addr=%#x)\n", ctlreg);
+ return EIO;
+ }
+
+ return 0;
+}
+
+int
+bcm_cm_set(enum bcm_cm_clock clk, uint32_t ctl, uint32_t div)
+{
+ struct bcm2835cm_softc *sc;
+ device_t dev;
+ int ctlreg, divreg;
+ uint32_t r;
+
+ dev = device_find_by_driver_unit("bcmcm", 0);
+ if (dev == NULL)
+ return ENXIO;
+ sc = device_private(dev);
+
+ switch (clk) {
+ case BCM_CM_GP0:
+ ctlreg = CM_GP0CTL;
+ divreg = CM_GP0DIV;
+ break;
+ case BCM_CM_GP1:
+ ctlreg = CM_GP1CTL;
+ divreg = CM_GP1DIV;
+ break;
+ case BCM_CM_GP2:
+ ctlreg = CM_GP2CTL;
+ divreg = CM_GP2DIV;
+ break;
+ case BCM_CM_PCM:
+ ctlreg = CM_PCMCTL;
+ divreg = CM_PCMDIV;
+ break;
+ case BCM_CM_PWM:
+ ctlreg = CM_PWMCTL;
+ divreg = CM_PWMDIV;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ ctl &= ~CM_CTL_PASSWD;
+ ctl |= __SHIFTIN(CM_PASSWD, CM_CTL_PASSWD);
+ div &= ~CM_DIV_PASSWD;
+ div |= __SHIFTIN(CM_PASSWD, CM_DIV_PASSWD);
+
+ /* if clock is running, turn it off and wait for
+ * the cycle to end
+ */
+ r = CM_READ(sc, ctlreg);
+ if (r & CM_CTL_ENAB) {
+ r &= ~CM_CTL_PASSWD;
+ r |= __SHIFTIN(CM_PASSWD, CM_CTL_PASSWD);
+ r &= ~CM_CTL_ENAB;
+ CM_WRITE(sc, ctlreg, r);
+ }
+
+ bcmcm_wait(sc, ctlreg, 0);
+
+ /* configure new divider, mode, don't enable */
+ CM_WRITE(sc, divreg, div);
+ CM_WRITE(sc, ctlreg, ctl & ~CM_CTL_ENAB);
+
+ /* enable it */
+ if (ctl & CM_CTL_ENAB) {
+ CM_WRITE(sc, ctlreg, ctl);
+ return bcmcm_wait(sc, ctlreg, 1);
+ }
+
+ return 0;
+}
+
+int
+bcm_cm_get(enum bcm_cm_clock clk, uint32_t *ctlp, uint32_t *divp)
+{
+ struct bcm2835cm_softc *sc;
+ device_t dev;
+ int ctlreg, divreg;
+
+ dev = device_find_by_driver_unit("bcmcm", 0);
+ if (dev == NULL)
+ return ENXIO;
+ sc = device_private(dev);
+
+ switch (clk) {
+ case BCM_CM_GP0:
+ ctlreg = CM_GP0CTL;
+ divreg = CM_GP0DIV;
+ break;
+ case BCM_CM_GP1:
+ ctlreg = CM_GP1CTL;
+ divreg = CM_GP1DIV;
+ break;
+ case BCM_CM_GP2:
+ ctlreg = CM_GP2CTL;
+ divreg = CM_GP2DIV;
+ break;
+ case BCM_CM_PCM:
+ ctlreg = CM_PCMCTL;
+ divreg = CM_PCMDIV;
+ break;
+ case BCM_CM_PWM:
+ ctlreg = CM_PWMCTL;
+ divreg = CM_PWMDIV;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ if (ctlp != NULL)
+ *ctlp = CM_READ(sc, ctlreg);
+ if (divp != NULL)
+ *divp = CM_READ(sc, divreg);
+
+ return 0;
+}
Index: src/sys/arch/arm/broadcom/bcm2835_cm.h
diff -u /dev/null src/sys/arch/arm/broadcom/bcm2835_cm.h:1.1
--- /dev/null Sat Nov 21 07:41:29 2015
+++ src/sys/arch/arm/broadcom/bcm2835_cm.h Sat Nov 21 07:41:29 2015
@@ -0,0 +1,177 @@
+/* $NetBSD: */
+
+/*-
+ * Copyright (c) 2015 The NetBSD Foundation, Inc.
+ * 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 ``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 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.
+ */
+
+#ifndef BCM2835_CMREG_H
+#define BCM2835_CMREG_H
+
+#define CM_GP0CTL 0x70
+#define CM_CTL_PASSWD __BITS(24,31)
+#define CM_CTL_MASH __BITS(9,10)
+#define CM_CTL_FLIP __BIT(8)
+#define CM_CTL_BUSY __BIT(7)
+#define CM_CTL_KILL __BIT(5)
+#define CM_CTL_ENAB __BIT(4)
+#define CM_CTL_SRC __BIT(0,3)
+#define CM_GP0DIV 0x74
+#define CM_DIV_PASSWD __BITS(24,31)
+#define CM_DIV_DIVI __BITS(12,23)
+#define CM_DIV_DIVF __BITS(0,11)
+#define CM_GP1CTL 0x78
+#define CM_GP1DIV 0x7c
+#define CM_GP2CTL 0x80
+#define CM_GP2DIV 0x84
+
+#define CM_PCMCTL 0x98 /* PCM / I2S */
+#define CM_PCMDIV 0x9c
+#define CM_PWMCTL 0xa0
+#define CM_PWMDIV 0xa4
+
+#define CM_PASSWD 0x5a
+
+/* clock sources (frequencies for RPI) */
+#define CM_CTL_SRC_GND 0
+#define CM_CTL_SRC_OSCILLATOR 1 /* 19.2MHz */
+#define CM_CTL_SRC_TESTDEBUG0 2
+#define CM_CTL_SRC_TESTDEBUG1 3
+#define CM_CTL_SRC_PLLA 4
+#define CM_CTL_SRC_PLLC 5 /* 1000MHz (changes with overclock) */
+#define CM_CTL_SRC_PLLD 6 /* 500MHz core clock */
+#define CM_CTL_SRC_HDMIAUX 7 /* 216MHz HDMI auxiliary */
+
+#if 0
+#define CM_GNRICCTL 0x00
+#define CM_GNRICDIV 0x04
+#define CM_VPUCTL 0x08
+#define CM_VPUDIV 0x0c
+#define CM_SYSCTL 0x10
+#define CM_SYSDIV 0x14
+#define CM_PERIACTL 0x18
+#define CM_PERIADIV 0x1c
+#define CM_PERIICTL 0x20
+#define CM_PERIIDIV 0x24
+#define CM_H264CTL 0x28
+#define CM_H264DIV 0x2c
+#define CM_ISPCTL 0x30
+#define CM_ISPDIV 0x34
+#define CM_V3DCTL 0x38
+#define CM_V3DDIV 0x3c
+#define CM_CAM0CTL 0x40
+#define CM_CAM0DIV 0x44
+#define CM_CAM1CTL 0x48
+#define CM_CAM1DIV 0x4c
+#define CM_CCP2CTL 0x50
+#define CM_CCP2DIV 0x54
+#define CM_DSIOECTL 0x58
+#define CM_DSIOEDIV 0x5c
+#define CM_DSIOPCTL 0x60
+#define CM_DSIOPDIV 0x64
+#define CM_DPICTL 0x68
+#define CM_DPIDIV 0x6c
+
+#define CM_HSMCTL 0x88
+#define CM_HSMDIV 0x8c
+#define CM_HSMCTL 0x90
+#define CM_HSMDIV 0x94
+
+#define CM_SLIMCTL 0xa8
+#define CM_SLIMDIV 0xac
+#define CM_SMICTL 0xb0
+#define CM_SMIDIV 0xb4
+
+#define CM_TCNTCTL 0xc0
+#define CM_TCNTDIV 0xc4
+#define CM_TECCTL 0xc8
+#define CM_TECDIV 0xcc
+#define CM_TD0CTL 0xd0
+#define CM_TD0DIV 0xd4
+#define CM_TD1CTL 0xd8
+#define CM_TD1DIV 0xdc
+#define CM_TSENSCTL 0xe0
+#define CM_TSENSDIV 0xe4
+#define CM_TIMERCTL 0xe8
+#define CM_TIMERDIV 0xec
+#define CM_UARTCTL 0xf0
+#define CM_UARTDIV 0xf4
+#define CM_VECCTL 0xf8
+#define CM_VECDIV 0xfc
+
+#define CM_DSI1ECTL 0x158
+#define CM_DSI1EDIV 0x15c
+#define CM_DSI1PCTL 0x160
+#define CM_DSI1PDIV 0x164
+#define CM_DFTCTL 0x168
+#define CM_DFTDIV 0x16c
+
+#define CM_PULSECTL 0x190
+#define CM_PULSEDIV 0x194
+
+#define CM_SDCCTL 0x1ab
+#define CM_SDCDIV 0x1ac
+#define CM_ARMCTL 0x1b0
+#define CM_ARMDIV 0x1b4
+#define CM_AVE0CTL 0x1b8
+#define CM_AVE0DIV 0x1bc
+#define CM_EMMCCTL 0x1c0
+#define CM_EMMCDIV 0x1c4
+
+#define CM_OSCCOUNT 0x100
+#define CM_PLLA 0x104
+#define CM_PLLB 0x170
+#define CM_PLLC 0x108
+#define CM_PLLD 0x10c
+#define CM_PLLH 0x110
+#define CM_LOCK 0x114
+#define CM_EVENT 0x118
+#define CM_INTEN CM_EVENT
+#define CM_DSIOHSCK 0x120
+#define CM_CKSM 0x124
+#define CM_OSCFREQI 0x128
+#define CM_OSCFREQF 0x12c
+#define CM_PLLTCTL 0x130
+#define CM_PLLTCNT0 0x134
+#define CM_PLLTCNT1 0x138
+#define CM_PLLTCNT2 0x13c
+#define CM_PLLTCNT3 0x140
+#define CM_TDCLKEN 0x144
+#define CM_BURSTCTL 0x148
+#define CM_BURSTCNT 0x14C
+
+#endif
+
+enum bcm_cm_clock {
+ BCM_CM_GP0,
+ BCM_CM_GP1,
+ BCM_CM_GP2,
+ BCM_CM_PCM,
+ BCM_CM_PWM
+};
+
+int bcm_cm_set(enum bcm_cm_clock, uint32_t, uint32_t);
+int bcm_cm_get(enum bcm_cm_clock, uint32_t *, uint32_t *);
+
+#endif /* !BCM2835_CMREG_H */
Index: src/sys/arch/arm/broadcom/bcm2835_pwm.c
diff -u /dev/null src/sys/arch/arm/broadcom/bcm2835_pwm.c:1.1
--- /dev/null Sat Nov 21 07:41:29 2015
+++ src/sys/arch/arm/broadcom/bcm2835_pwm.c Sat Nov 21 07:41:29 2015
@@ -0,0 +1,341 @@
+/* $NetBSD: bcm2835_pwm.c,v 1.1 2015/11/21 07:41:29 mlelstv Exp $ */
+
+/*-
+ * Copyright (c) 2015 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Michael van Elst
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Driver for BCM2835 Pulse Width Modulator
+ *
+ * Each channel can be allocated and used individually, but
+ * for FIFO usage, both channels must to be requested.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_pwm.c,v 1.1 2015/11/21 07:41:29 mlelstv Exp $");
+
+#include "bcmdmac.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/atomic.h>
+#include <sys/intr.h>
+
+#include <arm/broadcom/bcm2835reg.h>
+#include <arm/broadcom/bcm_amba.h>
+
+#include <arm/broadcom/bcm2835_pwm.h>
+
+struct bcm_pwm_channel {
+ struct bcm2835pwm_softc *sc;
+ uint32_t ctlmask, stamask, gapomask;
+ int rng, dat;
+ bool inuse;
+ uint32_t ctlsave, rngsave, datsave;
+};
+
+struct bcm2835pwm_softc {
+ device_t sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ int sc_clockrate;
+ struct bcm_pwm_channel sc_channels[2];
+ kmutex_t sc_lock;
+
+ uint32_t sc_physaddr;
+};
+
+#define PWM_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define PWM_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
+
+static int bcmpwm_match(device_t, cfdata_t, void *);
+static void bcmpwm_attach(device_t, device_t, void *);
+static int bcmpwm_wait(struct bcm2835pwm_softc *);
+
+CFATTACH_DECL_NEW(bcmpwm_amba, sizeof(struct bcm2835pwm_softc),
+ bcmpwm_match, bcmpwm_attach, NULL, NULL);
+
+/* ARGSUSED */
+static int
+bcmpwm_match(device_t parent, cfdata_t match, void *aux)
+{
+ struct amba_attach_args *aaa = aux;
+
+ if (strcmp(aaa->aaa_name, "bcmpwm") != 0)
+ return 0;
+
+ if (aaa->aaa_addr != BCM2835_PWM_BASE)
+ return 0;
+
+ return 1;
+}
+
+static void
+bcmpwm_attach(device_t parent, device_t self, void *aux)
+{
+ struct bcm2835pwm_softc *sc = device_private(self);
+ struct amba_attach_args *aaa = aux;
+ const prop_dictionary_t cfg = device_properties(self);
+
+ aprint_naive("\n");
+ aprint_normal(": PWM\n");
+
+ sc->sc_dev = self;
+ sc->sc_iot = aaa->aaa_iot;
+ sc->sc_physaddr = aaa->aaa_addr;
+
+ if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, BCM2835_PWM_SIZE, 0,
+ &sc->sc_ioh)) {
+ aprint_error_dev(sc->sc_dev, "unable to map device\n");
+ goto fail0;
+ }
+
+ prop_dictionary_get_uint32(cfg, "pwmclockrate", &sc->sc_clockrate);
+
+ sc->sc_channels[0].sc = sc;
+ sc->sc_channels[0].ctlmask = PWM_CTL_MSEN1 | PWM_CTL_USEF1 |
+ PWM_CTL_POLA1 | PWM_CTL_SBIT1 |
+ PWM_CTL_RPTL1 | PWM_CTL_MODE1 |
+ PWM_CTL_PWEN1;
+ sc->sc_channels[0].stamask = PWM_STA_STA1;
+ sc->sc_channels[0].gapomask = PWM_STA_GAPO1;
+ sc->sc_channels[0].rng = PWM_RNG1;
+ sc->sc_channels[0].dat = PWM_DAT1;
+
+ sc->sc_channels[1].sc = sc;
+ sc->sc_channels[1].ctlmask = PWM_CTL_MSEN2 | PWM_CTL_USEF2 |
+ PWM_CTL_POLA2 | PWM_CTL_SBIT2 |
+ PWM_CTL_RPTL2 | PWM_CTL_MODE2 |
+ PWM_CTL_PWEN2;
+ sc->sc_channels[1].stamask = PWM_STA_STA2;
+ sc->sc_channels[1].gapomask = PWM_STA_GAPO2;
+ sc->sc_channels[1].rng = PWM_RNG2;
+ sc->sc_channels[1].dat = PWM_DAT2;
+
+ /* The PWM hardware can be used by vcaudio if the
+ * analog output is selected
+ */
+ sc->sc_channels[0].inuse = false;
+ sc->sc_channels[1].inuse = false;
+
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+
+ /* Success! */
+
+fail0: return;
+}
+
+struct bcm_pwm_channel *
+bcm_pwm_alloc(int num)
+{
+ struct bcm2835pwm_softc *sc;
+ device_t dev;
+ struct bcm_pwm_channel *pwm;
+
+ dev = device_find_by_driver_unit("bcmpwm", 0);
+ if (dev == NULL)
+ return NULL;
+ sc = device_private(dev);
+
+ if (num < 0 || num >= __arraycount(sc->sc_channels))
+ return NULL;
+
+ pwm = &sc->sc_channels[num];
+
+ mutex_enter(&sc->sc_lock);
+ if (pwm->inuse)
+ pwm = NULL;
+ else
+ pwm->inuse = true;
+ mutex_exit(&sc->sc_lock);
+
+ if (pwm) {
+ pwm->datsave = PWM_READ(pwm->sc, pwm->dat);
+ pwm->ctlsave = PWM_READ(pwm->sc, PWM_CTL);
+ pwm->rngsave = PWM_READ(pwm->sc, pwm->rng);
+ }
+
+ return pwm;
+}
+
+void
+bcm_pwm_free(struct bcm_pwm_channel *pwm)
+{
+ struct bcm2835pwm_softc *sc = pwm->sc;
+
+ KASSERT(pwm->inuse);
+
+ PWM_WRITE(pwm->sc, pwm->rng, pwm->rngsave);
+ PWM_WRITE(pwm->sc, PWM_CTL, pwm->ctlsave & ~PWM_CTL_WRITEZERO);
+ PWM_WRITE(pwm->sc, pwm->dat, pwm->datsave);
+
+ mutex_enter(&sc->sc_lock);
+ pwm->inuse = false;
+ mutex_exit(&sc->sc_lock);
+}
+
+void
+bcm_pwm_control(struct bcm_pwm_channel *pwm, uint32_t ctl, uint32_t rng)
+{
+ struct bcm2835pwm_softc *sc = pwm->sc;
+ uint32_t w;
+
+ KASSERT(pwm->inuse);
+
+ /* set control bits like for channel 0
+ * there are generic bit definitions that the caller can use.
+ */
+ w = PWM_READ(pwm->sc, PWM_CTL);
+ ctl = (w & ~pwm->ctlmask) | __SHIFTIN(ctl, pwm->ctlmask);
+
+ /* when FIFO usage gets enabled but wasn't clear the FIFO */
+ if ((w & (PWM_CTL_USEF1|PWM_CTL_USEF2)) == 0 &&
+ (ctl & (PWM_CTL_USEF1|PWM_CTL_USEF2)) != 0)
+ ctl |= PWM_CTL_CLRF1;
+
+ PWM_WRITE(sc, pwm->rng, rng);
+ PWM_WRITE(sc, PWM_CTL, ctl & ~PWM_CTL_WRITEZERO);
+}
+
+uint32_t
+bcm_pwm_status(struct bcm_pwm_channel *pwm)
+{
+ uint32_t w;
+ uint32_t common = PWM_STA_BERR | PWM_STA_RERR1 |
+ PWM_STA_WERR1 | PWM_STA_EMPT1 | PWM_STA_FULL1;
+
+ /* return status bits like for channel 0
+ * there are generic bit definitions that the caller can use.
+ *
+ * The BERR bit is returned for both channels.
+ */
+ w = PWM_READ(pwm->sc, PWM_STA);
+ PWM_WRITE(pwm->sc, PWM_STA, w &
+ (pwm->stamask | pwm->gapomask | common));
+
+ w = __SHIFTIN(__SHIFTOUT(w, pwm->stamask), PWM_STA_STA)
+ | __SHIFTIN(__SHIFTOUT(w, pwm->gapomask), PWM_STA_GAPO)
+ | (w & common);
+
+ return w;
+}
+
+static int
+bcmpwm_wait(struct bcm2835pwm_softc *sc)
+{
+ int i;
+ uint32_t s;
+
+ for (i=0; i<1000; ++i) {
+ s = PWM_READ(sc, PWM_STA);
+ if ((s & PWM_STA_FULL1) == 0)
+ break;
+ delay(1);
+ }
+ if (i >= 1000)
+ return -1;
+
+ return 0;
+}
+
+int
+bcm_pwm_write(struct bcm_pwm_channel *pwm, uint32_t *data1, uint32_t *data2,
+ int len)
+{
+ struct bcm2835pwm_softc *sc = pwm->sc;
+ int n;
+ uint32_t r;
+ bool even = false;
+
+ KASSERT(pwm->inuse);
+
+ n = len;
+ while (n > 0) {
+ if (bcmpwm_wait(sc))
+ break;
+ r = even ? *data2++ : *data1++;
+ PWM_WRITE(sc, PWM_FIFO, r);
+ if (data2 != NULL)
+ even = !even;
+ --n;
+ }
+
+ return len - n;
+}
+
+void
+bcm_pwm_set(struct bcm_pwm_channel *pwm, uint32_t w)
+{
+ struct bcm2835pwm_softc *sc = pwm->sc;
+
+ PWM_WRITE(sc, pwm->dat, w);
+}
+
+int
+bcm_pwm_flush(struct bcm_pwm_channel *pwm)
+{
+ struct bcm2835pwm_softc *sc = pwm->sc;
+
+ return bcmpwm_wait(sc) ? EIO : 0;
+}
+
+void
+bcm_pwm_dma_enable(struct bcm_pwm_channel *pwm, bool enable)
+{
+ struct bcm2835pwm_softc *sc = pwm->sc;
+ uint32_t w;
+
+#if 0
+ w = PWM_READ(sc, PWM_DMAC);
+ if (enable)
+ w |= PWM_DMAC_ENAB;
+ else
+ w &= ~PWM_DMAC_ENAB;
+#else
+ w = (enable ? PWM_DMAC_ENAB : 0)
+ | __SHIFTIN(7, PWM_DMAC_PANIC)
+ | __SHIFTIN(7, PWM_DMAC_DREQ);
+#endif
+ PWM_WRITE(sc, PWM_DMAC, w & ~PWM_DMAC_WRITEZERO);
+}
+
+uint32_t
+bcm_pwm_dma_address(struct bcm_pwm_channel *pwm)
+{
+ struct bcm2835pwm_softc *sc = pwm->sc;
+
+ return BCM2835_PERIPHERALS_TO_BUS(sc->sc_physaddr + PWM_FIFO);
+}
+
Index: src/sys/arch/arm/broadcom/bcm2835_pwm.h
diff -u /dev/null src/sys/arch/arm/broadcom/bcm2835_pwm.h:1.1
--- /dev/null Sat Nov 21 07:41:29 2015
+++ src/sys/arch/arm/broadcom/bcm2835_pwm.h Sat Nov 21 07:41:29 2015
@@ -0,0 +1,101 @@
+/* $NetBSD: */
+
+/*-
+ * Copyright (c) 2015 The NetBSD Foundation, Inc.
+ * 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 ``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 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.
+ */
+
+#ifndef BCM2835_PWMREG_H
+#define BCM2835_PWMREG_H
+
+#define PWM_CTL 0x00
+#define PWM_CTL_MSEN2 __BIT(15)
+#define PWM_CTL_USEF2 __BIT(13)
+#define PWM_CTL_POLA2 __BIT(12)
+#define PWM_CTL_SBIT2 __BIT(11)
+#define PWM_CTL_RPTL2 __BIT(10)
+#define PWM_CTL_MODE2 __BIT(9)
+#define PWM_CTL_PWEN2 __BIT(8)
+#define PWM_CTL_MSEN1 __BIT(7)
+#define PWM_CTL_CLRF1 __BIT(6)
+#define PWM_CTL_USEF1 __BIT(5)
+#define PWM_CTL_POLA1 __BIT(4)
+#define PWM_CTL_SBIT1 __BIT(3)
+#define PWM_CTL_RPTL1 __BIT(2)
+#define PWM_CTL_MODE1 __BIT(1)
+#define PWM_CTL_PWEN1 __BIT(0)
+#define PWM_CTL_WRITEZERO (__BITS(16,31)|__BIT(14))
+#define PWM_STA 0x04
+#define PWM_STA_STA4 __BIT(12)
+#define PWM_STA_STA3 __BIT(11)
+#define PWM_STA_STA2 __BIT(10)
+#define PWM_STA_STA1 __BIT(9)
+#define PWM_STA_BERR __BIT(8)
+#define PWM_STA_GAPO4 __BIT(7)
+#define PWM_STA_GAPO3 __BIT(6)
+#define PWM_STA_GAPO2 __BIT(5)
+#define PWM_STA_GAPO1 __BIT(4)
+#define PWM_STA_RERR1 __BIT(3)
+#define PWM_STA_WERR1 __BIT(2)
+#define PWM_STA_EMPT1 __BIT(1)
+#define PWM_STA_FULL1 __BIT(0)
+#define PWM_STA_WRITEZERO __BITS(13,31)
+#define PWM_DMAC 0x08
+#define PWM_DMAC_ENAB __BIT(31)
+#define PWM_DMAC_PANIC __BITS(8,15)
+#define PWM_DMAC_DREQ __BITS(0,7)
+#define PWM_DMAC_WRITEZERO __BITS(16,30)
+#define PWM_RNG1 0x10
+#define PWM_DAT1 0x14
+#define PWM_FIFO 0x18
+#define PWM_RNG2 0x20
+#define PWM_DAT2 0x24
+
+struct bcm_pwm_channel;
+
+struct bcm_pwm_channel *bcm_pwm_alloc(int num);
+void bcm_pwm_free(struct bcm_pwm_channel *);
+void bcm_pwm_control(struct bcm_pwm_channel *, uint32_t, uint32_t);
+uint32_t bcm_pwm_status(struct bcm_pwm_channel *);
+int bcm_pwm_write(struct bcm_pwm_channel *, uint32_t *, uint32_t *, int);
+void bcm_pwm_set(struct bcm_pwm_channel *, uint32_t);
+int bcm_pwm_flush(struct bcm_pwm_channel *);
+void bcm_pwm_dma_enable(struct bcm_pwm_channel *, bool);
+uint32_t bcm_pwm_dma_address(struct bcm_pwm_channel *);
+
+#define PWM_CTL_MSEN PWM_CTL_MSEN1
+#define PWM_CTL_USEF PWM_CTL_USEF1
+#define PWM_CTL_RPTL PWM_CTL_RPTL1
+#define PWM_CTL_MODE PWM_CTL_MODE1
+#define PWM_CTL_PWEN PWM_CTL_PWEN1
+
+#define PWM_STA_STA PWM_STA_STA1
+#define PWM_STA_GAPO PWM_STA_GAPO1
+#define PWM_STA_RERR PWM_STA_RERR1
+#define PWM_STA_WERR PWM_STA_WERR1
+#define PWM_STA_EMPT PWM_STA_EMPT1
+#define PWM_STA_FULL PWM_STA_FULL1
+
+
+#endif /* !BCM2835_PWMREG_H */