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

via-gpio.c (7268B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Support for viafb GPIO ports.
      4 *
      5 * Copyright 2009 Jonathan Corbet <corbet@lwn.net>
      6 */
      7
      8#include <linux/spinlock.h>
      9#include <linux/gpio/driver.h>
     10#include <linux/platform_device.h>
     11#include <linux/via-core.h>
     12#include <linux/via-gpio.h>
     13#include <linux/export.h>
     14
     15/*
     16 * The ports we know about.  Note that the port-25 gpios are not
     17 * mentioned in the datasheet.
     18 */
     19
     20struct viafb_gpio {
     21	char *vg_name;	/* Data sheet name */
     22	u16 vg_io_port;
     23	u8  vg_port_index;
     24	int  vg_mask_shift;
     25};
     26
     27static struct viafb_gpio viafb_all_gpios[] = {
     28	{
     29		.vg_name = "VGPIO0",  /* Guess - not in datasheet */
     30		.vg_io_port = VIASR,
     31		.vg_port_index = 0x25,
     32		.vg_mask_shift = 1
     33	},
     34	{
     35		.vg_name = "VGPIO1",
     36		.vg_io_port = VIASR,
     37		.vg_port_index = 0x25,
     38		.vg_mask_shift = 0
     39	},
     40	{
     41		.vg_name = "VGPIO2",  /* aka DISPCLKI0 */
     42		.vg_io_port = VIASR,
     43		.vg_port_index = 0x2c,
     44		.vg_mask_shift = 1
     45	},
     46	{
     47		.vg_name = "VGPIO3",  /* aka DISPCLKO0 */
     48		.vg_io_port = VIASR,
     49		.vg_port_index = 0x2c,
     50		.vg_mask_shift = 0
     51	},
     52	{
     53		.vg_name = "VGPIO4",  /* DISPCLKI1 */
     54		.vg_io_port = VIASR,
     55		.vg_port_index = 0x3d,
     56		.vg_mask_shift = 1
     57	},
     58	{
     59		.vg_name = "VGPIO5",  /* DISPCLKO1 */
     60		.vg_io_port = VIASR,
     61		.vg_port_index = 0x3d,
     62		.vg_mask_shift = 0
     63	},
     64};
     65
     66#define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios)
     67
     68/*
     69 * This structure controls the active GPIOs, which may be a subset
     70 * of those which are known.
     71 */
     72
     73struct viafb_gpio_cfg {
     74	struct gpio_chip gpio_chip;
     75	struct viafb_dev *vdev;
     76	struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS];
     77	const char *gpio_names[VIAFB_NUM_GPIOS];
     78};
     79
     80/*
     81 * GPIO access functions
     82 */
     83static void via_gpio_set(struct gpio_chip *chip, unsigned int nr,
     84			 int value)
     85{
     86	struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
     87	u8 reg;
     88	struct viafb_gpio *gpio;
     89	unsigned long flags;
     90
     91	spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
     92	gpio = cfg->active_gpios[nr];
     93	reg = via_read_reg(VIASR, gpio->vg_port_index);
     94	reg |= 0x40 << gpio->vg_mask_shift;  /* output enable */
     95	if (value)
     96		reg |= 0x10 << gpio->vg_mask_shift;
     97	else
     98		reg &= ~(0x10 << gpio->vg_mask_shift);
     99	via_write_reg(VIASR, gpio->vg_port_index, reg);
    100	spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
    101}
    102
    103static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr,
    104			    int value)
    105{
    106	via_gpio_set(chip, nr, value);
    107	return 0;
    108}
    109
    110/*
    111 * Set the input direction.  I'm not sure this is right; we should
    112 * be able to do input without disabling output.
    113 */
    114static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
    115{
    116	struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
    117	struct viafb_gpio *gpio;
    118	unsigned long flags;
    119
    120	spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
    121	gpio = cfg->active_gpios[nr];
    122	via_write_reg_mask(VIASR, gpio->vg_port_index, 0,
    123			0x40 << gpio->vg_mask_shift);
    124	spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
    125	return 0;
    126}
    127
    128static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
    129{
    130	struct viafb_gpio_cfg *cfg = gpiochip_get_data(chip);
    131	u8 reg;
    132	struct viafb_gpio *gpio;
    133	unsigned long flags;
    134
    135	spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
    136	gpio = cfg->active_gpios[nr];
    137	reg = via_read_reg(VIASR, gpio->vg_port_index);
    138	spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
    139	return !!(reg & (0x04 << gpio->vg_mask_shift));
    140}
    141
    142
    143static struct viafb_gpio_cfg viafb_gpio_config = {
    144	.gpio_chip = {
    145		.label = "VIAFB onboard GPIO",
    146		.owner = THIS_MODULE,
    147		.direction_output = via_gpio_dir_out,
    148		.set = via_gpio_set,
    149		.direction_input = via_gpio_dir_input,
    150		.get = via_gpio_get,
    151		.base = -1,
    152		.ngpio = 0,
    153		.can_sleep = 0
    154	}
    155};
    156
    157/*
    158 * Manage the software enable bit.
    159 */
    160static void viafb_gpio_enable(struct viafb_gpio *gpio)
    161{
    162	via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02);
    163}
    164
    165static void viafb_gpio_disable(struct viafb_gpio *gpio)
    166{
    167	via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
    168}
    169
    170#ifdef CONFIG_PM
    171
    172static int viafb_gpio_suspend(void *private)
    173{
    174	return 0;
    175}
    176
    177static int viafb_gpio_resume(void *private)
    178{
    179	int i;
    180
    181	for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
    182		viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
    183	return 0;
    184}
    185
    186static struct viafb_pm_hooks viafb_gpio_pm_hooks = {
    187	.suspend = viafb_gpio_suspend,
    188	.resume = viafb_gpio_resume
    189};
    190#endif /* CONFIG_PM */
    191
    192/*
    193 * Look up a specific gpio and return the number it was assigned.
    194 */
    195int viafb_gpio_lookup(const char *name)
    196{
    197	int i;
    198
    199	for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i++)
    200		if (!strcmp(name, viafb_gpio_config.active_gpios[i]->vg_name))
    201			return viafb_gpio_config.gpio_chip.base + i;
    202	return -1;
    203}
    204EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
    205
    206/*
    207 * Platform device stuff.
    208 */
    209static int viafb_gpio_probe(struct platform_device *platdev)
    210{
    211	struct viafb_dev *vdev = platdev->dev.platform_data;
    212	struct via_port_cfg *port_cfg = vdev->port_cfg;
    213	int i, ngpio = 0, ret;
    214	struct viafb_gpio *gpio;
    215	unsigned long flags;
    216
    217	/*
    218	 * Set up entries for all GPIOs which have been configured to
    219	 * operate as such (as opposed to as i2c ports).
    220	 */
    221	for (i = 0; i < VIAFB_NUM_PORTS; i++) {
    222		if (port_cfg[i].mode != VIA_MODE_GPIO)
    223			continue;
    224		for (gpio = viafb_all_gpios;
    225		     gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++)
    226			if (gpio->vg_port_index == port_cfg[i].ioport_index) {
    227				viafb_gpio_config.active_gpios[ngpio] = gpio;
    228				viafb_gpio_config.gpio_names[ngpio] =
    229					gpio->vg_name;
    230				ngpio++;
    231			}
    232	}
    233	viafb_gpio_config.gpio_chip.ngpio = ngpio;
    234	viafb_gpio_config.gpio_chip.names = viafb_gpio_config.gpio_names;
    235	viafb_gpio_config.vdev = vdev;
    236	if (ngpio == 0) {
    237		printk(KERN_INFO "viafb: no GPIOs configured\n");
    238		return 0;
    239	}
    240	/*
    241	 * Enable the ports.  They come in pairs, with a single
    242	 * enable bit for both.
    243	 */
    244	spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
    245	for (i = 0; i < ngpio; i += 2)
    246		viafb_gpio_enable(viafb_gpio_config.active_gpios[i]);
    247	spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
    248	/*
    249	 * Get registered.
    250	 */
    251	viafb_gpio_config.gpio_chip.base = -1;  /* Dynamic */
    252	ret = gpiochip_add_data(&viafb_gpio_config.gpio_chip,
    253				&viafb_gpio_config);
    254	if (ret) {
    255		printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
    256		viafb_gpio_config.gpio_chip.ngpio = 0;
    257	}
    258#ifdef CONFIG_PM
    259	viafb_pm_register(&viafb_gpio_pm_hooks);
    260#endif
    261	return ret;
    262}
    263
    264
    265static int viafb_gpio_remove(struct platform_device *platdev)
    266{
    267	unsigned long flags;
    268	int i;
    269
    270#ifdef CONFIG_PM
    271	viafb_pm_unregister(&viafb_gpio_pm_hooks);
    272#endif
    273
    274	/*
    275	 * Get unregistered.
    276	 */
    277	if (viafb_gpio_config.gpio_chip.ngpio > 0) {
    278		gpiochip_remove(&viafb_gpio_config.gpio_chip);
    279	}
    280	/*
    281	 * Disable the ports.
    282	 */
    283	spin_lock_irqsave(&viafb_gpio_config.vdev->reg_lock, flags);
    284	for (i = 0; i < viafb_gpio_config.gpio_chip.ngpio; i += 2)
    285		viafb_gpio_disable(viafb_gpio_config.active_gpios[i]);
    286	viafb_gpio_config.gpio_chip.ngpio = 0;
    287	spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
    288	return 0;
    289}
    290
    291static struct platform_driver via_gpio_driver = {
    292	.driver = {
    293		.name = "viafb-gpio",
    294	},
    295	.probe = viafb_gpio_probe,
    296	.remove = viafb_gpio_remove,
    297};
    298
    299int viafb_gpio_init(void)
    300{
    301	return platform_driver_register(&via_gpio_driver);
    302}
    303
    304void viafb_gpio_exit(void)
    305{
    306	platform_driver_unregister(&via_gpio_driver);
    307}