Lines Matching +full:channel +full:-

1 // SPDX-License-Identifier: GPL-2.0+
19 #include <asm/arch/imx-regs.h>
21 #include <asm/mach-imx/dma.h>
22 #include <asm/mach-imx/regs-apbh.h>
27 * Test is the DMA channel is valid channel
29 int mxs_dma_validate_chan(int channel) in mxs_dma_validate_chan() argument
33 if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) in mxs_dma_validate_chan()
34 return -EINVAL; in mxs_dma_validate_chan()
36 pchan = mxs_dma_channels + channel; in mxs_dma_validate_chan()
37 if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) in mxs_dma_validate_chan()
38 return -EINVAL; in mxs_dma_validate_chan()
48 return desc->address + offsetof(struct mxs_dma_desc, cmd); in mxs_dma_cmd_address()
52 * Read a DMA channel's hardware semaphore.
54 * As used by the MXS platform's DMA software, the DMA channel's hardware
59 * If the channel is not marked busy, or has finished processing all its
65 static int mxs_dma_read_semaphore(int channel) in mxs_dma_read_semaphore() argument
72 ret = mxs_dma_validate_chan(channel); in mxs_dma_read_semaphore()
76 tmp = readl(&apbh_regs->ch[channel].hw_apbh_ch_sema); in mxs_dma_read_semaphore()
100 * Enable a DMA channel.
102 * If the given channel has any DMA descriptors on its active list, this
105 * This function marks the DMA channel as "busy," whether or not there are any
108 static int mxs_dma_enable(int channel) in mxs_dma_enable() argument
117 ret = mxs_dma_validate_chan(channel); in mxs_dma_enable()
121 pchan = mxs_dma_channels + channel; in mxs_dma_enable()
123 if (pchan->pending_num == 0) { in mxs_dma_enable()
124 pchan->flags |= MXS_DMA_FLAGS_BUSY; in mxs_dma_enable()
128 pdesc = list_first_entry(&pchan->active, struct mxs_dma_desc, node); in mxs_dma_enable()
130 return -EFAULT; in mxs_dma_enable()
132 if (pchan->flags & MXS_DMA_FLAGS_BUSY) { in mxs_dma_enable()
133 if (!(pdesc->cmd.data & MXS_DMA_DESC_CHAIN)) in mxs_dma_enable()
136 sem = mxs_dma_read_semaphore(channel); in mxs_dma_enable()
141 pdesc = list_entry(pdesc->node.next, in mxs_dma_enable()
144 &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); in mxs_dma_enable()
146 writel(pchan->pending_num, in mxs_dma_enable()
147 &apbh_regs->ch[channel].hw_apbh_ch_sema); in mxs_dma_enable()
148 pchan->active_num += pchan->pending_num; in mxs_dma_enable()
149 pchan->pending_num = 0; in mxs_dma_enable()
151 pchan->active_num += pchan->pending_num; in mxs_dma_enable()
152 pchan->pending_num = 0; in mxs_dma_enable()
154 &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); in mxs_dma_enable()
155 writel(pchan->active_num, in mxs_dma_enable()
156 &apbh_regs->ch[channel].hw_apbh_ch_sema); in mxs_dma_enable()
157 writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), in mxs_dma_enable()
158 &apbh_regs->hw_apbh_ctrl0_clr); in mxs_dma_enable()
161 pchan->flags |= MXS_DMA_FLAGS_BUSY; in mxs_dma_enable()
166 * Disable a DMA channel.
168 * This function shuts down a DMA channel and marks it as "not busy." Any
174 * This function immediately shuts down a DMA channel's hardware, aborting any
179 static int mxs_dma_disable(int channel) in mxs_dma_disable() argument
186 ret = mxs_dma_validate_chan(channel); in mxs_dma_disable()
190 pchan = mxs_dma_channels + channel; in mxs_dma_disable()
192 if (!(pchan->flags & MXS_DMA_FLAGS_BUSY)) in mxs_dma_disable()
193 return -EINVAL; in mxs_dma_disable()
195 writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), in mxs_dma_disable()
196 &apbh_regs->hw_apbh_ctrl0_set); in mxs_dma_disable()
198 pchan->flags &= ~MXS_DMA_FLAGS_BUSY; in mxs_dma_disable()
199 pchan->active_num = 0; in mxs_dma_disable()
200 pchan->pending_num = 0; in mxs_dma_disable()
201 list_splice_init(&pchan->active, &pchan->done); in mxs_dma_disable()
207 * Resets the DMA channel hardware.
209 static int mxs_dma_reset(int channel) in mxs_dma_reset() argument
215 uint32_t setreg = (uint32_t)(&apbh_regs->hw_apbh_ctrl0_set); in mxs_dma_reset()
218 uint32_t setreg = (uint32_t)(&apbh_regs->hw_apbh_channel_ctrl_set); in mxs_dma_reset()
222 ret = mxs_dma_validate_chan(channel); in mxs_dma_reset()
226 writel(1 << (channel + offset), setreg); in mxs_dma_reset()
234 * This function enables the given DMA channel to interrupt the CPU.
236 static int mxs_dma_enable_irq(int channel, int enable) in mxs_dma_enable_irq() argument
242 ret = mxs_dma_validate_chan(channel); in mxs_dma_enable_irq()
247 writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), in mxs_dma_enable_irq()
248 &apbh_regs->hw_apbh_ctrl1_set); in mxs_dma_enable_irq()
250 writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), in mxs_dma_enable_irq()
251 &apbh_regs->hw_apbh_ctrl1_clr); in mxs_dma_enable_irq()
259 * The software that is using the DMA channel must register to receive its
262 static int mxs_dma_ack_irq(int channel) in mxs_dma_ack_irq() argument
268 ret = mxs_dma_validate_chan(channel); in mxs_dma_ack_irq()
272 writel(1 << channel, &apbh_regs->hw_apbh_ctrl1_clr); in mxs_dma_ack_irq()
273 writel(1 << channel, &apbh_regs->hw_apbh_ctrl2_clr); in mxs_dma_ack_irq()
279 * Request to reserve a DMA channel
281 static int mxs_dma_request(int channel) in mxs_dma_request() argument
285 if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) in mxs_dma_request()
286 return -EINVAL; in mxs_dma_request()
288 pchan = mxs_dma_channels + channel; in mxs_dma_request()
289 if ((pchan->flags & MXS_DMA_FLAGS_VALID) != MXS_DMA_FLAGS_VALID) in mxs_dma_request()
290 return -ENODEV; in mxs_dma_request()
292 if (pchan->flags & MXS_DMA_FLAGS_ALLOCATED) in mxs_dma_request()
293 return -EBUSY; in mxs_dma_request()
295 pchan->flags |= MXS_DMA_FLAGS_ALLOCATED; in mxs_dma_request()
296 pchan->active_num = 0; in mxs_dma_request()
297 pchan->pending_num = 0; in mxs_dma_request()
299 INIT_LIST_HEAD(&pchan->active); in mxs_dma_request()
300 INIT_LIST_HEAD(&pchan->done); in mxs_dma_request()
306 * Release a DMA channel.
308 * This function releases a DMA channel from its current owner.
310 * The channel will NOT be released if it's marked "busy" (see
313 int mxs_dma_release(int channel) in mxs_dma_release() argument
318 ret = mxs_dma_validate_chan(channel); in mxs_dma_release()
322 pchan = mxs_dma_channels + channel; in mxs_dma_release()
324 if (pchan->flags & MXS_DMA_FLAGS_BUSY) in mxs_dma_release()
325 return -EBUSY; in mxs_dma_release()
327 pchan->dev = 0; in mxs_dma_release()
328 pchan->active_num = 0; in mxs_dma_release()
329 pchan->pending_num = 0; in mxs_dma_release()
330 pchan->flags &= ~MXS_DMA_FLAGS_ALLOCATED; in mxs_dma_release()
350 pdesc->address = (dma_addr_t)pdesc; in mxs_dma_desc_alloc()
367 * Add a DMA descriptor to a channel.
369 * If the descriptor list for this channel is not empty, this function sets the
382 * The DMA channel's hardware semaphore must reflect the number of DMA
386 * A DMA channel begins processing commands when its hardware semaphore is
390 * When a channel finishes a DMA command, it will decrement its semaphore if
396 * bit set only in the last one. Then, setting the DMA channel's hardware
402 * channel's hardware semaphore will be decremented EVERY time a command is
405 int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc) in mxs_dma_desc_append() argument
411 ret = mxs_dma_validate_chan(channel); in mxs_dma_desc_append()
415 pchan = mxs_dma_channels + channel; in mxs_dma_desc_append()
417 pdesc->cmd.next = mxs_dma_cmd_address(pdesc); in mxs_dma_desc_append()
418 pdesc->flags |= MXS_DMA_DESC_FIRST | MXS_DMA_DESC_LAST; in mxs_dma_desc_append()
420 if (!list_empty(&pchan->active)) { in mxs_dma_desc_append()
421 last = list_entry(pchan->active.prev, struct mxs_dma_desc, in mxs_dma_desc_append()
424 pdesc->flags &= ~MXS_DMA_DESC_FIRST; in mxs_dma_desc_append()
425 last->flags &= ~MXS_DMA_DESC_LAST; in mxs_dma_desc_append()
427 last->cmd.next = mxs_dma_cmd_address(pdesc); in mxs_dma_desc_append()
428 last->cmd.data |= MXS_DMA_DESC_CHAIN; in mxs_dma_desc_append()
432 pdesc->flags |= MXS_DMA_DESC_READY; in mxs_dma_desc_append()
433 if (pdesc->flags & MXS_DMA_DESC_FIRST) in mxs_dma_desc_append()
434 pchan->pending_num++; in mxs_dma_desc_append()
435 list_add_tail(&pdesc->node, &pchan->active); in mxs_dma_desc_append()
446 * in a non-NULL list head to get the descriptors moved to your list. Pass NULL
447 * to get the descriptors moved to the channel's "done" list. Descriptors on
450 * This function marks the DMA channel as "not busy" if no unprocessed
453 static int mxs_dma_finish(int channel, struct list_head *head) in mxs_dma_finish() argument
461 ret = mxs_dma_validate_chan(channel); in mxs_dma_finish()
465 pchan = mxs_dma_channels + channel; in mxs_dma_finish()
467 sem = mxs_dma_read_semaphore(channel); in mxs_dma_finish()
471 if (sem == pchan->active_num) in mxs_dma_finish()
474 list_for_each_safe(p, q, &pchan->active) { in mxs_dma_finish()
475 if ((pchan->active_num) <= sem) in mxs_dma_finish()
479 pdesc->flags &= ~MXS_DMA_DESC_READY; in mxs_dma_finish()
484 list_move_tail(p, &pchan->done); in mxs_dma_finish()
486 if (pdesc->flags & MXS_DMA_DESC_LAST) in mxs_dma_finish()
487 pchan->active_num--; in mxs_dma_finish()
491 pchan->flags &= ~MXS_DMA_FLAGS_BUSY; in mxs_dma_finish()
497 * Wait for DMA channel to complete
509 if (mxs_wait_mask_set(&apbh_regs->hw_apbh_ctrl1_reg, in mxs_dma_wait_complete()
511 ret = -ETIMEDOUT; in mxs_dma_wait_complete()
519 * Execute the DMA channel
537 /* Shut the DMA channel down. */ in mxs_dma_go()
549 * for the LCD driver in Smart-LCD mode. It allows
562 &apbh_regs->ch[chan].hw_apbh_ch_nxtcmdar); in mxs_dma_circ_start()
563 writel(1, &apbh_regs->ch[chan].hw_apbh_ch_sema); in mxs_dma_circ_start()
565 &apbh_regs->hw_apbh_ctrl0_clr); in mxs_dma_circ_start()
576 mxs_reset_block(&apbh_regs->hw_apbh_ctrl0_reg); in mxs_dma_init()
580 &apbh_regs->hw_apbh_ctrl0_set); in mxs_dma_init()
583 &apbh_regs->hw_apbh_ctrl0_clr); in mxs_dma_init()
588 &apbh_regs->hw_apbh_ctrl0_set); in mxs_dma_init()
591 &apbh_regs->hw_apbh_ctrl0_clr); in mxs_dma_init()
595 int mxs_dma_init_channel(int channel) in mxs_dma_init_channel() argument
600 pchan = mxs_dma_channels + channel; in mxs_dma_init_channel()
601 pchan->flags = MXS_DMA_FLAGS_VALID; in mxs_dma_init_channel()
603 ret = mxs_dma_request(channel); in mxs_dma_init_channel()
606 printf("MXS DMA: Can't acquire DMA channel %i\n", in mxs_dma_init_channel()
607 channel); in mxs_dma_init_channel()
611 mxs_dma_reset(channel); in mxs_dma_init_channel()
612 mxs_dma_ack_irq(channel); in mxs_dma_init_channel()