summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-fsl-cpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-fsl-cpm.c')
-rw-r--r--drivers/spi/spi-fsl-cpm.c186
1 files changed, 109 insertions, 77 deletions
diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c
index 07971e3fe58b..23ad1249f121 100644
--- a/drivers/spi/spi-fsl-cpm.c
+++ b/drivers/spi/spi-fsl-cpm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Freescale SPI controller driver cpm functions.
*
@@ -9,22 +10,21 @@
* CPM SPI and QE buffer descriptors mode support:
* Copyright (c) 2009 MontaVista Software, Inc.
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
-#include <linux/types.h>
+#include <asm/cpm.h>
+#include <soc/fsl/qe/qe.h>
+#include <linux/dma-mapping.h>
+#include <linux/fsl_devices.h>
#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
#include <linux/spi/spi.h>
-#include <linux/fsl_devices.h>
-#include <linux/dma-mapping.h>
-#include <asm/cpm.h>
-#include <asm/qe.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/byteorder/generic.h>
-#include "spi-fsl-lib.h"
#include "spi-fsl-cpm.h"
+#include "spi-fsl-lib.h"
#include "spi-fsl-spi.h"
/* CPM1 and CPM2 are mutually exclusive. */
@@ -55,15 +55,19 @@ void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi)
qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
QE_CR_PROTOCOL_UNSPECIFIED, 0);
} else {
- cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
if (mspi->flags & SPI_CPM1) {
- out_be16(&mspi->pram->rbptr,
- in_be16(&mspi->pram->rbase));
- out_be16(&mspi->pram->tbptr,
- in_be16(&mspi->pram->tbase));
+ iowrite32be(0, &mspi->pram->rstate);
+ iowrite16be(ioread16be(&mspi->pram->rbase),
+ &mspi->pram->rbptr);
+ iowrite32be(0, &mspi->pram->tstate);
+ iowrite16be(ioread16be(&mspi->pram->tbase),
+ &mspi->pram->tbptr);
+ } else {
+ cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
}
}
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_reinit_txrx);
static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
{
@@ -71,42 +75,36 @@ static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
unsigned int xfer_ofs;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
if (mspi->rx_dma == mspi->dma_dummy_rx)
- out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma);
+ iowrite32be(mspi->rx_dma, &rx_bd->cbd_bufaddr);
else
- out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
- out_be16(&rx_bd->cbd_datlen, 0);
- out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
+ iowrite32be(mspi->rx_dma + xfer_ofs, &rx_bd->cbd_bufaddr);
+ iowrite16be(0, &rx_bd->cbd_datlen);
+ iowrite16be(BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP, &rx_bd->cbd_sc);
if (mspi->tx_dma == mspi->dma_dummy_tx)
- out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma);
+ iowrite32be(mspi->tx_dma, &tx_bd->cbd_bufaddr);
else
- out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
- out_be16(&tx_bd->cbd_datlen, xfer_len);
- out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
- BD_SC_LAST);
+ iowrite32be(mspi->tx_dma + xfer_ofs, &tx_bd->cbd_bufaddr);
+ iowrite16be(xfer_len, &tx_bd->cbd_datlen);
+ iowrite16be(BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP | BD_SC_LAST,
+ &tx_bd->cbd_sc);
/* start transfer */
mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
}
-int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
- struct spi_transfer *t, bool is_dma_mapped)
+int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t)
{
struct device *dev = mspi->dev;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
- if (is_dma_mapped) {
- mspi->map_tx_dma = 0;
- mspi->map_rx_dma = 0;
- } else {
- mspi->map_tx_dma = 1;
- mspi->map_rx_dma = 1;
- }
+ mspi->map_tx_dma = 1;
+ mspi->map_rx_dma = 1;
if (!t->tx_buf) {
mspi->tx_dma = mspi->dma_dummy_tx;
@@ -117,6 +115,21 @@ int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
mspi->rx_dma = mspi->dma_dummy_rx;
mspi->map_rx_dma = 0;
}
+ if (t->bits_per_word == 16 && t->tx_buf) {
+ const u16 *src = t->tx_buf;
+ __le16 *dst;
+ int i;
+
+ dst = kmalloc(t->len, GFP_KERNEL);
+ if (!dst)
+ return -ENOMEM;
+
+ for (i = 0; i < t->len >> 1; i++)
+ dst[i] = cpu_to_le16p(src + i);
+
+ mspi->tx = dst;
+ mspi->map_tx_dma = 1;
+ }
if (mspi->map_tx_dma) {
void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
@@ -128,7 +141,7 @@ int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
return -ENOMEM;
}
} else if (t->tx_buf) {
- mspi->tx_dma = t->tx_dma;
+ mspi->tx_dma = 0;
}
if (mspi->map_rx_dma) {
@@ -158,6 +171,7 @@ err_rx_dma:
dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
return -ENOMEM;
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs);
void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
{
@@ -169,17 +183,25 @@ void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
if (mspi->map_rx_dma)
dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
mspi->xfer_in_progress = NULL;
+
+ if (t->bits_per_word == 16 && t->rx_buf) {
+ int i;
+
+ for (i = 0; i < t->len; i += 2)
+ le16_to_cpus(t->rx_buf + i);
+ }
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs_complete);
void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
{
u16 len;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
- in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
+ ioread16be(&mspi->rx_bd->cbd_datlen), mspi->count);
- len = in_be16(&mspi->rx_bd->cbd_datlen);
+ len = ioread16be(&mspi->rx_bd->cbd_datlen);
if (len > mspi->count) {
WARN_ON(1);
len = mspi->count;
@@ -194,6 +216,7 @@ void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
else
complete(&mspi->done);
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_irq);
static void *fsl_spi_alloc_dummy_rx(void)
{
@@ -220,7 +243,7 @@ static void fsl_spi_free_dummy_rx(void)
case 1:
kfree(fsl_dummy_rx);
fsl_dummy_rx = NULL;
- /* fall through */
+ fallthrough;
default:
fsl_dummy_rx_refcnt--;
break;
@@ -260,17 +283,6 @@ static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
if (mspi->flags & SPI_CPM2) {
pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
out_be16(spi_base, pram_ofs);
- } else {
- struct spi_pram __iomem *pram = spi_base;
- u16 rpbase = in_be16(&pram->rpbase);
-
- /* Microcode relocation patch applied? */
- if (rpbase) {
- pram_ofs = rpbase;
- } else {
- pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
- out_be16(spi_base, pram_ofs);
- }
}
iounmap(spi_base);
@@ -283,7 +295,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
struct device_node *np = dev->of_node;
const u32 *iprop;
int size;
- unsigned long pram_ofs;
unsigned long bds_ofs;
if (!(mspi->flags & SPI_CPM_MODE))
@@ -299,8 +310,8 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
switch (mspi->subblock) {
default:
- dev_warn(dev, "cell-index unspecified, assuming SPI1");
- /* fall through */
+ dev_warn(dev, "cell-index unspecified, assuming SPI1\n");
+ fallthrough;
case 0:
mspi->subblock = QE_CR_SUBBLOCK_SPI1;
break;
@@ -310,8 +321,24 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
}
}
- pram_ofs = fsl_spi_cpm_get_pram(mspi);
- if (IS_ERR_VALUE(pram_ofs)) {
+ if (mspi->flags & SPI_CPM1) {
+ void __iomem *pram;
+
+ pram = devm_platform_ioremap_resource(to_platform_device(dev),
+ 1);
+ if (IS_ERR(pram))
+ mspi->pram = NULL;
+ else
+ mspi->pram = pram;
+ } else {
+ unsigned long pram_ofs = fsl_spi_cpm_get_pram(mspi);
+
+ if (IS_ERR_VALUE(pram_ofs))
+ mspi->pram = NULL;
+ else
+ mspi->pram = cpm_muram_addr(pram_ofs);
+ }
+ if (mspi->pram == NULL) {
dev_err(dev, "can't allocate spi parameter ram\n");
goto err_pram;
}
@@ -323,7 +350,7 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
goto err_bds;
}
- mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
+ mspi->dma_dummy_tx = dma_map_single(dev, ZERO_PAGE(0), PAGE_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
dev_err(dev, "unable to map dummy tx buffer\n");
@@ -337,27 +364,25 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
goto err_dummy_rx;
}
- mspi->pram = cpm_muram_addr(pram_ofs);
-
mspi->tx_bd = cpm_muram_addr(bds_ofs);
mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
/* Initialize parameter ram. */
- out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
- out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
- out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
- out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
- out_be16(&mspi->pram->mrblr, SPI_MRBLR);
- out_be32(&mspi->pram->rstate, 0);
- out_be32(&mspi->pram->rdp, 0);
- out_be16(&mspi->pram->rbptr, 0);
- out_be16(&mspi->pram->rbc, 0);
- out_be32(&mspi->pram->rxtmp, 0);
- out_be32(&mspi->pram->tstate, 0);
- out_be32(&mspi->pram->tdp, 0);
- out_be16(&mspi->pram->tbptr, 0);
- out_be16(&mspi->pram->tbc, 0);
- out_be32(&mspi->pram->txtmp, 0);
+ iowrite16be(cpm_muram_offset(mspi->tx_bd), &mspi->pram->tbase);
+ iowrite16be(cpm_muram_offset(mspi->rx_bd), &mspi->pram->rbase);
+ iowrite8(CPMFCR_EB | CPMFCR_GBL, &mspi->pram->tfcr);
+ iowrite8(CPMFCR_EB | CPMFCR_GBL, &mspi->pram->rfcr);
+ iowrite16be(SPI_MRBLR, &mspi->pram->mrblr);
+ iowrite32be(0, &mspi->pram->rstate);
+ iowrite32be(0, &mspi->pram->rdp);
+ iowrite16be(0, &mspi->pram->rbptr);
+ iowrite16be(0, &mspi->pram->rbc);
+ iowrite32be(0, &mspi->pram->rxtmp);
+ iowrite32be(0, &mspi->pram->tstate);
+ iowrite32be(0, &mspi->pram->tdp);
+ iowrite16be(0, &mspi->pram->tbptr);
+ iowrite16be(0, &mspi->pram->tbc);
+ iowrite32be(0, &mspi->pram->txtmp);
return 0;
@@ -366,11 +391,13 @@ err_dummy_rx:
err_dummy_tx:
cpm_muram_free(bds_ofs);
err_bds:
- cpm_muram_free(pram_ofs);
+ if (!(mspi->flags & SPI_CPM1))
+ cpm_muram_free(cpm_muram_offset(mspi->pram));
err_pram:
fsl_spi_free_dummy_rx();
return -ENOMEM;
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_init);
void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
{
@@ -382,6 +409,11 @@ void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
- cpm_muram_free(cpm_muram_offset(mspi->pram));
+ if (!(mspi->flags & SPI_CPM1))
+ cpm_muram_free(cpm_muram_offset(mspi->pram));
fsl_spi_free_dummy_rx();
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_free);
+
+MODULE_DESCRIPTION("Freescale SPI controller driver CPM functions");
+MODULE_LICENSE("GPL");