diff --git a/drivers/dma/qcom_bam_dma.c b/drivers/dma/qcom_bam_dma.c index 7a4bbb0f80a5..9fcde852a7a4 100644 --- a/drivers/dma/qcom_bam_dma.c +++ b/drivers/dma/qcom_bam_dma.c @@ -79,35 +79,49 @@ struct bam_async_desc { 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(ee) (0x0800 + ((ee) * 0x80)) -#define BAM_IRQ_SRCS_MSK_EE(ee) (0x0804 + ((ee) * 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)) +/* Register base offset and multplier values. Use version of map as index */ +static unsigned int ctrl_offs[] = { 0xf80, 0x0 }; +static unsigned int pipe_offs[] = { 0x0, 0x1000 }; +static unsigned int ee_offs[] = { 0x1800, 0x800 }; +static unsigned int evnt_offs[] = { 0x1000, 0x1800 }; +static unsigned int pipe_mult[] = { 0x80, 0x1000 }; +static unsigned int evnt_mult[] = { 0x40, 0x1000 }; + +/* relative offset from ctrl register base */ +#define BAM_CTRL 0x00 +#define BAM_REVISION 0x04 +#define BAM_DESC_CNT_TRSHLD 0x08 +#define BAM_IRQ_SRCS 0x0C +#define BAM_IRQ_SRCS_MSK 0x10 +#define BAM_IRQ_STTS 0x14 +#define BAM_IRQ_CLR 0x18 +#define BAM_IRQ_EN 0x1C +#define BAM_IRQ_SRCS_UNMASKED 0x30 +#define BAM_NUM_PIPES 0x3c +#define BAM_TIMER 0x40 +#define BAM_TIMER_CTRL 0x44 +#define BAM_CNFG_BITS 0x7c + +/* relative offset from irq register base */ +#define BAM_IRQ_SRCS_EE 0x00 +#define BAM_IRQ_SRCS_MSK_EE 0x04 + +/* relative offset from pipe register base */ +#define BAM_P_CTRL 0x00 +#define BAM_P_RST 0x04 +#define BAM_P_HALT 0x08 +#define BAM_P_IRQ_STTS 0x10 +#define BAM_P_IRQ_CLR 0x14 +#define BAM_P_IRQ_EN 0x18 + +/* relative offset from event register base */ +#define BAM_P_SW_OFSTS 0x00 +#define BAM_P_EVNT_REG 0x18 +#define BAM_P_DESC_FIFO_ADDR 0x1C +#define BAM_P_FIFO_SIZES 0x20 +#define BAM_P_DATA_FIFO_ADDR 0x24 +#define BAM_P_EVNT_TRSHLD 0x28 +#define BAM_P_EVNT_DEST_ADDR 0x2C /* BAM CTRL */ #define BAM_SW_RST BIT(0) @@ -297,6 +311,8 @@ struct bam_device { /* execution environment ID, from DT */ u32 ee; + u32 reg_ver; + struct clk *bamclk; int irq; @@ -304,6 +320,36 @@ struct bam_device { struct tasklet_struct task; }; +static inline void __iomem *ctrl_addr(struct bam_device *bdev, u32 reg) +{ + return bdev->regs + ctrl_offs[bdev->reg_ver] + reg; +} + +static inline void __iomem *ee_addr(struct bam_device *bdev, u32 reg) +{ + u32 offset = ee_offs[bdev->reg_ver] + reg + (bdev->ee * 0x80); + + return bdev->regs + offset; +} + +static inline void __iomem *pipe_addr(struct bam_device *bdev, u32 pipe, + u32 reg) +{ + u32 offset = pipe_offs[bdev->reg_ver] + reg; + + offset += pipe_mult[bdev->reg_ver] * pipe; + return bdev->regs + offset; +} + +static inline void __iomem *evnt_addr(struct bam_device *bdev, u32 pipe, + u32 reg) +{ + u32 offset = evnt_offs[bdev->reg_ver] + reg; + + offset += evnt_mult[bdev->reg_ver] * pipe; + return bdev->regs + offset; +} + /** * bam_reset_channel - Reset individual BAM DMA channel * @bchan: bam channel @@ -317,8 +363,8 @@ static void bam_reset_channel(struct bam_chan *bchan) lockdep_assert_held(&bchan->vc.lock); /* reset channel */ - writel_relaxed(1, bdev->regs + BAM_P_RST(bchan->id)); - writel_relaxed(0, bdev->regs + BAM_P_RST(bchan->id)); + writel_relaxed(1, pipe_addr(bdev, bchan->id, BAM_P_RST)); + writel_relaxed(0, pipe_addr(bdev, bchan->id, BAM_P_RST)); /* don't allow cpu to reorder BAM register accesses done after this */ wmb(); @@ -347,17 +393,18 @@ static void bam_chan_init_hw(struct bam_chan *bchan, * because we allocated 1 more descriptor (8 bytes) than we can use */ writel_relaxed(ALIGN(bchan->fifo_phys, sizeof(struct bam_desc_hw)), - bdev->regs + BAM_P_DESC_FIFO_ADDR(bchan->id)); - writel_relaxed(BAM_DESC_FIFO_SIZE, bdev->regs + - BAM_P_FIFO_SIZES(bchan->id)); + evnt_addr(bdev, bchan->id, BAM_P_DESC_FIFO_ADDR)); + writel_relaxed(BAM_DESC_FIFO_SIZE, evnt_addr(bdev, bchan->id, + BAM_P_FIFO_SIZES)); /* enable the per pipe interrupts, enable EOT, ERR, and INT irqs */ - writel_relaxed(P_DEFAULT_IRQS_EN, bdev->regs + BAM_P_IRQ_EN(bchan->id)); + writel_relaxed(P_DEFAULT_IRQS_EN, + pipe_addr(bdev, bchan->id, BAM_P_IRQ_EN)); /* unmask the specific pipe and EE combo */ - val = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee)); + val = readl_relaxed(ee_addr(bdev, BAM_IRQ_SRCS_MSK_EE)); val |= BIT(bchan->id); - writel_relaxed(val, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee)); + writel_relaxed(val, ee_addr(bdev, BAM_IRQ_SRCS_MSK_EE)); /* don't allow cpu to reorder the channel enable done below */ wmb(); @@ -367,7 +414,7 @@ static void bam_chan_init_hw(struct bam_chan *bchan, if (dir == DMA_DEV_TO_MEM) val |= P_DIRECTION; - writel_relaxed(val, bdev->regs + BAM_P_CTRL(bchan->id)); + writel_relaxed(val, pipe_addr(bdev, bchan->id, BAM_P_CTRL)); bchan->initialized = 1; @@ -432,12 +479,12 @@ static void bam_free_chan(struct dma_chan *chan) bchan->fifo_virt = NULL; /* mask irq for pipe/channel */ - val = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee)); + val = readl_relaxed(ee_addr(bdev, BAM_IRQ_SRCS_MSK_EE)); val &= ~BIT(bchan->id); - writel_relaxed(val, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee)); + writel_relaxed(val, ee_addr(bdev, BAM_IRQ_SRCS_MSK_EE)); /* disable irq */ - writel_relaxed(0, bdev->regs + BAM_P_IRQ_EN(bchan->id)); + writel_relaxed(0, pipe_addr(bdev, bchan->id, BAM_P_IRQ_EN)); } /** @@ -583,14 +630,14 @@ static int bam_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, switch (cmd) { case DMA_PAUSE: spin_lock_irqsave(&bchan->vc.lock, flag); - writel_relaxed(1, bdev->regs + BAM_P_HALT(bchan->id)); + writel_relaxed(1, pipe_addr(bdev, bchan->id, BAM_P_HALT)); bchan->paused = 1; spin_unlock_irqrestore(&bchan->vc.lock, flag); break; case DMA_RESUME: spin_lock_irqsave(&bchan->vc.lock, flag); - writel_relaxed(0, bdev->regs + BAM_P_HALT(bchan->id)); + writel_relaxed(0, pipe_addr(bdev, bchan->id, BAM_P_HALT)); bchan->paused = 0; spin_unlock_irqrestore(&bchan->vc.lock, flag); break; @@ -626,7 +673,7 @@ static u32 process_channel_irqs(struct bam_device *bdev) unsigned long flags; struct bam_async_desc *async_desc; - srcs = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_EE(bdev->ee)); + srcs = readl_relaxed(ee_addr(bdev, BAM_IRQ_SRCS_EE)); /* return early if no pipe/channel interrupts are present */ if (!(srcs & P_IRQ)) @@ -639,11 +686,9 @@ static u32 process_channel_irqs(struct bam_device *bdev) continue; /* clear pipe irq */ - pipe_stts = readl_relaxed(bdev->regs + - BAM_P_IRQ_STTS(i)); + pipe_stts = readl_relaxed(pipe_addr(bdev, i, BAM_P_IRQ_STTS)); - writel_relaxed(pipe_stts, bdev->regs + - BAM_P_IRQ_CLR(i)); + writel_relaxed(pipe_stts, pipe_addr(bdev, i, BAM_P_IRQ_CLR)); spin_lock_irqsave(&bchan->vc.lock, flags); async_desc = bchan->curr_txd; @@ -694,12 +739,12 @@ static irqreturn_t bam_dma_irq(int irq, void *data) tasklet_schedule(&bdev->task); if (srcs & BAM_IRQ) - clr_mask = readl_relaxed(bdev->regs + BAM_IRQ_STTS); + clr_mask = readl_relaxed(ctrl_addr(bdev, BAM_IRQ_STTS)); /* don't allow reorder of the various accesses to the BAM registers */ mb(); - writel_relaxed(clr_mask, bdev->regs + BAM_IRQ_CLR); + writel_relaxed(clr_mask, ctrl_addr(bdev, BAM_IRQ_CLR)); return IRQ_HANDLED; } @@ -763,7 +808,7 @@ static void bam_apply_new_config(struct bam_chan *bchan, else maxburst = bchan->slave.dst_maxburst; - writel_relaxed(maxburst, bdev->regs + BAM_DESC_CNT_TRSHLD); + writel_relaxed(maxburst, ctrl_addr(bdev, BAM_DESC_CNT_TRSHLD)); bchan->reconfigure = 0; } @@ -830,7 +875,7 @@ static void bam_start_dma(struct bam_chan *bchan) /* 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)); + evnt_addr(bdev, bchan->id, BAM_P_EVNT_REG)); } /** @@ -918,43 +963,45 @@ static int bam_init(struct bam_device *bdev) u32 val; /* read revision and configuration information */ - val = readl_relaxed(bdev->regs + BAM_REVISION) >> NUM_EES_SHIFT; + val = readl_relaxed(ctrl_addr(bdev, BAM_REVISION)) >> NUM_EES_SHIFT; val &= NUM_EES_MASK; /* check that configured EE is within range */ if (bdev->ee >= val) return -EINVAL; - val = readl_relaxed(bdev->regs + BAM_NUM_PIPES); + val = readl_relaxed(ctrl_addr(bdev, 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 = readl_relaxed(ctrl_addr(bdev, BAM_CTRL)); val |= BAM_SW_RST; - writel_relaxed(val, bdev->regs + BAM_CTRL); + writel_relaxed(val, ctrl_addr(bdev, BAM_CTRL)); val &= ~BAM_SW_RST; - writel_relaxed(val, bdev->regs + BAM_CTRL); + writel_relaxed(val, ctrl_addr(bdev, BAM_CTRL)); /* make sure previous stores are visible before enabling BAM */ wmb(); /* enable bam */ val |= BAM_EN; - writel_relaxed(val, bdev->regs + BAM_CTRL); + writel_relaxed(val, ctrl_addr(bdev, BAM_CTRL)); /* set descriptor threshhold, start with 4 bytes */ - writel_relaxed(DEFAULT_CNT_THRSHLD, bdev->regs + BAM_DESC_CNT_TRSHLD); + writel_relaxed(DEFAULT_CNT_THRSHLD, + ctrl_addr(bdev, 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); + writel_relaxed(BAM_CNFG_BITS_DEFAULT, + ctrl_addr(bdev, BAM_CNFG_BITS)); /* enable irqs for errors */ writel_relaxed(BAM_ERROR_EN | BAM_HRESP_ERR_EN, - bdev->regs + BAM_IRQ_EN); + ctrl_addr(bdev, BAM_IRQ_EN)); /* unmask global bam interrupt */ - writel_relaxed(BAM_IRQ_MSK, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee)); + writel_relaxed(BAM_IRQ_MSK, ee_addr(bdev, BAM_IRQ_SRCS_MSK_EE)); return 0; } @@ -996,6 +1043,9 @@ static int bam_dma_probe(struct platform_device *pdev) return ret; } + if (of_device_is_compatible(pdev->dev.of_node, "qcom,bam-v1.4.0")) + bdev->reg_ver = 1; + bdev->bamclk = devm_clk_get(bdev->dev, "bam_clk"); if (IS_ERR(bdev->bamclk)) return PTR_ERR(bdev->bamclk); @@ -1084,7 +1134,7 @@ static int bam_dma_remove(struct platform_device *pdev) dma_async_device_unregister(&bdev->common); /* mask all interrupts for this execution environment */ - writel_relaxed(0, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee)); + writel_relaxed(0, ee_addr(bdev, BAM_IRQ_SRCS_MSK_EE)); devm_free_irq(bdev->dev, bdev->irq, bdev); @@ -1105,6 +1155,7 @@ static int bam_dma_remove(struct platform_device *pdev) } static const struct of_device_id bam_of_match[] = { + { .compatible = "qcom,bam-v1.3.0", }, { .compatible = "qcom,bam-v1.4.0", }, {} };