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