summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoojin Kim <boojin.kim@samsung.com>2011-12-26 18:55:47 +0900
committerVinod Koul <vinod.koul@linux.intel.com>2012-03-08 17:59:29 +0530
commit3ecf51a45c0e218d70df2cc905b668fa0c115f73 (patch)
treef6a3b508cf0686d0b3c2700721a6e8fcd46c3f70
parentb06db6e56c0850617291b8921582d04255022425 (diff)
downloadlinux-3ecf51a45c0e218d70df2cc905b668fa0c115f73.tar.bz2
DMA: PL330: Support MEMTOMEM transmit w/o RMB, WMB
The DMAC PL330 r1p0 version fixed the lockup error being on r0p0. This patch supports the DMA transmission without memory barrier operation when the revision of DMAC PL330 is the next of r0p0. Cc: Jassi Brar <jassisinghbrar@gmail.com> Cc: Russell King <rmk+kernel@arm.linux.org.uk> Acked-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Boojin Kim <boojin.kim@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> Acked-by: Jassi Brar <jassisinghbrar@gmail.com> Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
-rw-r--r--drivers/dma/pl330.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index dd74c2478c6d..7253d17f05f8 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -151,6 +151,11 @@ enum pl330_reqtype {
#define CRD 0xe14
#define PERIPH_ID 0xfe0
+#define PERIPH_REV_SHIFT 20
+#define PERIPH_REV_MASK 0xf
+#define PERIPH_REV_R0P0 0
+#define PERIPH_REV_R1P0 1
+#define PERIPH_REV_R1P1 2
#define PCELL_ID 0xff0
#define CR0_PERIPH_REQ_SET (1 << 0)
@@ -344,6 +349,7 @@ struct pl330_reqcfg {
enum pl330_dstcachectrl dcctl;
enum pl330_srccachectrl scctl;
enum pl330_byteswap swap;
+ struct pl330_config *pcfg;
};
/*
@@ -655,6 +661,11 @@ static inline u32 get_id(struct pl330_info *pi, u32 off)
return id;
}
+static inline u32 get_revision(u32 periph_id)
+{
+ return (periph_id >> PERIPH_REV_SHIFT) & PERIPH_REV_MASK;
+}
+
static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[],
enum pl330_dst da, u16 val)
{
@@ -1241,12 +1252,21 @@ static inline int _ldst_memtomem(unsigned dry_run, u8 buf[],
const struct _xfer_spec *pxs, int cyc)
{
int off = 0;
+ struct pl330_config *pcfg = pxs->r->cfg->pcfg;
- while (cyc--) {
- off += _emit_LD(dry_run, &buf[off], ALWAYS);
- off += _emit_RMB(dry_run, &buf[off]);
- off += _emit_ST(dry_run, &buf[off], ALWAYS);
- off += _emit_WMB(dry_run, &buf[off]);
+ /* check lock-up free version */
+ if (get_revision(pcfg->periph_id) >= PERIPH_REV_R1P0) {
+ while (cyc--) {
+ off += _emit_LD(dry_run, &buf[off], ALWAYS);
+ off += _emit_ST(dry_run, &buf[off], ALWAYS);
+ }
+ } else {
+ while (cyc--) {
+ off += _emit_LD(dry_run, &buf[off], ALWAYS);
+ off += _emit_RMB(dry_run, &buf[off]);
+ off += _emit_ST(dry_run, &buf[off], ALWAYS);
+ off += _emit_WMB(dry_run, &buf[off]);
+ }
}
return off;
@@ -2619,6 +2639,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
async_tx_ack(&desc->txd);
desc->req.peri = peri_id ? pch->chan.chan_id : 0;
+ desc->rqcfg.pcfg = &pch->dmac->pif.pcfg;
dma_async_tx_descriptor_init(&desc->txd, &pch->chan);