cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gpio-raspberrypi-exp.c (6395B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *  Raspberry Pi 3 expander GPIO driver
      4 *
      5 *  Uses the firmware mailbox service to communicate with the
      6 *  GPIO expander on the VPU.
      7 *
      8 *  Copyright (C) 2017 Raspberry Pi Trading Ltd.
      9 */
     10
     11#include <linux/err.h>
     12#include <linux/gpio/driver.h>
     13#include <linux/module.h>
     14#include <linux/platform_device.h>
     15#include <soc/bcm2835/raspberrypi-firmware.h>
     16
     17#define MODULE_NAME "raspberrypi-exp-gpio"
     18#define NUM_GPIO 8
     19
     20#define RPI_EXP_GPIO_BASE	128
     21
     22#define RPI_EXP_GPIO_DIR_IN	0
     23#define RPI_EXP_GPIO_DIR_OUT	1
     24
     25struct rpi_exp_gpio {
     26	struct gpio_chip gc;
     27	struct rpi_firmware *fw;
     28};
     29
     30/* VC4 firmware mailbox interface data structures */
     31
     32struct gpio_set_config {
     33	u32 gpio;
     34	u32 direction;
     35	u32 polarity;
     36	u32 term_en;
     37	u32 term_pull_up;
     38	u32 state;
     39};
     40
     41struct gpio_get_config {
     42	u32 gpio;
     43	u32 direction;
     44	u32 polarity;
     45	u32 term_en;
     46	u32 term_pull_up;
     47};
     48
     49struct gpio_get_set_state {
     50	u32 gpio;
     51	u32 state;
     52};
     53
     54static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off)
     55{
     56	struct rpi_exp_gpio *gpio;
     57	struct gpio_get_config get;
     58	int ret;
     59
     60	gpio = gpiochip_get_data(gc);
     61
     62	get.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
     63
     64	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
     65				    &get, sizeof(get));
     66	if (ret || get.gpio != 0) {
     67		dev_err(gc->parent, "Failed to get GPIO %u config (%d %x)\n",
     68			off, ret, get.gpio);
     69		return ret ? ret : -EIO;
     70	}
     71	return get.polarity;
     72}
     73
     74static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off)
     75{
     76	struct rpi_exp_gpio *gpio;
     77	struct gpio_set_config set_in;
     78	int ret;
     79
     80	gpio = gpiochip_get_data(gc);
     81
     82	set_in.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
     83	set_in.direction = RPI_EXP_GPIO_DIR_IN;
     84	set_in.term_en = 0;		/* termination disabled */
     85	set_in.term_pull_up = 0;	/* n/a as termination disabled */
     86	set_in.state = 0;		/* n/a as configured as an input */
     87
     88	ret = rpi_exp_gpio_get_polarity(gc, off);
     89	if (ret < 0)
     90		return ret;
     91	set_in.polarity = ret;		/* Retain existing setting */
     92
     93	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
     94				    &set_in, sizeof(set_in));
     95	if (ret || set_in.gpio != 0) {
     96		dev_err(gc->parent, "Failed to set GPIO %u to input (%d %x)\n",
     97			off, ret, set_in.gpio);
     98		return ret ? ret : -EIO;
     99	}
    100	return 0;
    101}
    102
    103static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val)
    104{
    105	struct rpi_exp_gpio *gpio;
    106	struct gpio_set_config set_out;
    107	int ret;
    108
    109	gpio = gpiochip_get_data(gc);
    110
    111	set_out.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
    112	set_out.direction = RPI_EXP_GPIO_DIR_OUT;
    113	set_out.term_en = 0;		/* n/a as an output */
    114	set_out.term_pull_up = 0;	/* n/a as termination disabled */
    115	set_out.state = val;		/* Output state */
    116
    117	ret = rpi_exp_gpio_get_polarity(gc, off);
    118	if (ret < 0)
    119		return ret;
    120	set_out.polarity = ret;		/* Retain existing setting */
    121
    122	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
    123				    &set_out, sizeof(set_out));
    124	if (ret || set_out.gpio != 0) {
    125		dev_err(gc->parent, "Failed to set GPIO %u to output (%d %x)\n",
    126			off, ret, set_out.gpio);
    127		return ret ? ret : -EIO;
    128	}
    129	return 0;
    130}
    131
    132static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
    133{
    134	struct rpi_exp_gpio *gpio;
    135	struct gpio_get_config get;
    136	int ret;
    137
    138	gpio = gpiochip_get_data(gc);
    139
    140	get.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
    141
    142	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
    143				    &get, sizeof(get));
    144	if (ret || get.gpio != 0) {
    145		dev_err(gc->parent,
    146			"Failed to get GPIO %u config (%d %x)\n", off, ret,
    147			get.gpio);
    148		return ret ? ret : -EIO;
    149	}
    150	if (get.direction)
    151		return GPIO_LINE_DIRECTION_OUT;
    152
    153	return GPIO_LINE_DIRECTION_IN;
    154}
    155
    156static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)
    157{
    158	struct rpi_exp_gpio *gpio;
    159	struct gpio_get_set_state get;
    160	int ret;
    161
    162	gpio = gpiochip_get_data(gc);
    163
    164	get.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
    165	get.state = 0;		/* storage for returned value */
    166
    167	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_STATE,
    168					 &get, sizeof(get));
    169	if (ret || get.gpio != 0) {
    170		dev_err(gc->parent,
    171			"Failed to get GPIO %u state (%d %x)\n", off, ret,
    172			get.gpio);
    173		return ret ? ret : -EIO;
    174	}
    175	return !!get.state;
    176}
    177
    178static void rpi_exp_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
    179{
    180	struct rpi_exp_gpio *gpio;
    181	struct gpio_get_set_state set;
    182	int ret;
    183
    184	gpio = gpiochip_get_data(gc);
    185
    186	set.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
    187	set.state = val;	/* Output state */
    188
    189	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_STATE,
    190					 &set, sizeof(set));
    191	if (ret || set.gpio != 0)
    192		dev_err(gc->parent,
    193			"Failed to set GPIO %u state (%d %x)\n", off, ret,
    194			set.gpio);
    195}
    196
    197static int rpi_exp_gpio_probe(struct platform_device *pdev)
    198{
    199	struct device *dev = &pdev->dev;
    200	struct device_node *np = dev->of_node;
    201	struct device_node *fw_node;
    202	struct rpi_firmware *fw;
    203	struct rpi_exp_gpio *rpi_gpio;
    204
    205	fw_node = of_get_parent(np);
    206	if (!fw_node) {
    207		dev_err(dev, "Missing firmware node\n");
    208		return -ENOENT;
    209	}
    210
    211	fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
    212	of_node_put(fw_node);
    213	if (!fw)
    214		return -EPROBE_DEFER;
    215
    216	rpi_gpio = devm_kzalloc(dev, sizeof(*rpi_gpio), GFP_KERNEL);
    217	if (!rpi_gpio)
    218		return -ENOMEM;
    219
    220	rpi_gpio->fw = fw;
    221	rpi_gpio->gc.parent = dev;
    222	rpi_gpio->gc.label = MODULE_NAME;
    223	rpi_gpio->gc.owner = THIS_MODULE;
    224	rpi_gpio->gc.base = -1;
    225	rpi_gpio->gc.ngpio = NUM_GPIO;
    226
    227	rpi_gpio->gc.direction_input = rpi_exp_gpio_dir_in;
    228	rpi_gpio->gc.direction_output = rpi_exp_gpio_dir_out;
    229	rpi_gpio->gc.get_direction = rpi_exp_gpio_get_direction;
    230	rpi_gpio->gc.get = rpi_exp_gpio_get;
    231	rpi_gpio->gc.set = rpi_exp_gpio_set;
    232	rpi_gpio->gc.can_sleep = true;
    233
    234	return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio);
    235}
    236
    237static const struct of_device_id rpi_exp_gpio_ids[] = {
    238	{ .compatible = "raspberrypi,firmware-gpio" },
    239	{ }
    240};
    241MODULE_DEVICE_TABLE(of, rpi_exp_gpio_ids);
    242
    243static struct platform_driver rpi_exp_gpio_driver = {
    244	.driver	= {
    245		.name		= MODULE_NAME,
    246		.of_match_table	= of_match_ptr(rpi_exp_gpio_ids),
    247	},
    248	.probe	= rpi_exp_gpio_probe,
    249};
    250module_platform_driver(rpi_exp_gpio_driver);
    251
    252MODULE_LICENSE("GPL");
    253MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.org>");
    254MODULE_DESCRIPTION("Raspberry Pi 3 expander GPIO driver");
    255MODULE_ALIAS("platform:rpi-exp-gpio");