1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * spi-synquacer.c - Socionext Synquacer SPI driver 4 * Copyright 2021 Linaro Ltd. 5 * Copyright 2021 Socionext, Inc. 6 */ 7 8#include <clk.h> 9#include <common.h> 10#include <dm.h> 11#include <log.h> 12#include <time.h> 13#include <dm/device_compat.h> 14#include <linux/bitfield.h> 15#include <linux/bitops.h> 16#include <linux/delay.h> 17#include <linux/io.h> 18#include <spi.h> 19#include <wait_bit.h> 20 21#define MCTRL 0x0 22#define MEN 0 23#define CSEN 1 24#define IPCLK 3 25#define MES 4 26#define SYNCON 5 27 28#define PCC0 0x4 29#define PCC(n) (PCC0 + (n) * 4) 30#define RTM 3 31#define ACES 2 32#define SAFESYNC 16 33#define CPHA 0 34#define CPOL 1 35#define SSPOL 4 36#define SDIR 7 37#define SS2CD 5 38#define SENDIAN 8 39#define CDRS_SHIFT 9 40#define CDRS_MASK 0x7f 41 42#define TXF 0x14 43#define TXE 0x18 44#define TXC 0x1c 45#define RXF 0x20 46#define RXE 0x24 47#define RXC 0x28 48#define TFES 1 49#define TFLETE 4 50#define TSSRS 6 51#define RFMTE 5 52#define RSSRS 6 53 54#define FAULTF 0x2c 55#define FAULTC 0x30 56 57#define DMCFG 0x34 58#define SSDC 1 59#define MSTARTEN 2 60 61#define DMSTART 0x38 62#define TRIGGER 0 63#define DMSTOP 8 64#define CS_MASK 3 65#define CS_SHIFT 16 66#define DATA_TXRX 0 67#define DATA_RX 1 68#define DATA_TX 2 69#define DATA_MASK 3 70#define DATA_SHIFT 26 71#define BUS_WIDTH 24 72 73#define DMBCC 0x3c 74#define DMSTATUS 0x40 75#define RX_DATA_MASK 0x1f 76#define RX_DATA_SHIFT 8 77#define TX_DATA_MASK 0x1f 78#define TX_DATA_SHIFT 16 79 80#define TXBITCNT 0x44 81 82#define FIFOCFG 0x4c 83#define BPW_MASK 0x3 84#define BPW_SHIFT 8 85#define RX_FLUSH 11 86#define TX_FLUSH 12 87#define RX_TRSHLD_MASK 0xf 88#define RX_TRSHLD_SHIFT 0 89#define TX_TRSHLD_MASK 0xf 90#define TX_TRSHLD_SHIFT 4 91 92#define TXFIFO 0x50 93#define RXFIFO 0x90 94#define MID 0xfc 95 96#define FIFO_DEPTH 16 97#define TX_TRSHLD 4 98#define RX_TRSHLD (FIFO_DEPTH - TX_TRSHLD) 99 100#define TXBIT 1 101#define RXBIT 2 102 103DECLARE_GLOBAL_DATA_PTR; 104 105struct synquacer_spi_plat { 106 void __iomem *base; 107 bool aces, rtm; 108}; 109 110struct synquacer_spi_priv { 111 void __iomem *base; 112 bool aces, rtm; 113 int speed, cs, mode, rwflag; 114 void *rx_buf; 115 const void *tx_buf; 116 unsigned int tx_words, rx_words; 117}; 118 119static void read_fifo(struct synquacer_spi_priv *priv) 120{ 121 u32 len = readl(priv->base + DMSTATUS); 122 u8 *buf = priv->rx_buf; 123 int i; 124 125 len = (len >> RX_DATA_SHIFT) & RX_DATA_MASK; 126 len = min_t(unsigned int, len, priv->rx_words); 127 128 for (i = 0; i < len; i++) 129 *buf++ = readb(priv->base + RXFIFO); 130 131 priv->rx_buf = buf; 132 priv->rx_words -= len; 133} 134 135static void write_fifo(struct synquacer_spi_priv *priv) 136{ 137 u32 len = readl(priv->base + DMSTATUS); 138 const u8 *buf = priv->tx_buf; 139 int i; 140 141 len = (len >> TX_DATA_SHIFT) & TX_DATA_MASK; 142 len = min_t(unsigned int, FIFO_DEPTH - len, priv->tx_words); 143 144 for (i = 0; i < len; i++) 145 writeb(*buf++, priv->base + TXFIFO); 146 147 priv->tx_buf = buf; 148 priv->tx_words -= len; 149} 150 151static void synquacer_cs_set(struct synquacer_spi_priv *priv, bool active) 152{ 153 u32 val; 154 155 val = readl(priv->base + DMSTART); 156 val &= ~(CS_MASK << CS_SHIFT); 157 val |= priv->cs << CS_SHIFT; 158 159 if (active) { 160 writel(val, priv->base + DMSTART); 161 162 val = readl(priv->base + DMSTART); 163 val &= ~BIT(DMSTOP); 164 writel(val, priv->base + DMSTART); 165 } else { 166 val |= BIT(DMSTOP); 167 writel(val, priv->base + DMSTART); 168 169 if (priv->rx_buf) { 170 u32 buf[16]; 171 172 priv->rx_buf = buf; 173 priv->rx_words = 16; 174 read_fifo(priv); 175 } 176 177 /* wait until slave is deselected */ 178 while (!(readl(priv->base + TXF) & BIT(TSSRS)) || 179 !(readl(priv->base + RXF) & BIT(RSSRS))) 180 ; 181 } 182} 183 184static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx) 185{ 186 struct udevice *bus = dev->parent; 187 struct synquacer_spi_priv *priv = dev_get_priv(bus); 188 struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); 189 u32 val, div, bus_width; 190 int rwflag; 191 192 rwflag = (rx ? 1 : 0) | (tx ? 2 : 0); 193 194 /* if nothing to do */ 195 if (slave_plat->mode == priv->mode && 196 rwflag == priv->rwflag && 197 slave_plat->cs == priv->cs && 198 slave_plat->max_hz == priv->speed) 199 return; 200 201 priv->rwflag = rwflag; 202 priv->cs = slave_plat->cs; 203 priv->mode = slave_plat->mode; 204 priv->speed = slave_plat->max_hz; 205 206 if (priv->mode & SPI_TX_DUAL) 207 bus_width = 2; 208 else if (priv->mode & SPI_TX_QUAD) 209 bus_width = 4; 210 else if (priv->mode & SPI_TX_OCTAL) 211 bus_width = 8; 212 else 213 bus_width = 1; /* default is single bit mode */ 214 215 div = DIV_ROUND_UP(125000000, priv->speed); 216 217 val = readl(priv->base + PCC(priv->cs)); 218 val &= ~BIT(RTM); 219 val &= ~BIT(ACES); 220 val &= ~BIT(SAFESYNC); 221 if ((priv->mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3) 222 val |= BIT(SAFESYNC); 223 if ((priv->mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6) 224 val |= BIT(SAFESYNC); 225 226 if (priv->mode & SPI_CPHA) 227 val |= BIT(CPHA); 228 else 229 val &= ~BIT(CPHA); 230 231 if (priv->mode & SPI_CPOL) 232 val |= BIT(CPOL); 233 else 234 val &= ~BIT(CPOL); 235 236 if (priv->mode & SPI_CS_HIGH) 237 val |= BIT(SSPOL); 238 else 239 val &= ~BIT(SSPOL); 240 241 if (priv->mode & SPI_LSB_FIRST) 242 val |= BIT(SDIR); 243 else 244 val &= ~BIT(SDIR); 245 246 if (priv->aces) 247 val |= BIT(ACES); 248 249 if (priv->rtm) 250 val |= BIT(RTM); 251 252 val |= (3 << SS2CD); 253 val |= BIT(SENDIAN); 254 255 val &= ~(CDRS_MASK << CDRS_SHIFT); 256 val |= ((div >> 1) << CDRS_SHIFT); 257 258 writel(val, priv->base + PCC(priv->cs)); 259 260 val = readl(priv->base + FIFOCFG); 261 val &= ~(BPW_MASK << BPW_SHIFT); 262 val |= (0 << BPW_SHIFT); 263 writel(val, priv->base + FIFOCFG); 264 265 val = readl(priv->base + DMSTART); 266 val &= ~(DATA_MASK << DATA_SHIFT); 267 268 if (tx && rx) 269 val |= (DATA_TXRX << DATA_SHIFT); 270 else if (rx) 271 val |= (DATA_RX << DATA_SHIFT); 272 else 273 val |= (DATA_TX << DATA_SHIFT); 274 275 val &= ~(3 << BUS_WIDTH); 276 val |= ((bus_width >> 1) << BUS_WIDTH); 277 writel(val, priv->base + DMSTART); 278} 279 280static int synquacer_spi_xfer(struct udevice *dev, unsigned int bitlen, 281 const void *tx_buf, void *rx_buf, 282 unsigned long flags) 283{ 284 struct udevice *bus = dev->parent; 285 struct synquacer_spi_priv *priv = dev_get_priv(bus); 286 u32 val, words, busy = 0; 287 288 val = readl(priv->base + FIFOCFG); 289 val |= (1 << RX_FLUSH); 290 val |= (1 << TX_FLUSH); 291 writel(val, priv->base + FIFOCFG); 292 293 synquacer_spi_config(dev, rx_buf, tx_buf); 294 295 priv->tx_buf = tx_buf; 296 priv->rx_buf = rx_buf; 297 298 words = bitlen / 8; 299 300 if (tx_buf) { 301 busy |= BIT(TXBIT); 302 priv->tx_words = words; 303 } else { 304 busy &= ~BIT(TXBIT); 305 priv->tx_words = 0; 306 } 307 308 if (rx_buf) { 309 busy |= BIT(RXBIT); 310 priv->rx_words = words; 311 } else { 312 busy &= ~BIT(RXBIT); 313 priv->rx_words = 0; 314 } 315 316 if (flags & SPI_XFER_BEGIN) 317 synquacer_cs_set(priv, true); 318 319 if (tx_buf) 320 write_fifo(priv); 321 322 if (rx_buf) { 323 val = readl(priv->base + FIFOCFG); 324 val &= ~(RX_TRSHLD_MASK << RX_TRSHLD_SHIFT); 325 val |= ((priv->rx_words > FIFO_DEPTH ? 326 RX_TRSHLD : priv->rx_words) << RX_TRSHLD_SHIFT); 327 writel(val, priv->base + FIFOCFG); 328 } 329 330 writel(~0, priv->base + TXC); 331 writel(~0, priv->base + RXC); 332 333 /* Trigger */ 334 if (flags & SPI_XFER_BEGIN) { 335 val = readl(priv->base + DMSTART); 336 val |= BIT(TRIGGER); 337 writel(val, priv->base + DMSTART); 338 } 339 340 while (busy & (BIT(RXBIT) | BIT(TXBIT))) { 341 if (priv->rx_words) 342 read_fifo(priv); 343 else 344 busy &= ~BIT(RXBIT); 345 346 if (priv->tx_words) { 347 write_fifo(priv); 348 } else { 349 /* wait for shifter to empty out */ 350 while (!(readl(priv->base + TXF) & BIT(TFES))) 351 cpu_relax(); 352 353 busy &= ~BIT(TXBIT); 354 } 355 } 356 357 if (flags & SPI_XFER_END) 358 synquacer_cs_set(priv, false); 359 360 return 0; 361} 362 363static int synquacer_spi_set_speed(struct udevice *bus, uint speed) 364{ 365 return 0; 366} 367 368static int synquacer_spi_set_mode(struct udevice *bus, uint mode) 369{ 370 return 0; 371} 372 373static int synquacer_spi_claim_bus(struct udevice *dev) 374{ 375 return 0; 376} 377 378static int synquacer_spi_release_bus(struct udevice *dev) 379{ 380 return 0; 381} 382 383static void synquacer_spi_disable_module(struct synquacer_spi_priv *priv) 384{ 385 writel(0, priv->base + MCTRL); 386 while (readl(priv->base + MCTRL) & BIT(MES)) 387 cpu_relax(); 388} 389 390static void synquacer_spi_init(struct synquacer_spi_priv *priv) 391{ 392 u32 val; 393 394 synquacer_spi_disable_module(priv); 395 396 writel(0, priv->base + TXE); 397 writel(0, priv->base + RXE); 398 val = readl(priv->base + TXF); 399 writel(val, priv->base + TXC); 400 val = readl(priv->base + RXF); 401 writel(val, priv->base + RXC); 402 val = readl(priv->base + FAULTF); 403 writel(val, priv->base + FAULTC); 404 405 val = readl(priv->base + DMCFG); 406 val &= ~BIT(SSDC); 407 val &= ~BIT(MSTARTEN); 408 writel(val, priv->base + DMCFG); 409 410 /* Enable module with direct mode */ 411 val = readl(priv->base + MCTRL); 412 val &= ~BIT(IPCLK); 413 val &= ~BIT(CSEN); 414 val |= BIT(MEN); 415 val |= BIT(SYNCON); 416 writel(val, priv->base + MCTRL); 417} 418 419static void synquacer_spi_exit(struct synquacer_spi_priv *priv) 420{ 421 u32 val; 422 423 synquacer_spi_disable_module(priv); 424 425 /* Enable module with command sequence mode */ 426 val = readl(priv->base + MCTRL); 427 val &= ~BIT(IPCLK); 428 val |= BIT(CSEN); 429 val |= BIT(MEN); 430 val |= BIT(SYNCON); 431 writel(val, priv->base + MCTRL); 432 433 while (!(readl(priv->base + MCTRL) & BIT(MES))) 434 cpu_relax(); 435} 436 437static int synquacer_spi_probe(struct udevice *bus) 438{ 439 struct synquacer_spi_plat *plat = dev_get_plat(bus); 440 struct synquacer_spi_priv *priv = dev_get_priv(bus); 441 442 priv->base = plat->base; 443 priv->aces = plat->aces; 444 priv->rtm = plat->rtm; 445 446 synquacer_spi_init(priv); 447 return 0; 448} 449 450static int synquacer_spi_remove(struct udevice *bus) 451{ 452 struct synquacer_spi_priv *priv = dev_get_priv(bus); 453 454 synquacer_spi_exit(priv); 455 return 0; 456} 457 458static int synquacer_spi_of_to_plat(struct udevice *bus) 459{ 460 struct synquacer_spi_plat *plat = dev_get_plat(bus); 461 struct clk clk; 462 463 plat->base = dev_read_addr_ptr(bus); 464 465 plat->aces = dev_read_bool(bus, "socionext,set-aces"); 466 plat->rtm = dev_read_bool(bus, "socionext,use-rtm"); 467 468 clk_get_by_name(bus, "iHCLK", &clk); 469 clk_enable(&clk); 470 471 return 0; 472} 473 474static const struct dm_spi_ops synquacer_spi_ops = { 475 .claim_bus = synquacer_spi_claim_bus, 476 .release_bus = synquacer_spi_release_bus, 477 .xfer = synquacer_spi_xfer, 478 .set_speed = synquacer_spi_set_speed, 479 .set_mode = synquacer_spi_set_mode, 480}; 481 482static const struct udevice_id synquacer_spi_ids[] = { 483 { .compatible = "socionext,synquacer-spi" }, 484 { /* Sentinel */ } 485}; 486 487U_BOOT_DRIVER(synquacer_spi) = { 488 .name = "synquacer_spi", 489 .id = UCLASS_SPI, 490 .of_match = synquacer_spi_ids, 491 .ops = &synquacer_spi_ops, 492 .of_to_plat = synquacer_spi_of_to_plat, 493 .plat_auto = sizeof(struct synquacer_spi_plat), 494 .priv_auto = sizeof(struct synquacer_spi_priv), 495 .probe = synquacer_spi_probe, 496 .flags = DM_FLAG_OS_PREPARE, 497 .remove = synquacer_spi_remove, 498}; 499