[U-Boot] [PATCH v2 06/14] arm/km: enable BOCO2 FPGA download support

Holger Brunck
2012-06-13T13:33:12Z

From: Valentin Longchamp <valentin.longchamp@keymile.com>

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: Prafulla Wadaskar <prafulla@marvell.com>
---
changes for v2:
- nothing

board/keymile/common/common.h | 6 +
board/keymile/km_arm/Makefile | 4 +
board/keymile/km_arm/fpga_config.c | 212 ++++++++++++++++++++++++++++++++++++
board/keymile/km_arm/km_arm.c | 21 +++-
boards.cfg | 2 +-
include/configs/km/km_arm.h | 3 +
include/configs/km_kirkwood.h | 8 +-
7 files changed, 246 insertions(+), 10 deletions(-)
create mode 100644 board/keymile/km_arm/fpga_config.c

diff --git a/board/keymile/common/common.h b/board/keymile/common/common.h
index 49225b8..c58e565 100644
--- a/board/keymile/common/common.h
+++ b/board/keymile/common/common.h
@@ -131,6 +131,12 @@ int ext_switch_reg_write(const char *devname, u8 phy_addr, u8 port,
int ext_switch_reg_read(const char *devname, u8 phy_addr, u8 port,
u8 reg, u16 *data);

+
+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,
diff --git a/board/keymile/km_arm/Makefile b/board/keymile/km_arm/Makefile
index 06079e9..bd824e2 100644
--- a/board/keymile/km_arm/Makefile
+++ b/board/keymile/km_arm/Makefile
@@ -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
+
ifdef CONFIG_KM_MANAGED_SW_ADDR
COBJS += managed_switch.o
endif
diff --git a/board/keymile/km_arm/fpga_config.c b/board/keymile/km_arm/fpga_config.c
new file mode 100644
index 0000000..4356b9a
--- /dev/null
+++ b/board/keymile/km_arm/fpga_config.c
@@ -0,0 +1,212 @@
+/*
+ * (C) Copyright 2012
+ * Valentin Lontgchamp, Keymile AG, valentin.longchamp at 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;
+}
+
diff --git a/board/keymile/km_arm/km_arm.c b/board/keymile/km_arm/km_arm.c
index 66b82d0..5c9ba8f 100644
--- a/board/keymile/km_arm/km_arm.c
+++ b/board/keymile/km_arm/km_arm.c
@@ -272,12 +272,6 @@ int board_early_init_f(void)
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;
}

@@ -286,6 +280,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;
}

diff --git a/boards.cfg b/boards.cfg
index 3b63167..da52a49 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -139,7 +139,7 @@ calimain arm arm926ejs calimain omicron
pogo_e02 arm arm926ejs - cloudengines kirkwood
dns325 arm arm926ejs - d-link kirkwood
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
diff --git a/include/configs/km/km_arm.h b/include/configs/km/km_arm.h
index 9cd909c..5fbb590 100644
--- a/include/configs/km/km_arm.h
+++ b/include/configs/km/km_arm.h
@@ -310,4 +310,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 */
diff --git a/include/configs/km_kirkwood.h b/include/configs/km_kirkwood.h
index 503c27d..be0da83 100644
--- a/include/configs/km_kirkwood.h
+++ b/include/configs/km_kirkwood.h
@@ -175,10 +175,12 @@
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 */
--
1.7.1