18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PXA2xx SPI DMA engine support. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013, Intel Corporation 68c2ecf20Sopenharmony_ci * Author: Mika Westerberg <mika.westerberg@linux.intel.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 118c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 128c2ecf20Sopenharmony_ci#include <linux/pxa2xx_ssp.h> 138c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 148c2ecf20Sopenharmony_ci#include <linux/sizes.h> 158c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 168c2ecf20Sopenharmony_ci#include <linux/spi/pxa2xx_spi.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "spi-pxa2xx.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, 218c2ecf20Sopenharmony_ci bool error) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct spi_message *msg = drv_data->controller->cur_msg; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci /* 268c2ecf20Sopenharmony_ci * It is possible that one CPU is handling ROR interrupt and other 278c2ecf20Sopenharmony_ci * just gets DMA completion. Calling pump_transfers() twice for the 288c2ecf20Sopenharmony_ci * same transfer leads to problems thus we prevent concurrent calls 298c2ecf20Sopenharmony_ci * by using ->dma_running. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&drv_data->dma_running)) { 328c2ecf20Sopenharmony_ci /* 338c2ecf20Sopenharmony_ci * If the other CPU is still handling the ROR interrupt we 348c2ecf20Sopenharmony_ci * might not know about the error yet. So we re-check the 358c2ecf20Sopenharmony_ci * ROR bit here before we clear the status register. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci if (!error) { 388c2ecf20Sopenharmony_ci u32 status = pxa2xx_spi_read(drv_data, SSSR) 398c2ecf20Sopenharmony_ci & drv_data->mask_sr; 408c2ecf20Sopenharmony_ci error = status & SSSR_ROR; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* Clear status & disable interrupts */ 448c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, 458c2ecf20Sopenharmony_ci pxa2xx_spi_read(drv_data, SSCR1) 468c2ecf20Sopenharmony_ci & ~drv_data->dma_cr1); 478c2ecf20Sopenharmony_ci write_SSSR_CS(drv_data, drv_data->clear_sr); 488c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 498c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSTO, 0); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (error) { 528c2ecf20Sopenharmony_ci /* In case we got an error we disable the SSP now */ 538c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, 548c2ecf20Sopenharmony_ci pxa2xx_spi_read(drv_data, SSCR0) 558c2ecf20Sopenharmony_ci & ~SSCR0_SSE); 568c2ecf20Sopenharmony_ci msg->status = -EIO; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci spi_finalize_current_transfer(drv_data->controller); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void pxa2xx_spi_dma_callback(void *data) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci pxa2xx_spi_dma_transfer_complete(data, false); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor * 698c2ecf20Sopenharmony_cipxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, 708c2ecf20Sopenharmony_ci enum dma_transfer_direction dir, 718c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct chip_data *chip = 748c2ecf20Sopenharmony_ci spi_get_ctldata(drv_data->controller->cur_msg->spi); 758c2ecf20Sopenharmony_ci enum dma_slave_buswidth width; 768c2ecf20Sopenharmony_ci struct dma_slave_config cfg; 778c2ecf20Sopenharmony_ci struct dma_chan *chan; 788c2ecf20Sopenharmony_ci struct sg_table *sgt; 798c2ecf20Sopenharmony_ci int ret; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci switch (drv_data->n_bytes) { 828c2ecf20Sopenharmony_ci case 1: 838c2ecf20Sopenharmony_ci width = DMA_SLAVE_BUSWIDTH_1_BYTE; 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci case 2: 868c2ecf20Sopenharmony_ci width = DMA_SLAVE_BUSWIDTH_2_BYTES; 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci default: 898c2ecf20Sopenharmony_ci width = DMA_SLAVE_BUSWIDTH_4_BYTES; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 948c2ecf20Sopenharmony_ci cfg.direction = dir; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (dir == DMA_MEM_TO_DEV) { 978c2ecf20Sopenharmony_ci cfg.dst_addr = drv_data->ssdr_physical; 988c2ecf20Sopenharmony_ci cfg.dst_addr_width = width; 998c2ecf20Sopenharmony_ci cfg.dst_maxburst = chip->dma_burst_size; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci sgt = &xfer->tx_sg; 1028c2ecf20Sopenharmony_ci chan = drv_data->controller->dma_tx; 1038c2ecf20Sopenharmony_ci } else { 1048c2ecf20Sopenharmony_ci cfg.src_addr = drv_data->ssdr_physical; 1058c2ecf20Sopenharmony_ci cfg.src_addr_width = width; 1068c2ecf20Sopenharmony_ci cfg.src_maxburst = chip->dma_burst_size; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci sgt = &xfer->rx_sg; 1098c2ecf20Sopenharmony_ci chan = drv_data->controller->dma_rx; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci ret = dmaengine_slave_config(chan, &cfg); 1138c2ecf20Sopenharmony_ci if (ret) { 1148c2ecf20Sopenharmony_ci dev_warn(&drv_data->pdev->dev, "DMA slave config failed\n"); 1158c2ecf20Sopenharmony_ci return NULL; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return dmaengine_prep_slave_sg(chan, sgt->sgl, sgt->nents, dir, 1198c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ciirqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci u32 status; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr; 1278c2ecf20Sopenharmony_ci if (status & SSSR_ROR) { 1288c2ecf20Sopenharmony_ci dev_err(&drv_data->pdev->dev, "FIFO overrun\n"); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci dmaengine_terminate_async(drv_data->controller->dma_rx); 1318c2ecf20Sopenharmony_ci dmaengine_terminate_async(drv_data->controller->dma_tx); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci pxa2xx_spi_dma_transfer_complete(drv_data, true); 1348c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return IRQ_NONE; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ciint pxa2xx_spi_dma_prepare(struct driver_data *drv_data, 1418c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *tx_desc, *rx_desc; 1448c2ecf20Sopenharmony_ci int err; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV, xfer); 1478c2ecf20Sopenharmony_ci if (!tx_desc) { 1488c2ecf20Sopenharmony_ci dev_err(&drv_data->pdev->dev, 1498c2ecf20Sopenharmony_ci "failed to get DMA TX descriptor\n"); 1508c2ecf20Sopenharmony_ci err = -EBUSY; 1518c2ecf20Sopenharmony_ci goto err_tx; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM, xfer); 1558c2ecf20Sopenharmony_ci if (!rx_desc) { 1568c2ecf20Sopenharmony_ci dev_err(&drv_data->pdev->dev, 1578c2ecf20Sopenharmony_ci "failed to get DMA RX descriptor\n"); 1588c2ecf20Sopenharmony_ci err = -EBUSY; 1598c2ecf20Sopenharmony_ci goto err_rx; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* We are ready when RX completes */ 1638c2ecf20Sopenharmony_ci rx_desc->callback = pxa2xx_spi_dma_callback; 1648c2ecf20Sopenharmony_ci rx_desc->callback_param = drv_data; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci dmaengine_submit(rx_desc); 1678c2ecf20Sopenharmony_ci dmaengine_submit(tx_desc); 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cierr_rx: 1718c2ecf20Sopenharmony_ci dmaengine_terminate_async(drv_data->controller->dma_tx); 1728c2ecf20Sopenharmony_cierr_tx: 1738c2ecf20Sopenharmony_ci return err; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_civoid pxa2xx_spi_dma_start(struct driver_data *drv_data) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci dma_async_issue_pending(drv_data->controller->dma_rx); 1798c2ecf20Sopenharmony_ci dma_async_issue_pending(drv_data->controller->dma_tx); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci atomic_set(&drv_data->dma_running, 1); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_civoid pxa2xx_spi_dma_stop(struct driver_data *drv_data) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci atomic_set(&drv_data->dma_running, 0); 1878c2ecf20Sopenharmony_ci dmaengine_terminate_sync(drv_data->controller->dma_rx); 1888c2ecf20Sopenharmony_ci dmaengine_terminate_sync(drv_data->controller->dma_tx); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ciint pxa2xx_spi_dma_setup(struct driver_data *drv_data) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct pxa2xx_spi_controller *pdata = drv_data->controller_info; 1948c2ecf20Sopenharmony_ci struct device *dev = &drv_data->pdev->dev; 1958c2ecf20Sopenharmony_ci struct spi_controller *controller = drv_data->controller; 1968c2ecf20Sopenharmony_ci dma_cap_mask_t mask; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci dma_cap_zero(mask); 1998c2ecf20Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci controller->dma_tx = dma_request_slave_channel_compat(mask, 2028c2ecf20Sopenharmony_ci pdata->dma_filter, pdata->tx_param, dev, "tx"); 2038c2ecf20Sopenharmony_ci if (!controller->dma_tx) 2048c2ecf20Sopenharmony_ci return -ENODEV; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci controller->dma_rx = dma_request_slave_channel_compat(mask, 2078c2ecf20Sopenharmony_ci pdata->dma_filter, pdata->rx_param, dev, "rx"); 2088c2ecf20Sopenharmony_ci if (!controller->dma_rx) { 2098c2ecf20Sopenharmony_ci dma_release_channel(controller->dma_tx); 2108c2ecf20Sopenharmony_ci controller->dma_tx = NULL; 2118c2ecf20Sopenharmony_ci return -ENODEV; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return 0; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_civoid pxa2xx_spi_dma_release(struct driver_data *drv_data) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct spi_controller *controller = drv_data->controller; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (controller->dma_rx) { 2228c2ecf20Sopenharmony_ci dmaengine_terminate_sync(controller->dma_rx); 2238c2ecf20Sopenharmony_ci dma_release_channel(controller->dma_rx); 2248c2ecf20Sopenharmony_ci controller->dma_rx = NULL; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci if (controller->dma_tx) { 2278c2ecf20Sopenharmony_ci dmaengine_terminate_sync(controller->dma_tx); 2288c2ecf20Sopenharmony_ci dma_release_channel(controller->dma_tx); 2298c2ecf20Sopenharmony_ci controller->dma_tx = NULL; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciint pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip, 2348c2ecf20Sopenharmony_ci struct spi_device *spi, 2358c2ecf20Sopenharmony_ci u8 bits_per_word, u32 *burst_code, 2368c2ecf20Sopenharmony_ci u32 *threshold) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct pxa2xx_spi_chip *chip_info = spi->controller_data; 2398c2ecf20Sopenharmony_ci struct driver_data *drv_data = spi_controller_get_devdata(spi->controller); 2408c2ecf20Sopenharmony_ci u32 dma_burst_size = drv_data->controller_info->dma_burst_size; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* 2438c2ecf20Sopenharmony_ci * If the DMA burst size is given in chip_info we use that, 2448c2ecf20Sopenharmony_ci * otherwise we use the default. Also we use the default FIFO 2458c2ecf20Sopenharmony_ci * thresholds for now. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci *burst_code = chip_info ? chip_info->dma_burst_size : dma_burst_size; 2488c2ecf20Sopenharmony_ci *threshold = SSCR1_RxTresh(RX_THRESH_DFLT) 2498c2ecf20Sopenharmony_ci | SSCR1_TxTresh(TX_THRESH_DFLT); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 253