Merge branch 'master' of git://git.denx.de/u-boot-nios
authorWolfgang Denk <wd@denx.de>
Mon, 21 Nov 2011 21:00:37 +0000 (22:00 +0100)
committerWolfgang Denk <wd@denx.de>
Mon, 21 Nov 2011 21:00:37 +0000 (22:00 +0100)
* 'master' of git://git.denx.de/u-boot-nios:
  nios2: Offer ft_board_setup() capability and call fdt_fixup_ethernet().
  board/nios2-generic: Use altera_pio driver and remove board specific driver
  gpio: Add driver for Altera's PIO core
  nios2: Pseudo implement dcache_status/enable/disable()

arch/nios2/cpu/Makefile
arch/nios2/cpu/cpu.c
arch/nios2/cpu/fdt.c [new file with mode: 0644]
arch/nios2/include/asm/gpio.h
board/altera/nios2-generic/Makefile
board/altera/nios2-generic/custom_fpga.h
board/altera/nios2-generic/gpio.c [deleted file]
board/altera/nios2-generic/nios2-generic.c
drivers/gpio/Makefile
drivers/gpio/altera_pio.c [new file with mode: 0644]
include/configs/nios2-generic.h

index aa41160af35c60438a72db60a5b920c669e1caa9..402fd749ddd8db80f33357f7159aaced11fbb19c 100644 (file)
@@ -28,6 +28,7 @@ LIB   = $(obj)lib$(CPU).o
 START  = start.o
 SOBJS  = exceptions.o
 COBJS  = cpu.o interrupts.o sysid.o traps.o epcs.o
+COBJS  += fdt.o
 
 SRCS   := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS   := $(addprefix $(obj),$(SOBJS) $(COBJS))
index ef360eecbb4075aa1f39ca9b767c0450a84df23d..edf256017a3c2e79bcf295df3a2ee9034b48a739 100644 (file)
@@ -24,6 +24,7 @@
 #include <common.h>
 #include <nios2.h>
 #include <nios2-io.h>
+#include <asm/cache.h>
 
 #if defined (CONFIG_SYS_NIOS_SYSID_BASE)
 extern void display_sysid (void);
@@ -47,3 +48,18 @@ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        nios2_callr(CONFIG_SYS_RESET_ADDR);
        return 0;
 }
+
+int dcache_status(void)
+{
+       return 1;
+}
+
+void dcache_enable(void)
+{
+       flush_dcache(CONFIG_SYS_DCACHE_SIZE, CONFIG_SYS_DCACHELINE_SIZE);
+}
+
+void dcache_disable(void)
+{
+       flush_dcache(CONFIG_SYS_DCACHE_SIZE, CONFIG_SYS_DCACHELINE_SIZE);
+}
diff --git a/arch/nios2/cpu/fdt.c b/arch/nios2/cpu/fdt.c
new file mode 100644 (file)
index 0000000..b1ed9e1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * (C) Copyright 2011, Missing Link Electronics
+ *                     Joachim Foerster <joachim@missinglinkelectronics.com>
+ *
+ * Taken from arch/powerpc/cpu/ppc4xx/fdt.c:
+ *
+ * (C) Copyright 2007-2008
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
+#include <libfdt.h>
+#include <libfdt_env.h>
+#include <fdt_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void __ft_board_setup(void *blob, bd_t *bd)
+{
+       ft_cpu_setup(blob, bd);
+}
+void ft_board_setup(void *blob, bd_t *bd) \
+       __attribute__((weak, alias("__ft_board_setup")));
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+       /*
+        * Fixup all ethernet nodes
+        * Note: aliases in the dts are required for this
+        */
+       fdt_fixup_ethernet(blob);
+}
+#endif /* CONFIG_OF_LIBFDT && CONFIG_OF_BOARD_SETUP */
index 4b21c8f7f2ec6042023ba63f925bdc751271d239..908381f5f7b07dbfa1b1480de65e27f58221ecad 100644 (file)
@@ -5,8 +5,8 @@
  * bit[0] data
  * bit[1] output enable
  *
- * when CONFIG_SYS_GPIO_BASE is not defined, board may provide
- * its own driver.
+ * When CONFIG_SYS_GPIO_BASE is not defined, the board may either
+ * provide its own driver or the altera_pio driver may be used.
  *
  * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
  *
@@ -58,6 +58,15 @@ static inline int gpio_is_valid(int number)
        return ((unsigned)number) < CONFIG_SYS_GPIO_WIDTH;
 }
 #else
+#ifdef CONFIG_ALTERA_PIO
+extern int altera_pio_init(u32 base, u8 width, char iot,
+                          u32 rstval, u32 negmask,
+                          const char *label);
+
+extern void altera_pio_info(void);
+#define gpio_status() altera_pio_info()
+#endif
+
 extern int gpio_request(unsigned gpio, const char *label);
 extern int gpio_free(unsigned gpio);
 extern int gpio_direction_input(unsigned gpio);
index 359f5902195a3dc412209656ae7b0af72c50264c..59fd465c6b4178eba0edd9d0b10d87ac95c243cc 100644 (file)
@@ -32,7 +32,6 @@ LIB   = $(obj)lib$(BOARD).o
 COBJS-y        := $(BOARD).o
 COBJS-$(CONFIG_CMD_IDE) += ../common/cfide.o
 COBJS-$(CONFIG_EPLED) += ../common/epled.o
-COBJS-$(CONFIG_GPIO) += gpio.o
 COBJS-$(CONFIG_SEVENSEG) += ../common/sevenseg.o
 
 SOBJS-y        := text_base.o
