1 /* 2 * 3 * (C) Copyright 2000-2003 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 * 6 * Copyright (C) 2004-2009 Freescale Semiconductor, Inc. 7 * TsiChung Liew (Tsi-Chung.Liew@freescale.com) 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <spi.h> 14 #include <malloc.h> 15 #include <asm/immap.h> 16 17 struct cf_spi_slave { 18 struct spi_slave slave; 19 uint baudrate; 20 int charbit; 21 }; 22 23 extern void cfspi_port_conf(void); 24 extern int cfspi_claim_bus(uint bus, uint cs); 25 extern void cfspi_release_bus(uint bus, uint cs); 26 27 DECLARE_GLOBAL_DATA_PTR; 28 29 #ifndef CONFIG_SPI_IDLE_VAL 30 #if defined(CONFIG_SPI_MMC) 31 #define CONFIG_SPI_IDLE_VAL 0xFFFF 32 #else 33 #define CONFIG_SPI_IDLE_VAL 0x0 34 #endif 35 #endif 36 37 #if defined(CONFIG_CF_DSPI) 38 /* DSPI specific mode */ 39 #define SPI_MODE_MOD 0x00200000 40 #define SPI_DBLRATE 0x00100000 41 42 static inline struct cf_spi_slave *to_cf_spi_slave(struct spi_slave *slave) 43 { 44 return container_of(slave, struct cf_spi_slave, slave); 45 } 46 47 static void cfspi_init(void) 48 { 49 volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI; 50 51 cfspi_port_conf(); /* port configuration */ 52 53 dspi->mcr = DSPI_MCR_MSTR | DSPI_MCR_CSIS7 | DSPI_MCR_CSIS6 | 54 DSPI_MCR_CSIS5 | DSPI_MCR_CSIS4 | DSPI_MCR_CSIS3 | 55 DSPI_MCR_CSIS2 | DSPI_MCR_CSIS1 | DSPI_MCR_CSIS0 | 56 DSPI_MCR_CRXF | DSPI_MCR_CTXF; 57 58 /* Default setting in platform configuration */ 59 #ifdef CONFIG_SYS_DSPI_CTAR0 60 dspi->ctar[0] = CONFIG_SYS_DSPI_CTAR0; 61 #endif 62 #ifdef CONFIG_SYS_DSPI_CTAR1 63 dspi->ctar[1] = CONFIG_SYS_DSPI_CTAR1; 64 #endif 65 #ifdef CONFIG_SYS_DSPI_CTAR2 66 dspi->ctar[2] = CONFIG_SYS_DSPI_CTAR2; 67 #endif 68 #ifdef CONFIG_SYS_DSPI_CTAR3 69 dspi->ctar[3] = CONFIG_SYS_DSPI_CTAR3; 70 #endif 71 #ifdef CONFIG_SYS_DSPI_CTAR4 72 dspi->ctar[4] = CONFIG_SYS_DSPI_CTAR4; 73 #endif 74 #ifdef CONFIG_SYS_DSPI_CTAR5 75 dspi->ctar[5] = CONFIG_SYS_DSPI_CTAR5; 76 #endif 77 #ifdef CONFIG_SYS_DSPI_CTAR6 78 dspi->ctar[6] = CONFIG_SYS_DSPI_CTAR6; 79 #endif 80 #ifdef CONFIG_SYS_DSPI_CTAR7 81 dspi->ctar[7] = CONFIG_SYS_DSPI_CTAR7; 82 #endif 83 } 84 85 static void cfspi_tx(u32 ctrl, u16 data) 86 { 87 volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI; 88 89 while ((dspi->sr & 0x0000F000) >= 4) ; 90 91 dspi->tfr = (ctrl | data); 92 } 93 94 static u16 cfspi_rx(void) 95 { 96 volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI; 97 98 while ((dspi->sr & 0x000000F0) == 0) ; 99 100 return (dspi->rfr & 0xFFFF); 101 } 102 103 static int cfspi_xfer(struct spi_slave *slave, uint bitlen, const void *dout, 104 void *din, ulong flags) 105 { 106 struct cf_spi_slave *cfslave = to_cf_spi_slave(slave); 107 u16 *spi_rd16 = NULL, *spi_wr16 = NULL; 108 u8 *spi_rd = NULL, *spi_wr = NULL; 109 static u32 ctrl = 0; 110 uint len = bitlen >> 3; 111 112 if (cfslave->charbit == 16) { 113 bitlen >>= 1; 114 spi_wr16 = (u16 *) dout; 115 spi_rd16 = (u16 *) din; 116 } else { 117 spi_wr = (u8 *) dout; 118 spi_rd = (u8 *) din; 119 } 120 121 if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN) 122 ctrl |= DSPI_TFR_CONT; 123 124 ctrl = (ctrl & 0xFF000000) | ((1 << slave->cs) << 16); 125 126 if (len > 1) { 127 int tmp_len = len - 1; 128 while (tmp_len--) { 129 if (dout != NULL) { 130 if (cfslave->charbit == 16) 131 cfspi_tx(ctrl, *spi_wr16++); 132 else 133 cfspi_tx(ctrl, *spi_wr++); 134 cfspi_rx(); 135 } 136 137 if (din != NULL) { 138 cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL); 139 if (cfslave->charbit == 16) 140 *spi_rd16++ = cfspi_rx(); 141 else 142 *spi_rd++ = cfspi_rx(); 143 } 144 } 145 146 len = 1; /* remaining byte */ 147 } 148 149 if ((flags & SPI_XFER_END) == SPI_XFER_END) 150 ctrl &= ~DSPI_TFR_CONT; 151 152 if (len) { 153 if (dout != NULL) { 154 if (cfslave->charbit == 16) 155 cfspi_tx(ctrl, *spi_wr16); 156 else 157 cfspi_tx(ctrl, *spi_wr); 158 cfspi_rx(); 159 } 160 161 if (din != NULL) { 162 cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL); 163 if (cfslave->charbit == 16) 164 *spi_rd16 = cfspi_rx(); 165 else 166 *spi_rd = cfspi_rx(); 167 } 168 } else { 169 /* dummy read */ 170 cfspi_tx(ctrl, CONFIG_SPI_IDLE_VAL); 171 cfspi_rx(); 172 } 173 174 return 0; 175 } 176 177 static struct spi_slave *cfspi_setup_slave(struct cf_spi_slave *cfslave, 178 uint mode) 179 { 180 /* 181 * bit definition for mode: 182 * bit 31 - 28: Transfer size 3 to 16 bits 183 * 27 - 26: PCS to SCK delay prescaler 184 * 25 - 24: After SCK delay prescaler 185 * 23 - 22: Delay after transfer prescaler 186 * 21 : Allow overwrite for bit 31-22 and bit 20-8 187 * 20 : Double baud rate 188 * 19 - 16: PCS to SCK delay scaler 189 * 15 - 12: After SCK delay scaler 190 * 11 - 8: Delay after transfer scaler 191 * 7 - 0: SPI_CPHA, SPI_CPOL, SPI_LSB_FIRST 192 */ 193 volatile dspi_t *dspi = (dspi_t *) MMAP_DSPI; 194 int prescaler[] = { 2, 3, 5, 7 }; 195 int scaler[] = { 196 2, 4, 6, 8, 197 16, 32, 64, 128, 198 256, 512, 1024, 2048, 199 4096, 8192, 16384, 32768 200 }; 201 int i, j, pbrcnt, brcnt, diff, tmp, dbr = 0; 202 int best_i, best_j, bestmatch = 0x7FFFFFFF, baud_speed; 203 u32 bus_setup = 0; 204 205 tmp = (prescaler[3] * scaler[15]); 206 /* Maximum and minimum baudrate it can handle */ 207 if ((cfslave->baudrate > (gd->bus_clk >> 1)) || 208 (cfslave->baudrate < (gd->bus_clk / tmp))) { 209 printf("Exceed baudrate limitation: Max %d - Min %d\n", 210 (int)(gd->bus_clk >> 1), (int)(gd->bus_clk / tmp)); 211 return NULL; 212 } 213 214 /* Activate Double Baud when it exceed 1/4 the bus clk */ 215 if ((CONFIG_SYS_DSPI_CTAR0 & DSPI_CTAR_DBR) || 216 (cfslave->baudrate > (gd->bus_clk / (prescaler[0] * scaler[0])))) { 217 bus_setup |= DSPI_CTAR_DBR; 218 dbr = 1; 219 } 220 221 if (mode & SPI_CPOL) 222 bus_setup |= DSPI_CTAR_CPOL; 223 if (mode & SPI_CPHA) 224 bus_setup |= DSPI_CTAR_CPHA; 225 if (mode & SPI_LSB_FIRST) 226 bus_setup |= DSPI_CTAR_LSBFE; 227 228 /* Overwrite default value set in platform configuration file */ 229 if (mode & SPI_MODE_MOD) { 230 231 if ((mode & 0xF0000000) == 0) 232 bus_setup |= 233 dspi->ctar[cfslave->slave.bus] & 0x78000000; 234 else 235 bus_setup |= ((mode & 0xF0000000) >> 1); 236 237 /* 238 * Check to see if it is enabled by default in platform 239 * config, or manual setting passed by mode parameter 240 */ 241 if (mode & SPI_DBLRATE) { 242 bus_setup |= DSPI_CTAR_DBR; 243 dbr = 1; 244 } 245 bus_setup |= (mode & 0x0FC00000) >> 4; /* PSCSCK, PASC, PDT */ 246 bus_setup |= (mode & 0x000FFF00) >> 4; /* CSSCK, ASC, DT */ 247 } else 248 bus_setup |= (dspi->ctar[cfslave->slave.bus] & 0x78FCFFF0); 249 250 cfslave->charbit = 251 ((dspi->ctar[cfslave->slave.bus] & 0x78000000) == 252 0x78000000) ? 16 : 8; 253 254 pbrcnt = sizeof(prescaler) / sizeof(int); 255 brcnt = sizeof(scaler) / sizeof(int); 256 257 /* baudrate calculation - to closer value, may not be exact match */ 258 for (best_i = 0, best_j = 0, i = 0; i < pbrcnt; i++) { 259 baud_speed = gd->bus_clk / prescaler[i]; 260 for (j = 0; j < brcnt; j++) { 261 tmp = (baud_speed / scaler[j]) * (1 + dbr); 262 263 if (tmp > cfslave->baudrate) 264 diff = tmp - cfslave->baudrate; 265 else 266 diff = cfslave->baudrate - tmp; 267 268 if (diff < bestmatch) { 269 bestmatch = diff; 270 best_i = i; 271 best_j = j; 272 } 273 } 274 } 275 bus_setup |= (DSPI_CTAR_PBR(best_i) | DSPI_CTAR_BR(best_j)); 276 dspi->ctar[cfslave->slave.bus] = bus_setup; 277 278 return &cfslave->slave; 279 } 280 #endif /* CONFIG_CF_DSPI */ 281 282 #ifdef CONFIG_CMD_SPI 283 int spi_cs_is_valid(unsigned int bus, unsigned int cs) 284 { 285 if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8))) 286 return 1; 287 else 288 return 0; 289 } 290 291 void spi_init_f(void) 292 { 293 } 294 295 void spi_init_r(void) 296 { 297 } 298 299 void spi_init(void) 300 { 301 cfspi_init(); 302 } 303 304 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 305 unsigned int max_hz, unsigned int mode) 306 { 307 struct cf_spi_slave *cfslave; 308 309 if (!spi_cs_is_valid(bus, cs)) 310 return NULL; 311 312 cfslave = spi_alloc_slave(struct cf_spi_slave, bus, cs); 313 if (!cfslave) 314 return NULL; 315 316 cfslave->baudrate = max_hz; 317 318 /* specific setup */ 319 return cfspi_setup_slave(cfslave, mode); 320 } 321 322 void spi_free_slave(struct spi_slave *slave) 323 { 324 struct cf_spi_slave *cfslave = to_cf_spi_slave(slave); 325 326 free(cfslave); 327 } 328 329 int spi_claim_bus(struct spi_slave *slave) 330 { 331 return cfspi_claim_bus(slave->bus, slave->cs); 332 } 333 334 void spi_release_bus(struct spi_slave *slave) 335 { 336 cfspi_release_bus(slave->bus, slave->cs); 337 } 338 339 int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, 340 void *din, unsigned long flags) 341 { 342 return cfspi_xfer(slave, bitlen, dout, din, flags); 343 } 344 #endif /* CONFIG_CMD_SPI */ 345