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 /* 56aa72e43bSMarek Vasut * Return the address of the command within a descriptor. 57aa72e43bSMarek Vasut */ 58aa72e43bSMarek Vasut static unsigned int mxs_dma_cmd_address(struct mxs_dma_desc *desc) 59aa72e43bSMarek Vasut { 60aa72e43bSMarek Vasut return desc->address + offsetof(struct mxs_dma_desc, cmd); 61aa72e43bSMarek Vasut } 62aa72e43bSMarek Vasut 63aa72e43bSMarek Vasut /* 64aa72e43bSMarek Vasut * Read a DMA channel's hardware semaphore. 65aa72e43bSMarek Vasut * 66aa72e43bSMarek Vasut * As used by the MXS platform's DMA software, the DMA channel's hardware 67aa72e43bSMarek Vasut * semaphore reflects the number of DMA commands the hardware will process, but 68aa72e43bSMarek Vasut * has not yet finished. This is a volatile value read directly from hardware, 69aa72e43bSMarek Vasut * so it must be be viewed as immediately stale. 70aa72e43bSMarek Vasut * 71aa72e43bSMarek Vasut * If the channel is not marked busy, or has finished processing all its 72aa72e43bSMarek Vasut * commands, this value should be zero. 73aa72e43bSMarek Vasut * 74aa72e43bSMarek Vasut * See mxs_dma_append() for details on how DMA command blocks must be configured 75aa72e43bSMarek Vasut * to maintain the expected behavior of the semaphore's value. 76aa72e43bSMarek Vasut */ 77aa72e43bSMarek Vasut static int mxs_dma_read_semaphore(int channel) 78aa72e43bSMarek Vasut { 79*9c471142SOtavio Salvador struct mxs_apbh_regs *apbh_regs = 80*9c471142SOtavio Salvador (struct mxs_apbh_regs *)MXS_APBH_BASE; 81aa72e43bSMarek Vasut uint32_t tmp; 82aa72e43bSMarek Vasut int ret; 83aa72e43bSMarek Vasut 84aa72e43bSMarek Vasut ret = mxs_dma_validate_chan(channel); 85aa72e43bSMarek Vasut if (ret) 86aa72e43bSMarek Vasut return ret; 87aa72e43bSMarek Vasut 88aa72e43bSMarek Vasut tmp = readl(&apbh_regs->ch[channel].hw_apbh_ch_sema); 89aa72e43bSMarek Vasut 90aa72e43bSMarek Vasut tmp &= APBH_CHn_SEMA_PHORE_MASK; 91aa72e43bSMarek Vasut tmp >>= APBH_CHn_SEMA_PHORE_OFFSET; 92aa72e43bSMarek Vasut 93aa72e43bSMarek Vasut return tmp; 94aa72e43bSMarek Vasut } 95aa72e43bSMarek Vasut 96c3dfe707SMarek Vasut #ifndef CONFIG_SYS_DCACHE_OFF 97c3dfe707SMarek Vasut void mxs_dma_flush_desc(struct mxs_dma_desc *desc) 98c3dfe707SMarek Vasut { 99c3dfe707SMarek Vasut uint32_t addr; 100c3dfe707SMarek Vasut uint32_t size; 101c3dfe707SMarek Vasut 102c3dfe707SMarek Vasut addr = (uint32_t)desc; 103c3dfe707SMarek Vasut size = roundup(sizeof(struct mxs_dma_desc), MXS_DMA_ALIGNMENT); 104c3dfe707SMarek Vasut 105c3dfe707SMarek Vasut flush_dcache_range(addr, addr + size); 106c3dfe707SMarek Vasut } 107c3dfe707SMarek Vasut #else 108c3dfe707SMarek Vasut inline void mxs_dma_flush_desc(struct mxs_dma_desc *desc) {} 109c3dfe707SMarek Vasut #endif 110c3dfe707SMarek Vasut 111aa72e43bSMarek Vasut /* 11231650d64SMarek Vasut * Enable a DMA channel. 11331650d64SMarek Vasut * 11431650d64SMarek Vasut * If the given channel has any DMA descriptors on its active list, this 11531650d64SMarek Vasut * function causes the DMA hardware to begin processing them. 11631650d64SMarek Vasut * 11731650d64SMarek Vasut * This function marks the DMA channel as "busy," whether or not there are any 11831650d64SMarek Vasut * descriptors to process. 11931650d64SMarek Vasut */ 120aa72e43bSMarek Vasut static int mxs_dma_enable(int channel) 12131650d64SMarek Vasut { 122*9c471142SOtavio Salvador struct mxs_apbh_regs *apbh_regs = 123*9c471142SOtavio Salvador (struct mxs_apbh_regs *)MXS_APBH_BASE; 12431650d64SMarek Vasut unsigned int sem; 12531650d64SMarek Vasut struct mxs_dma_chan *pchan; 12631650d64SMarek Vasut struct mxs_dma_desc *pdesc; 12731650d64SMarek Vasut int ret; 12831650d64SMarek Vasut 12931650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 13031650d64SMarek Vasut if (ret) 13131650d64SMarek Vasut return ret; 13231650d64SMarek Vasut 13331650d64SMarek Vasut pchan = mxs_dma_channels + channel; 13431650d64SMarek Vasut 13531650d64SMarek Vasut if (pchan->pending_num == 0) { 13631650d64SMarek Vasut pchan->flags |= MXS_DMA_FLAGS_BUSY; 13731650d64SMarek Vasut return 0; 13831650d64SMarek Vasut } 13931650d64SMarek Vasut 14031650d64SMarek Vasut pdesc = list_first_entry(&pchan->active, struct mxs_dma_desc, node); 14131650d64SMarek Vasut if (pdesc == NULL) 14231650d64SMarek Vasut return -EFAULT; 14331650d64SMarek Vasut 14431650d64SMarek Vasut if (pchan->flags & MXS_DMA_FLAGS_BUSY) { 14531650d64SMarek Vasut if (!(pdesc->cmd.data & MXS_DMA_DESC_CHAIN)) 14631650d64SMarek Vasut return 0; 14731650d64SMarek Vasut 14831650d64SMarek Vasut sem = mxs_dma_read_semaphore(channel); 14931650d64SMarek Vasut if (sem == 0) 15031650d64SMarek Vasut return 0; 15131650d64SMarek Vasut 15231650d64SMarek Vasut if (sem == 1) { 15331650d64SMarek Vasut pdesc = list_entry(pdesc->node.next, 15431650d64SMarek Vasut struct mxs_dma_desc, node); 15531650d64SMarek Vasut writel(mxs_dma_cmd_address(pdesc), 15631650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); 15731650d64SMarek Vasut } 15831650d64SMarek Vasut writel(pchan->pending_num, 15931650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_sema); 16031650d64SMarek Vasut pchan->active_num += pchan->pending_num; 16131650d64SMarek Vasut pchan->pending_num = 0; 16231650d64SMarek Vasut } else { 16331650d64SMarek Vasut pchan->active_num += pchan->pending_num; 16431650d64SMarek Vasut pchan->pending_num = 0; 16531650d64SMarek Vasut writel(mxs_dma_cmd_address(pdesc), 16631650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar); 16731650d64SMarek Vasut writel(pchan->active_num, 16831650d64SMarek Vasut &apbh_regs->ch[channel].hw_apbh_ch_sema); 16931650d64SMarek Vasut writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), 17031650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_clr); 17131650d64SMarek Vasut } 17231650d64SMarek Vasut 17331650d64SMarek Vasut pchan->flags |= MXS_DMA_FLAGS_BUSY; 17431650d64SMarek Vasut return 0; 17531650d64SMarek Vasut } 17631650d64SMarek Vasut 17731650d64SMarek Vasut /* 17831650d64SMarek Vasut * Disable a DMA channel. 17931650d64SMarek Vasut * 18031650d64SMarek Vasut * This function shuts down a DMA channel and marks it as "not busy." Any 18131650d64SMarek Vasut * descriptors on the active list are immediately moved to the head of the 18231650d64SMarek Vasut * "done" list, whether or not they have actually been processed by the 18331650d64SMarek Vasut * hardware. The "ready" flags of these descriptors are NOT cleared, so they 18431650d64SMarek Vasut * still appear to be active. 18531650d64SMarek Vasut * 18631650d64SMarek Vasut * This function immediately shuts down a DMA channel's hardware, aborting any 18731650d64SMarek Vasut * I/O that may be in progress, potentially leaving I/O hardware in an undefined 18831650d64SMarek Vasut * state. It is unwise to call this function if there is ANY chance the hardware 18931650d64SMarek Vasut * is still processing a command. 19031650d64SMarek Vasut */ 191aa72e43bSMarek Vasut static int mxs_dma_disable(int channel) 19231650d64SMarek Vasut { 19331650d64SMarek Vasut struct mxs_dma_chan *pchan; 194*9c471142SOtavio Salvador struct mxs_apbh_regs *apbh_regs = 195*9c471142SOtavio Salvador (struct mxs_apbh_regs *)MXS_APBH_BASE; 19631650d64SMarek Vasut int ret; 19731650d64SMarek Vasut 19831650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 19931650d64SMarek Vasut if (ret) 20031650d64SMarek Vasut return ret; 20131650d64SMarek Vasut 20231650d64SMarek Vasut pchan = mxs_dma_channels + channel; 20331650d64SMarek Vasut 20431650d64SMarek Vasut if (!(pchan->flags & MXS_DMA_FLAGS_BUSY)) 20531650d64SMarek Vasut return -EINVAL; 20631650d64SMarek Vasut 20731650d64SMarek Vasut writel(1 << (channel + APBH_CTRL0_CLKGATE_CHANNEL_OFFSET), 20831650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_set); 20931650d64SMarek Vasut 21031650d64SMarek Vasut pchan->flags &= ~MXS_DMA_FLAGS_BUSY; 21131650d64SMarek Vasut pchan->active_num = 0; 21231650d64SMarek Vasut pchan->pending_num = 0; 21331650d64SMarek Vasut list_splice_init(&pchan->active, &pchan->done); 21431650d64SMarek Vasut 21531650d64SMarek Vasut return 0; 21631650d64SMarek Vasut } 21731650d64SMarek Vasut 21831650d64SMarek Vasut /* 21931650d64SMarek Vasut * Resets the DMA channel hardware. 22031650d64SMarek Vasut */ 221aa72e43bSMarek Vasut static int mxs_dma_reset(int channel) 22231650d64SMarek Vasut { 223*9c471142SOtavio Salvador struct mxs_apbh_regs *apbh_regs = 224*9c471142SOtavio Salvador (struct mxs_apbh_regs *)MXS_APBH_BASE; 22531650d64SMarek Vasut int ret; 22631650d64SMarek Vasut 22731650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 22831650d64SMarek Vasut if (ret) 22931650d64SMarek Vasut return ret; 23031650d64SMarek Vasut 23131650d64SMarek Vasut writel(1 << (channel + APBH_CHANNEL_CTRL_RESET_CHANNEL_OFFSET), 23231650d64SMarek Vasut &apbh_regs->hw_apbh_channel_ctrl_set); 23331650d64SMarek Vasut 23431650d64SMarek Vasut return 0; 23531650d64SMarek Vasut } 23631650d64SMarek Vasut 23731650d64SMarek Vasut /* 23831650d64SMarek Vasut * Enable or disable DMA interrupt. 23931650d64SMarek Vasut * 24031650d64SMarek Vasut * This function enables the given DMA channel to interrupt the CPU. 24131650d64SMarek Vasut */ 242aa72e43bSMarek Vasut static int mxs_dma_enable_irq(int channel, int enable) 24331650d64SMarek Vasut { 244*9c471142SOtavio Salvador struct mxs_apbh_regs *apbh_regs = 245*9c471142SOtavio Salvador (struct mxs_apbh_regs *)MXS_APBH_BASE; 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 if (enable) 25331650d64SMarek Vasut writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), 25431650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl1_set); 25531650d64SMarek Vasut else 25631650d64SMarek Vasut writel(1 << (channel + APBH_CTRL1_CH_CMDCMPLT_IRQ_EN_OFFSET), 25731650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl1_clr); 25831650d64SMarek Vasut 25931650d64SMarek Vasut return 0; 26031650d64SMarek Vasut } 26131650d64SMarek Vasut 26231650d64SMarek Vasut /* 26331650d64SMarek Vasut * Clear DMA interrupt. 26431650d64SMarek Vasut * 26531650d64SMarek Vasut * The software that is using the DMA channel must register to receive its 26631650d64SMarek Vasut * interrupts and, when they arrive, must call this function to clear them. 26731650d64SMarek Vasut */ 268aa72e43bSMarek Vasut static int mxs_dma_ack_irq(int channel) 26931650d64SMarek Vasut { 270*9c471142SOtavio Salvador struct mxs_apbh_regs *apbh_regs = 271*9c471142SOtavio Salvador (struct mxs_apbh_regs *)MXS_APBH_BASE; 27231650d64SMarek Vasut int ret; 27331650d64SMarek Vasut 27431650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 27531650d64SMarek Vasut if (ret) 27631650d64SMarek Vasut return ret; 27731650d64SMarek Vasut 27831650d64SMarek Vasut writel(1 << channel, &apbh_regs->hw_apbh_ctrl1_clr); 27931650d64SMarek Vasut writel(1 << channel, &apbh_regs->hw_apbh_ctrl2_clr); 28031650d64SMarek Vasut 28131650d64SMarek Vasut return 0; 28231650d64SMarek Vasut } 28331650d64SMarek Vasut 28431650d64SMarek Vasut /* 28531650d64SMarek Vasut * Request to reserve a DMA channel 28631650d64SMarek Vasut */ 287aa72e43bSMarek Vasut static int mxs_dma_request(int channel) 28831650d64SMarek Vasut { 28931650d64SMarek Vasut struct mxs_dma_chan *pchan; 29031650d64SMarek Vasut 29131650d64SMarek Vasut if ((channel < 0) || (channel >= MXS_MAX_DMA_CHANNELS)) 29231650d64SMarek Vasut return -EINVAL; 29331650d64SMarek Vasut 29431650d64SMarek Vasut pchan = mxs_dma_channels + channel; 29531650d64SMarek Vasut if ((pchan->flags & MXS_DMA_FLAGS_VALID) != MXS_DMA_FLAGS_VALID) 29631650d64SMarek Vasut return -ENODEV; 29731650d64SMarek Vasut 29831650d64SMarek Vasut if (pchan->flags & MXS_DMA_FLAGS_ALLOCATED) 29931650d64SMarek Vasut return -EBUSY; 30031650d64SMarek Vasut 30131650d64SMarek Vasut pchan->flags |= MXS_DMA_FLAGS_ALLOCATED; 30231650d64SMarek Vasut pchan->active_num = 0; 30331650d64SMarek Vasut pchan->pending_num = 0; 30431650d64SMarek Vasut 30531650d64SMarek Vasut INIT_LIST_HEAD(&pchan->active); 30631650d64SMarek Vasut INIT_LIST_HEAD(&pchan->done); 30731650d64SMarek Vasut 30831650d64SMarek Vasut return 0; 30931650d64SMarek Vasut } 31031650d64SMarek Vasut 31131650d64SMarek Vasut /* 31231650d64SMarek Vasut * Release a DMA channel. 31331650d64SMarek Vasut * 31431650d64SMarek Vasut * This function releases a DMA channel from its current owner. 31531650d64SMarek Vasut * 31631650d64SMarek Vasut * The channel will NOT be released if it's marked "busy" (see 31731650d64SMarek Vasut * mxs_dma_enable()). 31831650d64SMarek Vasut */ 31996666a39SMarek Vasut int mxs_dma_release(int channel) 32031650d64SMarek Vasut { 32131650d64SMarek Vasut struct mxs_dma_chan *pchan; 32231650d64SMarek Vasut int ret; 32331650d64SMarek Vasut 32431650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 32531650d64SMarek Vasut if (ret) 32631650d64SMarek Vasut return ret; 32731650d64SMarek Vasut 32831650d64SMarek Vasut pchan = mxs_dma_channels + channel; 32931650d64SMarek Vasut 33031650d64SMarek Vasut if (pchan->flags & MXS_DMA_FLAGS_BUSY) 33131650d64SMarek Vasut return -EBUSY; 33231650d64SMarek Vasut 33331650d64SMarek Vasut pchan->dev = 0; 33431650d64SMarek Vasut pchan->active_num = 0; 33531650d64SMarek Vasut pchan->pending_num = 0; 33631650d64SMarek Vasut pchan->flags &= ~MXS_DMA_FLAGS_ALLOCATED; 33731650d64SMarek Vasut 33831650d64SMarek Vasut return 0; 33931650d64SMarek Vasut } 34031650d64SMarek Vasut 34131650d64SMarek Vasut /* 34231650d64SMarek Vasut * Allocate DMA descriptor 34331650d64SMarek Vasut */ 34431650d64SMarek Vasut struct mxs_dma_desc *mxs_dma_desc_alloc(void) 34531650d64SMarek Vasut { 34631650d64SMarek Vasut struct mxs_dma_desc *pdesc; 347c3dfe707SMarek Vasut uint32_t size; 34831650d64SMarek Vasut 349c3dfe707SMarek Vasut size = roundup(sizeof(struct mxs_dma_desc), MXS_DMA_ALIGNMENT); 350c3dfe707SMarek Vasut pdesc = memalign(MXS_DMA_ALIGNMENT, size); 35131650d64SMarek Vasut 35231650d64SMarek Vasut if (pdesc == NULL) 35331650d64SMarek Vasut return NULL; 35431650d64SMarek Vasut 35531650d64SMarek Vasut memset(pdesc, 0, sizeof(*pdesc)); 35631650d64SMarek Vasut pdesc->address = (dma_addr_t)pdesc; 35731650d64SMarek Vasut 35831650d64SMarek Vasut return pdesc; 35931650d64SMarek Vasut }; 36031650d64SMarek Vasut 36131650d64SMarek Vasut /* 36231650d64SMarek Vasut * Free DMA descriptor 36331650d64SMarek Vasut */ 36431650d64SMarek Vasut void mxs_dma_desc_free(struct mxs_dma_desc *pdesc) 36531650d64SMarek Vasut { 36631650d64SMarek Vasut if (pdesc == NULL) 36731650d64SMarek Vasut return; 36831650d64SMarek Vasut 36931650d64SMarek Vasut free(pdesc); 37031650d64SMarek Vasut } 37131650d64SMarek Vasut 37231650d64SMarek Vasut /* 37331650d64SMarek Vasut * Add a DMA descriptor to a channel. 37431650d64SMarek Vasut * 37531650d64SMarek Vasut * If the descriptor list for this channel is not empty, this function sets the 37631650d64SMarek Vasut * CHAIN bit and the NEXTCMD_ADDR fields in the last descriptor's DMA command so 37731650d64SMarek Vasut * it will chain to the new descriptor's command. 37831650d64SMarek Vasut * 37931650d64SMarek Vasut * Then, this function marks the new descriptor as "ready," adds it to the end 38031650d64SMarek Vasut * of the active descriptor list, and increments the count of pending 38131650d64SMarek Vasut * descriptors. 38231650d64SMarek Vasut * 38331650d64SMarek Vasut * The MXS platform DMA software imposes some rules on DMA commands to maintain 38431650d64SMarek Vasut * important invariants. These rules are NOT checked, but they must be carefully 38531650d64SMarek Vasut * applied by software that uses MXS DMA channels. 38631650d64SMarek Vasut * 38731650d64SMarek Vasut * Invariant: 38831650d64SMarek Vasut * The DMA channel's hardware semaphore must reflect the number of DMA 38931650d64SMarek Vasut * commands the hardware will process, but has not yet finished. 39031650d64SMarek Vasut * 39131650d64SMarek Vasut * Explanation: 39231650d64SMarek Vasut * A DMA channel begins processing commands when its hardware semaphore is 39331650d64SMarek Vasut * written with a value greater than zero, and it stops processing commands 39431650d64SMarek Vasut * when the semaphore returns to zero. 39531650d64SMarek Vasut * 39631650d64SMarek Vasut * When a channel finishes a DMA command, it will decrement its semaphore if 39731650d64SMarek Vasut * the DECREMENT_SEMAPHORE bit is set in that command's flags bits. 39831650d64SMarek Vasut * 39931650d64SMarek Vasut * In principle, it's not necessary for the DECREMENT_SEMAPHORE to be set, 40031650d64SMarek Vasut * unless it suits the purposes of the software. For example, one could 40131650d64SMarek Vasut * construct a series of five DMA commands, with the DECREMENT_SEMAPHORE 40231650d64SMarek Vasut * bit set only in the last one. Then, setting the DMA channel's hardware 40331650d64SMarek Vasut * semaphore to one would cause the entire series of five commands to be 40431650d64SMarek Vasut * processed. However, this example would violate the invariant given above. 40531650d64SMarek Vasut * 40631650d64SMarek Vasut * Rule: 40731650d64SMarek Vasut * ALL DMA commands MUST have the DECREMENT_SEMAPHORE bit set so that the DMA 40831650d64SMarek Vasut * channel's hardware semaphore will be decremented EVERY time a command is 40931650d64SMarek Vasut * processed. 41031650d64SMarek Vasut */ 41131650d64SMarek Vasut int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc) 41231650d64SMarek Vasut { 41331650d64SMarek Vasut struct mxs_dma_chan *pchan; 41431650d64SMarek Vasut struct mxs_dma_desc *last; 41531650d64SMarek Vasut int ret; 41631650d64SMarek Vasut 41731650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 41831650d64SMarek Vasut if (ret) 41931650d64SMarek Vasut return ret; 42031650d64SMarek Vasut 42131650d64SMarek Vasut pchan = mxs_dma_channels + channel; 42231650d64SMarek Vasut 42331650d64SMarek Vasut pdesc->cmd.next = mxs_dma_cmd_address(pdesc); 42431650d64SMarek Vasut pdesc->flags |= MXS_DMA_DESC_FIRST | MXS_DMA_DESC_LAST; 42531650d64SMarek Vasut 42631650d64SMarek Vasut if (!list_empty(&pchan->active)) { 42731650d64SMarek Vasut last = list_entry(pchan->active.prev, struct mxs_dma_desc, 42831650d64SMarek Vasut node); 42931650d64SMarek Vasut 43031650d64SMarek Vasut pdesc->flags &= ~MXS_DMA_DESC_FIRST; 43131650d64SMarek Vasut last->flags &= ~MXS_DMA_DESC_LAST; 43231650d64SMarek Vasut 43331650d64SMarek Vasut last->cmd.next = mxs_dma_cmd_address(pdesc); 43431650d64SMarek Vasut last->cmd.data |= MXS_DMA_DESC_CHAIN; 435c3dfe707SMarek Vasut 436c3dfe707SMarek Vasut mxs_dma_flush_desc(last); 43731650d64SMarek Vasut } 43831650d64SMarek Vasut pdesc->flags |= MXS_DMA_DESC_READY; 43931650d64SMarek Vasut if (pdesc->flags & MXS_DMA_DESC_FIRST) 44031650d64SMarek Vasut pchan->pending_num++; 44131650d64SMarek Vasut list_add_tail(&pdesc->node, &pchan->active); 44231650d64SMarek Vasut 443c3dfe707SMarek Vasut mxs_dma_flush_desc(pdesc); 444c3dfe707SMarek Vasut 44531650d64SMarek Vasut return ret; 44631650d64SMarek Vasut } 44731650d64SMarek Vasut 44831650d64SMarek Vasut /* 44931650d64SMarek Vasut * Clean up processed DMA descriptors. 45031650d64SMarek Vasut * 45131650d64SMarek Vasut * This function removes processed DMA descriptors from the "active" list. Pass 45231650d64SMarek Vasut * in a non-NULL list head to get the descriptors moved to your list. Pass NULL 45331650d64SMarek Vasut * to get the descriptors moved to the channel's "done" list. Descriptors on 45431650d64SMarek Vasut * the "done" list can be retrieved with mxs_dma_get_finished(). 45531650d64SMarek Vasut * 45631650d64SMarek Vasut * This function marks the DMA channel as "not busy" if no unprocessed 45731650d64SMarek Vasut * descriptors remain on the "active" list. 45831650d64SMarek Vasut */ 459aa72e43bSMarek Vasut static int mxs_dma_finish(int channel, struct list_head *head) 46031650d64SMarek Vasut { 46131650d64SMarek Vasut int sem; 46231650d64SMarek Vasut struct mxs_dma_chan *pchan; 46331650d64SMarek Vasut struct list_head *p, *q; 46431650d64SMarek Vasut struct mxs_dma_desc *pdesc; 46531650d64SMarek Vasut int ret; 46631650d64SMarek Vasut 46731650d64SMarek Vasut ret = mxs_dma_validate_chan(channel); 46831650d64SMarek Vasut if (ret) 46931650d64SMarek Vasut return ret; 47031650d64SMarek Vasut 47131650d64SMarek Vasut pchan = mxs_dma_channels + channel; 47231650d64SMarek Vasut 47331650d64SMarek Vasut sem = mxs_dma_read_semaphore(channel); 47431650d64SMarek Vasut if (sem < 0) 47531650d64SMarek Vasut return sem; 47631650d64SMarek Vasut 47731650d64SMarek Vasut if (sem == pchan->active_num) 47831650d64SMarek Vasut return 0; 47931650d64SMarek Vasut 48031650d64SMarek Vasut list_for_each_safe(p, q, &pchan->active) { 48131650d64SMarek Vasut if ((pchan->active_num) <= sem) 48231650d64SMarek Vasut break; 48331650d64SMarek Vasut 48431650d64SMarek Vasut pdesc = list_entry(p, struct mxs_dma_desc, node); 48531650d64SMarek Vasut pdesc->flags &= ~MXS_DMA_DESC_READY; 48631650d64SMarek Vasut 48731650d64SMarek Vasut if (head) 48831650d64SMarek Vasut list_move_tail(p, head); 48931650d64SMarek Vasut else 49031650d64SMarek Vasut list_move_tail(p, &pchan->done); 49131650d64SMarek Vasut 49231650d64SMarek Vasut if (pdesc->flags & MXS_DMA_DESC_LAST) 49331650d64SMarek Vasut pchan->active_num--; 49431650d64SMarek Vasut } 49531650d64SMarek Vasut 49631650d64SMarek Vasut if (sem == 0) 49731650d64SMarek Vasut pchan->flags &= ~MXS_DMA_FLAGS_BUSY; 49831650d64SMarek Vasut 49931650d64SMarek Vasut return 0; 50031650d64SMarek Vasut } 50131650d64SMarek Vasut 50231650d64SMarek Vasut /* 50331650d64SMarek Vasut * Wait for DMA channel to complete 50431650d64SMarek Vasut */ 505aa72e43bSMarek Vasut static int mxs_dma_wait_complete(uint32_t timeout, unsigned int chan) 50631650d64SMarek Vasut { 507*9c471142SOtavio Salvador struct mxs_apbh_regs *apbh_regs = 508*9c471142SOtavio Salvador (struct mxs_apbh_regs *)MXS_APBH_BASE; 50931650d64SMarek Vasut int ret; 51031650d64SMarek Vasut 51131650d64SMarek Vasut ret = mxs_dma_validate_chan(chan); 51231650d64SMarek Vasut if (ret) 51331650d64SMarek Vasut return ret; 51431650d64SMarek Vasut 51531650d64SMarek Vasut if (mx28_wait_mask_set(&apbh_regs->hw_apbh_ctrl1_reg, 51631650d64SMarek Vasut 1 << chan, timeout)) { 51731650d64SMarek Vasut ret = -ETIMEDOUT; 51831650d64SMarek Vasut mxs_dma_reset(chan); 51931650d64SMarek Vasut } 52031650d64SMarek Vasut 52112dab4ceSWolfram Sang return ret; 52231650d64SMarek Vasut } 52331650d64SMarek Vasut 52431650d64SMarek Vasut /* 52531650d64SMarek Vasut * Execute the DMA channel 52631650d64SMarek Vasut */ 52731650d64SMarek Vasut int mxs_dma_go(int chan) 52831650d64SMarek Vasut { 52931650d64SMarek Vasut uint32_t timeout = 10000; 53031650d64SMarek Vasut int ret; 53131650d64SMarek Vasut 53231650d64SMarek Vasut LIST_HEAD(tmp_desc_list); 53331650d64SMarek Vasut 53431650d64SMarek Vasut mxs_dma_enable_irq(chan, 1); 53531650d64SMarek Vasut mxs_dma_enable(chan); 53631650d64SMarek Vasut 53731650d64SMarek Vasut /* Wait for DMA to finish. */ 53831650d64SMarek Vasut ret = mxs_dma_wait_complete(timeout, chan); 53931650d64SMarek Vasut 54031650d64SMarek Vasut /* Clear out the descriptors we just ran. */ 54131650d64SMarek Vasut mxs_dma_finish(chan, &tmp_desc_list); 54231650d64SMarek Vasut 54331650d64SMarek Vasut /* Shut the DMA channel down. */ 54431650d64SMarek Vasut mxs_dma_ack_irq(chan); 54531650d64SMarek Vasut mxs_dma_reset(chan); 54631650d64SMarek Vasut mxs_dma_enable_irq(chan, 0); 54731650d64SMarek Vasut mxs_dma_disable(chan); 54831650d64SMarek Vasut 54931650d64SMarek Vasut return ret; 55031650d64SMarek Vasut } 55131650d64SMarek Vasut 55231650d64SMarek Vasut /* 55331650d64SMarek Vasut * Initialize the DMA hardware 55431650d64SMarek Vasut */ 55596666a39SMarek Vasut void mxs_dma_init(void) 55631650d64SMarek Vasut { 557*9c471142SOtavio Salvador struct mxs_apbh_regs *apbh_regs = 558*9c471142SOtavio Salvador (struct mxs_apbh_regs *)MXS_APBH_BASE; 55931650d64SMarek Vasut 56031650d64SMarek Vasut mx28_reset_block(&apbh_regs->hw_apbh_ctrl0_reg); 56131650d64SMarek Vasut 56231650d64SMarek Vasut #ifdef CONFIG_APBH_DMA_BURST8 56331650d64SMarek Vasut writel(APBH_CTRL0_AHB_BURST8_EN, 56431650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_set); 56531650d64SMarek Vasut #else 56631650d64SMarek Vasut writel(APBH_CTRL0_AHB_BURST8_EN, 56731650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_clr); 56831650d64SMarek Vasut #endif 56931650d64SMarek Vasut 57031650d64SMarek Vasut #ifdef CONFIG_APBH_DMA_BURST 57131650d64SMarek Vasut writel(APBH_CTRL0_APB_BURST_EN, 57231650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_set); 57331650d64SMarek Vasut #else 57431650d64SMarek Vasut writel(APBH_CTRL0_APB_BURST_EN, 57531650d64SMarek Vasut &apbh_regs->hw_apbh_ctrl0_clr); 57631650d64SMarek Vasut #endif 57796666a39SMarek Vasut } 57831650d64SMarek Vasut 57996666a39SMarek Vasut int mxs_dma_init_channel(int channel) 58096666a39SMarek Vasut { 58196666a39SMarek Vasut struct mxs_dma_chan *pchan; 58296666a39SMarek Vasut int ret; 58396666a39SMarek Vasut 58431650d64SMarek Vasut pchan = mxs_dma_channels + channel; 58531650d64SMarek Vasut pchan->flags = MXS_DMA_FLAGS_VALID; 58631650d64SMarek Vasut 58731650d64SMarek Vasut ret = mxs_dma_request(channel); 58831650d64SMarek Vasut 58931650d64SMarek Vasut if (ret) { 59031650d64SMarek Vasut printf("MXS DMA: Can't acquire DMA channel %i\n", 59131650d64SMarek Vasut channel); 59296666a39SMarek Vasut return ret; 59331650d64SMarek Vasut } 59431650d64SMarek Vasut 59531650d64SMarek Vasut mxs_dma_reset(channel); 59631650d64SMarek Vasut mxs_dma_ack_irq(channel); 59731650d64SMarek Vasut 59831650d64SMarek Vasut return 0; 59931650d64SMarek Vasut } 600