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-lpc18xx.c (10188B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * GPIO driver for NXP LPC18xx/43xx.
      4 *
      5 * Copyright (C) 2018 Vladimir Zapolskiy <vz@mleia.com>
      6 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
      7 *
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/gpio/driver.h>
     12#include <linux/io.h>
     13#include <linux/irqdomain.h>
     14#include <linux/module.h>
     15#include <linux/of.h>
     16#include <linux/of_address.h>
     17#include <linux/of_gpio.h>
     18#include <linux/of_irq.h>
     19#include <linux/pinctrl/consumer.h>
     20#include <linux/platform_device.h>
     21
     22/* LPC18xx GPIO register offsets */
     23#define LPC18XX_REG_DIR(n)	(0x2000 + n * sizeof(u32))
     24
     25#define LPC18XX_MAX_PORTS	8
     26#define LPC18XX_PINS_PER_PORT	32
     27
     28/* LPC18xx GPIO pin interrupt controller register offsets */
     29#define LPC18XX_GPIO_PIN_IC_ISEL	0x00
     30#define LPC18XX_GPIO_PIN_IC_IENR	0x04
     31#define LPC18XX_GPIO_PIN_IC_SIENR	0x08
     32#define LPC18XX_GPIO_PIN_IC_CIENR	0x0c
     33#define LPC18XX_GPIO_PIN_IC_IENF	0x10
     34#define LPC18XX_GPIO_PIN_IC_SIENF	0x14
     35#define LPC18XX_GPIO_PIN_IC_CIENF	0x18
     36#define LPC18XX_GPIO_PIN_IC_RISE	0x1c
     37#define LPC18XX_GPIO_PIN_IC_FALL	0x20
     38#define LPC18XX_GPIO_PIN_IC_IST		0x24
     39
     40#define NR_LPC18XX_GPIO_PIN_IC_IRQS	8
     41
     42struct lpc18xx_gpio_pin_ic {
     43	void __iomem *base;
     44	struct irq_domain *domain;
     45	struct raw_spinlock lock;
     46};
     47
     48struct lpc18xx_gpio_chip {
     49	struct gpio_chip gpio;
     50	void __iomem *base;
     51	struct clk *clk;
     52	struct lpc18xx_gpio_pin_ic *pin_ic;
     53	spinlock_t lock;
     54};
     55
     56static inline void lpc18xx_gpio_pin_ic_isel(struct lpc18xx_gpio_pin_ic *ic,
     57					    u32 pin, bool set)
     58{
     59	u32 val = readl_relaxed(ic->base + LPC18XX_GPIO_PIN_IC_ISEL);
     60
     61	if (set)
     62		val &= ~BIT(pin);
     63	else
     64		val |= BIT(pin);
     65
     66	writel_relaxed(val, ic->base + LPC18XX_GPIO_PIN_IC_ISEL);
     67}
     68
     69static inline void lpc18xx_gpio_pin_ic_set(struct lpc18xx_gpio_pin_ic *ic,
     70					   u32 pin, u32 reg)
     71{
     72	writel_relaxed(BIT(pin), ic->base + reg);
     73}
     74
     75static void lpc18xx_gpio_pin_ic_mask(struct irq_data *d)
     76{
     77	struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
     78	u32 type = irqd_get_trigger_type(d);
     79
     80	raw_spin_lock(&ic->lock);
     81
     82	if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING)
     83		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
     84					LPC18XX_GPIO_PIN_IC_CIENR);
     85
     86	if (type & IRQ_TYPE_EDGE_FALLING)
     87		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
     88					LPC18XX_GPIO_PIN_IC_CIENF);
     89
     90	raw_spin_unlock(&ic->lock);
     91
     92	irq_chip_mask_parent(d);
     93}
     94
     95static void lpc18xx_gpio_pin_ic_unmask(struct irq_data *d)
     96{
     97	struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
     98	u32 type = irqd_get_trigger_type(d);
     99
    100	raw_spin_lock(&ic->lock);
    101
    102	if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING)
    103		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
    104					LPC18XX_GPIO_PIN_IC_SIENR);
    105
    106	if (type & IRQ_TYPE_EDGE_FALLING)
    107		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
    108					LPC18XX_GPIO_PIN_IC_SIENF);
    109
    110	raw_spin_unlock(&ic->lock);
    111
    112	irq_chip_unmask_parent(d);
    113}
    114
    115static void lpc18xx_gpio_pin_ic_eoi(struct irq_data *d)
    116{
    117	struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
    118	u32 type = irqd_get_trigger_type(d);
    119
    120	raw_spin_lock(&ic->lock);
    121
    122	if (type & IRQ_TYPE_EDGE_BOTH)
    123		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
    124					LPC18XX_GPIO_PIN_IC_IST);
    125
    126	raw_spin_unlock(&ic->lock);
    127
    128	irq_chip_eoi_parent(d);
    129}
    130
    131static int lpc18xx_gpio_pin_ic_set_type(struct irq_data *d, unsigned int type)
    132{
    133	struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
    134
    135	raw_spin_lock(&ic->lock);
    136
    137	if (type & IRQ_TYPE_LEVEL_HIGH) {
    138		lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true);
    139		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
    140					LPC18XX_GPIO_PIN_IC_SIENF);
    141	} else if (type & IRQ_TYPE_LEVEL_LOW) {
    142		lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true);
    143		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
    144					LPC18XX_GPIO_PIN_IC_CIENF);
    145	} else {
    146		lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, false);
    147	}
    148
    149	raw_spin_unlock(&ic->lock);
    150
    151	return 0;
    152}
    153
    154static struct irq_chip lpc18xx_gpio_pin_ic = {
    155	.name		= "LPC18xx GPIO pin",
    156	.irq_mask	= lpc18xx_gpio_pin_ic_mask,
    157	.irq_unmask	= lpc18xx_gpio_pin_ic_unmask,
    158	.irq_eoi	= lpc18xx_gpio_pin_ic_eoi,
    159	.irq_set_type	= lpc18xx_gpio_pin_ic_set_type,
    160	.flags		= IRQCHIP_SET_TYPE_MASKED,
    161};
    162
    163static int lpc18xx_gpio_pin_ic_domain_alloc(struct irq_domain *domain,
    164					    unsigned int virq,
    165					    unsigned int nr_irqs, void *data)
    166{
    167	struct irq_fwspec parent_fwspec, *fwspec = data;
    168	struct lpc18xx_gpio_pin_ic *ic = domain->host_data;
    169	irq_hw_number_t hwirq;
    170	int ret;
    171
    172	if (nr_irqs != 1)
    173		return -EINVAL;
    174
    175	hwirq = fwspec->param[0];
    176	if (hwirq >= NR_LPC18XX_GPIO_PIN_IC_IRQS)
    177		return -EINVAL;
    178
    179	/*
    180	 * All LPC18xx/LPC43xx GPIO pin hardware interrupts are translated
    181	 * into edge interrupts 32...39 on parent Cortex-M3/M4 NVIC
    182	 */
    183	parent_fwspec.fwnode = domain->parent->fwnode;
    184	parent_fwspec.param_count = 1;
    185	parent_fwspec.param[0] = hwirq + 32;
    186
    187	ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
    188	if (ret < 0) {
    189		pr_err("failed to allocate parent irq %u: %d\n",
    190		       parent_fwspec.param[0], ret);
    191		return ret;
    192	}
    193
    194	return irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
    195					     &lpc18xx_gpio_pin_ic, ic);
    196}
    197
    198static const struct irq_domain_ops lpc18xx_gpio_pin_ic_domain_ops = {
    199	.alloc	= lpc18xx_gpio_pin_ic_domain_alloc,
    200	.xlate	= irq_domain_xlate_twocell,
    201	.free	= irq_domain_free_irqs_common,
    202};
    203
    204static int lpc18xx_gpio_pin_ic_probe(struct lpc18xx_gpio_chip *gc)
    205{
    206	struct device *dev = gc->gpio.parent;
    207	struct irq_domain *parent_domain;
    208	struct device_node *parent_node;
    209	struct lpc18xx_gpio_pin_ic *ic;
    210	struct resource res;
    211	int ret, index;
    212
    213	parent_node = of_irq_find_parent(dev->of_node);
    214	if (!parent_node)
    215		return -ENXIO;
    216
    217	parent_domain = irq_find_host(parent_node);
    218	of_node_put(parent_node);
    219	if (!parent_domain)
    220		return -ENXIO;
    221
    222	ic = devm_kzalloc(dev, sizeof(*ic), GFP_KERNEL);
    223	if (!ic)
    224		return -ENOMEM;
    225
    226	index = of_property_match_string(dev->of_node, "reg-names",
    227					 "gpio-pin-ic");
    228	if (index < 0) {
    229		ret = -ENODEV;
    230		goto free_ic;
    231	}
    232
    233	ret = of_address_to_resource(dev->of_node, index, &res);
    234	if (ret < 0)
    235		goto free_ic;
    236
    237	ic->base = devm_ioremap_resource(dev, &res);
    238	if (IS_ERR(ic->base)) {
    239		ret = PTR_ERR(ic->base);
    240		goto free_ic;
    241	}
    242
    243	raw_spin_lock_init(&ic->lock);
    244
    245	ic->domain = irq_domain_add_hierarchy(parent_domain, 0,
    246					      NR_LPC18XX_GPIO_PIN_IC_IRQS,
    247					      dev->of_node,
    248					      &lpc18xx_gpio_pin_ic_domain_ops,
    249					      ic);
    250	if (!ic->domain) {
    251		pr_err("unable to add irq domain\n");
    252		ret = -ENODEV;
    253		goto free_iomap;
    254	}
    255
    256	gc->pin_ic = ic;
    257
    258	return 0;
    259
    260free_iomap:
    261	devm_iounmap(dev, ic->base);
    262free_ic:
    263	devm_kfree(dev, ic);
    264
    265	return ret;
    266}
    267
    268static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
    269{
    270	struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
    271	writeb(value ? 1 : 0, gc->base + offset);
    272}
    273
    274static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset)
    275{
    276	struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
    277	return !!readb(gc->base + offset);
    278}
    279
    280static int lpc18xx_gpio_direction(struct gpio_chip *chip, unsigned offset,
    281				  bool out)
    282{
    283	struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
    284	unsigned long flags;
    285	u32 port, pin, dir;
    286
    287	port = offset / LPC18XX_PINS_PER_PORT;
    288	pin  = offset % LPC18XX_PINS_PER_PORT;
    289
    290	spin_lock_irqsave(&gc->lock, flags);
    291	dir = readl(gc->base + LPC18XX_REG_DIR(port));
    292	if (out)
    293		dir |= BIT(pin);
    294	else
    295		dir &= ~BIT(pin);
    296	writel(dir, gc->base + LPC18XX_REG_DIR(port));
    297	spin_unlock_irqrestore(&gc->lock, flags);
    298
    299	return 0;
    300}
    301
    302static int lpc18xx_gpio_direction_input(struct gpio_chip *chip,
    303					unsigned offset)
    304{
    305	return lpc18xx_gpio_direction(chip, offset, false);
    306}
    307
    308static int lpc18xx_gpio_direction_output(struct gpio_chip *chip,
    309					 unsigned offset, int value)
    310{
    311	lpc18xx_gpio_set(chip, offset, value);
    312	return lpc18xx_gpio_direction(chip, offset, true);
    313}
    314
    315static const struct gpio_chip lpc18xx_chip = {
    316	.label			= "lpc18xx/43xx-gpio",
    317	.request		= gpiochip_generic_request,
    318	.free			= gpiochip_generic_free,
    319	.direction_input	= lpc18xx_gpio_direction_input,
    320	.direction_output	= lpc18xx_gpio_direction_output,
    321	.set			= lpc18xx_gpio_set,
    322	.get			= lpc18xx_gpio_get,
    323	.ngpio			= LPC18XX_MAX_PORTS * LPC18XX_PINS_PER_PORT,
    324	.owner			= THIS_MODULE,
    325};
    326
    327static int lpc18xx_gpio_probe(struct platform_device *pdev)
    328{
    329	struct device *dev = &pdev->dev;
    330	struct lpc18xx_gpio_chip *gc;
    331	int index, ret;
    332
    333	gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
    334	if (!gc)
    335		return -ENOMEM;
    336
    337	gc->gpio = lpc18xx_chip;
    338	platform_set_drvdata(pdev, gc);
    339
    340	index = of_property_match_string(dev->of_node, "reg-names", "gpio");
    341	if (index < 0) {
    342		/* To support backward compatibility take the first resource */
    343		gc->base = devm_platform_ioremap_resource(pdev, 0);
    344	} else {
    345		struct resource res;
    346
    347		ret = of_address_to_resource(dev->of_node, index, &res);
    348		if (ret < 0)
    349			return ret;
    350
    351		gc->base = devm_ioremap_resource(dev, &res);
    352	}
    353	if (IS_ERR(gc->base))
    354		return PTR_ERR(gc->base);
    355
    356	gc->clk = devm_clk_get(dev, NULL);
    357	if (IS_ERR(gc->clk)) {
    358		dev_err(dev, "input clock not found\n");
    359		return PTR_ERR(gc->clk);
    360	}
    361
    362	ret = clk_prepare_enable(gc->clk);
    363	if (ret) {
    364		dev_err(dev, "unable to enable clock\n");
    365		return ret;
    366	}
    367
    368	spin_lock_init(&gc->lock);
    369
    370	gc->gpio.parent = dev;
    371
    372	ret = devm_gpiochip_add_data(dev, &gc->gpio, gc);
    373	if (ret) {
    374		dev_err(dev, "failed to add gpio chip\n");
    375		clk_disable_unprepare(gc->clk);
    376		return ret;
    377	}
    378
    379	/* On error GPIO pin interrupt controller just won't be registered */
    380	lpc18xx_gpio_pin_ic_probe(gc);
    381
    382	return 0;
    383}
    384
    385static int lpc18xx_gpio_remove(struct platform_device *pdev)
    386{
    387	struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev);
    388
    389	if (gc->pin_ic)
    390		irq_domain_remove(gc->pin_ic->domain);
    391
    392	clk_disable_unprepare(gc->clk);
    393
    394	return 0;
    395}
    396
    397static const struct of_device_id lpc18xx_gpio_match[] = {
    398	{ .compatible = "nxp,lpc1850-gpio" },
    399	{ }
    400};
    401MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match);
    402
    403static struct platform_driver lpc18xx_gpio_driver = {
    404	.probe	= lpc18xx_gpio_probe,
    405	.remove	= lpc18xx_gpio_remove,
    406	.driver	= {
    407		.name		= "lpc18xx-gpio",
    408		.of_match_table	= lpc18xx_gpio_match,
    409	},
    410};
    411module_platform_driver(lpc18xx_gpio_driver);
    412
    413MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
    414MODULE_AUTHOR("Vladimir Zapolskiy <vz@mleia.com>");
    415MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx");
    416MODULE_LICENSE("GPL v2");