18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Freescale SPI controller driver cpm functions. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Maintainer: Kumar Gala 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2006 Polycom, Inc. 88c2ecf20Sopenharmony_ci * Copyright 2010 Freescale Semiconductor, Inc. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * CPM SPI and QE buffer descriptors mode support: 118c2ecf20Sopenharmony_ci * Copyright (c) 2009 MontaVista Software, Inc. 128c2ecf20Sopenharmony_ci * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#include <asm/cpm.h> 158c2ecf20Sopenharmony_ci#include <soc/fsl/qe/qe.h> 168c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 178c2ecf20Sopenharmony_ci#include <linux/fsl_devices.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/of_address.h> 218c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 228c2ecf20Sopenharmony_ci#include <linux/types.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 248c2ecf20Sopenharmony_ci#include <linux/byteorder/generic.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "spi-fsl-cpm.h" 278c2ecf20Sopenharmony_ci#include "spi-fsl-lib.h" 288c2ecf20Sopenharmony_ci#include "spi-fsl-spi.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* CPM1 and CPM2 are mutually exclusive. */ 318c2ecf20Sopenharmony_ci#ifdef CONFIG_CPM1 328c2ecf20Sopenharmony_ci#include <asm/cpm1.h> 338c2ecf20Sopenharmony_ci#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0) 348c2ecf20Sopenharmony_ci#else 358c2ecf20Sopenharmony_ci#include <asm/cpm2.h> 368c2ecf20Sopenharmony_ci#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0) 378c2ecf20Sopenharmony_ci#endif 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define SPIE_TXB 0x00000200 /* Last char is written to tx fifo */ 408c2ecf20Sopenharmony_ci#define SPIE_RXB 0x00000100 /* Last char is written to rx buf */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* SPCOM register values */ 438c2ecf20Sopenharmony_ci#define SPCOM_STR (1 << 23) /* Start transmit */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define SPI_PRAM_SIZE 0x100 468c2ecf20Sopenharmony_ci#define SPI_MRBLR ((unsigned int)PAGE_SIZE) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void *fsl_dummy_rx; 498c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(fsl_dummy_rx_lock); 508c2ecf20Sopenharmony_cistatic int fsl_dummy_rx_refcnt; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_civoid fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci if (mspi->flags & SPI_QE) { 558c2ecf20Sopenharmony_ci qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock, 568c2ecf20Sopenharmony_ci QE_CR_PROTOCOL_UNSPECIFIED, 0); 578c2ecf20Sopenharmony_ci } else { 588c2ecf20Sopenharmony_ci if (mspi->flags & SPI_CPM1) { 598c2ecf20Sopenharmony_ci out_be32(&mspi->pram->rstate, 0); 608c2ecf20Sopenharmony_ci out_be16(&mspi->pram->rbptr, 618c2ecf20Sopenharmony_ci in_be16(&mspi->pram->rbase)); 628c2ecf20Sopenharmony_ci out_be32(&mspi->pram->tstate, 0); 638c2ecf20Sopenharmony_ci out_be16(&mspi->pram->tbptr, 648c2ecf20Sopenharmony_ci in_be16(&mspi->pram->tbase)); 658c2ecf20Sopenharmony_ci } else { 668c2ecf20Sopenharmony_ci cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX); 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_spi_cpm_reinit_txrx); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd; 758c2ecf20Sopenharmony_ci struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd; 768c2ecf20Sopenharmony_ci unsigned int xfer_len = min(mspi->count, SPI_MRBLR); 778c2ecf20Sopenharmony_ci unsigned int xfer_ofs; 788c2ecf20Sopenharmony_ci struct fsl_spi_reg *reg_base = mspi->reg_base; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci xfer_ofs = mspi->xfer_in_progress->len - mspi->count; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (mspi->rx_dma == mspi->dma_dummy_rx) 838c2ecf20Sopenharmony_ci out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma); 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs); 868c2ecf20Sopenharmony_ci out_be16(&rx_bd->cbd_datlen, 0); 878c2ecf20Sopenharmony_ci out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (mspi->tx_dma == mspi->dma_dummy_tx) 908c2ecf20Sopenharmony_ci out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma); 918c2ecf20Sopenharmony_ci else 928c2ecf20Sopenharmony_ci out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs); 938c2ecf20Sopenharmony_ci out_be16(&tx_bd->cbd_datlen, xfer_len); 948c2ecf20Sopenharmony_ci out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP | 958c2ecf20Sopenharmony_ci BD_SC_LAST); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* start transfer */ 988c2ecf20Sopenharmony_ci mpc8xxx_spi_write_reg(®_base->command, SPCOM_STR); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciint fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, 1028c2ecf20Sopenharmony_ci struct spi_transfer *t, bool is_dma_mapped) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct device *dev = mspi->dev; 1058c2ecf20Sopenharmony_ci struct fsl_spi_reg *reg_base = mspi->reg_base; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (is_dma_mapped) { 1088c2ecf20Sopenharmony_ci mspi->map_tx_dma = 0; 1098c2ecf20Sopenharmony_ci mspi->map_rx_dma = 0; 1108c2ecf20Sopenharmony_ci } else { 1118c2ecf20Sopenharmony_ci mspi->map_tx_dma = 1; 1128c2ecf20Sopenharmony_ci mspi->map_rx_dma = 1; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (!t->tx_buf) { 1168c2ecf20Sopenharmony_ci mspi->tx_dma = mspi->dma_dummy_tx; 1178c2ecf20Sopenharmony_ci mspi->map_tx_dma = 0; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (!t->rx_buf) { 1218c2ecf20Sopenharmony_ci mspi->rx_dma = mspi->dma_dummy_rx; 1228c2ecf20Sopenharmony_ci mspi->map_rx_dma = 0; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci if (t->bits_per_word == 16 && t->tx_buf) { 1258c2ecf20Sopenharmony_ci const u16 *src = t->tx_buf; 1268c2ecf20Sopenharmony_ci u16 *dst; 1278c2ecf20Sopenharmony_ci int i; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci dst = kmalloc(t->len, GFP_KERNEL); 1308c2ecf20Sopenharmony_ci if (!dst) 1318c2ecf20Sopenharmony_ci return -ENOMEM; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci for (i = 0; i < t->len >> 1; i++) 1348c2ecf20Sopenharmony_ci dst[i] = cpu_to_le16p(src + i); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci mspi->tx = dst; 1378c2ecf20Sopenharmony_ci mspi->map_tx_dma = 1; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (mspi->map_tx_dma) { 1418c2ecf20Sopenharmony_ci void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */ 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len, 1448c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 1458c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, mspi->tx_dma)) { 1468c2ecf20Sopenharmony_ci dev_err(dev, "unable to map tx dma\n"); 1478c2ecf20Sopenharmony_ci return -ENOMEM; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci } else if (t->tx_buf) { 1508c2ecf20Sopenharmony_ci mspi->tx_dma = t->tx_dma; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (mspi->map_rx_dma) { 1548c2ecf20Sopenharmony_ci mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len, 1558c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 1568c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, mspi->rx_dma)) { 1578c2ecf20Sopenharmony_ci dev_err(dev, "unable to map rx dma\n"); 1588c2ecf20Sopenharmony_ci goto err_rx_dma; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci } else if (t->rx_buf) { 1618c2ecf20Sopenharmony_ci mspi->rx_dma = t->rx_dma; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* enable rx ints */ 1658c2ecf20Sopenharmony_ci mpc8xxx_spi_write_reg(®_base->mask, SPIE_RXB); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci mspi->xfer_in_progress = t; 1688c2ecf20Sopenharmony_ci mspi->count = t->len; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* start CPM transfers */ 1718c2ecf20Sopenharmony_ci fsl_spi_cpm_bufs_start(mspi); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cierr_rx_dma: 1768c2ecf20Sopenharmony_ci if (mspi->map_tx_dma) 1778c2ecf20Sopenharmony_ci dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); 1788c2ecf20Sopenharmony_ci return -ENOMEM; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_civoid fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct device *dev = mspi->dev; 1858c2ecf20Sopenharmony_ci struct spi_transfer *t = mspi->xfer_in_progress; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (mspi->map_tx_dma) 1888c2ecf20Sopenharmony_ci dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); 1898c2ecf20Sopenharmony_ci if (mspi->map_rx_dma) 1908c2ecf20Sopenharmony_ci dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE); 1918c2ecf20Sopenharmony_ci mspi->xfer_in_progress = NULL; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (t->bits_per_word == 16 && t->rx_buf) { 1948c2ecf20Sopenharmony_ci int i; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci for (i = 0; i < t->len; i += 2) 1978c2ecf20Sopenharmony_ci le16_to_cpus(t->rx_buf + i); 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs_complete); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_civoid fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci u16 len; 2058c2ecf20Sopenharmony_ci struct fsl_spi_reg *reg_base = mspi->reg_base; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__, 2088c2ecf20Sopenharmony_ci in_be16(&mspi->rx_bd->cbd_datlen), mspi->count); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci len = in_be16(&mspi->rx_bd->cbd_datlen); 2118c2ecf20Sopenharmony_ci if (len > mspi->count) { 2128c2ecf20Sopenharmony_ci WARN_ON(1); 2138c2ecf20Sopenharmony_ci len = mspi->count; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* Clear the events */ 2178c2ecf20Sopenharmony_ci mpc8xxx_spi_write_reg(®_base->event, events); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci mspi->count -= len; 2208c2ecf20Sopenharmony_ci if (mspi->count) 2218c2ecf20Sopenharmony_ci fsl_spi_cpm_bufs_start(mspi); 2228c2ecf20Sopenharmony_ci else 2238c2ecf20Sopenharmony_ci complete(&mspi->done); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_spi_cpm_irq); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void *fsl_spi_alloc_dummy_rx(void) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci mutex_lock(&fsl_dummy_rx_lock); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (!fsl_dummy_rx) 2328c2ecf20Sopenharmony_ci fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL); 2338c2ecf20Sopenharmony_ci if (fsl_dummy_rx) 2348c2ecf20Sopenharmony_ci fsl_dummy_rx_refcnt++; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci mutex_unlock(&fsl_dummy_rx_lock); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return fsl_dummy_rx; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void fsl_spi_free_dummy_rx(void) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci mutex_lock(&fsl_dummy_rx_lock); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci switch (fsl_dummy_rx_refcnt) { 2468c2ecf20Sopenharmony_ci case 0: 2478c2ecf20Sopenharmony_ci WARN_ON(1); 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci case 1: 2508c2ecf20Sopenharmony_ci kfree(fsl_dummy_rx); 2518c2ecf20Sopenharmony_ci fsl_dummy_rx = NULL; 2528c2ecf20Sopenharmony_ci fallthrough; 2538c2ecf20Sopenharmony_ci default: 2548c2ecf20Sopenharmony_ci fsl_dummy_rx_refcnt--; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci mutex_unlock(&fsl_dummy_rx_lock); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct device *dev = mspi->dev; 2648c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 2658c2ecf20Sopenharmony_ci const u32 *iprop; 2668c2ecf20Sopenharmony_ci int size; 2678c2ecf20Sopenharmony_ci void __iomem *spi_base; 2688c2ecf20Sopenharmony_ci unsigned long pram_ofs = -ENOMEM; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Can't use of_address_to_resource(), QE muram isn't at 0. */ 2718c2ecf20Sopenharmony_ci iprop = of_get_property(np, "reg", &size); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* QE with a fixed pram location? */ 2748c2ecf20Sopenharmony_ci if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4) 2758c2ecf20Sopenharmony_ci return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* QE but with a dynamic pram location? */ 2788c2ecf20Sopenharmony_ci if (mspi->flags & SPI_QE) { 2798c2ecf20Sopenharmony_ci pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); 2808c2ecf20Sopenharmony_ci qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock, 2818c2ecf20Sopenharmony_ci QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs); 2828c2ecf20Sopenharmony_ci return pram_ofs; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci spi_base = of_iomap(np, 1); 2868c2ecf20Sopenharmony_ci if (spi_base == NULL) 2878c2ecf20Sopenharmony_ci return -EINVAL; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (mspi->flags & SPI_CPM2) { 2908c2ecf20Sopenharmony_ci pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); 2918c2ecf20Sopenharmony_ci out_be16(spi_base, pram_ofs); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci iounmap(spi_base); 2958c2ecf20Sopenharmony_ci return pram_ofs; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciint fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct device *dev = mspi->dev; 3018c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 3028c2ecf20Sopenharmony_ci const u32 *iprop; 3038c2ecf20Sopenharmony_ci int size; 3048c2ecf20Sopenharmony_ci unsigned long bds_ofs; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (!(mspi->flags & SPI_CPM_MODE)) 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (!fsl_spi_alloc_dummy_rx()) 3108c2ecf20Sopenharmony_ci return -ENOMEM; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (mspi->flags & SPI_QE) { 3138c2ecf20Sopenharmony_ci iprop = of_get_property(np, "cell-index", &size); 3148c2ecf20Sopenharmony_ci if (iprop && size == sizeof(*iprop)) 3158c2ecf20Sopenharmony_ci mspi->subblock = *iprop; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci switch (mspi->subblock) { 3188c2ecf20Sopenharmony_ci default: 3198c2ecf20Sopenharmony_ci dev_warn(dev, "cell-index unspecified, assuming SPI1\n"); 3208c2ecf20Sopenharmony_ci fallthrough; 3218c2ecf20Sopenharmony_ci case 0: 3228c2ecf20Sopenharmony_ci mspi->subblock = QE_CR_SUBBLOCK_SPI1; 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci case 1: 3258c2ecf20Sopenharmony_ci mspi->subblock = QE_CR_SUBBLOCK_SPI2; 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (mspi->flags & SPI_CPM1) { 3318c2ecf20Sopenharmony_ci void *pram; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci pram = devm_platform_ioremap_resource(to_platform_device(dev), 3348c2ecf20Sopenharmony_ci 1); 3358c2ecf20Sopenharmony_ci if (IS_ERR(pram)) 3368c2ecf20Sopenharmony_ci mspi->pram = NULL; 3378c2ecf20Sopenharmony_ci else 3388c2ecf20Sopenharmony_ci mspi->pram = pram; 3398c2ecf20Sopenharmony_ci } else { 3408c2ecf20Sopenharmony_ci unsigned long pram_ofs = fsl_spi_cpm_get_pram(mspi); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (IS_ERR_VALUE(pram_ofs)) 3438c2ecf20Sopenharmony_ci mspi->pram = NULL; 3448c2ecf20Sopenharmony_ci else 3458c2ecf20Sopenharmony_ci mspi->pram = cpm_muram_addr(pram_ofs); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci if (mspi->pram == NULL) { 3488c2ecf20Sopenharmony_ci dev_err(dev, "can't allocate spi parameter ram\n"); 3498c2ecf20Sopenharmony_ci goto err_pram; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) + 3538c2ecf20Sopenharmony_ci sizeof(*mspi->rx_bd), 8); 3548c2ecf20Sopenharmony_ci if (IS_ERR_VALUE(bds_ofs)) { 3558c2ecf20Sopenharmony_ci dev_err(dev, "can't allocate bds\n"); 3568c2ecf20Sopenharmony_ci goto err_bds; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE, 3608c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3618c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, mspi->dma_dummy_tx)) { 3628c2ecf20Sopenharmony_ci dev_err(dev, "unable to map dummy tx buffer\n"); 3638c2ecf20Sopenharmony_ci goto err_dummy_tx; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR, 3678c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 3688c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, mspi->dma_dummy_rx)) { 3698c2ecf20Sopenharmony_ci dev_err(dev, "unable to map dummy rx buffer\n"); 3708c2ecf20Sopenharmony_ci goto err_dummy_rx; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci mspi->tx_bd = cpm_muram_addr(bds_ofs); 3748c2ecf20Sopenharmony_ci mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd)); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* Initialize parameter ram. */ 3778c2ecf20Sopenharmony_ci out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd)); 3788c2ecf20Sopenharmony_ci out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd)); 3798c2ecf20Sopenharmony_ci out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL); 3808c2ecf20Sopenharmony_ci out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL); 3818c2ecf20Sopenharmony_ci out_be16(&mspi->pram->mrblr, SPI_MRBLR); 3828c2ecf20Sopenharmony_ci out_be32(&mspi->pram->rstate, 0); 3838c2ecf20Sopenharmony_ci out_be32(&mspi->pram->rdp, 0); 3848c2ecf20Sopenharmony_ci out_be16(&mspi->pram->rbptr, 0); 3858c2ecf20Sopenharmony_ci out_be16(&mspi->pram->rbc, 0); 3868c2ecf20Sopenharmony_ci out_be32(&mspi->pram->rxtmp, 0); 3878c2ecf20Sopenharmony_ci out_be32(&mspi->pram->tstate, 0); 3888c2ecf20Sopenharmony_ci out_be32(&mspi->pram->tdp, 0); 3898c2ecf20Sopenharmony_ci out_be16(&mspi->pram->tbptr, 0); 3908c2ecf20Sopenharmony_ci out_be16(&mspi->pram->tbc, 0); 3918c2ecf20Sopenharmony_ci out_be32(&mspi->pram->txtmp, 0); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cierr_dummy_rx: 3968c2ecf20Sopenharmony_ci dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE); 3978c2ecf20Sopenharmony_cierr_dummy_tx: 3988c2ecf20Sopenharmony_ci cpm_muram_free(bds_ofs); 3998c2ecf20Sopenharmony_cierr_bds: 4008c2ecf20Sopenharmony_ci if (!(mspi->flags & SPI_CPM1)) 4018c2ecf20Sopenharmony_ci cpm_muram_free(cpm_muram_offset(mspi->pram)); 4028c2ecf20Sopenharmony_cierr_pram: 4038c2ecf20Sopenharmony_ci fsl_spi_free_dummy_rx(); 4048c2ecf20Sopenharmony_ci return -ENOMEM; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_spi_cpm_init); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_civoid fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct device *dev = mspi->dev; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (!(mspi->flags & SPI_CPM_MODE)) 4138c2ecf20Sopenharmony_ci return; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE); 4168c2ecf20Sopenharmony_ci dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE); 4178c2ecf20Sopenharmony_ci cpm_muram_free(cpm_muram_offset(mspi->tx_bd)); 4188c2ecf20Sopenharmony_ci if (!(mspi->flags & SPI_CPM1)) 4198c2ecf20Sopenharmony_ci cpm_muram_free(cpm_muram_offset(mspi->pram)); 4208c2ecf20Sopenharmony_ci fsl_spi_free_dummy_rx(); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_spi_cpm_free); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 425