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 <malloc.h> 22#include <mpc8xx.h> 23#include <spi.h> 24#include <linux/delay.h> 25 26#include <asm/cpm_8xx.h> 27#include <asm/io.h> 28#include <asm/gpio.h> 29 30#define CPM_SPI_BASE_RX CPM_SPI_BASE 31#define CPM_SPI_BASE_TX (CPM_SPI_BASE + sizeof(cbd_t)) 32 33#define MAX_BUFFER 0x8000 /* Max possible is 0xffff. We want power of 2 */ 34#define MIN_HWORD_XFER 64 /* Minimum size for 16 bits transfer */ 35 36struct mpc8xx_priv { 37 spi_t __iomem *spi; 38 struct gpio_desc gpios[16]; 39 int max_cs; 40}; 41 42static char dummy_buffer[MAX_BUFFER]; 43 44static int mpc8xx_spi_set_mode(struct udevice *dev, uint mod) 45{ 46 return 0; 47} 48 49static int mpc8xx_spi_set_speed(struct udevice *dev, uint speed) 50{ 51 immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 52 cpm8xx_t __iomem *cp = &immr->im_cpm; 53 u8 pm = (gd->arch.brg_clk - 1) / (speed * 16); 54 55 if (pm > 16) { 56 setbits_be16(&cp->cp_spmode, SPMODE_DIV16); 57 pm /= 16; 58 if (pm > 16) 59 pm = 16; 60 } else { 61 clrbits_be16(&cp->cp_spmode, SPMODE_DIV16); 62 } 63 64 clrsetbits_be16(&cp->cp_spmode, SPMODE_PM(0xf), SPMODE_PM(pm)); 65 66 return 0; 67} 68 69static int mpc8xx_spi_probe(struct udevice *dev) 70{ 71 immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 72 cpm8xx_t __iomem *cp = &immr->im_cpm; 73 spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dpmem[PROFF_SPI]; 74 u16 spi_rpbase; 75 cbd_t __iomem *tbdf, *rbdf; 76 77 spi_rpbase = in_be16(&spi->spi_rpbase); 78 if (spi_rpbase) 79 spi = (spi_t __iomem *)&cp->cp_dpmem[spi_rpbase]; 80 81/* 1 */ 82 /* Initialize the parameter ram. 83 * We need to make sure many things are initialized to zero 84 */ 85 out_be32(&spi->spi_rstate, 0); 86 out_be32(&spi->spi_rdp, 0); 87 out_be16(&spi->spi_rbptr, 0); 88 out_be16(&spi->spi_rbc, 0); 89 out_be32(&spi->spi_rxtmp, 0); 90 out_be32(&spi->spi_tstate, 0); 91 out_be32(&spi->spi_tdp, 0); 92 out_be16(&spi->spi_tbptr, 0); 93 out_be16(&spi->spi_tbc, 0); 94 out_be32(&spi->spi_txtmp, 0); 95 96/* 3 */ 97 /* Set up the SPI parameters in the parameter ram */ 98 out_be16(&spi->spi_rbase, CPM_SPI_BASE_RX); 99 out_be16(&spi->spi_tbase, CPM_SPI_BASE_TX); 100 101 /***********IMPORTANT******************/ 102 103 /* 104 * Setting transmit and receive buffer descriptor pointers 105 * initially to rbase and tbase. Only the microcode patches 106 * documentation talks about initializing this pointer. This 107 * is missing from the sample I2C driver. If you dont 108 * initialize these pointers, the kernel hangs. 109 */ 110 out_be16(&spi->spi_rbptr, CPM_SPI_BASE_RX); 111 out_be16(&spi->spi_tbptr, CPM_SPI_BASE_TX); 112 113/* 4 */ 114 /* Init SPI Tx + Rx Parameters */ 115 while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) 116 ; 117 118 out_be16(&cp->cp_cpcr, mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | 119 CPM_CR_FLG); 120 while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) 121 ; 122 123/* 6 */ 124 /* Set to big endian. */ 125 out_8(&spi->spi_tfcr, SMC_EB); 126 out_8(&spi->spi_rfcr, SMC_EB); 127 128/* 7 */ 129 /* Set maximum receive size. */ 130 out_be16(&spi->spi_mrblr, MAX_BUFFER); 131 132/* 8 + 9 */ 133 /* tx and rx buffer descriptors */ 134 tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX]; 135 rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX]; 136 137 clrbits_be16(&tbdf->cbd_sc, BD_SC_READY); 138 clrbits_be16(&rbdf->cbd_sc, BD_SC_EMPTY); 139 140/* 10 + 11 */ 141 out_8(&cp->cp_spim, 0); /* Mask all SPI events */ 142 out_8(&cp->cp_spie, SPI_EMASK); /* Clear all SPI events */ 143 144 return 0; 145} 146 147static void mpc8xx_spi_cs_activate(struct udevice *dev) 148{ 149 struct mpc8xx_priv *priv = dev_get_priv(dev->parent); 150 struct dm_spi_slave_plat *platdata = dev_get_parent_plat(dev); 151 152 dm_gpio_set_value(&priv->gpios[platdata->cs], 1); 153} 154 155static void mpc8xx_spi_cs_deactivate(struct udevice *dev) 156{ 157 struct mpc8xx_priv *priv = dev_get_priv(dev->parent); 158 struct dm_spi_slave_plat *platdata = dev_get_parent_plat(dev); 159 160 dm_gpio_set_value(&priv->gpios[platdata->cs], 0); 161} 162 163static int mpc8xx_spi_xfer_one(struct udevice *dev, size_t count, 164 const void *dout, void *din) 165{ 166 immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 167 cpm8xx_t __iomem *cp = &immr->im_cpm; 168 cbd_t __iomem *tbdf, *rbdf; 169 void *bufout, *bufin; 170 u16 spmode_len; 171 int tm; 172 173 tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX]; 174 rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX]; 175 176 if (!(count & 1) && count >= MIN_HWORD_XFER) { 177 spmode_len = SPMODE_LEN(16); 178 if (dout) { 179 int i; 180 181 bufout = malloc(count); 182 for (i = 0; i < count; i += 2) 183 *(u16 *)(bufout + i) = swab16(*(u16 *)(dout + i)); 184 } else { 185 bufout = NULL; 186 } 187 if (din) 188 bufin = malloc(count); 189 else 190 bufin = NULL; 191 } else { 192 spmode_len = SPMODE_LEN(8); 193 bufout = (void *)dout; 194 bufin = din; 195 } 196 197 /* Setting tx bd status and data length */ 198 out_be32(&tbdf->cbd_bufaddr, bufout ? (ulong)bufout : (ulong)dummy_buffer); 199 out_be16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_LAST | BD_SC_WRAP); 200 out_be16(&tbdf->cbd_datlen, count); 201 202 /* Setting rx bd status and data length */ 203 out_be32(&rbdf->cbd_bufaddr, bufin ? (ulong)bufin : (ulong)dummy_buffer); 204 out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_WRAP); 205 out_be16(&rbdf->cbd_datlen, 0); /* rx length has no significance */ 206 207 clrsetbits_be16(&cp->cp_spmode, ~(SPMODE_LOOP | SPMODE_PM(0xf) | SPMODE_DIV16), 208 SPMODE_REV | SPMODE_MSTR | SPMODE_EN | spmode_len); 209 out_8(&cp->cp_spim, 0); /* Mask all SPI events */ 210 out_8(&cp->cp_spie, SPI_EMASK); /* Clear all SPI events */ 211 212 /* start spi transfer */ 213 setbits_8(&cp->cp_spcom, SPI_STR); /* Start transmit */ 214 215 /* -------------------------------- 216 * Wait for SPI transmit to get out 217 * or time out (1 second = 1000 ms) 218 * -------------------------------- */ 219 for (tm = 0; tm < 1000; ++tm) { 220 if (in_8(&cp->cp_spie) & SPI_TXB) /* Tx Buffer Empty */ 221 break; 222 223 if ((in_be16(&tbdf->cbd_sc) & BD_SC_READY) == 0) 224 break; 225 udelay(1000); 226 } 227 228 if (tm >= 1000) 229 return -ETIMEDOUT; 230 231 if (!(count & 1) && count > MIN_HWORD_XFER) { 232 if (dout) 233 free(bufout); 234 if (din) { 235 int i; 236 237 bufout = malloc(count); 238 for (i = 0; i < count; i += 2) 239 *(u16 *)(din + i) = swab16(*(u16 *)(bufin + i)); 240 free(bufin); 241 } 242 } 243 244 return 0; 245} 246 247static int mpc8xx_spi_xfer(struct udevice *dev, unsigned int bitlen, 248 const void *dout, void *din, unsigned long flags) 249{ 250 size_t count = (bitlen + 7) / 8; 251 size_t offset = 0; 252 int ret = 0; 253 254 if (!din && !dout) 255 return -EINVAL; 256 257 /* Set CS for device */ 258 if (flags & SPI_XFER_BEGIN) 259 mpc8xx_spi_cs_activate(dev); 260 261 while (count > 0 && !ret) { 262 size_t chunk = min(count, (size_t)MAX_BUFFER); 263 const void *out = dout ? dout + offset : NULL; 264 void *in = din ? din + offset : NULL; 265 266 ret = mpc8xx_spi_xfer_one(dev, chunk, out, in); 267 268 offset += chunk; 269 count -= chunk; 270 } 271 /* Clear CS for device */ 272 if (flags & SPI_XFER_END) 273 mpc8xx_spi_cs_deactivate(dev); 274 275 if (ret) 276 printf("*** spi_xfer: Time out while xferring to/from SPI!\n"); 277 278 return ret; 279} 280 281static int mpc8xx_spi_ofdata_to_platdata(struct udevice *dev) 282{ 283 struct mpc8xx_priv *priv = dev_get_priv(dev); 284 int ret; 285 286 ret = gpio_request_list_by_name(dev, "gpios", priv->gpios, 287 ARRAY_SIZE(priv->gpios), GPIOD_IS_OUT); 288 if (ret < 0) 289 return ret; 290 291 priv->max_cs = ret; 292 293 return 0; 294} 295static const struct dm_spi_ops mpc8xx_spi_ops = { 296 .xfer = mpc8xx_spi_xfer, 297 .set_speed = mpc8xx_spi_set_speed, 298 .set_mode = mpc8xx_spi_set_mode, 299}; 300 301static const struct udevice_id mpc8xx_spi_ids[] = { 302 { .compatible = "fsl,mpc8xx-spi" }, 303 { } 304}; 305 306U_BOOT_DRIVER(mpc8xx_spi) = { 307 .name = "mpc8xx_spi", 308 .id = UCLASS_SPI, 309 .of_match = mpc8xx_spi_ids, 310 .of_to_plat = mpc8xx_spi_ofdata_to_platdata, 311 .ops = &mpc8xx_spi_ops, 312 .probe = mpc8xx_spi_probe, 313 .priv_auto = sizeof(struct mpc8xx_priv), 314}; 315