1 /* 2 * Xilinx Spartan6 Slave Serial SPI Driver 3 * 4 * Copyright (C) 2017 DENX Software Engineering 5 * 6 * Anatolij Gustschin <agust@denx.de> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms and conditions of the GNU General Public License, 10 * version 2, as published by the Free Software Foundation. 11 * 12 * Manage Xilinx FPGA firmware that is loaded over SPI using 13 * the slave serial configuration interface. 14 */ 15 16 #include <linux/delay.h> 17 #include <linux/device.h> 18 #include <linux/fpga/fpga-mgr.h> 19 #include <linux/gpio/consumer.h> 20 #include <linux/module.h> 21 #include <linux/mod_devicetable.h> 22 #include <linux/of.h> 23 #include <linux/spi/spi.h> 24 #include <linux/sizes.h> 25 26 struct xilinx_spi_conf { 27 struct spi_device *spi; 28 struct gpio_desc *prog_b; 29 struct gpio_desc *done; 30 }; 31 32 static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr) 33 { 34 struct xilinx_spi_conf *conf = mgr->priv; 35 36 if (!gpiod_get_value(conf->done)) 37 return FPGA_MGR_STATE_RESET; 38 39 return FPGA_MGR_STATE_UNKNOWN; 40 } 41 42 static int xilinx_spi_write_init(struct fpga_manager *mgr, 43 struct fpga_image_info *info, 44 const char *buf, size_t count) 45 { 46 struct xilinx_spi_conf *conf = mgr->priv; 47 const size_t prog_latency_7500us = 7500; 48 const size_t prog_pulse_1us = 1; 49 50 if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { 51 dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); 52 return -EINVAL; 53 } 54 55 gpiod_set_value(conf->prog_b, 1); 56 57 udelay(prog_pulse_1us); /* min is 500 ns */ 58 59 gpiod_set_value(conf->prog_b, 0); 60 61 if (gpiod_get_value(conf->done)) { 62 dev_err(&mgr->dev, "Unexpected DONE pin state...\n"); 63 return -EIO; 64 } 65 66 /* program latency */ 67 usleep_range(prog_latency_7500us, prog_latency_7500us + 100); 68 return 0; 69 } 70 71 static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf, 72 size_t count) 73 { 74 struct xilinx_spi_conf *conf = mgr->priv; 75 const char *fw_data = buf; 76 const char *fw_data_end = fw_data + count; 77 78 while (fw_data < fw_data_end) { 79 size_t remaining, stride; 80 int ret; 81 82 remaining = fw_data_end - fw_data; 83 stride = min_t(size_t, remaining, SZ_4K); 84 85 ret = spi_write(conf->spi, fw_data, stride); 86 if (ret) { 87 dev_err(&mgr->dev, "SPI error in firmware write: %d\n", 88 ret); 89 return ret; 90 } 91 fw_data += stride; 92 } 93 94 return 0; 95 } 96 97 static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf) 98 { 99 struct spi_device *spi = conf->spi; 100 const u8 din_data[1] = { 0xff }; 101 int ret; 102 103 ret = spi_write(conf->spi, din_data, sizeof(din_data)); 104 if (ret) 105 dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret); 106 107 return ret; 108 } 109 110 static int xilinx_spi_write_complete(struct fpga_manager *mgr, 111 struct fpga_image_info *info) 112 { 113 struct xilinx_spi_conf *conf = mgr->priv; 114 unsigned long timeout; 115 int ret; 116 117 if (gpiod_get_value(conf->done)) 118 return xilinx_spi_apply_cclk_cycles(conf); 119 120 timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us); 121 122 while (time_before(jiffies, timeout)) { 123 124 ret = xilinx_spi_apply_cclk_cycles(conf); 125 if (ret) 126 return ret; 127 128 if (gpiod_get_value(conf->done)) 129 return xilinx_spi_apply_cclk_cycles(conf); 130 } 131 132 dev_err(&mgr->dev, "Timeout after config data transfer.\n"); 133 return -ETIMEDOUT; 134 } 135 136 static const struct fpga_manager_ops xilinx_spi_ops = { 137 .state = xilinx_spi_state, 138 .write_init = xilinx_spi_write_init, 139 .write = xilinx_spi_write, 140 .write_complete = xilinx_spi_write_complete, 141 }; 142 143 static int xilinx_spi_probe(struct spi_device *spi) 144 { 145 struct xilinx_spi_conf *conf; 146 struct fpga_manager *mgr; 147 148 conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); 149 if (!conf) 150 return -ENOMEM; 151 152 conf->spi = spi; 153 154 /* PROGRAM_B is active low */ 155 conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW); 156 if (IS_ERR(conf->prog_b)) { 157 dev_err(&spi->dev, "Failed to get PROGRAM_B gpio: %ld\n", 158 PTR_ERR(conf->prog_b)); 159 return PTR_ERR(conf->prog_b); 160 } 161 162 conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN); 163 if (IS_ERR(conf->done)) { 164 dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n", 165 PTR_ERR(conf->done)); 166 return PTR_ERR(conf->done); 167 } 168 169 mgr = devm_fpga_mgr_create(&spi->dev, 170 "Xilinx Slave Serial FPGA Manager", 171 &xilinx_spi_ops, conf); 172 if (!mgr) 173 return -ENOMEM; 174 175 spi_set_drvdata(spi, mgr); 176 177 return fpga_mgr_register(mgr); 178 } 179 180 static int xilinx_spi_remove(struct spi_device *spi) 181 { 182 struct fpga_manager *mgr = spi_get_drvdata(spi); 183 184 fpga_mgr_unregister(mgr); 185 186 return 0; 187 } 188 189 static const struct of_device_id xlnx_spi_of_match[] = { 190 { .compatible = "xlnx,fpga-slave-serial", }, 191 {} 192 }; 193 MODULE_DEVICE_TABLE(of, xlnx_spi_of_match); 194 195 static struct spi_driver xilinx_slave_spi_driver = { 196 .driver = { 197 .name = "xlnx-slave-spi", 198 .of_match_table = of_match_ptr(xlnx_spi_of_match), 199 }, 200 .probe = xilinx_spi_probe, 201 .remove = xilinx_spi_remove, 202 }; 203 204 module_spi_driver(xilinx_slave_spi_driver) 205 206 MODULE_LICENSE("GPL v2"); 207 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); 208 MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SPI"); 209