arm: mvebu: theadorable: Add StratixV FPGA programming support
authorStefan Roese <sr@denx.de>
Fri, 12 Feb 2016 13:24:07 +0000 (14:24 +0100)
committerStefan Roese <sr@denx.de>
Thu, 24 Mar 2016 08:48:34 +0000 (09:48 +0100)
This patch adds support for Altera StratixV bitstream programming. 2 FPGAs
are connected to the SPI busses. This patch uses board specific write
code to program the bitstream via SPI direct write mode.

Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Luka Perkov <luka.perkov@sartura.hr>
Signed-off-by: Stefan Roese <sr@denx.de>
arch/arm/dts/armada-xp-theadorable.dts
board/theadorable/Makefile
board/theadorable/fpga.c [new file with mode: 0644]
board/theadorable/theadorable.c
board/theadorable/theadorable.h [new file with mode: 0644]
configs/theadorable_debug_defconfig
configs/theadorable_defconfig
include/configs/theadorable.h

index cf1be2a3d4eb94fa035c1343d876a561a0c85fc0..7087ccfc2f0f60565b7824233dbb055e2fb1942b 100644 (file)
@@ -69,6 +69,7 @@
 
        aliases {
                spi0 = &spi0;
+               spi1 = &spi1;
                ethernet0 = &eth0;
        };
 
                                        reg = <0>; /* Chip select 0 */
                                        spi-max-frequency = <27777777>;
                                };
+
+                               fpga@1 {
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       compatible = "spi-generic-device";
+                                       reg = <1>; /* Chip select 1 */
+                                       spi-max-frequency = <27777777>;
+                               };
+                       };
+
+                       spi1: spi@10680 {
+                               status = "okay";
+
+                               fpga@2 {
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       compatible = "spi-generic-device";
+                                       reg = <2>; /* Chip select 2 */
+                                       spi-max-frequency = <27777777>;
+                               };
                        };
                };
        };
index 9d5b39e696439bef79bf4801ce6df2f6548bb55c..ef5a519ada9c190c5abad7ff814ce3881cfc7657 100644 (file)
@@ -5,3 +5,4 @@
 #
 
 obj-y  := theadorable.o
