Cyclic SDMA transfers to SAI haulting on imx6

Andriy Fudimov Andriy at webbelectronicsinc.com
Sat Aug 7 02:41:08 CEST 2021


Hi,
Im trying to set up a cyclic dma transfer to/from the sai on an imx6, but im noticing weird behavior. First of all if my buffer length is small the DMA transfer will just hault as soon as it reaches the end of the buffer. If I make my buffer length larger it wont hault however it seems that only one of the rx or tx transfers can be on at once. Once my rx callback starts getting called my tx callback stops being called.
Any tips would be appreciated.

#define HARDWARE_BUFFER_BYTES 64*2 //* 2
#define HARDWARE_BUFFER_PERIOD_BYTES 32*2

static void dma_rx_complete(void *data)
{
    rxstacnt++;
    printk("rxstacnt: %u\n",txstacnt);
}

static void dma_tx_complete(void *data)
{
    txstacnt++;
    printk("txstacnt: %u\n",txstacnt);
}

static int imx_tx_pingdma_init(struct imx_dma *master, struct device *dev)
{
    int err;

    dma_addr_t pcm_hardware_reg_base;
    const __be32 *addr;
    addr = of_get_address(dev->of_node, 0, NULL, NULL);
    if (!addr) {
        dev_err(dev, "could not get pcm hardware register address\n");
    }
    pcm_hardware_reg_base = be32_to_cpup(addr);
    master->dma_tx = dma_request_slave_channel(dev, "tx");
    if (!master->dma_tx) {
        dev_err(dev, "no tx-dma configuration found - not using dma mode\n");
        tdm_dma_release(master);
        return -1;
    }

    master->dma_rx = dma_request_slave_channel(dev, "rx");
    if (!master->dma_rx) {
        dev_err(dev, "no rx-dma configuration found - not using dma mode\n");
        tdm_dma_release(master);
        return -1;
    }

    /* configure DMAs */
    master->tx_ping_buffer =
        dma_alloc_coherent(master->dma_tx->device->dev,
        HARDWARE_BUFFER_BYTES,
        &master->tx_ping_buffer_dma,
        GFP_KERNEL);

    if (!master->tx_ping_buffer) {
        dev_err(dev, "could not allocate dma address\n");
        tdm_dma_release(master);
        return -1;
    }

    memset(master->tx_ping_buffer, 0, HARDWARE_BUFFER_BYTES);

    master->rx_ping_buffer =
        dma_alloc_coherent(master->dma_rx->device->dev,
        HARDWARE_BUFFER_BYTES,
        &master->rx_ping_buffer_dma,
        GFP_KERNEL);

    if (!master->rx_ping_buffer) {
        dev_err(dev, "could not allocate rx dma address\n");
        tdm_dma_release(master);
        return -1;
    }

    memset(master->rx_ping_buffer, 0, HARDWARE_BUFFER_BYTES);
    master->dma_tx_slave_config.direction = DMA_MEM_TO_DEV;
    master->dma_tx_slave_config.dst_addr = 0x202c000 + 0x20;
    master->dma_tx_slave_config.dst_maxburst = 1;
    master->dma_tx_slave_config.dst_addr_width = 4;
    master->dma_tx_slave_config.src_addr = master->tx_ping_buffer_dma;
    master->dma_tx_slave_config.src_maxburst = 1;
    master->dma_tx_slave_config.src_addr_width = 4;

    err = dmaengine_slave_config(master->dma_tx,
        &master->dma_tx_slave_config);

    if (err < 0) {
        printk("could not setup slave_tx_config\n");
        tdm_dma_release(master);
        return err;
    }

    master->dma_rx_slave_config.direction = DMA_DEV_TO_MEM;
    master->dma_rx_slave_config.dst_addr = master->rx_ping_buffer_dma;
    master->dma_rx_slave_config.dst_maxburst = 1;
    master->dma_rx_slave_config.dst_addr_width = 4;
    master->dma_rx_slave_config.src_addr = 0x202c000 + 0xa0;
    master->dma_rx_slave_config.src_maxburst = 1;
    master->dma_rx_slave_config.src_addr_width = 4;

    err = dmaengine_slave_config(master->dma_rx,
        &master->dma_rx_slave_config);

    if (err < 0) {
        printk("could not setup slave_rx_config\n");
        tdm_dma_release(master);
        return err;
    }

    master->dma_tx_desc =
        dmaengine_prep_dma_cyclic(master->dma_tx,
        master->tx_ping_buffer_dma,
        HARDWARE_BUFFER_BYTES,
        HARDWARE_BUFFER_PERIOD_BYTES,
        DMA_MEM_TO_DEV,
        DMA_CTRL_ACK | DMA_PREP_INTERRUPT);

    if (!master->dma_tx_desc) {
        printk("could not setup dma_tx_desc\n");
        tdm_dma_release(master);
        return -1;
    }

    master->dma_rx_desc =
        dmaengine_prep_dma_cyclic(master->dma_rx,
        master->rx_ping_buffer_dma,
        HARDWARE_BUFFER_BYTES,
        HARDWARE_BUFFER_PERIOD_BYTES,
        DMA_DEV_TO_MEM,
        DMA_CTRL_ACK | DMA_PREP_INTERRUPT);

    if (!master->dma_rx_desc) {
        printk("could not setup dma_rx_desc\n");
        tdm_dma_release(master);
        return -1;
    }

    master->dma_tx_desc->callback = dma_tx_complete;
    master->dma_tx_desc->callback_param = master;

    master->dma_rx_desc->callback = dma_rx_complete;
    master->dma_rx_desc->callback_param = master;

    printk("DMA configured by success!\n");
    return 0;
}

static void start_dma(struct imx_dma *master)
{
    master->dma_tx_cookie = dmaengine_submit(master->dma_tx_desc);
    dma_async_issue_pending(master->dma_tx);

    master->dma_rx_cookie = dmaengine_submit(master->dma_rx_desc);
    dma_async_issue_pending(master->dma_rx);

    printk("DMA submited! dma_tx_cookie:%d\n", master->dma_tx_cookie);
    printk("DMA submited! dma_rx_cookie:%d\n", master->dma_rx_cookie);
    txcnt = 0;
}


More information about the Alsa-devel mailing list