Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / u-boot / drivers / gpio / altera_pio.c
diff --git a/qemu/roms/u-boot/drivers/gpio/altera_pio.c b/qemu/roms/u-boot/drivers/gpio/altera_pio.c
new file mode 100644 (file)
index 0000000..3ca5907
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Driver for Altera's PIO ip core
+ *
+ * Copyright (C) 2011  Missing Link Electronics
+ *                     Joachim Foerster <joachim@missinglinkelectronics.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ *
+ * To use this driver, in your board's config. header:
+ * #define CONFIG_ALTERA_PIO
+ * #define CONFIG_SYS_ALTERA_PIO_NUM <number-of-pio-cores>
+ * #define CONFIG_SYS_ALTERA_PIO_GPIO_NUM <total-number-of-gpios>
+ * And in your board's early setup routine:
+ * altera_pio_init(<baseaddr>, <width>, 'i'|'o'|'t',
+ *                 <reset-value>, <neg-mask>, "label");
+ *  - 'i'|'o'|'t': PIO is input-only/output-only/tri-state
+ *  - <reset-value>: for correct initial status display, output-only
+ *  - <neg-mask> is meant to be used to in cases of active-low
+ *    GPIOs, such as LEDs and buttons (on/pressed == 0). Each bit
+ *    which is 1 in <neg-mask> inverts the corresponding GPIO's value
+ *    before set/after get. So: gpio_set_value(gpio, 1) => LED on .
+ *
+ * Do NOT define CONFIG_SYS_GPIO_BASE !
+ *
+ * Optionally, in your board's config. header:
+ * - To force a GPIO numbering scheme like in Linux ...
+ * #define CONFIG_GPIO_DOWNTO_NUMBERING
+ * ... starting with 255 (default)
+ * #define CONFIG_GPIO_DOWNTO_MAX 255
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+#ifdef CONFIG_GPIO_DOWNTO_NUMBERING
+#ifndef CONFIG_GPIO_DOWNTO_MAX
+#define CONFIG_GPIO_DOWNTO_MAX 255
+#endif
+#endif
+
+#define ALTERA_PIO_DATA                0x0
+#define ALTERA_PIO_DIR         0x4
+
+#define GPIO_LABEL_SIZE                9
+
+
+static struct altera_pio {
+       u32 base;
+       u8 width;
+       char iot;
+       u32 negmask;
+       u32 sh_data;
+       u32 sh_dir;
+       int gidx;
+       char label[GPIO_LABEL_SIZE];
+} pios[CONFIG_SYS_ALTERA_PIO_NUM];
+
+static int pio_num;
+
+static struct altera_pio_gpio {
+       unsigned num;
+       struct altera_pio *pio;
+       char reqlabel[GPIO_LABEL_SIZE];
+} gpios[CONFIG_SYS_ALTERA_PIO_GPIO_NUM];
+
+static int pio_gpio_num;
+
+
+static int altera_pio_gidx(unsigned gpio)
+{
+       int i;
+
+       for (i = 0; i < pio_gpio_num; ++i) {
+               if (gpio == gpios[i].num)
+                       break;
+       }
+       if (i >= pio_gpio_num)
+               return -1;
+       return i;
+}
+
+static struct altera_pio *altera_pio_get_and_mask(unsigned gpio, u32 *mask)
+{
+       int gidx = altera_pio_gidx(gpio);
+       if (gidx < 0)
+               return NULL;
+       if (mask)
+               *mask = 1 << (gidx - gpios[gidx].pio->gidx);
+       return gpios[gidx].pio;
+}
+
+#define altera_pio_use_gidx(_gidx, _reqlabel) \
+       { strncpy(gpios[_gidx].reqlabel, _reqlabel, GPIO_LABEL_SIZE); }
+#define altera_pio_unuse_gidx(_gidx) { gpios[_gidx].reqlabel[0] = '\0'; }
+#define altera_pio_is_gidx_used(_gidx) (gpios[_gidx].reqlabel[0] != '\0')
+
+static int altera_pio_gpio_init(struct altera_pio *pio, u8 width)
+{
+       u8 gidx = pio_gpio_num;
+       int i;
+
+       if (!width)
+               return -1;
+       if ((pio_gpio_num + width) > CONFIG_SYS_ALTERA_PIO_GPIO_NUM)
+               return -1;
+
+       for (i = 0; i < width; ++i) {
+#ifdef CONFIG_GPIO_DOWNTO_NUMBERING
+               gpios[pio_gpio_num + i].num = \
+                       CONFIG_GPIO_DOWNTO_MAX + 1 - gidx - width + i;
+#else
+               gpios[pio_gpio_num + i].num = pio_gpio_num + i;
+#endif
+               gpios[pio_gpio_num + i].pio = pio;
+               altera_pio_unuse_gidx(pio_gpio_num + i);
+       }
+       pio_gpio_num += width;
+       return gidx;
+}
+
+int altera_pio_init(u32 base, u8 width, char iot, u32 rstval, u32 negmask,
+                const char *label)
+{
+       if (pio_num >= CONFIG_SYS_ALTERA_PIO_NUM)
+               return -1;
+
+       pios[pio_num].base = base;
+       pios[pio_num].width = width;
+       pios[pio_num].iot = iot;
+       switch (iot) {
+       case 'i':
+               /* input only */
+               pios[pio_num].sh_dir = 0;
+               pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA);
+               break;
+       case 'o':
+               /* output only */
+               pios[pio_num].sh_dir = 0xffffffff & ((1 << width) - 1);
+               pios[pio_num].sh_data = rstval;
+               break;
+       case 't':
+               /* bidir, tri-state */
+               pios[pio_num].sh_dir = readl(base + ALTERA_PIO_DIR);
+               pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA);
+               break;
+       default:
+               return -1;
+       }
+       pios[pio_num].negmask = negmask & ((1 << width) - 1);
+       pios[pio_num].gidx = altera_pio_gpio_init(&pios[pio_num], width);
+       if (pios[pio_num].gidx < 0)
+               return -1;
+       strncpy(pios[pio_num].label, label, GPIO_LABEL_SIZE);
+       return pio_num++;
+}
+
+void altera_pio_info(void)
+{
+       int i;
+       int j;
+       int gidx;
+       u32 mask;
+
+       for (i = 0; i < pio_num; ++i) {
+               printf("Altera PIO % 2d, @0x%08x, "
+                       "width: %u, label: %s\n",
+                      i, pios[i].base, pios[i].width, pios[i].label);
+               gidx = pios[i].gidx;
+               for (j = gidx; j < (gidx + pios[i].width); ++j) {
+                       mask = 1 << (j - gidx);
+                       printf("\tGPIO % 4d: %s %s [%c] %s\n",
+                               gpios[j].num,
+                               gpios[j].pio->sh_dir & mask ? "out" : " in",
+                               gpio_get_value(gpios[j].num) ? "set" : "clr",
+                               altera_pio_is_gidx_used(j) ? 'x' : ' ',
+                               gpios[j].reqlabel);
+               }
+       }
+}
+
+
+int gpio_request(unsigned gpio, const char *label)
+{
+       int gidx = altera_pio_gidx(gpio);
+       if (gidx < 0)
+               return gidx;
+       if (altera_pio_is_gidx_used(gidx))
+               return -1;
+
+       altera_pio_use_gidx(gidx, label);
+       return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+       int gidx = altera_pio_gidx(gpio);
+       if (gidx < 0)
+               return gidx;
+       if (!altera_pio_is_gidx_used(gidx))
+               return -1;
+
+       altera_pio_unuse_gidx(gidx);
+       return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+       u32 mask;
+       struct altera_pio *pio;
+
+       pio = altera_pio_get_and_mask(gpio, &mask);
+       if (!pio)
+               return -1;
+       if (pio->iot == 'o')
+               return -1;
+
+       writel(pio->sh_dir &= ~mask, pio->base + ALTERA_PIO_DIR);
+       return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+       u32 mask;
+       struct altera_pio *pio;
+
+       pio = altera_pio_get_and_mask(gpio, &mask);
+       if (!pio)
+               return -1;
+       if (pio->iot == 'i')
+               return -1;
+
+       value = (pio->negmask & mask) ? !value : value;
+       if (value)
+               pio->sh_data |= mask;
+       else
+               pio->sh_data &= ~mask;
+       writel(pio->sh_data, pio->base + ALTERA_PIO_DATA);
+       writel(pio->sh_dir |= mask, pio->base + ALTERA_PIO_DIR);
+       return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+       u32 mask;
+       struct altera_pio *pio;
+       u32 val;
+
+       pio = altera_pio_get_and_mask(gpio, &mask);
+       if (!pio)
+               return -1;
+
+       if ((pio->sh_dir & mask) || (pio->iot == 'o'))
+               val = pio->sh_data & mask;
+       else
+               val = readl(pio->base + ALTERA_PIO_DATA) & mask;
+       return (pio->negmask & mask) ? !val : val;
+}
+
+void gpio_set_value(unsigned gpio, int value)
+{
+       u32 mask;
+       struct altera_pio *pio;
+
+       pio = altera_pio_get_and_mask(gpio, &mask);
+       if (!pio)
+               return;
+       if (pio->iot == 'i')
+               return;
+
+       value = (pio->negmask & mask) ? !value : value;
+       if (value)
+               pio->sh_data |= mask;
+       else
+               pio->sh_data &= ~mask;
+       writel(pio->sh_data, pio->base + ALTERA_PIO_DATA);
+       return;
+}
+
+int gpio_is_valid(int number)
+{
+       int gidx = altera_pio_gidx(number);
+
+       if (gidx < 0)
+               return 1;
+       return 0;
+}