index f7f38535fa557389a09de3d45525f65134bcbaca..fd3ec9a8d8ee2550bca30e9a8e637b42da0ebd47 100644 (file)
@@ -51,6 +51,7 @@
 /* led_pio.s1 is a altera_avalon_pio */
 #define LED_PIO_BASE 0x82120870
 #define LED_PIO_WIDTH 8
+#define LED_PIO_RSTVAL 0x0
 
 /* high_res_timer.s1 is a altera_avalon_timer */
 #define CONFIG_SYS_TIMER_BASE 0x82120820
diff --git a/board/altera/nios2-generic/gpio.c b/board/altera/nios2-generic/gpio.c
deleted file mode 100644 (file)
index 4a30564..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * board gpio driver
- *
- * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
- * Licensed under the GPL-2 or later.
- */
-#include <common.h>
-#include <asm/io.h>
-
-#ifndef CONFIG_SYS_GPIO_BASE
-
-#define ALTERA_PIO_BASE LED_PIO_BASE
-#define ALTERA_PIO_WIDTH LED_PIO_WIDTH
-#define ALTERA_PIO_DATA (ALTERA_PIO_BASE + 0)
-#define ALTERA_PIO_DIR (ALTERA_PIO_BASE + 4)
-static u32 pio_data_reg;
-static u32 pio_dir_reg;
-
-int gpio_request(unsigned gpio, const char *label)
-{
-       return 0;
-}
-
-int gpio_free(unsigned gpio)
-{
-       return 0;
-}
-
-int gpio_direction_input(unsigned gpio)
-{
-       u32 mask = 1 << gpio;
-       writel(pio_dir_reg &= ~mask, ALTERA_PIO_DIR);
-       return 0;
-}
-
-int gpio_direction_output(unsigned gpio, int value)
-{
-       u32 mask = 1 << gpio;
-       if (value)
-               pio_data_reg |= mask;
-       else
-               pio_data_reg &= ~mask;
-       writel(pio_data_reg, ALTERA_PIO_DATA);
-       writel(pio_dir_reg |= mask, ALTERA_PIO_DIR);
-       return 0;
-}
-
-int gpio_get_value(unsigned gpio)
-{
-       u32 mask = 1 << gpio;
-       if (pio_dir_reg & mask)
-               return (pio_data_reg & mask) ? 1 : 0;
-       else
-               return (readl(ALTERA_PIO_DATA) & mask) ? 1 : 0;
-}
-
-void gpio_set_value(unsigned gpio, int value)
-{
-       u32 mask = 1 << gpio;
-       if (value)
-               pio_data_reg |= mask;
-       else
-               pio_data_reg &= ~mask;
-       writel(pio_data_reg, ALTERA_PIO_DATA);
-}
-
-int gpio_is_valid(int number)
-{
-       return ((unsigned)number) < ALTERA_PIO_WIDTH;
-}
-#endif
index 49ef80de96dd36b494b960f8aa7c42908d10c979..0f882756f5ef23b6d23b494e2361f9e5a8da0577 100644 (file)
@@ -26,6 +26,7 @@
 #include <netdev.h>
 #include <mtd/cfi_flash.h>
 #include <asm/io.h>
+#include <asm/gpio.h>
 
 void text_base_hook(void); /* nop hook for text_base.S */
 
@@ -43,6 +44,13 @@ void early_flash_cmd_reset(void)
 int board_early_init_f(void)
 {
        text_base_hook();
+#ifdef CONFIG_ALTERA_PIO
+#ifdef LED_PIO_BASE
+       altera_pio_init(LED_PIO_BASE, LED_PIO_WIDTH, 'o',
+                       LED_PIO_RSTVAL, (1 << LED_PIO_WIDTH) - 1,
+                       "led");
+#endif
+#endif
 #if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR)
        early_flash_cmd_reset();
 #endif
index e1142d14be4810340e73666800d5b1cfc79443d1..e22c09689de6bea9af2e5c322d7fb0466c8aadfb 100644 (file)
@@ -36,6 +36,7 @@ COBJS-$(CONFIG_PCA9698)               += pca9698.o
 COBJS-$(CONFIG_S5P)            += s5p_gpio.o
 COBJS-$(CONFIG_TEGRA2_GPIO)    += tegra2_gpio.o
 COBJS-$(CONFIG_DA8XX_GPIO)     += da8xx_gpio.o
+COBJS-$(CONFIG_ALTERA_PIO)     += altera_pio.o
 
 COBJS  := $(COBJS-y)
 SRCS   := $(COBJS:.o=.c)
diff --git a/drivers/gpio/altera_pio.c b/drivers/gpio/altera_pio.c
new file mode 100644 (file)
index 0000000..fb03760
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Driver for Altera's PIO ip core
+ *
+ * Copyright (C) 2011  Missing Link Electronics
+ *                     Joachim Foerster <joachim@missinglinkelectronics.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * 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;
+}
index 1395939ce04d9cdffd5c707ad4ff60b44bad994c..9ba35e8810356150e558eedecf3e8de008268ef8 100644 (file)
 /*
  * STATUS LED
  */
+#define CONFIG_ALTERA_PIO
+#define CONFIG_SYS_ALTERA_PIO_NUM      1
+#define CONFIG_SYS_ALTERA_PIO_GPIO_NUM LED_PIO_WIDTH
+
 #define CONFIG_STATUS_LED              /* Enable status driver */
 #define CONFIG_GPIO_LED                /* Enable GPIO LED driver */
 #define CONFIG_GPIO                    /* Enable GPIO driver */