[rpi] Add fdt_pinctrl(4) support to Raspberry Pi GPIO driver
On Raspberry Pi platform GPIO controller also responsible for pins multiplexing. Pi code predates proper FDT support in FreeBSD so a lot of pinmux info is hardcoded. This patch: - Implements pinctl methods in bcm2835_gpio - Converts all devices with ad-hoc pinmux info to proper pin control mechanisms and adds pinmux info in FreeBSD's custom dts files. - Adds fdt_pinctrl option to RPI2 and RPI-B kernels - Adds SPI pinmux config to FreeBSD's customization of GNU DTS. Reviewed by: imp, manu Differential Revision: https://reviews.freebsd.org/D14104
This commit is contained in:
parent
1fa996add5
commit
91cc58af37
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=332262
@ -100,7 +100,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <dev/ofw/ofw_bus.h>
|
#include <dev/ofw/ofw_bus.h>
|
||||||
#include <dev/ofw/ofw_bus_subr.h>
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
#include <arm/broadcom/bcm2835/bcm2835_gpio.h>
|
|
||||||
#include <arm/broadcom/bcm2835/bcm2835_bscreg.h>
|
#include <arm/broadcom/bcm2835/bcm2835_bscreg.h>
|
||||||
#include <arm/broadcom/bcm2835/bcm2835_bscvar.h>
|
#include <arm/broadcom/bcm2835/bcm2835_bscvar.h>
|
||||||
|
|
||||||
@ -298,9 +297,7 @@ static int
|
|||||||
bcm_bsc_attach(device_t dev)
|
bcm_bsc_attach(device_t dev)
|
||||||
{
|
{
|
||||||
struct bcm_bsc_softc *sc;
|
struct bcm_bsc_softc *sc;
|
||||||
unsigned long start;
|
int rid;
|
||||||
device_t gpio;
|
|
||||||
int i, rid;
|
|
||||||
|
|
||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
sc->sc_dev = dev;
|
sc->sc_dev = dev;
|
||||||
@ -316,31 +313,6 @@ bcm_bsc_attach(device_t dev)
|
|||||||
sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
|
sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
|
||||||
sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
|
sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
|
||||||
|
|
||||||
/* Check the unit we are attaching by its base address. */
|
|
||||||
start = rman_get_start(sc->sc_mem_res);
|
|
||||||
for (i = 0; i < nitems(bcm_bsc_pins); i++) {
|
|
||||||
if (bcm_bsc_pins[i].start == (start & BCM_BSC_BASE_MASK))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i == nitems(bcm_bsc_pins)) {
|
|
||||||
device_printf(dev, "only bsc0 and bsc1 are supported\n");
|
|
||||||
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
|
|
||||||
return (ENXIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Configure the GPIO pins to ALT0 function to enable BSC control
|
|
||||||
* over the pins.
|
|
||||||
*/
|
|
||||||
gpio = devclass_get_device(devclass_find("gpio"), 0);
|
|
||||||
if (!gpio) {
|
|
||||||
device_printf(dev, "cannot find gpio0\n");
|
|
||||||
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
|
|
||||||
return (ENXIO);
|
|
||||||
}
|
|
||||||
bcm_gpio_set_alternate(gpio, bcm_bsc_pins[i].sda, BCM_GPIO_ALT0);
|
|
||||||
bcm_gpio_set_alternate(gpio, bcm_bsc_pins[i].scl, BCM_GPIO_ALT0);
|
|
||||||
|
|
||||||
rid = 0;
|
rid = 0;
|
||||||
sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
|
sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
|
||||||
RF_ACTIVE | RF_SHAREABLE);
|
RF_ACTIVE | RF_SHAREABLE);
|
||||||
|
@ -32,16 +32,6 @@
|
|||||||
#ifndef _BCM2835_BSCVAR_H
|
#ifndef _BCM2835_BSCVAR_H
|
||||||
#define _BCM2835_BSCVAR_H
|
#define _BCM2835_BSCVAR_H
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t sda;
|
|
||||||
uint32_t scl;
|
|
||||||
unsigned long start;
|
|
||||||
} bcm_bsc_pins[] = {
|
|
||||||
{ 0, 1, 0x205000 }, /* BSC0 GPIO pins and base address. */
|
|
||||||
{ 2, 3, 0x804000 } /* BSC1 GPIO pins and base address. */
|
|
||||||
};
|
|
||||||
#define BCM_BSC_BASE_MASK 0x00ffffff
|
|
||||||
|
|
||||||
struct iic_msg;
|
struct iic_msg;
|
||||||
|
|
||||||
struct bcm_bsc_softc {
|
struct bcm_bsc_softc {
|
||||||
|
@ -48,11 +48,10 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <machine/bus.h>
|
#include <machine/bus.h>
|
||||||
#include <machine/intr.h>
|
#include <machine/intr.h>
|
||||||
|
|
||||||
|
#include <dev/fdt/fdt_pinctrl.h>
|
||||||
#include <dev/gpio/gpiobusvar.h>
|
#include <dev/gpio/gpiobusvar.h>
|
||||||
#include <dev/ofw/ofw_bus.h>
|
#include <dev/ofw/ofw_bus.h>
|
||||||
|
|
||||||
#include <arm/broadcom/bcm2835/bcm2835_gpio.h>
|
|
||||||
|
|
||||||
#include "gpio_if.h"
|
#include "gpio_if.h"
|
||||||
|
|
||||||
#include "pic_if.h"
|
#include "pic_if.h"
|
||||||
@ -73,6 +72,19 @@ __FBSDID("$FreeBSD$");
|
|||||||
GPIO_INTR_LEVEL_HIGH | GPIO_INTR_EDGE_RISING | \
|
GPIO_INTR_LEVEL_HIGH | GPIO_INTR_EDGE_RISING | \
|
||||||
GPIO_INTR_EDGE_FALLING | GPIO_INTR_EDGE_BOTH)
|
GPIO_INTR_EDGE_FALLING | GPIO_INTR_EDGE_BOTH)
|
||||||
|
|
||||||
|
#define BCM2835_FSEL_GPIO_IN 0
|
||||||
|
#define BCM2835_FSEL_GPIO_OUT 1
|
||||||
|
#define BCM2835_FSEL_ALT5 2
|
||||||
|
#define BCM2835_FSEL_ALT4 3
|
||||||
|
#define BCM2835_FSEL_ALT0 4
|
||||||
|
#define BCM2835_FSEL_ALT1 5
|
||||||
|
#define BCM2835_FSEL_ALT2 6
|
||||||
|
#define BCM2835_FSEL_ALT3 7
|
||||||
|
|
||||||
|
#define BCM2835_PUD_OFF 0
|
||||||
|
#define BCM2835_PUD_DOWN 1
|
||||||
|
#define BCM2835_PUD_UP 2
|
||||||
|
|
||||||
static struct resource_spec bcm_gpio_res_spec[] = {
|
static struct resource_spec bcm_gpio_res_spec[] = {
|
||||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||||
{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* bank 0 interrupt */
|
{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* bank 0 interrupt */
|
||||||
@ -187,28 +199,28 @@ bcm_gpio_func_str(uint32_t nfunc, char *buf, int bufsize)
|
|||||||
{
|
{
|
||||||
|
|
||||||
switch (nfunc) {
|
switch (nfunc) {
|
||||||
case BCM_GPIO_INPUT:
|
case BCM2835_FSEL_GPIO_IN:
|
||||||
strncpy(buf, "input", bufsize);
|
strncpy(buf, "input", bufsize);
|
||||||
break;
|
break;
|
||||||
case BCM_GPIO_OUTPUT:
|
case BCM2835_FSEL_GPIO_OUT:
|
||||||
strncpy(buf, "output", bufsize);
|
strncpy(buf, "output", bufsize);
|
||||||
break;
|
break;
|
||||||
case BCM_GPIO_ALT0:
|
case BCM2835_FSEL_ALT0:
|
||||||
strncpy(buf, "alt0", bufsize);
|
strncpy(buf, "alt0", bufsize);
|
||||||
break;
|
break;
|
||||||
case BCM_GPIO_ALT1:
|
case BCM2835_FSEL_ALT1:
|
||||||
strncpy(buf, "alt1", bufsize);
|
strncpy(buf, "alt1", bufsize);
|
||||||
break;
|
break;
|
||||||
case BCM_GPIO_ALT2:
|
case BCM2835_FSEL_ALT2:
|
||||||
strncpy(buf, "alt2", bufsize);
|
strncpy(buf, "alt2", bufsize);
|
||||||
break;
|
break;
|
||||||
case BCM_GPIO_ALT3:
|
case BCM2835_FSEL_ALT3:
|
||||||
strncpy(buf, "alt3", bufsize);
|
strncpy(buf, "alt3", bufsize);
|
||||||
break;
|
break;
|
||||||
case BCM_GPIO_ALT4:
|
case BCM2835_FSEL_ALT4:
|
||||||
strncpy(buf, "alt4", bufsize);
|
strncpy(buf, "alt4", bufsize);
|
||||||
break;
|
break;
|
||||||
case BCM_GPIO_ALT5:
|
case BCM2835_FSEL_ALT5:
|
||||||
strncpy(buf, "alt5", bufsize);
|
strncpy(buf, "alt5", bufsize);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -221,21 +233,21 @@ bcm_gpio_str_func(char *func, uint32_t *nfunc)
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (strcasecmp(func, "input") == 0)
|
if (strcasecmp(func, "input") == 0)
|
||||||
*nfunc = BCM_GPIO_INPUT;
|
*nfunc = BCM2835_FSEL_GPIO_IN;
|
||||||
else if (strcasecmp(func, "output") == 0)
|
else if (strcasecmp(func, "output") == 0)
|
||||||
*nfunc = BCM_GPIO_OUTPUT;
|
*nfunc = BCM2835_FSEL_GPIO_OUT;
|
||||||
else if (strcasecmp(func, "alt0") == 0)
|
else if (strcasecmp(func, "alt0") == 0)
|
||||||
*nfunc = BCM_GPIO_ALT0;
|
*nfunc = BCM2835_FSEL_ALT0;
|
||||||
else if (strcasecmp(func, "alt1") == 0)
|
else if (strcasecmp(func, "alt1") == 0)
|
||||||
*nfunc = BCM_GPIO_ALT1;
|
*nfunc = BCM2835_FSEL_ALT1;
|
||||||
else if (strcasecmp(func, "alt2") == 0)
|
else if (strcasecmp(func, "alt2") == 0)
|
||||||
*nfunc = BCM_GPIO_ALT2;
|
*nfunc = BCM2835_FSEL_ALT2;
|
||||||
else if (strcasecmp(func, "alt3") == 0)
|
else if (strcasecmp(func, "alt3") == 0)
|
||||||
*nfunc = BCM_GPIO_ALT3;
|
*nfunc = BCM2835_FSEL_ALT3;
|
||||||
else if (strcasecmp(func, "alt4") == 0)
|
else if (strcasecmp(func, "alt4") == 0)
|
||||||
*nfunc = BCM_GPIO_ALT4;
|
*nfunc = BCM2835_FSEL_ALT4;
|
||||||
else if (strcasecmp(func, "alt5") == 0)
|
else if (strcasecmp(func, "alt5") == 0)
|
||||||
*nfunc = BCM_GPIO_ALT5;
|
*nfunc = BCM2835_FSEL_ALT5;
|
||||||
else
|
else
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
@ -247,9 +259,9 @@ bcm_gpio_func_flag(uint32_t nfunc)
|
|||||||
{
|
{
|
||||||
|
|
||||||
switch (nfunc) {
|
switch (nfunc) {
|
||||||
case BCM_GPIO_INPUT:
|
case BCM2835_FSEL_GPIO_IN:
|
||||||
return (GPIO_PIN_INPUT);
|
return (GPIO_PIN_INPUT);
|
||||||
case BCM_GPIO_OUTPUT:
|
case BCM2835_FSEL_GPIO_OUT:
|
||||||
return (GPIO_PIN_OUTPUT);
|
return (GPIO_PIN_OUTPUT);
|
||||||
}
|
}
|
||||||
return (0);
|
return (0);
|
||||||
@ -288,7 +300,7 @@ bcm_gpio_set_pud(struct bcm_gpio_softc *sc, uint32_t pin, uint32_t state)
|
|||||||
BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUDCLK(bank), 0);
|
BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUDCLK(bank), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
bcm_gpio_set_alternate(device_t dev, uint32_t pin, uint32_t nfunc)
|
bcm_gpio_set_alternate(device_t dev, uint32_t pin, uint32_t nfunc)
|
||||||
{
|
{
|
||||||
struct bcm_gpio_softc *sc;
|
struct bcm_gpio_softc *sc;
|
||||||
@ -297,10 +309,7 @@ bcm_gpio_set_alternate(device_t dev, uint32_t pin, uint32_t nfunc)
|
|||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
BCM_GPIO_LOCK(sc);
|
BCM_GPIO_LOCK(sc);
|
||||||
|
|
||||||
/* Disable pull-up or pull-down on pin. */
|
/* Set the pin function. */
|
||||||
bcm_gpio_set_pud(sc, pin, BCM_GPIO_NONE);
|
|
||||||
|
|
||||||
/* And now set the pin function. */
|
|
||||||
bcm_gpio_set_function(sc, pin, nfunc);
|
bcm_gpio_set_function(sc, pin, nfunc);
|
||||||
|
|
||||||
/* Update the pin flags. */
|
/* Update the pin flags. */
|
||||||
@ -329,11 +338,11 @@ bcm_gpio_pin_configure(struct bcm_gpio_softc *sc, struct gpio_pin *pin,
|
|||||||
if (flags & GPIO_PIN_OUTPUT) {
|
if (flags & GPIO_PIN_OUTPUT) {
|
||||||
pin->gp_flags |= GPIO_PIN_OUTPUT;
|
pin->gp_flags |= GPIO_PIN_OUTPUT;
|
||||||
bcm_gpio_set_function(sc, pin->gp_pin,
|
bcm_gpio_set_function(sc, pin->gp_pin,
|
||||||
BCM_GPIO_OUTPUT);
|
BCM2835_FSEL_GPIO_OUT);
|
||||||
} else {
|
} else {
|
||||||
pin->gp_flags |= GPIO_PIN_INPUT;
|
pin->gp_flags |= GPIO_PIN_INPUT;
|
||||||
bcm_gpio_set_function(sc, pin->gp_pin,
|
bcm_gpio_set_function(sc, pin->gp_pin,
|
||||||
BCM_GPIO_INPUT);
|
BCM2835_FSEL_GPIO_IN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -793,6 +802,9 @@ bcm_gpio_attach(device_t dev)
|
|||||||
if (sc->sc_busdev == NULL)
|
if (sc->sc_busdev == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
fdt_pinctrl_register(dev, "brcm,pins");
|
||||||
|
fdt_pinctrl_configure_tree(dev);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@ -1187,6 +1199,84 @@ bcm_gpio_get_node(device_t bus, device_t dev)
|
|||||||
return (ofw_bus_get_node(bus));
|
return (ofw_bus_get_node(bus));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bcm_gpio_configure_pins(device_t dev, phandle_t cfgxref)
|
||||||
|
{
|
||||||
|
phandle_t cfgnode;
|
||||||
|
int i, pintuples, pulltuples;
|
||||||
|
uint32_t pin;
|
||||||
|
uint32_t *pins;
|
||||||
|
uint32_t *pulls;
|
||||||
|
uint32_t function;
|
||||||
|
static struct bcm_gpio_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
cfgnode = OF_node_from_xref(cfgxref);
|
||||||
|
|
||||||
|
pins = NULL;
|
||||||
|
pintuples = OF_getencprop_alloc(cfgnode, "brcm,pins", sizeof(*pins),
|
||||||
|
(void **)&pins);
|
||||||
|
|
||||||
|
char name[32];
|
||||||
|
OF_getprop(cfgnode, "name", &name, sizeof(name));
|
||||||
|
|
||||||
|
if (pintuples < 0)
|
||||||
|
return (ENOENT);
|
||||||
|
|
||||||
|
if (pintuples == 0)
|
||||||
|
return (0); /* Empty property is not an error. */
|
||||||
|
|
||||||
|
if (OF_getencprop(cfgnode, "brcm,function", &function,
|
||||||
|
sizeof(function)) <= 0) {
|
||||||
|
OF_prop_free(pins);
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
pulls = NULL;
|
||||||
|
pulltuples = OF_getencprop_alloc(cfgnode, "brcm,pull", sizeof(*pulls),
|
||||||
|
(void **)&pulls);
|
||||||
|
|
||||||
|
if ((pulls != NULL) && (pulltuples != pintuples)) {
|
||||||
|
OF_prop_free(pins);
|
||||||
|
OF_prop_free(pulls);
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < pintuples; i++) {
|
||||||
|
pin = pins[i];
|
||||||
|
bcm_gpio_set_alternate(dev, pin, function);
|
||||||
|
if (bootverbose)
|
||||||
|
device_printf(dev, "set pin %d to func %d", pin, function);
|
||||||
|
if (pulls) {
|
||||||
|
if (bootverbose)
|
||||||
|
printf(", pull %d", pulls[i]);
|
||||||
|
switch (pulls[i]) {
|
||||||
|
/* Convert to gpio(4) flags */
|
||||||
|
case BCM2835_PUD_OFF:
|
||||||
|
bcm_gpio_pin_setflags(dev, pin, 0);
|
||||||
|
break;
|
||||||
|
case BCM2835_PUD_UP:
|
||||||
|
bcm_gpio_pin_setflags(dev, pin, GPIO_PIN_PULLUP);
|
||||||
|
break;
|
||||||
|
case BCM2835_PUD_DOWN:
|
||||||
|
bcm_gpio_pin_setflags(dev, pin, GPIO_PIN_PULLDOWN);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("%s: invalid pull value for pin %d: %d\n",
|
||||||
|
name, pin, pulls[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bootverbose)
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
OF_prop_free(pins);
|
||||||
|
if (pulls)
|
||||||
|
OF_prop_free(pulls);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static device_method_t bcm_gpio_methods[] = {
|
static device_method_t bcm_gpio_methods[] = {
|
||||||
/* Device interface */
|
/* Device interface */
|
||||||
DEVMETHOD(device_probe, bcm_gpio_probe),
|
DEVMETHOD(device_probe, bcm_gpio_probe),
|
||||||
@ -1217,6 +1307,9 @@ static device_method_t bcm_gpio_methods[] = {
|
|||||||
/* ofw_bus interface */
|
/* ofw_bus interface */
|
||||||
DEVMETHOD(ofw_bus_get_node, bcm_gpio_get_node),
|
DEVMETHOD(ofw_bus_get_node, bcm_gpio_get_node),
|
||||||
|
|
||||||
|
/* fdt_pinctrl interface */
|
||||||
|
DEVMETHOD(fdt_pinctrl_configure, bcm_gpio_configure_pins),
|
||||||
|
|
||||||
DEVMETHOD_END
|
DEVMETHOD_END
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1228,4 +1321,4 @@ static driver_t bcm_gpio_driver = {
|
|||||||
sizeof(struct bcm_gpio_softc),
|
sizeof(struct bcm_gpio_softc),
|
||||||
};
|
};
|
||||||
|
|
||||||
DRIVER_MODULE(bcm_gpio, simplebus, bcm_gpio_driver, bcm_gpio_devclass, 0, 0);
|
EARLY_DRIVER_MODULE(bcm_gpio, simplebus, bcm_gpio_driver, bcm_gpio_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
/*-
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
||||||
*
|
|
||||||
* Copyright (c) 2013 Oleksandr Tymoshenko <gonzo@bluezbox.com>
|
|
||||||
*
|
|
||||||
* 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_GPIO_H_
|
|
||||||
#define _BCM2835_GPIO_H_
|
|
||||||
|
|
||||||
enum bcm_gpio_fsel {
|
|
||||||
BCM_GPIO_INPUT,
|
|
||||||
BCM_GPIO_OUTPUT,
|
|
||||||
BCM_GPIO_ALT5,
|
|
||||||
BCM_GPIO_ALT4,
|
|
||||||
BCM_GPIO_ALT0,
|
|
||||||
BCM_GPIO_ALT1,
|
|
||||||
BCM_GPIO_ALT2,
|
|
||||||
BCM_GPIO_ALT3,
|
|
||||||
};
|
|
||||||
|
|
||||||
void bcm_gpio_set_alternate(device_t, uint32_t, uint32_t);
|
|
||||||
|
|
||||||
#endif /* _BCM2835_GPIO_H_ */
|
|
@ -452,4 +452,4 @@ static driver_t bcm_intc_driver = {
|
|||||||
static devclass_t bcm_intc_devclass;
|
static devclass_t bcm_intc_devclass;
|
||||||
|
|
||||||
EARLY_DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass,
|
EARLY_DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass,
|
||||||
0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
|
0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
|
||||||
|
@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <dev/ofw/ofw_bus.h>
|
#include <dev/ofw/ofw_bus.h>
|
||||||
#include <dev/ofw/ofw_bus_subr.h>
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
#include <arm/broadcom/bcm2835/bcm2835_gpio.h>
|
|
||||||
#include <arm/broadcom/bcm2835/bcm2835_clkman.h>
|
#include <arm/broadcom/bcm2835/bcm2835_clkman.h>
|
||||||
|
|
||||||
static struct ofw_compat_data compat_data[] = {
|
static struct ofw_compat_data compat_data[] = {
|
||||||
@ -93,7 +92,6 @@ static int
|
|||||||
bcm_pwm_reconf(struct bcm_pwm_softc *sc)
|
bcm_pwm_reconf(struct bcm_pwm_softc *sc)
|
||||||
{
|
{
|
||||||
uint32_t u;
|
uint32_t u;
|
||||||
device_t gpio;
|
|
||||||
|
|
||||||
/* Disable PWM */
|
/* Disable PWM */
|
||||||
W_CTL(sc, 0);
|
W_CTL(sc, 0);
|
||||||
@ -104,14 +102,6 @@ bcm_pwm_reconf(struct bcm_pwm_softc *sc)
|
|||||||
if (sc->mode == 0)
|
if (sc->mode == 0)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/* Ask GPIO0 to set ALT0 for pin 12 */
|
|
||||||
gpio = devclass_get_device(devclass_find("gpio"), 0);
|
|
||||||
if (!gpio) {
|
|
||||||
device_printf(sc->sc_dev, "cannot find gpio0\n");
|
|
||||||
return (ENXIO);
|
|
||||||
}
|
|
||||||
bcm_gpio_set_alternate(gpio, 12, BCM_GPIO_ALT0);
|
|
||||||
|
|
||||||
u = bcm2835_clkman_set_frequency(sc->clkman, BCM_PWM_CLKSRC, sc->freq);
|
u = bcm2835_clkman_set_frequency(sc->clkman, BCM_PWM_CLKSRC, sc->freq);
|
||||||
if (u == 0)
|
if (u == 0)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
|
@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <dev/spibus/spi.h>
|
#include <dev/spibus/spi.h>
|
||||||
#include <dev/spibus/spibusvar.h>
|
#include <dev/spibus/spibusvar.h>
|
||||||
|
|
||||||
#include <arm/broadcom/bcm2835/bcm2835_gpio.h>
|
|
||||||
#include <arm/broadcom/bcm2835/bcm2835_spireg.h>
|
#include <arm/broadcom/bcm2835/bcm2835_spireg.h>
|
||||||
#include <arm/broadcom/bcm2835/bcm2835_spivar.h>
|
#include <arm/broadcom/bcm2835/bcm2835_spivar.h>
|
||||||
|
|
||||||
@ -250,8 +249,7 @@ static int
|
|||||||
bcm_spi_attach(device_t dev)
|
bcm_spi_attach(device_t dev)
|
||||||
{
|
{
|
||||||
struct bcm_spi_softc *sc;
|
struct bcm_spi_softc *sc;
|
||||||
device_t gpio;
|
int rid;
|
||||||
int i, rid;
|
|
||||||
|
|
||||||
if (device_get_unit(dev) != 0) {
|
if (device_get_unit(dev) != 0) {
|
||||||
device_printf(dev, "only one SPI controller supported\n");
|
device_printf(dev, "only one SPI controller supported\n");
|
||||||
@ -261,15 +259,6 @@ bcm_spi_attach(device_t dev)
|
|||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
sc->sc_dev = dev;
|
sc->sc_dev = dev;
|
||||||
|
|
||||||
/* Configure the GPIO pins to ALT0 function to enable SPI the pins. */
|
|
||||||
gpio = devclass_get_device(devclass_find("gpio"), 0);
|
|
||||||
if (!gpio) {
|
|
||||||
device_printf(dev, "cannot find gpio0\n");
|
|
||||||
return (ENXIO);
|
|
||||||
}
|
|
||||||
for (i = 0; i < nitems(bcm_spi_pins); i++)
|
|
||||||
bcm_gpio_set_alternate(gpio, bcm_spi_pins[i], BCM_GPIO_ALT0);
|
|
||||||
|
|
||||||
rid = 0;
|
rid = 0;
|
||||||
sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
||||||
RF_ACTIVE);
|
RF_ACTIVE);
|
||||||
|
@ -32,18 +32,6 @@
|
|||||||
#ifndef _BCM2835_SPIVAR_H_
|
#ifndef _BCM2835_SPIVAR_H_
|
||||||
#define _BCM2835_SPIVAR_H_
|
#define _BCM2835_SPIVAR_H_
|
||||||
|
|
||||||
/*
|
|
||||||
* Only the available pins are listed here.
|
|
||||||
* i.e. CS2 isn't available.
|
|
||||||
*/
|
|
||||||
uint32_t bcm_spi_pins[] = {
|
|
||||||
7, /* CS1 */
|
|
||||||
8, /* CS0 */
|
|
||||||
9, /* MISO */
|
|
||||||
10, /* MOSI */
|
|
||||||
11 /* SCLK */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bcm_spi_softc {
|
struct bcm_spi_softc {
|
||||||
device_t sc_dev;
|
device_t sc_dev;
|
||||||
struct mtx sc_mtx;
|
struct mtx sc_mtx;
|
||||||
|
@ -736,4 +736,4 @@ static driver_t bcm_lintc_driver = {
|
|||||||
static devclass_t bcm_lintc_devclass;
|
static devclass_t bcm_lintc_devclass;
|
||||||
|
|
||||||
EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
|
EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
|
||||||
0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
|
0, 0, BUS_PASS_INTERRUPT);
|
||||||
|
@ -90,6 +90,8 @@ device bcm2835_spi
|
|||||||
device vchiq
|
device vchiq
|
||||||
device sound
|
device sound
|
||||||
|
|
||||||
|
device fdt_pinctrl
|
||||||
|
|
||||||
# Flattened Device Tree
|
# Flattened Device Tree
|
||||||
options FDT # Configure using FDT/DTB data
|
options FDT # Configure using FDT/DTB data
|
||||||
# Note: DTB is normally loaded and modified by RPi boot loader, then
|
# Note: DTB is normally loaded and modified by RPi boot loader, then
|
||||||
|
@ -93,6 +93,8 @@ device bcm2835_spi
|
|||||||
device vchiq
|
device vchiq
|
||||||
device sound
|
device sound
|
||||||
|
|
||||||
|
device fdt_pinctrl
|
||||||
|
|
||||||
# Flattened Device Tree
|
# Flattened Device Tree
|
||||||
options FDT # Configure using FDT/DTB data
|
options FDT # Configure using FDT/DTB data
|
||||||
# Note: DTB is normally loaded and modified by RPi boot loader, then
|
# Note: DTB is normally loaded and modified by RPi boot loader, then
|
||||||
|
@ -53,6 +53,10 @@
|
|||||||
|
|
||||||
spi@7e204000 {
|
spi@7e204000 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
|
||||||
};
|
};
|
||||||
|
|
||||||
gpio@7e200000 {
|
gpio@7e200000 {
|
||||||
@ -67,6 +71,16 @@
|
|||||||
broadcom,pins = <48>, <49>, <50>, <51>, <52>,
|
broadcom,pins = <48>, <49>, <50>, <51>, <52>,
|
||||||
<53>;
|
<53>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
spi0_pins: spi0_pins {
|
||||||
|
brcm,pins = <9 10 11>;
|
||||||
|
brcm,function = <4>; /* alt0 */
|
||||||
|
};
|
||||||
|
|
||||||
|
spi0_cs_pins: spi0_cs_pins {
|
||||||
|
brcm,pins = <8 7>;
|
||||||
|
brcm,function = <1>; /* output */
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
vchiq {
|
vchiq {
|
||||||
@ -89,4 +103,3 @@
|
|||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,6 +53,8 @@
|
|||||||
|
|
||||||
spi@7e204000 {
|
spi@7e204000 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
|
||||||
};
|
};
|
||||||
|
|
||||||
gpio@7e200000 {
|
gpio@7e200000 {
|
||||||
@ -67,6 +69,16 @@
|
|||||||
broadcom,pins = <48>, <49>, <50>, <51>, <52>,
|
broadcom,pins = <48>, <49>, <50>, <51>, <52>,
|
||||||
<53>;
|
<53>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
spi0_pins: spi0_pins {
|
||||||
|
brcm,pins = <9 10 11>;
|
||||||
|
brcm,function = <4>; /* alt0 */
|
||||||
|
};
|
||||||
|
|
||||||
|
spi0_cs_pins: spi0_cs_pins {
|
||||||
|
brcm,pins = <8 7>;
|
||||||
|
brcm,function = <1>; /* output */
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
vchiq {
|
vchiq {
|
||||||
|
Loading…
Reference in New Issue
Block a user