summaryrefslogtreecommitdiff
path: root/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c')
-rw-r--r--drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c112
1 files changed, 82 insertions, 30 deletions
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index 35993ab92154..cd0d745eb071 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -79,6 +79,32 @@ axi_chan_iowrite64(struct axi_dma_chan *chan, u32 reg, u64 val)
iowrite32(upper_32_bits(val), chan->chan_regs + reg + 4);
}
+static inline void axi_chan_config_write(struct axi_dma_chan *chan,
+ struct axi_dma_chan_config *config)
+{
+ u32 cfg_lo, cfg_hi;
+
+ cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS |
+ config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
+ if (chan->chip->dw->hdata->reg_map_8_channels) {
+ cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS |
+ config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS |
+ config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS |
+ config->src_per << CH_CFG_H_SRC_PER_POS |
+ config->dst_per << CH_CFG_H_DST_PER_POS |
+ config->prior << CH_CFG_H_PRIORITY_POS;
+ } else {
+ cfg_lo |= config->src_per << CH_CFG2_L_SRC_PER_POS |
+ config->dst_per << CH_CFG2_L_DST_PER_POS;
+ cfg_hi = config->tt_fc << CH_CFG2_H_TT_FC_POS |
+ config->hs_sel_src << CH_CFG2_H_HS_SEL_SRC_POS |
+ config->hs_sel_dst << CH_CFG2_H_HS_SEL_DST_POS |
+ config->prior << CH_CFG2_H_PRIORITY_POS;
+ }
+ axi_chan_iowrite32(chan, CH_CFG_L, cfg_lo);
+ axi_chan_iowrite32(chan, CH_CFG_H, cfg_hi);
+}
+
static inline void axi_dma_disable(struct axi_dma_chip *chip)
{
u32 val;
@@ -154,7 +180,10 @@ static inline void axi_chan_disable(struct axi_dma_chan *chan)
val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT);
- val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
+ if (chan->chip->dw->hdata->reg_map_8_channels)
+ val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
+ else
+ val |= BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT;
axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
}
@@ -163,8 +192,12 @@ static inline void axi_chan_enable(struct axi_dma_chan *chan)
u32 val;
val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
- val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
- BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
+ if (chan->chip->dw->hdata->reg_map_8_channels)
+ val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
+ BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
+ else
+ val |= BIT(chan->id) << DMAC_CHAN_EN_SHIFT |
+ BIT(chan->id) << DMAC_CHAN_EN2_WE_SHIFT;
axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
}
@@ -179,12 +212,16 @@ static inline bool axi_chan_is_hw_enable(struct axi_dma_chan *chan)
static void axi_dma_hw_init(struct axi_dma_chip *chip)
{
+ int ret;
u32 i;
for (i = 0; i < chip->dw->hdata->nr_channels; i++) {
axi_chan_irq_disable(&chip->dw->chan[i], DWAXIDMAC_IRQ_ALL);
axi_chan_disable(&chip->dw->chan[i]);
}
+ ret = dma_set_mask_and_coherent(chip->dev, DMA_BIT_MASK(64));
+ if (ret)
+ dev_warn(chip->dev, "Unable to set coherent mask\n");
}
static u32 axi_chan_get_xfer_width(struct axi_dma_chan *chan, dma_addr_t src,
@@ -336,7 +373,8 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
struct axi_dma_desc *first)
{
u32 priority = chan->chip->dw->hdata->priority[chan->id];
- u32 reg, irq_mask;
+ struct axi_dma_chan_config config;
+ u32 irq_mask;
u8 lms = 0; /* Select AXI0 master for LLI fetching */
if (unlikely(axi_chan_is_hw_enable(chan))) {
@@ -348,36 +386,36 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
axi_dma_enable(chan->chip);
- reg = (DWAXIDMAC_MBLK_TYPE_LL << CH_CFG_L_DST_MULTBLK_TYPE_POS |
- DWAXIDMAC_MBLK_TYPE_LL << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
- axi_chan_iowrite32(chan, CH_CFG_L, reg);
-
- reg = (DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC << CH_CFG_H_TT_FC_POS |
- priority << CH_CFG_H_PRIORITY_POS |
- DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_DST_POS |
- DWAXIDMAC_HS_SEL_HW << CH_CFG_H_HS_SEL_SRC_POS);
+ config.dst_multblk_type = DWAXIDMAC_MBLK_TYPE_LL;
+ config.src_multblk_type = DWAXIDMAC_MBLK_TYPE_LL;
+ config.tt_fc = DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC;
+ config.prior = priority;
+ config.hs_sel_dst = DWAXIDMAC_HS_SEL_HW;
+ config.hs_sel_dst = DWAXIDMAC_HS_SEL_HW;
switch (chan->direction) {
case DMA_MEM_TO_DEV:
dw_axi_dma_set_byte_halfword(chan, true);
- reg |= (chan->config.device_fc ?
- DWAXIDMAC_TT_FC_MEM_TO_PER_DST :
- DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC)
- << CH_CFG_H_TT_FC_POS;
+ config.tt_fc = chan->config.device_fc ?
+ DWAXIDMAC_TT_FC_MEM_TO_PER_DST :
+ DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC;
if (chan->chip->apb_regs)
- reg |= (chan->id << CH_CFG_H_DST_PER_POS);
+ config.dst_per = chan->id;
+ else
+ config.dst_per = chan->hw_handshake_num;
break;
case DMA_DEV_TO_MEM:
- reg |= (chan->config.device_fc ?
- DWAXIDMAC_TT_FC_PER_TO_MEM_SRC :
- DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC)
- << CH_CFG_H_TT_FC_POS;
+ config.tt_fc = chan->config.device_fc ?
+ DWAXIDMAC_TT_FC_PER_TO_MEM_SRC :
+ DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC;
if (chan->chip->apb_regs)
- reg |= (chan->id << CH_CFG_H_SRC_PER_POS);
+ config.src_per = chan->id;
+ else
+ config.src_per = chan->hw_handshake_num;
break;
default:
break;
}
- axi_chan_iowrite32(chan, CH_CFG_H, reg);
+ axi_chan_config_write(chan, &config);
write_chan_llp(chan, first->hw_desc[0].llp | lms);
@@ -1120,10 +1158,16 @@ static int dma_chan_pause(struct dma_chan *dchan)
spin_lock_irqsave(&chan->vc.lock, flags);
- val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
- val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT |
- BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT;
- axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
+ if (chan->chip->dw->hdata->reg_map_8_channels) {
+ val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
+ val |= BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT |
+ BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT;
+ axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
+ } else {
+ val = BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
+ BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
+ axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
+ }
do {
if (axi_chan_irq_read(chan) & DWAXIDMAC_IRQ_SUSPENDED)
@@ -1147,9 +1191,15 @@ static inline void axi_chan_resume(struct axi_dma_chan *chan)
u32 val;
val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
- val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT);
- val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT);
- axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
+ if (chan->chip->dw->hdata->reg_map_8_channels) {
+ val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT);
+ val |= (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT);
+ axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
+ } else {
+ val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT);
+ val |= (BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT);
+ axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
+ }
chan->is_paused = false;
}
@@ -1241,6 +1291,8 @@ static int parse_device_properties(struct axi_dma_chip *chip)
return -EINVAL;
chip->dw->hdata->nr_channels = tmp;
+ if (tmp <= DMA_REG_MAP_CH_REF)
+ chip->dw->hdata->reg_map_8_channels = true;
ret = device_property_read_u32(dev, "snps,dma-masters", &tmp);
if (ret)