On Mon, Jan 13, 2014 at 10:31:01AM +0000, Shevchenko, Andriy wrote:
> On Fri, 2014-01-10 at 13:07 -0600, Andy Gross wrote:
> > Add the DMA engine driver for the QCOM Bus Access Manager (BAM) DMA 
> > controller
> > found in the MSM 8x74 platforms.
> > 
> > Each BAM DMA device is associated with a specific on-chip peripheral.  Each
> > channel provides a uni-directional data transfer engine that is capable of
> > transferring data between the peripheral and system memory (System mode), or
> > between two peripherals (BAM2BAM).
> > 
> > The initial release of this driver only supports slave transfers between
> > peripherals and system memory.
> > 
> > Signed-off-by: Andy Gross <[email protected]>
> > ---
> >  drivers/dma/Kconfig        |   9 +
> >  drivers/dma/Makefile       |   1 +
> >  drivers/dma/qcom_bam_dma.c | 843 
> > +++++++++++++++++++++++++++++++++++++++++++++
> >  drivers/dma/qcom_bam_dma.h | 268 ++++++++++++++
> >  4 files changed, 1121 insertions(+)
> >  create mode 100644 drivers/dma/qcom_bam_dma.c
> >  create mode 100644 drivers/dma/qcom_bam_dma.h
> > 
[...]
> > + * bam_tx_status - returns status of transaction
> > + * @chan: dma channel
> > + * @cookie: transaction cookie
> > + * @txstate: DMA transaction state
> > + *
> > + * Return status of dma transaction
> > + */
> > +static enum dma_status bam_tx_status(struct dma_chan *chan, dma_cookie_t 
> > cookie,
> > +           struct dma_tx_state *txstate)
> > +{
> > +   struct bam_chan *bchan = to_bam_chan(chan);
> > +   struct virt_dma_desc *vd;
> > +   int ret;
> > +   size_t residue = 0;
> > +   unsigned int i;
> > +   unsigned long flags;
> > +
> > +   ret = dma_cookie_status(chan, cookie, txstate);
> > +
> 
> Redundant empty line.
> 

Will remove.

> > +   if (ret == DMA_COMPLETE)
> > +           return ret;
> > +
> > +   if (!txstate)
> > +           return bchan->paused ? DMA_PAUSED : ret;
> > +
> > +   spin_lock_irqsave(&bchan->vc.lock, flags);
> > +   vd = vchan_find_desc(&bchan->vc, cookie);
> > +   if (vd)
> > +           residue = container_of(vd, struct bam_async_desc, vd)->length;
> > +   else if (bchan->curr_txd && bchan->curr_txd->vd.tx.cookie == cookie)
> > +           for (i = 0; i < bchan->curr_txd->num_desc; i++)
> > +                   residue += bchan->curr_txd->curr_desc[i].size;
> > +
> > +   dma_set_residue(txstate, residue);
> 
> I'm pretty sure you could do this outside of spin lock.
> 

Yes, I'll move it.

> > +
> > +   spin_unlock_irqrestore(&bchan->vc.lock, flags);
> > +
> > +   if (ret == DMA_IN_PROGRESS && bchan->paused)
> > +           ret = DMA_PAUSED;
> > +
> > +   return ret;
> > +}
> > +
> > +/**
> > + * bam_start_dma - start next transaction
> > + * @bchan - bam dma channel
> > + *
> > + * Note: must hold bam dma channel vc.lock
> > + */
> > +static void bam_start_dma(struct bam_chan *bchan)
> > +{
> > +   struct virt_dma_desc *vd = vchan_next_desc(&bchan->vc);
> > +   struct bam_device *bdev = bchan->bdev;
> > +   struct bam_async_desc *async_desc;
> > +   struct bam_desc_hw *desc;
> > +   struct bam_desc_hw *fifo = PTR_ALIGN(bchan->fifo_virt,
> > +                           sizeof(struct bam_desc_hw));
> 
> > +
> > +   if (!vd)
> > +           return;
> > +
> > +   list_del(&vd->node);
> > +
> > +   async_desc = container_of(vd, struct bam_async_desc, vd);
> > +   bchan->curr_txd = async_desc;
> > +
> > +   desc = bchan->curr_txd->curr_desc;
> > +
> > +   if (async_desc->num_desc > MAX_DESCRIPTORS)
> > +           async_desc->xfer_len = MAX_DESCRIPTORS;
> > +   else
> > +           async_desc->xfer_len = async_desc->num_desc;
> > +
> > +   /* set INT on last descriptor */
> > +   desc[async_desc->xfer_len - 1].flags |= DESC_FLAG_INT;
> > +
> > +   if (bchan->tail + async_desc->xfer_len > MAX_DESCRIPTORS) {
> > +           u32 partial = MAX_DESCRIPTORS - bchan->tail;
> > +
> > +           memcpy(&fifo[bchan->tail], desc,
> > +                           partial * sizeof(struct bam_desc_hw));
> > +           memcpy(fifo, &desc[partial], (async_desc->xfer_len - partial) *
> > +                           sizeof(struct bam_desc_hw));
> 
> I'm just curious if you could avoid memcpys at all somehow.
> 

Unfortunately not.  The descriptors have to be copied into the FIFO memory that
is being used by the dma controller for this channel.  Due to the way the FIFO
works, I have to copy into the FIFO during either the issue_pending or when I
start the next transaction.  Either way, it means copying from the txd to the
FIFO.

> > +   } else
> 
> Keep style
> 

OK.

> } else {
> ...
> }
> 
> Have you run checkpatch.pl?
> 

