summaryrefslogtreecommitdiff
path: root/board
diff options
context:
space:
mode:
Diffstat (limited to 'board')
-rw-r--r--board/keymile/common/common.h5
-rw-r--r--board/keymile/km_arm/Makefile4
-rw-r--r--board/keymile/km_arm/fpga_config.c212
-rw-r--r--board/keymile/km_arm/km_arm.c21
4 files changed, 236 insertions, 6 deletions
diff --git a/board/keymile/common/common.h b/board/keymile/common/common.h
index f457aa3..aab706e 100644
--- a/board/keymile/common/common.h
+++ b/board/keymile/common/common.h
@@ -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,
diff --git a/board/keymile/km_arm/Makefile b/board/keymile/km_arm/Makefile
index aa51255..13d485a 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
+
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
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@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 daab27b..c8da823 100644
--- a/board/keymile/km_arm/km_arm.c
+++ b/board/keymile/km_arm/km_arm.c
@@ -268,12 +268,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;
}
@@ -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;
}