|
@@ -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 |
|
|
|
|
- MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
|
|
|
|
-
|
|
|
|
- /* Disable hardware DMA requests */
|
|
|
|
- out_be32(&mdma->regs->dmaerqh, 0);
|
|
|
|
- out_be32(&mdma->regs->dmaerql, 0);
|
|
|
|
-
|
|
|
|
- /* Disable error interrupts */
|
|
|
|
- out_be32(&mdma->regs->dmaeeih, 0);
|
|
|
|
- out_be32(&mdma->regs->dmaeeil, 0);
|
|
|
|
-
|
|
|
|
- /* Clear interrupts status */
|
|
|
|
- out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
|
|
|
|
- out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
|
|
|
|
- out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
|
|
|
|
- out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
|
|
|
|
-
|
|
|
|
- /* Route interrupts to IPIC */
|
|
|
|
- out_be32(&mdma->regs->dmaihsa, 0);
|
|
|
|
- out_be32(&mdma->regs->dmailsa, 0);
|
|
|
|
|
|
+ if (!mdma->is_mpc8308) {
|
|
|
|
+ out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
|
|
|
|
+ MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
|
|
|
|
+
|
|
|
|
+ /* Disable hardware DMA requests */
|
|
|
|
+ out_be32(&mdma->regs->dmaerqh, 0);
|
|
|
|
+ out_be32(&mdma->regs->dmaerql, 0);
|
|
|
|
+
|
|
|
|
+ /* Disable error interrupts */
|
|
|
|
+ out_be32(&mdma->regs->dmaeeih, 0);
|
|
|
|
+ out_be32(&mdma->regs->dmaeeil, 0);
|
|
|
|
+
|
|
|
|
+ /* Clear interrupts status */
|
|
|
|
+ out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
|
|
|
|
+ out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
|
|
|
|
+ out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
|
|
|
|
+ out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
|
|
|
|
+
|
|
|
|
+ /* Route interrupts to IPIC */
|
|
|
|
+ out_be32(&mdma->regs->dmaihsa, 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);
|