Yes. And I fixed any discrepancies before sending this.

> > +           memcpy(&fifo[bchan->tail], desc,
> > +                   async_desc->xfer_len * sizeof(struct bam_desc_hw));
> > +
> > +   bchan->tail += async_desc->xfer_len;
> > +   bchan->tail %= MAX_DESCRIPTORS;
> > +
> > +   /* ensure descriptor writes and dma start not reordered */
> > +   wmb();
> > +   writel_relaxed(bchan->tail * sizeof(struct bam_desc_hw),
> > +                   bdev->regs + BAM_P_EVNT_REG(bchan->id));
> > +}
> > +
> > +/**
> > + * dma_tasklet - DMA IRQ tasklet
> > + * @data: tasklet argument (bam controller structure)
> > + *
> > + * Sets up next DMA operation and then processes all completed transactions
> > + */
> > +static void dma_tasklet(unsigned long data)
> > +{
> > +   struct bam_device *bdev = (struct bam_device *)data;
> > +   struct bam_chan *bchan;
> > +   unsigned long flags;
> > +   unsigned int i;
> > +
> > +   /* go through the channels and kick off transactions */
> > +   for (i = 0; i < bdev->num_channels; i++) {
> > +           bchan = &bdev->channels[i];
> > +           spin_lock_irqsave(&bchan->vc.lock, flags);
> > +
> > +           if (!list_empty(&bchan->vc.desc_issued) && !bchan->curr_txd)
> > +                   bam_start_dma(bchan);
> > +           spin_unlock_irqrestore(&bchan->vc.lock, flags);
> > +   }
> > +}
> > +
> > +/**
> > + * bam_issue_pending - starts pending transactions
> > + * @chan: dma channel
> > + *
> > + * Calls tasklet directly which in turn starts any pending transactions
> > + */
> > +static void bam_issue_pending(struct dma_chan *chan)
> > +{
> > +   struct bam_chan *bchan = to_bam_chan(chan);
> > +   unsigned long flags;
> > +
> > +   spin_lock_irqsave(&bchan->vc.lock, flags);
> > +
> > +   /* if work pending and idle, start a transaction */
> > +   if (vchan_issue_pending(&bchan->vc) && !bchan->curr_txd)
> > +           bam_start_dma(bchan);
> > +
> > +   spin_unlock_irqrestore(&bchan->vc.lock, flags);
> > +}
> > +
> > +/**
> > + * bam_dma_free_desc - free descriptor memory
> > + * @vd: virtual descriptor
> > + *
> > + */
> > +static void bam_dma_free_desc(struct virt_dma_desc *vd)
> > +{
> > +   struct bam_async_desc *async_desc = container_of(vd,
> > +                   struct bam_async_desc, vd);
> > +
> > +   kfree(async_desc);
> > +}
> > +
> > +struct bam_filter_args {
> > +   struct dma_device *dev;
> > +   u32 id;
> > +   u32 ee;
> > +   u32 dir;
> > +};
> > +
> > +static bool bam_dma_filter(struct dma_chan *chan, void *data)
> > +{
> > +   struct bam_filter_args *args = data;
> > +   struct bam_chan *bchan = to_bam_chan(chan);
> > +
> > +   if (args->dev == chan->device &&
> > +           args->id == bchan->id) {
> > +
> > +           /* we found the channel, so lets set the EE and dir */
> > +           bchan->ee = args->ee;
> > +           bchan->slave.direction = args->dir ?
> > +                           DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
> > +           return true;
> > +   }
> > +
> > +   return false;
> > +}
> > +
> > +static struct dma_chan *bam_dma_xlate(struct of_phandle_args *dma_spec,
> > +           struct of_dma *of)
> > +{
> > +   struct bam_filter_args args;
> > +   dma_cap_mask_t cap;
> > +
> > +   if (dma_spec->args_count != 3)
> > +           return NULL;
> > +
> > +   args.dev = of->of_dma_data;
> > +   args.id = dma_spec->args[0];
> > +   args.ee = dma_spec->args[1];
> > +   args.dir = dma_spec->args[2];
> > +
> > +   dma_cap_zero(cap);
> > +   dma_cap_set(DMA_SLAVE, cap);
> > +
> > +   return dma_request_channel(cap, bam_dma_filter, &args);
> > +}
> > +
> > +/**
> > + * bam_init
> > + * @bdev: bam device
> > + *
> > + * Initialization helper for global bam registers
> > + */
> > +static void bam_init(struct bam_device *bdev)
> > +{
> > +   u32 val;
> > +
> > +   /* read versioning information */
> > +   val = readl_relaxed(bdev->regs + BAM_REVISION);
> > +   bdev->num_ees = val & NUM_EES_MASK;
> > +
> > +   val = readl_relaxed(bdev->regs + BAM_NUM_PIPES);
> > +   bdev->num_channels = val & BAM_NUM_PIPES_MASK;
> > +
> > +   /* s/w reset bam */
> > +   /* after reset all pipes are disabled and idle */
> > +   val = readl_relaxed(bdev->regs + BAM_CTRL);
> > +   val |= BAM_SW_RST;
> > +   writel_relaxed(val, bdev->regs + BAM_CTRL);
> > +   val &= ~BAM_SW_RST;
> > +   writel_relaxed(val, bdev->regs + BAM_CTRL);
> > +
> > +   /* make sure previous stores are visible before enabling BAM */
> > +   wmb();
> > +
> > +   /* enable bam */
> > +   val |= BAM_EN;
> > +   writel_relaxed(val, bdev->regs + BAM_CTRL);
> > +
> > +   /* set descriptor threshhold, start with 4 bytes */
> > +   writel_relaxed(DEFAULT_CNT_THRSHLD, bdev->regs + BAM_DESC_CNT_TRSHLD);
> > +
> > +   /* Enable default set of h/w workarounds, ie all except BAM_FULL_PIPE */
> > +   writel_relaxed(BAM_CNFG_BITS_DEFAULT, bdev->regs + BAM_CNFG_BITS);
> > +
> > +   /* enable irqs for errors */
> > +   writel_relaxed(BAM_ERROR_EN | BAM_HRESP_ERR_EN,
> > +                           bdev->regs + BAM_IRQ_EN);
> > +}
> > +
> > +static void bam_channel_init(struct bam_device *bdev, struct bam_chan 
> > *bchan,
> > +   u32 index)
> > +{
> > +   bchan->id = index;
> > +   bchan->bdev = bdev;
> > +
> > +   vchan_init(&bchan->vc, &bdev->common);
> > +   bchan->vc.desc_free = bam_dma_free_desc;
> > +
> > +   bam_reset_channel(bdev, bchan->id);
> > +}
> > +
> > +static int bam_dma_probe(struct platform_device *pdev)
> > +{
> > +   struct bam_device *bdev;
> > +   struct resource *iores, *irq_res;
> > +   int ret, i;
> > +
> > +   bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
> > +   if (!bdev)
> > +           return -ENOMEM;
> > +
> > +   bdev->dev = &pdev->dev;
> > +
> > +   iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +   if (!iores) {
> > +           dev_err(bdev->dev, "register resource is missing\n");
> > +           return -EINVAL;
> > +   }
> 
> Useless check and messaging, devm_ioremap_resource will do this for you.
> 

Will fix this along with the other resource comment.

> > +
> > +   bdev->regs = devm_ioremap_resource(&pdev->dev, iores);
> > +   if (IS_ERR(bdev->regs))
> > +           return PTR_ERR(bdev->regs);
> > +
> > +   irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> > +   if (!irq_res) {
> > +           dev_err(bdev->dev, "irq resource is missing\n");
> > +           return -EINVAL;
> > +   }
> > +
> > +   bdev->bamclk = devm_clk_get(bdev->dev, "bam_clk");
> > +   if (IS_ERR(bdev->bamclk))
> > +           return PTR_ERR(bdev->bamclk);
> > +
> > +   ret = clk_prepare_enable(bdev->bamclk);
> > +   if (ret) {
> > +           dev_err(bdev->dev, "failed to prepare/enable clock");
> > +           return ret;
> > +   }
> > +
> > +   bam_init(bdev);
> > +
> > +   tasklet_init(&bdev->task, dma_tasklet, (unsigned long)bdev);
> > +
> > +   bdev->channels = devm_kzalloc(bdev->dev,
> 
> devm_kcalloc.
> 

Will fix.

> > +                           sizeof(*bdev->channels) * bdev->num_channels,
> > +                           GFP_KERNEL);
> > +
> > +   if (!bdev->channels) {
> > +           ret = -ENOMEM;
> > +           goto err_disable_clk;
> > +   }
> > +
> > +   /* allocate and initialize channels */
> > +   INIT_LIST_HEAD(&bdev->common.channels);
> > +
> > +   for (i = 0; i < bdev->num_channels; i++)
> > +           bam_channel_init(bdev, &bdev->channels[i], i);
> > +
> > +   ret = devm_request_irq(bdev->dev, irq_res->start, bam_dma_irq,
> > +                   IRQF_TRIGGER_HIGH, "bam_dma", bdev);
> > +   if (ret) {
> > +           dev_err(bdev->dev, "cannot register IRQ\n");
> > +           goto err_disable_clk;
> > +   }
> > +
> > +   /* set max dma segment size */
> > +   bdev->common.dev = bdev->dev;
> > +   bdev->common.dev->dma_parms = &bdev->dma_parms;
> > +   ret = dma_set_max_seg_size(bdev->common.dev, BAM_MAX_DATA_SIZE);
> > +   if (ret) {
> > +           dev_err(bdev->dev, "cannot set maximum segment size\n");
> > +           goto err_disable_clk;
> > +   }
> > +
> > +   platform_set_drvdata(pdev, bdev);
> > +
> > +   /* set capabilities */
> > +   dma_cap_zero(bdev->common.cap_mask);
> > +   dma_cap_set(DMA_SLAVE, bdev->common.cap_mask);
> > +
> > +   /* initialize dmaengine apis */
> > +   bdev->common.device_alloc_chan_resources = bam_alloc_chan;
> > +   bdev->common.device_free_chan_resources = bam_free_chan;
> > +   bdev->common.device_prep_slave_sg = bam_prep_slave_sg;
> > +   bdev->common.device_control = bam_control;
> > +   bdev->common.device_issue_pending = bam_issue_pending;
> > +   bdev->common.device_tx_status = bam_tx_status;
> > +   bdev->common.dev = bdev->dev;
> > +
> > +   ret = dma_async_device_register(&bdev->common);
> > +   if (ret) {
> > +           dev_err(bdev->dev, "failed to register dma async device\n");
> > +           goto err_disable_clk;
> > +   }
> > +
> > +   if (pdev->dev.of_node) {
> > +           ret = of_dma_controller_register(pdev->dev.of_node,
> > +                           bam_dma_xlate, &bdev->common);
> > +
> > +           if (ret) {
> > +                   dev_err(bdev->dev, "failed to register of_dma\n");
> > +                   goto err_unregister_dma;
> > +           }
> > +   }
> > +
> > +   return 0;
> > +
> > +err_unregister_dma:
> > +   dma_async_device_unregister(&bdev->common);
> > +err_disable_clk:
> > +   clk_disable_unprepare(bdev->bamclk);
> 
> 
> 
> > +   return ret;
> > +}
> > +
> > +static int bam_dma_remove(struct platform_device *pdev)
> > +{
> > +   struct bam_device *bdev = platform_get_drvdata(pdev);
> > +
> > +   dma_async_device_unregister(&bdev->common);
> > +
> > +   if (pdev->dev.of_node)
> > +           of_dma_controller_free(pdev->dev.of_node);
> > +
> > +   clk_disable_unprepare(bdev->bamclk);
> > +
> > +   return 0;
> > +}
> > +
> > +#ifdef CONFIG_OF
> > +static const struct of_device_id bam_of_match[] = {
> > +   { .compatible = "qcom,bam-v1.4.0", },
> > +   { .compatible = "qcom,bam-v1.4.1", },
> > +   {}
> > +};
> > +MODULE_DEVICE_TABLE(of, bam_of_match);
> > +#endif
> > +
> > +static struct platform_driver bam_dma_driver = {
> > +   .probe = bam_dma_probe,
> > +   .remove = bam_dma_remove,
> > +   .driver = {
> > +           .name = "bam-dma-engine",
> > +           .owner = THIS_MODULE,
> > +           .of_match_table = of_match_ptr(bam_of_match),
> > +   },
> > +};
> > +
> > +static int __init bam_dma_init(void)
> > +{
> > +   return platform_driver_register(&bam_dma_driver);
> > +}
> > +
> > +static void __exit bam_dma_exit(void)
> > +{
> > +   return platform_driver_unregister(&bam_dma_driver);
> > +}
> > +
> > +module_init(bam_dma_init);
> > +module_exit(bam_dma_exit);
> 
> module_platform_driver() ?
> 

