uboot/drivers/spi/mpc8xx_spi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2001 Navin Boppuri / Prashant Patel
   4 *      <nboppuri@trinetcommunication.com>,
   5 *      <pmpatel@trinetcommunication.com>
   6 * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
   7 * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
   8 */
   9
  10/*
  11 * MPC8xx CPM SPI interface.
  12 *
  13 * Parts of this code are probably not portable and/or specific to
  14 * the board which I used for the tests. Please send fixes/complaints
  15 * to wd@denx.de
  16 *
  17 */
  18
  19#include <common.h>
  20#include <dm.h>
  21#include <mpc8xx.h>
  22#include <spi.h>
  23#include <linux/delay.h>
  24
  25#include <asm/cpm_8xx.h>
  26#include <asm/io.h>
  27#include <asm/gpio.h>
  28
  29#define CPM_SPI_BASE_RX CPM_SPI_BASE
  30#define CPM_SPI_BASE_TX (CPM_SPI_BASE + sizeof(cbd_t))
  31
  32#define MAX_BUFFER      0x104
  33
  34struct mpc8xx_priv {
  35        spi_t __iomem *spi;
  36        struct gpio_desc gpios[16];
  37        int max_cs;
  38};
  39
  40static int mpc8xx_spi_set_mode(struct udevice *dev, uint mod)
  41{
  42        return 0;
  43}
  44
  45static int mpc8xx_spi_set_speed(struct udevice *dev, uint speed)
  46{
  47        return 0;
  48}
  49
  50static int mpc8xx_spi_probe(struct udevice *dev)
  51{
  52        immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
  53        cpm8xx_t __iomem *cp = &immr->im_cpm;
  54        spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dpmem[PROFF_SPI];
  55        u16 spi_rpbase;
  56        cbd_t __iomem *tbdf, *rbdf;
  57
  58        spi_rpbase = in_be16(&spi->spi_rpbase);
  59        if (spi_rpbase)
  60                spi = (spi_t __iomem *)&cp->cp_dpmem[spi_rpbase];
  61
  62/* 1 */
  63        /* Initialize the parameter ram.
  64         * We need to make sure many things are initialized to zero
  65         */
  66        out_be32(&spi->spi_rstate, 0);
  67        out_be32(&spi->spi_rdp, 0);
  68        out_be16(&spi->spi_rbptr, 0);
  69        out_be16(&spi->spi_rbc, 0);
  70        out_be32(&spi->spi_rxtmp, 0);
  71        out_be32(&spi->spi_tstate, 0);
  72        out_be32(&spi->spi_tdp, 0);
  73        out_be16(&spi->spi_tbptr, 0);
  74        out_be16(&spi->spi_tbc, 0);
  75        out_be32(&spi->spi_txtmp, 0);
  76
  77/* 3 */
  78        /* Set up the SPI parameters in the parameter ram */
  79        out_be16(&spi->spi_rbase, CPM_SPI_BASE_RX);
  80        out_be16(&spi->spi_tbase, CPM_SPI_BASE_TX);
  81
  82        /***********IMPORTANT******************/
  83
  84        /*
  85         * Setting transmit and receive buffer descriptor pointers
  86         * initially to rbase and tbase. Only the microcode patches
  87         * documentation talks about initializing this pointer. This
  88         * is missing from the sample I2C driver. If you dont
  89         * initialize these pointers, the kernel hangs.
  90         */
  91        out_be16(&spi->spi_rbptr, CPM_SPI_BASE_RX);
  92        out_be16(&spi->spi_tbptr, CPM_SPI_BASE_TX);
  93
  94/* 4 */
  95        /* Init SPI Tx + Rx Parameters */
  96        while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG)
  97                ;
  98
  99        out_be16(&cp->cp_cpcr, mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) |
 100                               CPM_CR_FLG);
 101        while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG)
 102                ;
 103
 104/* 5 */
 105        /* Set SDMA configuration register */
 106        out_be32(&immr->im_siu_conf.sc_sdcr, 0x0001);
 107
 108/* 6 */
 109        /* Set to big endian. */
 110        out_8(&spi->spi_tfcr, SMC_EB);
 111        out_8(&spi->spi_rfcr, SMC_EB);
 112
 113/* 7 */
 114        /* Set maximum receive size. */
 115        out_be16(&spi->spi_mrblr, MAX_BUFFER);
 116
 117/* 8 + 9 */
 118        /* tx and rx buffer descriptors */
 119        tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX];
 120        rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX];
 121
 122        clrbits_be16(&tbdf->cbd_sc, BD_SC_READY);
 123        clrbits_be16(&rbdf->cbd_sc, BD_SC_EMPTY);
 124
 125/* 10 + 11 */
 126        out_8(&cp->cp_spim, 0);                 /* Mask  all SPI events */
 127        out_8(&cp->cp_spie, SPI_EMASK);         /* Clear all SPI events */
 128
 129        return 0;
 130}
 131
 132static void mpc8xx_spi_cs_activate(struct udevice *dev)
 133{
 134        struct mpc8xx_priv *priv = dev_get_priv(dev->parent);
 135        struct dm_spi_slave_plat *platdata = dev_get_parent_plat(dev);
 136
 137        dm_gpio_set_value(&priv->gpios[platdata->cs], 1);
 138}
 139
 140static void mpc8xx_spi_cs_deactivate(struct udevice *dev)
 141{
 142        struct mpc8xx_priv *priv = dev_get_priv(dev->parent);
 143        struct dm_spi_slave_plat *platdata = dev_get_parent_plat(dev);
 144
 145        dm_gpio_set_value(&priv->gpios[platdata->cs], 0);
 146}
 147
 148static int mpc8xx_spi_xfer(struct udevice *dev, unsigned int bitlen,
 149                            const void *dout, void *din, unsigned long flags)
 150{
 151        immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
 152        cpm8xx_t __iomem *cp = &immr->im_cpm;
 153        cbd_t __iomem *tbdf, *rbdf;
 154        int tm;
 155        size_t count = (bitlen + 7) / 8;
 156
 157        if (count > MAX_BUFFER)
 158                return -EINVAL;
 159
 160        tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX];
 161        rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX];
 162
 163        /* Set CS for device */
 164        if (flags & SPI_XFER_BEGIN)
 165                mpc8xx_spi_cs_activate(dev);
 166
 167        /* Setting tx bd status and data length */
 168        out_be32(&tbdf->cbd_bufaddr, (ulong)dout);
 169        out_be16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_LAST | BD_SC_WRAP);
 170        out_be16(&tbdf->cbd_datlen, count);
 171
 172        /* Setting rx bd status and data length */
 173        out_be32(&rbdf->cbd_bufaddr, (ulong)din);
 174        out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_WRAP);
 175        out_be16(&rbdf->cbd_datlen, 0);  /* rx length has no significance */
 176
 177        clrsetbits_be16(&cp->cp_spmode, ~SPMODE_LOOP, SPMODE_REV | SPMODE_MSTR |
 178                        SPMODE_EN | SPMODE_LEN(8) | SPMODE_PM(0x8));
 179        out_8(&cp->cp_spim, 0);         /* Mask  all SPI events */
 180        out_8(&cp->cp_spie, SPI_EMASK); /* Clear all SPI events */
 181
 182        /* start spi transfer */
 183        setbits_8(&cp->cp_spcom, SPI_STR);              /* Start transmit */
 184
 185        /* --------------------------------
 186         * Wait for SPI transmit to get out
 187         * or time out (1 second = 1000 ms)
 188         * -------------------------------- */
 189        for (tm = 0; tm < 1000; ++tm) {
 190                if (in_8(&cp->cp_spie) & SPI_TXB)       /* Tx Buffer Empty */
 191                        break;
 192
 193                if ((in_be16(&tbdf->cbd_sc) & BD_SC_READY) == 0)
 194                        break;
 195                udelay(1000);
 196        }
 197
 198        if (tm >= 1000)
 199                printf("*** spi_xfer: Time out while xferring to/from SPI!\n");
 200
 201        /* Clear CS for device */
 202        if (flags & SPI_XFER_END)
 203                mpc8xx_spi_cs_deactivate(dev);
 204
 205        return 0;
 206}
 207
 208static int mpc8xx_spi_ofdata_to_platdata(struct udevice *dev)
 209{
 210        struct mpc8xx_priv *priv = dev_get_priv(dev);
 211        int ret;
 212
 213        ret = gpio_request_list_by_name(dev, "gpios", priv->gpios,
 214                                        ARRAY_SIZE(priv->gpios), GPIOD_IS_OUT);
 215        if (ret < 0)
 216                return ret;
 217
 218        priv->max_cs = ret;
 219
 220        return 0;
 221}
 222static const struct dm_spi_ops mpc8xx_spi_ops = {
 223        .xfer           = mpc8xx_spi_xfer,
 224        .set_speed      = mpc8xx_spi_set_speed,
 225        .set_mode       = mpc8xx_spi_set_mode,
 226};
 227
 228static const struct udevice_id mpc8xx_spi_ids[] = {
 229        { .compatible = "fsl,mpc8xx-spi" },
 230        { }
 231};
 232
 233U_BOOT_DRIVER(mpc8xx_spi) = {
 234        .name   = "mpc8xx_spi",
 235        .id     = UCLASS_SPI,
 236        .of_match = mpc8xx_spi_ids,
 237        .of_to_plat = mpc8xx_spi_ofdata_to_platdata,
 238        .ops    = &mpc8xx_spi_ops,
 239        .probe  = mpc8xx_spi_probe,
 240        .priv_auto = sizeof(struct mpc8xx_priv),
 241};
 242