powerpc/512x: add MPC8308 dma support

MPC8308 has pretty much the same DMA controller as MPC5121 and
this patch adds support for MPC8308 to the mpc512x_dma driver.

Signed-off-by: Ilya Yanok <yanok@emcraft.com>
Acked-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
Ilya Yanok 2010-10-27 01:52:57 +02:00 committed by Grant Likely
parent 2862559e8a
commit ba2eea251f
2 changed files with 68 additions and 21 deletions

View File

@ -109,7 +109,7 @@ config FSL_DMA
config MPC512X_DMA config MPC512X_DMA
tristate "Freescale MPC512x built-in DMA engine support" tristate "Freescale MPC512x built-in DMA engine support"
depends on PPC_MPC512x depends on PPC_MPC512x || PPC_MPC831x
select DMA_ENGINE select DMA_ENGINE
---help--- ---help---
Enable support for the Freescale MPC512x built-in DMA engine. Enable support for the Freescale MPC512x built-in DMA engine.

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (C) Freescale Semicondutor, Inc. 2007, 2008. * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
* Copyright (C) Semihalf 2009 * Copyright (C) Semihalf 2009
* Copyright (C) Ilya Yanok, Emcraft Systems 2010
* *
* Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description * Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
* (defines, structures and comments) was taken from MPC5121 DMA driver * (defines, structures and comments) was taken from MPC5121 DMA driver
@ -70,6 +71,8 @@
#define MPC_DMA_DMAES_SBE (1 << 1) #define MPC_DMA_DMAES_SBE (1 << 1)
#define MPC_DMA_DMAES_DBE (1 << 0) #define MPC_DMA_DMAES_DBE (1 << 0)
#define MPC_DMA_DMAGPOR_SNOOP_ENABLE (1 << 6)
#define MPC_DMA_TSIZE_1 0x00 #define MPC_DMA_TSIZE_1 0x00
#define MPC_DMA_TSIZE_2 0x01 #define MPC_DMA_TSIZE_2 0x01
#define MPC_DMA_TSIZE_4 0x02 #define MPC_DMA_TSIZE_4 0x02
@ -104,7 +107,10 @@ struct __attribute__ ((__packed__)) mpc_dma_regs {
/* 0x30 */ /* 0x30 */
u32 dmahrsh; /* DMA hw request status high(ch63~32) */ u32 dmahrsh; /* DMA hw request status high(ch63~32) */
u32 dmahrsl; /* DMA hardware request status low(ch31~0) */ u32 dmahrsl; /* DMA hardware request status low(ch31~0) */
u32 dmaihsa; /* DMA interrupt high select AXE(ch63~32) */ union {
u32 dmaihsa; /* DMA interrupt high select AXE(ch63~32) */
u32 dmagpor; /* (General purpose register on MPC8308) */
};
u32 dmailsa; /* DMA interrupt low select AXE(ch31~0) */ u32 dmailsa; /* DMA interrupt low select AXE(ch31~0) */
/* 0x40 ~ 0xff */ /* 0x40 ~ 0xff */
u32 reserve0[48]; /* Reserved */ u32 reserve0[48]; /* Reserved */
@ -195,7 +201,9 @@ struct mpc_dma {
struct mpc_dma_regs __iomem *regs; struct mpc_dma_regs __iomem *regs;
struct mpc_dma_tcd __iomem *tcd; struct mpc_dma_tcd __iomem *tcd;
int irq; int irq;
int irq2;
uint error_status; uint error_status;
int is_mpc8308;
/* Lock for error_status field in this structure */ /* Lock for error_status field in this structure */
spinlock_t error_status_lock; spinlock_t error_status_lock;
@ -307,8 +315,10 @@ static irqreturn_t mpc_dma_irq(int irq, void *data)
spin_unlock(&mdma->error_status_lock); spin_unlock(&mdma->error_status_lock);
/* Handle interrupt on each channel */ /* Handle interrupt on each channel */
mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth), if (mdma->dma.chancnt > 32) {
mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth),
in_be32(&mdma->regs->dmaerrh), 32); in_be32(&mdma->regs->dmaerrh), 32);
}
mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl), mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl),
in_be32(&mdma->regs->dmaerrl), 0); in_be32(&mdma->regs->dmaerrl), 0);
@ -562,6 +572,7 @@ static struct dma_async_tx_descriptor *
mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
size_t len, unsigned long flags) size_t len, unsigned long flags)
{ {
struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan); struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
struct mpc_dma_desc *mdesc = NULL; struct mpc_dma_desc *mdesc = NULL;
struct mpc_dma_tcd *tcd; struct mpc_dma_tcd *tcd;
@ -590,7 +601,8 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
tcd->dsize = MPC_DMA_TSIZE_32; tcd->dsize = MPC_DMA_TSIZE_32;
tcd->soff = 32; tcd->soff = 32;
tcd->doff = 32; tcd->doff = 32;
} else if (IS_ALIGNED(src | dst | len, 16)) { } else if (!mdma->is_mpc8308 && IS_ALIGNED(src | dst | len, 16)) {
/* MPC8308 doesn't support 16 byte transfers */
tcd->ssize = MPC_DMA_TSIZE_16; tcd->ssize = MPC_DMA_TSIZE_16;
tcd->dsize = MPC_DMA_TSIZE_16; tcd->dsize = MPC_DMA_TSIZE_16;
tcd->soff = 16; tcd->soff = 16;
@ -650,6 +662,15 @@ static int __devinit mpc_dma_probe(struct platform_device *op,
return -EINVAL; return -EINVAL;
} }
if (of_device_is_compatible(dn, "fsl,mpc8308-dma")) {
mdma->is_mpc8308 = 1;
mdma->irq2 = irq_of_parse_and_map(dn, 1);
if (mdma->irq2 == NO_IRQ) {
dev_err(dev, "Error mapping IRQ!\n");
return -EINVAL;
}
}
retval = of_address_to_resource(dn, 0, &res); retval = of_address_to_resource(dn, 0, &res);
if (retval) { if (retval) {
dev_err(dev, "Error parsing memory region!\n"); dev_err(dev, "Error parsing memory region!\n");
@ -680,11 +701,23 @@ static int __devinit mpc_dma_probe(struct platform_device *op,
return -EINVAL; return -EINVAL;
} }
if (mdma->is_mpc8308) {
retval = devm_request_irq(dev, mdma->irq2, &mpc_dma_irq, 0,
DRV_NAME, mdma);
if (retval) {
dev_err(dev, "Error requesting IRQ2!\n");
return -EINVAL;
}
}
spin_lock_init(&mdma->error_status_lock); spin_lock_init(&mdma->error_status_lock);
dma = &mdma->dma; dma = &mdma->dma;
dma->dev = dev; dma->dev = dev;
dma->chancnt = MPC_DMA_CHANNELS; if (!mdma->is_mpc8308)
dma->chancnt = MPC_DMA_CHANNELS;
else
dma->chancnt = 16; /* MPC8308 DMA has only 16 channels */
dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources; dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources;
dma->device_free_chan_resources = mpc_dma_free_chan_resources; dma->device_free_chan_resources = mpc_dma_free_chan_resources;
dma->device_issue_pending = mpc_dma_issue_pending; dma->device_issue_pending = mpc_dma_issue_pending;
@ -720,26 +753,40 @@ static int __devinit mpc_dma_probe(struct platform_device *op,
* - Round-robin group arbitration, * - Round-robin group arbitration,
* - Round-robin channel arbitration. * - Round-robin channel arbitration.
*/ */
out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG | if (!mdma->is_mpc8308) {
MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA); out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
/* Disable hardware DMA requests */ /* Disable hardware DMA requests */
out_be32(&mdma->regs->dmaerqh, 0); out_be32(&mdma->regs->dmaerqh, 0);
out_be32(&mdma->regs->dmaerql, 0); out_be32(&mdma->regs->dmaerql, 0);
/* Disable error interrupts */ /* Disable error interrupts */
out_be32(&mdma->regs->dmaeeih, 0); out_be32(&mdma->regs->dmaeeih, 0);
out_be32(&mdma->regs->dmaeeil, 0); out_be32(&mdma->regs->dmaeeil, 0);
/* Clear interrupts status */ /* Clear interrupts status */
out_be32(&mdma->regs->dmainth, 0xFFFFFFFF); out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF); out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF); out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF); out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
/* Route interrupts to IPIC */ /* Route interrupts to IPIC */
out_be32(&mdma->regs->dmaihsa, 0); out_be32(&mdma->regs->dmaihsa, 0);
out_be32(&mdma->regs->dmailsa, 0); out_be32(&mdma->regs->dmailsa, 0);
} else {
/* MPC8308 has 16 channels and lacks some registers */
out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA);
/* enable snooping */
out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE);
/* Disable error interrupts */
out_be32(&mdma->regs->dmaeeil, 0);
/* Clear interrupts status */
out_be32(&mdma->regs->dmaintl, 0xFFFF);
out_be32(&mdma->regs->dmaerrl, 0xFFFF);
}
/* Register DMA engine */ /* Register DMA engine */
dev_set_drvdata(dev, mdma); dev_set_drvdata(dev, mdma);