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-rdc321x.c (5137B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * RDC321x GPIO driver
      4 *
      5 * Copyright (C) 2008, Volker Weiss <dev@tintuc.de>
      6 * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org>
      7 */
      8#include <linux/module.h>
      9#include <linux/kernel.h>
     10#include <linux/init.h>
     11#include <linux/spinlock.h>
     12#include <linux/platform_device.h>
     13#include <linux/pci.h>
     14#include <linux/gpio/driver.h>
     15#include <linux/mfd/rdc321x.h>
     16#include <linux/slab.h>
     17
     18struct rdc321x_gpio {
     19	spinlock_t		lock;
     20	struct pci_dev		*sb_pdev;
     21	u32			data_reg[2];
     22	int			reg1_ctrl_base;
     23	int			reg1_data_base;
     24	int			reg2_ctrl_base;
     25	int			reg2_data_base;
     26	struct gpio_chip	chip;
     27};
     28
     29/* read GPIO pin */
     30static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
     31{
     32	struct rdc321x_gpio *gpch;
     33	u32 value = 0;
     34	int reg;
     35
     36	gpch = gpiochip_get_data(chip);
     37	reg = gpio < 32 ? gpch->reg1_data_base : gpch->reg2_data_base;
     38
     39	spin_lock(&gpch->lock);
     40	pci_write_config_dword(gpch->sb_pdev, reg,
     41					gpch->data_reg[gpio < 32 ? 0 : 1]);
     42	pci_read_config_dword(gpch->sb_pdev, reg, &value);
     43	spin_unlock(&gpch->lock);
     44
     45	return (1 << (gpio & 0x1f)) & value ? 1 : 0;
     46}
     47
     48static void rdc_gpio_set_value_impl(struct gpio_chip *chip,
     49				unsigned gpio, int value)
     50{
     51	struct rdc321x_gpio *gpch;
     52	int reg = (gpio < 32) ? 0 : 1;
     53
     54	gpch = gpiochip_get_data(chip);
     55
     56	if (value)
     57		gpch->data_reg[reg] |= 1 << (gpio & 0x1f);
     58	else
     59		gpch->data_reg[reg] &= ~(1 << (gpio & 0x1f));
     60
     61	pci_write_config_dword(gpch->sb_pdev,
     62			reg ? gpch->reg2_data_base : gpch->reg1_data_base,
     63			gpch->data_reg[reg]);
     64}
     65
     66/* set GPIO pin to value */
     67static void rdc_gpio_set_value(struct gpio_chip *chip,
     68				unsigned gpio, int value)
     69{
     70	struct rdc321x_gpio *gpch;
     71
     72	gpch = gpiochip_get_data(chip);
     73	spin_lock(&gpch->lock);
     74	rdc_gpio_set_value_impl(chip, gpio, value);
     75	spin_unlock(&gpch->lock);
     76}
     77
     78static int rdc_gpio_config(struct gpio_chip *chip,
     79				unsigned gpio, int value)
     80{
     81	struct rdc321x_gpio *gpch;
     82	int err;
     83	u32 reg;
     84
     85	gpch = gpiochip_get_data(chip);
     86
     87	spin_lock(&gpch->lock);
     88	err = pci_read_config_dword(gpch->sb_pdev, gpio < 32 ?
     89			gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, &reg);
     90	if (err)
     91		goto unlock;
     92
     93	reg |= 1 << (gpio & 0x1f);
     94
     95	err = pci_write_config_dword(gpch->sb_pdev, gpio < 32 ?
     96			gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, reg);
     97	if (err)
     98		goto unlock;
     99
    100	rdc_gpio_set_value_impl(chip, gpio, value);
    101
    102unlock:
    103	spin_unlock(&gpch->lock);
    104
    105	return err;
    106}
    107
    108/* configure GPIO pin as input */
    109static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
    110{
    111	return rdc_gpio_config(chip, gpio, 1);
    112}
    113
    114/*
    115 * Cache the initial value of both GPIO data registers
    116 */
    117static int rdc321x_gpio_probe(struct platform_device *pdev)
    118{
    119	int err;
    120	struct resource *r;
    121	struct rdc321x_gpio *rdc321x_gpio_dev;
    122	struct rdc321x_gpio_pdata *pdata;
    123
    124	pdata = dev_get_platdata(&pdev->dev);
    125	if (!pdata) {
    126		dev_err(&pdev->dev, "no platform data supplied\n");
    127		return -ENODEV;
    128	}
    129
    130	rdc321x_gpio_dev = devm_kzalloc(&pdev->dev, sizeof(struct rdc321x_gpio),
    131					GFP_KERNEL);
    132	if (!rdc321x_gpio_dev)
    133		return -ENOMEM;
    134
    135	r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1");
    136	if (!r) {
    137		dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n");
    138		return -ENODEV;
    139	}
    140
    141	spin_lock_init(&rdc321x_gpio_dev->lock);
    142	rdc321x_gpio_dev->sb_pdev = pdata->sb_pdev;
    143	rdc321x_gpio_dev->reg1_ctrl_base = r->start;
    144	rdc321x_gpio_dev->reg1_data_base = r->start + 0x4;
    145
    146	r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2");
    147	if (!r) {
    148		dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n");
    149		return -ENODEV;
    150	}
    151
    152	rdc321x_gpio_dev->reg2_ctrl_base = r->start;
    153	rdc321x_gpio_dev->reg2_data_base = r->start + 0x4;
    154
    155	rdc321x_gpio_dev->chip.label = "rdc321x-gpio";
    156	rdc321x_gpio_dev->chip.owner = THIS_MODULE;
    157	rdc321x_gpio_dev->chip.direction_input = rdc_gpio_direction_input;
    158	rdc321x_gpio_dev->chip.direction_output = rdc_gpio_config;
    159	rdc321x_gpio_dev->chip.get = rdc_gpio_get_value;
    160	rdc321x_gpio_dev->chip.set = rdc_gpio_set_value;
    161	rdc321x_gpio_dev->chip.base = 0;
    162	rdc321x_gpio_dev->chip.ngpio = pdata->max_gpios;
    163
    164	platform_set_drvdata(pdev, rdc321x_gpio_dev);
    165
    166	/* This might not be, what others (BIOS, bootloader, etc.)
    167	   wrote to these registers before, but it's a good guess. Still
    168	   better than just using 0xffffffff. */
    169	err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
    170					rdc321x_gpio_dev->reg1_data_base,
    171					&rdc321x_gpio_dev->data_reg[0]);
    172	if (err)
    173		return err;
    174
    175	err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
    176					rdc321x_gpio_dev->reg2_data_base,
    177					&rdc321x_gpio_dev->data_reg[1]);
    178	if (err)
    179		return err;
    180
    181	dev_info(&pdev->dev, "registering %d GPIOs\n",
    182					rdc321x_gpio_dev->chip.ngpio);
    183	return devm_gpiochip_add_data(&pdev->dev, &rdc321x_gpio_dev->chip,
    184				      rdc321x_gpio_dev);
    185}
    186
    187static struct platform_driver rdc321x_gpio_driver = {
    188	.driver.name	= "rdc321x-gpio",
    189	.probe		= rdc321x_gpio_probe,
    190};
    191
    192module_platform_driver(rdc321x_gpio_driver);
    193
    194MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
    195MODULE_DESCRIPTION("RDC321x GPIO driver");
    196MODULE_LICENSE("GPL");
    197MODULE_ALIAS("platform:rdc321x-gpio");