1173acc7cSZhang Wei /* 2173acc7cSZhang Wei * Freescale MPC85xx, MPC83xx DMA Engine support 3173acc7cSZhang Wei * 4e2c8e425SLi Yang * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved. 5173acc7cSZhang Wei * 6173acc7cSZhang Wei * Author: 7173acc7cSZhang Wei * Zhang Wei <wei.zhang@freescale.com>, Jul 2007 8173acc7cSZhang Wei * Ebony Zhu <ebony.zhu@freescale.com>, May 2007 9173acc7cSZhang Wei * 10173acc7cSZhang Wei * Description: 11173acc7cSZhang Wei * DMA engine driver for Freescale MPC8540 DMA controller, which is 12173acc7cSZhang Wei * also fit for MPC8560, MPC8555, MPC8548, MPC8641, and etc. 13c2e07b3aSStefan Weil * The support for MPC8349 DMA controller is also added. 14173acc7cSZhang Wei * 15a7aea373SIra W. Snyder * This driver instructs the DMA controller to issue the PCI Read Multiple 16a7aea373SIra W. Snyder * command for PCI read operations, instead of using the default PCI Read Line 17a7aea373SIra W. Snyder * command. Please be aware that this setting may result in read pre-fetching 18a7aea373SIra W. Snyder * on some platforms. 19a7aea373SIra W. Snyder * 20173acc7cSZhang Wei * This is free software; you can redistribute it and/or modify 21173acc7cSZhang Wei * it under the terms of the GNU General Public License as published by 22173acc7cSZhang Wei * the Free Software Foundation; either version 2 of the License, or 23173acc7cSZhang Wei * (at your option) any later version. 24173acc7cSZhang Wei * 25173acc7cSZhang Wei */ 26173acc7cSZhang Wei 27173acc7cSZhang Wei #include <linux/init.h> 28173acc7cSZhang Wei #include <linux/module.h> 29173acc7cSZhang Wei #include <linux/pci.h> 305a0e3ad6STejun Heo #include <linux/slab.h> 31173acc7cSZhang Wei #include <linux/interrupt.h> 32173acc7cSZhang Wei #include <linux/dmaengine.h> 33173acc7cSZhang Wei #include <linux/delay.h> 34173acc7cSZhang Wei #include <linux/dma-mapping.h> 35173acc7cSZhang Wei #include <linux/dmapool.h> 36173acc7cSZhang Wei #include <linux/of_platform.h> 37173acc7cSZhang Wei 38173acc7cSZhang Wei #include "fsldma.h" 39173acc7cSZhang Wei 40c1433041SIra Snyder static const char msg_ld_oom[] = "No free memory for link descriptor\n"; 41c1433041SIra Snyder 42*e8bd84dfSIra Snyder /* 43*e8bd84dfSIra Snyder * Register Helpers 44173acc7cSZhang Wei */ 45173acc7cSZhang Wei 46a1c03319SIra Snyder static void set_sr(struct fsldma_chan *chan, u32 val) 47173acc7cSZhang Wei { 48a1c03319SIra Snyder DMA_OUT(chan, &chan->regs->sr, val, 32); 49173acc7cSZhang Wei } 50173acc7cSZhang Wei 51a1c03319SIra Snyder static u32 get_sr(struct fsldma_chan *chan) 52173acc7cSZhang Wei { 53a1c03319SIra Snyder return DMA_IN(chan, &chan->regs->sr, 32); 54173acc7cSZhang Wei } 55173acc7cSZhang Wei 56*e8bd84dfSIra Snyder static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr) 57*e8bd84dfSIra Snyder { 58*e8bd84dfSIra Snyder DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64); 59*e8bd84dfSIra Snyder } 60*e8bd84dfSIra Snyder 61*e8bd84dfSIra Snyder static dma_addr_t get_cdar(struct fsldma_chan *chan) 62*e8bd84dfSIra Snyder { 63*e8bd84dfSIra Snyder return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; 64*e8bd84dfSIra Snyder } 65*e8bd84dfSIra Snyder 66*e8bd84dfSIra Snyder static dma_addr_t get_ndar(struct fsldma_chan *chan) 67*e8bd84dfSIra Snyder { 68*e8bd84dfSIra Snyder return DMA_IN(chan, &chan->regs->ndar, 64); 69*e8bd84dfSIra Snyder } 70*e8bd84dfSIra Snyder 71*e8bd84dfSIra Snyder static u32 get_bcr(struct fsldma_chan *chan) 72*e8bd84dfSIra Snyder { 73*e8bd84dfSIra Snyder return DMA_IN(chan, &chan->regs->bcr, 32); 74*e8bd84dfSIra Snyder } 75*e8bd84dfSIra Snyder 76*e8bd84dfSIra Snyder /* 77*e8bd84dfSIra Snyder * Descriptor Helpers 78*e8bd84dfSIra Snyder */ 79*e8bd84dfSIra Snyder 80a1c03319SIra Snyder static void set_desc_cnt(struct fsldma_chan *chan, 81173acc7cSZhang Wei struct fsl_dma_ld_hw *hw, u32 count) 82173acc7cSZhang Wei { 83a1c03319SIra Snyder hw->count = CPU_TO_DMA(chan, count, 32); 84173acc7cSZhang Wei } 85173acc7cSZhang Wei 86a1c03319SIra Snyder static void set_desc_src(struct fsldma_chan *chan, 87173acc7cSZhang Wei struct fsl_dma_ld_hw *hw, dma_addr_t src) 88173acc7cSZhang Wei { 89173acc7cSZhang Wei u64 snoop_bits; 90173acc7cSZhang Wei 91a1c03319SIra Snyder snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) 92173acc7cSZhang Wei ? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0; 93a1c03319SIra Snyder hw->src_addr = CPU_TO_DMA(chan, snoop_bits | src, 64); 94173acc7cSZhang Wei } 95173acc7cSZhang Wei 96a1c03319SIra Snyder static void set_desc_dst(struct fsldma_chan *chan, 97738f5f7eSIra Snyder struct fsl_dma_ld_hw *hw, dma_addr_t dst) 98173acc7cSZhang Wei { 99173acc7cSZhang Wei u64 snoop_bits; 100173acc7cSZhang Wei 101a1c03319SIra Snyder snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) 102173acc7cSZhang Wei ? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0; 103a1c03319SIra Snyder hw->dst_addr = CPU_TO_DMA(chan, snoop_bits | dst, 64); 104173acc7cSZhang Wei } 105173acc7cSZhang Wei 106a1c03319SIra Snyder static void set_desc_next(struct fsldma_chan *chan, 107173acc7cSZhang Wei struct fsl_dma_ld_hw *hw, dma_addr_t next) 108173acc7cSZhang Wei { 109173acc7cSZhang Wei u64 snoop_bits; 110173acc7cSZhang Wei 111a1c03319SIra Snyder snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX) 112173acc7cSZhang Wei ? FSL_DMA_SNEN : 0; 113a1c03319SIra Snyder hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64); 114173acc7cSZhang Wei } 115173acc7cSZhang Wei 116*e8bd84dfSIra Snyder static void set_ld_eol(struct fsldma_chan *chan, 117*e8bd84dfSIra Snyder struct fsl_desc_sw *desc) 118173acc7cSZhang Wei { 119*e8bd84dfSIra Snyder u64 snoop_bits; 120*e8bd84dfSIra Snyder 121*e8bd84dfSIra Snyder snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX) 122*e8bd84dfSIra Snyder ? FSL_DMA_SNEN : 0; 123*e8bd84dfSIra Snyder 124*e8bd84dfSIra Snyder desc->hw.next_ln_addr = CPU_TO_DMA(chan, 125*e8bd84dfSIra Snyder DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL 126*e8bd84dfSIra Snyder | snoop_bits, 64); 127173acc7cSZhang Wei } 128173acc7cSZhang Wei 129*e8bd84dfSIra Snyder /* 130*e8bd84dfSIra Snyder * DMA Engine Hardware Control Helpers 131*e8bd84dfSIra Snyder */ 132173acc7cSZhang Wei 133*e8bd84dfSIra Snyder static void dma_init(struct fsldma_chan *chan) 134173acc7cSZhang Wei { 135*e8bd84dfSIra Snyder /* Reset the channel */ 136*e8bd84dfSIra Snyder DMA_OUT(chan, &chan->regs->mr, 0, 32); 137173acc7cSZhang Wei 138*e8bd84dfSIra Snyder switch (chan->feature & FSL_DMA_IP_MASK) { 139*e8bd84dfSIra Snyder case FSL_DMA_IP_85XX: 140*e8bd84dfSIra Snyder /* Set the channel to below modes: 141*e8bd84dfSIra Snyder * EIE - Error interrupt enable 142*e8bd84dfSIra Snyder * EOSIE - End of segments interrupt enable (basic mode) 143*e8bd84dfSIra Snyder * EOLNIE - End of links interrupt enable 144*e8bd84dfSIra Snyder * BWC - Bandwidth sharing among channels 145*e8bd84dfSIra Snyder */ 146*e8bd84dfSIra Snyder DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC 147*e8bd84dfSIra Snyder | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE 148*e8bd84dfSIra Snyder | FSL_DMA_MR_EOSIE, 32); 149*e8bd84dfSIra Snyder break; 150*e8bd84dfSIra Snyder case FSL_DMA_IP_83XX: 151*e8bd84dfSIra Snyder /* Set the channel to below modes: 152*e8bd84dfSIra Snyder * EOTIE - End-of-transfer interrupt enable 153*e8bd84dfSIra Snyder * PRC_RM - PCI read multiple 154*e8bd84dfSIra Snyder */ 155*e8bd84dfSIra Snyder DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE 156*e8bd84dfSIra Snyder | FSL_DMA_MR_PRC_RM, 32); 157*e8bd84dfSIra Snyder break; 158*e8bd84dfSIra Snyder } 159f79abb62SZhang Wei } 160f79abb62SZhang Wei 161a1c03319SIra Snyder static int dma_is_idle(struct fsldma_chan *chan) 162173acc7cSZhang Wei { 163a1c03319SIra Snyder u32 sr = get_sr(chan); 164173acc7cSZhang Wei return (!(sr & FSL_DMA_SR_CB)) || (sr & FSL_DMA_SR_CH); 165173acc7cSZhang Wei } 166173acc7cSZhang Wei 167a1c03319SIra Snyder static void dma_start(struct fsldma_chan *chan) 168173acc7cSZhang Wei { 169272ca655SIra Snyder u32 mode; 170173acc7cSZhang Wei 171a1c03319SIra Snyder mode = DMA_IN(chan, &chan->regs->mr, 32); 172272ca655SIra Snyder 173a1c03319SIra Snyder if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { 174a1c03319SIra Snyder if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) { 175a1c03319SIra Snyder DMA_OUT(chan, &chan->regs->bcr, 0, 32); 176272ca655SIra Snyder mode |= FSL_DMA_MR_EMP_EN; 177272ca655SIra Snyder } else { 178272ca655SIra Snyder mode &= ~FSL_DMA_MR_EMP_EN; 179272ca655SIra Snyder } 18043a1a3edSIra Snyder } 181173acc7cSZhang Wei 182a1c03319SIra Snyder if (chan->feature & FSL_DMA_CHAN_START_EXT) 183272ca655SIra Snyder mode |= FSL_DMA_MR_EMS_EN; 184173acc7cSZhang Wei else 185272ca655SIra Snyder mode |= FSL_DMA_MR_CS; 186173acc7cSZhang Wei 187a1c03319SIra Snyder DMA_OUT(chan, &chan->regs->mr, mode, 32); 188173acc7cSZhang Wei } 189173acc7cSZhang Wei 190a1c03319SIra Snyder static void dma_halt(struct fsldma_chan *chan) 191173acc7cSZhang Wei { 192272ca655SIra Snyder u32 mode; 193900325a6SDan Williams int i; 194900325a6SDan Williams 195a1c03319SIra Snyder mode = DMA_IN(chan, &chan->regs->mr, 32); 196272ca655SIra Snyder mode |= FSL_DMA_MR_CA; 197a1c03319SIra Snyder DMA_OUT(chan, &chan->regs->mr, mode, 32); 198272ca655SIra Snyder 199272ca655SIra Snyder mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA); 200a1c03319SIra Snyder DMA_OUT(chan, &chan->regs->mr, mode, 32); 201173acc7cSZhang Wei 202900325a6SDan Williams for (i = 0; i < 100; i++) { 203a1c03319SIra Snyder if (dma_is_idle(chan)) 2049c3a50b7SIra Snyder return; 2059c3a50b7SIra Snyder 206173acc7cSZhang Wei udelay(10); 207900325a6SDan Williams } 208272ca655SIra Snyder 2099c3a50b7SIra Snyder if (!dma_is_idle(chan)) 210a1c03319SIra Snyder dev_err(chan->dev, "DMA halt timeout!\n"); 211173acc7cSZhang Wei } 212173acc7cSZhang Wei 213173acc7cSZhang Wei /** 214173acc7cSZhang Wei * fsl_chan_set_src_loop_size - Set source address hold transfer size 215a1c03319SIra Snyder * @chan : Freescale DMA channel 216173acc7cSZhang Wei * @size : Address loop size, 0 for disable loop 217173acc7cSZhang Wei * 218173acc7cSZhang Wei * The set source address hold transfer size. The source 219173acc7cSZhang Wei * address hold or loop transfer size is when the DMA transfer 220173acc7cSZhang Wei * data from source address (SA), if the loop size is 4, the DMA will 221173acc7cSZhang Wei * read data from SA, SA + 1, SA + 2, SA + 3, then loop back to SA, 222173acc7cSZhang Wei * SA + 1 ... and so on. 223173acc7cSZhang Wei */ 224a1c03319SIra Snyder static void fsl_chan_set_src_loop_size(struct fsldma_chan *chan, int size) 225173acc7cSZhang Wei { 226272ca655SIra Snyder u32 mode; 227272ca655SIra Snyder 228a1c03319SIra Snyder mode = DMA_IN(chan, &chan->regs->mr, 32); 229272ca655SIra Snyder 230173acc7cSZhang Wei switch (size) { 231173acc7cSZhang Wei case 0: 232272ca655SIra Snyder mode &= ~FSL_DMA_MR_SAHE; 233173acc7cSZhang Wei break; 234173acc7cSZhang Wei case 1: 235173acc7cSZhang Wei case 2: 236173acc7cSZhang Wei case 4: 237173acc7cSZhang Wei case 8: 238272ca655SIra Snyder mode |= FSL_DMA_MR_SAHE | (__ilog2(size) << 14); 239173acc7cSZhang Wei break; 240173acc7cSZhang Wei } 241272ca655SIra Snyder 242a1c03319SIra Snyder DMA_OUT(chan, &chan->regs->mr, mode, 32); 243173acc7cSZhang Wei } 244173acc7cSZhang Wei 245173acc7cSZhang Wei /** 246738f5f7eSIra Snyder * fsl_chan_set_dst_loop_size - Set destination address hold transfer size 247a1c03319SIra Snyder * @chan : Freescale DMA channel 248173acc7cSZhang Wei * @size : Address loop size, 0 for disable loop 249173acc7cSZhang Wei * 250173acc7cSZhang Wei * The set destination address hold transfer size. The destination 251173acc7cSZhang Wei * address hold or loop transfer size is when the DMA transfer 252173acc7cSZhang Wei * data to destination address (TA), if the loop size is 4, the DMA will 253173acc7cSZhang Wei * write data to TA, TA + 1, TA + 2, TA + 3, then loop back to TA, 254173acc7cSZhang Wei * TA + 1 ... and so on. 255173acc7cSZhang Wei */ 256a1c03319SIra Snyder static void fsl_chan_set_dst_loop_size(struct fsldma_chan *chan, int size) 257173acc7cSZhang Wei { 258272ca655SIra Snyder u32 mode; 259272ca655SIra Snyder 260a1c03319SIra Snyder mode = DMA_IN(chan, &chan->regs->mr, 32); 261272ca655SIra Snyder 262173acc7cSZhang Wei switch (size) { 263173acc7cSZhang Wei case 0: 264272ca655SIra Snyder mode &= ~FSL_DMA_MR_DAHE; 265173acc7cSZhang Wei break; 266173acc7cSZhang Wei case 1: 267173acc7cSZhang Wei case 2: 268173acc7cSZhang Wei case 4: 269173acc7cSZhang Wei case 8: 270272ca655SIra Snyder mode |= FSL_DMA_MR_DAHE | (__ilog2(size) << 16); 271173acc7cSZhang Wei break; 272173acc7cSZhang Wei } 273272ca655SIra Snyder 274a1c03319SIra Snyder DMA_OUT(chan, &chan->regs->mr, mode, 32); 275173acc7cSZhang Wei } 276173acc7cSZhang Wei 277173acc7cSZhang Wei /** 278e6c7ecb6SIra Snyder * fsl_chan_set_request_count - Set DMA Request Count for external control 279a1c03319SIra Snyder * @chan : Freescale DMA channel 280e6c7ecb6SIra Snyder * @size : Number of bytes to transfer in a single request 281173acc7cSZhang Wei * 282e6c7ecb6SIra Snyder * The Freescale DMA channel can be controlled by the external signal DREQ#. 283e6c7ecb6SIra Snyder * The DMA request count is how many bytes are allowed to transfer before 284e6c7ecb6SIra Snyder * pausing the channel, after which a new assertion of DREQ# resumes channel 285e6c7ecb6SIra Snyder * operation. 286e6c7ecb6SIra Snyder * 287e6c7ecb6SIra Snyder * A size of 0 disables external pause control. The maximum size is 1024. 288173acc7cSZhang Wei */ 289a1c03319SIra Snyder static void fsl_chan_set_request_count(struct fsldma_chan *chan, int size) 290173acc7cSZhang Wei { 291272ca655SIra Snyder u32 mode; 292272ca655SIra Snyder 293e6c7ecb6SIra Snyder BUG_ON(size > 1024); 294272ca655SIra Snyder 295a1c03319SIra Snyder mode = DMA_IN(chan, &chan->regs->mr, 32); 296272ca655SIra Snyder mode |= (__ilog2(size) << 24) & 0x0f000000; 297272ca655SIra Snyder 298a1c03319SIra Snyder DMA_OUT(chan, &chan->regs->mr, mode, 32); 299e6c7ecb6SIra Snyder } 300e6c7ecb6SIra Snyder 301e6c7ecb6SIra Snyder /** 302e6c7ecb6SIra Snyder * fsl_chan_toggle_ext_pause - Toggle channel external pause status 303a1c03319SIra Snyder * @chan : Freescale DMA channel 304e6c7ecb6SIra Snyder * @enable : 0 is disabled, 1 is enabled. 305e6c7ecb6SIra Snyder * 306e6c7ecb6SIra Snyder * The Freescale DMA channel can be controlled by the external signal DREQ#. 307e6c7ecb6SIra Snyder * The DMA Request Count feature should be used in addition to this feature 308e6c7ecb6SIra Snyder * to set the number of bytes to transfer before pausing the channel. 309e6c7ecb6SIra Snyder */ 310a1c03319SIra Snyder static void fsl_chan_toggle_ext_pause(struct fsldma_chan *chan, int enable) 311e6c7ecb6SIra Snyder { 312e6c7ecb6SIra Snyder if (enable) 313a1c03319SIra Snyder chan->feature |= FSL_DMA_CHAN_PAUSE_EXT; 314e6c7ecb6SIra Snyder else 315a1c03319SIra Snyder chan->feature &= ~FSL_DMA_CHAN_PAUSE_EXT; 316173acc7cSZhang Wei } 317173acc7cSZhang Wei 318173acc7cSZhang Wei /** 319173acc7cSZhang Wei * fsl_chan_toggle_ext_start - Toggle channel external start status 320a1c03319SIra Snyder * @chan : Freescale DMA channel 321173acc7cSZhang Wei * @enable : 0 is disabled, 1 is enabled. 322173acc7cSZhang Wei * 323173acc7cSZhang Wei * If enable the external start, the channel can be started by an 324173acc7cSZhang Wei * external DMA start pin. So the dma_start() does not start the 325173acc7cSZhang Wei * transfer immediately. The DMA channel will wait for the 326173acc7cSZhang Wei * control pin asserted. 327173acc7cSZhang Wei */ 328a1c03319SIra Snyder static void fsl_chan_toggle_ext_start(struct fsldma_chan *chan, int enable) 329173acc7cSZhang Wei { 330173acc7cSZhang Wei if (enable) 331a1c03319SIra Snyder chan->feature |= FSL_DMA_CHAN_START_EXT; 332173acc7cSZhang Wei else 333a1c03319SIra Snyder chan->feature &= ~FSL_DMA_CHAN_START_EXT; 334173acc7cSZhang Wei } 335173acc7cSZhang Wei 3369c3a50b7SIra Snyder static void append_ld_queue(struct fsldma_chan *chan, 3379c3a50b7SIra Snyder struct fsl_desc_sw *desc) 3389c3a50b7SIra Snyder { 3399c3a50b7SIra Snyder struct fsl_desc_sw *tail = to_fsl_desc(chan->ld_pending.prev); 3409c3a50b7SIra Snyder 3419c3a50b7SIra Snyder if (list_empty(&chan->ld_pending)) 3429c3a50b7SIra Snyder goto out_splice; 3439c3a50b7SIra Snyder 3449c3a50b7SIra Snyder /* 3459c3a50b7SIra Snyder * Add the hardware descriptor to the chain of hardware descriptors 3469c3a50b7SIra Snyder * that already exists in memory. 3479c3a50b7SIra Snyder * 3489c3a50b7SIra Snyder * This will un-set the EOL bit of the existing transaction, and the 3499c3a50b7SIra Snyder * last link in this transaction will become the EOL descriptor. 3509c3a50b7SIra Snyder */ 3519c3a50b7SIra Snyder set_desc_next(chan, &tail->hw, desc->async_tx.phys); 3529c3a50b7SIra Snyder 3539c3a50b7SIra Snyder /* 3549c3a50b7SIra Snyder * Add the software descriptor and all children to the list 3559c3a50b7SIra Snyder * of pending transactions 3569c3a50b7SIra Snyder */ 3579c3a50b7SIra Snyder out_splice: 3589c3a50b7SIra Snyder list_splice_tail_init(&desc->tx_list, &chan->ld_pending); 3599c3a50b7SIra Snyder } 3609c3a50b7SIra Snyder 361173acc7cSZhang Wei static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) 362173acc7cSZhang Wei { 363a1c03319SIra Snyder struct fsldma_chan *chan = to_fsl_chan(tx->chan); 364eda34234SDan Williams struct fsl_desc_sw *desc = tx_to_fsl_desc(tx); 365eda34234SDan Williams struct fsl_desc_sw *child; 366173acc7cSZhang Wei unsigned long flags; 367173acc7cSZhang Wei dma_cookie_t cookie; 368173acc7cSZhang Wei 369a1c03319SIra Snyder spin_lock_irqsave(&chan->desc_lock, flags); 370173acc7cSZhang Wei 3719c3a50b7SIra Snyder /* 3729c3a50b7SIra Snyder * assign cookies to all of the software descriptors 3739c3a50b7SIra Snyder * that make up this transaction 3749c3a50b7SIra Snyder */ 375a1c03319SIra Snyder cookie = chan->common.cookie; 376eda34234SDan Williams list_for_each_entry(child, &desc->tx_list, node) { 377173acc7cSZhang Wei cookie++; 378173acc7cSZhang Wei if (cookie < 0) 379173acc7cSZhang Wei cookie = 1; 380173acc7cSZhang Wei 3816ca3a7a9SSteven J. Magnani child->async_tx.cookie = cookie; 382bcfb7465SIra Snyder } 383bcfb7465SIra Snyder 384a1c03319SIra Snyder chan->common.cookie = cookie; 3859c3a50b7SIra Snyder 3869c3a50b7SIra Snyder /* put this transaction onto the tail of the pending queue */ 387a1c03319SIra Snyder append_ld_queue(chan, desc); 388173acc7cSZhang Wei 389a1c03319SIra Snyder spin_unlock_irqrestore(&chan->desc_lock, flags); 390173acc7cSZhang Wei 391173acc7cSZhang Wei return cookie; 392173acc7cSZhang Wei } 393173acc7cSZhang Wei 394173acc7cSZhang Wei /** 395173acc7cSZhang Wei * fsl_dma_alloc_descriptor - Allocate descriptor from channel's DMA pool. 396a1c03319SIra Snyder * @chan : Freescale DMA channel 397173acc7cSZhang Wei * 398173acc7cSZhang Wei * Return - The descriptor allocated. NULL for failed. 399173acc7cSZhang Wei */ 400173acc7cSZhang Wei static struct fsl_desc_sw *fsl_dma_alloc_descriptor( 401a1c03319SIra Snyder struct fsldma_chan *chan) 402173acc7cSZhang Wei { 4039c3a50b7SIra Snyder struct fsl_desc_sw *desc; 404173acc7cSZhang Wei dma_addr_t pdesc; 405173acc7cSZhang Wei 4069c3a50b7SIra Snyder desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc); 4079c3a50b7SIra Snyder if (!desc) { 4089c3a50b7SIra Snyder dev_dbg(chan->dev, "out of memory for link desc\n"); 4099c3a50b7SIra Snyder return NULL; 410173acc7cSZhang Wei } 411173acc7cSZhang Wei 4129c3a50b7SIra Snyder memset(desc, 0, sizeof(*desc)); 4139c3a50b7SIra Snyder INIT_LIST_HEAD(&desc->tx_list); 4149c3a50b7SIra Snyder dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); 4159c3a50b7SIra Snyder desc->async_tx.tx_submit = fsl_dma_tx_submit; 4169c3a50b7SIra Snyder desc->async_tx.phys = pdesc; 4179c3a50b7SIra Snyder 4189c3a50b7SIra Snyder return desc; 419173acc7cSZhang Wei } 420173acc7cSZhang Wei 421173acc7cSZhang Wei 422173acc7cSZhang Wei /** 423173acc7cSZhang Wei * fsl_dma_alloc_chan_resources - Allocate resources for DMA channel. 424a1c03319SIra Snyder * @chan : Freescale DMA channel 425173acc7cSZhang Wei * 426173acc7cSZhang Wei * This function will create a dma pool for descriptor allocation. 427173acc7cSZhang Wei * 428173acc7cSZhang Wei * Return - The number of descriptors allocated. 429173acc7cSZhang Wei */ 430a1c03319SIra Snyder static int fsl_dma_alloc_chan_resources(struct dma_chan *dchan) 431173acc7cSZhang Wei { 432a1c03319SIra Snyder struct fsldma_chan *chan = to_fsl_chan(dchan); 43377cd62e8STimur Tabi 43477cd62e8STimur Tabi /* Has this channel already been allocated? */ 435a1c03319SIra Snyder if (chan->desc_pool) 43677cd62e8STimur Tabi return 1; 437173acc7cSZhang Wei 4389c3a50b7SIra Snyder /* 4399c3a50b7SIra Snyder * We need the descriptor to be aligned to 32bytes 440173acc7cSZhang Wei * for meeting FSL DMA specification requirement. 441173acc7cSZhang Wei */ 442a1c03319SIra Snyder chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool", 4439c3a50b7SIra Snyder chan->dev, 4449c3a50b7SIra Snyder sizeof(struct fsl_desc_sw), 4459c3a50b7SIra Snyder __alignof__(struct fsl_desc_sw), 0); 446a1c03319SIra Snyder if (!chan->desc_pool) { 4479c3a50b7SIra Snyder dev_err(chan->dev, "unable to allocate channel %d " 4489c3a50b7SIra Snyder "descriptor pool\n", chan->id); 4499c3a50b7SIra Snyder return -ENOMEM; 450173acc7cSZhang Wei } 451173acc7cSZhang Wei 4529c3a50b7SIra Snyder /* there is at least one descriptor free to be allocated */ 453173acc7cSZhang Wei return 1; 454173acc7cSZhang Wei } 455173acc7cSZhang Wei 456173acc7cSZhang Wei /** 4579c3a50b7SIra Snyder * fsldma_free_desc_list - Free all descriptors in a queue 4589c3a50b7SIra Snyder * @chan: Freescae DMA channel 4599c3a50b7SIra Snyder * @list: the list to free 4609c3a50b7SIra Snyder * 4619c3a50b7SIra Snyder * LOCKING: must hold chan->desc_lock 4629c3a50b7SIra Snyder */ 4639c3a50b7SIra Snyder static void fsldma_free_desc_list(struct fsldma_chan *chan, 4649c3a50b7SIra Snyder struct list_head *list) 4659c3a50b7SIra Snyder { 4669c3a50b7SIra Snyder struct fsl_desc_sw *desc, *_desc; 4679c3a50b7SIra Snyder 4689c3a50b7SIra Snyder list_for_each_entry_safe(desc, _desc, list, node) { 4699c3a50b7SIra Snyder list_del(&desc->node); 4709c3a50b7SIra Snyder dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); 4719c3a50b7SIra Snyder } 4729c3a50b7SIra Snyder } 4739c3a50b7SIra Snyder 4749c3a50b7SIra Snyder static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan, 4759c3a50b7SIra Snyder struct list_head *list) 4769c3a50b7SIra Snyder { 4779c3a50b7SIra Snyder struct fsl_desc_sw *desc, *_desc; 4789c3a50b7SIra Snyder 4799c3a50b7SIra Snyder list_for_each_entry_safe_reverse(desc, _desc, list, node) { 4809c3a50b7SIra Snyder list_del(&desc->node); 4819c3a50b7SIra Snyder dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); 4829c3a50b7SIra Snyder } 4839c3a50b7SIra Snyder } 4849c3a50b7SIra Snyder 4859c3a50b7SIra Snyder /** 486173acc7cSZhang Wei * fsl_dma_free_chan_resources - Free all resources of the channel. 487a1c03319SIra Snyder * @chan : Freescale DMA channel 488173acc7cSZhang Wei */ 489a1c03319SIra Snyder static void fsl_dma_free_chan_resources(struct dma_chan *dchan) 490173acc7cSZhang Wei { 491a1c03319SIra Snyder struct fsldma_chan *chan = to_fsl_chan(dchan); 492173acc7cSZhang Wei unsigned long flags; 493173acc7cSZhang Wei 494a1c03319SIra Snyder dev_dbg(chan->dev, "Free all channel resources.\n"); 495a1c03319SIra Snyder spin_lock_irqsave(&chan->desc_lock, flags); 4969c3a50b7SIra Snyder fsldma_free_desc_list(chan, &chan->ld_pending); 4979c3a50b7SIra Snyder fsldma_free_desc_list(chan, &chan->ld_running); 498a1c03319SIra Snyder spin_unlock_irqrestore(&chan->desc_lock, flags); 49977cd62e8STimur Tabi 5009c3a50b7SIra Snyder dma_pool_destroy(chan->desc_pool); 501a1c03319SIra Snyder chan->desc_pool = NULL; 502173acc7cSZhang Wei } 503173acc7cSZhang Wei 5042187c269SZhang Wei static struct dma_async_tx_descriptor * 505a1c03319SIra Snyder fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags) 5062187c269SZhang Wei { 507a1c03319SIra Snyder struct fsldma_chan *chan; 5082187c269SZhang Wei struct fsl_desc_sw *new; 5092187c269SZhang Wei 510a1c03319SIra Snyder if (!dchan) 5112187c269SZhang Wei return NULL; 5122187c269SZhang Wei 513a1c03319SIra Snyder chan = to_fsl_chan(dchan); 5142187c269SZhang Wei 515a1c03319SIra Snyder new = fsl_dma_alloc_descriptor(chan); 5162187c269SZhang Wei if (!new) { 517c1433041SIra Snyder dev_err(chan->dev, msg_ld_oom); 5182187c269SZhang Wei return NULL; 5192187c269SZhang Wei } 5202187c269SZhang Wei 5212187c269SZhang Wei new->async_tx.cookie = -EBUSY; 522636bdeaaSDan Williams new->async_tx.flags = flags; 5232187c269SZhang Wei 524f79abb62SZhang Wei /* Insert the link descriptor to the LD ring */ 525eda34234SDan Williams list_add_tail(&new->node, &new->tx_list); 526f79abb62SZhang Wei 5272187c269SZhang Wei /* Set End-of-link to the last link descriptor of new list*/ 528a1c03319SIra Snyder set_ld_eol(chan, new); 5292187c269SZhang Wei 5302187c269SZhang Wei return &new->async_tx; 5312187c269SZhang Wei } 5322187c269SZhang Wei 533173acc7cSZhang Wei static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( 534a1c03319SIra Snyder struct dma_chan *dchan, dma_addr_t dma_dst, dma_addr_t dma_src, 535173acc7cSZhang Wei size_t len, unsigned long flags) 536173acc7cSZhang Wei { 537a1c03319SIra Snyder struct fsldma_chan *chan; 538173acc7cSZhang Wei struct fsl_desc_sw *first = NULL, *prev = NULL, *new; 539173acc7cSZhang Wei size_t copy; 540173acc7cSZhang Wei 541a1c03319SIra Snyder if (!dchan) 542173acc7cSZhang Wei return NULL; 543173acc7cSZhang Wei 544173acc7cSZhang Wei if (!len) 545173acc7cSZhang Wei return NULL; 546173acc7cSZhang Wei 547a1c03319SIra Snyder chan = to_fsl_chan(dchan); 548173acc7cSZhang Wei 549173acc7cSZhang Wei do { 550173acc7cSZhang Wei 551173acc7cSZhang Wei /* Allocate the link descriptor from DMA pool */ 552a1c03319SIra Snyder new = fsl_dma_alloc_descriptor(chan); 553173acc7cSZhang Wei if (!new) { 554c1433041SIra Snyder dev_err(chan->dev, msg_ld_oom); 5552e077f8eSIra Snyder goto fail; 556173acc7cSZhang Wei } 557173acc7cSZhang Wei #ifdef FSL_DMA_LD_DEBUG 558a1c03319SIra Snyder dev_dbg(chan->dev, "new link desc alloc %p\n", new); 559173acc7cSZhang Wei #endif 560173acc7cSZhang Wei 56156822843SZhang Wei copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT); 562173acc7cSZhang Wei 563a1c03319SIra Snyder set_desc_cnt(chan, &new->hw, copy); 564a1c03319SIra Snyder set_desc_src(chan, &new->hw, dma_src); 565a1c03319SIra Snyder set_desc_dst(chan, &new->hw, dma_dst); 566173acc7cSZhang Wei 567173acc7cSZhang Wei if (!first) 568173acc7cSZhang Wei first = new; 569173acc7cSZhang Wei else 570a1c03319SIra Snyder set_desc_next(chan, &prev->hw, new->async_tx.phys); 571173acc7cSZhang Wei 572173acc7cSZhang Wei new->async_tx.cookie = 0; 573636bdeaaSDan Williams async_tx_ack(&new->async_tx); 574173acc7cSZhang Wei 575173acc7cSZhang Wei prev = new; 576173acc7cSZhang Wei len -= copy; 577173acc7cSZhang Wei dma_src += copy; 578738f5f7eSIra Snyder dma_dst += copy; 579173acc7cSZhang Wei 580173acc7cSZhang Wei /* Insert the link descriptor to the LD ring */ 581eda34234SDan Williams list_add_tail(&new->node, &first->tx_list); 582173acc7cSZhang Wei } while (len); 583173acc7cSZhang Wei 584636bdeaaSDan Williams new->async_tx.flags = flags; /* client is in control of this ack */ 585173acc7cSZhang Wei new->async_tx.cookie = -EBUSY; 586173acc7cSZhang Wei 587173acc7cSZhang Wei /* Set End-of-link to the last link descriptor of new list*/ 588a1c03319SIra Snyder set_ld_eol(chan, new); 589173acc7cSZhang Wei 5902e077f8eSIra Snyder return &first->async_tx; 5912e077f8eSIra Snyder 5922e077f8eSIra Snyder fail: 5932e077f8eSIra Snyder if (!first) 5942e077f8eSIra Snyder return NULL; 5952e077f8eSIra Snyder 5969c3a50b7SIra Snyder fsldma_free_desc_list_reverse(chan, &first->tx_list); 5972e077f8eSIra Snyder return NULL; 598173acc7cSZhang Wei } 599173acc7cSZhang Wei 600c1433041SIra Snyder static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan, 601c1433041SIra Snyder struct scatterlist *dst_sg, unsigned int dst_nents, 602c1433041SIra Snyder struct scatterlist *src_sg, unsigned int src_nents, 603c1433041SIra Snyder unsigned long flags) 604c1433041SIra Snyder { 605c1433041SIra Snyder struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL; 606c1433041SIra Snyder struct fsldma_chan *chan = to_fsl_chan(dchan); 607c1433041SIra Snyder size_t dst_avail, src_avail; 608c1433041SIra Snyder dma_addr_t dst, src; 609c1433041SIra Snyder size_t len; 610c1433041SIra Snyder 611c1433041SIra Snyder /* basic sanity checks */ 612c1433041SIra Snyder if (dst_nents == 0 || src_nents == 0) 613c1433041SIra Snyder return NULL; 614c1433041SIra Snyder 615c1433041SIra Snyder if (dst_sg == NULL || src_sg == NULL) 616c1433041SIra Snyder return NULL; 617c1433041SIra Snyder 618c1433041SIra Snyder /* 619c1433041SIra Snyder * TODO: should we check that both scatterlists have the same 620c1433041SIra Snyder * TODO: number of bytes in total? Is that really an error? 621c1433041SIra Snyder */ 622c1433041SIra Snyder 623c1433041SIra Snyder /* get prepared for the loop */ 624c1433041SIra Snyder dst_avail = sg_dma_len(dst_sg); 625c1433041SIra Snyder src_avail = sg_dma_len(src_sg); 626c1433041SIra Snyder 627c1433041SIra Snyder /* run until we are out of scatterlist entries */ 628c1433041SIra Snyder while (true) { 629c1433041SIra Snyder 630c1433041SIra Snyder /* create the largest transaction possible */ 631c1433041SIra Snyder len = min_t(size_t, src_avail, dst_avail); 632c1433041SIra Snyder len = min_t(size_t, len, FSL_DMA_BCR_MAX_CNT); 633c1433041SIra Snyder if (len == 0) 634c1433041SIra Snyder goto fetch; 635c1433041SIra Snyder 636c1433041SIra Snyder dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_avail; 637c1433041SIra Snyder src = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_avail; 638c1433041SIra Snyder 639c1433041SIra Snyder /* allocate and populate the descriptor */ 640c1433041SIra Snyder new = fsl_dma_alloc_descriptor(chan); 641c1433041SIra Snyder if (!new) { 642c1433041SIra Snyder dev_err(chan->dev, msg_ld_oom); 643c1433041SIra Snyder goto fail; 644c1433041SIra Snyder } 645c1433041SIra Snyder #ifdef FSL_DMA_LD_DEBUG 646c1433041SIra Snyder dev_dbg(chan->dev, "new link desc alloc %p\n", new); 647c1433041SIra Snyder #endif 648c1433041SIra Snyder 649c1433041SIra Snyder set_desc_cnt(chan, &new->hw, len); 650c1433041SIra Snyder set_desc_src(chan, &new->hw, src); 651c1433041SIra Snyder set_desc_dst(chan, &new->hw, dst); 652c1433041SIra Snyder 653c1433041SIra Snyder if (!first) 654c1433041SIra Snyder first = new; 655c1433041SIra Snyder else 656c1433041SIra Snyder set_desc_next(chan, &prev->hw, new->async_tx.phys); 657c1433041SIra Snyder 658c1433041SIra Snyder new->async_tx.cookie = 0; 659c1433041SIra Snyder async_tx_ack(&new->async_tx); 660c1433041SIra Snyder prev = new; 661c1433041SIra Snyder 662c1433041SIra Snyder /* Insert the link descriptor to the LD ring */ 663c1433041SIra Snyder list_add_tail(&new->node, &first->tx_list); 664c1433041SIra Snyder 665c1433041SIra Snyder /* update metadata */ 666c1433041SIra Snyder dst_avail -= len; 667c1433041SIra Snyder src_avail -= len; 668c1433041SIra Snyder 669c1433041SIra Snyder fetch: 670c1433041SIra Snyder /* fetch the next dst scatterlist entry */ 671c1433041SIra Snyder if (dst_avail == 0) { 672c1433041SIra Snyder 673c1433041SIra Snyder /* no more entries: we're done */ 674c1433041SIra Snyder if (dst_nents == 0) 675c1433041SIra Snyder break; 676c1433041SIra Snyder 677c1433041SIra Snyder /* fetch the next entry: if there are no more: done */ 678c1433041SIra Snyder dst_sg = sg_next(dst_sg); 679c1433041SIra Snyder if (dst_sg == NULL) 680c1433041SIra Snyder break; 681c1433041SIra Snyder 682c1433041SIra Snyder dst_nents--; 683c1433041SIra Snyder dst_avail = sg_dma_len(dst_sg); 684c1433041SIra Snyder } 685c1433041SIra Snyder 686c1433041SIra Snyder /* fetch the next src scatterlist entry */ 687c1433041SIra Snyder if (src_avail == 0) { 688c1433041SIra Snyder 689c1433041SIra Snyder /* no more entries: we're done */ 690c1433041SIra Snyder if (src_nents == 0) 691c1433041SIra Snyder break; 692c1433041SIra Snyder 693c1433041SIra Snyder /* fetch the next entry: if there are no more: done */ 694c1433041SIra Snyder src_sg = sg_next(src_sg); 695c1433041SIra Snyder if (src_sg == NULL) 696c1433041SIra Snyder break; 697c1433041SIra Snyder 698c1433041SIra Snyder src_nents--; 699c1433041SIra Snyder src_avail = sg_dma_len(src_sg); 700c1433041SIra Snyder } 701c1433041SIra Snyder } 702c1433041SIra Snyder 703c1433041SIra Snyder new->async_tx.flags = flags; /* client is in control of this ack */ 704c1433041SIra Snyder new->async_tx.cookie = -EBUSY; 705c1433041SIra Snyder 706c1433041SIra Snyder /* Set End-of-link to the last link descriptor of new list */ 707c1433041SIra Snyder set_ld_eol(chan, new); 708c1433041SIra Snyder 709c1433041SIra Snyder return &first->async_tx; 710c1433041SIra Snyder 711c1433041SIra Snyder fail: 712c1433041SIra Snyder if (!first) 713c1433041SIra Snyder return NULL; 714c1433041SIra Snyder 715c1433041SIra Snyder fsldma_free_desc_list_reverse(chan, &first->tx_list); 716c1433041SIra Snyder return NULL; 717c1433041SIra Snyder } 718c1433041SIra Snyder 719173acc7cSZhang Wei /** 720bbea0b6eSIra Snyder * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction 721bbea0b6eSIra Snyder * @chan: DMA channel 722bbea0b6eSIra Snyder * @sgl: scatterlist to transfer to/from 723bbea0b6eSIra Snyder * @sg_len: number of entries in @scatterlist 724bbea0b6eSIra Snyder * @direction: DMA direction 725bbea0b6eSIra Snyder * @flags: DMAEngine flags 726bbea0b6eSIra Snyder * 727bbea0b6eSIra Snyder * Prepare a set of descriptors for a DMA_SLAVE transaction. Following the 728bbea0b6eSIra Snyder * DMA_SLAVE API, this gets the device-specific information from the 729bbea0b6eSIra Snyder * chan->private variable. 730bbea0b6eSIra Snyder */ 731bbea0b6eSIra Snyder static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg( 732a1c03319SIra Snyder struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len, 733bbea0b6eSIra Snyder enum dma_data_direction direction, unsigned long flags) 734bbea0b6eSIra Snyder { 735bbea0b6eSIra Snyder /* 736968f19aeSIra Snyder * This operation is not supported on the Freescale DMA controller 737bbea0b6eSIra Snyder * 738968f19aeSIra Snyder * However, we need to provide the function pointer to allow the 739968f19aeSIra Snyder * device_control() method to work. 740bbea0b6eSIra Snyder */ 741bbea0b6eSIra Snyder return NULL; 742bbea0b6eSIra Snyder } 743bbea0b6eSIra Snyder 744c3635c78SLinus Walleij static int fsl_dma_device_control(struct dma_chan *dchan, 74505827630SLinus Walleij enum dma_ctrl_cmd cmd, unsigned long arg) 746bbea0b6eSIra Snyder { 747968f19aeSIra Snyder struct dma_slave_config *config; 748a1c03319SIra Snyder struct fsldma_chan *chan; 749bbea0b6eSIra Snyder unsigned long flags; 750968f19aeSIra Snyder int size; 751c3635c78SLinus Walleij 752a1c03319SIra Snyder if (!dchan) 753c3635c78SLinus Walleij return -EINVAL; 754bbea0b6eSIra Snyder 755a1c03319SIra Snyder chan = to_fsl_chan(dchan); 756bbea0b6eSIra Snyder 757968f19aeSIra Snyder switch (cmd) { 758968f19aeSIra Snyder case DMA_TERMINATE_ALL: 759bbea0b6eSIra Snyder /* Halt the DMA engine */ 760a1c03319SIra Snyder dma_halt(chan); 761bbea0b6eSIra Snyder 762a1c03319SIra Snyder spin_lock_irqsave(&chan->desc_lock, flags); 763bbea0b6eSIra Snyder 764bbea0b6eSIra Snyder /* Remove and free all of the descriptors in the LD queue */ 7659c3a50b7SIra Snyder fsldma_free_desc_list(chan, &chan->ld_pending); 7669c3a50b7SIra Snyder fsldma_free_desc_list(chan, &chan->ld_running); 767bbea0b6eSIra Snyder 768a1c03319SIra Snyder spin_unlock_irqrestore(&chan->desc_lock, flags); 769968f19aeSIra Snyder return 0; 770968f19aeSIra Snyder 771968f19aeSIra Snyder case DMA_SLAVE_CONFIG: 772968f19aeSIra Snyder config = (struct dma_slave_config *)arg; 773968f19aeSIra Snyder 774968f19aeSIra Snyder /* make sure the channel supports setting burst size */ 775968f19aeSIra Snyder if (!chan->set_request_count) 776968f19aeSIra Snyder return -ENXIO; 777968f19aeSIra Snyder 778968f19aeSIra Snyder /* we set the controller burst size depending on direction */ 779968f19aeSIra Snyder if (config->direction == DMA_TO_DEVICE) 780968f19aeSIra Snyder size = config->dst_addr_width * config->dst_maxburst; 781968f19aeSIra Snyder else 782968f19aeSIra Snyder size = config->src_addr_width * config->src_maxburst; 783968f19aeSIra Snyder 784968f19aeSIra Snyder chan->set_request_count(chan, size); 785968f19aeSIra Snyder return 0; 786968f19aeSIra Snyder 787968f19aeSIra Snyder case FSLDMA_EXTERNAL_START: 788968f19aeSIra Snyder 789968f19aeSIra Snyder /* make sure the channel supports external start */ 790968f19aeSIra Snyder if (!chan->toggle_ext_start) 791968f19aeSIra Snyder return -ENXIO; 792968f19aeSIra Snyder 793968f19aeSIra Snyder chan->toggle_ext_start(chan, arg); 794968f19aeSIra Snyder return 0; 795968f19aeSIra Snyder 796968f19aeSIra Snyder default: 797968f19aeSIra Snyder return -ENXIO; 798968f19aeSIra Snyder } 799c3635c78SLinus Walleij 800c3635c78SLinus Walleij return 0; 801bbea0b6eSIra Snyder } 802bbea0b6eSIra Snyder 803bbea0b6eSIra Snyder /** 804173acc7cSZhang Wei * fsl_dma_update_completed_cookie - Update the completed cookie. 805a1c03319SIra Snyder * @chan : Freescale DMA channel 8069c3a50b7SIra Snyder * 8079c3a50b7SIra Snyder * CONTEXT: hardirq 808173acc7cSZhang Wei */ 809a1c03319SIra Snyder static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan) 810173acc7cSZhang Wei { 8119c3a50b7SIra Snyder struct fsl_desc_sw *desc; 8129c3a50b7SIra Snyder unsigned long flags; 8139c3a50b7SIra Snyder dma_cookie_t cookie; 814173acc7cSZhang Wei 8159c3a50b7SIra Snyder spin_lock_irqsave(&chan->desc_lock, flags); 816173acc7cSZhang Wei 8179c3a50b7SIra Snyder if (list_empty(&chan->ld_running)) { 8189c3a50b7SIra Snyder dev_dbg(chan->dev, "no running descriptors\n"); 8199c3a50b7SIra Snyder goto out_unlock; 820173acc7cSZhang Wei } 821173acc7cSZhang Wei 8229c3a50b7SIra Snyder /* Get the last descriptor, update the cookie to that */ 8239c3a50b7SIra Snyder desc = to_fsl_desc(chan->ld_running.prev); 824a1c03319SIra Snyder if (dma_is_idle(chan)) 8259c3a50b7SIra Snyder cookie = desc->async_tx.cookie; 82676bd061fSSteven J. Magnani else { 8279c3a50b7SIra Snyder cookie = desc->async_tx.cookie - 1; 82876bd061fSSteven J. Magnani if (unlikely(cookie < DMA_MIN_COOKIE)) 82976bd061fSSteven J. Magnani cookie = DMA_MAX_COOKIE; 83076bd061fSSteven J. Magnani } 8319c3a50b7SIra Snyder 8329c3a50b7SIra Snyder chan->completed_cookie = cookie; 8339c3a50b7SIra Snyder 8349c3a50b7SIra Snyder out_unlock: 8359c3a50b7SIra Snyder spin_unlock_irqrestore(&chan->desc_lock, flags); 836173acc7cSZhang Wei } 8379c3a50b7SIra Snyder 8389c3a50b7SIra Snyder /** 8399c3a50b7SIra Snyder * fsldma_desc_status - Check the status of a descriptor 8409c3a50b7SIra Snyder * @chan: Freescale DMA channel 8419c3a50b7SIra Snyder * @desc: DMA SW descriptor 8429c3a50b7SIra Snyder * 8439c3a50b7SIra Snyder * This function will return the status of the given descriptor 8449c3a50b7SIra Snyder */ 8459c3a50b7SIra Snyder static enum dma_status fsldma_desc_status(struct fsldma_chan *chan, 8469c3a50b7SIra Snyder struct fsl_desc_sw *desc) 8479c3a50b7SIra Snyder { 8489c3a50b7SIra Snyder return dma_async_is_complete(desc->async_tx.cookie, 8499c3a50b7SIra Snyder chan->completed_cookie, 8509c3a50b7SIra Snyder chan->common.cookie); 851173acc7cSZhang Wei } 852173acc7cSZhang Wei 853173acc7cSZhang Wei /** 854173acc7cSZhang Wei * fsl_chan_ld_cleanup - Clean up link descriptors 855a1c03319SIra Snyder * @chan : Freescale DMA channel 856173acc7cSZhang Wei * 857173acc7cSZhang Wei * This function clean up the ld_queue of DMA channel. 858173acc7cSZhang Wei */ 859a1c03319SIra Snyder static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) 860173acc7cSZhang Wei { 861173acc7cSZhang Wei struct fsl_desc_sw *desc, *_desc; 862173acc7cSZhang Wei unsigned long flags; 863173acc7cSZhang Wei 864a1c03319SIra Snyder spin_lock_irqsave(&chan->desc_lock, flags); 865173acc7cSZhang Wei 8669c3a50b7SIra Snyder dev_dbg(chan->dev, "chan completed_cookie = %d\n", chan->completed_cookie); 8679c3a50b7SIra Snyder list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) { 868173acc7cSZhang Wei dma_async_tx_callback callback; 869173acc7cSZhang Wei void *callback_param; 870173acc7cSZhang Wei 8719c3a50b7SIra Snyder if (fsldma_desc_status(chan, desc) == DMA_IN_PROGRESS) 872173acc7cSZhang Wei break; 873173acc7cSZhang Wei 8749c3a50b7SIra Snyder /* Remove from the list of running transactions */ 875173acc7cSZhang Wei list_del(&desc->node); 876173acc7cSZhang Wei 877173acc7cSZhang Wei /* Run the link descriptor callback function */ 8789c3a50b7SIra Snyder callback = desc->async_tx.callback; 8799c3a50b7SIra Snyder callback_param = desc->async_tx.callback_param; 880173acc7cSZhang Wei if (callback) { 881a1c03319SIra Snyder spin_unlock_irqrestore(&chan->desc_lock, flags); 8829c3a50b7SIra Snyder dev_dbg(chan->dev, "LD %p callback\n", desc); 883173acc7cSZhang Wei callback(callback_param); 884a1c03319SIra Snyder spin_lock_irqsave(&chan->desc_lock, flags); 885173acc7cSZhang Wei } 8869c3a50b7SIra Snyder 8879c3a50b7SIra Snyder /* Run any dependencies, then free the descriptor */ 8889c3a50b7SIra Snyder dma_run_dependencies(&desc->async_tx); 8899c3a50b7SIra Snyder dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); 890173acc7cSZhang Wei } 8919c3a50b7SIra Snyder 892a1c03319SIra Snyder spin_unlock_irqrestore(&chan->desc_lock, flags); 893173acc7cSZhang Wei } 894173acc7cSZhang Wei 895173acc7cSZhang Wei /** 8969c3a50b7SIra Snyder * fsl_chan_xfer_ld_queue - transfer any pending transactions 897a1c03319SIra Snyder * @chan : Freescale DMA channel 8989c3a50b7SIra Snyder * 8999c3a50b7SIra Snyder * This will make sure that any pending transactions will be run. 9009c3a50b7SIra Snyder * If the DMA controller is idle, it will be started. Otherwise, 9019c3a50b7SIra Snyder * the DMA controller's interrupt handler will start any pending 9029c3a50b7SIra Snyder * transactions when it becomes idle. 903173acc7cSZhang Wei */ 904a1c03319SIra Snyder static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) 905173acc7cSZhang Wei { 9069c3a50b7SIra Snyder struct fsl_desc_sw *desc; 907173acc7cSZhang Wei unsigned long flags; 908173acc7cSZhang Wei 909a1c03319SIra Snyder spin_lock_irqsave(&chan->desc_lock, flags); 910138ef018SIra Snyder 9119c3a50b7SIra Snyder /* 9129c3a50b7SIra Snyder * If the list of pending descriptors is empty, then we 9139c3a50b7SIra Snyder * don't need to do any work at all 9149c3a50b7SIra Snyder */ 9159c3a50b7SIra Snyder if (list_empty(&chan->ld_pending)) { 9169c3a50b7SIra Snyder dev_dbg(chan->dev, "no pending LDs\n"); 917138ef018SIra Snyder goto out_unlock; 9189c3a50b7SIra Snyder } 919173acc7cSZhang Wei 9209c3a50b7SIra Snyder /* 9219c3a50b7SIra Snyder * The DMA controller is not idle, which means the interrupt 9229c3a50b7SIra Snyder * handler will start any queued transactions when it runs 9239c3a50b7SIra Snyder * at the end of the current transaction 9249c3a50b7SIra Snyder */ 9259c3a50b7SIra Snyder if (!dma_is_idle(chan)) { 9269c3a50b7SIra Snyder dev_dbg(chan->dev, "DMA controller still busy\n"); 9279c3a50b7SIra Snyder goto out_unlock; 9289c3a50b7SIra Snyder } 9299c3a50b7SIra Snyder 9309c3a50b7SIra Snyder /* 9319c3a50b7SIra Snyder * TODO: 9329c3a50b7SIra Snyder * make sure the dma_halt() function really un-wedges the 9339c3a50b7SIra Snyder * controller as much as possible 9349c3a50b7SIra Snyder */ 935a1c03319SIra Snyder dma_halt(chan); 936173acc7cSZhang Wei 9379c3a50b7SIra Snyder /* 9389c3a50b7SIra Snyder * If there are some link descriptors which have not been 9399c3a50b7SIra Snyder * transferred, we need to start the controller 940173acc7cSZhang Wei */ 941173acc7cSZhang Wei 9429c3a50b7SIra Snyder /* 9439c3a50b7SIra Snyder * Move all elements from the queue of pending transactions 9449c3a50b7SIra Snyder * onto the list of running transactions 9459c3a50b7SIra Snyder */ 9469c3a50b7SIra Snyder desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node); 9479c3a50b7SIra Snyder list_splice_tail_init(&chan->ld_pending, &chan->ld_running); 948173acc7cSZhang Wei 9499c3a50b7SIra Snyder /* 9509c3a50b7SIra Snyder * Program the descriptor's address into the DMA controller, 9519c3a50b7SIra Snyder * then start the DMA transaction 9529c3a50b7SIra Snyder */ 9539c3a50b7SIra Snyder set_cdar(chan, desc->async_tx.phys); 954a1c03319SIra Snyder dma_start(chan); 955138ef018SIra Snyder 956138ef018SIra Snyder out_unlock: 957a1c03319SIra Snyder spin_unlock_irqrestore(&chan->desc_lock, flags); 958173acc7cSZhang Wei } 959173acc7cSZhang Wei 960173acc7cSZhang Wei /** 961173acc7cSZhang Wei * fsl_dma_memcpy_issue_pending - Issue the DMA start command 962a1c03319SIra Snyder * @chan : Freescale DMA channel 963173acc7cSZhang Wei */ 964a1c03319SIra Snyder static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan) 965173acc7cSZhang Wei { 966a1c03319SIra Snyder struct fsldma_chan *chan = to_fsl_chan(dchan); 967a1c03319SIra Snyder fsl_chan_xfer_ld_queue(chan); 968173acc7cSZhang Wei } 969173acc7cSZhang Wei 970173acc7cSZhang Wei /** 97107934481SLinus Walleij * fsl_tx_status - Determine the DMA status 972a1c03319SIra Snyder * @chan : Freescale DMA channel 973173acc7cSZhang Wei */ 97407934481SLinus Walleij static enum dma_status fsl_tx_status(struct dma_chan *dchan, 975173acc7cSZhang Wei dma_cookie_t cookie, 97607934481SLinus Walleij struct dma_tx_state *txstate) 977173acc7cSZhang Wei { 978a1c03319SIra Snyder struct fsldma_chan *chan = to_fsl_chan(dchan); 979173acc7cSZhang Wei dma_cookie_t last_used; 980173acc7cSZhang Wei dma_cookie_t last_complete; 981173acc7cSZhang Wei 982a1c03319SIra Snyder fsl_chan_ld_cleanup(chan); 983173acc7cSZhang Wei 984a1c03319SIra Snyder last_used = dchan->cookie; 985a1c03319SIra Snyder last_complete = chan->completed_cookie; 986173acc7cSZhang Wei 987bca34692SDan Williams dma_set_tx_state(txstate, last_complete, last_used, 0); 988173acc7cSZhang Wei 989173acc7cSZhang Wei return dma_async_is_complete(cookie, last_complete, last_used); 990173acc7cSZhang Wei } 991173acc7cSZhang Wei 992d3f620b2SIra Snyder /*----------------------------------------------------------------------------*/ 993d3f620b2SIra Snyder /* Interrupt Handling */ 994d3f620b2SIra Snyder /*----------------------------------------------------------------------------*/ 995d3f620b2SIra Snyder 996e7a29151SIra Snyder static irqreturn_t fsldma_chan_irq(int irq, void *data) 997173acc7cSZhang Wei { 998a1c03319SIra Snyder struct fsldma_chan *chan = data; 9991c62979eSZhang Wei int update_cookie = 0; 10001c62979eSZhang Wei int xfer_ld_q = 0; 1001a1c03319SIra Snyder u32 stat; 1002173acc7cSZhang Wei 10039c3a50b7SIra Snyder /* save and clear the status register */ 1004a1c03319SIra Snyder stat = get_sr(chan); 10059c3a50b7SIra Snyder set_sr(chan, stat); 10069c3a50b7SIra Snyder dev_dbg(chan->dev, "irq: channel %d, stat = 0x%x\n", chan->id, stat); 1007173acc7cSZhang Wei 1008173acc7cSZhang Wei stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH); 1009173acc7cSZhang Wei if (!stat) 1010173acc7cSZhang Wei return IRQ_NONE; 1011173acc7cSZhang Wei 1012173acc7cSZhang Wei if (stat & FSL_DMA_SR_TE) 1013a1c03319SIra Snyder dev_err(chan->dev, "Transfer Error!\n"); 1014173acc7cSZhang Wei 10159c3a50b7SIra Snyder /* 10169c3a50b7SIra Snyder * Programming Error 1017f79abb62SZhang Wei * The DMA_INTERRUPT async_tx is a NULL transfer, which will 1018f79abb62SZhang Wei * triger a PE interrupt. 1019f79abb62SZhang Wei */ 1020f79abb62SZhang Wei if (stat & FSL_DMA_SR_PE) { 10219c3a50b7SIra Snyder dev_dbg(chan->dev, "irq: Programming Error INT\n"); 1022a1c03319SIra Snyder if (get_bcr(chan) == 0) { 1023f79abb62SZhang Wei /* BCR register is 0, this is a DMA_INTERRUPT async_tx. 1024f79abb62SZhang Wei * Now, update the completed cookie, and continue the 1025f79abb62SZhang Wei * next uncompleted transfer. 1026f79abb62SZhang Wei */ 10271c62979eSZhang Wei update_cookie = 1; 10281c62979eSZhang Wei xfer_ld_q = 1; 1029f79abb62SZhang Wei } 1030f79abb62SZhang Wei stat &= ~FSL_DMA_SR_PE; 1031f79abb62SZhang Wei } 1032f79abb62SZhang Wei 10339c3a50b7SIra Snyder /* 10349c3a50b7SIra Snyder * If the link descriptor segment transfer finishes, 1035173acc7cSZhang Wei * we will recycle the used descriptor. 1036173acc7cSZhang Wei */ 1037173acc7cSZhang Wei if (stat & FSL_DMA_SR_EOSI) { 10389c3a50b7SIra Snyder dev_dbg(chan->dev, "irq: End-of-segments INT\n"); 10399c3a50b7SIra Snyder dev_dbg(chan->dev, "irq: clndar 0x%llx, nlndar 0x%llx\n", 1040a1c03319SIra Snyder (unsigned long long)get_cdar(chan), 1041a1c03319SIra Snyder (unsigned long long)get_ndar(chan)); 1042173acc7cSZhang Wei stat &= ~FSL_DMA_SR_EOSI; 10431c62979eSZhang Wei update_cookie = 1; 10441c62979eSZhang Wei } 10451c62979eSZhang Wei 10469c3a50b7SIra Snyder /* 10479c3a50b7SIra Snyder * For MPC8349, EOCDI event need to update cookie 10481c62979eSZhang Wei * and start the next transfer if it exist. 10491c62979eSZhang Wei */ 10501c62979eSZhang Wei if (stat & FSL_DMA_SR_EOCDI) { 10519c3a50b7SIra Snyder dev_dbg(chan->dev, "irq: End-of-Chain link INT\n"); 10521c62979eSZhang Wei stat &= ~FSL_DMA_SR_EOCDI; 10531c62979eSZhang Wei update_cookie = 1; 10541c62979eSZhang Wei xfer_ld_q = 1; 1055173acc7cSZhang Wei } 1056173acc7cSZhang Wei 10579c3a50b7SIra Snyder /* 10589c3a50b7SIra Snyder * If it current transfer is the end-of-transfer, 1059173acc7cSZhang Wei * we should clear the Channel Start bit for 1060173acc7cSZhang Wei * prepare next transfer. 1061173acc7cSZhang Wei */ 10621c62979eSZhang Wei if (stat & FSL_DMA_SR_EOLNI) { 10639c3a50b7SIra Snyder dev_dbg(chan->dev, "irq: End-of-link INT\n"); 1064173acc7cSZhang Wei stat &= ~FSL_DMA_SR_EOLNI; 10651c62979eSZhang Wei xfer_ld_q = 1; 1066173acc7cSZhang Wei } 1067173acc7cSZhang Wei 10681c62979eSZhang Wei if (update_cookie) 1069a1c03319SIra Snyder fsl_dma_update_completed_cookie(chan); 10701c62979eSZhang Wei if (xfer_ld_q) 1071a1c03319SIra Snyder fsl_chan_xfer_ld_queue(chan); 1072173acc7cSZhang Wei if (stat) 10739c3a50b7SIra Snyder dev_dbg(chan->dev, "irq: unhandled sr 0x%02x\n", stat); 1074173acc7cSZhang Wei 10759c3a50b7SIra Snyder dev_dbg(chan->dev, "irq: Exit\n"); 1076a1c03319SIra Snyder tasklet_schedule(&chan->tasklet); 1077173acc7cSZhang Wei return IRQ_HANDLED; 1078173acc7cSZhang Wei } 1079173acc7cSZhang Wei 1080173acc7cSZhang Wei static void dma_do_tasklet(unsigned long data) 1081173acc7cSZhang Wei { 1082a1c03319SIra Snyder struct fsldma_chan *chan = (struct fsldma_chan *)data; 1083a1c03319SIra Snyder fsl_chan_ld_cleanup(chan); 1084173acc7cSZhang Wei } 1085173acc7cSZhang Wei 1086d3f620b2SIra Snyder static irqreturn_t fsldma_ctrl_irq(int irq, void *data) 1087d3f620b2SIra Snyder { 1088d3f620b2SIra Snyder struct fsldma_device *fdev = data; 1089d3f620b2SIra Snyder struct fsldma_chan *chan; 1090d3f620b2SIra Snyder unsigned int handled = 0; 1091d3f620b2SIra Snyder u32 gsr, mask; 1092d3f620b2SIra Snyder int i; 1093d3f620b2SIra Snyder 1094d3f620b2SIra Snyder gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->regs) 1095d3f620b2SIra Snyder : in_le32(fdev->regs); 1096d3f620b2SIra Snyder mask = 0xff000000; 1097d3f620b2SIra Snyder dev_dbg(fdev->dev, "IRQ: gsr 0x%.8x\n", gsr); 1098d3f620b2SIra Snyder 1099d3f620b2SIra Snyder for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { 1100d3f620b2SIra Snyder chan = fdev->chan[i]; 1101d3f620b2SIra Snyder if (!chan) 1102d3f620b2SIra Snyder continue; 1103d3f620b2SIra Snyder 1104d3f620b2SIra Snyder if (gsr & mask) { 1105d3f620b2SIra Snyder dev_dbg(fdev->dev, "IRQ: chan %d\n", chan->id); 1106d3f620b2SIra Snyder fsldma_chan_irq(irq, chan); 1107d3f620b2SIra Snyder handled++; 1108d3f620b2SIra Snyder } 1109d3f620b2SIra Snyder 1110d3f620b2SIra Snyder gsr &= ~mask; 1111d3f620b2SIra Snyder mask >>= 8; 1112d3f620b2SIra Snyder } 1113d3f620b2SIra Snyder 1114d3f620b2SIra Snyder return IRQ_RETVAL(handled); 1115d3f620b2SIra Snyder } 1116d3f620b2SIra Snyder 1117d3f620b2SIra Snyder static void fsldma_free_irqs(struct fsldma_device *fdev) 1118d3f620b2SIra Snyder { 1119d3f620b2SIra Snyder struct fsldma_chan *chan; 1120d3f620b2SIra Snyder int i; 1121d3f620b2SIra Snyder 1122d3f620b2SIra Snyder if (fdev->irq != NO_IRQ) { 1123d3f620b2SIra Snyder dev_dbg(fdev->dev, "free per-controller IRQ\n"); 1124d3f620b2SIra Snyder free_irq(fdev->irq, fdev); 1125d3f620b2SIra Snyder return; 1126d3f620b2SIra Snyder } 1127d3f620b2SIra Snyder 1128d3f620b2SIra Snyder for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { 1129d3f620b2SIra Snyder chan = fdev->chan[i]; 1130d3f620b2SIra Snyder if (chan && chan->irq != NO_IRQ) { 1131d3f620b2SIra Snyder dev_dbg(fdev->dev, "free channel %d IRQ\n", chan->id); 1132d3f620b2SIra Snyder free_irq(chan->irq, chan); 1133d3f620b2SIra Snyder } 1134d3f620b2SIra Snyder } 1135d3f620b2SIra Snyder } 1136d3f620b2SIra Snyder 1137d3f620b2SIra Snyder static int fsldma_request_irqs(struct fsldma_device *fdev) 1138d3f620b2SIra Snyder { 1139d3f620b2SIra Snyder struct fsldma_chan *chan; 1140d3f620b2SIra Snyder int ret; 1141d3f620b2SIra Snyder int i; 1142d3f620b2SIra Snyder 1143d3f620b2SIra Snyder /* if we have a per-controller IRQ, use that */ 1144d3f620b2SIra Snyder if (fdev->irq != NO_IRQ) { 1145d3f620b2SIra Snyder dev_dbg(fdev->dev, "request per-controller IRQ\n"); 1146d3f620b2SIra Snyder ret = request_irq(fdev->irq, fsldma_ctrl_irq, IRQF_SHARED, 1147d3f620b2SIra Snyder "fsldma-controller", fdev); 1148d3f620b2SIra Snyder return ret; 1149d3f620b2SIra Snyder } 1150d3f620b2SIra Snyder 1151d3f620b2SIra Snyder /* no per-controller IRQ, use the per-channel IRQs */ 1152d3f620b2SIra Snyder for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { 1153d3f620b2SIra Snyder chan = fdev->chan[i]; 1154d3f620b2SIra Snyder if (!chan) 1155d3f620b2SIra Snyder continue; 1156d3f620b2SIra Snyder 1157d3f620b2SIra Snyder if (chan->irq == NO_IRQ) { 1158d3f620b2SIra Snyder dev_err(fdev->dev, "no interrupts property defined for " 1159d3f620b2SIra Snyder "DMA channel %d. Please fix your " 1160d3f620b2SIra Snyder "device tree\n", chan->id); 1161d3f620b2SIra Snyder ret = -ENODEV; 1162d3f620b2SIra Snyder goto out_unwind; 1163d3f620b2SIra Snyder } 1164d3f620b2SIra Snyder 1165d3f620b2SIra Snyder dev_dbg(fdev->dev, "request channel %d IRQ\n", chan->id); 1166d3f620b2SIra Snyder ret = request_irq(chan->irq, fsldma_chan_irq, IRQF_SHARED, 1167d3f620b2SIra Snyder "fsldma-chan", chan); 1168d3f620b2SIra Snyder if (ret) { 1169d3f620b2SIra Snyder dev_err(fdev->dev, "unable to request IRQ for DMA " 1170d3f620b2SIra Snyder "channel %d\n", chan->id); 1171d3f620b2SIra Snyder goto out_unwind; 1172d3f620b2SIra Snyder } 1173d3f620b2SIra Snyder } 1174d3f620b2SIra Snyder 1175d3f620b2SIra Snyder return 0; 1176d3f620b2SIra Snyder 1177d3f620b2SIra Snyder out_unwind: 1178d3f620b2SIra Snyder for (/* none */; i >= 0; i--) { 1179d3f620b2SIra Snyder chan = fdev->chan[i]; 1180d3f620b2SIra Snyder if (!chan) 1181d3f620b2SIra Snyder continue; 1182d3f620b2SIra Snyder 1183d3f620b2SIra Snyder if (chan->irq == NO_IRQ) 1184d3f620b2SIra Snyder continue; 1185d3f620b2SIra Snyder 1186d3f620b2SIra Snyder free_irq(chan->irq, chan); 1187d3f620b2SIra Snyder } 1188d3f620b2SIra Snyder 1189d3f620b2SIra Snyder return ret; 1190d3f620b2SIra Snyder } 1191d3f620b2SIra Snyder 1192a4f56d4bSIra Snyder /*----------------------------------------------------------------------------*/ 1193a4f56d4bSIra Snyder /* OpenFirmware Subsystem */ 1194a4f56d4bSIra Snyder /*----------------------------------------------------------------------------*/ 1195a4f56d4bSIra Snyder 1196a4f56d4bSIra Snyder static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev, 119777cd62e8STimur Tabi struct device_node *node, u32 feature, const char *compatible) 1198173acc7cSZhang Wei { 1199a1c03319SIra Snyder struct fsldma_chan *chan; 12004ce0e953SIra Snyder struct resource res; 1201173acc7cSZhang Wei int err; 1202173acc7cSZhang Wei 1203173acc7cSZhang Wei /* alloc channel */ 1204a1c03319SIra Snyder chan = kzalloc(sizeof(*chan), GFP_KERNEL); 1205a1c03319SIra Snyder if (!chan) { 1206e7a29151SIra Snyder dev_err(fdev->dev, "no free memory for DMA channels!\n"); 1207e7a29151SIra Snyder err = -ENOMEM; 1208e7a29151SIra Snyder goto out_return; 1209173acc7cSZhang Wei } 1210173acc7cSZhang Wei 1211e7a29151SIra Snyder /* ioremap registers for use */ 1212a1c03319SIra Snyder chan->regs = of_iomap(node, 0); 1213a1c03319SIra Snyder if (!chan->regs) { 1214e7a29151SIra Snyder dev_err(fdev->dev, "unable to ioremap registers\n"); 1215e7a29151SIra Snyder err = -ENOMEM; 1216a1c03319SIra Snyder goto out_free_chan; 1217e7a29151SIra Snyder } 1218e7a29151SIra Snyder 12194ce0e953SIra Snyder err = of_address_to_resource(node, 0, &res); 1220173acc7cSZhang Wei if (err) { 1221e7a29151SIra Snyder dev_err(fdev->dev, "unable to find 'reg' property\n"); 1222e7a29151SIra Snyder goto out_iounmap_regs; 1223173acc7cSZhang Wei } 1224173acc7cSZhang Wei 1225a1c03319SIra Snyder chan->feature = feature; 1226173acc7cSZhang Wei if (!fdev->feature) 1227a1c03319SIra Snyder fdev->feature = chan->feature; 1228173acc7cSZhang Wei 1229e7a29151SIra Snyder /* 1230e7a29151SIra Snyder * If the DMA device's feature is different than the feature 1231e7a29151SIra Snyder * of its channels, report the bug 1232173acc7cSZhang Wei */ 1233a1c03319SIra Snyder WARN_ON(fdev->feature != chan->feature); 1234173acc7cSZhang Wei 1235a1c03319SIra Snyder chan->dev = fdev->dev; 1236a1c03319SIra Snyder chan->id = ((res.start - 0x100) & 0xfff) >> 7; 1237a1c03319SIra Snyder if (chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) { 1238e7a29151SIra Snyder dev_err(fdev->dev, "too many channels for device\n"); 1239173acc7cSZhang Wei err = -EINVAL; 1240e7a29151SIra Snyder goto out_iounmap_regs; 1241173acc7cSZhang Wei } 1242173acc7cSZhang Wei 1243a1c03319SIra Snyder fdev->chan[chan->id] = chan; 1244a1c03319SIra Snyder tasklet_init(&chan->tasklet, dma_do_tasklet, (unsigned long)chan); 1245e7a29151SIra Snyder 1246e7a29151SIra Snyder /* Initialize the channel */ 1247a1c03319SIra Snyder dma_init(chan); 1248173acc7cSZhang Wei 1249173acc7cSZhang Wei /* Clear cdar registers */ 1250a1c03319SIra Snyder set_cdar(chan, 0); 1251173acc7cSZhang Wei 1252a1c03319SIra Snyder switch (chan->feature & FSL_DMA_IP_MASK) { 1253173acc7cSZhang Wei case FSL_DMA_IP_85XX: 1254a1c03319SIra Snyder chan->toggle_ext_pause = fsl_chan_toggle_ext_pause; 1255173acc7cSZhang Wei case FSL_DMA_IP_83XX: 1256a1c03319SIra Snyder chan->toggle_ext_start = fsl_chan_toggle_ext_start; 1257a1c03319SIra Snyder chan->set_src_loop_size = fsl_chan_set_src_loop_size; 1258a1c03319SIra Snyder chan->set_dst_loop_size = fsl_chan_set_dst_loop_size; 1259a1c03319SIra Snyder chan->set_request_count = fsl_chan_set_request_count; 1260173acc7cSZhang Wei } 1261173acc7cSZhang Wei 1262a1c03319SIra Snyder spin_lock_init(&chan->desc_lock); 12639c3a50b7SIra Snyder INIT_LIST_HEAD(&chan->ld_pending); 12649c3a50b7SIra Snyder INIT_LIST_HEAD(&chan->ld_running); 1265173acc7cSZhang Wei 1266a1c03319SIra Snyder chan->common.device = &fdev->common; 1267173acc7cSZhang Wei 1268d3f620b2SIra Snyder /* find the IRQ line, if it exists in the device tree */ 1269a1c03319SIra Snyder chan->irq = irq_of_parse_and_map(node, 0); 1270d3f620b2SIra Snyder 1271173acc7cSZhang Wei /* Add the channel to DMA device channel list */ 1272a1c03319SIra Snyder list_add_tail(&chan->common.device_node, &fdev->common.channels); 1273173acc7cSZhang Wei fdev->common.chancnt++; 1274173acc7cSZhang Wei 1275a1c03319SIra Snyder dev_info(fdev->dev, "#%d (%s), irq %d\n", chan->id, compatible, 1276a1c03319SIra Snyder chan->irq != NO_IRQ ? chan->irq : fdev->irq); 1277173acc7cSZhang Wei 1278173acc7cSZhang Wei return 0; 127951ee87f2SLi Yang 1280e7a29151SIra Snyder out_iounmap_regs: 1281a1c03319SIra Snyder iounmap(chan->regs); 1282a1c03319SIra Snyder out_free_chan: 1283a1c03319SIra Snyder kfree(chan); 1284e7a29151SIra Snyder out_return: 1285173acc7cSZhang Wei return err; 1286173acc7cSZhang Wei } 1287173acc7cSZhang Wei 1288a1c03319SIra Snyder static void fsl_dma_chan_remove(struct fsldma_chan *chan) 1289173acc7cSZhang Wei { 1290a1c03319SIra Snyder irq_dispose_mapping(chan->irq); 1291a1c03319SIra Snyder list_del(&chan->common.device_node); 1292a1c03319SIra Snyder iounmap(chan->regs); 1293a1c03319SIra Snyder kfree(chan); 1294173acc7cSZhang Wei } 1295173acc7cSZhang Wei 12962dc11581SGrant Likely static int __devinit fsldma_of_probe(struct platform_device *op, 1297173acc7cSZhang Wei const struct of_device_id *match) 1298173acc7cSZhang Wei { 1299a4f56d4bSIra Snyder struct fsldma_device *fdev; 130077cd62e8STimur Tabi struct device_node *child; 1301e7a29151SIra Snyder int err; 1302173acc7cSZhang Wei 1303a4f56d4bSIra Snyder fdev = kzalloc(sizeof(*fdev), GFP_KERNEL); 1304173acc7cSZhang Wei if (!fdev) { 1305e7a29151SIra Snyder dev_err(&op->dev, "No enough memory for 'priv'\n"); 1306e7a29151SIra Snyder err = -ENOMEM; 1307e7a29151SIra Snyder goto out_return; 1308173acc7cSZhang Wei } 1309e7a29151SIra Snyder 1310e7a29151SIra Snyder fdev->dev = &op->dev; 1311173acc7cSZhang Wei INIT_LIST_HEAD(&fdev->common.channels); 1312173acc7cSZhang Wei 1313e7a29151SIra Snyder /* ioremap the registers for use */ 131461c7a080SGrant Likely fdev->regs = of_iomap(op->dev.of_node, 0); 1315e7a29151SIra Snyder if (!fdev->regs) { 1316e7a29151SIra Snyder dev_err(&op->dev, "unable to ioremap registers\n"); 1317e7a29151SIra Snyder err = -ENOMEM; 1318e7a29151SIra Snyder goto out_free_fdev; 1319173acc7cSZhang Wei } 1320173acc7cSZhang Wei 1321d3f620b2SIra Snyder /* map the channel IRQ if it exists, but don't hookup the handler yet */ 132261c7a080SGrant Likely fdev->irq = irq_of_parse_and_map(op->dev.of_node, 0); 1323d3f620b2SIra Snyder 1324173acc7cSZhang Wei dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); 1325173acc7cSZhang Wei dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); 1326c1433041SIra Snyder dma_cap_set(DMA_SG, fdev->common.cap_mask); 1327bbea0b6eSIra Snyder dma_cap_set(DMA_SLAVE, fdev->common.cap_mask); 1328173acc7cSZhang Wei fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; 1329173acc7cSZhang Wei fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; 13302187c269SZhang Wei fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt; 1331173acc7cSZhang Wei fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; 1332c1433041SIra Snyder fdev->common.device_prep_dma_sg = fsl_dma_prep_sg; 133307934481SLinus Walleij fdev->common.device_tx_status = fsl_tx_status; 1334173acc7cSZhang Wei fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; 1335bbea0b6eSIra Snyder fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg; 1336c3635c78SLinus Walleij fdev->common.device_control = fsl_dma_device_control; 1337e7a29151SIra Snyder fdev->common.dev = &op->dev; 1338173acc7cSZhang Wei 1339e2c8e425SLi Yang dma_set_mask(&(op->dev), DMA_BIT_MASK(36)); 1340e2c8e425SLi Yang 1341e7a29151SIra Snyder dev_set_drvdata(&op->dev, fdev); 134277cd62e8STimur Tabi 1343e7a29151SIra Snyder /* 1344e7a29151SIra Snyder * We cannot use of_platform_bus_probe() because there is no 1345e7a29151SIra Snyder * of_platform_bus_remove(). Instead, we manually instantiate every DMA 134677cd62e8STimur Tabi * channel object. 134777cd62e8STimur Tabi */ 134861c7a080SGrant Likely for_each_child_of_node(op->dev.of_node, child) { 1349e7a29151SIra Snyder if (of_device_is_compatible(child, "fsl,eloplus-dma-channel")) { 135077cd62e8STimur Tabi fsl_dma_chan_probe(fdev, child, 135177cd62e8STimur Tabi FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN, 135277cd62e8STimur Tabi "fsl,eloplus-dma-channel"); 1353e7a29151SIra Snyder } 1354e7a29151SIra Snyder 1355e7a29151SIra Snyder if (of_device_is_compatible(child, "fsl,elo-dma-channel")) { 135677cd62e8STimur Tabi fsl_dma_chan_probe(fdev, child, 135777cd62e8STimur Tabi FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN, 135877cd62e8STimur Tabi "fsl,elo-dma-channel"); 135977cd62e8STimur Tabi } 1360e7a29151SIra Snyder } 1361173acc7cSZhang Wei 1362d3f620b2SIra Snyder /* 1363d3f620b2SIra Snyder * Hookup the IRQ handler(s) 1364d3f620b2SIra Snyder * 1365d3f620b2SIra Snyder * If we have a per-controller interrupt, we prefer that to the 1366d3f620b2SIra Snyder * per-channel interrupts to reduce the number of shared interrupt 1367d3f620b2SIra Snyder * handlers on the same IRQ line 1368d3f620b2SIra Snyder */ 1369d3f620b2SIra Snyder err = fsldma_request_irqs(fdev); 1370d3f620b2SIra Snyder if (err) { 1371d3f620b2SIra Snyder dev_err(fdev->dev, "unable to request IRQs\n"); 1372d3f620b2SIra Snyder goto out_free_fdev; 1373d3f620b2SIra Snyder } 1374d3f620b2SIra Snyder 1375173acc7cSZhang Wei dma_async_device_register(&fdev->common); 1376173acc7cSZhang Wei return 0; 1377173acc7cSZhang Wei 1378e7a29151SIra Snyder out_free_fdev: 1379d3f620b2SIra Snyder irq_dispose_mapping(fdev->irq); 1380173acc7cSZhang Wei kfree(fdev); 1381e7a29151SIra Snyder out_return: 1382173acc7cSZhang Wei return err; 1383173acc7cSZhang Wei } 1384173acc7cSZhang Wei 13852dc11581SGrant Likely static int fsldma_of_remove(struct platform_device *op) 138677cd62e8STimur Tabi { 1387a4f56d4bSIra Snyder struct fsldma_device *fdev; 138877cd62e8STimur Tabi unsigned int i; 138977cd62e8STimur Tabi 1390e7a29151SIra Snyder fdev = dev_get_drvdata(&op->dev); 139177cd62e8STimur Tabi dma_async_device_unregister(&fdev->common); 139277cd62e8STimur Tabi 1393d3f620b2SIra Snyder fsldma_free_irqs(fdev); 1394d3f620b2SIra Snyder 1395e7a29151SIra Snyder for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { 139677cd62e8STimur Tabi if (fdev->chan[i]) 139777cd62e8STimur Tabi fsl_dma_chan_remove(fdev->chan[i]); 1398e7a29151SIra Snyder } 139977cd62e8STimur Tabi 1400e7a29151SIra Snyder iounmap(fdev->regs); 1401e7a29151SIra Snyder dev_set_drvdata(&op->dev, NULL); 140277cd62e8STimur Tabi kfree(fdev); 140377cd62e8STimur Tabi 140477cd62e8STimur Tabi return 0; 140577cd62e8STimur Tabi } 140677cd62e8STimur Tabi 14074b1cf1faSMárton Németh static const struct of_device_id fsldma_of_ids[] = { 1408049c9d45SKumar Gala { .compatible = "fsl,eloplus-dma", }, 1409049c9d45SKumar Gala { .compatible = "fsl,elo-dma", }, 1410173acc7cSZhang Wei {} 1411173acc7cSZhang Wei }; 1412173acc7cSZhang Wei 1413a4f56d4bSIra Snyder static struct of_platform_driver fsldma_of_driver = { 14144018294bSGrant Likely .driver = { 141577cd62e8STimur Tabi .name = "fsl-elo-dma", 14164018294bSGrant Likely .owner = THIS_MODULE, 14174018294bSGrant Likely .of_match_table = fsldma_of_ids, 14184018294bSGrant Likely }, 1419a4f56d4bSIra Snyder .probe = fsldma_of_probe, 1420a4f56d4bSIra Snyder .remove = fsldma_of_remove, 1421173acc7cSZhang Wei }; 1422173acc7cSZhang Wei 1423a4f56d4bSIra Snyder /*----------------------------------------------------------------------------*/ 1424a4f56d4bSIra Snyder /* Module Init / Exit */ 1425a4f56d4bSIra Snyder /*----------------------------------------------------------------------------*/ 1426a4f56d4bSIra Snyder 1427a4f56d4bSIra Snyder static __init int fsldma_init(void) 1428173acc7cSZhang Wei { 142977cd62e8STimur Tabi int ret; 143077cd62e8STimur Tabi 143177cd62e8STimur Tabi pr_info("Freescale Elo / Elo Plus DMA driver\n"); 143277cd62e8STimur Tabi 1433a4f56d4bSIra Snyder ret = of_register_platform_driver(&fsldma_of_driver); 143477cd62e8STimur Tabi if (ret) 143577cd62e8STimur Tabi pr_err("fsldma: failed to register platform driver\n"); 143677cd62e8STimur Tabi 143777cd62e8STimur Tabi return ret; 1438173acc7cSZhang Wei } 1439173acc7cSZhang Wei 1440a4f56d4bSIra Snyder static void __exit fsldma_exit(void) 144177cd62e8STimur Tabi { 1442a4f56d4bSIra Snyder of_unregister_platform_driver(&fsldma_of_driver); 144377cd62e8STimur Tabi } 144477cd62e8STimur Tabi 1445a4f56d4bSIra Snyder subsys_initcall(fsldma_init); 1446a4f56d4bSIra Snyder module_exit(fsldma_exit); 144777cd62e8STimur Tabi 144877cd62e8STimur Tabi MODULE_DESCRIPTION("Freescale Elo / Elo Plus DMA driver"); 144977cd62e8STimur Tabi MODULE_LICENSE("GPL"); 1450