1 /*
2  * Copyright (c) 2023 TOKITA Hiroshi <tokita.hiroshi@fujitsu.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/clock_control.h>
9 #include <zephyr/drivers/dma.h>
10 #include <zephyr/drivers/reset.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/irq.h>
13 #if defined(CONFIG_SOC_SERIES_RP2040)
14 #include <zephyr/dt-bindings/dma/rpi-pico-dma-rp2040.h>
15 #elif defined(CONFIG_SOC_SERIES_RP2350)
16 #include <zephyr/dt-bindings/dma/rpi-pico-dma-rp2350.h>
17 #endif
18 
19 #include <hardware/dma.h>
20 
21 #define DT_DRV_COMPAT raspberrypi_pico_dma
22 
23 #define DMA_INT_ERROR_FLAGS                                                                        \
24 	(DMA_CH0_CTRL_TRIG_AHB_ERROR_BITS | DMA_CH0_CTRL_TRIG_READ_ERROR_BITS |                    \
25 	 DMA_CH0_CTRL_TRIG_WRITE_ERROR_BITS)
26 
27 LOG_MODULE_REGISTER(dma_rpi_pico, CONFIG_DMA_LOG_LEVEL);
28 
29 struct dma_rpi_pico_config {
30 	uint32_t reg;
31 	uint32_t channels;
32 	struct reset_dt_spec reset;
33 	void (*irq_configure)(void);
34 	uint32_t *irq0_channels;
35 	size_t irq0_channels_size;
36 };
37 
38 struct dma_rpi_pico_channel {
39 	dma_callback_t callback;
40 	void *user_data;
41 	uint32_t direction;
42 	dma_channel_config config;
43 	void *source_address;
44 	void *dest_address;
45 	size_t block_size;
46 };
47 
48 struct dma_rpi_pico_data {
49 	struct dma_context ctx;
50 	struct dma_rpi_pico_channel *channels;
51 };
52 
53 /*
54  * Register access functions
55  */
56 
rpi_pico_dma_channel_clear_error_flags(const struct device * dev,uint32_t channel)57 static inline void rpi_pico_dma_channel_clear_error_flags(const struct device *dev,
58 							  uint32_t channel)
59 {
60 	const struct dma_rpi_pico_config *cfg = dev->config;
61 
62 	((dma_hw_t *)cfg->reg)->ch[channel].al1_ctrl &= ~DMA_INT_ERROR_FLAGS;
63 }
64 
rpi_pico_dma_channel_get_error_flags(const struct device * dev,uint32_t channel)65 static inline uint32_t rpi_pico_dma_channel_get_error_flags(const struct device *dev,
66 							    uint32_t channel)
67 {
68 	const struct dma_rpi_pico_config *cfg = dev->config;
69 
70 	return ((dma_hw_t *)cfg->reg)->ch[channel].al1_ctrl & DMA_INT_ERROR_FLAGS;
71 }
72 
rpi_pico_dma_channel_abort(const struct device * dev,uint32_t channel)73 static inline void rpi_pico_dma_channel_abort(const struct device *dev, uint32_t channel)
74 {
75 	const struct dma_rpi_pico_config *cfg = dev->config;
76 
77 	((dma_hw_t *)cfg->reg)->abort = BIT(channel);
78 }
79 
80 /*
81  * Utility functions
82  */
83 
dma_rpi_pico_transfer_size(uint32_t width)84 static inline uint32_t dma_rpi_pico_transfer_size(uint32_t width)
85 {
86 	switch (width) {
87 	case 4:
88 		return DMA_SIZE_32;
89 	case 2:
90 		return DMA_SIZE_16;
91 	default:
92 		return DMA_SIZE_8;
93 	}
94 }
95 
dma_rpi_pico_channel_irq(const struct device * dev,uint32_t channel)96 static inline uint32_t dma_rpi_pico_channel_irq(const struct device *dev, uint32_t channel)
97 {
98 	const struct dma_rpi_pico_config *cfg = dev->config;
99 
100 	for (size_t i = 0; i < cfg->irq0_channels_size; i++) {
101 		if (cfg->irq0_channels[i] == channel) {
102 			return 0;
103 		}
104 	}
105 
106 	return 1;
107 }
108 
109 /*
110  * API functions
111  */
112 
dma_rpi_pico_config(const struct device * dev,uint32_t channel,struct dma_config * dma_cfg)113 static int dma_rpi_pico_config(const struct device *dev, uint32_t channel,
114 			       struct dma_config *dma_cfg)
115 {
116 	const struct dma_rpi_pico_config *cfg = dev->config;
117 	struct dma_rpi_pico_data *data = dev->data;
118 
119 	if (channel >= cfg->channels) {
120 		LOG_ERR("channel must be < %" PRIu32 " (%" PRIu32 ")", cfg->channels, channel);
121 		return -EINVAL;
122 	}
123 
124 	if (dma_cfg->block_count != 1) {
125 		LOG_ERR("chained block transfer not supported.");
126 		return -ENOTSUP;
127 	}
128 
129 	if (dma_cfg->channel_priority > 3) {
130 		LOG_ERR("channel_priority must be < 4 (%" PRIu32 ")", dma_cfg->channel_priority);
131 		return -EINVAL;
132 	}
133 
134 	if (dma_cfg->head_block->source_addr_adj == DMA_ADDR_ADJ_DECREMENT) {
135 		LOG_ERR("source_addr_adj not supported DMA_ADDR_ADJ_DECREMENT");
136 		return -ENOTSUP;
137 	}
138 
139 	if (dma_cfg->head_block->dest_addr_adj == DMA_ADDR_ADJ_DECREMENT) {
140 		LOG_ERR("dest_addr_adj not supported DMA_ADDR_ADJ_DECREMENT");
141 		return -ENOTSUP;
142 	}
143 
144 	if (dma_cfg->head_block->source_addr_adj != DMA_ADDR_ADJ_INCREMENT &&
145 	    dma_cfg->head_block->source_addr_adj != DMA_ADDR_ADJ_NO_CHANGE) {
146 		LOG_ERR("invalid source_addr_adj %" PRIu16, dma_cfg->head_block->source_addr_adj);
147 		return -ENOTSUP;
148 	}
149 	if (dma_cfg->head_block->dest_addr_adj != DMA_ADDR_ADJ_INCREMENT &&
150 	    dma_cfg->head_block->dest_addr_adj != DMA_ADDR_ADJ_NO_CHANGE) {
151 		LOG_ERR("invalid dest_addr_adj %" PRIu16, dma_cfg->head_block->dest_addr_adj);
152 		return -ENOTSUP;
153 	}
154 
155 	if (dma_cfg->source_data_size != 1 && dma_cfg->source_data_size != 2 &&
156 	    dma_cfg->source_data_size != 4) {
157 		LOG_ERR("source_data_size must be 1, 2, or 4 (%" PRIu32 ")",
158 			dma_cfg->source_data_size);
159 		return -EINVAL;
160 	}
161 
162 	if (dma_cfg->source_data_size != dma_cfg->dest_data_size) {
163 		return -EINVAL;
164 	}
165 
166 	if (dma_cfg->dest_data_size != 1 && dma_cfg->dest_data_size != 2 &&
167 	    dma_cfg->dest_data_size != 4) {
168 		LOG_ERR("dest_data_size must be 1, 2, or 4 (%" PRIu32 ")", dma_cfg->dest_data_size);
169 		return -EINVAL;
170 	}
171 
172 	if (dma_cfg->channel_direction > PERIPHERAL_TO_MEMORY) {
173 		LOG_ERR("channel_direction must be MEMORY_TO_MEMORY, "
174 			"MEMORY_TO_PERIPHERAL or PERIPHERAL_TO_MEMORY (%" PRIu32 ")",
175 			dma_cfg->channel_direction);
176 		return -ENOTSUP;
177 	}
178 
179 	data->channels[channel].config = dma_channel_get_default_config(channel);
180 
181 	data->channels[channel].source_address = (void *)dma_cfg->head_block->source_address;
182 	data->channels[channel].dest_address = (void *)dma_cfg->head_block->dest_address;
183 	data->channels[channel].block_size = dma_cfg->head_block->block_size;
184 	channel_config_set_read_increment(&data->channels[channel].config,
185 					  dma_cfg->head_block->source_addr_adj ==
186 						  DMA_ADDR_ADJ_INCREMENT);
187 	channel_config_set_write_increment(&data->channels[channel].config,
188 					   dma_cfg->head_block->dest_addr_adj ==
189 						   DMA_ADDR_ADJ_INCREMENT);
190 	channel_config_set_transfer_data_size(
191 		&data->channels[channel].config,
192 		dma_rpi_pico_transfer_size(dma_cfg->source_data_size));
193 	channel_config_set_dreq(&data->channels[channel].config,
194 				RPI_PICO_DMA_SLOT_TO_DREQ(dma_cfg->dma_slot));
195 	channel_config_set_high_priority(&data->channels[channel].config,
196 					 !!(dma_cfg->channel_priority));
197 
198 	data->channels[channel].callback = dma_cfg->dma_callback;
199 	data->channels[channel].user_data = dma_cfg->user_data;
200 	data->channels[channel].direction = dma_cfg->channel_direction;
201 
202 	return 0;
203 }
204 
dma_rpi_pico_reload(const struct device * dev,uint32_t ch,uint32_t src,uint32_t dst,size_t size)205 static int dma_rpi_pico_reload(const struct device *dev, uint32_t ch, uint32_t src, uint32_t dst,
206 			       size_t size)
207 {
208 	const struct dma_rpi_pico_config *cfg = dev->config;
209 	struct dma_rpi_pico_data *data = dev->data;
210 
211 	if (ch >= cfg->channels) {
212 		LOG_ERR("reload channel must be < %" PRIu32 " (%" PRIu32 ")", cfg->channels, ch);
213 		return -EINVAL;
214 	}
215 
216 	if (dma_channel_is_busy(ch)) {
217 		return -EBUSY;
218 	}
219 
220 	data->channels[ch].source_address = (void *)src;
221 	data->channels[ch].dest_address = (void *)dst;
222 	data->channels[ch].block_size = size;
223 	dma_channel_configure(ch, &data->channels[ch].config, data->channels[ch].dest_address,
224 			      data->channels[ch].source_address, data->channels[ch].block_size,
225 			      true);
226 
227 	return 0;
228 }
229 
dma_rpi_pico_start(const struct device * dev,uint32_t ch)230 static int dma_rpi_pico_start(const struct device *dev, uint32_t ch)
231 {
232 	const struct dma_rpi_pico_config *cfg = dev->config;
233 	struct dma_rpi_pico_data *data = dev->data;
234 
235 	if (ch >= cfg->channels) {
236 		LOG_ERR("start channel must be < %" PRIu32 " (%" PRIu32 ")", cfg->channels, ch);
237 		return -EINVAL;
238 	}
239 
240 	dma_irqn_acknowledge_channel(dma_rpi_pico_channel_irq(dev, ch), ch);
241 	dma_irqn_set_channel_enabled(dma_rpi_pico_channel_irq(dev, ch), ch, true);
242 
243 	dma_channel_configure(ch, &data->channels[ch].config, data->channels[ch].dest_address,
244 			      data->channels[ch].source_address, data->channels[ch].block_size,
245 			      true);
246 
247 	return 0;
248 }
249 
dma_rpi_pico_stop(const struct device * dev,uint32_t ch)250 static int dma_rpi_pico_stop(const struct device *dev, uint32_t ch)
251 {
252 	const struct dma_rpi_pico_config *cfg = dev->config;
253 
254 	if (ch >= cfg->channels) {
255 		LOG_ERR("stop channel must be < %" PRIu32 " (%" PRIu32 ")", cfg->channels, ch);
256 		return -EINVAL;
257 	}
258 
259 	dma_irqn_set_channel_enabled(dma_rpi_pico_channel_irq(dev, ch), ch, false);
260 	rpi_pico_dma_channel_clear_error_flags(dev, ch);
261 
262 	/*
263 	 * Considering the possibility of being called in an interrupt context,
264 	 * it does not wait until the abort bit becomes clear.
265 	 * Ensure the busy status is canceled with dma_get_status
266 	 * before the next transfer starts.
267 	 */
268 	rpi_pico_dma_channel_abort(dev, ch);
269 
270 	return 0;
271 }
272 
dma_rpi_pico_get_status(const struct device * dev,uint32_t ch,struct dma_status * stat)273 static int dma_rpi_pico_get_status(const struct device *dev, uint32_t ch, struct dma_status *stat)
274 {
275 	const struct dma_rpi_pico_config *cfg = dev->config;
276 	struct dma_rpi_pico_data *data = dev->data;
277 
278 	if (ch >= cfg->channels) {
279 		LOG_ERR("channel must be < %" PRIu32 " (%" PRIu32 ")", cfg->channels, ch);
280 		return -EINVAL;
281 	}
282 
283 	stat->pending_length = 0;
284 	stat->dir = data->channels[ch].direction;
285 	stat->busy = dma_channel_is_busy(ch);
286 
287 	return 0;
288 }
289 
dma_rpi_pico_api_chan_filter(const struct device * dev,int ch,void * filter_param)290 static bool dma_rpi_pico_api_chan_filter(const struct device *dev, int ch, void *filter_param)
291 {
292 	uint32_t filter;
293 
294 	if (!filter_param) {
295 		return true;
296 	}
297 
298 	filter = *((uint32_t *)filter_param);
299 
300 	return (filter & BIT(ch));
301 }
302 
dma_rpi_pico_init(const struct device * dev)303 static int dma_rpi_pico_init(const struct device *dev)
304 {
305 	const struct dma_rpi_pico_config *cfg = dev->config;
306 
307 	(void)reset_line_toggle_dt(&cfg->reset);
308 
309 	cfg->irq_configure();
310 
311 	return 0;
312 }
313 
dma_rpi_pico_isr(const struct device * dev)314 static void dma_rpi_pico_isr(const struct device *dev)
315 {
316 	const struct dma_rpi_pico_config *cfg = dev->config;
317 	struct dma_rpi_pico_data *data = dev->data;
318 	int err = 0;
319 
320 	for (uint32_t i = 0; i < cfg->channels; i++) {
321 		if (!dma_irqn_get_channel_status(dma_rpi_pico_channel_irq(dev, i), i)) {
322 			continue;
323 		}
324 
325 		if (rpi_pico_dma_channel_get_error_flags(dev, i)) {
326 			err = -EIO;
327 		}
328 
329 		dma_irqn_acknowledge_channel(dma_rpi_pico_channel_irq(dev, i), i);
330 		dma_irqn_set_channel_enabled(dma_rpi_pico_channel_irq(dev, i), i, false);
331 		rpi_pico_dma_channel_clear_error_flags(dev, i);
332 
333 		if (data->channels[i].callback) {
334 			data->channels[i].callback(dev, data->channels[i].user_data, i, err);
335 		}
336 	}
337 }
338 
339 static DEVICE_API(dma, dma_rpi_pico_driver_api) = {
340 	.config = dma_rpi_pico_config,
341 	.reload = dma_rpi_pico_reload,
342 	.start = dma_rpi_pico_start,
343 	.stop = dma_rpi_pico_stop,
344 	.get_status = dma_rpi_pico_get_status,
345 	.chan_filter = dma_rpi_pico_api_chan_filter,
346 };
347 
348 #define IRQ_CONFIGURE(n, inst)                                                                     \
349 	IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, n, irq), DT_INST_IRQ_BY_IDX(inst, n, priority),       \
350 		    dma_rpi_pico_isr, DEVICE_DT_INST_GET(inst), 0);                                \
351 	irq_enable(DT_INST_IRQ_BY_IDX(inst, n, irq));
352 
353 #define CONFIGURE_ALL_IRQS(inst, n) LISTIFY(n, IRQ_CONFIGURE, (), inst)
354 
355 #define RPI_PICO_DMA_INIT(inst)                                                                    \
356 	static void dma_rpi_pico##inst##_irq_configure(void)                                       \
357 	{                                                                                          \
358 		CONFIGURE_ALL_IRQS(inst, DT_NUM_IRQS(DT_DRV_INST(inst)));                          \
359 	}                                                                                          \
360 	static uint32_t dma_rpi_pico##inst##_irq0_channels[] =                                     \
361 		DT_INST_PROP_OR(inst, irq0_channels, {0});                                         \
362 	static const struct dma_rpi_pico_config dma_rpi_pico##inst##_config = {                    \
363 		.reg = DT_INST_REG_ADDR(inst),                                                     \
364 		.channels = DT_INST_PROP(inst, dma_channels),                                      \
365 		.reset = RESET_DT_SPEC_INST_GET(inst),                                             \
366 		.irq_configure = dma_rpi_pico##inst##_irq_configure,                               \
367 		.irq0_channels = dma_rpi_pico##inst##_irq0_channels,                               \
368 		.irq0_channels_size = ARRAY_SIZE(dma_rpi_pico##inst##_irq0_channels),              \
369 	};                                                                                         \
370 	static struct dma_rpi_pico_channel                                                         \
371 		dma_rpi_pico##inst##_channels[DT_INST_PROP(inst, dma_channels)];                   \
372 	ATOMIC_DEFINE(dma_rpi_pico_atomic##inst, DT_INST_PROP(inst, dma_channels));                \
373 	static struct dma_rpi_pico_data dma_rpi_pico##inst##_data = {                              \
374 		.ctx =                                                                             \
375 			{                                                                          \
376 				.magic = DMA_MAGIC,                                                \
377 				.atomic = dma_rpi_pico_atomic##inst,                               \
378 				.dma_channels = DT_INST_PROP(inst, dma_channels),                  \
379 			},                                                                         \
380 		.channels = dma_rpi_pico##inst##_channels,                                         \
381 	};                                                                                         \
382                                                                                                    \
383 	DEVICE_DT_INST_DEFINE(inst, &dma_rpi_pico_init, NULL, &dma_rpi_pico##inst##_data,          \
384 			      &dma_rpi_pico##inst##_config, POST_KERNEL, CONFIG_DMA_INIT_PRIORITY, \
385 			      &dma_rpi_pico_driver_api);
386 
387 DT_INST_FOREACH_STATUS_OKAY(RPI_PICO_DMA_INIT)
388