summaryrefslogtreecommitdiff
path: root/drivers/dma/owl-dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/owl-dma.c')
-rw-r--r--drivers/dma/owl-dma.c139
1 files changed, 90 insertions, 49 deletions
diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c
index 66ef70b00ec0..331c8d8b10a3 100644
--- a/drivers/dma/owl-dma.c
+++ b/drivers/dma/owl-dma.c
@@ -120,30 +120,38 @@
#define BIT_FIELD(val, width, shift, newshift) \
((((val) >> (shift)) & ((BIT(width)) - 1)) << (newshift))
+/* Frame count value is fixed as 1 */
+#define FCNT_VAL 0x1
+
/**
- * struct owl_dma_lli_hw - Hardware link list for dma transfer
- * @next_lli: physical address of the next link list
- * @saddr: source physical address
- * @daddr: destination physical address
- * @flen: frame length
- * @fcnt: frame count
- * @src_stride: source stride
- * @dst_stride: destination stride
- * @ctrla: dma_mode and linklist ctrl config
- * @ctrlb: interrupt config
- * @const_num: data for constant fill
+ * owl_dmadesc_offsets - Describe DMA descriptor, hardware link
+ * list for dma transfer
+ * @OWL_DMADESC_NEXT_LLI: physical address of the next link list
+ * @OWL_DMADESC_SADDR: source physical address
+ * @OWL_DMADESC_DADDR: destination physical address
+ * @OWL_DMADESC_FLEN: frame length
+ * @OWL_DMADESC_SRC_STRIDE: source stride
+ * @OWL_DMADESC_DST_STRIDE: destination stride
+ * @OWL_DMADESC_CTRLA: dma_mode and linklist ctrl config
+ * @OWL_DMADESC_CTRLB: interrupt config
+ * @OWL_DMADESC_CONST_NUM: data for constant fill
*/
-struct owl_dma_lli_hw {
- u32 next_lli;
- u32 saddr;
- u32 daddr;
- u32 flen:20;
- u32 fcnt:12;
- u32 src_stride;
- u32 dst_stride;
- u32 ctrla;
- u32 ctrlb;
- u32 const_num;
+enum owl_dmadesc_offsets {
+ OWL_DMADESC_NEXT_LLI = 0,
+ OWL_DMADESC_SADDR,
+ OWL_DMADESC_DADDR,
+ OWL_DMADESC_FLEN,
+ OWL_DMADESC_SRC_STRIDE,
+ OWL_DMADESC_DST_STRIDE,
+ OWL_DMADESC_CTRLA,
+ OWL_DMADESC_CTRLB,
+ OWL_DMADESC_CONST_NUM,
+ OWL_DMADESC_SIZE
+};
+
+enum owl_dma_id {
+ S900_DMA,
+ S700_DMA,
};
/**
@@ -153,7 +161,7 @@ struct owl_dma_lli_hw {
* @node: node for txd's lli_list
*/
struct owl_dma_lli {
- struct owl_dma_lli_hw hw;
+ u32 hw[OWL_DMADESC_SIZE];
dma_addr_t phys;
struct list_head node;
};
@@ -210,6 +218,7 @@ struct owl_dma_vchan {
* @pchans: array of data for the physical channels
* @nr_vchans: the number of physical channels
* @vchans: array of data for the physical channels
+ * @devid: device id based on OWL SoC
*/
struct owl_dma {
struct dma_device dma;
@@ -224,6 +233,7 @@ struct owl_dma {
unsigned int nr_vchans;
struct owl_dma_vchan *vchans;
+ enum owl_dma_id devid;
};
static void pchan_update(struct owl_dma_pchan *pchan, u32 reg,
@@ -313,11 +323,20 @@ static inline u32 llc_hw_ctrlb(u32 int_ctl)
{
u32 ctl;
+ /*
+ * Irrespective of the SoC, ctrlb value starts filling from
+ * bit 18.
+ */
ctl = BIT_FIELD(int_ctl, 7, 0, 18);
return ctl;
}
+static u32 llc_hw_flen(struct owl_dma_lli *lli)
+{
+ return lli->hw[OWL_DMADESC_FLEN] & GENMASK(19, 0);
+}
+
static void owl_dma_free_lli(struct owl_dma *od,
struct owl_dma_lli *lli)
{
@@ -349,8 +368,9 @@ static struct owl_dma_lli *owl_dma_add_lli(struct owl_dma_txd *txd,
list_add_tail(&next->node, &txd->lli_list);
if (prev) {
- prev->hw.next_lli = next->phys;
- prev->hw.ctrla |= llc_hw_ctrla(OWL_DMA_MODE_LME, 0);
+ prev->hw[OWL_DMADESC_NEXT_LLI] = next->phys;
+ prev->hw[OWL_DMADESC_CTRLA] |=
+ llc_hw_ctrla(OWL_DMA_MODE_LME, 0);
}
return next;
@@ -363,8 +383,8 @@ static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
struct dma_slave_config *sconfig,
bool is_cyclic)
{
- struct owl_dma_lli_hw *hw = &lli->hw;
- u32 mode;
+ struct owl_dma *od = to_owl_dma(vchan->vc.chan.device);
+ u32 mode, ctrlb;
mode = OWL_DMA_MODE_PW(0);
@@ -405,22 +425,40 @@ static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
return -EINVAL;
}
- hw->next_lli = 0; /* One link list by default */
- hw->saddr = src;
- hw->daddr = dst;
-
- hw->fcnt = 1; /* Frame count fixed as 1 */
- hw->flen = len; /* Max frame length is 1MB */
- hw->src_stride = 0;
- hw->dst_stride = 0;
- hw->ctrla = llc_hw_ctrla(mode,
- OWL_DMA_LLC_SAV_LOAD_NEXT |
- OWL_DMA_LLC_DAV_LOAD_NEXT);
+ lli->hw[OWL_DMADESC_CTRLA] = llc_hw_ctrla(mode,
+ OWL_DMA_LLC_SAV_LOAD_NEXT |
+ OWL_DMA_LLC_DAV_LOAD_NEXT);
if (is_cyclic)
- hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_BLOCK);
+ ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_BLOCK);
else
- hw->ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_SUPER_BLOCK);
+ ctrlb = llc_hw_ctrlb(OWL_DMA_INTCTL_SUPER_BLOCK);
+
+ lli->hw[OWL_DMADESC_NEXT_LLI] = 0; /* One link list by default */
+ lli->hw[OWL_DMADESC_SADDR] = src;
+ lli->hw[OWL_DMADESC_DADDR] = dst;
+ lli->hw[OWL_DMADESC_SRC_STRIDE] = 0;
+ lli->hw[OWL_DMADESC_DST_STRIDE] = 0;
+
+ if (od->devid == S700_DMA) {
+ /* Max frame length is 1MB */
+ lli->hw[OWL_DMADESC_FLEN] = len;
+ /*
+ * On S700, word starts from offset 0x1C is shared between
+ * frame count and ctrlb, where first 12 bits are for frame
+ * count and rest of 20 bits are for ctrlb.
+ */
+ lli->hw[OWL_DMADESC_CTRLB] = FCNT_VAL | ctrlb;
+ } else {
+ /*
+ * On S900, word starts from offset 0xC is shared between
+ * frame length (max frame length is 1MB) and frame count,
+ * where first 20 bits are for frame length and rest of
+ * 12 bits are for frame count.
+ */
+ lli->hw[OWL_DMADESC_FLEN] = len | FCNT_VAL << 20;
+ lli->hw[OWL_DMADESC_CTRLB] = ctrlb;
+ }
return 0;
}
@@ -582,7 +620,7 @@ static irqreturn_t owl_dma_interrupt(int irq, void *dev_id)
global_irq_pending = dma_readl(od, OWL_DMA_IRQ_PD0);
- if (chan_irq_pending && !(global_irq_pending & BIT(i))) {
+ if (chan_irq_pending && !(global_irq_pending & BIT(i))) {
dev_dbg(od->dma.dev,
"global and channel IRQ pending match err\n");
@@ -752,7 +790,7 @@ static u32 owl_dma_getbytes_chan(struct owl_dma_vchan *vchan)
/* Start from the next active node */
if (lli->phys == next_lli_phy) {
list_for_each_entry(lli, &txd->lli_list, node)
- bytes += lli->hw.flen;
+ bytes += llc_hw_flen(lli);
break;
}
}
@@ -783,7 +821,7 @@ static enum dma_status owl_dma_tx_status(struct dma_chan *chan,
if (vd) {
txd = to_owl_txd(&vd->tx);
list_for_each_entry(lli, &txd->lli_list, node)
- bytes += lli->hw.flen;
+ bytes += llc_hw_flen(lli);
} else {
bytes = owl_dma_getbytes_chan(vchan);
}
@@ -1040,6 +1078,13 @@ static struct dma_chan *owl_dma_of_xlate(struct of_phandle_args *dma_spec,
return chan;
}
+static const struct of_device_id owl_dma_match[] = {
+ { .compatible = "actions,s900-dma", .data = (void *)S900_DMA,},
+ { .compatible = "actions,s700-dma", .data = (void *)S700_DMA,},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, owl_dma_match);
+
static int owl_dma_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1069,6 +1114,8 @@ static int owl_dma_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "dma-channels %d, dma-requests %d\n",
nr_channels, nr_requests);
+ od->devid = (enum owl_dma_id)of_device_get_match_data(&pdev->dev);
+
od->nr_pchans = nr_channels;
od->nr_vchans = nr_requests;
@@ -1201,12 +1248,6 @@ static int owl_dma_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id owl_dma_match[] = {
- { .compatible = "actions,s900-dma", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, owl_dma_match);
-
static struct platform_driver owl_dma_driver = {
.probe = owl_dma_probe,
.remove = owl_dma_remove,