|
@@ -110,7 +110,7 @@ struct mmp_tdma_chan {
|
|
struct tasklet_struct tasklet;
|
|
struct tasklet_struct tasklet;
|
|
|
|
|
|
struct mmp_tdma_desc *desc_arr;
|
|
struct mmp_tdma_desc *desc_arr;
|
|
- phys_addr_t desc_arr_phys;
|
|
|
|
|
|
+ dma_addr_t desc_arr_phys;
|
|
int desc_num;
|
|
int desc_num;
|
|
enum dma_transfer_direction dir;
|
|
enum dma_transfer_direction dir;
|
|
dma_addr_t dev_addr;
|
|
dma_addr_t dev_addr;
|
|
@@ -166,9 +166,12 @@ static void mmp_tdma_enable_chan(struct mmp_tdma_chan *tdmac)
|
|
static int mmp_tdma_disable_chan(struct dma_chan *chan)
|
|
static int mmp_tdma_disable_chan(struct dma_chan *chan)
|
|
{
|
|
{
|
|
struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
|
|
struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
|
|
|
|
+ u32 tdcr;
|
|
|
|
|
|
- writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
|
|
|
|
- tdmac->reg_base + TDCR);
|
|
|
|
|
|
+ tdcr = readl(tdmac->reg_base + TDCR);
|
|
|
|
+ tdcr |= TDCR_ABR;
|
|
|
|
+ tdcr &= ~TDCR_CHANEN;
|
|
|
|
+ writel(tdcr, tdmac->reg_base + TDCR);
|
|
|
|
|
|
tdmac->status = DMA_COMPLETE;
|
|
tdmac->status = DMA_COMPLETE;
|
|
|
|
|
|
@@ -296,12 +299,27 @@ static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static size_t mmp_tdma_get_pos(struct mmp_tdma_chan *tdmac)
|
|
|
|
+{
|
|
|
|
+ size_t reg;
|
|
|
|
+
|
|
|
|
+ if (tdmac->idx == 0) {
|
|
|
|
+ reg = __raw_readl(tdmac->reg_base + TDSAR);
|
|
|
|
+ reg -= tdmac->desc_arr[0].src_addr;
|
|
|
|
+ } else if (tdmac->idx == 1) {
|
|
|
|
+ reg = __raw_readl(tdmac->reg_base + TDDAR);
|
|
|
|
+ reg -= tdmac->desc_arr[0].dst_addr;
|
|
|
|
+ } else
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ return reg;
|
|
|
|
+}
|
|
|
|
+
|
|
static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
|
|
static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
|
|
{
|
|
{
|
|
struct mmp_tdma_chan *tdmac = dev_id;
|
|
struct mmp_tdma_chan *tdmac = dev_id;
|
|
|
|
|
|
if (mmp_tdma_clear_chan_irq(tdmac) == 0) {
|
|
if (mmp_tdma_clear_chan_irq(tdmac) == 0) {
|
|
- tdmac->pos = (tdmac->pos + tdmac->period_len) % tdmac->buf_len;
|
|
|
|
tasklet_schedule(&tdmac->tasklet);
|
|
tasklet_schedule(&tdmac->tasklet);
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
} else
|
|
} else
|
|
@@ -343,7 +361,7 @@ static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
|
|
int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
|
|
int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
|
|
|
|
|
|
gpool = tdmac->pool;
|
|
gpool = tdmac->pool;
|
|
- if (tdmac->desc_arr)
|
|
|
|
|
|
+ if (gpool && tdmac->desc_arr)
|
|
gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
|
|
gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
|
|
size);
|
|
size);
|
|
tdmac->desc_arr = NULL;
|
|
tdmac->desc_arr = NULL;
|
|
@@ -499,6 +517,7 @@ static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
|
|
{
|
|
{
|
|
struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
|
|
struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
|
|
|
|
|
|
|
|
+ tdmac->pos = mmp_tdma_get_pos(tdmac);
|
|
dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
|
|
dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
|
|
tdmac->buf_len - tdmac->pos);
|
|
tdmac->buf_len - tdmac->pos);
|
|
|
|
|
|
@@ -610,7 +629,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
|
|
int i, ret;
|
|
int i, ret;
|
|
int irq = 0, irq_num = 0;
|
|
int irq = 0, irq_num = 0;
|
|
int chan_num = TDMA_CHANNEL_NUM;
|
|
int chan_num = TDMA_CHANNEL_NUM;
|
|
- struct gen_pool *pool;
|
|
|
|
|
|
+ struct gen_pool *pool = NULL;
|
|
|
|
|
|
of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev);
|
|
of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev);
|
|
if (of_id)
|
|
if (of_id)
|