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 /* 5631650d64SMarek Vasut * Enable a DMA channel. 5731650d64SMarek Vasut * 5831650d64SMarek Vasut * If the given channel has any DMA descriptors on its active list, this 5931650d64SMarek Vasut * function causes the DMA hardware to begin processing them. 6031650d64SMarek Vasut * 6131650d64SMarek Vasut * This function marks the DMA channel as "busy," whether or not there are any 6231650d64SMarek Vasut * descriptors to process. 6331650d64SMarek Vasut */ 6431650d64SMarek Vasut int mxs_dma_enable(int channel) 6531650d64SMarek Vasut { 6631650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 6731650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 6831650d64SMarek Vasut unsigned int sem; 6931650d64SMarek Vasut struct mxs_dma_chan *pchan; 7031650d64SMarek Vasut struct mxs_dma_desc *pdesc; 7131650d64SMarek Vasut int ret; 7231650d64SMarek Vasut 7331650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 7431650d64SMarek Vasut if (ret) 7531650d64SMarek Vasut return ret; 7631650d64SMarek Vasut 7731650d64SMarek Vasut pchan = mxs_dma_channels + channel; 7831650d64SMarek Vasut 7931650d64SMarek Vasut if (pchan->pending_num == 0) { 8031650d64SMarek Vasut pchan->flags |= MXS_DMA_FLAGS_BUSY; 8131650d64SMarek Vasut return 0; 8231650d64SMarek Vasut } 8331650d64SMarek Vasut 8431650d64SMarek Vasut pdesc = list_first_entry(&pchan->active, struct mxs_dma_desc, node); 8531650d64SMarek Vasut if (pdesc == NULL) 8631650d64SMarek Vasut return -EFAULT; 8731650d64SMarek Vasut 8831650d64SMarek Vasut if (pchan->flags & MXS_DMA_FLAGS_BUSY) { 8931650d64SMarek Vasut if (!(pdesc->cmd.data & MXS_DMA_DESC_CHAIN)) 9031650d64SMarek Vasut return 0; 9131650d64SMarek Vasut 9231650d64SMarek Vasut sem = mxs_dma_read_semaphore(channel); 9331650d64SMarek Vasut if (sem == 0) 9431650d64SMarek Vasut return 0; 9531650d64SMarek Vasut 9631650d64SMarek Vasut if (sem == 1) { 9731650d64SMarek Vasut pdesc = list_entry(pdesc->node.next, 9831650d64SMarek Vasut struct mxs_dma_desc, node); 9931650d64SMarek Vasut writel(mxs_dma_cmd_address(pdesc), 10031650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); 10131650d64SMarek Vasut } 10231650d64SMarek Vasut writel(pchan->pending_num, 10331650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_sema); 10431650d64SMarek Vasut pchan->active_num += pchan->pending_num; 10531650d64SMarek Vasut pchan->pending_num = 0; 10631650d64SMarek Vasut } else { 10731650d64SMarek Vasut pchan->active_num += pchan->pending_num; 10831650d64SMarek Vasut pchan->pending_num = 0; 10931650d64SMarek Vasut writel(mxs_dma_cmd_address(pdesc), 11031650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); 11131650d64SMarek Vasut writel(pchan->active_num, 11231650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_sema); 11331650d64SMarek Vasut writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), 11431650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_clr); 11531650d64SMarek Vasut } 11631650d64SMarek Vasut 11731650d64SMarek Vasut pchan->flags |= MXS_DMA_FLAGS_BUSY; 11831650d64SMarek Vasut return 0; 11931650d64SMarek Vasut } 12031650d64SMarek Vasut 12131650d64SMarek Vasut /* 12231650d64SMarek Vasut * Disable a DMA channel. 12331650d64SMarek Vasut * 12431650d64SMarek Vasut * This function shuts down a DMA channel and marks it as "not busy." Any 12531650d64SMarek Vasut * descriptors on the active list are immediately moved to the head of the 12631650d64SMarek Vasut * "done" list, whether or not they have actually been processed by the 12731650d64SMarek Vasut * hardware. The "ready" flags of these descriptors are NOT cleared, so they 12831650d64SMarek Vasut * still appear to be active. 12931650d64SMarek Vasut * 13031650d64SMarek Vasut * This function immediately shuts down a DMA channel's hardware, aborting any 13131650d64SMarek Vasut * I/O that may be in progress, potentially leaving I/O hardware in an undefined 13231650d64SMarek Vasut * state. It is unwise to call this function if there is ANY chance the hardware 13331650d64SMarek Vasut * is still processing a command. 13431650d64SMarek Vasut */ 13531650d64SMarek Vasut int mxs_dma_disable(int channel) 13631650d64SMarek Vasut { 13731650d64SMarek Vasut struct mxs_dma_chan *pchan; 13831650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 13931650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 14031650d64SMarek Vasut int ret; 14131650d64SMarek Vasut 14231650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 14331650d64SMarek Vasut if (ret) 14431650d64SMarek Vasut return ret; 14531650d64SMarek Vasut 14631650d64SMarek Vasut pchan = mxs_dma_channels + channel; 14731650d64SMarek Vasut 14831650d64SMarek Vasut if (!(pchan->flags & MXS_DMA_FLAGS_BUSY)) 14931650d64SMarek Vasut return -EINVAL; 15031650d64SMarek Vasut 15131650d64SMarek Vasut writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), 15231650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_set); 15331650d64SMarek Vasut 15431650d64SMarek Vasut pchan->flags &= ~MXS_DMA_FLAGS_BUSY; 15531650d64SMarek Vasut pchan->active_num = 0; 15631650d64SMarek Vasut pchan->pending_num = 0; 15731650d64SMarek Vasut list_splice_init(&pchan->active, &pchan->done); 15831650d64SMarek Vasut 15931650d64SMarek Vasut return 0; 16031650d64SMarek Vasut } 16131650d64SMarek Vasut 16231650d64SMarek Vasut /* 16331650d64SMarek Vasut * Resets the DMA channel hardware. 16431650d64SMarek Vasut */ 16531650d64SMarek Vasut int mxs_dma_reset(int channel) 16631650d64SMarek Vasut { 16731650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 16831650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 16931650d64SMarek Vasut int ret; 17031650d64SMarek Vasut 17131650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 17231650d64SMarek Vasut if (ret) 17331650d64SMarek Vasut return ret; 17431650d64SMarek Vasut 17531650d64SMarek Vasut writel(1 << (channel + APBH_CHANNEL_CTRL_RESET_CHANNEL_OFFSET), 17631650d64SMarek Vasut &apbh_regs->hw_apbh_channel_ctrl_set); 17731650d64SMarek Vasut 17831650d64SMarek Vasut return 0; 17931650d64SMarek Vasut } 18031650d64SMarek Vasut 18131650d64SMarek Vasut /* 18231650d64SMarek Vasut * Freeze a DMA channel. 18331650d64SMarek Vasut * 18431650d64SMarek Vasut * This function causes the channel to continuously fail arbitration for bus 18531650d64SMarek Vasut * access, which halts all forward progress without losing any state. A call to 18631650d64SMarek Vasut * mxs_dma_unfreeze() will cause the channel to continue its current operation 18731650d64SMarek Vasut * with no ill effect. 18831650d64SMarek Vasut */ 18931650d64SMarek Vasut int mxs_dma_freeze(int channel) 19031650d64SMarek Vasut { 19131650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 19231650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 19331650d64SMarek Vasut int ret; 19431650d64SMarek Vasut 19531650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 19631650d64SMarek Vasut if (ret) 19731650d64SMarek Vasut return ret; 19831650d64SMarek Vasut 19931650d64SMarek Vasut writel(1 << (channel + APBH_CHANNEL_CTRL_FREEZE_CHANNEL_OFFSET), 20031650d64SMarek Vasut &apbh_regs->hw_apbh_channel_ctrl_set); 20131650d64SMarek Vasut 20231650d64SMarek Vasut return 0; 20331650d64SMarek Vasut } 20431650d64SMarek Vasut 20531650d64SMarek Vasut /* 20631650d64SMarek Vasut * Unfreeze a DMA channel. 20731650d64SMarek Vasut * 20831650d64SMarek Vasut * This function reverses the effect of mxs_dma_freeze(), enabling the DMA 20931650d64SMarek Vasut * channel to continue from where it was frozen. 21031650d64SMarek Vasut */ 21131650d64SMarek Vasut int mxs_dma_unfreeze(int channel) 21231650d64SMarek Vasut { 21331650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 21431650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 21531650d64SMarek Vasut int ret; 21631650d64SMarek Vasut 21731650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 21831650d64SMarek Vasut if (ret) 21931650d64SMarek Vasut return ret; 22031650d64SMarek Vasut 22131650d64SMarek Vasut writel(1 << (channel + APBH_CHANNEL_CTRL_FREEZE_CHANNEL_OFFSET), 22231650d64SMarek Vasut &apbh_regs->hw_apbh_channel_ctrl_clr); 22331650d64SMarek Vasut 22431650d64SMarek Vasut return 0; 22531650d64SMarek Vasut } 22631650d64SMarek Vasut 22731650d64SMarek Vasut /* 22831650d64SMarek Vasut * Read a DMA channel's hardware semaphore. 22931650d64SMarek Vasut * 23031650d64SMarek Vasut * As used by the MXS platform's DMA software, the DMA channel's hardware 23131650d64SMarek Vasut * semaphore reflects the number of DMA commands the hardware will process, but 23231650d64SMarek Vasut * has not yet finished. This is a volatile value read directly from hardware, 23331650d64SMarek Vasut * so it must be be viewed as immediately stale. 23431650d64SMarek Vasut * 23531650d64SMarek Vasut * If the channel is not marked busy, or has finished processing all its 23631650d64SMarek Vasut * commands, this value should be zero. 23731650d64SMarek Vasut * 23831650d64SMarek Vasut * See mxs_dma_append() for details on how DMA command blocks must be configured 23931650d64SMarek Vasut * to maintain the expected behavior of the semaphore's value. 24031650d64SMarek Vasut */ 24131650d64SMarek Vasut int mxs_dma_read_semaphore(int channel) 24231650d64SMarek Vasut { 24331650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 24431650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 24531650d64SMarek Vasut uint32_t tmp; 24631650d64SMarek Vasut int ret; 24731650d64SMarek Vasut 24831650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 24931650d64SMarek Vasut if (ret) 25031650d64SMarek Vasut return ret; 25131650d64SMarek Vasut 25231650d64SMarek Vasut tmp = readl(&apbh_regs->ch[channel].hw_apbh_ch_sema); 25331650d64SMarek Vasut 25431650d64SMarek Vasut tmp &= APBH_CHn_SEMA_PHORE_MASK; 25531650d64SMarek Vasut tmp >>= APBH_CHn_SEMA_PHORE_OFFSET; 25631650d64SMarek Vasut 25731650d64SMarek Vasut return tmp; 25831650d64SMarek Vasut } 25931650d64SMarek Vasut 26031650d64SMarek Vasut /* 26131650d64SMarek Vasut * Enable or disable DMA interrupt. 26231650d64SMarek Vasut * 26331650d64SMarek Vasut * This function enables the given DMA channel to interrupt the CPU. 26431650d64SMarek Vasut */ 26531650d64SMarek Vasut int mxs_dma_enable_irq(int channel, int enable) 26631650d64SMarek Vasut { 26731650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 26831650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 26931650d64SMarek Vasut int ret; 27031650d64SMarek Vasut 27131650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 27231650d64SMarek Vasut if (ret) 27331650d64SMarek Vasut return ret; 27431650d64SMarek Vasut 27531650d64SMarek Vasut if (enable) 27631650d64SMarek Vasut writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), 27731650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl1_set); 27831650d64SMarek Vasut else 27931650d64SMarek Vasut writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), 28031650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl1_clr); 28131650d64SMarek Vasut 28231650d64SMarek Vasut return 0; 28331650d64SMarek Vasut } 28431650d64SMarek Vasut 28531650d64SMarek Vasut /* 28631650d64SMarek Vasut * Check if a DMA interrupt is pending. 28731650d64SMarek Vasut */ 28831650d64SMarek Vasut int mxs_dma_irq_is_pending(int channel) 28931650d64SMarek Vasut { 29031650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 29131650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 29231650d64SMarek Vasut uint32_t tmp; 29331650d64SMarek Vasut int ret; 29431650d64SMarek Vasut 29531650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 29631650d64SMarek Vasut if (ret) 29731650d64SMarek Vasut return ret; 29831650d64SMarek Vasut 29931650d64SMarek Vasut tmp = readl(&apbh_regs->hw_apbh_ctrl1); 30031650d64SMarek Vasut tmp |= readl(&apbh_regs->hw_apbh_ctrl2); 30131650d64SMarek Vasut 30231650d64SMarek Vasut return (tmp >> channel) & 1; 30331650d64SMarek Vasut } 30431650d64SMarek Vasut 30531650d64SMarek Vasut /* 30631650d64SMarek Vasut * Clear DMA interrupt. 30731650d64SMarek Vasut * 30831650d64SMarek Vasut * The software that is using the DMA channel must register to receive its 30931650d64SMarek Vasut * interrupts and, when they arrive, must call this function to clear them. 31031650d64SMarek Vasut */ 31131650d64SMarek Vasut int mxs_dma_ack_irq(int channel) 31231650d64SMarek Vasut { 31331650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 31431650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 31531650d64SMarek Vasut int ret; 31631650d64SMarek Vasut 31731650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 31831650d64SMarek Vasut if (ret) 31931650d64SMarek Vasut return ret; 32031650d64SMarek Vasut 32131650d64SMarek Vasut writel(1 << channel, &apbh_regs->hw_apbh_ctrl1_clr); 32231650d64SMarek Vasut writel(1 << channel, &apbh_regs->hw_apbh_ctrl2_clr); 32331650d64SMarek Vasut 32431650d64SMarek Vasut return 0; 32531650d64SMarek Vasut } 32631650d64SMarek Vasut 32731650d64SMarek Vasut /* 32831650d64SMarek Vasut * Request to reserve a DMA channel 32931650d64SMarek Vasut */ 33031650d64SMarek Vasut int mxs_dma_request(int channel) 33131650d64SMarek Vasut { 33231650d64SMarek Vasut struct mxs_dma_chan *pchan; 33331650d64SMarek Vasut 33431650d64SMarek Vasut if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) 33531650d64SMarek Vasut return -EINVAL; 33631650d64SMarek Vasut 33731650d64SMarek Vasut pchan = mxs_dma_channels + channel; 33831650d64SMarek Vasut if ((pchan->flags & MXS_DMA_FLAGS_VALID) != MXS_DMA_FLAGS_VALID) 33931650d64SMarek Vasut return -ENODEV; 34031650d64SMarek Vasut 34131650d64SMarek Vasut if (pchan->flags & MXS_DMA_FLAGS_ALLOCATED) 34231650d64SMarek Vasut return -EBUSY; 34331650d64SMarek Vasut 34431650d64SMarek Vasut pchan->flags |= MXS_DMA_FLAGS_ALLOCATED; 34531650d64SMarek Vasut pchan->active_num = 0; 34631650d64SMarek Vasut pchan->pending_num = 0; 34731650d64SMarek Vasut 34831650d64SMarek Vasut INIT_LIST_HEAD(&pchan->active); 34931650d64SMarek Vasut INIT_LIST_HEAD(&pchan->done); 35031650d64SMarek Vasut 35131650d64SMarek Vasut return 0; 35231650d64SMarek Vasut } 35331650d64SMarek Vasut 35431650d64SMarek Vasut /* 35531650d64SMarek Vasut * Release a DMA channel. 35631650d64SMarek Vasut * 35731650d64SMarek Vasut * This function releases a DMA channel from its current owner. 35831650d64SMarek Vasut * 35931650d64SMarek Vasut * The channel will NOT be released if it's marked "busy" (see 36031650d64SMarek Vasut * mxs_dma_enable()). 36131650d64SMarek Vasut */ 36231650d64SMarek Vasut int mxs_dma_release(int channel) 36331650d64SMarek Vasut { 36431650d64SMarek Vasut struct mxs_dma_chan *pchan; 36531650d64SMarek Vasut int ret; 36631650d64SMarek Vasut 36731650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 36831650d64SMarek Vasut if (ret) 36931650d64SMarek Vasut return ret; 37031650d64SMarek Vasut 37131650d64SMarek Vasut pchan = mxs_dma_channels + channel; 37231650d64SMarek Vasut 37331650d64SMarek Vasut if (pchan->flags & MXS_DMA_FLAGS_BUSY) 37431650d64SMarek Vasut return -EBUSY; 37531650d64SMarek Vasut 37631650d64SMarek Vasut pchan->dev = 0; 37731650d64SMarek Vasut pchan->active_num = 0; 37831650d64SMarek Vasut pchan->pending_num = 0; 37931650d64SMarek Vasut pchan->flags &= ~MXS_DMA_FLAGS_ALLOCATED; 38031650d64SMarek Vasut 38131650d64SMarek Vasut return 0; 38231650d64SMarek Vasut } 38331650d64SMarek Vasut 38431650d64SMarek Vasut /* 38531650d64SMarek Vasut * Allocate DMA descriptor 38631650d64SMarek Vasut */ 38731650d64SMarek Vasut struct mxs_dma_desc *mxs_dma_desc_alloc(void) 38831650d64SMarek Vasut { 38931650d64SMarek Vasut struct mxs_dma_desc *pdesc; 39031650d64SMarek Vasut 39131650d64SMarek Vasut pdesc = memalign(MXS_DMA_ALIGNMENT, sizeof(struct mxs_dma_desc)); 39231650d64SMarek Vasut 39331650d64SMarek Vasut if (pdesc == NULL) 39431650d64SMarek Vasut return NULL; 39531650d64SMarek Vasut 39631650d64SMarek Vasut memset(pdesc, 0, sizeof(*pdesc)); 39731650d64SMarek Vasut pdesc->address = (dma_addr_t)pdesc; 39831650d64SMarek Vasut 39931650d64SMarek Vasut return pdesc; 40031650d64SMarek Vasut }; 40131650d64SMarek Vasut 40231650d64SMarek Vasut /* 40331650d64SMarek Vasut * Free DMA descriptor 40431650d64SMarek Vasut */ 40531650d64SMarek Vasut void mxs_dma_desc_free(struct mxs_dma_desc *pdesc) 40631650d64SMarek Vasut { 40731650d64SMarek Vasut if (pdesc == NULL) 40831650d64SMarek Vasut return; 40931650d64SMarek Vasut 41031650d64SMarek Vasut free(pdesc); 41131650d64SMarek Vasut } 41231650d64SMarek Vasut 41331650d64SMarek Vasut /* 41431650d64SMarek Vasut * Return the address of the command within a descriptor. 41531650d64SMarek Vasut */ 41631650d64SMarek Vasut unsigned int mxs_dma_cmd_address(struct mxs_dma_desc *desc) 41731650d64SMarek Vasut { 41831650d64SMarek Vasut return desc->address + offsetof(struct mxs_dma_desc, cmd); 41931650d64SMarek Vasut } 42031650d64SMarek Vasut 42131650d64SMarek Vasut /* 42231650d64SMarek Vasut * Check if descriptor is on a channel's active list. 42331650d64SMarek Vasut * 42431650d64SMarek Vasut * This function returns the state of a descriptor's "ready" flag. This flag is 42531650d64SMarek Vasut * usually set only if the descriptor appears on a channel's active list. The 42631650d64SMarek Vasut * descriptor may or may not have already been processed by the hardware. 42731650d64SMarek Vasut * 42831650d64SMarek Vasut * The "ready" flag is set when the descriptor is submitted to a channel by a 42931650d64SMarek Vasut * call to mxs_dma_append() or mxs_dma_append_list(). The "ready" flag is 43031650d64SMarek Vasut * cleared when a processed descriptor is moved off the active list by a call 43131650d64SMarek Vasut * to mxs_dma_finish(). The "ready" flag is NOT cleared if the descriptor is 43231650d64SMarek Vasut * aborted by a call to mxs_dma_disable(). 43331650d64SMarek Vasut */ 43431650d64SMarek Vasut int mxs_dma_desc_pending(struct mxs_dma_desc *pdesc) 43531650d64SMarek Vasut { 43631650d64SMarek Vasut return pdesc->flags & MXS_DMA_DESC_READY; 43731650d64SMarek Vasut } 43831650d64SMarek Vasut 43931650d64SMarek Vasut /* 44031650d64SMarek Vasut * Add a DMA descriptor to a channel. 44131650d64SMarek Vasut * 44231650d64SMarek Vasut * If the descriptor list for this channel is not empty, this function sets the 44331650d64SMarek Vasut * CHAIN bit and the NEXTCMD_ADDR fields in the last descriptor's DMA command so 44431650d64SMarek Vasut * it will chain to the new descriptor's command. 44531650d64SMarek Vasut * 44631650d64SMarek Vasut * Then, this function marks the new descriptor as "ready," adds it to the end 44731650d64SMarek Vasut * of the active descriptor list, and increments the count of pending 44831650d64SMarek Vasut * descriptors. 44931650d64SMarek Vasut * 45031650d64SMarek Vasut * The MXS platform DMA software imposes some rules on DMA commands to maintain 45131650d64SMarek Vasut * important invariants. These rules are NOT checked, but they must be carefully 45231650d64SMarek Vasut * applied by software that uses MXS DMA channels. 45331650d64SMarek Vasut * 45431650d64SMarek Vasut * Invariant: 45531650d64SMarek Vasut * The DMA channel's hardware semaphore must reflect the number of DMA 45631650d64SMarek Vasut * commands the hardware will process, but has not yet finished. 45731650d64SMarek Vasut * 45831650d64SMarek Vasut * Explanation: 45931650d64SMarek Vasut * A DMA channel begins processing commands when its hardware semaphore is 46031650d64SMarek Vasut * written with a value greater than zero, and it stops processing commands 46131650d64SMarek Vasut * when the semaphore returns to zero. 46231650d64SMarek Vasut * 46331650d64SMarek Vasut * When a channel finishes a DMA command, it will decrement its semaphore if 46431650d64SMarek Vasut * the DECREMENT_SEMAPHORE bit is set in that command's flags bits. 46531650d64SMarek Vasut * 46631650d64SMarek Vasut * In principle, it's not necessary for the DECREMENT_SEMAPHORE to be set, 46731650d64SMarek Vasut * unless it suits the purposes of the software. For example, one could 46831650d64SMarek Vasut * construct a series of five DMA commands, with the DECREMENT_SEMAPHORE 46931650d64SMarek Vasut * bit set only in the last one. Then, setting the DMA channel's hardware 47031650d64SMarek Vasut * semaphore to one would cause the entire series of five commands to be 47131650d64SMarek Vasut * processed. However, this example would violate the invariant given above. 47231650d64SMarek Vasut * 47331650d64SMarek Vasut * Rule: 47431650d64SMarek Vasut * ALL DMA commands MUST have the DECREMENT_SEMAPHORE bit set so that the DMA 47531650d64SMarek Vasut * channel's hardware semaphore will be decremented EVERY time a command is 47631650d64SMarek Vasut * processed. 47731650d64SMarek Vasut */ 47831650d64SMarek Vasut int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc) 47931650d64SMarek Vasut { 48031650d64SMarek Vasut struct mxs_dma_chan *pchan; 48131650d64SMarek Vasut struct mxs_dma_desc *last; 48231650d64SMarek Vasut int ret; 48331650d64SMarek Vasut 48431650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 48531650d64SMarek Vasut if (ret) 48631650d64SMarek Vasut return ret; 48731650d64SMarek Vasut 48831650d64SMarek Vasut pchan = mxs_dma_channels + channel; 48931650d64SMarek Vasut 49031650d64SMarek Vasut pdesc->cmd.next = mxs_dma_cmd_address(pdesc); 49131650d64SMarek Vasut pdesc->flags |= MXS_DMA_DESC_FIRST | MXS_DMA_DESC_LAST; 49231650d64SMarek Vasut 49331650d64SMarek Vasut if (!list_empty(&pchan->active)) { 49431650d64SMarek Vasut last = list_entry(pchan->active.prev, struct mxs_dma_desc, 49531650d64SMarek Vasut node); 49631650d64SMarek Vasut 49731650d64SMarek Vasut pdesc->flags &= ~MXS_DMA_DESC_FIRST; 49831650d64SMarek Vasut last->flags &= ~MXS_DMA_DESC_LAST; 49931650d64SMarek Vasut 50031650d64SMarek Vasut last->cmd.next = mxs_dma_cmd_address(pdesc); 50131650d64SMarek Vasut last->cmd.data |= MXS_DMA_DESC_CHAIN; 50231650d64SMarek Vasut } 50331650d64SMarek Vasut pdesc->flags |= MXS_DMA_DESC_READY; 50431650d64SMarek Vasut if (pdesc->flags & MXS_DMA_DESC_FIRST) 50531650d64SMarek Vasut pchan->pending_num++; 50631650d64SMarek Vasut list_add_tail(&pdesc->node, &pchan->active); 50731650d64SMarek Vasut 50831650d64SMarek Vasut return ret; 50931650d64SMarek Vasut } 51031650d64SMarek Vasut 51131650d64SMarek Vasut /* 51231650d64SMarek Vasut * Retrieve processed DMA descriptors. 51331650d64SMarek Vasut * 51431650d64SMarek Vasut * This function moves all the descriptors from the DMA channel's "done" list to 51531650d64SMarek Vasut * the head of the given list. 51631650d64SMarek Vasut */ 51731650d64SMarek Vasut int mxs_dma_get_finished(int channel, struct list_head *head) 51831650d64SMarek Vasut { 51931650d64SMarek Vasut struct mxs_dma_chan *pchan; 52031650d64SMarek Vasut int ret; 52131650d64SMarek Vasut 52231650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 52331650d64SMarek Vasut if (ret) 52431650d64SMarek Vasut return ret; 52531650d64SMarek Vasut 52631650d64SMarek Vasut if (head == NULL) 52731650d64SMarek Vasut return 0; 52831650d64SMarek Vasut 52931650d64SMarek Vasut pchan = mxs_dma_channels + channel; 53031650d64SMarek Vasut 53131650d64SMarek Vasut list_splice(&pchan->done, head); 53231650d64SMarek Vasut 53331650d64SMarek Vasut return 0; 53431650d64SMarek Vasut } 53531650d64SMarek Vasut 53631650d64SMarek Vasut /* 53731650d64SMarek Vasut * Clean up processed DMA descriptors. 53831650d64SMarek Vasut * 53931650d64SMarek Vasut * This function removes processed DMA descriptors from the "active" list. Pass 54031650d64SMarek Vasut * in a non-NULL list head to get the descriptors moved to your list. Pass NULL 54131650d64SMarek Vasut * to get the descriptors moved to the channel's "done" list. Descriptors on 54231650d64SMarek Vasut * the "done" list can be retrieved with mxs_dma_get_finished(). 54331650d64SMarek Vasut * 54431650d64SMarek Vasut * This function marks the DMA channel as "not busy" if no unprocessed 54531650d64SMarek Vasut * descriptors remain on the "active" list. 54631650d64SMarek Vasut */ 54731650d64SMarek Vasut int mxs_dma_finish(int channel, struct list_head *head) 54831650d64SMarek Vasut { 54931650d64SMarek Vasut int sem; 55031650d64SMarek Vasut struct mxs_dma_chan *pchan; 55131650d64SMarek Vasut struct list_head *p, *q; 55231650d64SMarek Vasut struct mxs_dma_desc *pdesc; 55331650d64SMarek Vasut int ret; 55431650d64SMarek Vasut 55531650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 55631650d64SMarek Vasut if (ret) 55731650d64SMarek Vasut return ret; 55831650d64SMarek Vasut 55931650d64SMarek Vasut pchan = mxs_dma_channels + channel; 56031650d64SMarek Vasut 56131650d64SMarek Vasut sem = mxs_dma_read_semaphore(channel); 56231650d64SMarek Vasut if (sem < 0) 56331650d64SMarek Vasut return sem; 56431650d64SMarek Vasut 56531650d64SMarek Vasut if (sem == pchan->active_num) 56631650d64SMarek Vasut return 0; 56731650d64SMarek Vasut 56831650d64SMarek Vasut list_for_each_safe(p, q, &pchan->active) { 56931650d64SMarek Vasut if ((pchan->active_num) <= sem) 57031650d64SMarek Vasut break; 57131650d64SMarek Vasut 57231650d64SMarek Vasut pdesc = list_entry(p, struct mxs_dma_desc, node); 57331650d64SMarek Vasut pdesc->flags &= ~MXS_DMA_DESC_READY; 57431650d64SMarek Vasut 57531650d64SMarek Vasut if (head) 57631650d64SMarek Vasut list_move_tail(p, head); 57731650d64SMarek Vasut else 57831650d64SMarek Vasut list_move_tail(p, &pchan->done); 57931650d64SMarek Vasut 58031650d64SMarek Vasut if (pdesc->flags & MXS_DMA_DESC_LAST) 58131650d64SMarek Vasut pchan->active_num--; 58231650d64SMarek Vasut } 58331650d64SMarek Vasut 58431650d64SMarek Vasut if (sem == 0) 58531650d64SMarek Vasut pchan->flags &= ~MXS_DMA_FLAGS_BUSY; 58631650d64SMarek Vasut 58731650d64SMarek Vasut return 0; 58831650d64SMarek Vasut } 58931650d64SMarek Vasut 59031650d64SMarek Vasut /* 59131650d64SMarek Vasut * Wait for DMA channel to complete 59231650d64SMarek Vasut */ 59331650d64SMarek Vasut int mxs_dma_wait_complete(uint32_t timeout, unsigned int chan) 59431650d64SMarek Vasut { 59531650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 59631650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 59731650d64SMarek Vasut int ret; 59831650d64SMarek Vasut 59931650d64SMarek Vasut ret = mxs_dma_validate_chan(chan); 60031650d64SMarek Vasut if (ret) 60131650d64SMarek Vasut return ret; 60231650d64SMarek Vasut 60331650d64SMarek Vasut if (mx28_wait_mask_set(&apbh_regs->hw_apbh_ctrl1_reg, 60431650d64SMarek Vasut 1 << chan, timeout)) { 60531650d64SMarek Vasut ret = -ETIMEDOUT; 60631650d64SMarek Vasut mxs_dma_reset(chan); 60731650d64SMarek Vasut } 60831650d64SMarek Vasut 609*12dab4ceSWolfram Sang return ret; 61031650d64SMarek Vasut } 61131650d64SMarek Vasut 61231650d64SMarek Vasut /* 61331650d64SMarek Vasut * Execute the DMA channel 61431650d64SMarek Vasut */ 61531650d64SMarek Vasut int mxs_dma_go(int chan) 61631650d64SMarek Vasut { 61731650d64SMarek Vasut uint32_t timeout = 10000; 61831650d64SMarek Vasut int ret; 61931650d64SMarek Vasut 62031650d64SMarek Vasut LIST_HEAD(tmp_desc_list); 62131650d64SMarek Vasut 62231650d64SMarek Vasut mxs_dma_enable_irq(chan, 1); 62331650d64SMarek Vasut mxs_dma_enable(chan); 62431650d64SMarek Vasut 62531650d64SMarek Vasut /* Wait for DMA to finish. */ 62631650d64SMarek Vasut ret = mxs_dma_wait_complete(timeout, chan); 62731650d64SMarek Vasut 62831650d64SMarek Vasut /* Clear out the descriptors we just ran. */ 62931650d64SMarek Vasut mxs_dma_finish(chan, &tmp_desc_list); 63031650d64SMarek Vasut 63131650d64SMarek Vasut /* Shut the DMA channel down. */ 63231650d64SMarek Vasut mxs_dma_ack_irq(chan); 63331650d64SMarek Vasut mxs_dma_reset(chan); 63431650d64SMarek Vasut mxs_dma_enable_irq(chan, 0); 63531650d64SMarek Vasut mxs_dma_disable(chan); 63631650d64SMarek Vasut 63731650d64SMarek Vasut return ret; 63831650d64SMarek Vasut } 63931650d64SMarek Vasut 64031650d64SMarek Vasut /* 64131650d64SMarek Vasut * Initialize the DMA hardware 64231650d64SMarek Vasut */ 64331650d64SMarek Vasut int mxs_dma_init(void) 64431650d64SMarek Vasut { 64531650d64SMarek Vasut struct mx28_apbh_regs *apbh_regs = 64631650d64SMarek Vasut (struct mx28_apbh_regs *)MXS_APBH_BASE; 64731650d64SMarek Vasut struct mxs_dma_chan *pchan; 64831650d64SMarek Vasut int ret, channel; 64931650d64SMarek Vasut 65031650d64SMarek Vasut mx28_reset_block(&apbh_regs->hw_apbh_ctrl0_reg); 65131650d64SMarek Vasut 65231650d64SMarek Vasut #ifdef CONFIG_APBH_DMA_BURST8 65331650d64SMarek Vasut writel(APBH_CTRL0_AHB_BURST8_EN, 65431650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_set); 65531650d64SMarek Vasut #else 65631650d64SMarek Vasut writel(APBH_CTRL0_AHB_BURST8_EN, 65731650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_clr); 65831650d64SMarek Vasut #endif 65931650d64SMarek Vasut 66031650d64SMarek Vasut #ifdef CONFIG_APBH_DMA_BURST 66131650d64SMarek Vasut writel(APBH_CTRL0_APB_BURST_EN, 66231650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_set); 66331650d64SMarek Vasut #else 66431650d64SMarek Vasut writel(APBH_CTRL0_APB_BURST_EN, 66531650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_clr); 66631650d64SMarek Vasut #endif 66731650d64SMarek Vasut 66831650d64SMarek Vasut for (channel = 0; channel < MXS_MAX_DMA_CHANNELS; channel++) { 66931650d64SMarek Vasut pchan = mxs_dma_channels + channel; 67031650d64SMarek Vasut pchan->flags = MXS_DMA_FLAGS_VALID; 67131650d64SMarek Vasut 67231650d64SMarek Vasut ret = mxs_dma_request(channel); 67331650d64SMarek Vasut 67431650d64SMarek Vasut if (ret) { 67531650d64SMarek Vasut printf("MXS DMA: Can't acquire DMA channel %i\n", 67631650d64SMarek Vasut channel); 67731650d64SMarek Vasut 67831650d64SMarek Vasut goto err; 67931650d64SMarek Vasut } 68031650d64SMarek Vasut 68131650d64SMarek Vasut mxs_dma_reset(channel); 68231650d64SMarek Vasut mxs_dma_ack_irq(channel); 68331650d64SMarek Vasut } 68431650d64SMarek Vasut 68531650d64SMarek Vasut return 0; 68631650d64SMarek Vasut 68731650d64SMarek Vasut err: 68831650d64SMarek Vasut while (--channel >= 0) 68931650d64SMarek Vasut mxs_dma_release(channel); 69031650d64SMarek Vasut return ret; 69131650d64SMarek Vasut } 692