2010/10/22 Alan Cox <[email protected]>:
> From: Mathieu SOULARD <[email protected]>
> (...)
> +/**
> + * intel_mid_ssp_spi_dma_init() - Initialize DMA
> + * @drv_context: Pointer to the private driver context
> + *
> + * This function is called at driver setup phase to allocate DMA
> + * ressources.
> + */
> +static void intel_mid_ssp_spi_dma_init(struct ssp_driver_context
> *drv_context)
> +{
> + struct intel_mid_dma_slave *rxs, *txs;
> + struct dma_slave_config *ds;
Hey, I really like this :-)
But where are you actually using this config?
It looks like you're in some transition phase to the
generic API.
> + dma_cap_mask_t mask;
> + struct device *dev = &drv_context->pdev->dev;
> + unsigned int device_id;
> +
> + /* Configure RX channel parameters */
> + rxs = &drv_context->dmas_rx;
> + ds = &rxs->dma_slave;
> +
> + ds->direction = DMA_FROM_DEVICE;
> + rxs->hs_mode = LNW_DMA_HW_HS;
> + rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
> + ds->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> + ds->src_addr_width = drv_context->n_bytes;
> +
> + /* Use a DMA burst according to the FIFO thresholds */
> + if (drv_context->rx_fifo_threshold == 8) {
> + ds->src_maxburst = 8;
> + ds->dst_maxburst = 8;
> + } else if (drv_context->rx_fifo_threshold == 4) {
> + ds->src_maxburst = 4;
> + ds->dst_maxburst = 4;
> + } else {
> + ds->src_maxburst = 1;
> + ds->dst_maxburst = 1;
> + }
> +
> + /* Configure TX channel parameters */
> + txs = &drv_context->dmas_tx;
> + ds = &txs->dma_slave;
> +
> + ds->direction = DMA_TO_DEVICE;
> + txs->hs_mode = LNW_DMA_HW_HS;
> + txs->cfg_mode = LNW_DMA_MEM_TO_PER;
What I cannot wrap my head around is why your DMA
controller cannot figure these things out from the data
passed in to the
> + ds->src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> + ds->dst_addr_width = drv_context->n_bytes;
You also want to se
ds->src_addr and ds->dst_addr instead of passing that
through an artificial memcpy() call.
> + /* Use a DMA burst according to the FIFO thresholds */
> + if (drv_context->rx_fifo_threshold == 8) {
> + ds->src_maxburst = 8;
> + ds->dst_maxburst = 8;
> + } else if (drv_context->rx_fifo_threshold == 4) {
> + ds->src_maxburst = 4;
> + ds->dst_maxburst = 4;
> + } else {
> + ds->src_maxburst = 1;
> + ds->dst_maxburst = 1;
> + }
> +
> + /* Nothing more to do if already initialized */
There isn't?
You need to call
rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
(unsigned long) ds);
To use that config you've set.
> + if (drv_context->dma_initialized)
> + return;
> +
> + /* Use DMAC1 */
> + if (drv_context->quirks & QUIRKS_PLATFORM_MRST)
> + device_id = PCI_MRST_DMAC1_ID;
> + else
> + device_id = PCI_MDFL_DMAC1_ID;
> +
> + drv_context->dmac1 = pci_get_device(PCI_VENDOR_ID_INTEL,
> + device_id, NULL);
> +
> + if (!drv_context->dmac1) {
> + dev_err(dev, "Can't find DMAC1");
> + return;
> + }
> +
> + if (drv_context->quirks & QUIRKS_SRAM_ADDITIONAL_CPY) {
> + drv_context->virt_addr_sram_rx =
> ioremap_nocache(SRAM_BASE_ADDR,
> + 2 * MAX_SPI_TRANSFER_SIZE);
> + if (drv_context->virt_addr_sram_rx)
> + drv_context->virt_addr_sram_tx =
> + drv_context->virt_addr_sram_rx +
> + MAX_SPI_TRANSFER_SIZE;
> + else
> + dev_err(dev, "Virt_addr_sram_rx is null\n");
> + }
> +
> + /* 1. Allocate rx channel */
> + dma_cap_zero(mask);
> + dma_cap_set(DMA_MEMCPY, mask);
> + dma_cap_set(DMA_SLAVE, mask);
You only want to request DMA_SLAVE really.
> +
> + drv_context->rxchan = dma_request_channel(mask, chan_filter,
> + drv_context);
> + if (!drv_context->rxchan)
> + goto err_exit;
> +
> + drv_context->rxchan->private = rxs;
> +
> + /* 2. Allocate tx channel */
> + dma_cap_set(DMA_SLAVE, mask);
> + dma_cap_set(DMA_MEMCPY, mask);
> +
> + drv_context->txchan = dma_request_channel(mask, chan_filter,
> + drv_context);
> +
> + if (!drv_context->txchan)
> + goto free_rxchan;
> + else
> + drv_context->txchan->private = txs;
rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
(unsigned long) ds);
txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
(unsigned long) ds);
> + /* set the dma done bit to 1 */
> + drv_context->txdma_done = 1;
> + drv_context->rxdma_done = 1;
> +
> + drv_context->tx_param.drv_context = drv_context;
> + drv_context->tx_param.direction = TX_DIRECTION;
> + drv_context->rx_param.drv_context = drv_context;
> + drv_context->rx_param.direction = RX_DIRECTION;
> +
> + drv_context->dma_initialized = 1;
> +
> + return;
> +
> +free_rxchan:
> + dma_release_channel(drv_context->rxchan);
> +err_exit:
> + dev_err(dev, "Error : DMA Channel Not available\n");
> +
> + if (drv_context->quirks & QUIRKS_SRAM_ADDITIONAL_CPY)
> + iounmap(drv_context->virt_addr_sram_rx);
> +
> + pci_dev_put(drv_context->dmac1);
> + return;
> +}
> +
> (...)
> +/**
> + * dma_transfer() - Initiate a DMA transfer
> + * @drv_context: Pointer to the private driver context
> + */
> +static void dma_transfer(struct ssp_driver_context *drv_context)
> +{
> + dma_addr_t ssdr_addr;
> + struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
> + struct dma_chan *txchan, *rxchan;
> + enum dma_ctrl_flags flag;
> + struct device *dev = &drv_context->pdev->dev;
> +
> + /* get Data Read/Write address */
> + ssdr_addr = (dma_addr_t)(drv_context->paddr + 0x10);
> +
> + if (drv_context->tx_dma)
> + drv_context->txdma_done = 0;
> +
> + if (drv_context->rx_dma)
> + drv_context->rxdma_done = 0;
> +
> + /* 2. prepare the RX dma transfer */
> + txchan = drv_context->txchan;
> + rxchan = drv_context->rxchan;
> +
> + flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
> +
> + if (likely(drv_context->quirks & QUIRKS_DMA_USE_NO_TRAIL)) {
> + /* Since the DMA is configured to do 32bits access */
> + /* to/from the DDR, the DMA transfer size must be */
> + /* a multiple of 4 bytes */
> + drv_context->len_dma_rx = drv_context->len & ~(4 - 1);
> + drv_context->len_dma_tx = drv_context->len_dma_rx;
> +
> + /* In Rx direction, TRAIL Bytes are handled by memcpy */
> + if (drv_context->rx_dma &&
> + (drv_context->len_dma_rx >
> + drv_context->rx_fifo_threshold *
> drv_context->n_bytes))
> + drv_context->len_dma_rx =
> + TRUNCATE(drv_context->len_dma_rx,
> + drv_context->rx_fifo_threshold *
> + drv_context->n_bytes);
> + else if (!drv_context->rx_dma)
> + dev_err(dev, "ERROR : rx_dma is null\r\n");
> + } else {
> + /* TRAIL Bytes are handled by DMA */
> + if (drv_context->rx_dma) {
> + drv_context->len_dma_rx = drv_context->len;
> + drv_context->len_dma_tx = drv_context->len;
> + } else {
> + dev_err(dev, "ERROR : drv_context->rx_dma is
> null!\n");
> + }
> + }
> +
> + rxdesc = rxchan->device->device_prep_dma_memcpy
> + (rxchan, /* DMA Channel */
> + drv_context->rx_dma, /* DAR */
/* DAR */ ?
Isn't that just a buffer?
> + ssdr_addr, /* SAR */
This is not really a memcpy() targetr address because it's fixed,
right?
> + drv_context->len_dma_rx, /* Data Length */
> + flag); /* Flag */
If your slave config command is working then replace this
with ->device_prep_slave_sg() and drop these address
encoding through memcpy calls.
> + /* 3. prepare the TX dma transfer */
> + if (drv_context->tx_dma) {
> + txdesc = txchan->device->device_prep_dma_memcpy
> + (txchan, /* DMA Channel */
> + ssdr_addr, /* DAR */
> + drv_context->tx_dma, /* SAR */
> + drv_context->len_dma_tx, /* Data Length */
> + flag); /* Flag */
Dito.
Yours,
Linus Walleij
------------------------------------------------------------------------------
Nokia and AT&T present the 2010 Calling All Innovators-North America contest
Create new apps & games for the Nokia N8 for consumers in U.S. and Canada
$10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing
Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store
http://p.sf.net/sfu/nokia-dev2dev
_______________________________________________
spi-devel-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spi-devel-general