diff options
author | Linus Walleij | 2010-06-22 18:06:42 -0700 |
---|---|---|
committer | Dan Williams | 2010-06-22 18:06:42 -0700 |
commit | f41855929c9fdc3b4f2863ada9df3e0cf4231b5b (patch) | |
tree | 4a31c0bd50af7c13664352e929edcdd2bd5bbf26 | |
parent | 6b7acd84426235c63a3c0f0b230a95064f97b0d4 (diff) |
DMAENGINE: ste_dma40: support older silicon
This makes sure the DMA40 driver will also work on the oldest
silicon revisions that have the on-chip memory on another location
in the DB8500 and also requires explicit suspend before starting
or resuming a logical channel.
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
[added parenthesis to the definition of U8500_DMA_LCPA_BASE_ED]
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | arch/arm/mach-ux500/devices-db8500.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/db8500-regs.h | 1 | ||||
-rw-r--r-- | drivers/dma/ste_dma40.c | 32 |
3 files changed, 31 insertions, 4 deletions
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c index e2b7c31ef372..c62cdbee3bd9 100644 --- a/arch/arm/mach-ux500/devices-db8500.c +++ b/arch/arm/mach-ux500/devices-db8500.c @@ -213,4 +213,6 @@ void dma40_u8500ed_fixup(void) dma40_plat_data.memcpy_len = 0; dma40_resources[0].start = U8500_DMA_BASE_ED; dma40_resources[0].end = U8500_DMA_BASE_ED + SZ_4K - 1; + dma40_resources[1].start = U8500_DMA_LCPA_BASE_ED; + dma40_resources[1].end = U8500_DMA_LCPA_BASE_ED + 2 * SZ_1K - 1; } diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h index 897fa35078ef..f000218210c9 100644 --- a/arch/arm/mach-ux500/include/mach/db8500-regs.h +++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h @@ -17,6 +17,7 @@ #define U8500_ESRAM_BANK4 (U8500_ESRAM_BANK3 + U8500_ESRAM_BANK_SIZE) /* Use bank 4 for DMA LCPA */ #define U8500_DMA_LCPA_BASE U8500_ESRAM_BANK4 +#define U8500_DMA_LCPA_BASE_ED (U8500_ESRAM_BANK4 + 0x4000) #define U8500_PER3_BASE 0x80000000 #define U8500_STM_BASE 0x80100000 diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 1d21fbd419d1..21a759731ef1 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -218,6 +218,7 @@ struct d40_chan { * the same physical register. * @dev: The device structure. * @virtbase: The virtual base address of the DMA's register. + * @rev: silicon revision detected. * @clk: Pointer to the DMA clock structure. * @phy_start: Physical memory start of the DMA registers. * @phy_size: Size of the DMA register map. @@ -250,6 +251,7 @@ struct d40_base { spinlock_t execmd_lock; struct device *dev; void __iomem *virtbase; + u8 rev:4; struct clk *clk; phys_addr_t phy_start; resource_size_t phy_size; @@ -757,6 +759,17 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx) static int d40_start(struct d40_chan *d40c) { + if (d40c->base->rev == 0) { + int err; + + if (d40c->log_num != D40_PHY_CHAN) { + err = d40_channel_execute_command(d40c, + D40_DMA_SUSPEND_REQ); + if (err) + return err; + } + } + if (d40c->log_num != D40_PHY_CHAN) d40_config_set_event(d40c, true); @@ -1426,6 +1439,13 @@ static int d40_resume(struct dma_chan *chan) spin_lock_irqsave(&d40c->lock, flags); + if (d40c->base->rev == 0) + if (d40c->log_num != D40_PHY_CHAN) { + res = d40_channel_execute_command(d40c, + D40_DMA_SUSPEND_REQ); + goto no_suspend; + } + /* If bytes left to transfer or linked tx resume job */ if (d40_residue(d40c) || d40_tx_is_linked(d40c)) { if (d40c->log_num != D40_PHY_CHAN) @@ -1433,6 +1453,7 @@ static int d40_resume(struct dma_chan *chan) res = d40_channel_execute_command(d40c, D40_DMA_RUN); } +no_suspend: spin_unlock_irqrestore(&d40c->lock, flags); return res; } @@ -2286,6 +2307,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) int num_log_chans = 0; int num_phy_chans; int i; + u32 val; clk = clk_get(&pdev->dev, NULL); @@ -2324,12 +2346,13 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) } } - i = readl(virtbase + D40_DREG_PERIPHID2); + /* Get silicon revision */ + val = readl(virtbase + D40_DREG_PERIPHID2); - if ((i & 0xf) != D40_PERIPHID2_DESIGNER) { + if ((val & 0xf) != D40_PERIPHID2_DESIGNER) { dev_err(&pdev->dev, "[%s] Unknown designer! Got %x wanted %x\n", - __func__, i & 0xf, D40_PERIPHID2_DESIGNER); + __func__, val & 0xf, D40_PERIPHID2_DESIGNER); goto failure; } @@ -2337,7 +2360,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4; dev_info(&pdev->dev, "hardware revision: %d @ 0x%x\n", - (i >> 4) & 0xf, res->start); + (val >> 4) & 0xf, res->start); plat_data = pdev->dev.platform_data; @@ -2359,6 +2382,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) goto failure; } + base->rev = (val >> 4) & 0xf; base->clk = clk; base->num_phy_chans = num_phy_chans; base->num_log_chans = num_log_chans; |