+obj-y  += fpga.o
diff --git a/board/theadorable/fpga.c b/board/theadorable/fpga.c
new file mode 100644 (file)
index 0000000..6f068c3
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <altera.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+#include <asm/arch-mvebu/spi.h>
+#include "theadorable.h"
+
+/*
+ * FPGA programming support
+ */
+static int fpga_pre_fn(int cookie)
+{
+       int gpio_config = COOKIE2CONFIG(cookie);
+       int gpio_done = COOKIE2DONE(cookie);
+       int ret;
+
+       debug("%s (%d): cookie=%08x gpio_config=%d gpio_done=%d\n",
+             __func__, __LINE__, cookie, gpio_config, gpio_done);
+
+       /* Configure config pin */
+       /* Set to output */
+       ret = gpio_request(gpio_config, "CONFIG");
+       if (ret < 0)
+               return ret;
+       gpio_direction_output(gpio_config, 1);
+
+       /* Configure done pin */
+       /* Set to input */
+       ret = gpio_request(gpio_done, "DONE");
+       if (ret < 0)
+               return ret;
+
+       gpio_direction_input(gpio_done);
+
+       return 0;
+}
+
+static int fpga_config_fn(int assert, int flush, int cookie)
+{
+       int gpio_config = COOKIE2CONFIG(cookie);
+
+       debug("%s (%d): cookie=%08x gpio_config=%d\n",
+             __func__, __LINE__, cookie, gpio_config);
+
+       if (assert)
+               gpio_set_value(gpio_config, 1);
+       else
+               gpio_set_value(gpio_config, 0);
+
+       return 0;
+}
+
+static int fpga_write_fn(const void *buf, size_t len, int flush, int cookie)
+{
+       int spi_bus = COOKIE2SPI_BUS(cookie);
+       int spi_dev = COOKIE2SPI_DEV(cookie);
+       struct kwspi_registers *reg;
+       u32 control_reg;
+       u32 config_reg;
+       void *dst;
+
+       /*
+        * Write data to FPGA attached to SPI bus via SPI direct write.
+        * This results in the fastest and easiest way to program the
+        * bitstream into the FPGA.
+        */
+       debug("%s (%d): cookie=%08x spi_bus=%d spi_dev=%d\n",
+             __func__, __LINE__, cookie, spi_bus, spi_dev);
+
+       if (spi_bus == 0) {
+               reg = (struct kwspi_registers *)MVEBU_REGISTER(0x10600);
+               dst = (void *)SPI_BUS0_DEV1_BASE;
+       } else {
+               reg = (struct kwspi_registers *)MVEBU_REGISTER(0x10680);
+               dst = (void *)SPI_BUS1_DEV2_BASE;
+       }
+
+       /* Configure SPI controller for direct access mode */
+       control_reg = readl(&reg->ctrl);
+       config_reg = readl(&reg->cfg);
+       writel(0x00000214, &reg->cfg);          /* 27MHz clock */
+       writel(0x00000000, &reg->dw_cfg);       /* don't de-asset CS */
+       writel(KWSPI_CSN_ACT, &reg->ctrl);      /* activate CS */
+
+       /* Copy data to the SPI direct mapped window */
+       memcpy(dst, buf, len);
+
+       /* Restore original register values */
+       writel(control_reg, &reg->ctrl);
+       writel(config_reg, &reg->cfg);
+
+       return 0;
+}
+
+/* Returns the state of CONF_DONE Pin */
+static int fpga_done_fn(int cookie)
+{
+       int gpio_done = COOKIE2DONE(cookie);
+       unsigned long ts;
+
+       debug("%s (%d): cookie=%08x gpio_done=%d\n",
+             __func__, __LINE__, cookie, gpio_done);
+
+       ts = get_timer(0);
+       do {
+               if (gpio_get_value(gpio_done))
+                       return 0;
+       } while (get_timer(ts) < 1000);
+
+       /* timeout so return error */
+       return -ENODEV;
+}
+
+static altera_board_specific_func stratixv_fns = {
+       .pre = fpga_pre_fn,
+       .config = fpga_config_fn,
+       .write = fpga_write_fn,
+       .done = fpga_done_fn,
+};
+
+static Altera_desc altera_fpga[] = {
+       {
+               /* Family */
+               Altera_StratixV,
+               /* Interface type */
+               passive_serial,
+               /* No limitation as additional data will be ignored */
+               -1,
+               /* Device function table */
+               (void *)&stratixv_fns,
+               /* Base interface address specified in driver */
+               NULL,
+               /* Cookie implementation */
+               /*
+                * In this 32bit word the following information is coded:
+                * Bit 31 ... Bit 0
+                * SPI-Bus | SPI-Dev | Config-Pin | Done-Pin
+                */
+               FPGA_COOKIE(0, 1, 26, 7)
+       },
+       {
+               /* Family */
+               Altera_StratixV,
+               /* Interface type */
+               passive_serial,
+               /* No limitation as additional data will be ignored */
+               -1,
+               /* Device function table */
+               (void *)&stratixv_fns,
+               /* Base interface address specified in driver */
+               NULL,
+               /* Cookie implementation */
+               /*
+                * In this 32bit word the following information is coded:
+                * Bit 31 ... Bit 0
+                * SPI-Bus | SPI-Dev | Config-Pin | Done-Pin
+                */
+               FPGA_COOKIE(1, 2, 29, 9)
+       },
+};
+
+/* Add device descriptor to FPGA device table */
+void board_fpga_add(void)
+{
+       int i;
+
+       fpga_init();
+       for (i = 0; i < ARRAY_SIZE(altera_fpga); i++)
+               fpga_add(fpga_altera, &altera_fpga[i]);
+}
index 0e232656fc906f05d95b84fd61797f39aa5dbda7..ee88a98a24169c0de3a0fef2592d1e89385aaf08 100644 (file)
@@ -8,9 +8,11 @@
 #include <asm/io.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/soc.h>
