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 */

Reply via email to