summaryrefslogtreecommitdiffstats
path: root/configs/platform-v7a/patches/barebox-2019.12.0/0012-gpio-Add-raspberrypi-exp-gpio-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'configs/platform-v7a/patches/barebox-2019.12.0/0012-gpio-Add-raspberrypi-exp-gpio-driver.patch')
-rw-r--r--configs/platform-v7a/patches/barebox-2019.12.0/0012-gpio-Add-raspberrypi-exp-gpio-driver.patch335
1 files changed, 335 insertions, 0 deletions
diff --git a/configs/platform-v7a/patches/barebox-2019.12.0/0012-gpio-Add-raspberrypi-exp-gpio-driver.patch b/configs/platform-v7a/patches/barebox-2019.12.0/0012-gpio-Add-raspberrypi-exp-gpio-driver.patch
new file mode 100644
index 0000000..dcfc4c2
--- /dev/null
+++ b/configs/platform-v7a/patches/barebox-2019.12.0/0012-gpio-Add-raspberrypi-exp-gpio-driver.patch
@@ -0,0 +1,335 @@
+From: Sascha Hauer <s.hauer@pengutronix.de>
+Date: Tue, 7 Jan 2020 10:55:11 +0100
+Subject: [PATCH] gpio: Add raspberrypi exp gpio driver
+
+Taken from the kernel adopted to barebox.
+
+Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+---
+ arch/arm/mach-bcm283x/include/mach/mbox.h | 4 +
+ drivers/gpio/Kconfig | 7 +
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/gpio-raspberrypi-exp.c | 272 ++++++++++++++++++++++++++++++
+ 4 files changed, 284 insertions(+)
+ create mode 100644 drivers/gpio/gpio-raspberrypi-exp.c
+
+diff --git a/arch/arm/mach-bcm283x/include/mach/mbox.h b/arch/arm/mach-bcm283x/include/mach/mbox.h
+index 6db961b8076b..f10f5bc14844 100644
+--- a/arch/arm/mach-bcm283x/include/mach/mbox.h
++++ b/arch/arm/mach-bcm283x/include/mach/mbox.h
+@@ -126,6 +126,10 @@ struct bcm2835_mbox_tag_hdr {
+ */
+
+ #define BCM2835_MBOX_TAG_GET_BOARD_REV 0x00010002
++#define BCM2835_MBOX_TAG_GET_GPIO_STATE 0x00030041
++#define BCM2835_MBOX_TAG_SET_GPIO_STATE 0x00038041
++#define BCM2835_MBOX_TAG_GET_GPIO_CONFIG 0x00030043
++#define BCM2835_MBOX_TAG_SET_GPIO_CONFIG 0x00038043
+
+ /*
+ * ids
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 0f924d135f0e..7e4fc90d3934 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -129,6 +129,13 @@ config GPIO_PL061
+ help
+ Say yes here to support the PrimeCell PL061 GPIO device
+
++config GPIO_RASPBERRYPI_EXP
++ bool "Raspberry Pi 3 GPIO Expander"
++ depends on ARCH_BCM283X
++ help
++ Turn on GPIO support for the expander on Raspberry Pi 3 boards, using
++ the firmware mailbox to communicate with VideoCore on BCM283x chips.
++
+ config GPIO_STMPE
+ depends on MFD_STMPE
+ bool "STMPE GPIO Expander"
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index bc5c500e4d27..77dcf58f640d 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -22,3 +22,4 @@ obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
+ obj-$(CONFIG_GPIO_DESIGNWARE) += gpio-dw.o
+ obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
+ obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
++obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
+diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c
+new file mode 100644
+index 000000000000..0713e3ca5fb6
+--- /dev/null
++++ b/drivers/gpio/gpio-raspberrypi-exp.c
+@@ -0,0 +1,272 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Raspberry Pi 3 expander GPIO driver
++ *
++ * Uses the firmware mailbox service to communicate with the
++ * GPIO expander on the VPU.
++ *
++ * Copyright (C) 2017 Raspberry Pi Trading Ltd.
++ */
++
++#include <common.h>
++#include <gpio.h>
++#include <init.h>
++#include <mach/mbox.h>
++
++#define NUM_GPIO 8
++
++#define RPI_EXP_GPIO_BASE 128
++
++#define RPI_EXP_GPIO_DIR_IN 0
++#define RPI_EXP_GPIO_DIR_OUT 1
++
++struct rpi_exp_gpio {
++ struct gpio_chip gc;
++ struct rpi_firmware *fw;
++};
++
++/* VC4 firmware mailbox interface data structures */
++struct gpio_set_config {
++ struct bcm2835_mbox_hdr hdr; /* buf_size, code */
++ struct bcm2835_mbox_tag_hdr tag_hdr; /* tag, val_buf_size, val_len */
++ union {
++ struct {
++ u32 gpio;
++ u32 direction;
++ u32 polarity;
++ u32 term_en;
++ u32 term_pull_up;
++ u32 state;
++ } req;
++ } body;
++ u32 end_tag;
++};
++
++struct gpio_get_config {
++ struct bcm2835_mbox_hdr hdr;
++ struct bcm2835_mbox_tag_hdr tag_hdr;
++ union {
++ struct {
++ u32 gpio;
++ u32 direction;
++ u32 polarity;
++ u32 term_en;
++ u32 term_pull_up;
++ } req;
++ } body;
++ u32 end_tag;
++};
++
++struct gpio_get_set_state {
++ struct bcm2835_mbox_hdr hdr;
++ struct bcm2835_mbox_tag_hdr tag_hdr;
++ union {
++ struct {
++ u32 gpio;
++ u32 state;
++ } req;
++ } body;
++ u32 end_tag;
++};
++
++static inline struct rpi_exp_gpio *to_rpi_gpio(struct gpio_chip *gc)
++{
++ return container_of(gc, struct rpi_exp_gpio, gc);
++}
++
++static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off)
++{
++ struct rpi_exp_gpio *gpio;
++ int ret;
++ BCM2835_MBOX_STACK_ALIGN(struct gpio_get_config, get);
++ BCM2835_MBOX_INIT_HDR(get);
++ BCM2835_MBOX_INIT_TAG(get, GET_GPIO_CONFIG);
++
++ gpio = to_rpi_gpio(gc);
++
++ get->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++
++ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &get->hdr);
++ if (ret || get->body.req.gpio != 0) {
++ dev_err(gc->dev, "Failed to get GPIO %u config (%d %x)\n",
++ off, ret, get->body.req.gpio);
++ return ret ? ret : -EIO;
++ }
++ return get->body.req.polarity;
++}
++
++static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off)
++{
++ struct rpi_exp_gpio *gpio;
++ int ret;
++ BCM2835_MBOX_STACK_ALIGN(struct gpio_set_config, set_in);
++ BCM2835_MBOX_INIT_HDR(set_in);
++ BCM2835_MBOX_INIT_TAG(set_in, SET_GPIO_CONFIG);
++
++ gpio = to_rpi_gpio(gc);
++
++ set_in->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++ set_in->body.req.direction = RPI_EXP_GPIO_DIR_IN;
++ set_in->body.req.term_en = 0; /* termination disabled */
++ set_in->body.req.term_pull_up = 0; /* n/a as termination disabled */
++ set_in->body.req.state = 0; /* n/a as configured as an input */
++
++ ret = rpi_exp_gpio_get_polarity(gc, off);
++ if (ret < 0)
++ return ret;
++
++ set_in->body.req.polarity = ret; /* Retain existing setting */
++
++ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &set_in->hdr);
++ if (ret || set_in->body.req.gpio != 0) {
++ dev_err(gc->dev, "Failed to set GPIO %u to input (%d %x)\n",
++ off, ret, set_in->body.req.gpio);
++ return ret ? ret : -EIO;
++ }
++
++ return 0;
++}
++
++static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val)
++{
++ struct rpi_exp_gpio *gpio;
++ int ret;
++ BCM2835_MBOX_STACK_ALIGN(struct gpio_set_config, set_out);
++ BCM2835_MBOX_INIT_HDR(set_out);
++ BCM2835_MBOX_INIT_TAG(set_out, SET_GPIO_CONFIG);
++
++ gpio = to_rpi_gpio(gc);
++
++ set_out->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++ set_out->body.req.direction = RPI_EXP_GPIO_DIR_OUT;
++ set_out->body.req.term_en = 0; /* n/a as an output */
++ set_out->body.req.term_pull_up = 0; /* n/a as termination disabled */
++ set_out->body.req.state = val; /* Output state */
++
++ ret = rpi_exp_gpio_get_polarity(gc, off);
++ if (ret < 0)
++ return ret;
++ set_out->body.req.polarity = ret; /* Retain existing setting */
++
++ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &set_out->hdr);
++ if (ret || set_out->body.req.gpio != 0) {
++ dev_err(gc->dev, "Failed to set GPIO %u to output (%d %x)\n",
++ off, ret, set_out->body.req.gpio);
++ return ret ? ret : -EIO;
++ }
++ return 0;
++}
++
++static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
++{
++ struct rpi_exp_gpio *gpio;
++ int ret;
++ BCM2835_MBOX_STACK_ALIGN(struct gpio_get_config, get);
++ BCM2835_MBOX_INIT_HDR(get);
++ BCM2835_MBOX_INIT_TAG(get, GET_GPIO_CONFIG);
++
++ gpio = to_rpi_gpio(gc);
++
++ get->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++
++ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &get->hdr);
++ if (ret || get->body.req.gpio != 0) {
++ dev_err(gc->dev,
++ "Failed to get GPIO %u config (%d %x)\n", off, ret,
++ get->body.req.gpio);
++ return ret ? ret : -EIO;
++ }
++ if (get->body.req.direction)
++ return GPIOF_DIR_OUT;
++
++ return GPIOF_DIR_IN;
++}
++
++static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)
++{
++ struct rpi_exp_gpio *gpio;
++ int ret;
++ BCM2835_MBOX_STACK_ALIGN(struct gpio_get_set_state, get);
++ BCM2835_MBOX_INIT_HDR(get);
++ BCM2835_MBOX_INIT_TAG(get, GET_GPIO_STATE);
++
++ gpio = to_rpi_gpio(gc);
++
++ get->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++ get->body.req.state = 0; /* storage for returned value */
++
++ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &get->hdr);
++ if (ret || get->body.req.gpio != 0) {
++ dev_err(gc->dev,
++ "Failed to get GPIO %u state (%d %x)\n", off, ret,
++ get->body.req.gpio);
++ return ret ? ret : -EIO;
++ }
++ return !!get->body.req.state;
++}
++
++static void rpi_exp_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
++{
++ struct rpi_exp_gpio *gpio;
++ int ret;
++ BCM2835_MBOX_STACK_ALIGN(struct gpio_get_set_state, set);
++ BCM2835_MBOX_INIT_HDR(set);
++ BCM2835_MBOX_INIT_TAG(set, SET_GPIO_STATE);
++
++ gpio = to_rpi_gpio(gc);
++
++ set->body.req.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
++ set->body.req.state = val; /* Output state */
++
++ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &set->hdr);
++ if (ret || set->body.req.gpio != 0)
++ dev_err(gc->dev,
++ "Failed to set GPIO %u state (%d %x)\n", off, ret,
++ set->body.req.gpio);
++}
++
++static struct gpio_ops rpi_exp_gpio_ops = {
++ .direction_input = rpi_exp_gpio_dir_in,
++ .direction_output = rpi_exp_gpio_dir_out,
++ .get_direction = rpi_exp_gpio_get_direction,
++ .get = rpi_exp_gpio_get,
++ .set = rpi_exp_gpio_set,
++};
++
++static int rpi_exp_gpio_probe(struct device_d *dev)
++{
++ struct rpi_exp_gpio *rpi_gpio;
++ int ret;
++
++ rpi_gpio = xzalloc(sizeof(*rpi_gpio));
++
++ rpi_gpio->gc.dev = dev;
++ rpi_gpio->gc.base = -1;
++ rpi_gpio->gc.ngpio = NUM_GPIO;
++ rpi_gpio->gc.ops = &rpi_exp_gpio_ops;
++
++ ret = gpiochip_add(&rpi_gpio->gc);
++ if (ret)
++ return ret;
++
++ dev_dbg(dev, "probed gpiochip with %d gpios, base %d\n",
++ rpi_gpio->gc.ngpio, rpi_gpio->gc.base);
++
++ return 0;
++}
++
++static __maybe_unused struct of_device_id rpi_exp_gpio_ids[] = {
++ {
++ .compatible = "raspberrypi,firmware-gpio",
++ }, {
++ /* sentinel */
++ },
++};
++
++static struct driver_d rpi_exp_gpio_driver = {
++ .name = "rpi-exp-gpio",
++ .probe = rpi_exp_gpio_probe,
++ .of_compatible = DRV_OF_COMPAT(rpi_exp_gpio_ids),
++};
++
++device_platform_driver(rpi_exp_gpio_driver);