1 /*
2 * Copyright (c) 2024 GARDENA GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT silabs_si32_dma
8
9 #include <SI32_CLKCTRL_A_Type.h>
10 #include <SI32_DMACTRL_A_Type.h>
11 #include <SI32_DMADESC_A_Type.h>
12 #include <SI32_SCONFIG_A_Type.h>
13 #include <si32_device.h>
14
15 #include <soc.h>
16 #include <zephyr/device.h>
17 #include <zephyr/drivers/dma.h>
18 #include <zephyr/irq.h>
19
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(dma_si32, CONFIG_DMA_LOG_LEVEL);
22
23 #include <errno.h>
24 #include <inttypes.h>
25 #include <stdint.h>
26
27 /*
28 * Having just one instance allows to avoid using the passed `struct device *` arguments, which in
29 * turn (slightly) reduces verification code and flash space needed.
30 */
31 BUILD_ASSERT((uintptr_t)SI32_DMACTRL_0 == (uintptr_t)DT_INST_REG_ADDR(0),
32 "There is just one DMA controller");
33
34 #define CHANNEL_COUNT DT_INST_PROP(0, dma_channels) /* number of used/enabled DMA channels */
35
36 struct dma_si32_channel_data {
37 dma_callback_t callback;
38 void *callback_user_data;
39 unsigned int tmd: 3; /* transfer mode */
40 unsigned int memory_to_memory: 1;
41 };
42
43 struct dma_si32_data {
44 struct dma_context ctx; /* Must be first according to the API docs */
45 struct dma_si32_channel_data channel_data[CHANNEL_COUNT];
46 };
47
48 ATOMIC_DEFINE(dma_si32_atomic, CHANNEL_COUNT);
49 static struct dma_si32_data dma_si32_data = {.ctx = {
50 .magic = DMA_MAGIC,
51 .atomic = dma_si32_atomic,
52 .dma_channels = CHANNEL_COUNT,
53 }};
54
55 __aligned(SI32_DMADESC_PRI_ALIGN) struct SI32_DMADESC_A_Struct channel_descriptors[CHANNEL_COUNT];
56
dma_si32_isr_handler(const uint8_t channel)57 static void dma_si32_isr_handler(const uint8_t channel)
58 {
59 const struct SI32_DMADESC_A_Struct *channel_descriptor = &channel_descriptors[channel];
60 const dma_callback_t cb = dma_si32_data.channel_data[channel].callback;
61 void *user_data = dma_si32_data.channel_data[channel].callback_user_data;
62 int result;
63
64 LOG_INF("Channel %" PRIu8 " ISR fired", channel);
65
66 irq_disable(DMACH0_IRQn + channel);
67
68 if (SI32_DMACTRL_A_is_bus_error_set(SI32_DMACTRL_0)) {
69 LOG_ERR("Bus error on channel %" PRIu8, channel);
70 result = -EIO;
71 } else {
72 result = DMA_STATUS_COMPLETE;
73 __ASSERT(channel_descriptor->CONFIG.TMD == 0, "Result of success: TMD set to zero");
74 __ASSERT(channel_descriptor->CONFIG.NCOUNT == 0,
75 "Result of success: All blocks processed");
76 (void)channel_descriptor;
77 __ASSERT((SI32_DMACTRL_0->CHENSET.U32 & BIT(channel)) == 0,
78 "Result of success: Channel disabled");
79 }
80
81 if (!cb) {
82 return;
83 }
84
85 cb(DEVICE_DT_INST_GET(0), user_data, channel, result);
86 }
87
88 #define DMA_SI32_IRQ_CONNECT(channel) \
89 do { \
90 IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, channel, irq), \
91 DT_INST_IRQ_BY_IDX(0, channel, priority), dma_si32_isr_handler, \
92 channel, 0); \
93 } while (false)
94
95 #define DMA_SI32_IRQ_CONNECT_GEN(i, _) DMA_SI32_IRQ_CONNECT(i);
96
dma_si32_init(const struct device * dev)97 static int dma_si32_init(const struct device *dev)
98 {
99 ARG_UNUSED(dev);
100
101 __ASSERT(SI32_DMACTRL_0 == SI32_DMACTRL_0, "There is only one DMA controller");
102 __ASSERT(SI32_DMACTRL_A_get_number_of_channels(SI32_DMACTRL_0) >= CHANNEL_COUNT,
103 "Invalid channel count");
104
105 /* Route clock to the DMA controller */
106 SI32_CLKCTRL_A_enable_ahb_to_dma_controller(SI32_CLKCTRL_0);
107
108 /* Configure base address of the DMA channel descriptors */
109 SI32_DMACTRL_A_write_baseptr(SI32_DMACTRL_0, (uintptr_t)channel_descriptors);
110
111 /* Enable the DMA interface */
112 SI32_DMACTRL_A_enable_module(SI32_DMACTRL_0);
113
114 /* Primary descriptors only. This driver does do not support the more complex cases yet. */
115 SI32_DMACTRL_A_write_chalt(SI32_DMACTRL_0, 0);
116
117 /* AN666.pdf: The SCONFIG module contains a bit (FDMAEN) that enables faster DMA transfers
118 * when set to 1. It is recommended that all applications using the DMA set this bit to 1.
119 */
120 SI32_SCONFIG_A_enter_fast_dma_mode(SI32_SCONFIG_0);
121
122 /* Install handlers for all channels */
123 LISTIFY(DT_NUM_IRQS(DT_DRV_INST(0)), DMA_SI32_IRQ_CONNECT_GEN, (;));
124
125 return 0;
126 }
127
dma_si32_config(const struct device * dev,uint32_t channel,struct dma_config * cfg)128 static int dma_si32_config(const struct device *dev, uint32_t channel, struct dma_config *cfg)
129 {
130 ARG_UNUSED(dev);
131
132 const struct dma_block_config *block;
133 struct SI32_DMADESC_A_Struct *channel_descriptor;
134 struct dma_si32_channel_data *channel_data;
135 uint32_t ncount;
136
137 LOG_INF("Configuring channel %" PRIu8, channel);
138
139 if (channel >= CHANNEL_COUNT) {
140 LOG_ERR("Invalid channel (id %" PRIu32 ", have %d)", channel, CHANNEL_COUNT);
141 return -EINVAL;
142 }
143
144 /* Prevent messing up (potentially) ongoing DMA operations and their settings. This behavior
145 * is required by the Zephyr DMA API.
146 */
147 if (SI32_DMACTRL_A_is_channel_enabled(SI32_DMACTRL_0, channel)) {
148 LOG_ERR("DMA channel is currently in use");
149 return -EBUSY;
150 }
151
152 channel_descriptor = &channel_descriptors[channel];
153
154 if (cfg == NULL) {
155 LOG_ERR("Missing config");
156 return -EINVAL;
157 }
158
159 if (cfg->complete_callback_en > 1) {
160 LOG_ERR("Callback on each block not implemented");
161 return -ENOTSUP;
162 }
163
164 if (cfg->error_callback_dis > 1) {
165 LOG_ERR("Error callback disabling not implemented");
166 return -ENOTSUP;
167 }
168
169 if (cfg->source_handshake > 1 || cfg->dest_handshake > 1) {
170 LOG_ERR("Handshake not implemented");
171 return -ENOTSUP;
172 }
173
174 if (cfg->channel_priority > 1) {
175 LOG_ERR("Channel priority not implemented");
176 return -ENOTSUP;
177 }
178
179 if (cfg->source_chaining_en > 1 || cfg->dest_chaining_en > 1) {
180 LOG_ERR("Chaining not implemented");
181 return -ENOTSUP;
182 }
183
184 if (cfg->linked_channel > 1) {
185 LOG_ERR("Linked channel not implemented");
186 return -ENOTSUP;
187 }
188
189 if (cfg->cyclic > 1) {
190 LOG_ERR("Cyclic transfer not implemented");
191 return -ENOTSUP;
192 }
193
194 if (cfg->source_data_size != 1 && cfg->source_data_size != 2 &&
195 cfg->source_data_size != 4) {
196 LOG_ERR("source_data_size must be 1, 2, or 4 (%" PRIu32 ")", cfg->source_data_size);
197 return -ENOTSUP;
198 }
199
200 if (cfg->dest_data_size != 1 && cfg->dest_data_size != 2 && cfg->dest_data_size != 4) {
201 LOG_ERR("dest_data_size must be 1, 2, or 4 (%" PRIu32 ")", cfg->dest_data_size);
202 return -ENOTSUP;
203 }
204
205 __ASSERT(cfg->source_data_size == cfg->dest_data_size,
206 "The destination size (DSTSIZE) must equal the source size (SRCSIZE).");
207
208 if (cfg->source_burst_length != cfg->dest_burst_length) {
209 LOG_ERR("Individual burst modes not supported");
210 return -ENOTSUP;
211 }
212
213 if (POPCOUNT(cfg->source_burst_length) > 1) {
214 LOG_ERR("Burst lengths must be power of two");
215 return -ENOTSUP;
216 }
217
218 if (cfg->block_count > 1) {
219 LOG_ERR("Scatter-Gather not implemented");
220 return -ENOTSUP;
221 }
222
223 /* Config is sane, start using it */
224 channel_data = &dma_si32_data.channel_data[channel];
225 channel_data->callback = cfg->dma_callback;
226 channel_data->callback_user_data = cfg->user_data;
227
228 switch (cfg->source_data_size) {
229 case 4:
230 channel_descriptor->CONFIG.SRCSIZE = 0b10;
231 channel_descriptor->CONFIG.DSTSIZE = 0b10;
232 channel_descriptor->CONFIG.RPOWER =
233 cfg->source_burst_length ? find_msb_set(cfg->source_burst_length) - 3 : 0;
234 break;
235 case 2:
236 channel_descriptor->CONFIG.SRCSIZE = 0b01;
237 channel_descriptor->CONFIG.DSTSIZE = 0b01;
238 channel_descriptor->CONFIG.RPOWER =
239 cfg->source_burst_length ? find_msb_set(cfg->source_burst_length) - 2 : 0;
240 break;
241 case 1:
242 channel_descriptor->CONFIG.SRCSIZE = 0b00;
243 channel_descriptor->CONFIG.DSTSIZE = 0b00;
244 channel_descriptor->CONFIG.RPOWER =
245 cfg->source_burst_length ? find_msb_set(cfg->source_burst_length) - 1 : 0;
246 break;
247 default:
248 LOG_ERR("source_data_size must be 1, 2, or 4 (%" PRIu32 ")", cfg->source_data_size);
249 return -EINVAL;
250 }
251
252 /* Configuration evaluated and extracted, except for its (first) block. Do this now. */
253 if (!cfg->head_block || cfg->block_count == 0) {
254 LOG_ERR("Missing head block");
255 return -EINVAL;
256 }
257
258 block = cfg->head_block;
259
260 if (block->block_size % cfg->source_data_size != 0) {
261 LOG_ERR("Block size not a multiple of data size");
262 return -EINVAL;
263 }
264
265 if (block->source_address % cfg->source_data_size != 0) {
266 LOG_ERR("Block source address not aligned with source data size");
267 return -EINVAL;
268 }
269
270 if (block->dest_address % cfg->dest_data_size != 0) {
271 LOG_ERR("Block dest address not aligned with dest data size");
272 return -EINVAL;
273 }
274
275 ncount = block->block_size / cfg->source_data_size - 1;
276
277 /* NCOUNT (10 bits wide) works only for values up to 1023 (1024 transfers) */
278 if (ncount >= 1024) {
279 LOG_ERR("Transfer size exceeded");
280 return -EINVAL;
281 }
282
283 channel_descriptor->CONFIG.NCOUNT = ncount;
284
285 /* Copy data to own location so that cfg must not exist during all of the channels usage */
286 switch (cfg->channel_direction) {
287 case 0b000: /* memory to memory */
288 /* SiM3U1xx-SiM3C1xx-RM.pdf, 16.6.2. Auto-Request Transfers: This transfer type is
289 * recommended for memory to memory transfers.
290 */
291 channel_data->tmd = SI32_DMADESC_A_CONFIG_TMD_AUTO_REQUEST_VALUE;
292 channel_data->memory_to_memory = 1;
293 SI32_DMACTRL_A_disable_data_request(SI32_DMACTRL_0, channel);
294 break;
295 case 0b001: /* memory to peripheral */
296 case 0b010: /* peripheral to memory */
297 /* SiM3U1xx-SiM3C1xx-RM.pdf, 4.3.1. Basic Transfers: This transfer type is
298 * recommended for peripheral-to-memory or memory-to-peripheral transfers.
299 */
300 channel_data->tmd = SI32_DMADESC_A_CONFIG_TMD_BASIC_VALUE;
301 channel_data->memory_to_memory = 0;
302 SI32_DMACTRL_A_enable_data_request(SI32_DMACTRL_0, channel);
303 break;
304 default: /* everything else is not (yet) supported */
305 LOG_ERR("Channel direction not implemented: %d", cfg->channel_direction);
306 return -ENOTSUP;
307 }
308
309 switch (block->source_addr_adj) {
310 case 0b00: /* increment */
311 channel_descriptor->SRCEND.U32 =
312 block->source_address + ncount * cfg->source_data_size;
313 channel_descriptor->CONFIG.SRCAIMD = channel_descriptor->CONFIG.SRCSIZE;
314 break;
315 case 0b01: /* decrement */
316 LOG_ERR("source_addr_adj value not supported by HW");
317 return -ENOTSUP;
318 case 0b10: /* no change */
319 channel_descriptor->SRCEND.U32 = block->source_address;
320 channel_descriptor->CONFIG.SRCAIMD = 0b11;
321 break;
322 default:
323 LOG_ERR("Unknown source_addr_adj value");
324 return -EINVAL;
325 }
326
327 switch (block->dest_addr_adj) {
328 case 0b00: /* increment */
329 channel_descriptor->DSTEND.U32 = block->dest_address + ncount * cfg->dest_data_size;
330 channel_descriptor->CONFIG.DSTAIMD = channel_descriptor->CONFIG.DSTSIZE;
331 break;
332 case 0b01: /* decrement */
333 LOG_ERR("dest_addr_adj value not supported by HW");
334 return -ENOTSUP;
335 case 0b10: /* no change */
336 channel_descriptor->DSTEND.U32 = block->dest_address;
337 channel_descriptor->CONFIG.DSTAIMD = 0b11;
338 break;
339 default:
340 LOG_ERR("Unknown dest_addr_adj value");
341 return -EINVAL;
342 }
343
344 return 0;
345 }
346
dma_si32_start(const struct device * dev,const uint32_t channel)347 static int dma_si32_start(const struct device *dev, const uint32_t channel)
348 {
349 ARG_UNUSED(dev);
350
351 struct SI32_DMADESC_A_Struct *channel_desc = &channel_descriptors[channel];
352 struct dma_si32_channel_data *channel_data;
353
354 LOG_INF("Starting channel %" PRIu8, channel);
355
356 if (channel >= CHANNEL_COUNT) {
357 LOG_ERR("Invalid channel (id %" PRIu32 ", have %d)", channel, CHANNEL_COUNT);
358 return -EINVAL;
359 }
360
361 channel_data = &dma_si32_data.channel_data[channel];
362
363 /* All of this should be set by our own, previously running code. During development
364 * however, it is still useful to double check here.
365 */
366 __ASSERT(SI32_CLKCTRL_0->AHBCLKG.DMACEN,
367 "AHB clock to the DMA controller must be enabled.");
368 __ASSERT(SI32_DMACTRL_A_is_enabled(SI32_DMACTRL_0), "DMA controller must be enabled.");
369 __ASSERT(SI32_DMACTRL_0->BASEPTR.U32 == (uintptr_t)channel_descriptors,
370 "Address location of the channel transfer descriptors (BASEPTR) must be set.");
371 __ASSERT(SI32_DMACTRL_A_is_primary_selected(SI32_DMACTRL_0, channel),
372 "Primary descriptors must be used for basic and auto-request operations.");
373 __ASSERT(SI32_SCONFIG_0->CONFIG.FDMAEN, "Fast mode is recommened to be enabled.");
374 __ASSERT(SI32_DMACTRL_0->CHSTATUS.U32 & BIT(channel),
375 "Channel must be waiting for request");
376
377 channel_desc->CONFIG.TMD = channel_data->tmd;
378
379 /* Get rid of potentially lingering bus errors. */
380 SI32_DMACTRL_A_clear_bus_error(SI32_DMACTRL_0);
381
382 /* Enable interrupt for this DMA channels. */
383 irq_enable(DMACH0_IRQn + channel);
384
385 SI32_DMACTRL_A_enable_channel(SI32_DMACTRL_0, channel);
386
387 /* memory-to-memory transfers have to be started by this driver. When peripherals are
388 * involved, the caller has to enable the peripheral to start the transfer.
389 */
390 if (dma_si32_data.channel_data[channel].memory_to_memory) {
391 __ASSERT((SI32_DMACTRL_0->CHREQMSET.U32 & BIT(channel)),
392 "Peripheral data requests for the channel must be disabled");
393 SI32_DMACTRL_A_generate_software_request(SI32_DMACTRL_0, channel);
394 } else {
395 __ASSERT(!(SI32_DMACTRL_0->CHREQMSET.U32 & BIT(channel)),
396 "Data requests for the channel must be enabled");
397 }
398
399 return 0;
400 }
401
dma_si32_stop(const struct device * dev,const uint32_t channel)402 static int dma_si32_stop(const struct device *dev, const uint32_t channel)
403 {
404 ARG_UNUSED(dev);
405
406 if (channel >= CHANNEL_COUNT) {
407 LOG_ERR("Invalid channel (id %" PRIu32 ", have %d)", channel, CHANNEL_COUNT);
408 return -EINVAL;
409 }
410
411 irq_disable(DMACH0_IRQn + channel);
412
413 channel_descriptors[channel].CONFIG.TMD = 0; /* Stop the DMA channel. */
414
415 SI32_DMACTRL_A_disable_channel(SI32_DMACTRL_0, channel);
416
417 return 0;
418 }
419
420 static DEVICE_API(dma, dma_si32_driver_api) = {
421 .config = dma_si32_config,
422 .start = dma_si32_start,
423 .stop = dma_si32_stop,
424 };
425
426 DEVICE_DT_INST_DEFINE(0, &dma_si32_init, NULL, NULL, NULL, POST_KERNEL, CONFIG_DMA_INIT_PRIORITY,
427 &dma_si32_driver_api);
428