+#include <linux/mbus.h>
 #ifdef CONFIG_NET
 #include <netdev.h>
 #endif
+#include "theadorable.h"
 
 #include "../drivers/ddr/marvell/axp/ddr3_hw_training.h"
 #include "../arch/arm/mach-mvebu/serdes/axp/high_speed_env_spec.h"
@@ -136,6 +138,15 @@ int board_init(void)
        /* adress of boot parameters */
        gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
 
+       /*
+        * Map SPI devices via MBUS so that they can be accessed via
+        * the SPI direct access mode
+        */
+       mbus_dt_setup_win(&mbus_state, SPI_BUS0_DEV1_BASE, SPI_BUS0_DEV1_SIZE,
+                         CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPI0_CS1);
+       mbus_dt_setup_win(&mbus_state, SPI_BUS1_DEV2_BASE, SPI_BUS0_DEV1_SIZE,
+                         CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPI1_CS2);
+
        return 0;
 }
 
@@ -143,6 +154,8 @@ int checkboard(void)
 {
        puts("Board: theadorable\n");
 
+       board_fpga_add();
+
        return 0;
 }
 
diff --git a/board/theadorable/theadorable.h b/board/theadorable/theadorable.h
new file mode 100644 (file)
index 0000000..89fe117
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/* Base addresses for the SPI direct access mode */
+#define SPI_BUS0_DEV1_BASE     0xe0000000
+#define SPI_BUS0_DEV1_SIZE     (1 << 20)
+#define SPI_BUS1_DEV2_BASE     (SPI_BUS0_DEV1_BASE + SPI_BUS0_DEV1_SIZE)
+
+void board_fpga_add(void);
index 62a6ee6663bd4f9e76e64731c4fb41b4682aa028..054038a03bed673571ebcbd6152203595e9dbddf 100644 (file)
@@ -2,6 +2,7 @@ CONFIG_ARM=y
 CONFIG_ARCH_MVEBU=y
 CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_TARGET_THEADORABLE=y
+CONFIG_DM_GPIO=y
 CONFIG_DEFAULT_DEVICE_TREE="armada-xp-theadorable"
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
 CONFIG_SPL=y
@@ -10,7 +11,7 @@ CONFIG_FIT=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_SF=y
 CONFIG_CMD_USB=y
-# CONFIG_CMD_FPGA is not set
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_SPL_OF_TRANSLATE=y
index 4d5f3b0a0aaa608a5b4653674773d791ff2202bd..9a6abf2f7e33c1cf4cbe63211cc4373af91adcd4 100644 (file)
@@ -2,6 +2,7 @@ CONFIG_ARM=y
 CONFIG_ARCH_MVEBU=y
 CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_TARGET_THEADORABLE=y
+CONFIG_DM_GPIO=y
 CONFIG_DEFAULT_DEVICE_TREE="armada-xp-theadorable"
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
 CONFIG_SPL=y
@@ -9,7 +10,6 @@ CONFIG_FIT=y
 # CONFIG_CMD_IMLS is not set
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_SF=y
-# CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_SETEXPR is not set
 # CONFIG_CMD_NET is not set
 # CONFIG_CMD_NFS is not set
index 9f186add71f427af7430b1a7235c9222d3ebe56b..a4bcf212108ed7b4d0d111bc07ffe850717b5576 100644 (file)
 #define CONFIG_VGA_AS_SINGLE_DEVICE
 #define CONFIG_CMD_BMP
 
+/* FPGA programming support */
+#define CONFIG_FPGA
+#define CONFIG_FPGA_ALTERA
+#define CONFIG_FPGA_STRATIX_V
+
 /*
  * mv-common.h should be defined after CMD configs since it used them
  * to enable certain macros