1 /*
2  * Copyright 2020 Broadcom
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/dma.h>
9 #include <errno.h>
10 #include <zephyr/init.h>
11 #include <string.h>
12 #include <soc.h>
13 #include <zephyr/sys/__assert.h>
14 #include "dma_pl330.h"
15 
16 #define LOG_LEVEL CONFIG_DMA_LOG_LEVEL
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(dma_pl330);
19 
20 #define BYTE_WIDTH(burst_size) (1 << (burst_size))
21 
22 static int dma_pl330_submit(const struct device *dev, uint64_t dst,
23 			    uint64_t src, uint32_t channel, uint32_t size);
24 
dma_pl330_get_counter(struct dma_pl330_ch_internal * ch_handle,uint32_t * psrc_byte_width,uint32_t * pdst_byte_width,uint32_t * ploop_counter,uint32_t * presidue)25 static void dma_pl330_get_counter(struct dma_pl330_ch_internal *ch_handle,
26 				  uint32_t *psrc_byte_width,
27 				  uint32_t *pdst_byte_width,
28 				  uint32_t *ploop_counter,
29 				  uint32_t *presidue)
30 {
31 	uint32_t srcbytewidth, dstbytewidth;
32 	uint32_t loop_counter, residue;
33 
34 	srcbytewidth = BYTE_WIDTH(ch_handle->src_burst_sz);
35 	dstbytewidth = BYTE_WIDTH(ch_handle->dst_burst_sz);
36 
37 	loop_counter = ch_handle->trans_size /
38 		       (srcbytewidth * (ch_handle->src_burst_len + 1));
39 
40 	residue = ch_handle->trans_size - loop_counter *
41 		  (srcbytewidth * (ch_handle->src_burst_len + 1));
42 
43 	*psrc_byte_width = srcbytewidth;
44 	*pdst_byte_width = dstbytewidth;
45 	*ploop_counter = loop_counter;
46 	*presidue = residue;
47 }
48 
dma_pl330_ch_ccr(struct dma_pl330_ch_internal * ch_handle)49 static uint32_t dma_pl330_ch_ccr(struct dma_pl330_ch_internal *ch_handle)
50 {
51 	uint32_t ccr;
52 	int secure = ch_handle->nonsec_mode ? SRC_PRI_NONSEC_VALUE :
53 		     SRC_PRI_SEC_VALUE;
54 
55 	ccr = ((ch_handle->dst_cache_ctrl & CC_SRCCCTRL_MASK) <<
56 		CC_DSTCCTRL_SHIFT) +
57 	       ((ch_handle->nonsec_mode) << CC_DSTNS_SHIFT) +
58 	       (ch_handle->dst_burst_len << CC_DSTBRSTLEN_SHIFT) +
59 	       (ch_handle->dst_burst_sz << CC_DSTBRSTSIZE_SHIFT) +
60 	       (ch_handle->dst_inc << CC_DSTINC_SHIFT) +
61 	       ((ch_handle->src_cache_ctrl & CC_SRCCCTRL_MASK) <<
62 		CC_SRCCCTRL_SHIFT) +
63 	       (secure << CC_SRCPRI_SHIFT) +
64 	       (ch_handle->src_burst_len << CC_SRCBRSTLEN_SHIFT)  +
65 	       (ch_handle->src_burst_sz << CC_SRCBRSTSIZE_SHIFT)  +
66 	       (ch_handle->src_inc << CC_SRCINC_SHIFT);
67 
68 	return ccr;
69 }
70 
dma_pl330_calc_burstsz_len(struct dma_pl330_ch_internal * ch_handle,uint64_t dst,uint64_t src,uint32_t size)71 static void dma_pl330_calc_burstsz_len(struct dma_pl330_ch_internal *ch_handle,
72 				       uint64_t dst, uint64_t src,
73 				       uint32_t size)
74 {
75 	uint32_t byte_width, burst_sz, burst_len;
76 
77 	burst_sz = MAX_BURST_SIZE_LOG2;
78 	/* src, dst and size should be aligned to burst size in bytes */
79 	while ((src | dst | size) & ((BYTE_WIDTH(burst_sz)) - 1)) {
80 		burst_sz--;
81 	}
82 
83 	byte_width = BYTE_WIDTH(burst_sz);
84 
85 	burst_len = MAX_BURST_LEN;
86 	while (burst_len) {
87 		/* Choose burst length so that size is aligned */
88 		if (!(size % ((burst_len + 1) << byte_width))) {
89 			break;
90 		}
91 
92 		burst_len--;
93 	}
94 
95 	ch_handle->src_burst_len = burst_len;
96 	ch_handle->src_burst_sz = burst_sz;
97 	ch_handle->dst_burst_len = burst_len;
98 	ch_handle->dst_burst_sz = burst_sz;
99 }
100 
101 #ifdef CONFIG_DMA_64BIT
dma_pl330_cfg_dmac_add_control(uint32_t control_reg_base,uint64_t dst,uint64_t src,int ch)102 static void dma_pl330_cfg_dmac_add_control(uint32_t control_reg_base,
103 					   uint64_t dst, uint64_t src, int ch)
104 {
105 	uint32_t src_h = src >> 32;
106 	uint32_t dst_h = dst >> 32;
107 	uint32_t dmac_higher_addr;
108 
109 	dmac_higher_addr = ((dst_h & HIGHER_32_ADDR_MASK) << DST_ADDR_SHIFT) |
110 			   (src_h & HIGHER_32_ADDR_MASK);
111 
112 	sys_write32(dmac_higher_addr,
113 		    control_reg_base +
114 		    (ch * CONTROL_OFFSET)
115 		   );
116 }
117 #endif
118 
dma_pl330_config_channel(struct dma_pl330_ch_config * ch_cfg,uint64_t dst,uint64_t src,uint32_t size)119 static void dma_pl330_config_channel(struct dma_pl330_ch_config *ch_cfg,
120 				     uint64_t dst, uint64_t src, uint32_t size)
121 {
122 	struct dma_pl330_ch_internal *ch_handle = &ch_cfg->internal;
123 
124 	ch_handle->src_addr = src;
125 	ch_handle->dst_addr = dst;
126 	ch_handle->trans_size = size;
127 
128 	if (ch_cfg->src_addr_adj == DMA_ADDR_ADJ_INCREMENT) {
129 		ch_handle->src_inc = 1;
130 	}
131 
132 	if (ch_cfg->dst_addr_adj == DMA_ADDR_ADJ_INCREMENT) {
133 		ch_handle->dst_inc = 1;
134 	}
135 }
136 
dma_pl330_gen_mov(mem_addr_t buf,enum dmamov_type type,uint32_t val)137 static inline uint32_t dma_pl330_gen_mov(mem_addr_t buf,
138 					 enum dmamov_type type,
139 					 uint32_t val)
140 {
141 	sys_write8(OP_DMA_MOV, buf);
142 	sys_write8(type, buf + 1);
143 	sys_write8(val, buf + 2);
144 	sys_write8(val >> 8, buf + 3);
145 	sys_write8(val >> 16, buf + 4);
146 	sys_write8(val >> 24, buf + 5);
147 
148 	return SZ_CMD_DMAMOV;
149 }
150 
dma_pl330_gen_op(uint8_t opcode,uint32_t addr,uint32_t val)151 static inline void dma_pl330_gen_op(uint8_t opcode, uint32_t addr, uint32_t val)
152 {
153 	sys_write8(opcode, addr);
154 	sys_write8(val, addr + 1);
155 }
156 
dma_pl330_setup_ch(const struct device * dev,struct dma_pl330_ch_internal * ch_dat,int ch)157 static int dma_pl330_setup_ch(const struct device *dev,
158 			      struct dma_pl330_ch_internal *ch_dat,
159 			      int ch)
160 {
161 	mem_addr_t dma_exec_addr;
162 	uint32_t offset = 0, ccr;
163 	uint32_t lp0_start, lp1_start;
164 	uint32_t loop_counter0 = 0, loop_counter1 = 0;
165 	uint32_t srcbytewidth, dstbytewidth;
166 	uint32_t loop_counter, residue;
167 	struct dma_pl330_dev_data *const dev_data = dev->data;
168 	struct dma_pl330_ch_config *channel_cfg;
169 	int secure = ch_dat->nonsec_mode ? SRC_PRI_NONSEC_VALUE :
170 				SRC_PRI_SEC_VALUE;
171 
172 	channel_cfg = &dev_data->channels[ch];
173 	dma_exec_addr = channel_cfg->dma_exec_addr;
174 
175 	offset  += dma_pl330_gen_mov(dma_exec_addr,
176 				     SAR, ch_dat->src_addr);
177 
178 	offset  += dma_pl330_gen_mov(dma_exec_addr + offset,
179 				     DAR, ch_dat->dst_addr);
180 
181 	ccr = dma_pl330_ch_ccr(ch_dat);
182 
183 	offset  += dma_pl330_gen_mov(dma_exec_addr + offset,
184 				     CCR, ccr);
185 
186 	dma_pl330_get_counter(ch_dat, &srcbytewidth, &dstbytewidth,
187 			      &loop_counter, &residue);
188 
189 	if (loop_counter >= PL330_LOOP_COUNTER0_MAX) {
190 		loop_counter0 = PL330_LOOP_COUNTER0_MAX - 1;
191 		loop_counter1 = loop_counter / PL330_LOOP_COUNTER0_MAX - 1;
192 		dma_pl330_gen_op(OP_DMA_LOOP_COUNT1, dma_exec_addr + offset,
193 				 loop_counter1 & 0xff);
194 		offset = offset + 2;
195 		dma_pl330_gen_op(OP_DMA_LOOP, dma_exec_addr + offset,
196 				 loop_counter0 & 0xff);
197 		offset = offset + 2;
198 		lp1_start = offset;
199 		lp0_start = offset;
200 		sys_write8(OP_DMA_LD, dma_exec_addr + offset);
201 		sys_write8(OP_DMA_ST, dma_exec_addr + offset + 1);
202 		offset = offset + 2;
203 		dma_pl330_gen_op(OP_DMA_LP_BK_JMP1, dma_exec_addr + offset,
204 				 ((offset - lp0_start) & 0xff));
205 		offset = offset + 2;
206 		dma_pl330_gen_op(OP_DMA_LOOP, dma_exec_addr + offset,
207 				 (loop_counter0 & 0xff));
208 		offset = offset + 2;
209 		loop_counter1--;
210 		dma_pl330_gen_op(OP_DMA_LP_BK_JMP2, dma_exec_addr + offset,
211 				 ((offset - lp1_start) & 0xff));
212 		offset = offset + 2;
213 	}
214 
215 	if ((loop_counter % PL330_LOOP_COUNTER0_MAX) != 0) {
216 		loop_counter0 = (loop_counter % PL330_LOOP_COUNTER0_MAX) - 1;
217 		dma_pl330_gen_op(OP_DMA_LOOP, dma_exec_addr + offset,
218 				 (loop_counter0 & 0xff));
219 		offset = offset + 2;
220 		loop_counter1--;
221 		lp0_start = offset;
222 		sys_write8(OP_DMA_LD, dma_exec_addr + offset);
223 		sys_write8(OP_DMA_ST, dma_exec_addr + offset + 1);
224 		offset = offset + 2;
225 		dma_pl330_gen_op(OP_DMA_LP_BK_JMP1, dma_exec_addr + offset,
226 				 ((offset - lp0_start) & 0xff));
227 		offset = offset + 2;
228 	}
229 
230 	if (residue != 0) {
231 		ccr = ((ch_dat->nonsec_mode) << CC_DSTNS_SHIFT) +
232 		       (0x0 << CC_DSTBRSTLEN_SHIFT) +
233 		       (0x0 << CC_DSTBRSTSIZE_SHIFT) +
234 		       (ch_dat->dst_inc << CC_DSTINC_SHIFT) +
235 		       (secure << CC_SRCPRI_SHIFT) +
236 		       (0x0 << CC_SRCBRSTLEN_SHIFT) +
237 		       (0x0 << CC_SRCBRSTSIZE_SHIFT) +
238 		       ch_dat->src_inc;
239 		offset += dma_pl330_gen_mov(dma_exec_addr + offset,
240 					    CCR, ccr);
241 		dma_pl330_gen_op(OP_DMA_LOOP, dma_exec_addr + offset,
242 				 ((residue - 1) & 0xff));
243 		offset = offset + 2;
244 		lp0_start = offset;
245 		sys_write8(OP_DMA_LD, dma_exec_addr + offset);
246 		sys_write8(OP_DMA_ST, dma_exec_addr + offset + 1);
247 		offset = offset + 2;
248 		dma_pl330_gen_op(OP_DMA_LP_BK_JMP1, dma_exec_addr + offset,
249 				 ((offset - lp0_start) & 0xff));
250 		offset = offset + 2;
251 	}
252 
253 	sys_write8(OP_DMA_END, dma_exec_addr + offset);
254 	sys_write8(OP_DMA_END, dma_exec_addr + offset + 1);
255 	sys_write8(OP_DMA_END, dma_exec_addr + offset + 2);
256 	sys_write8(OP_DMA_END, dma_exec_addr + offset + 3);
257 
258 	return 0;
259 }
260 
dma_pl330_start_dma_ch(const struct device * dev,uint32_t reg_base,int ch,int secure)261 static int dma_pl330_start_dma_ch(const struct device *dev,
262 				  uint32_t reg_base, int ch, int secure)
263 {
264 	struct dma_pl330_dev_data *const dev_data = dev->data;
265 	struct dma_pl330_ch_config *channel_cfg;
266 	uint32_t count = 0U;
267 	uint32_t data;
268 
269 	channel_cfg = &dev_data->channels[ch];
270 	do {
271 		data = sys_read32(reg_base + DMAC_PL330_DBGSTATUS);
272 		if (++count > DMA_TIMEOUT_US) {
273 			return -ETIMEDOUT;
274 		}
275 		k_busy_wait(1);
276 	} while ((data & DATA_MASK) != 0);
277 
278 	sys_write32(((ch << DMA_INTSR1_SHIFT) +
279 		    (DMA_INTSR0 << DMA_INTSR0_SHIFT) +
280 		    (secure << DMA_SECURE_SHIFT) + (ch << DMA_CH_SHIFT)),
281 		    reg_base + DMAC_PL330_DBGINST0);
282 
283 	sys_write32(channel_cfg->dma_exec_addr,
284 		    reg_base + DMAC_PL330_DBGINST1);
285 
286 	sys_write32(0x0, reg_base + DMAC_PL330_DBGCMD);
287 
288 	count = 0U;
289 	do {
290 		data = sys_read32(reg_base + DMAC_PL330_DBGCMD);
291 		if (++count > DMA_TIMEOUT_US) {
292 			return -ETIMEDOUT;
293 		}
294 		k_busy_wait(1);
295 	} while ((data & DATA_MASK) != 0);
296 
297 	return 0;
298 }
299 
dma_pl330_wait(uint32_t reg_base,int ch)300 static int dma_pl330_wait(uint32_t reg_base, int ch)
301 {
302 	int count = 0U;
303 	uint32_t cs0_reg = reg_base + DMAC_PL330_CS0;
304 
305 	do {
306 		if (++count > DMA_TIMEOUT_US) {
307 			return -ETIMEDOUT;
308 		}
309 		k_busy_wait(1);
310 	} while (((sys_read32(cs0_reg + ch * 8)) & CH_STATUS_MASK) != 0);
311 
312 	return 0;
313 }
314 
dma_pl330_xfer(const struct device * dev,uint64_t dst,uint64_t src,uint32_t size,uint32_t channel,uint32_t * xfer_size)315 static int dma_pl330_xfer(const struct device *dev, uint64_t dst,
316 			  uint64_t src, uint32_t size, uint32_t channel,
317 			  uint32_t *xfer_size)
318 {
319 	struct dma_pl330_dev_data *const dev_data = dev->data;
320 	const struct dma_pl330_config *const dev_cfg = dev->config;
321 	struct dma_pl330_ch_config *channel_cfg;
322 	struct dma_pl330_ch_internal *ch_handle;
323 	int ret;
324 	uint32_t max_size;
325 
326 	channel_cfg = &dev_data->channels[channel];
327 	ch_handle = &channel_cfg->internal;
328 
329 	dma_pl330_calc_burstsz_len(ch_handle, dst, src, size);
330 
331 	max_size = GET_MAX_DMA_SIZE((1 << ch_handle->src_burst_sz),
332 				    ch_handle->src_burst_len);
333 
334 	if (size > max_size) {
335 		size = max_size;
336 	}
337 
338 	dma_pl330_config_channel(channel_cfg, dst, src, size);
339 #ifdef CONFIG_DMA_64BIT
340 	/*
341 	 * Pl330 supports only 4GB boundary, but boundary region can be
342 	 * configured.
343 	 * Support added for 36bit address, lower 32bit address are configured
344 	 * in pl330 registers and higher 4bit address are configured in
345 	 * LS_ICFG_DMAC_AXI_ADD_CONTROL registers.
346 	 * Each channel has 1 control register to configure higher 4bit address.
347 	 */
348 
349 	dma_pl330_cfg_dmac_add_control(dev_cfg->control_reg_base,
350 				       dst, src, channel);
351 #endif
352 	ret = dma_pl330_setup_ch(dev, ch_handle, channel);
353 	if (ret) {
354 		LOG_ERR("Failed to setup channel for DMA PL330");
355 		goto err;
356 	}
357 
358 	ret = dma_pl330_start_dma_ch(dev, dev_cfg->reg_base, channel,
359 				     ch_handle->nonsec_mode);
360 	if (ret) {
361 		LOG_ERR("Failed to start DMA PL330");
362 		goto err;
363 	}
364 
365 	ret = dma_pl330_wait(dev_cfg->reg_base, channel);
366 	if (ret) {
367 		LOG_ERR("Failed waiting to finish DMA PL330");
368 		goto err;
369 	}
370 
371 	*xfer_size = size;
372 err:
373 	return ret;
374 }
375 
376 #if CONFIG_DMA_64BIT
dma_pl330_handle_boundary(const struct device * dev,uint64_t dst,uint64_t src,uint32_t channel,uint32_t size)377 static int dma_pl330_handle_boundary(const struct device *dev, uint64_t dst,
378 				     uint64_t src, uint32_t channel,
379 				     uint32_t size)
380 {
381 	uint32_t dst_low = (uint32_t)dst;
382 	uint32_t src_low = (uint32_t)src;
383 	uint32_t transfer_size;
384 	int ret;
385 
386 	/*
387 	 * Pl330 has only 32bit registers and supports 4GB memory.
388 	 * 4GB memory window can be configured using DMAC_AXI_ADD_CONTROL
389 	 * registers.
390 	 * Divide the DMA operation in 2 parts, 1st DMA from given address
391 	 * to boundary (0xffffffff) and 2nd DMA on remaining size.
392 	 */
393 
394 	if (size > (PL330_MAX_OFFSET - dst_low)) {
395 		transfer_size = PL330_MAX_OFFSET - dst_low;
396 		ret = dma_pl330_submit(dev, dst, src, channel,
397 				       transfer_size);
398 		if (ret < 0) {
399 			return ret;
400 		}
401 
402 		dst += transfer_size;
403 		src += transfer_size;
404 		size -= transfer_size;
405 		return dma_pl330_submit(dev, dst, src, channel, size);
406 	}
407 
408 	if (size > (PL330_MAX_OFFSET - src_low)) {
409 		transfer_size = PL330_MAX_OFFSET - src_low;
410 		ret = dma_pl330_submit(dev, dst, src, channel, transfer_size);
411 		if (ret < 0) {
412 			return ret;
413 		}
414 
415 		src += transfer_size;
416 		dst += transfer_size;
417 		size -= transfer_size;
418 		return dma_pl330_submit(dev, dst, src, channel, size);
419 	}
420 
421 	return 0;
422 }
423 #endif
424 
dma_pl330_submit(const struct device * dev,uint64_t dst,uint64_t src,uint32_t channel,uint32_t size)425 static int dma_pl330_submit(const struct device *dev, uint64_t dst,
426 			    uint64_t src,
427 			    uint32_t channel, uint32_t size)
428 {
429 	int ret;
430 	uint32_t xfer_size;
431 
432 #if CONFIG_DMA_64BIT
433 	/*
434 	 * Pl330 has only 32bit registers and supports 4GB memory.
435 	 * 4GB memory window can be configured using DMAC_AXI_ADD_CONTROL
436 	 * registers. 32bit boundary (0xffffffff) should be check.
437 	 * DMA on boundary condition is taken care in below function.
438 	 */
439 
440 	if ((size > (PL330_MAX_OFFSET - (uint32_t)dst)) ||
441 	    (size > (PL330_MAX_OFFSET - (uint32_t)src))) {
442 		return dma_pl330_handle_boundary(dev, dst, src,
443 						 channel, size);
444 	}
445 #endif
446 	while (size) {
447 		xfer_size = 0;
448 		ret = dma_pl330_xfer(dev, dst, src, size,
449 				     channel, &xfer_size);
450 		if (ret) {
451 			return ret;
452 		}
453 		if (xfer_size > size) {
454 			return -EFAULT;
455 		}
456 		size -= xfer_size;
457 		dst += xfer_size;
458 		src += xfer_size;
459 	}
460 
461 	return 0;
462 }
463 
dma_pl330_configure(const struct device * dev,uint32_t channel,struct dma_config * cfg)464 static int dma_pl330_configure(const struct device *dev, uint32_t channel,
465 			       struct dma_config *cfg)
466 {
467 	struct dma_pl330_dev_data *const dev_data = dev->data;
468 	struct dma_pl330_ch_config *channel_cfg;
469 	struct dma_pl330_ch_internal *ch_handle;
470 
471 	if (channel >= MAX_DMA_CHANNELS) {
472 		return -EINVAL;
473 	}
474 
475 	channel_cfg = &dev_data->channels[channel];
476 	k_mutex_lock(&channel_cfg->ch_mutex, K_FOREVER);
477 	if (channel_cfg->channel_active) {
478 		k_mutex_unlock(&channel_cfg->ch_mutex);
479 		return -EBUSY;
480 	}
481 	channel_cfg->channel_active = 1;
482 	k_mutex_unlock(&channel_cfg->ch_mutex);
483 
484 	if (cfg->channel_direction != MEMORY_TO_MEMORY) {
485 		return -ENOTSUP;
486 	}
487 
488 	ch_handle = &channel_cfg->internal;
489 	memset(ch_handle, 0, sizeof(*ch_handle));
490 
491 	channel_cfg->direction = cfg->channel_direction;
492 	channel_cfg->dst_addr_adj = cfg->head_block->dest_addr_adj;
493 
494 	channel_cfg->src_addr = cfg->head_block->source_address;
495 	channel_cfg->dst_addr = cfg->head_block->dest_address;
496 	channel_cfg->trans_size = cfg->head_block->block_size;
497 
498 	channel_cfg->dma_callback = cfg->dma_callback;
499 	channel_cfg->user_data = cfg->user_data;
500 
501 	if (cfg->head_block->source_addr_adj == DMA_ADDR_ADJ_INCREMENT ||
502 	    cfg->head_block->source_addr_adj == DMA_ADDR_ADJ_NO_CHANGE) {
503 		channel_cfg->src_addr_adj = cfg->head_block->source_addr_adj;
504 	} else {
505 		return -ENOTSUP;
506 	}
507 
508 	if (cfg->head_block->dest_addr_adj == DMA_ADDR_ADJ_INCREMENT ||
509 	    cfg->head_block->dest_addr_adj == DMA_ADDR_ADJ_NO_CHANGE) {
510 		channel_cfg->dst_addr_adj = cfg->head_block->dest_addr_adj;
511 	} else {
512 		return -ENOTSUP;
513 	}
514 
515 	return 0;
516 }
517 
dma_pl330_transfer_start(const struct device * dev,uint32_t channel)518 static int dma_pl330_transfer_start(const struct device *dev,
519 				    uint32_t channel)
520 {
521 	struct dma_pl330_dev_data *const dev_data = dev->data;
522 	struct dma_pl330_ch_config *channel_cfg;
523 	int ret;
524 
525 	if (channel >= MAX_DMA_CHANNELS) {
526 		return -EINVAL;
527 	}
528 
529 	channel_cfg = &dev_data->channels[channel];
530 	ret = dma_pl330_submit(dev, channel_cfg->dst_addr,
531 			       channel_cfg->src_addr, channel,
532 			       channel_cfg->trans_size);
533 
534 	k_mutex_lock(&channel_cfg->ch_mutex, K_FOREVER);
535 	channel_cfg->channel_active = 0;
536 	k_mutex_unlock(&channel_cfg->ch_mutex);
537 
538 	return ret;
539 }
540 
dma_pl330_transfer_stop(const struct device * dev,uint32_t channel)541 static int dma_pl330_transfer_stop(const struct device *dev, uint32_t channel)
542 {
543 	if (channel >= MAX_DMA_CHANNELS) {
544 		return -EINVAL;
545 	}
546 
547 	/* Nothing as of now */
548 	return 0;
549 }
550 
dma_pl330_initialize(const struct device * dev)551 static int dma_pl330_initialize(const struct device *dev)
552 {
553 	const struct dma_pl330_config *const dev_cfg = dev->config;
554 	struct dma_pl330_dev_data *const dev_data = dev->data;
555 	struct dma_pl330_ch_config *channel_cfg;
556 
557 	for (int channel = 0; channel < MAX_DMA_CHANNELS; channel++) {
558 		channel_cfg = &dev_data->channels[channel];
559 		channel_cfg->dma_exec_addr = dev_cfg->mcode_base +
560 					(channel * MICROCODE_SIZE_MAX);
561 		k_mutex_init(&channel_cfg->ch_mutex);
562 	}
563 
564 	LOG_INF("Device %s initialized", dev->name);
565 	return 0;
566 }
567 
568 static const struct dma_driver_api pl330_driver_api = {
569 	.config = dma_pl330_configure,
570 	.start = dma_pl330_transfer_start,
571 	.stop = dma_pl330_transfer_stop,
572 };
573 
574 static const struct dma_pl330_config pl330_config = {
575 	.reg_base = DT_INST_REG_ADDR(0),
576 #ifdef CONFIG_DMA_64BIT
577 	.control_reg_base = DT_INST_REG_ADDR_BY_NAME(0, control_regs),
578 #endif
579 	.mcode_base = DT_INST_PROP_BY_IDX(0, microcode, 0),
580 };
581 
582 static struct dma_pl330_dev_data pl330_data;
583 
584 DEVICE_DT_INST_DEFINE(0, &dma_pl330_initialize, NULL,
585 		    &pl330_data, &pl330_config,
586 		    POST_KERNEL, CONFIG_DMA_INIT_PRIORITY,
587 		    &pl330_driver_api);
588