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-amdpt.c (3927B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * AMD Promontory GPIO driver
      4 *
      5 * Copyright (C) 2015 ASMedia Technology Inc.
      6 * Author: YD Tseng <yd_tseng@asmedia.com.tw>
      7 */
      8
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/gpio/driver.h>
     12#include <linux/spinlock.h>
     13#include <linux/acpi.h>
     14#include <linux/platform_device.h>
     15
     16#define PT_TOTAL_GPIO 8
     17#define PT_TOTAL_GPIO_EX 24
     18
     19/* PCI-E MMIO register offsets */
     20#define PT_DIRECTION_REG   0x00
     21#define PT_INPUTDATA_REG   0x04
     22#define PT_OUTPUTDATA_REG  0x08
     23#define PT_CLOCKRATE_REG   0x0C
     24#define PT_SYNC_REG        0x28
     25
     26struct pt_gpio_chip {
     27	struct gpio_chip         gc;
     28	void __iomem             *reg_base;
     29};
     30
     31static int pt_gpio_request(struct gpio_chip *gc, unsigned offset)
     32{
     33	struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
     34	unsigned long flags;
     35	u32 using_pins;
     36
     37	dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset);
     38
     39	raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
     40
     41	using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
     42	if (using_pins & BIT(offset)) {
     43		dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n",
     44			 offset);
     45		raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
     46		return -EINVAL;
     47	}
     48
     49	writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG);
     50
     51	raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
     52
     53	return 0;
     54}
     55
     56static void pt_gpio_free(struct gpio_chip *gc, unsigned offset)
     57{
     58	struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
     59	unsigned long flags;
     60	u32 using_pins;
     61
     62	raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
     63
     64	using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
     65	using_pins &= ~BIT(offset);
     66	writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG);
     67
     68	raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
     69
     70	dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset);
     71}
     72
     73static int pt_gpio_probe(struct platform_device *pdev)
     74{
     75	struct device *dev = &pdev->dev;
     76	struct pt_gpio_chip *pt_gpio;
     77	int ret = 0;
     78
     79	if (!ACPI_COMPANION(dev)) {
     80		dev_err(dev, "PT GPIO device node not found\n");
     81		return -ENODEV;
     82	}
     83
     84	pt_gpio = devm_kzalloc(dev, sizeof(struct pt_gpio_chip), GFP_KERNEL);
     85	if (!pt_gpio)
     86		return -ENOMEM;
     87
     88	pt_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0);
     89	if (IS_ERR(pt_gpio->reg_base)) {
     90		dev_err(dev, "Failed to map MMIO resource for PT GPIO.\n");
     91		return PTR_ERR(pt_gpio->reg_base);
     92	}
     93
     94	ret = bgpio_init(&pt_gpio->gc, dev, 4,
     95			 pt_gpio->reg_base + PT_INPUTDATA_REG,
     96			 pt_gpio->reg_base + PT_OUTPUTDATA_REG, NULL,
     97			 pt_gpio->reg_base + PT_DIRECTION_REG, NULL,
     98			 BGPIOF_READ_OUTPUT_REG_SET);
     99	if (ret) {
    100		dev_err(dev, "bgpio_init failed\n");
    101		return ret;
    102	}
    103
    104	pt_gpio->gc.owner            = THIS_MODULE;
    105	pt_gpio->gc.request          = pt_gpio_request;
    106	pt_gpio->gc.free             = pt_gpio_free;
    107	pt_gpio->gc.ngpio            = (uintptr_t)device_get_match_data(dev);
    108
    109	ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio);
    110	if (ret) {
    111		dev_err(dev, "Failed to register GPIO lib\n");
    112		return ret;
    113	}
    114
    115	platform_set_drvdata(pdev, pt_gpio);
    116
    117	/* initialize register setting */
    118	writel(0, pt_gpio->reg_base + PT_SYNC_REG);
    119	writel(0, pt_gpio->reg_base + PT_CLOCKRATE_REG);
    120
    121	dev_dbg(dev, "PT GPIO driver loaded\n");
    122	return ret;
    123}
    124
    125static int pt_gpio_remove(struct platform_device *pdev)
    126{
    127	struct pt_gpio_chip *pt_gpio = platform_get_drvdata(pdev);
    128
    129	gpiochip_remove(&pt_gpio->gc);
    130
    131	return 0;
    132}
    133
    134static const struct acpi_device_id pt_gpio_acpi_match[] = {
    135	{ "AMDF030", PT_TOTAL_GPIO },
    136	{ "AMDIF030", PT_TOTAL_GPIO },
    137	{ "AMDIF031", PT_TOTAL_GPIO_EX },
    138	{ },
    139};
    140MODULE_DEVICE_TABLE(acpi, pt_gpio_acpi_match);
    141
    142static struct platform_driver pt_gpio_driver = {
    143	.driver = {
    144		.name = "pt-gpio",
    145		.acpi_match_table = ACPI_PTR(pt_gpio_acpi_match),
    146	},
    147	.probe = pt_gpio_probe,
    148	.remove = pt_gpio_remove,
    149};
    150
    151module_platform_driver(pt_gpio_driver);
    152
    153MODULE_LICENSE("GPL");
    154MODULE_AUTHOR("YD Tseng <yd_tseng@asmedia.com.tw>");
    155MODULE_DESCRIPTION("AMD Promontory GPIO Driver");