From d1ddca78f9f603ab70369e76fa2610d7e385c1b8 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 11 Jun 2020 23:11:41 +0200 Subject: fpga manager: xilinx-spi: valid for the 7 Series too The Xilinx 7-series uses the same protocol, mention that. Signed-off-by: Luca Ceresoli Signed-off-by: Moritz Fischer --- drivers/fpga/xilinx-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/fpga/xilinx-spi.c') diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index 272ee0c22822..79106626c3f8 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Xilinx Spartan6 Slave Serial SPI Driver + * Xilinx Spartan6 and 7 Series Slave Serial SPI Driver * * Copyright (C) 2017 DENX Software Engineering * -- cgit v1.2.3 From 23f872b6ece695750667a44016037154b91addef Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 11 Jun 2020 23:11:42 +0200 Subject: fpga manager: xilinx-spi: remove unneeded, mistyped variables Using variables does not add readability here: parameters passed to udelay*() are obviously in microseconds and their meaning is clear from the context. The type is also wrong, udelay expects an unsigned long. Signed-off-by: Luca Ceresoli Signed-off-by: Moritz Fischer --- drivers/fpga/xilinx-spi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/fpga/xilinx-spi.c') diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index 79106626c3f8..799ae04301be 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -41,8 +41,6 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr, const char *buf, size_t count) { struct xilinx_spi_conf *conf = mgr->priv; - const size_t prog_latency_7500us = 7500; - const size_t prog_pulse_1us = 1; if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); @@ -51,7 +49,7 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr, gpiod_set_value(conf->prog_b, 1); - udelay(prog_pulse_1us); /* min is 500 ns */ + udelay(1); /* min is 500 ns */ gpiod_set_value(conf->prog_b, 0); @@ -61,7 +59,7 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr, } /* program latency */ - usleep_range(prog_latency_7500us, prog_latency_7500us + 100); + usleep_range(7500, 7600); return 0; } -- cgit v1.2.3 From dd2784c01d93db20252a6416f3007cbbb89e4758 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 22 Jun 2020 15:37:23 +0200 Subject: fpga manager: xilinx-spi: check INIT_B pin during write_init The INIT_B pin reports the status during startup and after the end of the programming process. However the current driver completely ignores it. Check the pin status during startup to make sure programming is never started too early and also to detect any hardware issues in the FPGA connection. This is optional for backward compatibility. If INIT_B is not passed by device tree, just fallback to the old udelays. Signed-off-by: Luca Ceresoli Signed-off-by: Moritz Fischer --- drivers/fpga/xilinx-spi.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) (limited to 'drivers/fpga/xilinx-spi.c') diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index 799ae04301be..2967aa2a74e2 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -23,6 +23,7 @@ struct xilinx_spi_conf { struct spi_device *spi; struct gpio_desc *prog_b; + struct gpio_desc *init_b; struct gpio_desc *done; }; @@ -36,11 +37,45 @@ static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr) return FPGA_MGR_STATE_UNKNOWN; } +/** + * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait + * a given delay if the pin is unavailable + * + * @mgr: The FPGA manager object + * @value: Value INIT_B to wait for (1 = asserted = low) + * @alt_udelay: Delay to wait if the INIT_B GPIO is not available + * + * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if + * too much time passed waiting for that. If no INIT_B GPIO is available + * then always return 0. + */ +static int wait_for_init_b(struct fpga_manager *mgr, int value, + unsigned long alt_udelay) +{ + struct xilinx_spi_conf *conf = mgr->priv; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + if (conf->init_b) { + while (time_before(jiffies, timeout)) { + /* dump_state(conf, "wait for init_d .."); */ + if (gpiod_get_value(conf->init_b) == value) + return 0; + usleep_range(100, 400); + } + return -ETIMEDOUT; + } + + udelay(alt_udelay); + + return 0; +} + static int xilinx_spi_write_init(struct fpga_manager *mgr, struct fpga_image_info *info, const char *buf, size_t count) { struct xilinx_spi_conf *conf = mgr->priv; + int err; if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); @@ -49,10 +84,21 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr, gpiod_set_value(conf->prog_b, 1); - udelay(1); /* min is 500 ns */ + err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */ + if (err) { + dev_err(&mgr->dev, "INIT_B pin did not go low\n"); + gpiod_set_value(conf->prog_b, 0); + return err; + } gpiod_set_value(conf->prog_b, 0); + err = wait_for_init_b(mgr, 0, 0); + if (err) { + dev_err(&mgr->dev, "INIT_B pin did not go high\n"); + return err; + } + if (gpiod_get_value(conf->done)) { dev_err(&mgr->dev, "Unexpected DONE pin state...\n"); return -EIO; @@ -154,6 +200,13 @@ static int xilinx_spi_probe(struct spi_device *spi) return PTR_ERR(conf->prog_b); } + conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN); + if (IS_ERR(conf->init_b)) { + dev_err(&spi->dev, "Failed to get INIT_B gpio: %ld\n", + PTR_ERR(conf->init_b)); + return PTR_ERR(conf->init_b); + } + conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN); if (IS_ERR(conf->done)) { dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n", -- cgit v1.2.3