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 int ret; 148 149 conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); 150 if (!conf) 151 return -ENOMEM; 152 153 conf->spi = spi; 154 155 /* PROGRAM_B is active low */ 156 conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW); 157 if (IS_ERR(conf->prog_b)) { 158 dev_err(&spi->dev, "Failed to get PROGRAM_B gpio: %ld\n", 159 PTR_ERR(conf->prog_b)); 160 return PTR_ERR(conf->prog_b); 161 } 162 163 conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN); 164 if (IS_ERR(conf->done)) { 165 dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n", 166 PTR_ERR(conf->done)); 167 return PTR_ERR(conf->done); 168 } 169 170 mgr = fpga_mgr_create(&spi->dev, "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 ret = fpga_mgr_register(mgr); 178 if (ret) 179 fpga_mgr_free(mgr); 180 181 return ret; 182 } 183 184 static int xilinx_spi_remove(struct spi_device *spi) 185 { 186 struct fpga_manager *mgr = spi_get_drvdata(spi); 187 188 fpga_mgr_unregister(mgr); 189 190 return 0; 191 } 192 193 static const struct of_device_id xlnx_spi_of_match[] = { 194 { .compatible = "xlnx,fpga-slave-serial", }, 195 {} 196 }; 197 MODULE_DEVICE_TABLE(of, xlnx_spi_of_match); 198 199 static struct spi_driver xilinx_slave_spi_driver = { 200 .driver = { 201 .name = "xlnx-slave-spi", 202 .of_match_table = of_match_ptr(xlnx_spi_of_match), 203 }, 204 .probe = xilinx_spi_probe, 205 .remove = xilinx_spi_remove, 206 }; 207 208 module_spi_driver(xilinx_slave_spi_driver) 209 210 MODULE_LICENSE("GPL v2"); 211 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); 212 MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SPI"); 213