summaryrefslogtreecommitdiff
path: root/drivers/fpga/xilinx-spi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-10-15 10:01:51 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-10-15 10:01:51 -0700
commit726eb70e0d34dc4bc4dada71f52bba8ed638431e (patch)
treee49674616f4513c8c6a4746a08e93c9441708d34 /drivers/fpga/xilinx-spi.c
parentc6dbef7307629cce855aa6b482b60cbf7777ed88 (diff)
parentf3277cbfba763cd2826396521b9296de67cf1bbc (diff)
downloadlinux-stable-726eb70e0d34dc4bc4dada71f52bba8ed638431e.tar.gz
Merge tag 'char-misc-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH: "Here is the big set of char, misc, and other assorted driver subsystem patches for 5.10-rc1. There's a lot of different things in here, all over the drivers/ directory. Some summaries: - soundwire driver updates - habanalabs driver updates - extcon driver updates - nitro_enclaves new driver - fsl-mc driver and core updates - mhi core and bus updates - nvmem driver updates - eeprom driver updates - binder driver updates and fixes - vbox minor bugfixes - fsi driver updates - w1 driver updates - coresight driver updates - interconnect driver updates - misc driver updates - other minor driver updates All of these have been in linux-next for a while with no reported issues" * tag 'char-misc-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (396 commits) binder: fix UAF when releasing todo list docs: w1: w1_therm: Fix broken xref, mistakes, clarify text misc: Kconfig: fix a HISI_HIKEY_USB dependency LSM: Fix type of id parameter in kernel_post_load_data prototype misc: Kconfig: add a new dependency for HISI_HIKEY_USB firmware_loader: fix a kernel-doc markup w1: w1_therm: make w1_poll_completion static binder: simplify the return expression of binder_mmap test_firmware: Test partial read support firmware: Add request_partial_firmware_into_buf() firmware: Store opt_flags in fw_priv fs/kernel_file_read: Add "offset" arg for partial reads IMA: Add support for file reads without contents LSM: Add "contents" flag to kernel_read_file hook module: Call security_kernel_post_load_data() firmware_loader: Use security_post_load_data() LSM: Introduce kernel_post_load_data() hook fs/kernel_read_file: Add file_size output argument fs/kernel_read_file: Switch buffer size arg to size_t fs/kernel_read_file: Remove redundant size argument ...
Diffstat (limited to 'drivers/fpga/xilinx-spi.c')
-rw-r--r--drivers/fpga/xilinx-spi.c77
1 files changed, 58 insertions, 19 deletions
diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
index 2967aa2a74e2..824abbbd631e 100644
--- a/drivers/fpga/xilinx-spi.c
+++ b/drivers/fpga/xilinx-spi.c
@@ -27,11 +27,22 @@ struct xilinx_spi_conf {
struct gpio_desc *done;
};
-static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
+static int get_done_gpio(struct fpga_manager *mgr)
{
struct xilinx_spi_conf *conf = mgr->priv;
+ int ret;
+
+ ret = gpiod_get_value(conf->done);
+
+ if (ret < 0)
+ dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
+
+ return ret;
+}
- if (!gpiod_get_value(conf->done))
+static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
+{
+ if (!get_done_gpio(mgr))
return FPGA_MGR_STATE_RESET;
return FPGA_MGR_STATE_UNKNOWN;
@@ -57,11 +68,21 @@ static int wait_for_init_b(struct fpga_manager *mgr, int value,
if (conf->init_b) {
while (time_before(jiffies, timeout)) {
- /* dump_state(conf, "wait for init_d .."); */
- if (gpiod_get_value(conf->init_b) == value)
+ int ret = gpiod_get_value(conf->init_b);
+
+ if (ret == value)
return 0;
+
+ if (ret < 0) {
+ dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
+ return ret;
+ }
+
usleep_range(100, 400);
}
+
+ dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
+ value ? "assert" : "deassert");
return -ETIMEDOUT;
}
@@ -78,7 +99,7 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr,
int err;
if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
- dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
+ dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
return -EINVAL;
}
@@ -86,7 +107,6 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr,
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;
}
@@ -94,12 +114,10 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr,
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");
+ if (err)
return err;
- }
- if (gpiod_get_value(conf->done)) {
+ if (get_done_gpio(mgr)) {
dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
return -EIO;
}
@@ -152,25 +170,46 @@ static int xilinx_spi_write_complete(struct fpga_manager *mgr,
struct fpga_image_info *info)
{
struct xilinx_spi_conf *conf = mgr->priv;
- unsigned long timeout;
+ unsigned long timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
+ bool expired = false;
+ int done;
int ret;
- if (gpiod_get_value(conf->done))
- return xilinx_spi_apply_cclk_cycles(conf);
+ /*
+ * This loop is carefully written such that if the driver is
+ * scheduled out for more than 'timeout', we still check for DONE
+ * before giving up and we apply 8 extra CCLK cycles in all cases.
+ */
+ while (!expired) {
+ expired = time_after(jiffies, timeout);
- timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
-
- while (time_before(jiffies, timeout)) {
+ done = get_done_gpio(mgr);
+ if (done < 0)
+ return done;
ret = xilinx_spi_apply_cclk_cycles(conf);
if (ret)
return ret;
- if (gpiod_get_value(conf->done))
- return xilinx_spi_apply_cclk_cycles(conf);
+ if (done)
+ return 0;
+ }
+
+ if (conf->init_b) {
+ ret = gpiod_get_value(conf->init_b);
+
+ if (ret < 0) {
+ dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
+ return ret;
+ }
+
+ dev_err(&mgr->dev,
+ ret ? "CRC error or invalid device\n"
+ : "Missing sync word or incomplete bitstream\n");
+ } else {
+ dev_err(&mgr->dev, "Timeout after config data transfer\n");
}
- dev_err(&mgr->dev, "Timeout after config data transfer.\n");
return -ETIMEDOUT;
}