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);