Will fix.

> > +
> > +MODULE_AUTHOR("Andy Gross <[email protected]>");
> > +MODULE_DESCRIPTION("QCOM BAM DMA engine driver");
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/drivers/dma/qcom_bam_dma.h b/drivers/dma/qcom_bam_dma.h
> > new file mode 100644
> > index 0000000..2cb3b5f
> > --- /dev/null
> > +++ b/drivers/dma/qcom_bam_dma.h
> > @@ -0,0 +1,268 @@
> > +/*
> > + * Copyright (c) 2013, The Linux Foundation. All rights reserved.
> 
> 2014 ?
> 

Should probably be 2013-2014 since development has spanned the change in year.

> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 and
> > + * only version 2 as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +#ifndef __QCOM_BAM_DMA_H__
> > +#define __QCOM_BAM_DMA_H__
> > +
> > +#include <linux/dmaengine.h>
> > +#include "virt-dma.h"
> > +
> > +enum bam_channel_dir {
> > +   BAM_PIPE_CONSUMER = 0,  /* channel reads from data-fifo or memory */
> > +   BAM_PIPE_PRODUCER,      /* channel writes to data-fifo or memory */
> > +};
> > +
> > +struct bam_desc_hw {
> > +   u32 addr;               /* Buffer physical address */
> > +   u16 size;               /* Buffer size in bytes */
> > +   u16 flags;
> > +} __packed;
> > +
> > +#define DESC_FLAG_INT      BIT(15)
> > +#define DESC_FLAG_EOT      BIT(14)
> > +#define DESC_FLAG_EOB      BIT(13)
> > +
> > +struct bam_async_desc {
> > +   struct virt_dma_desc vd;
> > +
> > +   u32 num_desc;
> > +   u32 xfer_len;
> > +   struct bam_desc_hw *curr_desc;
> > +
> > +   enum bam_channel_dir dir;
> > +   size_t length;
> > +   struct bam_desc_hw desc[0];
> > +};
> > +
> > +#define BAM_CTRL                   0x0000
> > +#define BAM_REVISION                       0x0004
> > +#define BAM_SW_REVISION                    0x0080
> > +#define BAM_NUM_PIPES                      0x003C
> > +#define BAM_TIMER                  0x0040
> > +#define BAM_TIMER_CTRL                     0x0044
> > +#define BAM_DESC_CNT_TRSHLD                0x0008
> > +#define BAM_IRQ_SRCS                       0x000C
> > +#define BAM_IRQ_SRCS_MSK           0x0010
> > +#define BAM_IRQ_SRCS_UNMASKED              0x0030
> > +#define BAM_IRQ_STTS                       0x0014
> > +#define BAM_IRQ_CLR                        0x0018
> > +#define BAM_IRQ_EN                 0x001C
> > +#define BAM_CNFG_BITS                      0x007C
> > +#define BAM_IRQ_SRCS_EE(pipe)              (0x0800 + ((pipe) * 0x80))
> > +#define BAM_IRQ_SRCS_MSK_EE(pipe)  (0x0804 + ((pipe) * 0x80))
> > +#define BAM_P_CTRL(pipe)           (0x1000 + ((pipe) * 0x1000))
> > +#define BAM_P_RST(pipe)                    (0x1004 + ((pipe) * 0x1000))
> > +#define BAM_P_HALT(pipe)           (0x1008 + ((pipe) * 0x1000))
> > +#define BAM_P_IRQ_STTS(pipe)               (0x1010 + ((pipe) * 0x1000))
> > +#define BAM_P_IRQ_CLR(pipe)                (0x1014 + ((pipe) * 0x1000))
> > +#define BAM_P_IRQ_EN(pipe)         (0x1018 + ((pipe) * 0x1000))
> > +#define BAM_P_EVNT_DEST_ADDR(pipe) (0x182C + ((pipe) * 0x1000))
> > +#define BAM_P_EVNT_REG(pipe)               (0x1818 + ((pipe) * 0x1000))
> > +#define BAM_P_SW_OFSTS(pipe)               (0x1800 + ((pipe) * 0x1000))
> > +#define BAM_P_DATA_FIFO_ADDR(pipe) (0x1824 + ((pipe) * 0x1000))
> > +#define BAM_P_DESC_FIFO_ADDR(pipe) (0x181C + ((pipe) * 0x1000))
> > +#define BAM_P_EVNT_TRSHLD(pipe)            (0x1828 + ((pipe) * 0x1000))
> > +#define BAM_P_FIFO_SIZES(pipe)             (0x1820 + ((pipe) * 0x1000))
> > +
> > +/* BAM CTRL */
> > +#define BAM_SW_RST                 BIT(0)
> > +#define BAM_EN                             BIT(1)
> > +#define BAM_EN_ACCUM                       BIT(4)
> > +#define BAM_TESTBUS_SEL_SHIFT              5
> > +#define BAM_TESTBUS_SEL_MASK               0x3F
> > +#define BAM_DESC_CACHE_SEL_SHIFT   13
> > +#define BAM_DESC_CACHE_SEL_MASK            0x3
> > +#define BAM_CACHED_DESC_STORE              BIT(15)
> > +#define IBC_DISABLE                        BIT(16)
> > +
> > +/* BAM REVISION */
> > +#define REVISION_SHIFT             0
> > +#define REVISION_MASK              0xFF
> > +#define NUM_EES_SHIFT              8
> > +#define NUM_EES_MASK               0xF
> > +#define CE_BUFFER_SIZE             BIT(13)
> > +#define AXI_ACTIVE         BIT(14)
> > +#define USE_VMIDMT         BIT(15)
> > +#define SECURED                    BIT(16)
> > +#define BAM_HAS_NO_BYPASS  BIT(17)
> > +#define HIGH_FREQUENCY_BAM BIT(18)
> > +#define INACTIV_TMRS_EXST  BIT(19)
> > +#define NUM_INACTIV_TMRS   BIT(20)
> > +#define DESC_CACHE_DEPTH_SHIFT     21
> > +#define DESC_CACHE_DEPTH_1 (0 << DESC_CACHE_DEPTH_SHIFT)
> > +#define DESC_CACHE_DEPTH_2 (1 << DESC_CACHE_DEPTH_SHIFT)
> > +#define DESC_CACHE_DEPTH_3 (2 << DESC_CACHE_DEPTH_SHIFT)
> > +#define DESC_CACHE_DEPTH_4 (3 << DESC_CACHE_DEPTH_SHIFT)
> > +#define CMD_DESC_EN                BIT(23)
> > +#define INACTIV_TMR_BASE_SHIFT     24
> > +#define INACTIV_TMR_BASE_MASK      0xFF
> > +
> > +/* BAM NUM PIPES */
> > +#define BAM_NUM_PIPES_SHIFT                0
> > +#define BAM_NUM_PIPES_MASK         0xFF
> > +#define PERIPH_NON_PIPE_GRP_SHIFT  16
> > +#define PERIPH_NON_PIP_GRP_MASK            0xFF
> > +#define BAM_NON_PIPE_GRP_SHIFT             24
> > +#define BAM_NON_PIPE_GRP_MASK              0xFF
> > +
> > +/* BAM CNFG BITS */
> > +#define BAM_PIPE_CNFG              BIT(2)
> > +#define BAM_FULL_PIPE              BIT(11)
> > +#define BAM_NO_EXT_P_RST   BIT(12)
> > +#define BAM_IBC_DISABLE            BIT(13)
> > +#define BAM_SB_CLK_REQ             BIT(14)
> > +#define BAM_PSM_CSW_REQ            BIT(15)
> > +#define BAM_PSM_P_RES              BIT(16)
> > +#define BAM_AU_P_RES               BIT(17)
> > +#define BAM_SI_P_RES               BIT(18)
> > +#define BAM_WB_P_RES               BIT(19)
> > +#define BAM_WB_BLK_CSW             BIT(20)
> > +#define BAM_WB_CSW_ACK_IDL BIT(21)
> > +#define BAM_WB_RETR_SVPNT  BIT(22)
> > +#define BAM_WB_DSC_AVL_P_RST       BIT(23)
> > +#define BAM_REG_P_EN               BIT(24)
> > +#define BAM_PSM_P_HD_DATA  BIT(25)
> > +#define BAM_AU_ACCUMED             BIT(26)
> > +#define BAM_CMD_ENABLE             BIT(27)
> > +
> > +#define BAM_CNFG_BITS_DEFAULT      (BAM_PIPE_CNFG |        \
> > +                   BAM_NO_EXT_P_RST |              \
> > +                   BAM_IBC_DISABLE |               \
> > +                   BAM_SB_CLK_REQ |                \
> > +                   BAM_PSM_CSW_REQ |               \
> > +                   BAM_PSM_P_RES |                 \
> > +                   BAM_AU_P_RES |                  \
> > +                   BAM_SI_P_RES |                  \
> > +                   BAM_WB_P_RES |                  \
> > +                   BAM_WB_BLK_CSW |                \
> > +                   BAM_WB_CSW_ACK_IDL |            \
> > +                   BAM_WB_RETR_SVPNT |             \
> > +                   BAM_WB_DSC_AVL_P_RST |          \
> > +                   BAM_REG_P_EN |                  \
> > +                   BAM_PSM_P_HD_DATA |             \
> > +                   BAM_AU_ACCUMED |                \
> > +                   BAM_CMD_ENABLE)
> > +
> > +/* PIPE CTRL */
> > +#define    P_EN                    BIT(1)
> > +#define P_DIRECTION                BIT(3)
> > +#define P_SYS_STRM         BIT(4)
> > +#define P_SYS_MODE         BIT(5)
> > +#define P_AUTO_EOB         BIT(6)
> > +#define P_AUTO_EOB_SEL_SHIFT       7
> > +#define P_AUTO_EOB_SEL_512 (0 << P_AUTO_EOB_SEL_SHIFT)
> > +#define P_AUTO_EOB_SEL_256 (1 << P_AUTO_EOB_SEL_SHIFT)
> > +#define P_AUTO_EOB_SEL_128 (2 << P_AUTO_EOB_SEL_SHIFT)
> > +#define P_AUTO_EOB_SEL_64  (3 << P_AUTO_EOB_SEL_SHIFT)
> > +#define P_PREFETCH_LIMIT_SHIFT     9
> > +#define P_PREFETCH_LIMIT_32        (0 << P_PREFETCH_LIMIT_SHIFT)
> > +#define P_PREFETCH_LIMIT_16        (1 << P_PREFETCH_LIMIT_SHIFT)
> > +#define P_PREFETCH_LIMIT_4 (2 << P_PREFETCH_LIMIT_SHIFT)
> > +#define P_WRITE_NWD                BIT(11)
> > +#define P_LOCK_GROUP_SHIFT 16
> > +#define P_LOCK_GROUP_MASK  0x1F
> > +
> > +/* BAM_DESC_CNT_TRSHLD */
> > +#define CNT_TRSHLD         0xffff
> > +#define DEFAULT_CNT_THRSHLD        0x4
> > +
> > +/* BAM_IRQ_SRCS */
> > +#define BAM_IRQ                    BIT(31)
> > +#define P_IRQ                      0x7fffffff
> > +
> > +/* BAM_IRQ_SRCS_MSK */
> > +#define BAM_IRQ_MSK                BAM_IRQ
> > +#define P_IRQ_MSK          P_IRQ
> > +
> > +/* BAM_IRQ_STTS */
> > +#define BAM_TIMER_IRQ              BIT(4)
> > +#define BAM_EMPTY_IRQ              BIT(3)
> > +#define BAM_ERROR_IRQ              BIT(2)
> > +#define BAM_HRESP_ERR_IRQ  BIT(1)
> > +
> > +/* BAM_IRQ_CLR */
> > +#define BAM_TIMER_CLR              BIT(4)
> > +#define BAM_EMPTY_CLR              BIT(3)
> > +#define BAM_ERROR_CLR              BIT(2)
> > +#define BAM_HRESP_ERR_CLR  BIT(1)
> > +
> > +/* BAM_IRQ_EN */
> > +#define BAM_TIMER_EN               BIT(4)
> > +#define BAM_EMPTY_EN               BIT(3)
> > +#define BAM_ERROR_EN               BIT(2)
> > +#define BAM_HRESP_ERR_EN   BIT(1)
> > +
> > +/* BAM_P_IRQ_EN */
> > +#define P_PRCSD_DESC_EN            BIT(0)
> > +#define P_TIMER_EN         BIT(1)
> > +#define P_WAKE_EN          BIT(2)
> > +#define P_OUT_OF_DESC_EN   BIT(3)
> > +#define P_ERR_EN           BIT(4)
> > +#define P_TRNSFR_END_EN            BIT(5)
> > +#define P_DEFAULT_IRQS_EN  (P_PRCSD_DESC_EN | P_ERR_EN | P_TRNSFR_END_EN)
> > +
> > +/* BAM_P_SW_OFSTS */
> > +#define P_SW_OFSTS_MASK            0xffff
> > +
> > +#define BAM_DESC_FIFO_SIZE SZ_32K
> > +#define MAX_DESCRIPTORS (BAM_DESC_FIFO_SIZE / sizeof(struct bam_desc_hw) - 
> > 1)
> > +#define BAM_MAX_DATA_SIZE  (SZ_32K - 8)
> > +
> > +struct bam_chan {
> > +   struct virt_dma_chan vc;
> > +
> > +   struct bam_device *bdev;
> > +
> > +   /* configuration from device tree */
> > +   u32 id;
> > +   u32 ee;
> > +
> > +   struct bam_async_desc *curr_txd;        /* current running dma */
> > +
> > +   /* runtime configuration */
> > +   struct dma_slave_config slave;
> > +
> > +   /* fifo storage */
> > +   struct bam_desc_hw *fifo_virt;
> > +   dma_addr_t fifo_phys;
> > +
> > +   /* fifo markers */
> > +   unsigned short head;            /* start of active descriptor entries */
> > +   unsigned short tail;            /* end of active descriptor entries */
> > +
> > +   unsigned int paused;            /* is the channel paused? */
> > +
> > +   struct list_head node;
> > +};
> > +
> > +static inline struct bam_chan *to_bam_chan(struct dma_chan *common)
> > +{
> > +   return container_of(common, struct bam_chan, vc.chan);
> > +}
> > +
> > +struct bam_device {
> > +   void __iomem *regs;
> > +   struct device *dev;
> > +   struct dma_device common;
> > +   struct device_dma_parameters dma_parms;
> > +   struct bam_chan *channels;
> > +   u32 num_channels;
> > +   u32 num_ees;
> > +   unsigned long enabled_ees;
> > +   int irq;
> > +   struct clk *bamclk;
> > +
> > +   /* dma start transaction tasklet */
> > +   struct tasklet_struct task;
> > +};
> > +
> > +#endif /* __QCOM_BAM_DMA_H__ */
> 
> -- 
> Andy Shevchenko <[email protected]>
> Intel Finland Oy
> ---------------------------------------------------------------------
> Intel Finland Oy
> Registered Address: PL 281, 00181 Helsinki 
> Business Identity Code: 0357606 - 4 
> Domiciled in Helsinki 
> 
> This e-mail and any attachments may contain confidential material for
> the sole use of the intended recipient(s). Any review or distribution
> by others is strictly prohibited. If you are not the intended
> recipient, please contact the sender and delete all copies.

-- 
sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to