131650d64SMarek Vasut /* 231650d64SMarek Vasut * Freescale i.MX28 APBH DMA driver 331650d64SMarek Vasut * 431650d64SMarek Vasut * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> 531650d64SMarek Vasut * on behalf of DENX Software Engineering GmbH 631650d64SMarek Vasut * 731650d64SMarek Vasut * Based on code from LTIB: 831650d64SMarek Vasut * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. 931650d64SMarek Vasut * 1031650d64SMarek Vasut * This program is free software; you can redistribute it and/or modify 1131650d64SMarek Vasut * it under the terms of the GNU General Public License as published by 1231650d64SMarek Vasut * the Free Software Foundation; either version 2 of the License, or 1331650d64SMarek Vasut * (at your option) any later version. 1431650d64SMarek Vasut * 1531650d64SMarek Vasut * This program is distributed in the hope that it will be useful, 1631650d64SMarek Vasut * but WITHOUT ANY WARRANTY; without even the implied warranty of 1731650d64SMarek Vasut * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1831650d64SMarek Vasut * GNU General Public License for more details. 1931650d64SMarek Vasut * 2031650d64SMarek Vasut * You should have received a copy of the GNU General Public License along 2131650d64SMarek Vasut * with this program; if not, write to the Free Software Foundation, Inc., 2231650d64SMarek Vasut * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 2331650d64SMarek Vasut */ 2431650d64SMarek Vasut 2531650d64SMarek Vasut #include <linux/list.h> 2631650d64SMarek Vasut 2731650d64SMarek Vasut #include <common.h> 2831650d64SMarek Vasut #include <malloc.h> 2931650d64SMarek Vasut #include <asm/errno.h> 3031650d64SMarek Vasut #include <asm/io.h> 3131650d64SMarek Vasut #include <asm/arch/clock.h> 3231650d64SMarek Vasut #include <asm/arch/imx-regs.h> 3331650d64SMarek Vasut #include <asm/arch/sys_proto.h> 3431650d64SMarek Vasut #include <asm/arch/dma.h> 3531650d64SMarek Vasut 3631650d64SMarek Vasut static struct mxs_dma_chan mxs_dma_channels[MXS_MAX_DMA_CHANNELS]; 3731650d64SMarek Vasut 3831650d64SMarek Vasut /* 3931650d64SMarek Vasut * Test is the DMA channel is valid channel 4031650d64SMarek Vasut */ 4131650d64SMarek Vasut int mxs_dma_validate_chan(int channel) 4231650d64SMarek Vasut { 4331650d64SMarek Vasut struct mxs_dma_chan *pchan; 4431650d64SMarek Vasut 4531650d64SMarek Vasut if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) 4631650d64SMarek Vasut return -EINVAL; 4731650d64SMarek Vasut 4831650d64SMarek Vasut pchan = mxs_dma_channels + channel; 4931650d64SMarek Vasut if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) 5031650d64SMarek Vasut return -EINVAL; 5131650d64SMarek Vasut 5231650d64SMarek Vasut return 0; 5331650d64SMarek Vasut } 5431650d64SMarek Vasut 5531650d64SMarek Vasut /* 56*aa72e43bSMarek Vasut * Return the address of the command within a descriptor. 57*aa72e43bSMarek Vasut */ 58*aa72e43bSMarek Vasut static unsigned int mxs_dma_cmd_address(struct mxs_dma_desc *desc) 59*aa72e43bSMarek Vasut { 60*aa72e43bSMarek Vasut return desc->address + offsetof(struct mxs_dma_desc, cmd); 61*aa72e43bSMarek Vasut } 62*aa72e43bSMarek Vasut 63*aa72e43bSMarek Vasut /* 64*aa72e43bSMarek Vasut * Read a DMA channel's hardware semaphore. 65*aa72e43bSMarek Vasut * 66*aa72e43bSMarek Vasut * As used by the MXS platform's DMA software, the DMA channel's hardware 67*aa72e43bSMarek Vasut * semaphore reflects the number of DMA commands the hardware will process, but 68*aa72e43bSMarek Vasut * has not yet finished. This is a volatile value read directly from hardware, 69*aa72e43bSMarek Vasut * so it must be be viewed as immediately stale. 70*aa72e43bSMarek Vasut * 71*aa72e43bSMarek Vasut * If the channel is not marked busy, or has finished processing all its 72*aa72e43bSMarek Vasut * commands, this value should be zero. 73*aa72e43bSMarek Vasut * 74*aa72e43bSMarek Vasut * See mxs_dma_append() for details on how DMA command blocks must be configured 75*aa72e43bSMarek Vasut * to maintain the expected behavior of the semaphore's value. 76*aa72e43bSMarek Vasut */ 77*aa72e43bSMarek Vasut static int mxs_dma_read_semaphore(int channel) 78*aa72e43bSMarek Vasut { 79*aa72e43bSMarek Vasut struct mx28_apbh_regs *apbh_regs = 80*aa72e43bSMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 81*aa72e43bSMarek Vasut uint32_t tmp; 82*aa72e43bSMarek Vasut int ret; 83*aa72e43bSMarek Vasut 84*aa72e43bSMarek Vasut ret = mxs_dma_validate_chan(channel); 85*aa72e43bSMarek Vasut if (ret) 86*aa72e43bSMarek Vasut return ret; 87*aa72e43bSMarek Vasut 88*aa72e43bSMarek Vasut tmp = readl(&apbh_regs->ch[channel].hw_apbh_ch_sema); 89*aa72e43bSMarek Vasut 90*aa72e43bSMarek Vasut tmp &= APBH_CHn_SEMA_PHORE_MASK; 91*aa72e43bSMarek Vasut tmp >>= APBH_CHn_SEMA_PHORE_OFFSET; 92*aa72e43bSMarek Vasut 93*aa72e43bSMarek Vasut return tmp; 94*aa72e43bSMarek Vasut } 95*aa72e43bSMarek Vasut 96*aa72e43bSMarek Vasut /* 9731650d64SMarek Vasut * Enable a DMA channel. 9831650d64SMarek Vasut * 9931650d64SMarek Vasut * If the given channel has any DMA descriptors on its active list, this 10031650d64SMarek Vasut * function causes the DMA hardware to begin processing them. 10131650d64SMarek Vasut * 10231650d64SMarek Vasut * This function marks the DMA channel as "busy," whether or not there are any 10331650d64SMarek Vasut * descriptors to process. 10431650d64SMarek Vasut */ 105*aa72e43bSMarek Vasut static int mxs_dma_enable(int channel) 10631650d64SMarek Vasut { 10731650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 10831650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 10931650d64SMarek Vasut unsigned int sem; 11031650d64SMarek Vasut struct mxs_dma_chan *pchan; 11131650d64SMarek Vasut struct mxs_dma_desc *pdesc; 11231650d64SMarek Vasut int ret; 11331650d64SMarek Vasut 11431650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 11531650d64SMarek Vasut if (ret) 11631650d64SMarek Vasut return ret; 11731650d64SMarek Vasut 11831650d64SMarek Vasut pchan = mxs_dma_channels + channel; 11931650d64SMarek Vasut 12031650d64SMarek Vasut if (pchan->pending_num == 0) { 12131650d64SMarek Vasut pchan->flags |= MXS_DMA_FLAGS_BUSY; 12231650d64SMarek Vasut return 0; 12331650d64SMarek Vasut } 12431650d64SMarek Vasut 12531650d64SMarek Vasut pdesc = list_first_entry(&pchan->active, struct mxs_dma_desc, node); 12631650d64SMarek Vasut if (pdesc == NULL) 12731650d64SMarek Vasut return -EFAULT; 12831650d64SMarek Vasut 12931650d64SMarek Vasut if (pchan->flags & MXS_DMA_FLAGS_BUSY) { 13031650d64SMarek Vasut if (!(pdesc->cmd.data & MXS_DMA_DESC_CHAIN)) 13131650d64SMarek Vasut return 0; 13231650d64SMarek Vasut 13331650d64SMarek Vasut sem = mxs_dma_read_semaphore(channel); 13431650d64SMarek Vasut if (sem == 0) 13531650d64SMarek Vasut return 0; 13631650d64SMarek Vasut 13731650d64SMarek Vasut if (sem == 1) { 13831650d64SMarek Vasut pdesc = list_entry(pdesc->node.next, 13931650d64SMarek Vasut struct mxs_dma_desc, node); 14031650d64SMarek Vasut writel(mxs_dma_cmd_address(pdesc), 14131650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); 14231650d64SMarek Vasut } 14331650d64SMarek Vasut writel(pchan->pending_num, 14431650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_sema); 14531650d64SMarek Vasut pchan->active_num += pchan->pending_num; 14631650d64SMarek Vasut pchan->pending_num = 0; 14731650d64SMarek Vasut } else { 14831650d64SMarek Vasut pchan->active_num += pchan->pending_num; 14931650d64SMarek Vasut pchan->pending_num = 0; 15031650d64SMarek Vasut writel(mxs_dma_cmd_address(pdesc), 15131650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); 15231650d64SMarek Vasut writel(pchan->active_num, 15331650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_sema); 15431650d64SMarek Vasut writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), 15531650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_clr); 15631650d64SMarek Vasut } 15731650d64SMarek Vasut 15831650d64SMarek Vasut pchan->flags |= MXS_DMA_FLAGS_BUSY; 15931650d64SMarek Vasut return 0; 16031650d64SMarek Vasut } 16131650d64SMarek Vasut 16231650d64SMarek Vasut /* 16331650d64SMarek Vasut * Disable a DMA channel. 16431650d64SMarek Vasut * 16531650d64SMarek Vasut * This function shuts down a DMA channel and marks it as "not busy." Any 16631650d64SMarek Vasut * descriptors on the active list are immediately moved to the head of the 16731650d64SMarek Vasut * "done" list, whether or not they have actually been processed by the 16831650d64SMarek Vasut * hardware. The "ready" flags of these descriptors are NOT cleared, so they 16931650d64SMarek Vasut * still appear to be active. 17031650d64SMarek Vasut * 17131650d64SMarek Vasut * This function immediately shuts down a DMA channel's hardware, aborting any 17231650d64SMarek Vasut * I/O that may be in progress, potentially leaving I/O hardware in an undefined 17331650d64SMarek Vasut * state. It is unwise to call this function if there is ANY chance the hardware 17431650d64SMarek Vasut * is still processing a command. 17531650d64SMarek Vasut */ 176*aa72e43bSMarek Vasut static int mxs_dma_disable(int channel) 17731650d64SMarek Vasut { 17831650d64SMarek Vasut struct mxs_dma_chan *pchan; 17931650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 18031650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 18131650d64SMarek Vasut int ret; 18231650d64SMarek Vasut 18331650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 18431650d64SMarek Vasut if (ret) 18531650d64SMarek Vasut return ret; 18631650d64SMarek Vasut 18731650d64SMarek Vasut pchan = mxs_dma_channels + channel; 18831650d64SMarek Vasut 18931650d64SMarek Vasut if (!(pchan->flags & MXS_DMA_FLAGS_BUSY)) 19031650d64SMarek Vasut return -EINVAL; 19131650d64SMarek Vasut 19231650d64SMarek Vasut writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), 19331650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_set); 19431650d64SMarek Vasut 19531650d64SMarek Vasut pchan->flags &= ~MXS_DMA_FLAGS_BUSY; 19631650d64SMarek Vasut pchan->active_num = 0; 19731650d64SMarek Vasut pchan->pending_num = 0; 19831650d64SMarek Vasut list_splice_init(&pchan->active, &pchan->done); 19931650d64SMarek Vasut 20031650d64SMarek Vasut return 0; 20131650d64SMarek Vasut } 20231650d64SMarek Vasut 20331650d64SMarek Vasut /* 20431650d64SMarek Vasut * Resets the DMA channel hardware. 20531650d64SMarek Vasut */ 206*aa72e43bSMarek Vasut static int mxs_dma_reset(int channel) 20731650d64SMarek Vasut { 20831650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 20931650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 21031650d64SMarek Vasut int ret; 21131650d64SMarek Vasut 21231650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 21331650d64SMarek Vasut if (ret) 21431650d64SMarek Vasut return ret; 21531650d64SMarek Vasut 21631650d64SMarek Vasut writel(1 << (channel + APBH_CHANNEL_CTRL_RESET_CHANNEL_OFFSET), 21731650d64SMarek Vasut &apbh_regs->hw_apbh_channel_ctrl_set); 21831650d64SMarek Vasut 21931650d64SMarek Vasut return 0; 22031650d64SMarek Vasut } 22131650d64SMarek Vasut 22231650d64SMarek Vasut /* 22331650d64SMarek Vasut * Enable or disable DMA interrupt. 22431650d64SMarek Vasut * 22531650d64SMarek Vasut * This function enables the given DMA channel to interrupt the CPU. 22631650d64SMarek Vasut */ 227*aa72e43bSMarek Vasut static int mxs_dma_enable_irq(int channel, int enable) 22831650d64SMarek Vasut { 22931650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 23031650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 23131650d64SMarek Vasut int ret; 23231650d64SMarek Vasut 23331650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 23431650d64SMarek Vasut if (ret) 23531650d64SMarek Vasut return ret; 23631650d64SMarek Vasut 23731650d64SMarek Vasut if (enable) 23831650d64SMarek Vasut writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), 23931650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl1_set); 24031650d64SMarek Vasut else 24131650d64SMarek Vasut writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), 24231650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl1_clr); 24331650d64SMarek Vasut 24431650d64SMarek Vasut return 0; 24531650d64SMarek Vasut } 24631650d64SMarek Vasut 24731650d64SMarek Vasut /* 24831650d64SMarek Vasut * Clear DMA interrupt. 24931650d64SMarek Vasut * 25031650d64SMarek Vasut * The software that is using the DMA channel must register to receive its 25131650d64SMarek Vasut * interrupts and, when they arrive, must call this function to clear them. 25231650d64SMarek Vasut */ 253*aa72e43bSMarek Vasut static int mxs_dma_ack_irq(int channel) 25431650d64SMarek Vasut { 25531650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 25631650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 25731650d64SMarek Vasut int ret; 25831650d64SMarek Vasut 25931650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 26031650d64SMarek Vasut if (ret) 26131650d64SMarek Vasut return ret; 26231650d64SMarek Vasut 26331650d64SMarek Vasut writel(1 << channel, &apbh_regs->hw_apbh_ctrl1_clr); 26431650d64SMarek Vasut writel(1 << channel, &apbh_regs->hw_apbh_ctrl2_clr); 26531650d64SMarek Vasut 26631650d64SMarek Vasut return 0; 26731650d64SMarek Vasut } 26831650d64SMarek Vasut 26931650d64SMarek Vasut /* 27031650d64SMarek Vasut * Request to reserve a DMA channel 27131650d64SMarek Vasut */ 272*aa72e43bSMarek Vasut static int mxs_dma_request(int channel) 27331650d64SMarek Vasut { 27431650d64SMarek Vasut struct mxs_dma_chan *pchan; 27531650d64SMarek Vasut 27631650d64SMarek Vasut if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) 27731650d64SMarek Vasut return -EINVAL; 27831650d64SMarek Vasut 27931650d64SMarek Vasut pchan = mxs_dma_channels + channel; 28031650d64SMarek Vasut if ((pchan->flags & MXS_DMA_FLAGS_VALID) != MXS_DMA_FLAGS_VALID) 28131650d64SMarek Vasut return -ENODEV; 28231650d64SMarek Vasut 28331650d64SMarek Vasut if (pchan->flags & MXS_DMA_FLAGS_ALLOCATED) 28431650d64SMarek Vasut return -EBUSY; 28531650d64SMarek Vasut 28631650d64SMarek Vasut pchan->flags |= MXS_DMA_FLAGS_ALLOCATED; 28731650d64SMarek Vasut pchan->active_num = 0; 28831650d64SMarek Vasut pchan->pending_num = 0; 28931650d64SMarek Vasut 29031650d64SMarek Vasut INIT_LIST_HEAD(&pchan->active); 29131650d64SMarek Vasut INIT_LIST_HEAD(&pchan->done); 29231650d64SMarek Vasut 29331650d64SMarek Vasut return 0; 29431650d64SMarek Vasut } 29531650d64SMarek Vasut 29631650d64SMarek Vasut /* 29731650d64SMarek Vasut * Release a DMA channel. 29831650d64SMarek Vasut * 29931650d64SMarek Vasut * This function releases a DMA channel from its current owner. 30031650d64SMarek Vasut * 30131650d64SMarek Vasut * The channel will NOT be released if it's marked "busy" (see 30231650d64SMarek Vasut * mxs_dma_enable()). 30331650d64SMarek Vasut */ 304*aa72e43bSMarek Vasut static int mxs_dma_release(int channel) 30531650d64SMarek Vasut { 30631650d64SMarek Vasut struct mxs_dma_chan *pchan; 30731650d64SMarek Vasut int ret; 30831650d64SMarek Vasut 30931650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 31031650d64SMarek Vasut if (ret) 31131650d64SMarek Vasut return ret; 31231650d64SMarek Vasut 31331650d64SMarek Vasut pchan = mxs_dma_channels + channel; 31431650d64SMarek Vasut 31531650d64SMarek Vasut if (pchan->flags & MXS_DMA_FLAGS_BUSY) 31631650d64SMarek Vasut return -EBUSY; 31731650d64SMarek Vasut 31831650d64SMarek Vasut pchan->dev = 0; 31931650d64SMarek Vasut pchan->active_num = 0; 32031650d64SMarek Vasut pchan->pending_num = 0; 32131650d64SMarek Vasut pchan->flags &= ~MXS_DMA_FLAGS_ALLOCATED; 32231650d64SMarek Vasut 32331650d64SMarek Vasut return 0; 32431650d64SMarek Vasut } 32531650d64SMarek Vasut 32631650d64SMarek Vasut /* 32731650d64SMarek Vasut * Allocate DMA descriptor 32831650d64SMarek Vasut */ 32931650d64SMarek Vasut struct mxs_dma_desc *mxs_dma_desc_alloc(void) 33031650d64SMarek Vasut { 33131650d64SMarek Vasut struct mxs_dma_desc *pdesc; 33231650d64SMarek Vasut 33331650d64SMarek Vasut pdesc = memalign(MXS_DMA_ALIGNMENT, sizeof(struct mxs_dma_desc)); 33431650d64SMarek Vasut 33531650d64SMarek Vasut if (pdesc == NULL) 33631650d64SMarek Vasut return NULL; 33731650d64SMarek Vasut 33831650d64SMarek Vasut memset(pdesc, 0, sizeof(*pdesc)); 33931650d64SMarek Vasut pdesc->address = (dma_addr_t)pdesc; 34031650d64SMarek Vasut 34131650d64SMarek Vasut return pdesc; 34231650d64SMarek Vasut }; 34331650d64SMarek Vasut 34431650d64SMarek Vasut /* 34531650d64SMarek Vasut * Free DMA descriptor 34631650d64SMarek Vasut */ 34731650d64SMarek Vasut void mxs_dma_desc_free(struct mxs_dma_desc *pdesc) 34831650d64SMarek Vasut { 34931650d64SMarek Vasut if (pdesc == NULL) 35031650d64SMarek Vasut return; 35131650d64SMarek Vasut 35231650d64SMarek Vasut free(pdesc); 35331650d64SMarek Vasut } 35431650d64SMarek Vasut 35531650d64SMarek Vasut /* 35631650d64SMarek Vasut * Add a DMA descriptor to a channel. 35731650d64SMarek Vasut * 35831650d64SMarek Vasut * If the descriptor list for this channel is not empty, this function sets the 35931650d64SMarek Vasut * CHAIN bit and the NEXTCMD_ADDR fields in the last descriptor's DMA command so 36031650d64SMarek Vasut * it will chain to the new descriptor's command. 36131650d64SMarek Vasut * 36231650d64SMarek Vasut * Then, this function marks the new descriptor as "ready," adds it to the end 36331650d64SMarek Vasut * of the active descriptor list, and increments the count of pending 36431650d64SMarek Vasut * descriptors. 36531650d64SMarek Vasut * 36631650d64SMarek Vasut * The MXS platform DMA software imposes some rules on DMA commands to maintain 36731650d64SMarek Vasut * important invariants. These rules are NOT checked, but they must be carefully 36831650d64SMarek Vasut * applied by software that uses MXS DMA channels. 36931650d64SMarek Vasut * 37031650d64SMarek Vasut * Invariant: 37131650d64SMarek Vasut * The DMA channel's hardware semaphore must reflect the number of DMA 37231650d64SMarek Vasut * commands the hardware will process, but has not yet finished. 37331650d64SMarek Vasut * 37431650d64SMarek Vasut * Explanation: 37531650d64SMarek Vasut * A DMA channel begins processing commands when its hardware semaphore is 37631650d64SMarek Vasut * written with a value greater than zero, and it stops processing commands 37731650d64SMarek Vasut * when the semaphore returns to zero. 37831650d64SMarek Vasut * 37931650d64SMarek Vasut * When a channel finishes a DMA command, it will decrement its semaphore if 38031650d64SMarek Vasut * the DECREMENT_SEMAPHORE bit is set in that command's flags bits. 38131650d64SMarek Vasut * 38231650d64SMarek Vasut * In principle, it's not necessary for the DECREMENT_SEMAPHORE to be set, 38331650d64SMarek Vasut * unless it suits the purposes of the software. For example, one could 38431650d64SMarek Vasut * construct a series of five DMA commands, with the DECREMENT_SEMAPHORE 38531650d64SMarek Vasut * bit set only in the last one. Then, setting the DMA channel's hardware 38631650d64SMarek Vasut * semaphore to one would cause the entire series of five commands to be 38731650d64SMarek Vasut * processed. However, this example would violate the invariant given above. 38831650d64SMarek Vasut * 38931650d64SMarek Vasut * Rule: 39031650d64SMarek Vasut * ALL DMA commands MUST have the DECREMENT_SEMAPHORE bit set so that the DMA 39131650d64SMarek Vasut * channel's hardware semaphore will be decremented EVERY time a command is 39231650d64SMarek Vasut * processed. 39331650d64SMarek Vasut */ 39431650d64SMarek Vasut int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc) 39531650d64SMarek Vasut { 39631650d64SMarek Vasut struct mxs_dma_chan *pchan; 39731650d64SMarek Vasut struct mxs_dma_desc *last; 39831650d64SMarek Vasut int ret; 39931650d64SMarek Vasut 40031650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 40131650d64SMarek Vasut if (ret) 40231650d64SMarek Vasut return ret; 40331650d64SMarek Vasut 40431650d64SMarek Vasut pchan = mxs_dma_channels + channel; 40531650d64SMarek Vasut 40631650d64SMarek Vasut pdesc->cmd.next = mxs_dma_cmd_address(pdesc); 40731650d64SMarek Vasut pdesc->flags |= MXS_DMA_DESC_FIRST | MXS_DMA_DESC_LAST; 40831650d64SMarek Vasut 40931650d64SMarek Vasut if (!list_empty(&pchan->active)) { 41031650d64SMarek Vasut last = list_entry(pchan->active.prev, struct mxs_dma_desc, 41131650d64SMarek Vasut node); 41231650d64SMarek Vasut 41331650d64SMarek Vasut pdesc->flags &= ~MXS_DMA_DESC_FIRST; 41431650d64SMarek Vasut last->flags &= ~MXS_DMA_DESC_LAST; 41531650d64SMarek Vasut 41631650d64SMarek Vasut last->cmd.next = mxs_dma_cmd_address(pdesc); 41731650d64SMarek Vasut last->cmd.data |= MXS_DMA_DESC_CHAIN; 41831650d64SMarek Vasut } 41931650d64SMarek Vasut pdesc->flags |= MXS_DMA_DESC_READY; 42031650d64SMarek Vasut if (pdesc->flags & MXS_DMA_DESC_FIRST) 42131650d64SMarek Vasut pchan->pending_num++; 42231650d64SMarek Vasut list_add_tail(&pdesc->node, &pchan->active); 42331650d64SMarek Vasut 42431650d64SMarek Vasut return ret; 42531650d64SMarek Vasut } 42631650d64SMarek Vasut 42731650d64SMarek Vasut /* 42831650d64SMarek Vasut * Clean up processed DMA descriptors. 42931650d64SMarek Vasut * 43031650d64SMarek Vasut * This function removes processed DMA descriptors from the "active" list. Pass 43131650d64SMarek Vasut * in a non-NULL list head to get the descriptors moved to your list. Pass NULL 43231650d64SMarek Vasut * to get the descriptors moved to the channel's "done" list. Descriptors on 43331650d64SMarek Vasut * the "done" list can be retrieved with mxs_dma_get_finished(). 43431650d64SMarek Vasut * 43531650d64SMarek Vasut * This function marks the DMA channel as "not busy" if no unprocessed 43631650d64SMarek Vasut * descriptors remain on the "active" list. 43731650d64SMarek Vasut */ 438*aa72e43bSMarek Vasut static int mxs_dma_finish(int channel, struct list_head *head) 43931650d64SMarek Vasut { 44031650d64SMarek Vasut int sem; 44131650d64SMarek Vasut struct mxs_dma_chan *pchan; 44231650d64SMarek Vasut struct list_head *p, *q; 44331650d64SMarek Vasut struct mxs_dma_desc *pdesc; 44431650d64SMarek Vasut int ret; 44531650d64SMarek Vasut 44631650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 44731650d64SMarek Vasut if (ret) 44831650d64SMarek Vasut return ret; 44931650d64SMarek Vasut 45031650d64SMarek Vasut pchan = mxs_dma_channels + channel; 45131650d64SMarek Vasut 45231650d64SMarek Vasut sem = mxs_dma_read_semaphore(channel); 45331650d64SMarek Vasut if (sem < 0) 45431650d64SMarek Vasut return sem; 45531650d64SMarek Vasut 45631650d64SMarek Vasut if (sem == pchan->active_num) 45731650d64SMarek Vasut return 0; 45831650d64SMarek Vasut 45931650d64SMarek Vasut list_for_each_safe(p, q, &pchan->active) { 46031650d64SMarek Vasut if ((pchan->active_num) <= sem) 46131650d64SMarek Vasut break; 46231650d64SMarek Vasut 46331650d64SMarek Vasut pdesc = list_entry(p, struct mxs_dma_desc, node); 46431650d64SMarek Vasut pdesc->flags &= ~MXS_DMA_DESC_READY; 46531650d64SMarek Vasut 46631650d64SMarek Vasut if (head) 46731650d64SMarek Vasut list_move_tail(p, head); 46831650d64SMarek Vasut else 46931650d64SMarek Vasut list_move_tail(p, &pchan->done); 47031650d64SMarek Vasut 47131650d64SMarek Vasut if (pdesc->flags & MXS_DMA_DESC_LAST) 47231650d64SMarek Vasut pchan->active_num--; 47331650d64SMarek Vasut } 47431650d64SMarek Vasut 47531650d64SMarek Vasut if (sem == 0) 47631650d64SMarek Vasut pchan->flags &= ~MXS_DMA_FLAGS_BUSY; 47731650d64SMarek Vasut 47831650d64SMarek Vasut return 0; 47931650d64SMarek Vasut } 48031650d64SMarek Vasut 48131650d64SMarek Vasut /* 48231650d64SMarek Vasut * Wait for DMA channel to complete 48331650d64SMarek Vasut */ 484*aa72e43bSMarek Vasut static int mxs_dma_wait_complete(uint32_t timeout, unsigned int chan) 48531650d64SMarek Vasut { 48631650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 48731650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 48831650d64SMarek Vasut int ret; 48931650d64SMarek Vasut 49031650d64SMarek Vasut ret = mxs_dma_validate_chan(chan); 49131650d64SMarek Vasut if (ret) 49231650d64SMarek Vasut return ret; 49331650d64SMarek Vasut 49431650d64SMarek Vasut if (mx28_wait_mask_set(&apbh_regs->hw_apbh_ctrl1_reg, 49531650d64SMarek Vasut 1 << chan, timeout)) { 49631650d64SMarek Vasut ret = -ETIMEDOUT; 49731650d64SMarek Vasut mxs_dma_reset(chan); 49831650d64SMarek Vasut } 49931650d64SMarek Vasut 50012dab4ceSWolfram Sang return ret; 50131650d64SMarek Vasut } 50231650d64SMarek Vasut 50331650d64SMarek Vasut /* 50431650d64SMarek Vasut * Execute the DMA channel 50531650d64SMarek Vasut */ 50631650d64SMarek Vasut int mxs_dma_go(int chan) 50731650d64SMarek Vasut { 50831650d64SMarek Vasut uint32_t timeout = 10000; 50931650d64SMarek Vasut int ret; 51031650d64SMarek Vasut 51131650d64SMarek Vasut LIST_HEAD(tmp_desc_list); 51231650d64SMarek Vasut 51331650d64SMarek Vasut mxs_dma_enable_irq(chan, 1); 51431650d64SMarek Vasut mxs_dma_enable(chan); 51531650d64SMarek Vasut 51631650d64SMarek Vasut /* Wait for DMA to finish. */ 51731650d64SMarek Vasut ret = mxs_dma_wait_complete(timeout, chan); 51831650d64SMarek Vasut 51931650d64SMarek Vasut /* Clear out the descriptors we just ran. */ 52031650d64SMarek Vasut mxs_dma_finish(chan, &tmp_desc_list); 52131650d64SMarek Vasut 52231650d64SMarek Vasut /* Shut the DMA channel down. */ 52331650d64SMarek Vasut mxs_dma_ack_irq(chan); 52431650d64SMarek Vasut mxs_dma_reset(chan); 52531650d64SMarek Vasut mxs_dma_enable_irq(chan, 0); 52631650d64SMarek Vasut mxs_dma_disable(chan); 52731650d64SMarek Vasut 52831650d64SMarek Vasut return ret; 52931650d64SMarek Vasut } 53031650d64SMarek Vasut 53131650d64SMarek Vasut /* 53231650d64SMarek Vasut * Initialize the DMA hardware 53331650d64SMarek Vasut */ 53431650d64SMarek Vasut int mxs_dma_init(void) 53531650d64SMarek Vasut { 53631650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 53731650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 53831650d64SMarek Vasut struct mxs_dma_chan *pchan; 53931650d64SMarek Vasut int ret, channel; 54031650d64SMarek Vasut 54131650d64SMarek Vasut mx28_reset_block(&apbh_regs->hw_apbh_ctrl0_reg); 54231650d64SMarek Vasut 54331650d64SMarek Vasut #ifdef CONFIG_APBH_DMA_BURST8 54431650d64SMarek Vasut writel(APBH_CTRL0_AHB_BURST8_EN, 54531650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_set); 54631650d64SMarek Vasut #else 54731650d64SMarek Vasut writel(APBH_CTRL0_AHB_BURST8_EN, 54831650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_clr); 54931650d64SMarek Vasut #endif 55031650d64SMarek Vasut 55131650d64SMarek Vasut #ifdef CONFIG_APBH_DMA_BURST 55231650d64SMarek Vasut writel(APBH_CTRL0_APB_BURST_EN, 55331650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_set); 55431650d64SMarek Vasut #else 55531650d64SMarek Vasut writel(APBH_CTRL0_APB_BURST_EN, 55631650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_clr); 55731650d64SMarek Vasut #endif 55831650d64SMarek Vasut 55931650d64SMarek Vasut for (channel = 0; channel < MXS_MAX_DMA_CHANNELS; channel++) { 56031650d64SMarek Vasut pchan = mxs_dma_channels + channel; 56131650d64SMarek Vasut pchan->flags = MXS_DMA_FLAGS_VALID; 56231650d64SMarek Vasut 56331650d64SMarek Vasut ret = mxs_dma_request(channel); 56431650d64SMarek Vasut 56531650d64SMarek Vasut if (ret) { 56631650d64SMarek Vasut printf("MXS DMA: Can't acquire DMA channel %i\n", 56731650d64SMarek Vasut channel); 56831650d64SMarek Vasut 56931650d64SMarek Vasut goto err; 57031650d64SMarek Vasut } 57131650d64SMarek Vasut 57231650d64SMarek Vasut mxs_dma_reset(channel); 57331650d64SMarek Vasut mxs_dma_ack_irq(channel); 57431650d64SMarek Vasut } 57531650d64SMarek Vasut 57631650d64SMarek Vasut return 0; 57731650d64SMarek Vasut 57831650d64SMarek Vasut err: 57931650d64SMarek Vasut while (--channel >= 0) 58031650d64SMarek Vasut mxs_dma_release(channel); 58131650d64SMarek Vasut return ret; 58231650d64SMarek Vasut } 583