1 /* 2 * Andestech ATCSPI200 SPI controller driver. 3 * 4 * Copyright 2017 Andes Technology, Inc. 5 * Author: Rick Chen (rick@andestech.com) 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <clk.h> 11 #include <common.h> 12 #include <malloc.h> 13 #include <spi.h> 14 #include <asm/io.h> 15 #include <dm.h> 16 17 DECLARE_GLOBAL_DATA_PTR; 18 19 #define MAX_TRANSFER_LEN 512 20 #define CHUNK_SIZE 1 21 #define SPI_TIMEOUT 0x100000 22 #define SPI0_BUS 0 23 #define SPI1_BUS 1 24 #define SPI0_BASE 0xf0b00000 25 #define SPI1_BASE 0xf0f00000 26 #define NSPI_MAX_CS_NUM 1 27 28 struct atcspi200_spi_regs { 29 u32 rev; 30 u32 reserve1[3]; 31 u32 format; /* 0x10 */ 32 #define DATA_LENGTH(x) ((x-1)<<8) 33 u32 pio; 34 u32 reserve2[2]; 35 u32 tctrl; /* 0x20 */ 36 #define TRAMODE_OFFSET 24 37 #define TRAMODE_MASK (0x0F<<TRAMODE_OFFSET) 38 #define TRAMODE_WR_SYNC (0<<TRAMODE_OFFSET) 39 #define TRAMODE_WO (1<<TRAMODE_OFFSET) 40 #define TRAMODE_RO (2<<TRAMODE_OFFSET) 41 #define TRAMODE_WR (3<<TRAMODE_OFFSET) 42 #define TRAMODE_RW (4<<TRAMODE_OFFSET) 43 #define TRAMODE_WDR (5<<TRAMODE_OFFSET) 44 #define TRAMODE_RDW (6<<TRAMODE_OFFSET) 45 #define TRAMODE_NONE (7<<TRAMODE_OFFSET) 46 #define TRAMODE_DW (8<<TRAMODE_OFFSET) 47 #define TRAMODE_DR (9<<TRAMODE_OFFSET) 48 #define WCNT_OFFSET 12 49 #define WCNT_MASK (0x1FF<<WCNT_OFFSET) 50 #define RCNT_OFFSET 0 51 #define RCNT_MASK (0x1FF<<RCNT_OFFSET) 52 u32 cmd; 53 u32 addr; 54 u32 data; 55 u32 ctrl; /* 0x30 */ 56 #define TXFTH_OFFSET 16 57 #define RXFTH_OFFSET 8 58 #define TXDMAEN (1<<4) 59 #define RXDMAEN (1<<3) 60 #define TXFRST (1<<2) 61 #define RXFRST (1<<1) 62 #define SPIRST (1<<0) 63 u32 status; 64 #define TXFFL (1<<23) 65 #define TXEPTY (1<<22) 66 #define TXFVE_MASK (0x1F<<16) 67 #define RXFEM (1<<14) 68 #define RXFVE_OFFSET (8) 69 #define RXFVE_MASK (0x1F<<RXFVE_OFFSET) 70 #define SPIBSY (1<<0) 71 u32 inten; 72 u32 intsta; 73 u32 timing; /* 0x40 */ 74 #define SCLK_DIV_MASK 0xFF 75 }; 76 77 struct nds_spi_slave { 78 volatile struct atcspi200_spi_regs *regs; 79 int to; 80 unsigned int freq; 81 ulong clock; 82 unsigned int mode; 83 u8 num_cs; 84 unsigned int mtiming; 85 size_t cmd_len; 86 u8 cmd_buf[16]; 87 size_t data_len; 88 size_t tran_len; 89 u8 *din; 90 u8 *dout; 91 unsigned int max_transfer_length; 92 }; 93 94 static int __atcspi200_spi_set_speed(struct nds_spi_slave *ns) 95 { 96 u32 tm; 97 u8 div; 98 tm = ns->regs->timing; 99 tm &= ~SCLK_DIV_MASK; 100 101 if(ns->freq >= ns->clock) 102 div =0xff; 103 else{ 104 for (div = 0; div < 0xff; div++) { 105 if (ns->freq >= ns->clock / (2 * (div + 1))) 106 break; 107 } 108 } 109 110 tm |= div; 111 ns->regs->timing = tm; 112 113 return 0; 114 115 } 116 117 static int __atcspi200_spi_claim_bus(struct nds_spi_slave *ns) 118 { 119 unsigned int format=0; 120 ns->regs->ctrl |= (TXFRST|RXFRST|SPIRST); 121 while((ns->regs->ctrl &(TXFRST|RXFRST|SPIRST))&&(ns->to--)) 122 if(!ns->to) 123 return -EINVAL; 124 125 ns->cmd_len = 0; 126 format = ns->mode|DATA_LENGTH(8); 127 ns->regs->format = format; 128 __atcspi200_spi_set_speed(ns); 129 130 return 0; 131 } 132 133 static int __atcspi200_spi_release_bus(struct nds_spi_slave *ns) 134 { 135 /* do nothing */ 136 return 0; 137 } 138 139 static int __atcspi200_spi_start(struct nds_spi_slave *ns) 140 { 141 int i,olen=0; 142 int tc = ns->regs->tctrl; 143 144 tc &= ~(WCNT_MASK|RCNT_MASK|TRAMODE_MASK); 145 if ((ns->din)&&(ns->cmd_len)) 146 tc |= TRAMODE_WR; 147 else if (ns->din) 148 tc |= TRAMODE_RO; 149 else 150 tc |= TRAMODE_WO; 151 152 if(ns->dout) 153 olen = ns->tran_len; 154 tc |= (ns->cmd_len+olen-1) << WCNT_OFFSET; 155 156 if(ns->din) 157 tc |= (ns->tran_len-1) << RCNT_OFFSET; 158 159 ns->regs->tctrl = tc; 160 ns->regs->cmd = 1; 161 162 for (i=0;i<ns->cmd_len;i++) 163 ns->regs->data = ns->cmd_buf[i]; 164 165 return 0; 166 } 167 168 static int __atcspi200_spi_stop(struct nds_spi_slave *ns) 169 { 170 ns->regs->timing = ns->mtiming; 171 while ((ns->regs->status & SPIBSY)&&(ns->to--)) 172 if (!ns->to) 173 return -EINVAL; 174 175 return 0; 176 } 177 178 static void __nspi_espi_tx(struct nds_spi_slave *ns, const void *dout) 179 { 180 ns->regs->data = *(u8 *)dout; 181 } 182 183 static int __nspi_espi_rx(struct nds_spi_slave *ns, void *din, unsigned int bytes) 184 { 185 *(u8 *)din = ns->regs->data; 186 return bytes; 187 } 188 189 190 static int __atcspi200_spi_xfer(struct nds_spi_slave *ns, 191 unsigned int bitlen, const void *data_out, void *data_in, 192 unsigned long flags) 193 { 194 unsigned int event, rx_bytes; 195 const void *dout = NULL; 196 void *din = NULL; 197 int num_blks, num_chunks, max_tran_len, tran_len; 198 int num_bytes; 199 u8 *cmd_buf = ns->cmd_buf; 200 size_t cmd_len = ns->cmd_len; 201 size_t data_len = bitlen / 8; 202 int rf_cnt; 203 int ret = 0; 204 205 max_tran_len = ns->max_transfer_length; 206 switch (flags) { 207 case SPI_XFER_BEGIN: 208 cmd_len = ns->cmd_len = data_len; 209 memcpy(cmd_buf, data_out, cmd_len); 210 return 0; 211 212 case 0: 213 case SPI_XFER_END: 214 if (bitlen == 0) { 215 return 0; 216 } 217 ns->data_len = data_len; 218 ns->din = (u8 *)data_in; 219 ns->dout = (u8 *)data_out; 220 break; 221 222 case SPI_XFER_BEGIN | SPI_XFER_END: 223 ns->data_len = 0; 224 ns->din = 0; 225 ns->dout = 0; 226 cmd_len = ns->cmd_len = data_len; 227 memcpy(cmd_buf, data_out, cmd_len); 228 data_out = 0; 229 data_len = 0; 230 __atcspi200_spi_start(ns); 231 break; 232 } 233 debug("spi_xfer: data_out %08X(%p) data_in %08X(%p) data_len %u\n", 234 *(uint *)data_out, data_out, *(uint *)data_in, data_in, data_len); 235 num_chunks = DIV_ROUND_UP(data_len, max_tran_len); 236 din = data_in; 237 dout = data_out; 238 while (num_chunks--) { 239 tran_len = min(data_len, (size_t)max_tran_len); 240 ns->tran_len = tran_len; 241 num_blks = DIV_ROUND_UP(tran_len , CHUNK_SIZE); 242 num_bytes = (tran_len) % CHUNK_SIZE; 243 if(num_bytes == 0) 244 num_bytes = CHUNK_SIZE; 245 __atcspi200_spi_start(ns); 246 247 while (num_blks) { 248 event = in_le32(&ns->regs->status); 249 if ((event & TXEPTY) && (data_out)) { 250 __nspi_espi_tx(ns, dout); 251 num_blks -= CHUNK_SIZE; 252 dout += CHUNK_SIZE; 253 } 254 255 if ((event & RXFVE_MASK) && (data_in)) { 256 rf_cnt = ((event & RXFVE_MASK)>> RXFVE_OFFSET); 257 if (rf_cnt >= CHUNK_SIZE) 258 rx_bytes = CHUNK_SIZE; 259 else if (num_blks == 1 && rf_cnt == num_bytes) 260 rx_bytes = num_bytes; 261 else 262 continue; 263 264 if (__nspi_espi_rx(ns, din, rx_bytes) == rx_bytes) { 265 num_blks -= CHUNK_SIZE; 266 din = (unsigned char *)din + rx_bytes; 267 } 268 } 269 } 270 271 data_len -= tran_len; 272 if(data_len) 273 { 274 ns->cmd_buf[1] += ((tran_len>>16)&0xff); 275 ns->cmd_buf[2] += ((tran_len>>8)&0xff); 276 ns->cmd_buf[3] += ((tran_len)&0xff); 277 ns->data_len = data_len; 278 } 279 ret = __atcspi200_spi_stop(ns); 280 } 281 ret = __atcspi200_spi_stop(ns); 282 283 return ret; 284 } 285 286 static int atcspi200_spi_set_speed(struct udevice *bus, uint max_hz) 287 { 288 struct nds_spi_slave *ns = dev_get_priv(bus); 289 290 debug("%s speed %u\n", __func__, max_hz); 291 292 ns->freq = max_hz; 293 __atcspi200_spi_set_speed(ns); 294 295 return 0; 296 } 297 298 static int atcspi200_spi_set_mode(struct udevice *bus, uint mode) 299 { 300 struct nds_spi_slave *ns = dev_get_priv(bus); 301 302 debug("%s mode %u\n", __func__, mode); 303 ns->mode = mode; 304 305 return 0; 306 } 307 308 static int atcspi200_spi_claim_bus(struct udevice *dev) 309 { 310 struct dm_spi_slave_platdata *slave_plat = 311 dev_get_parent_platdata(dev); 312 struct udevice *bus = dev->parent; 313 struct nds_spi_slave *ns = dev_get_priv(bus); 314 315 if (slave_plat->cs >= ns->num_cs) { 316 printf("Invalid SPI chipselect\n"); 317 return -EINVAL; 318 } 319 320 return __atcspi200_spi_claim_bus(ns); 321 } 322 323 static int atcspi200_spi_release_bus(struct udevice *dev) 324 { 325 struct nds_spi_slave *ns = dev_get_priv(dev->parent); 326 327 return __atcspi200_spi_release_bus(ns); 328 } 329 330 static int atcspi200_spi_xfer(struct udevice *dev, unsigned int bitlen, 331 const void *dout, void *din, 332 unsigned long flags) 333 { 334 struct udevice *bus = dev->parent; 335 struct nds_spi_slave *ns = dev_get_priv(bus); 336 337 return __atcspi200_spi_xfer(ns, bitlen, dout, din, flags); 338 } 339 340 static int atcspi200_spi_get_clk(struct udevice *bus) 341 { 342 struct nds_spi_slave *ns = dev_get_priv(bus); 343 struct clk clk; 344 ulong clk_rate; 345 int ret; 346 347 ret = clk_get_by_index(bus, 0, &clk); 348 if (ret) 349 return -EINVAL; 350 351 clk_rate = clk_get_rate(&clk); 352 if (!clk_rate) 353 return -EINVAL; 354 355 ns->clock = clk_rate; 356 clk_free(&clk); 357 358 return 0; 359 } 360 361 static int atcspi200_spi_probe(struct udevice *bus) 362 { 363 struct nds_spi_slave *ns = dev_get_priv(bus); 364 365 ns->to = SPI_TIMEOUT; 366 ns->max_transfer_length = MAX_TRANSFER_LEN; 367 ns->mtiming = ns->regs->timing; 368 atcspi200_spi_get_clk(bus); 369 370 return 0; 371 } 372 373 static int atcspi200_ofdata_to_platadata(struct udevice *bus) 374 { 375 struct nds_spi_slave *ns = dev_get_priv(bus); 376 const void *blob = gd->fdt_blob; 377 int node = dev_of_offset(bus); 378 379 ns->regs = map_physmem(devfdt_get_addr(bus), 380 sizeof(struct atcspi200_spi_regs), 381 MAP_NOCACHE); 382 if (!ns->regs) { 383 printf("%s: could not map device address\n", __func__); 384 return -EINVAL; 385 } 386 ns->num_cs = fdtdec_get_int(blob, node, "num-cs", 4); 387 388 return 0; 389 } 390 391 static const struct dm_spi_ops atcspi200_spi_ops = { 392 .claim_bus = atcspi200_spi_claim_bus, 393 .release_bus = atcspi200_spi_release_bus, 394 .xfer = atcspi200_spi_xfer, 395 .set_speed = atcspi200_spi_set_speed, 396 .set_mode = atcspi200_spi_set_mode, 397 }; 398 399 static const struct udevice_id atcspi200_spi_ids[] = { 400 { .compatible = "andestech,atcspi200" }, 401 { } 402 }; 403 404 U_BOOT_DRIVER(atcspi200_spi) = { 405 .name = "atcspi200_spi", 406 .id = UCLASS_SPI, 407 .of_match = atcspi200_spi_ids, 408 .ops = &atcspi200_spi_ops, 409 .ofdata_to_platdata = atcspi200_ofdata_to_platadata, 410 .priv_auto_alloc_size = sizeof(struct nds_spi_slave), 411 .probe = atcspi200_spi_probe, 412 }; 413