aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/pl330.c
diff options
context:
space:
mode:
authorBoojin Kim <boojin.kim@samsung.com>2011-12-26 04:55:47 -0500
committerVinod Koul <vinod.koul@linux.intel.com>2012-03-08 07:29:29 -0500
commit3ecf51a45c0e218d70df2cc905b668fa0c115f73 (patch)
treef6a3b508cf0686d0b3c2700721a6e8fcd46c3f70 /drivers/dma/pl330.c
parentb06db6e56c0850617291b8921582d04255022425 (diff)
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>
Diffstat (limited to 'drivers/dma/pl330.c')
-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 dd74c2478c6..7253d17f05f 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -151,6 +151,11 @@ enum pl330_reqtype {
151#define CRD 0xe14 151#define CRD 0xe14
152 152
153#define PERIPH_ID 0xfe0 153#define PERIPH_ID 0xfe0
154#define PERIPH_REV_SHIFT 20
155#define PERIPH_REV_MASK 0xf
156#define PERIPH_REV_R0P0 0
157#define PERIPH_REV_R1P0 1
158#define PERIPH_REV_R1P1 2
154#define PCELL_ID 0xff0 159#define PCELL_ID 0xff0
155 160
156#define CR0_PERIPH_REQ_SET (1 << 0) 161#define CR0_PERIPH_REQ_SET (1 << 0)
@@ -344,6 +349,7 @@ struct pl330_reqcfg {
344 enum pl330_dstcachectrl dcctl; 349 enum pl330_dstcachectrl dcctl;
345 enum pl330_srccachectrl scctl; 350 enum pl330_srccachectrl scctl;
346 enum pl330_byteswap swap; 351 enum pl330_byteswap swap;
352 struct pl330_config *pcfg;
347}; 353};
348 354
349/* 355/*
@@ -655,6 +661,11 @@ static inline u32 get_id(struct pl330_info *pi, u32 off)
655 return id; 661 return id;
656} 662}
657 663
664static inline u32 get_revision(u32 periph_id)
665{
666 return (periph_id >> PERIPH_REV_SHIFT) & PERIPH_REV_MASK;
667}
668
658static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[], 669static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[],
659 enum pl330_dst da, u16 val) 670 enum pl330_dst da, u16 val)
660{ 671{
@@ -1241,12 +1252,21 @@ static inline int _ldst_memtomem(unsigned dry_run, u8 buf[],
1241 const struct _xfer_spec *pxs, int cyc) 1252 const struct _xfer_spec *pxs, int cyc)
1242{ 1253{
1243 int off = 0; 1254 int off = 0;
1255 struct pl330_config *pcfg = pxs->r->cfg->pcfg;
1244 1256
1245 while (cyc--) { 1257 /* check lock-up free version */
1246 off += _emit_LD(dry_run, &buf[off], ALWAYS); 1258 if (get_revision(pcfg->periph_id) >= PERIPH_REV_R1P0) {
1247 off += _emit_RMB(dry_run, &buf[off]); 1259 while (cyc--) {
1248 off += _emit_ST(dry_run, &buf[off], ALWAYS); 1260 off += _emit_LD(dry_run, &buf[off], ALWAYS);
1249 off += _emit_WMB(dry_run, &buf[off]); 1261 off += _emit_ST(dry_run, &buf[off], ALWAYS);
1262 }
1263 } else {
1264 while (cyc--) {
1265 off += _emit_LD(dry_run, &buf[off], ALWAYS);
1266 off += _emit_RMB(dry_run, &buf[off]);
1267 off += _emit_ST(dry_run, &buf[off], ALWAYS);
1268 off += _emit_WMB(dry_run, &buf[off]);
1269 }
1250 } 1270 }
1251 1271
1252 return off; 1272 return off;
@@ -2619,6 +2639,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
2619 async_tx_ack(&desc->txd); 2639 async_tx_ack(&desc->txd);
2620 2640
2621 desc->req.peri = peri_id ? pch->chan.chan_id : 0; 2641 desc->req.peri = peri_id ? pch->chan.chan_id : 0;
2642 desc->rqcfg.pcfg = &pch->dmac->pif.pcfg;
2622 2643
2623 dma_async_tx_descriptor_init(&desc->txd, &pch->chan); 2644 dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
2624 2645