static int tegra_spi_dma_prepare(struct tegra_spi_channel *spi, unsigned int bytes, enum spi_direction dir) { unsigned int todo, wcount; /* * For DMA we need to think of things in terms of word count. * AHB width is fixed at 32-bits. To avoid overrunning * the in/out buffers we must align down. (Note: lowest 2-bits * in WCOUNT register are ignored, and WCOUNT seems to count * words starting at n-1) * * Example: If "bytes" is 7 and we are transferring 1-byte at a time, * WCOUNT should be 4. The remaining 3 bytes must be transferred * using PIO. */ todo = MIN(bytes, SPI_MAX_TRANSFER_BYTES_DMA - TEGRA_DMA_ALIGN_BYTES); todo = ALIGN_DOWN(todo, TEGRA_DMA_ALIGN_BYTES); wcount = ALIGN_DOWN(todo - TEGRA_DMA_ALIGN_BYTES, TEGRA_DMA_ALIGN_BYTES); flush_fifos(spi); if (dir == SPI_SEND) { spi->dma_out = dma_claim(); if (!spi->dma_out) return -1; /* ensure bytes to send will be visible to DMA controller */ dcache_clean_by_mva(spi->out_buf, bytes); write32(&spi->dma_out->regs->apb_ptr, (uintptr_t) & spi->regs->tx_fifo); write32(&spi->dma_out->regs->ahb_ptr, (uintptr_t)spi->out_buf); setbits_le32(&spi->dma_out->regs->csr, APB_CSR_DIR); setup_dma_params(spi, spi->dma_out); write32(&spi->dma_out->regs->wcount, wcount); } else { spi->dma_in = dma_claim(); if (!spi->dma_in) return -1; /* avoid data collisions */ dcache_clean_invalidate_by_mva(spi->in_buf, bytes); write32(&spi->dma_in->regs->apb_ptr, (uintptr_t)&spi->regs->rx_fifo); write32(&spi->dma_in->regs->ahb_ptr, (uintptr_t)spi->in_buf); clrbits_le32(&spi->dma_in->regs->csr, APB_CSR_DIR); setup_dma_params(spi, spi->dma_in); write32(&spi->dma_in->regs->wcount, wcount); } /* BLOCK_SIZE starts at n-1 */ write32(&spi->regs->dma_blk, todo - 1); return todo; }
int pcie_write(char *buf, int size) { volatile char *tmp = (char *)_dma_addr_ptr; int i, tlp_sz, tlp_cnt, nsize; unsigned long long watchdog=0; for(i=0; i < size; i++) { tmp[i] = buf[i]; // todo: is memcpy safe here? } setup_dma_params(size, &nsize, &tlp_sz, &tlp_cnt); setup_read_dma(tlp_sz, tlp_cnt); read_dma_start(); // move data from main memory to FPGA ++__fifowcnt__; // increment local write count while(__fifowcnt__ != read_ctrl(RX_CNT_OFFSET)) { // spin-wait until FPGA consumes entire DMA payload if(++watchdog > TIMEOUT) { printk("timeout\n"); return 0; } } return size; }
int pcie_read(char *buf, int size) { unsigned long long watchdog=0; volatile char *tmp = (char *)_dma_addr_ptr; int i, tlp_sz, tlp_cnt, nsize; //unsigned long long watchdog=0; ++__fiforcnt__; // increment local read count //printk("waiting.... me:%llx it:%x\n", __fiforcnt__, read_ctrl(TX_CNT_OFFSET)); while(__fiforcnt__ != read_ctrl(TX_CNT_OFFSET)) { //printk("waiting.... me:%llx it:%x\n", __fiforcnt__, read_ctrl(TX_CNT_OFFSET)); if(++watchdog > TIMEOUT) { printk("fiforcnt timeout\n"); return 0; } } //printk("done waiting.... me:%llx it:%x\n", __fiforcnt__, read_ctrl(TX_CNT_OFFSET)); setup_dma_params(size, &nsize, &tlp_sz, &tlp_cnt); setup_write_dma(tlp_sz, tlp_cnt); write_dma_start(); // move data from FPGA to main memory // printk("waiting for write_dma_done()\n"); watchdog = 0; while(!write_dma_done()) { if(++watchdog > TIMEOUT) { printk("write dma done timeout\n"); return 0; } } // printk("write_dma_done()\n"); for(i=0; i < size; i++) buf[i] = tmp[i]; return size; }