arm/km: enable BOCO2 FPGA download support
authorValentin Longchamp <valentin.longchamp@keymile.com>
Thu, 5 Jul 2012 05:05:05 +0000 (05:05 +0000)
committerAlbert ARIBAUD <albert.u.boot@aribaud.net>
Sat, 7 Jul 2012 12:07:37 +0000 (14:07 +0200)
This adds a first support of the FPGA download for a PCIe FPGA based
on the BOCO2 CPLD.

This takes place in 3 steps, all done accessing the SPICTRL reg of the
BOCO2:
1) start the FPGA config with an access to the FPGA_PROG bit
2) later in the boot sequence, wait for the FPGA_DONE bit to toggle to 1
   for the end of the FPGA configuration (with a timeout)
3) reset the FPGA
4) finally remove the access to its config EEPROM from the FPGA so that
   the CPU can update the FPGA configuration when the kernel is running

The boards with a PCIe FPGA but without BOCO2 still are supported.

The config option name is CONFIG_KM_FPGA_CONFIG

Signed-off-by: Valentin Longchamp <valentin.longchamp@keymile.com>
Signed-off-by: Holger Brunck <holger.brunck@keymile.com>
cc: Gerlando Falauto <gerlando.falauto@keymile.com>
cc: Prafulla Wadaskar <prafulla@marvell.com>

board/keymile/common/common.h
board/keymile/km_arm/Makefile
board/keymile/km_arm/fpga_config.c [new file with mode: 0644]
board/keymile/km_arm/km_arm.c
boards.cfg
include/configs/km/km_arm.h
include/configs/km_kirkwood.h

