Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/fpga/ice40-spi.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* FPGA Manager Driver for Lattice iCE40.
4
*
5
* Copyright (c) 2016 Joel Holdsworth
6
*
7
* This driver adds support to the FPGA manager for configuring the SRAM of
8
* Lattice iCE40 FPGAs through slave SPI.
9
*/
10
11
#include <linux/fpga/fpga-mgr.h>
12
#include <linux/gpio/consumer.h>
13
#include <linux/mod_devicetable.h>
14
#include <linux/module.h>
15
#include <linux/spi/spi.h>
16
#include <linux/stringify.h>
17
18
#define ICE40_SPI_MAX_SPEED 25000000 /* Hz */
19
#define ICE40_SPI_MIN_SPEED 1000000 /* Hz */
20
21
#define ICE40_SPI_RESET_DELAY 1 /* us (>200ns) */
22
#define ICE40_SPI_HOUSEKEEPING_DELAY 1200 /* us */
23
24
#define ICE40_SPI_NUM_ACTIVATION_BYTES DIV_ROUND_UP(49, 8)
25
26
struct ice40_fpga_priv {
27
struct spi_device *dev;
28
struct gpio_desc *reset;
29
struct gpio_desc *cdone;
30
};
31
32
static enum fpga_mgr_states ice40_fpga_ops_state(struct fpga_manager *mgr)
33
{
34
struct ice40_fpga_priv *priv = mgr->priv;
35
36
return gpiod_get_value(priv->cdone) ? FPGA_MGR_STATE_OPERATING :
37
FPGA_MGR_STATE_UNKNOWN;
38
}
39
40
static int ice40_fpga_ops_write_init(struct fpga_manager *mgr,
41
struct fpga_image_info *info,
42
const char *buf, size_t count)
43
{
44
struct ice40_fpga_priv *priv = mgr->priv;
45
struct spi_device *dev = priv->dev;
46
struct spi_message message;
47
struct spi_transfer assert_cs_then_reset_delay = {
48
.cs_change = 1,
49
.delay = {
50
.value = ICE40_SPI_RESET_DELAY,
51
.unit = SPI_DELAY_UNIT_USECS
52
}
53
};
54
struct spi_transfer housekeeping_delay_then_release_cs = {
55
.delay = {
56
.value = ICE40_SPI_HOUSEKEEPING_DELAY,
57
.unit = SPI_DELAY_UNIT_USECS
58
}
59
};
60
int ret;
61
62
if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
63
dev_err(&dev->dev,
64
"Partial reconfiguration is not supported\n");
65
return -ENOTSUPP;
66
}
67
68
/* Lock the bus, assert CRESET_B and SS_B and delay >200ns */
69
spi_bus_lock(dev->controller);
70
71
gpiod_set_value(priv->reset, 1);
72
73
spi_message_init(&message);
74
spi_message_add_tail(&assert_cs_then_reset_delay, &message);
75
ret = spi_sync_locked(dev, &message);
76
77
/* Come out of reset */
78
gpiod_set_value(priv->reset, 0);
79
80
/* Abort if the chip-select failed */
81
if (ret)
82
goto fail;
83
84
/* Check CDONE is de-asserted i.e. the FPGA is reset */
85
if (gpiod_get_value(priv->cdone)) {
86
dev_err(&dev->dev, "Device reset failed, CDONE is asserted\n");
87
ret = -EIO;
88
goto fail;
89
}
90
91
/* Wait for the housekeeping to complete, and release SS_B */
92
spi_message_init(&message);
93
spi_message_add_tail(&housekeeping_delay_then_release_cs, &message);
94
ret = spi_sync_locked(dev, &message);
95
96
fail:
97
spi_bus_unlock(dev->controller);
98
99
return ret;
100
}
101
102
static int ice40_fpga_ops_write(struct fpga_manager *mgr,
103
const char *buf, size_t count)
104
{
105
struct ice40_fpga_priv *priv = mgr->priv;
106
107
return spi_write(priv->dev, buf, count);
108
}
109
110
static int ice40_fpga_ops_write_complete(struct fpga_manager *mgr,
111
struct fpga_image_info *info)
112
{
113
struct ice40_fpga_priv *priv = mgr->priv;
114
struct spi_device *dev = priv->dev;
115
const u8 padding[ICE40_SPI_NUM_ACTIVATION_BYTES] = {0};
116
117
/* Check CDONE is asserted */
118
if (!gpiod_get_value(priv->cdone)) {
119
dev_err(&dev->dev,
120
"CDONE was not asserted after firmware transfer\n");
121
return -EIO;
122
}
123
124
/* Send of zero-padding to activate the firmware */
125
return spi_write(dev, padding, sizeof(padding));
126
}
127
128
static const struct fpga_manager_ops ice40_fpga_ops = {
129
.state = ice40_fpga_ops_state,
130
.write_init = ice40_fpga_ops_write_init,
131
.write = ice40_fpga_ops_write,
132
.write_complete = ice40_fpga_ops_write_complete,
133
};
134
135
static int ice40_fpga_probe(struct spi_device *spi)
136
{
137
struct device *dev = &spi->dev;
138
struct ice40_fpga_priv *priv;
139
struct fpga_manager *mgr;
140
int ret;
141
142
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
143
if (!priv)
144
return -ENOMEM;
145
146
priv->dev = spi;
147
148
/* Check board setup data. */
149
if (spi->max_speed_hz > ICE40_SPI_MAX_SPEED) {
150
dev_err(dev, "SPI speed is too high, maximum speed is "
151
__stringify(ICE40_SPI_MAX_SPEED) "\n");
152
return -EINVAL;
153
}
154
155
if (spi->max_speed_hz < ICE40_SPI_MIN_SPEED) {
156
dev_err(dev, "SPI speed is too low, minimum speed is "
157
__stringify(ICE40_SPI_MIN_SPEED) "\n");
158
return -EINVAL;
159
}
160
161
if (spi->mode & SPI_CPHA) {
162
dev_err(dev, "Bad SPI mode, CPHA not supported\n");
163
return -EINVAL;
164
}
165
166
/* Set up the GPIOs */
167
priv->cdone = devm_gpiod_get(dev, "cdone", GPIOD_IN);
168
if (IS_ERR(priv->cdone)) {
169
ret = PTR_ERR(priv->cdone);
170
dev_err(dev, "Failed to get CDONE GPIO: %d\n", ret);
171
return ret;
172
}
173
174
priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
175
if (IS_ERR(priv->reset)) {
176
ret = PTR_ERR(priv->reset);
177
dev_err(dev, "Failed to get CRESET_B GPIO: %d\n", ret);
178
return ret;
179
}
180
181
mgr = devm_fpga_mgr_register(dev, "Lattice iCE40 FPGA Manager",
182
&ice40_fpga_ops, priv);
183
return PTR_ERR_OR_ZERO(mgr);
184
}
185
186
static const struct of_device_id ice40_fpga_of_match[] = {
187
{ .compatible = "lattice,ice40-fpga-mgr", },
188
{},
189
};
190
MODULE_DEVICE_TABLE(of, ice40_fpga_of_match);
191
192
static const struct spi_device_id ice40_fpga_spi_ids[] = {
193
{ .name = "ice40-fpga-mgr", },
194
{},
195
};
196
MODULE_DEVICE_TABLE(spi, ice40_fpga_spi_ids);
197
198
static struct spi_driver ice40_fpga_driver = {
199
.probe = ice40_fpga_probe,
200
.driver = {
201
.name = "ice40spi",
202
.of_match_table = ice40_fpga_of_match,
203
},
204
.id_table = ice40_fpga_spi_ids,
205
};
206
207
module_spi_driver(ice40_fpga_driver);
208
209
MODULE_AUTHOR("Joel Holdsworth <[email protected]>");
210
MODULE_DESCRIPTION("Lattice iCE40 FPGA Manager");
211
MODULE_LICENSE("GPL v2");
212
213