1 /*
2 * Copyright (c) 2023 Rivos Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(spi_opentitan);
9
10 #include "spi_context.h"
11
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/spi.h>
14 #include <zephyr/drivers/spi/rtio.h>
15 #include <soc.h>
16 #include <stdbool.h>
17
18 /* Register offsets within the SPI host register space. */
19 #define SPI_HOST_INTR_STATE_REG_OFFSET 0x00
20 #define SPI_HOST_INTR_ENABLE_REG_OFFSET 0x04
21 #define SPI_HOST_INTR_TEST_REG_OFFSET 0x08
22 #define SPI_HOST_ALERT_TEST_REG_OFFSET 0x0c
23 #define SPI_HOST_CONTROL_REG_OFFSET 0x10
24 #define SPI_HOST_STATUS_REG_OFFSET 0x14
25 #define SPI_HOST_CONFIGOPTS_REG_OFFSET 0x18
26 #define SPI_HOST_CSID_REG_OFFSET 0x1c
27 #define SPI_HOST_COMMAND_REG_OFFSET 0x20
28 #define SPI_HOST_RXDATA_REG_OFFSET 0x24
29 #define SPI_HOST_TXDATA_REG_OFFSET 0x28
30 #define SPI_HOST_ERROR_ENABLE_REG_OFFSET 0x2c
31 #define SPI_HOST_ERROR_STATUS_REG_OFFSET 0x30
32 #define SPI_HOST_EVENT_ENABLE_REG_OFFSET 0x34
33
34 /* Control register fields. */
35 #define SPI_HOST_CONTROL_OUTPUT_EN_BIT BIT(29)
36 #define SPI_HOST_CONTROL_SW_RST_BIT BIT(30)
37 #define SPI_HOST_CONTROL_SPIEN_BIT BIT(31)
38
39 /* Status register fields. */
40 #define SPI_HOST_STATUS_TXQD_MASK GENMASK(7, 0)
41 #define SPI_HOST_STATUS_RXQD_MASK GENMASK(15, 8)
42 #define SPI_HOST_STATUS_BYTEORDER_BIT BIT(22)
43 #define SPI_HOST_STATUS_RXEMPTY_BIT BIT(24)
44 #define SPI_HOST_STATUS_ACTIVE_BIT BIT(30)
45 #define SPI_HOST_STATUS_READY_BIT BIT(31)
46
47 /* Command register fields. */
48 #define SPI_HOST_COMMAND_LEN_MASK GENMASK(8, 0)
49 /* "Chip select active after transaction" */
50 #define SPI_HOST_COMMAND_CSAAT_BIT BIT(9)
51 #define SPI_HOST_COMMAND_SPEED_MASK GENMASK(11, 10)
52 #define SPI_HOST_COMMAND_SPEED_STANDARD (0 << 10)
53 #define SPI_HOST_COMMAND_SPEED_DUAL (1 << 10)
54 #define SPI_HOST_COMMAND_SPEED_QUAD (2 << 10)
55 #define SPI_HOST_COMMAND_DIRECTION_MASK GENMASK(13, 12)
56 #define SPI_HOST_COMMAND_DIRECTION_RX (0x1 << 12)
57 #define SPI_HOST_COMMAND_DIRECTION_TX (0x2 << 12)
58 #define SPI_HOST_COMMAND_DIRECTION_BOTH (0x3 << 12)
59
60 /* Configopts register fields. */
61 #define SPI_HOST_CONFIGOPTS_CPHA0_BIT BIT(30)
62 #define SPI_HOST_CONFIGOPTS_CPOL0_BIT BIT(31)
63
64 #define DT_DRV_COMPAT lowrisc_opentitan_spi
65
66 struct spi_opentitan_data {
67 struct spi_context ctx;
68 };
69
70 struct spi_opentitan_cfg {
71 uint32_t base;
72 uint32_t f_input;
73 };
74
spi_config(const struct device * dev,uint32_t frequency,uint16_t operation)75 static int spi_config(const struct device *dev, uint32_t frequency,
76 uint16_t operation)
77 {
78 const struct spi_opentitan_cfg *cfg = dev->config;
79
80 uint32_t reg;
81
82 if (operation & SPI_HALF_DUPLEX) {
83 return -ENOTSUP;
84 }
85
86 if (SPI_OP_MODE_GET(operation) != SPI_OP_MODE_MASTER) {
87 return -ENOTSUP;
88 }
89
90 if (operation & SPI_MODE_LOOP) {
91 return -ENOTSUP;
92 }
93
94 if (SPI_WORD_SIZE_GET(operation) != 8) {
95 return -ENOTSUP;
96 }
97
98 if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) &&
99 (operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) {
100 return -ENOTSUP;
101 }
102
103 /* Most significant bit always transferred first. */
104 if (operation & SPI_TRANSFER_LSB) {
105 return -ENOTSUP;
106 }
107
108 /* Set the SPI frequency, polarity, and clock phase in CONFIGOPTS register.
109 * Applied divider (divides f_in / 2) is CLKDIV register (16 bit) + 1.
110 */
111 reg = cfg->f_input / 2 / frequency;
112 if (reg > 0xffffu) {
113 reg = 0xffffu;
114 } else if (reg > 0) {
115 reg--;
116 }
117 /* Setup phase */
118 if (operation & SPI_MODE_CPHA) {
119 reg |= SPI_HOST_CONFIGOPTS_CPHA0_BIT;
120 }
121 /* Setup polarity. */
122 if (operation & SPI_MODE_CPOL) {
123 reg |= SPI_HOST_CONFIGOPTS_CPOL0_BIT;
124 }
125 sys_write32(reg, cfg->base + SPI_HOST_CONFIGOPTS_REG_OFFSET);
126
127 return 0;
128 }
129
spi_opentitan_rx_available(const struct spi_opentitan_cfg * cfg)130 static bool spi_opentitan_rx_available(const struct spi_opentitan_cfg *cfg)
131 {
132 /* Rx bytes are available if Tx FIFO is non-empty. */
133 return !(sys_read32(cfg->base + SPI_HOST_STATUS_REG_OFFSET) & SPI_HOST_STATUS_RXEMPTY_BIT);
134 }
135
spi_opentitan_xfer(const struct device * dev,const bool gpio_cs_control)136 static void spi_opentitan_xfer(const struct device *dev, const bool gpio_cs_control)
137 {
138 const struct spi_opentitan_cfg *cfg = dev->config;
139 struct spi_opentitan_data *data = dev->data;
140 struct spi_context *ctx = &data->ctx;
141
142 while (spi_context_tx_on(ctx) || spi_context_rx_on(ctx)) {
143 const size_t segment_len = MAX(ctx->tx_len, ctx->rx_len);
144 uint32_t host_command_reg;
145
146 /* Setup transaction duplex. */
147 if (!spi_context_tx_on(ctx)) {
148 host_command_reg = SPI_HOST_COMMAND_DIRECTION_RX;
149 } else if (!spi_context_rx_on(ctx)) {
150 host_command_reg = SPI_HOST_COMMAND_DIRECTION_TX;
151 } else {
152 host_command_reg = SPI_HOST_COMMAND_DIRECTION_BOTH;
153 }
154
155 size_t tx_bytes_to_queue = spi_context_tx_buf_on(ctx) ? ctx->tx_len : 0;
156
157 /* First place Tx bytes in FIFO, packed four to a word. */
158 while (tx_bytes_to_queue > 0) {
159 uint32_t fifo_word = 0;
160
161 for (int byte = 0; byte < 4; ++byte) {
162 if (tx_bytes_to_queue == 0) {
163 break;
164 }
165 fifo_word |= *ctx->tx_buf << (8 * byte);
166 spi_context_update_tx(ctx, 1, 1);
167 tx_bytes_to_queue--;
168 }
169 sys_write32(fifo_word, cfg->base + SPI_HOST_TXDATA_REG_OFFSET);
170 }
171
172 /* Keep CS asserted if another Tx segment remains or if two more Rx
173 * segments remain (because we will handle one Rx segment after the
174 * forthcoming transaction).
175 */
176 if (ctx->tx_count > 0 || ctx->rx_count > 1) {
177 host_command_reg |= SPI_HOST_COMMAND_CSAAT_BIT;
178 }
179 /* Segment length field holds COMMAND.LEN + 1. */
180 host_command_reg |= segment_len - 1;
181
182 /* Issue transaction. */
183 sys_write32(host_command_reg, cfg->base + SPI_HOST_COMMAND_REG_OFFSET);
184
185 size_t rx_bytes_to_read = spi_context_rx_buf_on(ctx) ? ctx->rx_len : 0;
186
187 /* Read from Rx FIFO as required. */
188 while (rx_bytes_to_read > 0) {
189 while (!spi_opentitan_rx_available(cfg)) {
190 ;
191 }
192 uint32_t rx_word = sys_read32(cfg->base +
193 SPI_HOST_RXDATA_REG_OFFSET);
194 for (int byte = 0; byte < 4; ++byte) {
195 if (rx_bytes_to_read == 0) {
196 break;
197 }
198 *ctx->rx_buf = (rx_word >> (8 * byte)) & 0xff;
199 spi_context_update_rx(ctx, 1, 1);
200 rx_bytes_to_read--;
201 }
202 }
203 }
204
205 /* Deassert the CS line if required. */
206 if (gpio_cs_control) {
207 spi_context_cs_control(ctx, false);
208 }
209
210 spi_context_complete(ctx, dev, 0);
211 }
212
spi_opentitan_init(const struct device * dev)213 static int spi_opentitan_init(const struct device *dev)
214 {
215 const struct spi_opentitan_cfg *cfg = dev->config;
216 struct spi_opentitan_data *data = dev->data;
217 int err;
218
219 /* Place SPI host peripheral in reset and wait for reset to complete. */
220 sys_write32(SPI_HOST_CONTROL_SW_RST_BIT,
221 cfg->base + SPI_HOST_CONTROL_REG_OFFSET);
222 while (sys_read32(cfg->base + SPI_HOST_STATUS_REG_OFFSET)
223 & (SPI_HOST_STATUS_ACTIVE_BIT | SPI_HOST_STATUS_TXQD_MASK |
224 SPI_HOST_STATUS_RXQD_MASK)) {
225 ;
226 }
227 /* Clear reset and enable SPI host peripheral. */
228 sys_write32(SPI_HOST_CONTROL_OUTPUT_EN_BIT | SPI_HOST_CONTROL_SPIEN_BIT,
229 cfg->base + SPI_HOST_CONTROL_REG_OFFSET);
230
231 err = spi_context_cs_configure_all(&data->ctx);
232 if (err < 0) {
233 return err;
234 }
235
236 /* Make sure the context is unlocked */
237 spi_context_unlock_unconditionally(&data->ctx);
238 return 0;
239 }
240
spi_opentitan_transceive(const struct device * dev,const struct spi_config * config,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs)241 static int spi_opentitan_transceive(const struct device *dev,
242 const struct spi_config *config,
243 const struct spi_buf_set *tx_bufs,
244 const struct spi_buf_set *rx_bufs)
245 {
246 int rc = 0;
247 bool gpio_cs_control = false;
248 struct spi_opentitan_data *data = dev->data;
249
250 /* Lock the SPI Context */
251 spi_context_lock(&data->ctx, false, NULL, NULL, config);
252
253 /* Configure the SPI bus */
254 data->ctx.config = config;
255 rc = spi_config(dev, config->frequency, config->operation);
256 if (rc < 0) {
257 spi_context_release(&data->ctx, rc);
258 return rc;
259 }
260
261 spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1);
262
263 /* Assert the CS line. HW will always assert the CS pin identified by CSID
264 * (default CSID: 0), so GPIO CS control will work in addition to HW
265 * asserted (and presumably ignored) CS.
266 */
267 if (config->cs) {
268 gpio_cs_control = true;
269 spi_context_cs_control(&data->ctx, true);
270 }
271
272 /* Perform transfer */
273 spi_opentitan_xfer(dev, gpio_cs_control);
274
275 rc = spi_context_wait_for_completion(&data->ctx);
276
277 spi_context_release(&data->ctx, rc);
278
279 return rc;
280 }
281
282 #ifdef CONFIG_SPI_ASYNC
spi_opentitan_transceive_async(const struct device * dev,const struct spi_config * spi_cfg,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs,spi_callback_t cb,void * userdata)283 static int spi_opentitan_transceive_async(const struct device *dev,
284 const struct spi_config *spi_cfg,
285 const struct spi_buf_set *tx_bufs,
286 const struct spi_buf_set *rx_bufs,
287 spi_callback_t cb,
288 void *userdata)
289 {
290 return -ENOTSUP;
291 }
292 #endif
293
spi_opentitan_release(const struct device * dev,const struct spi_config * config)294 static int spi_opentitan_release(const struct device *dev,
295 const struct spi_config *config)
296 {
297 struct spi_opentitan_data *data = dev->data;
298
299 spi_context_unlock_unconditionally(&data->ctx);
300 return 0;
301 }
302
303 /* Device Instantiation */
304
305 static DEVICE_API(spi, spi_opentitan_api) = {
306 .transceive = spi_opentitan_transceive,
307 #ifdef CONFIG_SPI_ASYNC
308 .transceive_async = spi_opentitan_transceive_async,
309 #endif
310 #ifdef CONFIG_SPI_RTIO
311 .iodev_submit = spi_rtio_iodev_default_submit,
312 #endif
313 .release = spi_opentitan_release,
314 };
315
316 #define SPI_INIT(n) \
317 static struct spi_opentitan_data spi_opentitan_data_##n = { \
318 SPI_CONTEXT_INIT_LOCK(spi_opentitan_data_##n, ctx), \
319 SPI_CONTEXT_INIT_SYNC(spi_opentitan_data_##n, ctx), \
320 SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \
321 }; \
322 static struct spi_opentitan_cfg spi_opentitan_cfg_##n = { \
323 .base = DT_INST_REG_ADDR(n), \
324 .f_input = DT_INST_PROP(n, clock_frequency), \
325 }; \
326 SPI_DEVICE_DT_INST_DEFINE(n, \
327 spi_opentitan_init, \
328 NULL, \
329 &spi_opentitan_data_##n, \
330 &spi_opentitan_cfg_##n, \
331 POST_KERNEL, \
332 CONFIG_SPI_INIT_PRIORITY, \
333 &spi_opentitan_api);
334
335 DT_INST_FOREACH_STATUS_OKAY(SPI_INIT)
336