1e8beacbbSAndreas Larsson /* 2e8beacbbSAndreas Larsson * Freescale SPI controller driver cpm functions. 3e8beacbbSAndreas Larsson * 4e8beacbbSAndreas Larsson * Maintainer: Kumar Gala 5e8beacbbSAndreas Larsson * 6e8beacbbSAndreas Larsson * Copyright (C) 2006 Polycom, Inc. 7e8beacbbSAndreas Larsson * Copyright 2010 Freescale Semiconductor, Inc. 8e8beacbbSAndreas Larsson * 9e8beacbbSAndreas Larsson * CPM SPI and QE buffer descriptors mode support: 10e8beacbbSAndreas Larsson * Copyright (c) 2009 MontaVista Software, Inc. 11e8beacbbSAndreas Larsson * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 12e8beacbbSAndreas Larsson * 13e8beacbbSAndreas Larsson * This program is free software; you can redistribute it and/or modify it 14e8beacbbSAndreas Larsson * under the terms of the GNU General Public License as published by the 15e8beacbbSAndreas Larsson * Free Software Foundation; either version 2 of the License, or (at your 16e8beacbbSAndreas Larsson * option) any later version. 17e8beacbbSAndreas Larsson */ 18e8beacbbSAndreas Larsson #include <linux/types.h> 19e8beacbbSAndreas Larsson #include <linux/kernel.h> 20e8beacbbSAndreas Larsson #include <linux/spi/spi.h> 21e8beacbbSAndreas Larsson #include <linux/fsl_devices.h> 22e8beacbbSAndreas Larsson #include <linux/dma-mapping.h> 23e8beacbbSAndreas Larsson #include <asm/cpm.h> 24e8beacbbSAndreas Larsson #include <asm/qe.h> 25e8beacbbSAndreas Larsson 26e8beacbbSAndreas Larsson #include "spi-fsl-lib.h" 27e8beacbbSAndreas Larsson #include "spi-fsl-cpm.h" 28e8beacbbSAndreas Larsson #include "spi-fsl-spi.h" 29e8beacbbSAndreas Larsson 30e8beacbbSAndreas Larsson /* CPM1 and CPM2 are mutually exclusive. */ 31e8beacbbSAndreas Larsson #ifdef CONFIG_CPM1 32e8beacbbSAndreas Larsson #include <asm/cpm1.h> 33e8beacbbSAndreas Larsson #define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0) 34e8beacbbSAndreas Larsson #else 35e8beacbbSAndreas Larsson #include <asm/cpm2.h> 36e8beacbbSAndreas Larsson #define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0) 37e8beacbbSAndreas Larsson #endif 38e8beacbbSAndreas Larsson 39e8beacbbSAndreas Larsson #define SPIE_TXB 0x00000200 /* Last char is written to tx fifo */ 40e8beacbbSAndreas Larsson #define SPIE_RXB 0x00000100 /* Last char is written to rx buf */ 41e8beacbbSAndreas Larsson 42e8beacbbSAndreas Larsson /* SPCOM register values */ 43e8beacbbSAndreas Larsson #define SPCOM_STR (1 << 23) /* Start transmit */ 44e8beacbbSAndreas Larsson 45e8beacbbSAndreas Larsson #define SPI_PRAM_SIZE 0x100 46e8beacbbSAndreas Larsson #define SPI_MRBLR ((unsigned int)PAGE_SIZE) 47e8beacbbSAndreas Larsson 48e8beacbbSAndreas Larsson static void *fsl_dummy_rx; 49e8beacbbSAndreas Larsson static DEFINE_MUTEX(fsl_dummy_rx_lock); 50e8beacbbSAndreas Larsson static int fsl_dummy_rx_refcnt; 51e8beacbbSAndreas Larsson 52e8beacbbSAndreas Larsson void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi) 53e8beacbbSAndreas Larsson { 54e8beacbbSAndreas Larsson if (mspi->flags & SPI_QE) { 55e8beacbbSAndreas Larsson qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock, 56e8beacbbSAndreas Larsson QE_CR_PROTOCOL_UNSPECIFIED, 0); 57e8beacbbSAndreas Larsson } else { 58e8beacbbSAndreas Larsson cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX); 59e8beacbbSAndreas Larsson if (mspi->flags & SPI_CPM1) { 60e8beacbbSAndreas Larsson out_be16(&mspi->pram->rbptr, 61e8beacbbSAndreas Larsson in_be16(&mspi->pram->rbase)); 62e8beacbbSAndreas Larsson out_be16(&mspi->pram->tbptr, 63e8beacbbSAndreas Larsson in_be16(&mspi->pram->tbase)); 64e8beacbbSAndreas Larsson } 65e8beacbbSAndreas Larsson } 66e8beacbbSAndreas Larsson } 67e8beacbbSAndreas Larsson 68e8beacbbSAndreas Larsson static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) 69e8beacbbSAndreas Larsson { 70e8beacbbSAndreas Larsson struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd; 71e8beacbbSAndreas Larsson struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd; 72e8beacbbSAndreas Larsson unsigned int xfer_len = min(mspi->count, SPI_MRBLR); 73e8beacbbSAndreas Larsson unsigned int xfer_ofs; 74e8beacbbSAndreas Larsson struct fsl_spi_reg *reg_base = mspi->reg_base; 75e8beacbbSAndreas Larsson 76e8beacbbSAndreas Larsson xfer_ofs = mspi->xfer_in_progress->len - mspi->count; 77e8beacbbSAndreas Larsson 78e8beacbbSAndreas Larsson if (mspi->rx_dma == mspi->dma_dummy_rx) 79e8beacbbSAndreas Larsson out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma); 80e8beacbbSAndreas Larsson else 81e8beacbbSAndreas Larsson out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs); 82e8beacbbSAndreas Larsson out_be16(&rx_bd->cbd_datlen, 0); 83e8beacbbSAndreas Larsson out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP); 84e8beacbbSAndreas Larsson 85e8beacbbSAndreas Larsson if (mspi->tx_dma == mspi->dma_dummy_tx) 86e8beacbbSAndreas Larsson out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma); 87e8beacbbSAndreas Larsson else 88e8beacbbSAndreas Larsson out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs); 89e8beacbbSAndreas Larsson out_be16(&tx_bd->cbd_datlen, xfer_len); 90e8beacbbSAndreas Larsson out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP | 91e8beacbbSAndreas Larsson BD_SC_LAST); 92e8beacbbSAndreas Larsson 93e8beacbbSAndreas Larsson /* start transfer */ 94e8beacbbSAndreas Larsson mpc8xxx_spi_write_reg(®_base->command, SPCOM_STR); 95e8beacbbSAndreas Larsson } 96e8beacbbSAndreas Larsson 97e8beacbbSAndreas Larsson int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, 98e8beacbbSAndreas Larsson struct spi_transfer *t, bool is_dma_mapped) 99e8beacbbSAndreas Larsson { 100e8beacbbSAndreas Larsson struct device *dev = mspi->dev; 101e8beacbbSAndreas Larsson struct fsl_spi_reg *reg_base = mspi->reg_base; 102e8beacbbSAndreas Larsson 103e8beacbbSAndreas Larsson if (is_dma_mapped) { 104e8beacbbSAndreas Larsson mspi->map_tx_dma = 0; 105e8beacbbSAndreas Larsson mspi->map_rx_dma = 0; 106e8beacbbSAndreas Larsson } else { 107e8beacbbSAndreas Larsson mspi->map_tx_dma = 1; 108e8beacbbSAndreas Larsson mspi->map_rx_dma = 1; 109e8beacbbSAndreas Larsson } 110e8beacbbSAndreas Larsson 111e8beacbbSAndreas Larsson if (!t->tx_buf) { 112e8beacbbSAndreas Larsson mspi->tx_dma = mspi->dma_dummy_tx; 113e8beacbbSAndreas Larsson mspi->map_tx_dma = 0; 114e8beacbbSAndreas Larsson } 115e8beacbbSAndreas Larsson 116e8beacbbSAndreas Larsson if (!t->rx_buf) { 117e8beacbbSAndreas Larsson mspi->rx_dma = mspi->dma_dummy_rx; 118e8beacbbSAndreas Larsson mspi->map_rx_dma = 0; 119e8beacbbSAndreas Larsson } 120e8beacbbSAndreas Larsson 121e8beacbbSAndreas Larsson if (mspi->map_tx_dma) { 122e8beacbbSAndreas Larsson void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */ 123e8beacbbSAndreas Larsson 124e8beacbbSAndreas Larsson mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len, 125e8beacbbSAndreas Larsson DMA_TO_DEVICE); 126e8beacbbSAndreas Larsson if (dma_mapping_error(dev, mspi->tx_dma)) { 127e8beacbbSAndreas Larsson dev_err(dev, "unable to map tx dma\n"); 128e8beacbbSAndreas Larsson return -ENOMEM; 129e8beacbbSAndreas Larsson } 130e8beacbbSAndreas Larsson } else if (t->tx_buf) { 131e8beacbbSAndreas Larsson mspi->tx_dma = t->tx_dma; 132e8beacbbSAndreas Larsson } 133e8beacbbSAndreas Larsson 134e8beacbbSAndreas Larsson if (mspi->map_rx_dma) { 135e8beacbbSAndreas Larsson mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len, 136e8beacbbSAndreas Larsson DMA_FROM_DEVICE); 137e8beacbbSAndreas Larsson if (dma_mapping_error(dev, mspi->rx_dma)) { 138e8beacbbSAndreas Larsson dev_err(dev, "unable to map rx dma\n"); 139e8beacbbSAndreas Larsson goto err_rx_dma; 140e8beacbbSAndreas Larsson } 141e8beacbbSAndreas Larsson } else if (t->rx_buf) { 142e8beacbbSAndreas Larsson mspi->rx_dma = t->rx_dma; 143e8beacbbSAndreas Larsson } 144e8beacbbSAndreas Larsson 145e8beacbbSAndreas Larsson /* enable rx ints */ 146e8beacbbSAndreas Larsson mpc8xxx_spi_write_reg(®_base->mask, SPIE_RXB); 147e8beacbbSAndreas Larsson 148e8beacbbSAndreas Larsson mspi->xfer_in_progress = t; 149e8beacbbSAndreas Larsson mspi->count = t->len; 150e8beacbbSAndreas Larsson 151e8beacbbSAndreas Larsson /* start CPM transfers */ 152e8beacbbSAndreas Larsson fsl_spi_cpm_bufs_start(mspi); 153e8beacbbSAndreas Larsson 154e8beacbbSAndreas Larsson return 0; 155e8beacbbSAndreas Larsson 156e8beacbbSAndreas Larsson err_rx_dma: 157e8beacbbSAndreas Larsson if (mspi->map_tx_dma) 158e8beacbbSAndreas Larsson dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); 159e8beacbbSAndreas Larsson return -ENOMEM; 160e8beacbbSAndreas Larsson } 161e8beacbbSAndreas Larsson 162e8beacbbSAndreas Larsson void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) 163e8beacbbSAndreas Larsson { 164e8beacbbSAndreas Larsson struct device *dev = mspi->dev; 165e8beacbbSAndreas Larsson struct spi_transfer *t = mspi->xfer_in_progress; 166e8beacbbSAndreas Larsson 167e8beacbbSAndreas Larsson if (mspi->map_tx_dma) 168e8beacbbSAndreas Larsson dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); 169e8beacbbSAndreas Larsson if (mspi->map_rx_dma) 170e8beacbbSAndreas Larsson dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE); 171e8beacbbSAndreas Larsson mspi->xfer_in_progress = NULL; 172e8beacbbSAndreas Larsson } 173e8beacbbSAndreas Larsson 174e8beacbbSAndreas Larsson void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) 175e8beacbbSAndreas Larsson { 176e8beacbbSAndreas Larsson u16 len; 177e8beacbbSAndreas Larsson struct fsl_spi_reg *reg_base = mspi->reg_base; 178e8beacbbSAndreas Larsson 179e8beacbbSAndreas Larsson dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__, 180e8beacbbSAndreas Larsson in_be16(&mspi->rx_bd->cbd_datlen), mspi->count); 181e8beacbbSAndreas Larsson 182e8beacbbSAndreas Larsson len = in_be16(&mspi->rx_bd->cbd_datlen); 183e8beacbbSAndreas Larsson if (len > mspi->count) { 184e8beacbbSAndreas Larsson WARN_ON(1); 185e8beacbbSAndreas Larsson len = mspi->count; 186e8beacbbSAndreas Larsson } 187e8beacbbSAndreas Larsson 188e8beacbbSAndreas Larsson /* Clear the events */ 189e8beacbbSAndreas Larsson mpc8xxx_spi_write_reg(®_base->event, events); 190e8beacbbSAndreas Larsson 191e8beacbbSAndreas Larsson mspi->count -= len; 192e8beacbbSAndreas Larsson if (mspi->count) 193e8beacbbSAndreas Larsson fsl_spi_cpm_bufs_start(mspi); 194e8beacbbSAndreas Larsson else 195e8beacbbSAndreas Larsson complete(&mspi->done); 196e8beacbbSAndreas Larsson } 197e8beacbbSAndreas Larsson 198e8beacbbSAndreas Larsson static void *fsl_spi_alloc_dummy_rx(void) 199e8beacbbSAndreas Larsson { 200e8beacbbSAndreas Larsson mutex_lock(&fsl_dummy_rx_lock); 201e8beacbbSAndreas Larsson 202e8beacbbSAndreas Larsson if (!fsl_dummy_rx) 203e8beacbbSAndreas Larsson fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL); 204e8beacbbSAndreas Larsson if (fsl_dummy_rx) 205e8beacbbSAndreas Larsson fsl_dummy_rx_refcnt++; 206e8beacbbSAndreas Larsson 207e8beacbbSAndreas Larsson mutex_unlock(&fsl_dummy_rx_lock); 208e8beacbbSAndreas Larsson 209e8beacbbSAndreas Larsson return fsl_dummy_rx; 210e8beacbbSAndreas Larsson } 211e8beacbbSAndreas Larsson 212e8beacbbSAndreas Larsson static void fsl_spi_free_dummy_rx(void) 213e8beacbbSAndreas Larsson { 214e8beacbbSAndreas Larsson mutex_lock(&fsl_dummy_rx_lock); 215e8beacbbSAndreas Larsson 216e8beacbbSAndreas Larsson switch (fsl_dummy_rx_refcnt) { 217e8beacbbSAndreas Larsson case 0: 218e8beacbbSAndreas Larsson WARN_ON(1); 219e8beacbbSAndreas Larsson break; 220e8beacbbSAndreas Larsson case 1: 221e8beacbbSAndreas Larsson kfree(fsl_dummy_rx); 222e8beacbbSAndreas Larsson fsl_dummy_rx = NULL; 223e8beacbbSAndreas Larsson /* fall through */ 224e8beacbbSAndreas Larsson default: 225e8beacbbSAndreas Larsson fsl_dummy_rx_refcnt--; 226e8beacbbSAndreas Larsson break; 227e8beacbbSAndreas Larsson } 228e8beacbbSAndreas Larsson 229e8beacbbSAndreas Larsson mutex_unlock(&fsl_dummy_rx_lock); 230e8beacbbSAndreas Larsson } 231e8beacbbSAndreas Larsson 232e8beacbbSAndreas Larsson static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) 233e8beacbbSAndreas Larsson { 234e8beacbbSAndreas Larsson struct device *dev = mspi->dev; 235e8beacbbSAndreas Larsson struct device_node *np = dev->of_node; 236e8beacbbSAndreas Larsson const u32 *iprop; 237e8beacbbSAndreas Larsson int size; 238e8beacbbSAndreas Larsson void __iomem *spi_base; 239e8beacbbSAndreas Larsson unsigned long pram_ofs = -ENOMEM; 240e8beacbbSAndreas Larsson 241e8beacbbSAndreas Larsson /* Can't use of_address_to_resource(), QE muram isn't at 0. */ 242e8beacbbSAndreas Larsson iprop = of_get_property(np, "reg", &size); 243e8beacbbSAndreas Larsson 244e8beacbbSAndreas Larsson /* QE with a fixed pram location? */ 245e8beacbbSAndreas Larsson if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4) 246e8beacbbSAndreas Larsson return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE); 247e8beacbbSAndreas Larsson 248e8beacbbSAndreas Larsson /* QE but with a dynamic pram location? */ 249e8beacbbSAndreas Larsson if (mspi->flags & SPI_QE) { 250e8beacbbSAndreas Larsson pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); 251e8beacbbSAndreas Larsson qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock, 252e8beacbbSAndreas Larsson QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs); 253e8beacbbSAndreas Larsson return pram_ofs; 254e8beacbbSAndreas Larsson } 255e8beacbbSAndreas Larsson 256e8beacbbSAndreas Larsson spi_base = of_iomap(np, 1); 257e8beacbbSAndreas Larsson if (spi_base == NULL) 258e8beacbbSAndreas Larsson return -EINVAL; 259e8beacbbSAndreas Larsson 260e8beacbbSAndreas Larsson if (mspi->flags & SPI_CPM2) { 261e8beacbbSAndreas Larsson pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); 262e8beacbbSAndreas Larsson out_be16(spi_base, pram_ofs); 263e8beacbbSAndreas Larsson } else { 264e8beacbbSAndreas Larsson struct spi_pram __iomem *pram = spi_base; 265e8beacbbSAndreas Larsson u16 rpbase = in_be16(&pram->rpbase); 266e8beacbbSAndreas Larsson 267e8beacbbSAndreas Larsson /* Microcode relocation patch applied? */ 268e8beacbbSAndreas Larsson if (rpbase) { 269e8beacbbSAndreas Larsson pram_ofs = rpbase; 270e8beacbbSAndreas Larsson } else { 271e8beacbbSAndreas Larsson pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); 272e8beacbbSAndreas Larsson out_be16(spi_base, pram_ofs); 273e8beacbbSAndreas Larsson } 274e8beacbbSAndreas Larsson } 275e8beacbbSAndreas Larsson 276e8beacbbSAndreas Larsson iounmap(spi_base); 277e8beacbbSAndreas Larsson return pram_ofs; 278e8beacbbSAndreas Larsson } 279e8beacbbSAndreas Larsson 280e8beacbbSAndreas Larsson int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) 281e8beacbbSAndreas Larsson { 282e8beacbbSAndreas Larsson struct device *dev = mspi->dev; 283e8beacbbSAndreas Larsson struct device_node *np = dev->of_node; 284e8beacbbSAndreas Larsson const u32 *iprop; 285e8beacbbSAndreas Larsson int size; 286e8beacbbSAndreas Larsson unsigned long pram_ofs; 287e8beacbbSAndreas Larsson unsigned long bds_ofs; 288e8beacbbSAndreas Larsson 289e8beacbbSAndreas Larsson if (!(mspi->flags & SPI_CPM_MODE)) 290e8beacbbSAndreas Larsson return 0; 291e8beacbbSAndreas Larsson 292e8beacbbSAndreas Larsson if (!fsl_spi_alloc_dummy_rx()) 293e8beacbbSAndreas Larsson return -ENOMEM; 294e8beacbbSAndreas Larsson 295e8beacbbSAndreas Larsson if (mspi->flags & SPI_QE) { 296e8beacbbSAndreas Larsson iprop = of_get_property(np, "cell-index", &size); 297e8beacbbSAndreas Larsson if (iprop && size == sizeof(*iprop)) 298e8beacbbSAndreas Larsson mspi->subblock = *iprop; 299e8beacbbSAndreas Larsson 300e8beacbbSAndreas Larsson switch (mspi->subblock) { 301e8beacbbSAndreas Larsson default: 302*a1829d2bSJarkko Nikula dev_warn(dev, "cell-index unspecified, assuming SPI1\n"); 303e8beacbbSAndreas Larsson /* fall through */ 304e8beacbbSAndreas Larsson case 0: 305e8beacbbSAndreas Larsson mspi->subblock = QE_CR_SUBBLOCK_SPI1; 306e8beacbbSAndreas Larsson break; 307e8beacbbSAndreas Larsson case 1: 308e8beacbbSAndreas Larsson mspi->subblock = QE_CR_SUBBLOCK_SPI2; 309e8beacbbSAndreas Larsson break; 310e8beacbbSAndreas Larsson } 311e8beacbbSAndreas Larsson } 312e8beacbbSAndreas Larsson 313e8beacbbSAndreas Larsson pram_ofs = fsl_spi_cpm_get_pram(mspi); 314e8beacbbSAndreas Larsson if (IS_ERR_VALUE(pram_ofs)) { 315e8beacbbSAndreas Larsson dev_err(dev, "can't allocate spi parameter ram\n"); 316e8beacbbSAndreas Larsson goto err_pram; 317e8beacbbSAndreas Larsson } 318e8beacbbSAndreas Larsson 319e8beacbbSAndreas Larsson bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) + 320e8beacbbSAndreas Larsson sizeof(*mspi->rx_bd), 8); 321e8beacbbSAndreas Larsson if (IS_ERR_VALUE(bds_ofs)) { 322e8beacbbSAndreas Larsson dev_err(dev, "can't allocate bds\n"); 323e8beacbbSAndreas Larsson goto err_bds; 324e8beacbbSAndreas Larsson } 325e8beacbbSAndreas Larsson 326e8beacbbSAndreas Larsson mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE, 327e8beacbbSAndreas Larsson DMA_TO_DEVICE); 328e8beacbbSAndreas Larsson if (dma_mapping_error(dev, mspi->dma_dummy_tx)) { 329e8beacbbSAndreas Larsson dev_err(dev, "unable to map dummy tx buffer\n"); 330e8beacbbSAndreas Larsson goto err_dummy_tx; 331e8beacbbSAndreas Larsson } 332e8beacbbSAndreas Larsson 333e8beacbbSAndreas Larsson mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR, 334e8beacbbSAndreas Larsson DMA_FROM_DEVICE); 335e8beacbbSAndreas Larsson if (dma_mapping_error(dev, mspi->dma_dummy_rx)) { 336e8beacbbSAndreas Larsson dev_err(dev, "unable to map dummy rx buffer\n"); 337e8beacbbSAndreas Larsson goto err_dummy_rx; 338e8beacbbSAndreas Larsson } 339e8beacbbSAndreas Larsson 340e8beacbbSAndreas Larsson mspi->pram = cpm_muram_addr(pram_ofs); 341e8beacbbSAndreas Larsson 342e8beacbbSAndreas Larsson mspi->tx_bd = cpm_muram_addr(bds_ofs); 343e8beacbbSAndreas Larsson mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd)); 344e8beacbbSAndreas Larsson 345e8beacbbSAndreas Larsson /* Initialize parameter ram. */ 346e8beacbbSAndreas Larsson out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd)); 347e8beacbbSAndreas Larsson out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd)); 348e8beacbbSAndreas Larsson out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL); 349e8beacbbSAndreas Larsson out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL); 350e8beacbbSAndreas Larsson out_be16(&mspi->pram->mrblr, SPI_MRBLR); 351e8beacbbSAndreas Larsson out_be32(&mspi->pram->rstate, 0); 352e8beacbbSAndreas Larsson out_be32(&mspi->pram->rdp, 0); 353e8beacbbSAndreas Larsson out_be16(&mspi->pram->rbptr, 0); 354e8beacbbSAndreas Larsson out_be16(&mspi->pram->rbc, 0); 355e8beacbbSAndreas Larsson out_be32(&mspi->pram->rxtmp, 0); 356e8beacbbSAndreas Larsson out_be32(&mspi->pram->tstate, 0); 357e8beacbbSAndreas Larsson out_be32(&mspi->pram->tdp, 0); 358e8beacbbSAndreas Larsson out_be16(&mspi->pram->tbptr, 0); 359e8beacbbSAndreas Larsson out_be16(&mspi->pram->tbc, 0); 360e8beacbbSAndreas Larsson out_be32(&mspi->pram->txtmp, 0); 361e8beacbbSAndreas Larsson 362e8beacbbSAndreas Larsson return 0; 363e8beacbbSAndreas Larsson 364e8beacbbSAndreas Larsson err_dummy_rx: 365e8beacbbSAndreas Larsson dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE); 366e8beacbbSAndreas Larsson err_dummy_tx: 367e8beacbbSAndreas Larsson cpm_muram_free(bds_ofs); 368e8beacbbSAndreas Larsson err_bds: 369e8beacbbSAndreas Larsson cpm_muram_free(pram_ofs); 370e8beacbbSAndreas Larsson err_pram: 371e8beacbbSAndreas Larsson fsl_spi_free_dummy_rx(); 372e8beacbbSAndreas Larsson return -ENOMEM; 373e8beacbbSAndreas Larsson } 374e8beacbbSAndreas Larsson 375e8beacbbSAndreas Larsson void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) 376e8beacbbSAndreas Larsson { 377e8beacbbSAndreas Larsson struct device *dev = mspi->dev; 378e8beacbbSAndreas Larsson 379e8beacbbSAndreas Larsson if (!(mspi->flags & SPI_CPM_MODE)) 380e8beacbbSAndreas Larsson return; 381e8beacbbSAndreas Larsson 382e8beacbbSAndreas Larsson dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE); 383e8beacbbSAndreas Larsson dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE); 384e8beacbbSAndreas Larsson cpm_muram_free(cpm_muram_offset(mspi->tx_bd)); 385e8beacbbSAndreas Larsson cpm_muram_free(cpm_muram_offset(mspi->pram)); 386e8beacbbSAndreas Larsson fsl_spi_free_dummy_rx(); 387e8beacbbSAndreas Larsson } 388