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