index f457aa30c6a49a71831316caa8563a97aa3c2679..aab706e6c9c0457a28c360428aa046040ca52c79 100644 (file)
@@ -131,6 +131,11 @@ struct bfticu_iomap {
 int ethernet_present(void);
 int ivm_read_eeprom(void);
 
+int trigger_fpga_config(void);
+int wait_for_fpga_config(void);
+int fpga_reset(void);
+int toggle_eeprom_spi_bus(void);
+
 int set_km_env(void);
 int fdt_set_node_and_value(void *blob,
                        char *nodename,
index aa512552658016af0b2b22fb1836c9014369f19c..13d485aedb4193227e88ad623ab6567328eb458e 100644 (file)
@@ -31,6 +31,10 @@ LIB  = $(obj)lib$(BOARD).o
 
 COBJS  := $(BOARD).o ../common/common.o ../common/ivm.o
 
+ifdef CONFIG_KM_FPGA_CONFIG
+COBJS  += fpga_config.o
+endif
+
 SRCS   := $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS   := $(addprefix $(obj),$(COBJS))
 SOBJS  := $(addprefix $(obj),$(SOBJS))
diff --git a/board/keymile/km_arm/fpga_config.c b/board/keymile/km_arm/fpga_config.c
new file mode 100644 (file)
index 0000000..4356b9a
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * (C) Copyright 2012
+ * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <asm/errno.h>
+
+/* GPIO Pin from kirkwood connected to PROGRAM_B pin of the xilinx FPGA */
+#define KM_XLX_PROGRAM_B_PIN    39
+
+#define BOCO_ADDR      0x10
+
+#define ID_REG         0x00
+#define BOCO2_ID       0x5b
+
+static int check_boco2(void)
+{
+       int ret;
+       u8 id;
+
+       ret = i2c_read(BOCO_ADDR, ID_REG, 1, &id, 1);
+       if (ret) {
+               printf("%s: error reading the BOCO id !!\n", __func__);
+               return ret;
+       }
+
+       return (id == BOCO2_ID);
+}
+
+static int boco_clear_bits(u8 reg, u8 flags)
+{
+       int ret;
+       u8 regval;
+
+       /* give access to the EEPROM from FPGA */
+       ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
+       if (ret) {
+               printf("%s: error reading the BOCO @%#x !!\n",
+                       __func__, reg);
+               return ret;
+       }
+       regval &= ~flags;
+       ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
+       if (ret) {
+               printf("%s: error writing the BOCO @%#x !!\n",
+                       __func__, reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int boco_set_bits(u8 reg, u8 flags)
+{
+       int ret;
+       u8 regval;
+
+       /* give access to the EEPROM from FPGA */
+       ret = i2c_read(BOCO_ADDR, reg, 1, &regval, 1);
+       if (ret) {
+               printf("%s: error reading the BOCO @%#x !!\n",
+                       __func__, reg);
+               return ret;
+       }
+       regval |= flags;
+       ret = i2c_write(BOCO_ADDR, reg, 1, &regval, 1);
+       if (ret) {
+               printf("%s: error writing the BOCO @%#x !!\n",
+                       __func__, reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+#define SPI_REG                0x06
+#define CFG_EEPROM     0x02
+#define FPGA_PROG      0x04
+#define FPGA_DONE      0x20
+
+int trigger_fpga_config(void)
+{
+       int ret = 0;
+
+       if (check_boco2()) {
+               /* we have a BOCO2, this has to be triggered here */
+
+               /* make sure the FPGA_can access the EEPROM */
+               ret = boco_clear_bits(SPI_REG, CFG_EEPROM);
+               if (ret)
+                       return ret;
+
+               /* trigger the config start */
+               ret = boco_clear_bits(SPI_REG, FPGA_PROG);
+               if (ret)
+                       return ret;
+
+               /* small delay for the pulse */
+               udelay(10);
+
+               /* up signal for pulse end */
+               ret = boco_set_bits(SPI_REG, FPGA_PROG);
+               if (ret)
+                       return ret;
+
+       } else {
+               /* we do it the old way, with the gpio pin */
+               kw_gpio_set_valid(KM_XLX_PROGRAM_B_PIN, 1);
+               kw_gpio_direction_output(KM_XLX_PROGRAM_B_PIN, 0);
+               /* small delay for the pulse */
+               udelay(10);
+               kw_gpio_direction_input(KM_XLX_PROGRAM_B_PIN);
+       }
+
+       return 0;
+}
+
+int wait_for_fpga_config(void)
+{
+       int ret = 0;
+       u8 spictrl;
+       u32 timeout = 20000;
+
+       if (!check_boco2()) {
+               /* we do not have BOCO2, this is not really used */
+               return 0;
+       }
+
+       printf("PCIe FPGA config:");
+       do {
+               ret = i2c_read(BOCO_ADDR, SPI_REG, 1, &spictrl, 1);
+               if (ret) {
+                       printf("%s: error reading the BOCO spictrl !!\n",
+                               __func__);
+                       return ret;
+               }
+               if (timeout-- == 0) {
+                       printf(" FPGA_DONE timeout\n");
+                       return -EFAULT;
+               }
+               udelay(10);
+       } while (!(spictrl & FPGA_DONE));
+
+       printf(" done\n");
+
+       return 0;
+}
+
+#define PRST1          0x4
+#define BRIDGE_RST     0x4
+
+int fpga_reset(void)
+{
+       int ret = 0;
+
+       if (!check_boco2()) {
+               /* we do not have BOCO2, this is not really used */
+               return 0;
+       }
+
+       ret = boco_clear_bits(PRST1, BRIDGE_RST);
+       if (ret)
+               return ret;
+
+       /* small delay for the pulse */
+       udelay(10);
+
+       ret = boco_set_bits(PRST1, BRIDGE_RST);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+/* the FPGA was configured, we configure the BOCO2 so that the EEPROM
+ * is available from the Bobcat SPI bus */
+int toggle_eeprom_spi_bus(void)
+{
+       int ret = 0;
+
+       if (!check_boco2()) {
+               /* we do not have BOCO2, this is not really used */
+               return 0;
+       }
+
+       ret = boco_set_bits(SPI_REG, CFG_EEPROM);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
index daab27bbb71e202c7f8cff4ebbbfc64e340fec5c..c8da823cb289cab715508b221408f05792535d02 100644 (file)
@@ -267,12 +267,6 @@ int board_early_init_f(void)
 #if defined(CONFIG_SYS_EEPROM_WREN)
        kw_gpio_set_valid(KM_KIRKWOOD_ENV_WP, 38);
        kw_gpio_direction_output(KM_KIRKWOOD_ENV_WP, 1);
-#endif
-#if defined(CONFIG_KM_RECONFIG_XLX)
-       /* trigger the reconfiguration of the xilinx fpga */
-       kw_gpio_set_valid(KM_XLX_PROGRAM_B_PIN, 1);
-       kw_gpio_direction_output(KM_XLX_PROGRAM_B_PIN, 0);
-       kw_gpio_direction_input(KM_XLX_PROGRAM_B_PIN);
 #endif
        return 0;
 }
@@ -282,6 +276,21 @@ int board_init(void)
        /* address of boot parameters */
        gd->bd->bi_boot_params = kw_sdram_bar(0) + 0x100;
 
+#if defined(CONFIG_KM_FPGA_CONFIG)
+       trigger_fpga_config();
+#endif
+
+       return 0;
+}
+
+int board_late_init(void)
+{
+#if defined(CONFIG_KM_FPGA_CONFIG)
+       wait_for_fpga_config();
+       fpga_reset();
+       toggle_eeprom_spi_bus();
+#endif
+
        return 0;
 }
 
index db7902fa1624dd4cb27ebdd146b28478df509e23..26c0a9904e6c3af6651619bca1f43329bfe01482 100644 (file)
@@ -141,7 +141,7 @@ dns325                       arm         arm926ejs   -                   d-link
 lschlv2                      arm         arm926ejs   lsxl                buffalo        kirkwood    lsxl:LSCHLV2
 lsxhl                        arm         arm926ejs   lsxl                buffalo        kirkwood    lsxl:LSXHL
 km_kirkwood                  arm         arm926ejs   km_arm              keymile        kirkwood    km_kirkwood:KM_KIRKWOOD,KM_DISABLE_PCI
-km_kirkwood_pci              arm         arm926ejs   km_arm              keymile        kirkwood    km_kirkwood:KM_KIRKWOOD_PCI,KM_RECONFIG_XLX
+km_kirkwood_pci              arm         arm926ejs   km_arm              keymile        kirkwood    km_kirkwood:KM_KIRKWOOD_PCI,KM_FPGA_CONFIG
 kmnusa                       arm         arm926ejs   km_arm              keymile        kirkwood    km_kirkwood:KM_NUSA
 mgcoge3un                    arm         arm926ejs   km_arm              keymile        kirkwood    km_kirkwood:KM_MGCOGE3UN
 kmcoge5un                    arm         arm926ejs   km_arm              keymile        kirkwood    km_kirkwood:KM_COGE5UN
index 60e2450d285aa7312a38aaf29806b275a6208010..1a5f04bc74f3ee45d88b882f3a958e60b1bd23fb 100644 (file)
@@ -313,4 +313,7 @@ int get_scl(void);
 #define CONFIG_POST_EXTERNAL_WORD_FUNCS
 #define CONFIG_CMD_DIAG
 
+/* we do the whole PCIe FPGA config stuff here */
+#define        BOARD_LATE_INIT
+
 #endif /* _CONFIG_KM_ARM_H */
index 44a3e7a6e89a4ae8dc5e47e1fa63f6de27509328..0a61b7d9eb10d896d32438ddc4ef245b6819c2d4 100644 (file)
        MVGBE_SET_MII_SPEED_TO_100)
 #endif
 
-/* GPIO Pin from kirkwood connected to PROGRAM_B pin of the xilinx FPGA */
-#define KM_XLX_PROGRAM_B_PIN    39
-
 #ifdef CONFIG_KM_DISABLE_PCI
 #undef  CONFIG_KIRKWOOD_PCIE_INIT
 #endif
+
+#ifndef CONFIG_KM_FPGA_CONFIG
+#undef  BOARD_LATE_INIT
+#endif
+
 #endif /* _CONFIG_KM_KIRKWOOD */