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-janz-ttl.c (4425B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Janz MODULbus VMOD-TTL GPIO Driver
      4 *
      5 * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/module.h>
     10#include <linux/init.h>
     11#include <linux/interrupt.h>
     12#include <linux/delay.h>
     13#include <linux/platform_device.h>
     14#include <linux/io.h>
     15#include <linux/gpio/driver.h>
     16#include <linux/slab.h>
     17#include <linux/bitops.h>
     18
     19#include <linux/mfd/janz.h>
     20
     21#define DRV_NAME "janz-ttl"
     22
     23#define PORTA_DIRECTION		0x23
     24#define PORTB_DIRECTION		0x2B
     25#define PORTC_DIRECTION		0x06
     26#define PORTA_IOCTL		0x24
     27#define PORTB_IOCTL		0x2C
     28#define PORTC_IOCTL		0x07
     29
     30#define MASTER_INT_CTL		0x00
     31#define MASTER_CONF_CTL		0x01
     32
     33#define CONF_PAE		BIT(2)
     34#define CONF_PBE		BIT(7)
     35#define CONF_PCE		BIT(4)
     36
     37struct ttl_control_regs {
     38	__be16 portc;
     39	__be16 portb;
     40	__be16 porta;
     41	__be16 control;
     42};
     43
     44struct ttl_module {
     45	struct gpio_chip gpio;
     46
     47	/* base address of registers */
     48	struct ttl_control_regs __iomem *regs;
     49
     50	u8 portc_shadow;
     51	u8 portb_shadow;
     52	u8 porta_shadow;
     53
     54	spinlock_t lock;
     55};
     56
     57static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
     58{
     59	struct ttl_module *mod = dev_get_drvdata(gpio->parent);
     60	u8 *shadow;
     61	int ret;
     62
     63	if (offset < 8) {
     64		shadow = &mod->porta_shadow;
     65	} else if (offset < 16) {
     66		shadow = &mod->portb_shadow;
     67		offset -= 8;
     68	} else {
     69		shadow = &mod->portc_shadow;
     70		offset -= 16;
     71	}
     72
     73	spin_lock(&mod->lock);
     74	ret = *shadow & BIT(offset);
     75	spin_unlock(&mod->lock);
     76	return !!ret;
     77}
     78
     79static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
     80{
     81	struct ttl_module *mod = dev_get_drvdata(gpio->parent);
     82	void __iomem *port;
     83	u8 *shadow;
     84
     85	if (offset < 8) {
     86		port = &mod->regs->porta;
     87		shadow = &mod->porta_shadow;
     88	} else if (offset < 16) {
     89		port = &mod->regs->portb;
     90		shadow = &mod->portb_shadow;
     91		offset -= 8;
     92	} else {
     93		port = &mod->regs->portc;
     94		shadow = &mod->portc_shadow;
     95		offset -= 16;
     96	}
     97
     98	spin_lock(&mod->lock);
     99	if (value)
    100		*shadow |= BIT(offset);
    101	else
    102		*shadow &= ~BIT(offset);
    103
    104	iowrite16be(*shadow, port);
    105	spin_unlock(&mod->lock);
    106}
    107
    108static void ttl_write_reg(struct ttl_module *mod, u8 reg, u16 val)
    109{
    110	iowrite16be(reg, &mod->regs->control);
    111	iowrite16be(val, &mod->regs->control);
    112}
    113
    114static void ttl_setup_device(struct ttl_module *mod)
    115{
    116	/* reset the device to a known state */
    117	iowrite16be(0x0000, &mod->regs->control);
    118	iowrite16be(0x0001, &mod->regs->control);
    119	iowrite16be(0x0000, &mod->regs->control);
    120
    121	/* put all ports in open-drain mode */
    122	ttl_write_reg(mod, PORTA_IOCTL, 0x00ff);
    123	ttl_write_reg(mod, PORTB_IOCTL, 0x00ff);
    124	ttl_write_reg(mod, PORTC_IOCTL, 0x000f);
    125
    126	/* set all ports as outputs */
    127	ttl_write_reg(mod, PORTA_DIRECTION, 0x0000);
    128	ttl_write_reg(mod, PORTB_DIRECTION, 0x0000);
    129	ttl_write_reg(mod, PORTC_DIRECTION, 0x0000);
    130
    131	/* set all ports to drive zeroes */
    132	iowrite16be(0x0000, &mod->regs->porta);
    133	iowrite16be(0x0000, &mod->regs->portb);
    134	iowrite16be(0x0000, &mod->regs->portc);
    135
    136	/* enable all ports */
    137	ttl_write_reg(mod, MASTER_CONF_CTL, CONF_PAE | CONF_PBE | CONF_PCE);
    138}
    139
    140static int ttl_probe(struct platform_device *pdev)
    141{
    142	struct janz_platform_data *pdata;
    143	struct ttl_module *mod;
    144	struct gpio_chip *gpio;
    145	int ret;
    146
    147	pdata = dev_get_platdata(&pdev->dev);
    148	if (!pdata) {
    149		dev_err(&pdev->dev, "no platform data\n");
    150		return -ENXIO;
    151	}
    152
    153	mod = devm_kzalloc(&pdev->dev, sizeof(*mod), GFP_KERNEL);
    154	if (!mod)
    155		return -ENOMEM;
    156
    157	platform_set_drvdata(pdev, mod);
    158	spin_lock_init(&mod->lock);
    159
    160	/* get access to the MODULbus registers for this module */
    161	mod->regs = devm_platform_ioremap_resource(pdev, 0);
    162	if (IS_ERR(mod->regs))
    163		return PTR_ERR(mod->regs);
    164
    165	ttl_setup_device(mod);
    166
    167	/* Initialize the GPIO data structures */
    168	gpio = &mod->gpio;
    169	gpio->parent = &pdev->dev;
    170	gpio->label = pdev->name;
    171	gpio->get = ttl_get_value;
    172	gpio->set = ttl_set_value;
    173	gpio->owner = THIS_MODULE;
    174
    175	/* request dynamic allocation */
    176	gpio->base = -1;
    177	gpio->ngpio = 20;
    178
    179	ret = devm_gpiochip_add_data(&pdev->dev, gpio, NULL);
    180	if (ret) {
    181		dev_err(&pdev->dev, "unable to add GPIO chip\n");
    182		return ret;
    183	}
    184
    185	return 0;
    186}
    187
    188static struct platform_driver ttl_driver = {
    189	.driver		= {
    190		.name	= DRV_NAME,
    191	},
    192	.probe		= ttl_probe,
    193};
    194
    195module_platform_driver(ttl_driver);
    196
    197MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
    198MODULE_DESCRIPTION("Janz MODULbus VMOD-TTL Driver");
    199MODULE_LICENSE("GPL");
    200MODULE_ALIAS("platform:janz-ttl");