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-em.c (9547B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Emma Mobile GPIO Support - GIO
      4 *
      5 *  Copyright (C) 2012 Magnus Damm
      6 */
      7
      8#include <linux/init.h>
      9#include <linux/platform_device.h>
     10#include <linux/spinlock.h>
     11#include <linux/interrupt.h>
     12#include <linux/ioport.h>
     13#include <linux/io.h>
     14#include <linux/irq.h>
     15#include <linux/irqdomain.h>
     16#include <linux/bitops.h>
     17#include <linux/err.h>
     18#include <linux/gpio/driver.h>
     19#include <linux/slab.h>
     20#include <linux/module.h>
     21#include <linux/pinctrl/consumer.h>
     22
     23struct em_gio_priv {
     24	void __iomem *base0;
     25	void __iomem *base1;
     26	spinlock_t sense_lock;
     27	struct platform_device *pdev;
     28	struct gpio_chip gpio_chip;
     29	struct irq_chip irq_chip;
     30	struct irq_domain *irq_domain;
     31};
     32
     33#define GIO_E1 0x00
     34#define GIO_E0 0x04
     35#define GIO_EM 0x04
     36#define GIO_OL 0x08
     37#define GIO_OH 0x0c
     38#define GIO_I 0x10
     39#define GIO_IIA 0x14
     40#define GIO_IEN 0x18
     41#define GIO_IDS 0x1c
     42#define GIO_IIM 0x1c
     43#define GIO_RAW 0x20
     44#define GIO_MST 0x24
     45#define GIO_IIR 0x28
     46
     47#define GIO_IDT0 0x40
     48#define GIO_IDT1 0x44
     49#define GIO_IDT2 0x48
     50#define GIO_IDT3 0x4c
     51#define GIO_RAWBL 0x50
     52#define GIO_RAWBH 0x54
     53#define GIO_IRBL 0x58
     54#define GIO_IRBH 0x5c
     55
     56#define GIO_IDT(n) (GIO_IDT0 + ((n) * 4))
     57
     58static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs)
     59{
     60	if (offs < GIO_IDT0)
     61		return ioread32(p->base0 + offs);
     62	else
     63		return ioread32(p->base1 + (offs - GIO_IDT0));
     64}
     65
     66static inline void em_gio_write(struct em_gio_priv *p, int offs,
     67				unsigned long value)
     68{
     69	if (offs < GIO_IDT0)
     70		iowrite32(value, p->base0 + offs);
     71	else
     72		iowrite32(value, p->base1 + (offs - GIO_IDT0));
     73}
     74
     75static void em_gio_irq_disable(struct irq_data *d)
     76{
     77	struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
     78
     79	em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d)));
     80}
     81
     82static void em_gio_irq_enable(struct irq_data *d)
     83{
     84	struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
     85
     86	em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
     87}
     88
     89static int em_gio_irq_reqres(struct irq_data *d)
     90{
     91	struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
     92	int ret;
     93
     94	ret = gpiochip_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d));
     95	if (ret) {
     96		dev_err(p->gpio_chip.parent,
     97			"unable to lock HW IRQ %lu for IRQ\n",
     98			irqd_to_hwirq(d));
     99		return ret;
    100	}
    101	return 0;
    102}
    103
    104static void em_gio_irq_relres(struct irq_data *d)
    105{
    106	struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
    107
    108	gpiochip_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d));
    109}
    110
    111
    112#define GIO_ASYNC(x) (x + 8)
    113
    114static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
    115	[IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00),
    116	[IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01),
    117	[IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02),
    118	[IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03),
    119	[IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04),
    120};
    121
    122static int em_gio_irq_set_type(struct irq_data *d, unsigned int type)
    123{
    124	unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK];
    125	struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
    126	unsigned int reg, offset, shift;
    127	unsigned long flags;
    128	unsigned long tmp;
    129
    130	if (!value)
    131		return -EINVAL;
    132
    133	offset = irqd_to_hwirq(d);
    134
    135	pr_debug("gio: sense irq = %d, mode = %d\n", offset, value);
    136
    137	/* 8 x 4 bit fields in 4 IDT registers */
    138	reg = GIO_IDT(offset >> 3);
    139	shift = (offset & 0x07) << 4;
    140
    141	spin_lock_irqsave(&p->sense_lock, flags);
    142
    143	/* disable the interrupt in IIA */
    144	tmp = em_gio_read(p, GIO_IIA);
    145	tmp &= ~BIT(offset);
    146	em_gio_write(p, GIO_IIA, tmp);
    147
    148	/* change the sense setting in IDT */
    149	tmp = em_gio_read(p, reg);
    150	tmp &= ~(0xf << shift);
    151	tmp |= value << shift;
    152	em_gio_write(p, reg, tmp);
    153
    154	/* clear pending interrupts */
    155	em_gio_write(p, GIO_IIR, BIT(offset));
    156
    157	/* enable the interrupt in IIA */
    158	tmp = em_gio_read(p, GIO_IIA);
    159	tmp |= BIT(offset);
    160	em_gio_write(p, GIO_IIA, tmp);
    161
    162	spin_unlock_irqrestore(&p->sense_lock, flags);
    163
    164	return 0;
    165}
    166
    167static irqreturn_t em_gio_irq_handler(int irq, void *dev_id)
    168{
    169	struct em_gio_priv *p = dev_id;
    170	unsigned long pending;
    171	unsigned int offset, irqs_handled = 0;
    172
    173	while ((pending = em_gio_read(p, GIO_MST))) {
    174		offset = __ffs(pending);
    175		em_gio_write(p, GIO_IIR, BIT(offset));
    176		generic_handle_domain_irq(p->irq_domain, offset);
    177		irqs_handled++;
    178	}
    179
    180	return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
    181}
    182
    183static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
    184{
    185	return gpiochip_get_data(chip);
    186}
    187
    188static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
    189{
    190	em_gio_write(gpio_to_priv(chip), GIO_E0, BIT(offset));
    191	return 0;
    192}
    193
    194static int em_gio_get(struct gpio_chip *chip, unsigned offset)
    195{
    196	return !!(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
    197}
    198
    199static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
    200			 unsigned shift, int value)
    201{
    202	/* upper 16 bits contains mask and lower 16 actual value */
    203	em_gio_write(gpio_to_priv(chip), reg,
    204		     (BIT(shift + 16)) | (value << shift));
    205}
    206
    207static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
    208{
    209	/* output is split into two registers */
    210	if (offset < 16)
    211		__em_gio_set(chip, GIO_OL, offset, value);
    212	else
    213		__em_gio_set(chip, GIO_OH, offset - 16, value);
    214}
    215
    216static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
    217				   int value)
    218{
    219	/* write GPIO value to output before selecting output mode of pin */
    220	em_gio_set(chip, offset, value);
    221	em_gio_write(gpio_to_priv(chip), GIO_E1, BIT(offset));
    222	return 0;
    223}
    224
    225static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
    226{
    227	return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
    228}
    229
    230static int em_gio_request(struct gpio_chip *chip, unsigned offset)
    231{
    232	return pinctrl_gpio_request(chip->base + offset);
    233}
    234
    235static void em_gio_free(struct gpio_chip *chip, unsigned offset)
    236{
    237	pinctrl_gpio_free(chip->base + offset);
    238
    239	/* Set the GPIO as an input to ensure that the next GPIO request won't
    240	* drive the GPIO pin as an output.
    241	*/
    242	em_gio_direction_input(chip, offset);
    243}
    244
    245static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq,
    246				 irq_hw_number_t hwirq)
    247{
    248	struct em_gio_priv *p = h->host_data;
    249
    250	pr_debug("gio: map hw irq = %d, irq = %d\n", (int)hwirq, irq);
    251
    252	irq_set_chip_data(irq, h->host_data);
    253	irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq);
    254	return 0;
    255}
    256
    257static const struct irq_domain_ops em_gio_irq_domain_ops = {
    258	.map	= em_gio_irq_domain_map,
    259	.xlate	= irq_domain_xlate_twocell,
    260};
    261
    262static void em_gio_irq_domain_remove(void *data)
    263{
    264	struct irq_domain *domain = data;
    265
    266	irq_domain_remove(domain);
    267}
    268
    269static int em_gio_probe(struct platform_device *pdev)
    270{
    271	struct em_gio_priv *p;
    272	struct gpio_chip *gpio_chip;
    273	struct irq_chip *irq_chip;
    274	struct device *dev = &pdev->dev;
    275	const char *name = dev_name(dev);
    276	unsigned int ngpios;
    277	int irq[2], ret;
    278
    279	p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
    280	if (!p)
    281		return -ENOMEM;
    282
    283	p->pdev = pdev;
    284	platform_set_drvdata(pdev, p);
    285	spin_lock_init(&p->sense_lock);
    286
    287	irq[0] = platform_get_irq(pdev, 0);
    288	if (irq[0] < 0)
    289		return irq[0];
    290
    291	irq[1] = platform_get_irq(pdev, 1);
    292	if (irq[1] < 0)
    293		return irq[1];
    294
    295	p->base0 = devm_platform_ioremap_resource(pdev, 0);
    296	if (IS_ERR(p->base0))
    297		return PTR_ERR(p->base0);
    298
    299	p->base1 = devm_platform_ioremap_resource(pdev, 1);
    300	if (IS_ERR(p->base1))
    301		return PTR_ERR(p->base1);
    302
    303	if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
    304		dev_err(dev, "Missing ngpios OF property\n");
    305		return -EINVAL;
    306	}
    307
    308	gpio_chip = &p->gpio_chip;
    309	gpio_chip->direction_input = em_gio_direction_input;
    310	gpio_chip->get = em_gio_get;
    311	gpio_chip->direction_output = em_gio_direction_output;
    312	gpio_chip->set = em_gio_set;
    313	gpio_chip->to_irq = em_gio_to_irq;
    314	gpio_chip->request = em_gio_request;
    315	gpio_chip->free = em_gio_free;
    316	gpio_chip->label = name;
    317	gpio_chip->parent = dev;
    318	gpio_chip->owner = THIS_MODULE;
    319	gpio_chip->base = -1;
    320	gpio_chip->ngpio = ngpios;
    321
    322	irq_chip = &p->irq_chip;
    323	irq_chip->name = "gpio-em";
    324	irq_chip->irq_mask = em_gio_irq_disable;
    325	irq_chip->irq_unmask = em_gio_irq_enable;
    326	irq_chip->irq_set_type = em_gio_irq_set_type;
    327	irq_chip->irq_request_resources = em_gio_irq_reqres;
    328	irq_chip->irq_release_resources = em_gio_irq_relres;
    329	irq_chip->flags	= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND;
    330
    331	p->irq_domain = irq_domain_add_simple(dev->of_node, ngpios, 0,
    332					      &em_gio_irq_domain_ops, p);
    333	if (!p->irq_domain) {
    334		dev_err(dev, "cannot initialize irq domain\n");
    335		return -ENXIO;
    336	}
    337
    338	ret = devm_add_action_or_reset(dev, em_gio_irq_domain_remove,
    339				       p->irq_domain);
    340	if (ret)
    341		return ret;
    342
    343	if (devm_request_irq(dev, irq[0], em_gio_irq_handler, 0, name, p)) {
    344		dev_err(dev, "failed to request low IRQ\n");
    345		return -ENOENT;
    346	}
    347
    348	if (devm_request_irq(dev, irq[1], em_gio_irq_handler, 0, name, p)) {
    349		dev_err(dev, "failed to request high IRQ\n");
    350		return -ENOENT;
    351	}
    352
    353	ret = devm_gpiochip_add_data(dev, gpio_chip, p);
    354	if (ret) {
    355		dev_err(dev, "failed to add GPIO controller\n");
    356		return ret;
    357	}
    358
    359	return 0;
    360}
    361
    362static const struct of_device_id em_gio_dt_ids[] = {
    363	{ .compatible = "renesas,em-gio", },
    364	{},
    365};
    366MODULE_DEVICE_TABLE(of, em_gio_dt_ids);
    367
    368static struct platform_driver em_gio_device_driver = {
    369	.probe		= em_gio_probe,
    370	.driver		= {
    371		.name	= "em_gio",
    372		.of_match_table = em_gio_dt_ids,
    373	}
    374};
    375
    376static int __init em_gio_init(void)
    377{
    378	return platform_driver_register(&em_gio_device_driver);
    379}
    380postcore_initcall(em_gio_init);
    381
    382static void __exit em_gio_exit(void)
    383{
    384	platform_driver_unregister(&em_gio_device_driver);
    385}
    386module_exit(em_gio_exit);
    387
    388MODULE_AUTHOR("Magnus Damm");
    389MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
    390MODULE_LICENSE("GPL v2");