altera-ps-spi.c (8381B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Altera Passive Serial SPI Driver 4 * 5 * Copyright (c) 2017 United Western Technologies, Corporation 6 * 7 * Joshua Clayton <stillcompiling@gmail.com> 8 * 9 * Manage Altera FPGA firmware that is loaded over SPI using the passive 10 * serial configuration method. 11 * Firmware must be in binary "rbf" format. 12 * Works on Arria 10, Cyclone V and Stratix V. Should work on Cyclone series. 13 * May work on other Altera FPGAs. 14 */ 15 16#include <linux/bitrev.h> 17#include <linux/delay.h> 18#include <linux/fpga/fpga-mgr.h> 19#include <linux/gpio/consumer.h> 20#include <linux/module.h> 21#include <linux/of_gpio.h> 22#include <linux/of_device.h> 23#include <linux/spi/spi.h> 24#include <linux/sizes.h> 25 26enum altera_ps_devtype { 27 CYCLONE5, 28 ARRIA10, 29}; 30 31struct altera_ps_data { 32 enum altera_ps_devtype devtype; 33 int status_wait_min_us; 34 int status_wait_max_us; 35 int t_cfg_us; 36 int t_st2ck_us; 37}; 38 39struct altera_ps_conf { 40 struct gpio_desc *config; 41 struct gpio_desc *confd; 42 struct gpio_desc *status; 43 struct spi_device *spi; 44 const struct altera_ps_data *data; 45 u32 info_flags; 46 char mgr_name[64]; 47}; 48 49/* | Arria 10 | Cyclone5 | Stratix5 | 50 * t_CF2ST0 | [; 600] | [; 600] | [; 600] |ns 51 * t_CFG | [2;] | [2;] | [2;] |µs 52 * t_STATUS | [268; 3000] | [268; 1506] | [268; 1506] |µs 53 * t_CF2ST1 | [; 3000] | [; 1506] | [; 1506] |µs 54 * t_CF2CK | [3010;] | [1506;] | [1506;] |µs 55 * t_ST2CK | [10;] | [2;] | [2;] |µs 56 * t_CD2UM | [175; 830] | [175; 437] | [175; 437] |µs 57 */ 58static struct altera_ps_data c5_data = { 59 /* these values for Cyclone5 are compatible with Stratix5 */ 60 .devtype = CYCLONE5, 61 .status_wait_min_us = 268, 62 .status_wait_max_us = 1506, 63 .t_cfg_us = 2, 64 .t_st2ck_us = 2, 65}; 66 67static struct altera_ps_data a10_data = { 68 .devtype = ARRIA10, 69 .status_wait_min_us = 268, /* min(t_STATUS) */ 70 .status_wait_max_us = 3000, /* max(t_CF2ST1) */ 71 .t_cfg_us = 2, /* max { min(t_CFG), max(tCF2ST0) } */ 72 .t_st2ck_us = 10, /* min(t_ST2CK) */ 73}; 74 75/* Array index is enum altera_ps_devtype */ 76static const struct altera_ps_data *altera_ps_data_map[] = { 77 &c5_data, 78 &a10_data, 79}; 80 81static const struct of_device_id of_ef_match[] = { 82 { .compatible = "altr,fpga-passive-serial", .data = &c5_data }, 83 { .compatible = "altr,fpga-arria10-passive-serial", .data = &a10_data }, 84 {} 85}; 86MODULE_DEVICE_TABLE(of, of_ef_match); 87 88static enum fpga_mgr_states altera_ps_state(struct fpga_manager *mgr) 89{ 90 struct altera_ps_conf *conf = mgr->priv; 91 92 if (gpiod_get_value_cansleep(conf->status)) 93 return FPGA_MGR_STATE_RESET; 94 95 return FPGA_MGR_STATE_UNKNOWN; 96} 97 98static inline void altera_ps_delay(int delay_us) 99{ 100 if (delay_us > 10) 101 usleep_range(delay_us, delay_us + 5); 102 else 103 udelay(delay_us); 104} 105 106static int altera_ps_write_init(struct fpga_manager *mgr, 107 struct fpga_image_info *info, 108 const char *buf, size_t count) 109{ 110 struct altera_ps_conf *conf = mgr->priv; 111 int min, max, waits; 112 int i; 113 114 conf->info_flags = info->flags; 115 116 if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { 117 dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); 118 return -EINVAL; 119 } 120 121 gpiod_set_value_cansleep(conf->config, 1); 122 123 /* wait min reset pulse time */ 124 altera_ps_delay(conf->data->t_cfg_us); 125 126 if (!gpiod_get_value_cansleep(conf->status)) { 127 dev_err(&mgr->dev, "Status pin failed to show a reset\n"); 128 return -EIO; 129 } 130 131 gpiod_set_value_cansleep(conf->config, 0); 132 133 min = conf->data->status_wait_min_us; 134 max = conf->data->status_wait_max_us; 135 waits = max / min; 136 if (max % min) 137 waits++; 138 139 /* wait for max { max(t_STATUS), max(t_CF2ST1) } */ 140 for (i = 0; i < waits; i++) { 141 usleep_range(min, min + 10); 142 if (!gpiod_get_value_cansleep(conf->status)) { 143 /* wait for min(t_ST2CK)*/ 144 altera_ps_delay(conf->data->t_st2ck_us); 145 return 0; 146 } 147 } 148 149 dev_err(&mgr->dev, "Status pin not ready.\n"); 150 return -EIO; 151} 152 153static void rev_buf(char *buf, size_t len) 154{ 155 u32 *fw32 = (u32 *)buf; 156 size_t extra_bytes = (len & 0x03); 157 const u32 *fw_end = (u32 *)(buf + len - extra_bytes); 158 159 /* set buffer to lsb first */ 160 while (fw32 < fw_end) { 161 *fw32 = bitrev8x4(*fw32); 162 fw32++; 163 } 164 165 if (extra_bytes) { 166 buf = (char *)fw_end; 167 while (extra_bytes) { 168 *buf = bitrev8(*buf); 169 buf++; 170 extra_bytes--; 171 } 172 } 173} 174 175static int altera_ps_write(struct fpga_manager *mgr, const char *buf, 176 size_t count) 177{ 178 struct altera_ps_conf *conf = mgr->priv; 179 const char *fw_data = buf; 180 const char *fw_data_end = fw_data + count; 181 182 while (fw_data < fw_data_end) { 183 int ret; 184 size_t stride = min_t(size_t, fw_data_end - fw_data, SZ_4K); 185 186 if (!(conf->info_flags & FPGA_MGR_BITSTREAM_LSB_FIRST)) 187 rev_buf((char *)fw_data, stride); 188 189 ret = spi_write(conf->spi, fw_data, stride); 190 if (ret) { 191 dev_err(&mgr->dev, "spi error in firmware write: %d\n", 192 ret); 193 return ret; 194 } 195 fw_data += stride; 196 } 197 198 return 0; 199} 200 201static int altera_ps_write_complete(struct fpga_manager *mgr, 202 struct fpga_image_info *info) 203{ 204 struct altera_ps_conf *conf = mgr->priv; 205 static const char dummy[] = {0}; 206 int ret; 207 208 if (gpiod_get_value_cansleep(conf->status)) { 209 dev_err(&mgr->dev, "Error during configuration.\n"); 210 return -EIO; 211 } 212 213 if (conf->confd) { 214 if (!gpiod_get_raw_value_cansleep(conf->confd)) { 215 dev_err(&mgr->dev, "CONF_DONE is inactive!\n"); 216 return -EIO; 217 } 218 } 219 220 /* 221 * After CONF_DONE goes high, send two additional falling edges on DCLK 222 * to begin initialization and enter user mode 223 */ 224 ret = spi_write(conf->spi, dummy, 1); 225 if (ret) { 226 dev_err(&mgr->dev, "spi error during end sequence: %d\n", ret); 227 return ret; 228 } 229 230 return 0; 231} 232 233static const struct fpga_manager_ops altera_ps_ops = { 234 .state = altera_ps_state, 235 .write_init = altera_ps_write_init, 236 .write = altera_ps_write, 237 .write_complete = altera_ps_write_complete, 238}; 239 240static const struct altera_ps_data *id_to_data(const struct spi_device_id *id) 241{ 242 kernel_ulong_t devtype = id->driver_data; 243 const struct altera_ps_data *data; 244 245 /* someone added a altera_ps_devtype without adding to the map array */ 246 if (devtype >= ARRAY_SIZE(altera_ps_data_map)) 247 return NULL; 248 249 data = altera_ps_data_map[devtype]; 250 if (!data || data->devtype != devtype) 251 return NULL; 252 253 return data; 254} 255 256static int altera_ps_probe(struct spi_device *spi) 257{ 258 struct altera_ps_conf *conf; 259 const struct of_device_id *of_id; 260 struct fpga_manager *mgr; 261 262 conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); 263 if (!conf) 264 return -ENOMEM; 265 266 if (spi->dev.of_node) { 267 of_id = of_match_device(of_ef_match, &spi->dev); 268 if (!of_id) 269 return -ENODEV; 270 conf->data = of_id->data; 271 } else { 272 conf->data = id_to_data(spi_get_device_id(spi)); 273 if (!conf->data) 274 return -ENODEV; 275 } 276 277 conf->spi = spi; 278 conf->config = devm_gpiod_get(&spi->dev, "nconfig", GPIOD_OUT_LOW); 279 if (IS_ERR(conf->config)) { 280 dev_err(&spi->dev, "Failed to get config gpio: %ld\n", 281 PTR_ERR(conf->config)); 282 return PTR_ERR(conf->config); 283 } 284 285 conf->status = devm_gpiod_get(&spi->dev, "nstat", GPIOD_IN); 286 if (IS_ERR(conf->status)) { 287 dev_err(&spi->dev, "Failed to get status gpio: %ld\n", 288 PTR_ERR(conf->status)); 289 return PTR_ERR(conf->status); 290 } 291 292 conf->confd = devm_gpiod_get_optional(&spi->dev, "confd", GPIOD_IN); 293 if (IS_ERR(conf->confd)) { 294 dev_err(&spi->dev, "Failed to get confd gpio: %ld\n", 295 PTR_ERR(conf->confd)); 296 return PTR_ERR(conf->confd); 297 } else if (!conf->confd) { 298 dev_warn(&spi->dev, "Not using confd gpio"); 299 } 300 301 /* Register manager with unique name */ 302 snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s %s", 303 dev_driver_string(&spi->dev), dev_name(&spi->dev)); 304 305 mgr = devm_fpga_mgr_register(&spi->dev, conf->mgr_name, 306 &altera_ps_ops, conf); 307 return PTR_ERR_OR_ZERO(mgr); 308} 309 310static const struct spi_device_id altera_ps_spi_ids[] = { 311 { "cyclone-ps-spi", CYCLONE5 }, 312 { "fpga-passive-serial", CYCLONE5 }, 313 { "fpga-arria10-passive-serial", ARRIA10 }, 314 {} 315}; 316MODULE_DEVICE_TABLE(spi, altera_ps_spi_ids); 317 318static struct spi_driver altera_ps_driver = { 319 .driver = { 320 .name = "altera-ps-spi", 321 .owner = THIS_MODULE, 322 .of_match_table = of_match_ptr(of_ef_match), 323 }, 324 .id_table = altera_ps_spi_ids, 325 .probe = altera_ps_probe, 326}; 327 328module_spi_driver(altera_ps_driver) 329 330MODULE_LICENSE("GPL v2"); 331MODULE_AUTHOR("Joshua Clayton <stillcompiling@gmail.com>"); 332MODULE_DESCRIPTION("Module to load Altera FPGA firmware over SPI");