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-amd-fch.c (4967B)


      1// SPDX-License-Identifier: GPL-2.0+
      2
      3/*
      4 * GPIO driver for the AMD G series FCH (eg. GX-412TC)
      5 *
      6 * Copyright (C) 2018 metux IT consult
      7 * Author: Enrico Weigelt, metux IT consult <info@metux.net>
      8 *
      9 */
     10
     11#include <linux/err.h>
     12#include <linux/io.h>
     13#include <linux/kernel.h>
     14#include <linux/module.h>
     15#include <linux/platform_device.h>
     16#include <linux/gpio/driver.h>
     17#include <linux/platform_data/gpio/gpio-amd-fch.h>
     18#include <linux/spinlock.h>
     19
     20#define AMD_FCH_MMIO_BASE		0xFED80000
     21#define AMD_FCH_GPIO_BANK0_BASE		0x1500
     22#define AMD_FCH_GPIO_SIZE		0x0300
     23
     24#define AMD_FCH_GPIO_FLAG_DIRECTION	BIT(23)
     25#define AMD_FCH_GPIO_FLAG_WRITE		BIT(22)
     26#define AMD_FCH_GPIO_FLAG_READ		BIT(16)
     27
     28static const struct resource amd_fch_gpio_iores =
     29	DEFINE_RES_MEM_NAMED(
     30		AMD_FCH_MMIO_BASE + AMD_FCH_GPIO_BANK0_BASE,
     31		AMD_FCH_GPIO_SIZE,
     32		"amd-fch-gpio-iomem");
     33
     34struct amd_fch_gpio_priv {
     35	struct gpio_chip		gc;
     36	void __iomem			*base;
     37	struct amd_fch_gpio_pdata	*pdata;
     38	spinlock_t			lock;
     39};
     40
     41static void __iomem *amd_fch_gpio_addr(struct amd_fch_gpio_priv *priv,
     42				       unsigned int gpio)
     43{
     44	return priv->base + priv->pdata->gpio_reg[gpio]*sizeof(u32);
     45}
     46
     47static int amd_fch_gpio_direction_input(struct gpio_chip *gc,
     48					unsigned int offset)
     49{
     50	unsigned long flags;
     51	struct amd_fch_gpio_priv *priv = gpiochip_get_data(gc);
     52	void __iomem *ptr = amd_fch_gpio_addr(priv, offset);
     53
     54	spin_lock_irqsave(&priv->lock, flags);
     55	writel_relaxed(readl_relaxed(ptr) & ~AMD_FCH_GPIO_FLAG_DIRECTION, ptr);
     56	spin_unlock_irqrestore(&priv->lock, flags);
     57
     58	return 0;
     59}
     60
     61static int amd_fch_gpio_direction_output(struct gpio_chip *gc,
     62					 unsigned int gpio, int value)
     63{
     64	unsigned long flags;
     65	struct amd_fch_gpio_priv *priv = gpiochip_get_data(gc);
     66	void __iomem *ptr = amd_fch_gpio_addr(priv, gpio);
     67	u32 val;
     68
     69	spin_lock_irqsave(&priv->lock, flags);
     70
     71	val = readl_relaxed(ptr);
     72	if (value)
     73		val |= AMD_FCH_GPIO_FLAG_WRITE;
     74	else
     75		val &= ~AMD_FCH_GPIO_FLAG_WRITE;
     76
     77	writel_relaxed(val | AMD_FCH_GPIO_FLAG_DIRECTION, ptr);
     78
     79	spin_unlock_irqrestore(&priv->lock, flags);
     80
     81	return 0;
     82}
     83
     84static int amd_fch_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
     85{
     86	int ret;
     87	unsigned long flags;
     88	struct amd_fch_gpio_priv *priv = gpiochip_get_data(gc);
     89	void __iomem *ptr = amd_fch_gpio_addr(priv, gpio);
     90
     91	spin_lock_irqsave(&priv->lock, flags);
     92	ret = (readl_relaxed(ptr) & AMD_FCH_GPIO_FLAG_DIRECTION);
     93	spin_unlock_irqrestore(&priv->lock, flags);
     94
     95	return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
     96}
     97
     98static void amd_fch_gpio_set(struct gpio_chip *gc,
     99			     unsigned int gpio, int value)
    100{
    101	unsigned long flags;
    102	struct amd_fch_gpio_priv *priv = gpiochip_get_data(gc);
    103	void __iomem *ptr = amd_fch_gpio_addr(priv, gpio);
    104	u32 mask;
    105
    106	spin_lock_irqsave(&priv->lock, flags);
    107
    108	mask = readl_relaxed(ptr);
    109	if (value)
    110		mask |= AMD_FCH_GPIO_FLAG_WRITE;
    111	else
    112		mask &= ~AMD_FCH_GPIO_FLAG_WRITE;
    113	writel_relaxed(mask, ptr);
    114
    115	spin_unlock_irqrestore(&priv->lock, flags);
    116}
    117
    118static int amd_fch_gpio_get(struct gpio_chip *gc,
    119			    unsigned int offset)
    120{
    121	unsigned long flags;
    122	int ret;
    123	struct amd_fch_gpio_priv *priv = gpiochip_get_data(gc);
    124	void __iomem *ptr = amd_fch_gpio_addr(priv, offset);
    125
    126	spin_lock_irqsave(&priv->lock, flags);
    127	ret = (readl_relaxed(ptr) & AMD_FCH_GPIO_FLAG_READ);
    128	spin_unlock_irqrestore(&priv->lock, flags);
    129
    130	return ret;
    131}
    132
    133static int amd_fch_gpio_request(struct gpio_chip *chip,
    134				unsigned int gpio_pin)
    135{
    136	return 0;
    137}
    138
    139static int amd_fch_gpio_probe(struct platform_device *pdev)
    140{
    141	struct amd_fch_gpio_priv *priv;
    142	struct amd_fch_gpio_pdata *pdata;
    143
    144	pdata = dev_get_platdata(&pdev->dev);
    145	if (!pdata) {
    146		dev_err(&pdev->dev, "no platform_data\n");
    147		return -ENOENT;
    148	}
    149
    150	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    151	if (!priv)
    152		return -ENOMEM;
    153
    154	priv->pdata	= pdata;
    155
    156	priv->gc.owner			= THIS_MODULE;
    157	priv->gc.parent			= &pdev->dev;
    158	priv->gc.label			= dev_name(&pdev->dev);
    159	priv->gc.ngpio			= priv->pdata->gpio_num;
    160	priv->gc.names			= priv->pdata->gpio_names;
    161	priv->gc.base			= -1;
    162	priv->gc.request		= amd_fch_gpio_request;
    163	priv->gc.direction_input	= amd_fch_gpio_direction_input;
    164	priv->gc.direction_output	= amd_fch_gpio_direction_output;
    165	priv->gc.get_direction		= amd_fch_gpio_get_direction;
    166	priv->gc.get			= amd_fch_gpio_get;
    167	priv->gc.set			= amd_fch_gpio_set;
    168
    169	spin_lock_init(&priv->lock);
    170
    171	priv->base = devm_ioremap_resource(&pdev->dev, &amd_fch_gpio_iores);
    172	if (IS_ERR(priv->base))
    173		return PTR_ERR(priv->base);
    174
    175	platform_set_drvdata(pdev, priv);
    176
    177	return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
    178}
    179
    180static struct platform_driver amd_fch_gpio_driver = {
    181	.driver = {
    182		.name = AMD_FCH_GPIO_DRIVER_NAME,
    183	},
    184	.probe = amd_fch_gpio_probe,
    185};
    186
    187module_platform_driver(amd_fch_gpio_driver);
    188
    189MODULE_AUTHOR("Enrico Weigelt, metux IT consult <info@metux.net>");
    190MODULE_DESCRIPTION("AMD G-series FCH GPIO driver");
    191MODULE_LICENSE("GPL");
    192MODULE_ALIAS("platform:" AMD_FCH_GPIO_DRIVER_NAME);