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-sch311x.c (11757B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * GPIO driver for the SMSC SCH311x Super-I/O chips
      4 *
      5 * Copyright (C) 2013 Bruno Randolf <br1@einfach.org>
      6 *
      7 * SuperIO functions and chip detection:
      8 * (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>.
      9 */
     10
     11#include <linux/ioport.h>
     12#include <linux/module.h>
     13#include <linux/kernel.h>
     14#include <linux/init.h>
     15#include <linux/platform_device.h>
     16#include <linux/gpio/driver.h>
     17#include <linux/bitops.h>
     18#include <linux/io.h>
     19
     20#define DRV_NAME			"gpio-sch311x"
     21
     22#define SCH311X_GPIO_CONF_DIR		BIT(0)
     23#define SCH311X_GPIO_CONF_INVERT	BIT(1)
     24#define SCH311X_GPIO_CONF_OPEN_DRAIN	BIT(7)
     25
     26#define SIO_CONFIG_KEY_ENTER		0x55
     27#define SIO_CONFIG_KEY_EXIT		0xaa
     28
     29#define GP1				0x4b
     30
     31static int sch311x_ioports[] = { 0x2e, 0x4e, 0x162e, 0x164e };
     32
     33static struct platform_device *sch311x_gpio_pdev;
     34
     35struct sch311x_pdev_data {		/* platform device data */
     36	unsigned short runtime_reg;	/* runtime register base address */
     37};
     38
     39struct sch311x_gpio_block {		/* one GPIO block runtime data */
     40	struct gpio_chip chip;
     41	unsigned short data_reg;	/* from definition below */
     42	unsigned short *config_regs;	/* pointer to definition below */
     43	unsigned short runtime_reg;	/* runtime register */
     44	spinlock_t lock;		/* lock for this GPIO block */
     45};
     46
     47struct sch311x_gpio_priv {		/* driver private data */
     48	struct sch311x_gpio_block blocks[6];
     49};
     50
     51struct sch311x_gpio_block_def {		/* register address definitions */
     52	unsigned short data_reg;
     53	unsigned short config_regs[8];
     54	unsigned short base;
     55};
     56
     57/* Note: some GPIOs are not available, these are marked with 0x00 */
     58
     59static struct sch311x_gpio_block_def sch311x_gpio_blocks[] = {
     60	{
     61		.data_reg = 0x4b,	/* GP1 */
     62		.config_regs = {0x23, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2a, 0x2b},
     63		.base = 10,
     64	},
     65	{
     66		.data_reg = 0x4c,	/* GP2 */
     67		.config_regs = {0x00, 0x2c, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x32},
     68		.base = 20,
     69	},
     70	{
     71		.data_reg = 0x4d,	/* GP3 */
     72		.config_regs = {0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x39, 0x3a},
     73		.base = 30,
     74	},
     75	{
     76		.data_reg = 0x4e,	/* GP4 */
     77		.config_regs = {0x3b, 0x00, 0x3d, 0x00, 0x6e, 0x6f, 0x72, 0x73},
     78		.base = 40,
     79	},
     80	{
     81		.data_reg = 0x4f,	/* GP5 */
     82		.config_regs = {0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46},
     83		.base = 50,
     84	},
     85	{
     86		.data_reg = 0x50,	/* GP6 */
     87		.config_regs = {0x47, 0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59},
     88		.base = 60,
     89	},
     90};
     91
     92/*
     93 *	Super-IO functions
     94 */
     95
     96static inline int sch311x_sio_enter(int sio_config_port)
     97{
     98	/* Don't step on other drivers' I/O space by accident. */
     99	if (!request_muxed_region(sio_config_port, 2, DRV_NAME)) {
    100		pr_err(DRV_NAME "I/O address 0x%04x already in use\n",
    101		       sio_config_port);
    102		return -EBUSY;
    103	}
    104
    105	outb(SIO_CONFIG_KEY_ENTER, sio_config_port);
    106	return 0;
    107}
    108
    109static inline void sch311x_sio_exit(int sio_config_port)
    110{
    111	outb(SIO_CONFIG_KEY_EXIT, sio_config_port);
    112	release_region(sio_config_port, 2);
    113}
    114
    115static inline int sch311x_sio_inb(int sio_config_port, int reg)
    116{
    117	outb(reg, sio_config_port);
    118	return inb(sio_config_port + 1);
    119}
    120
    121static inline void sch311x_sio_outb(int sio_config_port, int reg, int val)
    122{
    123	outb(reg, sio_config_port);
    124	outb(val, sio_config_port + 1);
    125}
    126
    127
    128/*
    129 *	GPIO functions
    130 */
    131
    132static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset)
    133{
    134	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
    135
    136	if (block->config_regs[offset] == 0) /* GPIO is not available */
    137		return -ENODEV;
    138
    139	if (!request_region(block->runtime_reg + block->config_regs[offset],
    140			    1, DRV_NAME)) {
    141		dev_err(chip->parent, "Failed to request region 0x%04x.\n",
    142			block->runtime_reg + block->config_regs[offset]);
    143		return -EBUSY;
    144	}
    145	return 0;
    146}
    147
    148static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset)
    149{
    150	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
    151
    152	if (block->config_regs[offset] == 0) /* GPIO is not available */
    153		return;
    154
    155	release_region(block->runtime_reg + block->config_regs[offset], 1);
    156}
    157
    158static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset)
    159{
    160	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
    161	u8 data;
    162
    163	spin_lock(&block->lock);
    164	data = inb(block->runtime_reg + block->data_reg);
    165	spin_unlock(&block->lock);
    166
    167	return !!(data & BIT(offset));
    168}
    169
    170static void __sch311x_gpio_set(struct sch311x_gpio_block *block,
    171			       unsigned offset, int value)
    172{
    173	u8 data = inb(block->runtime_reg + block->data_reg);
    174	if (value)
    175		data |= BIT(offset);
    176	else
    177		data &= ~BIT(offset);
    178	outb(data, block->runtime_reg + block->data_reg);
    179}
    180
    181static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
    182			     int value)
    183{
    184	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
    185
    186	spin_lock(&block->lock);
    187	__sch311x_gpio_set(block, offset, value);
    188	spin_unlock(&block->lock);
    189}
    190
    191static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
    192{
    193	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
    194	u8 data;
    195
    196	spin_lock(&block->lock);
    197	data = inb(block->runtime_reg + block->config_regs[offset]);
    198	data |= SCH311X_GPIO_CONF_DIR;
    199	outb(data, block->runtime_reg + block->config_regs[offset]);
    200	spin_unlock(&block->lock);
    201
    202	return 0;
    203}
    204
    205static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
    206				      int value)
    207{
    208	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
    209	u8 data;
    210
    211	spin_lock(&block->lock);
    212
    213	data = inb(block->runtime_reg + block->config_regs[offset]);
    214	data &= ~SCH311X_GPIO_CONF_DIR;
    215	outb(data, block->runtime_reg + block->config_regs[offset]);
    216	__sch311x_gpio_set(block, offset, value);
    217
    218	spin_unlock(&block->lock);
    219	return 0;
    220}
    221
    222static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
    223{
    224	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
    225	u8 data;
    226
    227	spin_lock(&block->lock);
    228	data = inb(block->runtime_reg + block->config_regs[offset]);
    229	spin_unlock(&block->lock);
    230
    231	if (data & SCH311X_GPIO_CONF_DIR)
    232		return GPIO_LINE_DIRECTION_IN;
    233
    234	return GPIO_LINE_DIRECTION_OUT;
    235}
    236
    237static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
    238				   unsigned long config)
    239{
    240	struct sch311x_gpio_block *block = gpiochip_get_data(chip);
    241	enum pin_config_param param = pinconf_to_config_param(config);
    242	u8 data;
    243
    244	switch (param) {
    245	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
    246		spin_lock(&block->lock);
    247		data = inb(block->runtime_reg + block->config_regs[offset]);
    248		data |= SCH311X_GPIO_CONF_OPEN_DRAIN;
    249		outb(data, block->runtime_reg + block->config_regs[offset]);
    250		spin_unlock(&block->lock);
    251		return 0;
    252	case PIN_CONFIG_DRIVE_PUSH_PULL:
    253		spin_lock(&block->lock);
    254		data = inb(block->runtime_reg + block->config_regs[offset]);
    255		data &= ~SCH311X_GPIO_CONF_OPEN_DRAIN;
    256		outb(data, block->runtime_reg + block->config_regs[offset]);
    257		spin_unlock(&block->lock);
    258		return 0;
    259	default:
    260		break;
    261	}
    262	return -ENOTSUPP;
    263}
    264
    265static int sch311x_gpio_probe(struct platform_device *pdev)
    266{
    267	struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev);
    268	struct sch311x_gpio_priv *priv;
    269	struct sch311x_gpio_block *block;
    270	int err, i;
    271
    272	/* we can register all GPIO data registers at once */
    273	if (!devm_request_region(&pdev->dev, pdata->runtime_reg + GP1, 6,
    274		DRV_NAME)) {
    275		dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n",
    276			pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5);
    277		return -EBUSY;
    278	}
    279
    280	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    281	if (!priv)
    282		return -ENOMEM;
    283
    284	platform_set_drvdata(pdev, priv);
    285
    286	for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
    287		block = &priv->blocks[i];
    288
    289		spin_lock_init(&block->lock);
    290
    291		block->chip.label = DRV_NAME;
    292		block->chip.owner = THIS_MODULE;
    293		block->chip.request = sch311x_gpio_request;
    294		block->chip.free = sch311x_gpio_free;
    295		block->chip.direction_input = sch311x_gpio_direction_in;
    296		block->chip.direction_output = sch311x_gpio_direction_out;
    297		block->chip.get_direction = sch311x_gpio_get_direction;
    298		block->chip.set_config = sch311x_gpio_set_config;
    299		block->chip.get = sch311x_gpio_get;
    300		block->chip.set = sch311x_gpio_set;
    301		block->chip.ngpio = 8;
    302		block->chip.parent = &pdev->dev;
    303		block->chip.base = sch311x_gpio_blocks[i].base;
    304		block->config_regs = sch311x_gpio_blocks[i].config_regs;
    305		block->data_reg = sch311x_gpio_blocks[i].data_reg;
    306		block->runtime_reg = pdata->runtime_reg;
    307
    308		err = gpiochip_add_data(&block->chip, block);
    309		if (err < 0) {
    310			dev_err(&pdev->dev,
    311				"Could not register gpiochip, %d\n", err);
    312			goto exit_err;
    313		}
    314		dev_info(&pdev->dev,
    315			 "SMSC SCH311x GPIO block %d registered.\n", i);
    316	}
    317
    318	return 0;
    319
    320exit_err:
    321	/* release already registered chips */
    322	for (--i; i >= 0; i--)
    323		gpiochip_remove(&priv->blocks[i].chip);
    324	return err;
    325}
    326
    327static int sch311x_gpio_remove(struct platform_device *pdev)
    328{
    329	struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
    330	int i;
    331
    332	for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
    333		gpiochip_remove(&priv->blocks[i].chip);
    334		dev_info(&pdev->dev,
    335			 "SMSC SCH311x GPIO block %d unregistered.\n", i);
    336	}
    337	return 0;
    338}
    339
    340static struct platform_driver sch311x_gpio_driver = {
    341	.driver.name	= DRV_NAME,
    342	.probe		= sch311x_gpio_probe,
    343	.remove		= sch311x_gpio_remove,
    344};
    345
    346
    347/*
    348 *	Init & exit routines
    349 */
    350
    351static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
    352{
    353	int err = 0, reg;
    354	unsigned short base_addr;
    355	u8 dev_id;
    356
    357	err = sch311x_sio_enter(sio_config_port);
    358	if (err)
    359		return err;
    360
    361	/* Check device ID. */
    362	reg = sch311x_sio_inb(sio_config_port, 0x20);
    363	switch (reg) {
    364	case 0x7c: /* SCH3112 */
    365		dev_id = 2;
    366		break;
    367	case 0x7d: /* SCH3114 */
    368		dev_id = 4;
    369		break;
    370	case 0x7f: /* SCH3116 */
    371		dev_id = 6;
    372		break;
    373	default:
    374		err = -ENODEV;
    375		goto exit;
    376	}
    377
    378	/* Select logical device A (runtime registers) */
    379	sch311x_sio_outb(sio_config_port, 0x07, 0x0a);
    380
    381	/* Check if Logical Device Register is currently active */
    382	if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
    383		pr_info("Seems that LDN 0x0a is not active...\n");
    384
    385	/* Get the base address of the runtime registers */
    386	base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
    387			   sch311x_sio_inb(sio_config_port, 0x61);
    388	if (!base_addr) {
    389		pr_err("Base address not set\n");
    390		err = -ENODEV;
    391		goto exit;
    392	}
    393	*addr = base_addr;
    394
    395	pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
    396
    397exit:
    398	sch311x_sio_exit(sio_config_port);
    399	return err;
    400}
    401
    402static int __init sch311x_gpio_pdev_add(const unsigned short addr)
    403{
    404	struct sch311x_pdev_data pdata;
    405	int err;
    406
    407	pdata.runtime_reg = addr;
    408
    409	sch311x_gpio_pdev = platform_device_alloc(DRV_NAME, -1);
    410	if (!sch311x_gpio_pdev)
    411		return -ENOMEM;
    412
    413	err = platform_device_add_data(sch311x_gpio_pdev,
    414				       &pdata, sizeof(pdata));
    415	if (err) {
    416		pr_err(DRV_NAME "Platform data allocation failed\n");
    417		goto err;
    418	}
    419
    420	err = platform_device_add(sch311x_gpio_pdev);
    421	if (err) {
    422		pr_err(DRV_NAME "Device addition failed\n");
    423		goto err;
    424	}
    425	return 0;
    426
    427err:
    428	platform_device_put(sch311x_gpio_pdev);
    429	return err;
    430}
    431
    432static int __init sch311x_gpio_init(void)
    433{
    434	int err, i;
    435	unsigned short addr = 0;
    436
    437	for (i = 0; i < ARRAY_SIZE(sch311x_ioports); i++)
    438		if (sch311x_detect(sch311x_ioports[i], &addr) == 0)
    439			break;
    440
    441	if (!addr)
    442		return -ENODEV;
    443
    444	err = platform_driver_register(&sch311x_gpio_driver);
    445	if (err)
    446		return err;
    447
    448	err = sch311x_gpio_pdev_add(addr);
    449	if (err)
    450		goto unreg_platform_driver;
    451
    452	return 0;
    453
    454unreg_platform_driver:
    455	platform_driver_unregister(&sch311x_gpio_driver);
    456	return err;
    457}
    458
    459static void __exit sch311x_gpio_exit(void)
    460{
    461	platform_device_unregister(sch311x_gpio_pdev);
    462	platform_driver_unregister(&sch311x_gpio_driver);
    463}
    464
    465module_init(sch311x_gpio_init);
    466module_exit(sch311x_gpio_exit);
    467
    468MODULE_AUTHOR("Bruno Randolf <br1@einfach.org>");
    469MODULE_DESCRIPTION("SMSC SCH311x GPIO Driver");
    470MODULE_LICENSE("GPL");
    471MODULE_ALIAS("platform:gpio-sch311x");