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-gpio-mm.c (9481B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * GPIO driver for the Diamond Systems GPIO-MM
      4 * Copyright (C) 2016 William Breathitt Gray
      5 *
      6 * This driver supports the following Diamond Systems devices: GPIO-MM and
      7 * GPIO-MM-12.
      8 */
      9#include <linux/bitmap.h>
     10#include <linux/bitops.h>
     11#include <linux/device.h>
     12#include <linux/errno.h>
     13#include <linux/gpio/driver.h>
     14#include <linux/io.h>
     15#include <linux/ioport.h>
     16#include <linux/isa.h>
     17#include <linux/kernel.h>
     18#include <linux/module.h>
     19#include <linux/moduleparam.h>
     20#include <linux/spinlock.h>
     21
     22#define GPIOMM_EXTENT 8
     23#define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
     24
     25static unsigned int base[MAX_NUM_GPIOMM];
     26static unsigned int num_gpiomm;
     27module_param_hw_array(base, uint, ioport, &num_gpiomm, 0);
     28MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
     29
     30/**
     31 * struct gpiomm_gpio - GPIO device private data structure
     32 * @chip:	instance of the gpio_chip
     33 * @io_state:	bit I/O state (whether bit is set to input or output)
     34 * @out_state:	output bits state
     35 * @control:	Control registers state
     36 * @lock:	synchronization lock to prevent I/O race conditions
     37 * @base:	base port address of the GPIO device
     38 */
     39struct gpiomm_gpio {
     40	struct gpio_chip chip;
     41	unsigned char io_state[6];
     42	unsigned char out_state[6];
     43	unsigned char control[2];
     44	spinlock_t lock;
     45	void __iomem *base;
     46};
     47
     48static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
     49	unsigned int offset)
     50{
     51	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
     52	const unsigned int port = offset / 8;
     53	const unsigned int mask = BIT(offset % 8);
     54
     55	if (gpiommgpio->io_state[port] & mask)
     56		return GPIO_LINE_DIRECTION_IN;
     57
     58	return GPIO_LINE_DIRECTION_OUT;
     59}
     60
     61static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
     62	unsigned int offset)
     63{
     64	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
     65	const unsigned int io_port = offset / 8;
     66	const unsigned int control_port = io_port / 3;
     67	unsigned long flags;
     68	unsigned int control;
     69
     70	spin_lock_irqsave(&gpiommgpio->lock, flags);
     71
     72	/* Check if configuring Port C */
     73	if (io_port == 2 || io_port == 5) {
     74		/* Port C can be configured by nibble */
     75		if (offset % 8 > 3) {
     76			gpiommgpio->io_state[io_port] |= 0xF0;
     77			gpiommgpio->control[control_port] |= BIT(3);
     78		} else {
     79			gpiommgpio->io_state[io_port] |= 0x0F;
     80			gpiommgpio->control[control_port] |= BIT(0);
     81		}
     82	} else {
     83		gpiommgpio->io_state[io_port] |= 0xFF;
     84		if (io_port == 0 || io_port == 3)
     85			gpiommgpio->control[control_port] |= BIT(4);
     86		else
     87			gpiommgpio->control[control_port] |= BIT(1);
     88	}
     89
     90	control = BIT(7) | gpiommgpio->control[control_port];
     91	iowrite8(control, gpiommgpio->base + 3 + control_port*4);
     92
     93	spin_unlock_irqrestore(&gpiommgpio->lock, flags);
     94
     95	return 0;
     96}
     97
     98static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
     99	unsigned int offset, int value)
    100{
    101	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
    102	const unsigned int io_port = offset / 8;
    103	const unsigned int control_port = io_port / 3;
    104	const unsigned int mask = BIT(offset % 8);
    105	const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
    106	unsigned long flags;
    107	unsigned int control;
    108
    109	spin_lock_irqsave(&gpiommgpio->lock, flags);
    110
    111	/* Check if configuring Port C */
    112	if (io_port == 2 || io_port == 5) {
    113		/* Port C can be configured by nibble */
    114		if (offset % 8 > 3) {
    115			gpiommgpio->io_state[io_port] &= 0x0F;
    116			gpiommgpio->control[control_port] &= ~BIT(3);
    117		} else {
    118			gpiommgpio->io_state[io_port] &= 0xF0;
    119			gpiommgpio->control[control_port] &= ~BIT(0);
    120		}
    121	} else {
    122		gpiommgpio->io_state[io_port] &= 0x00;
    123		if (io_port == 0 || io_port == 3)
    124			gpiommgpio->control[control_port] &= ~BIT(4);
    125		else
    126			gpiommgpio->control[control_port] &= ~BIT(1);
    127	}
    128
    129	if (value)
    130		gpiommgpio->out_state[io_port] |= mask;
    131	else
    132		gpiommgpio->out_state[io_port] &= ~mask;
    133
    134	control = BIT(7) | gpiommgpio->control[control_port];
    135	iowrite8(control, gpiommgpio->base + 3 + control_port*4);
    136
    137	iowrite8(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port);
    138
    139	spin_unlock_irqrestore(&gpiommgpio->lock, flags);
    140
    141	return 0;
    142}
    143
    144static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
    145{
    146	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
    147	const unsigned int port = offset / 8;
    148	const unsigned int mask = BIT(offset % 8);
    149	const unsigned int in_port = (port > 2) ? port + 1 : port;
    150	unsigned long flags;
    151	unsigned int port_state;
    152
    153	spin_lock_irqsave(&gpiommgpio->lock, flags);
    154
    155	/* ensure that GPIO is set for input */
    156	if (!(gpiommgpio->io_state[port] & mask)) {
    157		spin_unlock_irqrestore(&gpiommgpio->lock, flags);
    158		return -EINVAL;
    159	}
    160
    161	port_state = ioread8(gpiommgpio->base + in_port);
    162
    163	spin_unlock_irqrestore(&gpiommgpio->lock, flags);
    164
    165	return !!(port_state & mask);
    166}
    167
    168static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
    169
    170static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
    171	unsigned long *bits)
    172{
    173	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
    174	unsigned long offset;
    175	unsigned long gpio_mask;
    176	void __iomem *port_addr;
    177	unsigned long port_state;
    178
    179	/* clear bits array to a clean slate */
    180	bitmap_zero(bits, chip->ngpio);
    181
    182	for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
    183		port_addr = gpiommgpio->base + ports[offset / 8];
    184		port_state = ioread8(port_addr) & gpio_mask;
    185
    186		bitmap_set_value8(bits, port_state, offset);
    187	}
    188
    189	return 0;
    190}
    191
    192static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
    193	int value)
    194{
    195	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
    196	const unsigned int port = offset / 8;
    197	const unsigned int mask = BIT(offset % 8);
    198	const unsigned int out_port = (port > 2) ? port + 1 : port;
    199	unsigned long flags;
    200
    201	spin_lock_irqsave(&gpiommgpio->lock, flags);
    202
    203	if (value)
    204		gpiommgpio->out_state[port] |= mask;
    205	else
    206		gpiommgpio->out_state[port] &= ~mask;
    207
    208	iowrite8(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
    209
    210	spin_unlock_irqrestore(&gpiommgpio->lock, flags);
    211}
    212
    213static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
    214	unsigned long *mask, unsigned long *bits)
    215{
    216	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
    217	unsigned long offset;
    218	unsigned long gpio_mask;
    219	size_t index;
    220	void __iomem *port_addr;
    221	unsigned long bitmask;
    222	unsigned long flags;
    223
    224	for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
    225		index = offset / 8;
    226		port_addr = gpiommgpio->base + ports[index];
    227
    228		bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
    229
    230		spin_lock_irqsave(&gpiommgpio->lock, flags);
    231
    232		/* update output state data and set device gpio register */
    233		gpiommgpio->out_state[index] &= ~gpio_mask;
    234		gpiommgpio->out_state[index] |= bitmask;
    235		iowrite8(gpiommgpio->out_state[index], port_addr);
    236
    237		spin_unlock_irqrestore(&gpiommgpio->lock, flags);
    238	}
    239}
    240
    241#define GPIOMM_NGPIO 48
    242static const char *gpiomm_names[GPIOMM_NGPIO] = {
    243	"Port 1A0", "Port 1A1", "Port 1A2", "Port 1A3", "Port 1A4", "Port 1A5",
    244	"Port 1A6", "Port 1A7", "Port 1B0", "Port 1B1", "Port 1B2", "Port 1B3",
    245	"Port 1B4", "Port 1B5", "Port 1B6", "Port 1B7", "Port 1C0", "Port 1C1",
    246	"Port 1C2", "Port 1C3", "Port 1C4", "Port 1C5", "Port 1C6", "Port 1C7",
    247	"Port 2A0", "Port 2A1", "Port 2A2", "Port 2A3", "Port 2A4", "Port 2A5",
    248	"Port 2A6", "Port 2A7", "Port 2B0", "Port 2B1", "Port 2B2", "Port 2B3",
    249	"Port 2B4", "Port 2B5", "Port 2B6", "Port 2B7", "Port 2C0", "Port 2C1",
    250	"Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
    251};
    252
    253static int gpiomm_probe(struct device *dev, unsigned int id)
    254{
    255	struct gpiomm_gpio *gpiommgpio;
    256	const char *const name = dev_name(dev);
    257	int err;
    258
    259	gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
    260	if (!gpiommgpio)
    261		return -ENOMEM;
    262
    263	if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
    264		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
    265			base[id], base[id] + GPIOMM_EXTENT);
    266		return -EBUSY;
    267	}
    268
    269	gpiommgpio->base = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
    270	if (!gpiommgpio->base)
    271		return -ENOMEM;
    272
    273	gpiommgpio->chip.label = name;
    274	gpiommgpio->chip.parent = dev;
    275	gpiommgpio->chip.owner = THIS_MODULE;
    276	gpiommgpio->chip.base = -1;
    277	gpiommgpio->chip.ngpio = GPIOMM_NGPIO;
    278	gpiommgpio->chip.names = gpiomm_names;
    279	gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
    280	gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
    281	gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
    282	gpiommgpio->chip.get = gpiomm_gpio_get;
    283	gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
    284	gpiommgpio->chip.set = gpiomm_gpio_set;
    285	gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
    286
    287	spin_lock_init(&gpiommgpio->lock);
    288
    289	err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
    290	if (err) {
    291		dev_err(dev, "GPIO registering failed (%d)\n", err);
    292		return err;
    293	}
    294
    295	/* initialize all GPIO as output */
    296	iowrite8(0x80, gpiommgpio->base + 3);
    297	iowrite8(0x00, gpiommgpio->base);
    298	iowrite8(0x00, gpiommgpio->base + 1);
    299	iowrite8(0x00, gpiommgpio->base + 2);
    300	iowrite8(0x80, gpiommgpio->base + 7);
    301	iowrite8(0x00, gpiommgpio->base + 4);
    302	iowrite8(0x00, gpiommgpio->base + 5);
    303	iowrite8(0x00, gpiommgpio->base + 6);
    304
    305	return 0;
    306}
    307
    308static struct isa_driver gpiomm_driver = {
    309	.probe = gpiomm_probe,
    310	.driver = {
    311		.name = "gpio-mm"
    312	},
    313};
    314
    315module_isa_driver(gpiomm_driver, num_gpiomm);
    316
    317MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
    318MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver");
    319MODULE_LICENSE("GPL v2");