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-xgene.c (5586B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * AppliedMicro X-Gene SoC GPIO Driver
      4 *
      5 * Copyright (c) 2014, Applied Micro Circuits Corporation
      6 * Author: Feng Kan <fkan@apm.com>.
      7 */
      8
      9#include <linux/acpi.h>
     10#include <linux/kernel.h>
     11#include <linux/init.h>
     12#include <linux/io.h>
     13#include <linux/spinlock.h>
     14#include <linux/platform_device.h>
     15#include <linux/gpio/driver.h>
     16#include <linux/types.h>
     17#include <linux/bitops.h>
     18
     19#define GPIO_SET_DR_OFFSET	0x0C
     20#define GPIO_DATA_OFFSET	0x14
     21#define GPIO_BANK_STRIDE	0x0C
     22
     23#define XGENE_GPIOS_PER_BANK	16
     24#define XGENE_MAX_GPIO_BANKS	3
     25#define XGENE_MAX_GPIOS		(XGENE_GPIOS_PER_BANK * XGENE_MAX_GPIO_BANKS)
     26
     27#define GPIO_BIT_OFFSET(x)	(x % XGENE_GPIOS_PER_BANK)
     28#define GPIO_BANK_OFFSET(x)	((x / XGENE_GPIOS_PER_BANK) * GPIO_BANK_STRIDE)
     29
     30struct xgene_gpio {
     31	struct gpio_chip	chip;
     32	void __iomem		*base;
     33	spinlock_t		lock;
     34	u32			set_dr_val[XGENE_MAX_GPIO_BANKS];
     35};
     36
     37static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
     38{
     39	struct xgene_gpio *chip = gpiochip_get_data(gc);
     40	unsigned long bank_offset;
     41	u32 bit_offset;
     42
     43	bank_offset = GPIO_DATA_OFFSET + GPIO_BANK_OFFSET(offset);
     44	bit_offset = GPIO_BIT_OFFSET(offset);
     45	return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset));
     46}
     47
     48static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
     49{
     50	struct xgene_gpio *chip = gpiochip_get_data(gc);
     51	unsigned long bank_offset;
     52	u32 setval, bit_offset;
     53
     54	bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
     55	bit_offset = GPIO_BIT_OFFSET(offset) + XGENE_GPIOS_PER_BANK;
     56
     57	setval = ioread32(chip->base + bank_offset);
     58	if (val)
     59		setval |= BIT(bit_offset);
     60	else
     61		setval &= ~BIT(bit_offset);
     62	iowrite32(setval, chip->base + bank_offset);
     63}
     64
     65static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
     66{
     67	struct xgene_gpio *chip = gpiochip_get_data(gc);
     68	unsigned long flags;
     69
     70	spin_lock_irqsave(&chip->lock, flags);
     71	__xgene_gpio_set(gc, offset, val);
     72	spin_unlock_irqrestore(&chip->lock, flags);
     73}
     74
     75static int xgene_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
     76{
     77	struct xgene_gpio *chip = gpiochip_get_data(gc);
     78	unsigned long bank_offset, bit_offset;
     79
     80	bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
     81	bit_offset = GPIO_BIT_OFFSET(offset);
     82
     83	if (ioread32(chip->base + bank_offset) & BIT(bit_offset))
     84		return GPIO_LINE_DIRECTION_IN;
     85
     86	return GPIO_LINE_DIRECTION_OUT;
     87}
     88
     89static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
     90{
     91	struct xgene_gpio *chip = gpiochip_get_data(gc);
     92	unsigned long flags, bank_offset;
     93	u32 dirval, bit_offset;
     94
     95	bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
     96	bit_offset = GPIO_BIT_OFFSET(offset);
     97
     98	spin_lock_irqsave(&chip->lock, flags);
     99
    100	dirval = ioread32(chip->base + bank_offset);
    101	dirval |= BIT(bit_offset);
    102	iowrite32(dirval, chip->base + bank_offset);
    103
    104	spin_unlock_irqrestore(&chip->lock, flags);
    105
    106	return 0;
    107}
    108
    109static int xgene_gpio_dir_out(struct gpio_chip *gc,
    110					unsigned int offset, int val)
    111{
    112	struct xgene_gpio *chip = gpiochip_get_data(gc);
    113	unsigned long flags, bank_offset;
    114	u32 dirval, bit_offset;
    115
    116	bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
    117	bit_offset = GPIO_BIT_OFFSET(offset);
    118
    119	spin_lock_irqsave(&chip->lock, flags);
    120
    121	dirval = ioread32(chip->base + bank_offset);
    122	dirval &= ~BIT(bit_offset);
    123	iowrite32(dirval, chip->base + bank_offset);
    124	__xgene_gpio_set(gc, offset, val);
    125
    126	spin_unlock_irqrestore(&chip->lock, flags);
    127
    128	return 0;
    129}
    130
    131static __maybe_unused int xgene_gpio_suspend(struct device *dev)
    132{
    133	struct xgene_gpio *gpio = dev_get_drvdata(dev);
    134	unsigned long bank_offset;
    135	unsigned int bank;
    136
    137	for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
    138		bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
    139		gpio->set_dr_val[bank] = ioread32(gpio->base + bank_offset);
    140	}
    141	return 0;
    142}
    143
    144static __maybe_unused int xgene_gpio_resume(struct device *dev)
    145{
    146	struct xgene_gpio *gpio = dev_get_drvdata(dev);
    147	unsigned long bank_offset;
    148	unsigned int bank;
    149
    150	for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
    151		bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
    152		iowrite32(gpio->set_dr_val[bank], gpio->base + bank_offset);
    153	}
    154	return 0;
    155}
    156
    157static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
    158
    159static int xgene_gpio_probe(struct platform_device *pdev)
    160{
    161	struct xgene_gpio *gpio;
    162
    163	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
    164	if (!gpio)
    165		return -ENOMEM;
    166
    167	gpio->base = devm_platform_ioremap_resource(pdev, 0);
    168	if (IS_ERR(gpio->base))
    169		return PTR_ERR(gpio->base);
    170
    171	gpio->chip.ngpio = XGENE_MAX_GPIOS;
    172
    173	spin_lock_init(&gpio->lock);
    174	gpio->chip.parent = &pdev->dev;
    175	gpio->chip.get_direction = xgene_gpio_get_direction;
    176	gpio->chip.direction_input = xgene_gpio_dir_in;
    177	gpio->chip.direction_output = xgene_gpio_dir_out;
    178	gpio->chip.get = xgene_gpio_get;
    179	gpio->chip.set = xgene_gpio_set;
    180	gpio->chip.label = dev_name(&pdev->dev);
    181	gpio->chip.base = -1;
    182
    183	platform_set_drvdata(pdev, gpio);
    184
    185	return devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
    186}
    187
    188static const struct of_device_id xgene_gpio_of_match[] = {
    189	{ .compatible = "apm,xgene-gpio", },
    190	{},
    191};
    192
    193#ifdef CONFIG_ACPI
    194static const struct acpi_device_id xgene_gpio_acpi_match[] = {
    195	{ "APMC0D14", 0 },
    196	{ },
    197};
    198#endif
    199
    200static struct platform_driver xgene_gpio_driver = {
    201	.driver = {
    202		.name = "xgene-gpio",
    203		.of_match_table = xgene_gpio_of_match,
    204		.acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match),
    205		.pm     = &xgene_gpio_pm,
    206	},
    207	.probe = xgene_gpio_probe,
    208};
    209builtin_platform_driver(xgene_gpio_driver);