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


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
      4 * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
      5 * Copyright (C) 2009-2010 Florian Fainelli <florian@openwrt.org>
      6 */
      7
      8#include <linux/init.h>
      9#include <linux/export.h>
     10#include <linux/gpio.h>
     11
     12#include <asm/mach-ar7/ar7.h>
     13
     14#define AR7_GPIO_MAX 32
     15#define TITAN_GPIO_MAX 51
     16
     17struct ar7_gpio_chip {
     18	void __iomem		*regs;
     19	struct gpio_chip	chip;
     20};
     21
     22static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
     23{
     24	struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
     25	void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT;
     26
     27	return !!(readl(gpio_in) & (1 << gpio));
     28}
     29
     30static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
     31{
     32	struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
     33	void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0;
     34	void __iomem *gpio_in1 = gpch->regs + TITAN_GPIO_INPUT_1;
     35
     36	return readl(gpio >> 5 ? gpio_in1 : gpio_in0) & (1 << (gpio & 0x1f));
     37}
     38
     39static void ar7_gpio_set_value(struct gpio_chip *chip,
     40				unsigned gpio, int value)
     41{
     42	struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
     43	void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT;
     44	unsigned tmp;
     45
     46	tmp = readl(gpio_out) & ~(1 << gpio);
     47	if (value)
     48		tmp |= 1 << gpio;
     49	writel(tmp, gpio_out);
     50}
     51
     52static void titan_gpio_set_value(struct gpio_chip *chip,
     53				unsigned gpio, int value)
     54{
     55	struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
     56	void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0;
     57	void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1;
     58	unsigned tmp;
     59
     60	tmp = readl(gpio >> 5 ? gpio_out1 : gpio_out0) & ~(1 << (gpio & 0x1f));
     61	if (value)
     62		tmp |= 1 << (gpio & 0x1f);
     63	writel(tmp, gpio >> 5 ? gpio_out1 : gpio_out0);
     64}
     65
     66static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
     67{
     68	struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
     69	void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR;
     70
     71	writel(readl(gpio_dir) | (1 << gpio), gpio_dir);
     72
     73	return 0;
     74}
     75
     76static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
     77{
     78	struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
     79	void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
     80	void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1;
     81
     82	if (gpio >= TITAN_GPIO_MAX)
     83		return -EINVAL;
     84
     85	writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) | (1 << (gpio & 0x1f)),
     86			gpio >> 5 ? gpio_dir1 : gpio_dir0);
     87	return 0;
     88}
     89
     90static int ar7_gpio_direction_output(struct gpio_chip *chip,
     91					unsigned gpio, int value)
     92{
     93	struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
     94	void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR;
     95
     96	ar7_gpio_set_value(chip, gpio, value);
     97	writel(readl(gpio_dir) & ~(1 << gpio), gpio_dir);
     98
     99	return 0;
    100}
    101
    102static int titan_gpio_direction_output(struct gpio_chip *chip,
    103					unsigned gpio, int value)
    104{
    105	struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
    106	void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
    107	void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1;
    108
    109	if (gpio >= TITAN_GPIO_MAX)
    110		return -EINVAL;
    111
    112	titan_gpio_set_value(chip, gpio, value);
    113	writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) & ~(1 <<
    114		(gpio & 0x1f)), gpio >> 5 ? gpio_dir1 : gpio_dir0);
    115
    116	return 0;
    117}
    118
    119static struct ar7_gpio_chip ar7_gpio_chip = {
    120	.chip = {
    121		.label			= "ar7-gpio",
    122		.direction_input	= ar7_gpio_direction_input,
    123		.direction_output	= ar7_gpio_direction_output,
    124		.set			= ar7_gpio_set_value,
    125		.get			= ar7_gpio_get_value,
    126		.base			= 0,
    127		.ngpio			= AR7_GPIO_MAX,
    128	}
    129};
    130
    131static struct ar7_gpio_chip titan_gpio_chip = {
    132	.chip = {
    133		.label			= "titan-gpio",
    134		.direction_input	= titan_gpio_direction_input,
    135		.direction_output	= titan_gpio_direction_output,
    136		.set			= titan_gpio_set_value,
    137		.get			= titan_gpio_get_value,
    138		.base			= 0,
    139		.ngpio			= TITAN_GPIO_MAX,
    140	}
    141};
    142
    143static inline int ar7_gpio_enable_ar7(unsigned gpio)
    144{
    145	void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE;
    146
    147	writel(readl(gpio_en) | (1 << gpio), gpio_en);
    148
    149	return 0;
    150}
    151
    152static inline int ar7_gpio_enable_titan(unsigned gpio)
    153{
    154	void __iomem *gpio_en0 = titan_gpio_chip.regs  + TITAN_GPIO_ENBL_0;
    155	void __iomem *gpio_en1 = titan_gpio_chip.regs  + TITAN_GPIO_ENBL_1;
    156
    157	writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) | (1 << (gpio & 0x1f)),
    158		gpio >> 5 ? gpio_en1 : gpio_en0);
    159
    160	return 0;
    161}
    162
    163int ar7_gpio_enable(unsigned gpio)
    164{
    165	return ar7_is_titan() ? ar7_gpio_enable_titan(gpio) :
    166				ar7_gpio_enable_ar7(gpio);
    167}
    168EXPORT_SYMBOL(ar7_gpio_enable);
    169
    170static inline int ar7_gpio_disable_ar7(unsigned gpio)
    171{
    172	void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE;
    173
    174	writel(readl(gpio_en) & ~(1 << gpio), gpio_en);
    175
    176	return 0;
    177}
    178
    179static inline int ar7_gpio_disable_titan(unsigned gpio)
    180{
    181	void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0;
    182	void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1;
    183
    184	writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) & ~(1 << (gpio & 0x1f)),
    185			gpio >> 5 ? gpio_en1 : gpio_en0);
    186
    187	return 0;
    188}
    189
    190int ar7_gpio_disable(unsigned gpio)
    191{
    192	return ar7_is_titan() ? ar7_gpio_disable_titan(gpio) :
    193				ar7_gpio_disable_ar7(gpio);
    194}
    195EXPORT_SYMBOL(ar7_gpio_disable);
    196
    197struct titan_gpio_cfg {
    198	u32 reg;
    199	u32 shift;
    200	u32 func;
    201};
    202
    203static const struct titan_gpio_cfg titan_gpio_table[] = {
    204	/* reg, start bit, mux value */
    205	{4, 24, 1},
    206	{4, 26, 1},
    207	{4, 28, 1},
    208	{4, 30, 1},
    209	{5, 6, 1},
    210	{5, 8, 1},
    211	{5, 10, 1},
    212	{5, 12, 1},
    213	{7, 14, 3},
    214	{7, 16, 3},
    215	{7, 18, 3},
    216	{7, 20, 3},
    217	{7, 22, 3},
    218	{7, 26, 3},
    219	{7, 28, 3},
    220	{7, 30, 3},
    221	{8, 0, 3},
    222	{8, 2, 3},
    223	{8, 4, 3},
    224	{8, 10, 3},
    225	{8, 14, 3},
    226	{8, 16, 3},
    227	{8, 18, 3},
    228	{8, 20, 3},
    229	{9, 8, 3},
    230	{9, 10, 3},
    231	{9, 12, 3},
    232	{9, 14, 3},
    233	{9, 18, 3},
    234	{9, 20, 3},
    235	{9, 24, 3},
    236	{9, 26, 3},
    237	{9, 28, 3},
    238	{9, 30, 3},
    239	{10, 0, 3},
    240	{10, 2, 3},
    241	{10, 8, 3},
    242	{10, 10, 3},
    243	{10, 12, 3},
    244	{10, 14, 3},
    245	{13, 12, 3},
    246	{13, 14, 3},
    247	{13, 16, 3},
    248	{13, 18, 3},
    249	{13, 24, 3},
    250	{13, 26, 3},
    251	{13, 28, 3},
    252	{13, 30, 3},
    253	{14, 2, 3},
    254	{14, 6, 3},
    255	{14, 8, 3},
    256	{14, 12, 3}
    257};
    258
    259static int titan_gpio_pinsel(unsigned gpio)
    260{
    261	struct titan_gpio_cfg gpio_cfg;
    262	u32 mux_status, pin_sel_reg, tmp;
    263	void __iomem *pin_sel = (void __iomem *)KSEG1ADDR(AR7_REGS_PINSEL);
    264
    265	if (gpio >= ARRAY_SIZE(titan_gpio_table))
    266		return -EINVAL;
    267
    268	gpio_cfg = titan_gpio_table[gpio];
    269	pin_sel_reg = gpio_cfg.reg - 1;
    270
    271	mux_status = (readl(pin_sel + pin_sel_reg) >> gpio_cfg.shift) & 0x3;
    272
    273	/* Check the mux status */
    274	if (!((mux_status == 0) || (mux_status == gpio_cfg.func)))
    275		return 0;
    276
    277	/* Set the pin sel value */
    278	tmp = readl(pin_sel + pin_sel_reg);
    279	tmp |= ((gpio_cfg.func & 0x3) << gpio_cfg.shift);
    280	writel(tmp, pin_sel + pin_sel_reg);
    281
    282	return 0;
    283}
    284
    285/* Perform minimal Titan GPIO configuration */
    286static void titan_gpio_init(void)
    287{
    288	unsigned i;
    289
    290	for (i = 44; i < 48; i++) {
    291		titan_gpio_pinsel(i);
    292		ar7_gpio_enable_titan(i);
    293		titan_gpio_direction_input(&titan_gpio_chip.chip, i);
    294	}
    295}
    296
    297int __init ar7_gpio_init(void)
    298{
    299	int ret;
    300	struct ar7_gpio_chip *gpch;
    301	unsigned size;
    302
    303	if (!ar7_is_titan()) {
    304		gpch = &ar7_gpio_chip;
    305		size = 0x10;
    306	} else {
    307		gpch = &titan_gpio_chip;
    308		size = 0x1f;
    309	}
    310
    311	gpch->regs = ioremap(AR7_REGS_GPIO, size);
    312	if (!gpch->regs) {
    313		printk(KERN_ERR "%s: failed to ioremap regs\n",
    314					gpch->chip.label);
    315		return -ENOMEM;
    316	}
    317
    318	ret = gpiochip_add_data(&gpch->chip, gpch);
    319	if (ret) {
    320		printk(KERN_ERR "%s: failed to add gpiochip\n",
    321					gpch->chip.label);
    322		iounmap(gpch->regs);
    323		return ret;
    324	}
    325	printk(KERN_INFO "%s: registered %d GPIOs\n",
    326				gpch->chip.label, gpch->chip.ngpio);
    327
    328	if (ar7_is_titan())
    329		titan_gpio_init();
    330
    331	return ret;
    332}