2010/10/22 Alan Cox <a...@lxorguk.ukuu.org.uk>: > From: Mathieu SOULARD <mathieux.soul...@intel.com> > (...) > +/** > + * 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 spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general