594 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2// Copyright (C) IBM Corporation 20203 4#include <linux/bitfield.h>5#include <linux/bits.h>6#include <linux/fsi.h>7#include <linux/jiffies.h>8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/spi/spi.h>12 13#define FSI_ENGID_SPI 0x2314#define FSI_MBOX_ROOT_CTRL_8 0x286015#define FSI_MBOX_ROOT_CTRL_8_SPI_MUX 0xf000000016 17#define FSI2SPI_DATA0 0x0018#define FSI2SPI_DATA1 0x0419#define FSI2SPI_CMD 0x0820#define FSI2SPI_CMD_WRITE BIT(31)21#define FSI2SPI_RESET 0x1822#define FSI2SPI_STATUS 0x1c23#define FSI2SPI_STATUS_ANY_ERROR BIT(31)24#define FSI2SPI_IRQ 0x2025 26#define SPI_FSI_BASE 0x7000027#define SPI_FSI_TIMEOUT_MS 100028#define SPI_FSI_MAX_RX_SIZE 829#define SPI_FSI_MAX_TX_SIZE 4030 31#define SPI_FSI_ERROR 0x032#define SPI_FSI_COUNTER_CFG 0x133#define SPI_FSI_CFG1 0x234#define SPI_FSI_CLOCK_CFG 0x335#define SPI_FSI_CLOCK_CFG_MM_ENABLE BIT_ULL(32)36#define SPI_FSI_CLOCK_CFG_ECC_DISABLE (BIT_ULL(35) | BIT_ULL(33))37#define SPI_FSI_CLOCK_CFG_RESET1 (BIT_ULL(36) | BIT_ULL(38))38#define SPI_FSI_CLOCK_CFG_RESET2 (BIT_ULL(37) | BIT_ULL(39))39#define SPI_FSI_CLOCK_CFG_MODE (BIT_ULL(41) | BIT_ULL(42))40#define SPI_FSI_CLOCK_CFG_SCK_RECV_DEL GENMASK_ULL(51, 44)41#define SPI_FSI_CLOCK_CFG_SCK_NO_DEL BIT_ULL(51)42#define SPI_FSI_CLOCK_CFG_SCK_DIV GENMASK_ULL(63, 52)43#define SPI_FSI_MMAP 0x444#define SPI_FSI_DATA_TX 0x545#define SPI_FSI_DATA_RX 0x646#define SPI_FSI_SEQUENCE 0x747#define SPI_FSI_SEQUENCE_STOP 0x0048#define SPI_FSI_SEQUENCE_SEL_SLAVE(x) (0x10 | ((x) & 0xf))49#define SPI_FSI_SEQUENCE_SHIFT_OUT(x) (0x30 | ((x) & 0xf))50#define SPI_FSI_SEQUENCE_SHIFT_IN(x) (0x40 | ((x) & 0xf))51#define SPI_FSI_SEQUENCE_COPY_DATA_TX 0xc052#define SPI_FSI_SEQUENCE_BRANCH(x) (0xe0 | ((x) & 0xf))53#define SPI_FSI_STATUS 0x854#define SPI_FSI_STATUS_ERROR \55 (GENMASK_ULL(31, 21) | GENMASK_ULL(15, 12))56#define SPI_FSI_STATUS_SEQ_STATE GENMASK_ULL(55, 48)57#define SPI_FSI_STATUS_SEQ_STATE_IDLE BIT_ULL(48)58#define SPI_FSI_STATUS_TDR_UNDERRUN BIT_ULL(57)59#define SPI_FSI_STATUS_TDR_OVERRUN BIT_ULL(58)60#define SPI_FSI_STATUS_TDR_FULL BIT_ULL(59)61#define SPI_FSI_STATUS_RDR_UNDERRUN BIT_ULL(61)62#define SPI_FSI_STATUS_RDR_OVERRUN BIT_ULL(62)63#define SPI_FSI_STATUS_RDR_FULL BIT_ULL(63)64#define SPI_FSI_STATUS_ANY_ERROR \65 (SPI_FSI_STATUS_ERROR | \66 SPI_FSI_STATUS_TDR_OVERRUN | SPI_FSI_STATUS_RDR_UNDERRUN | \67 SPI_FSI_STATUS_RDR_OVERRUN)68#define SPI_FSI_PORT_CTRL 0x969 70struct fsi2spi {71 struct fsi_device *fsi; /* FSI2SPI CFAM engine device */72 struct mutex lock; /* lock access to the device */73};74 75struct fsi_spi {76 struct device *dev; /* SPI controller device */77 struct fsi2spi *bridge; /* FSI2SPI device */78 u32 base;79};80 81struct fsi_spi_sequence {82 int bit;83 u64 data;84};85 86static int fsi_spi_check_mux(struct fsi_device *fsi, struct device *dev)87{88 int rc;89 u32 root_ctrl_8;90 __be32 root_ctrl_8_be;91 92 rc = fsi_slave_read(fsi->slave, FSI_MBOX_ROOT_CTRL_8, &root_ctrl_8_be,93 sizeof(root_ctrl_8_be));94 if (rc)95 return rc;96 97 root_ctrl_8 = be32_to_cpu(root_ctrl_8_be);98 dev_dbg(dev, "Root control register 8: %08x\n", root_ctrl_8);99 if ((root_ctrl_8 & FSI_MBOX_ROOT_CTRL_8_SPI_MUX) ==100 FSI_MBOX_ROOT_CTRL_8_SPI_MUX)101 return 0;102 103 return -ENOLINK;104}105 106static int fsi_spi_check_status(struct fsi_spi *ctx)107{108 int rc;109 u32 sts;110 __be32 sts_be;111 112 rc = fsi_device_read(ctx->bridge->fsi, FSI2SPI_STATUS, &sts_be,113 sizeof(sts_be));114 if (rc)115 return rc;116 117 sts = be32_to_cpu(sts_be);118 if (sts & FSI2SPI_STATUS_ANY_ERROR) {119 dev_err(ctx->dev, "Error with FSI2SPI interface: %08x.\n", sts);120 return -EIO;121 }122 123 return 0;124}125 126static int fsi_spi_read_reg(struct fsi_spi *ctx, u32 offset, u64 *value)127{128 int rc = 0;129 __be32 cmd_be;130 __be32 data_be;131 u32 cmd = offset + ctx->base;132 struct fsi2spi *bridge = ctx->bridge;133 134 *value = 0ULL;135 136 if (cmd & FSI2SPI_CMD_WRITE)137 return -EINVAL;138 139 rc = mutex_lock_interruptible(&bridge->lock);140 if (rc)141 return rc;142 143 cmd_be = cpu_to_be32(cmd);144 rc = fsi_device_write(bridge->fsi, FSI2SPI_CMD, &cmd_be,145 sizeof(cmd_be));146 if (rc)147 goto unlock;148 149 rc = fsi_spi_check_status(ctx);150 if (rc)151 goto unlock;152 153 rc = fsi_device_read(bridge->fsi, FSI2SPI_DATA0, &data_be,154 sizeof(data_be));155 if (rc)156 goto unlock;157 158 *value |= (u64)be32_to_cpu(data_be) << 32;159 160 rc = fsi_device_read(bridge->fsi, FSI2SPI_DATA1, &data_be,161 sizeof(data_be));162 if (rc)163 goto unlock;164 165 *value |= (u64)be32_to_cpu(data_be);166 dev_dbg(ctx->dev, "Read %02x[%016llx].\n", offset, *value);167 168unlock:169 mutex_unlock(&bridge->lock);170 return rc;171}172 173static int fsi_spi_write_reg(struct fsi_spi *ctx, u32 offset, u64 value)174{175 int rc = 0;176 __be32 cmd_be;177 __be32 data_be;178 u32 cmd = offset + ctx->base;179 struct fsi2spi *bridge = ctx->bridge;180 181 if (cmd & FSI2SPI_CMD_WRITE)182 return -EINVAL;183 184 rc = mutex_lock_interruptible(&bridge->lock);185 if (rc)186 return rc;187 188 dev_dbg(ctx->dev, "Write %02x[%016llx].\n", offset, value);189 190 data_be = cpu_to_be32(upper_32_bits(value));191 rc = fsi_device_write(bridge->fsi, FSI2SPI_DATA0, &data_be,192 sizeof(data_be));193 if (rc)194 goto unlock;195 196 data_be = cpu_to_be32(lower_32_bits(value));197 rc = fsi_device_write(bridge->fsi, FSI2SPI_DATA1, &data_be,198 sizeof(data_be));199 if (rc)200 goto unlock;201 202 cmd_be = cpu_to_be32(cmd | FSI2SPI_CMD_WRITE);203 rc = fsi_device_write(bridge->fsi, FSI2SPI_CMD, &cmd_be,204 sizeof(cmd_be));205 if (rc)206 goto unlock;207 208 rc = fsi_spi_check_status(ctx);209 210unlock:211 mutex_unlock(&bridge->lock);212 return rc;213}214 215static int fsi_spi_data_in(u64 in, u8 *rx, int len)216{217 int i;218 int num_bytes = min(len, 8);219 220 for (i = 0; i < num_bytes; ++i)221 rx[i] = (u8)(in >> (8 * ((num_bytes - 1) - i)));222 223 return num_bytes;224}225 226static int fsi_spi_data_out(u64 *out, const u8 *tx, int len)227{228 int i;229 int num_bytes = min(len, 8);230 u8 *out_bytes = (u8 *)out;231 232 /* Unused bytes of the tx data should be 0. */233 *out = 0ULL;234 235 for (i = 0; i < num_bytes; ++i)236 out_bytes[8 - (i + 1)] = tx[i];237 238 return num_bytes;239}240 241static int fsi_spi_reset(struct fsi_spi *ctx)242{243 int rc;244 245 dev_dbg(ctx->dev, "Resetting SPI controller.\n");246 247 rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,248 SPI_FSI_CLOCK_CFG_RESET1);249 if (rc)250 return rc;251 252 rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,253 SPI_FSI_CLOCK_CFG_RESET2);254 if (rc)255 return rc;256 257 return fsi_spi_write_reg(ctx, SPI_FSI_STATUS, 0ULL);258}259 260static int fsi_spi_status(struct fsi_spi *ctx, u64 *status, const char *dir)261{262 int rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, status);263 264 if (rc)265 return rc;266 267 if (*status & SPI_FSI_STATUS_ANY_ERROR) {268 dev_err(ctx->dev, "%s error: %016llx\n", dir, *status);269 270 rc = fsi_spi_reset(ctx);271 if (rc)272 return rc;273 274 return -EREMOTEIO;275 }276 277 return 0;278}279 280static void fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val)281{282 /*283 * Add the next byte of instruction to the 8-byte sequence register.284 * Then decrement the counter so that the next instruction will go in285 * the right place. Return the index of the slot we just filled in the286 * sequence register.287 */288 seq->data |= (u64)val << seq->bit;289 seq->bit -= 8;290}291 292static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq)293{294 seq->bit = 56;295 seq->data = 0ULL;296}297 298static int fsi_spi_transfer_data(struct fsi_spi *ctx,299 struct spi_transfer *transfer)300{301 int loops;302 int rc = 0;303 unsigned long end;304 u64 status = 0ULL;305 306 if (transfer->tx_buf) {307 int nb;308 int sent = 0;309 u64 out = 0ULL;310 const u8 *tx = transfer->tx_buf;311 312 while (transfer->len > sent) {313 nb = fsi_spi_data_out(&out, &tx[sent],314 (int)transfer->len - sent);315 316 rc = fsi_spi_write_reg(ctx, SPI_FSI_DATA_TX, out);317 if (rc)318 return rc;319 320 loops = 0;321 end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS);322 do {323 if (loops++ && time_after(jiffies, end))324 return -ETIMEDOUT;325 326 rc = fsi_spi_status(ctx, &status, "TX");327 if (rc)328 return rc;329 } while (status & SPI_FSI_STATUS_TDR_FULL);330 331 sent += nb;332 }333 } else if (transfer->rx_buf) {334 int recv = 0;335 u64 in = 0ULL;336 u8 *rx = transfer->rx_buf;337 338 while (transfer->len > recv) {339 loops = 0;340 end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS);341 do {342 if (loops++ && time_after(jiffies, end))343 return -ETIMEDOUT;344 345 rc = fsi_spi_status(ctx, &status, "RX");346 if (rc)347 return rc;348 } while (!(status & SPI_FSI_STATUS_RDR_FULL));349 350 rc = fsi_spi_read_reg(ctx, SPI_FSI_DATA_RX, &in);351 if (rc)352 return rc;353 354 recv += fsi_spi_data_in(in, &rx[recv],355 (int)transfer->len - recv);356 }357 }358 359 return 0;360}361 362static int fsi_spi_transfer_init(struct fsi_spi *ctx)363{364 int loops = 0;365 int rc;366 bool reset = false;367 unsigned long end;368 u64 seq_state;369 u64 clock_cfg = 0ULL;370 u64 status = 0ULL;371 u64 wanted_clock_cfg = SPI_FSI_CLOCK_CFG_ECC_DISABLE |372 SPI_FSI_CLOCK_CFG_SCK_NO_DEL |373 FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 19);374 375 end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS);376 do {377 if (loops++ && time_after(jiffies, end))378 return -ETIMEDOUT;379 380 rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, &status);381 if (rc)382 return rc;383 384 seq_state = status & SPI_FSI_STATUS_SEQ_STATE;385 386 if (status & (SPI_FSI_STATUS_ANY_ERROR |387 SPI_FSI_STATUS_TDR_FULL |388 SPI_FSI_STATUS_RDR_FULL)) {389 if (reset) {390 dev_err(ctx->dev,391 "Initialization error: %08llx\n",392 status);393 return -EIO;394 }395 396 rc = fsi_spi_reset(ctx);397 if (rc)398 return rc;399 400 reset = true;401 continue;402 }403 } while (seq_state && (seq_state != SPI_FSI_STATUS_SEQ_STATE_IDLE));404 405 rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, 0ULL);406 if (rc)407 return rc;408 409 rc = fsi_spi_read_reg(ctx, SPI_FSI_CLOCK_CFG, &clock_cfg);410 if (rc)411 return rc;412 413 if ((clock_cfg & (SPI_FSI_CLOCK_CFG_MM_ENABLE |414 SPI_FSI_CLOCK_CFG_ECC_DISABLE |415 SPI_FSI_CLOCK_CFG_MODE |416 SPI_FSI_CLOCK_CFG_SCK_RECV_DEL |417 SPI_FSI_CLOCK_CFG_SCK_DIV)) != wanted_clock_cfg)418 rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,419 wanted_clock_cfg);420 421 return rc;422}423 424static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,425 struct spi_message *mesg)426{427 int rc;428 u8 seq_slave = SPI_FSI_SEQUENCE_SEL_SLAVE(spi_get_chipselect(mesg->spi, 0) + 1);429 unsigned int len;430 struct spi_transfer *transfer;431 struct fsi_spi *ctx = spi_controller_get_devdata(ctlr);432 433 rc = fsi_spi_check_mux(ctx->bridge->fsi, ctx->dev);434 if (rc)435 goto error;436 437 list_for_each_entry(transfer, &mesg->transfers, transfer_list) {438 struct fsi_spi_sequence seq;439 struct spi_transfer *next = NULL;440 441 /* Sequencer must do shift out (tx) first. */442 if (!transfer->tx_buf || transfer->len > SPI_FSI_MAX_TX_SIZE) {443 rc = -EINVAL;444 goto error;445 }446 447 dev_dbg(ctx->dev, "Start tx of %d bytes.\n", transfer->len);448 449 rc = fsi_spi_transfer_init(ctx);450 if (rc < 0)451 goto error;452 453 fsi_spi_sequence_init(&seq);454 fsi_spi_sequence_add(&seq, seq_slave);455 456 len = transfer->len;457 while (len > 8) {458 fsi_spi_sequence_add(&seq,459 SPI_FSI_SEQUENCE_SHIFT_OUT(8));460 len -= 8;461 }462 fsi_spi_sequence_add(&seq, SPI_FSI_SEQUENCE_SHIFT_OUT(len));463 464 if (!list_is_last(&transfer->transfer_list,465 &mesg->transfers)) {466 next = list_next_entry(transfer, transfer_list);467 468 /* Sequencer can only do shift in (rx) after tx. */469 if (next->rx_buf) {470 u8 shift;471 472 if (next->len > SPI_FSI_MAX_RX_SIZE) {473 rc = -EINVAL;474 goto error;475 }476 477 dev_dbg(ctx->dev, "Sequence rx of %d bytes.\n",478 next->len);479 480 shift = SPI_FSI_SEQUENCE_SHIFT_IN(next->len);481 fsi_spi_sequence_add(&seq, shift);482 } else {483 next = NULL;484 }485 }486 487 fsi_spi_sequence_add(&seq, SPI_FSI_SEQUENCE_SEL_SLAVE(0));488 489 rc = fsi_spi_write_reg(ctx, SPI_FSI_SEQUENCE, seq.data);490 if (rc)491 goto error;492 493 rc = fsi_spi_transfer_data(ctx, transfer);494 if (rc)495 goto error;496 497 if (next) {498 rc = fsi_spi_transfer_data(ctx, next);499 if (rc)500 goto error;501 502 transfer = next;503 }504 }505 506error:507 mesg->status = rc;508 spi_finalize_current_message(ctlr);509 510 return rc;511}512 513static size_t fsi_spi_max_transfer_size(struct spi_device *spi)514{515 return SPI_FSI_MAX_RX_SIZE;516}517 518static int fsi_spi_probe(struct device *dev)519{520 int rc;521 struct device_node *np;522 int num_controllers_registered = 0;523 struct fsi2spi *bridge;524 struct fsi_device *fsi = to_fsi_dev(dev);525 526 rc = fsi_spi_check_mux(fsi, dev);527 if (rc)528 return -ENODEV;529 530 bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);531 if (!bridge)532 return -ENOMEM;533 534 bridge->fsi = fsi;535 mutex_init(&bridge->lock);536 537 for_each_available_child_of_node(dev->of_node, np) {538 u32 base;539 struct fsi_spi *ctx;540 struct spi_controller *ctlr;541 542 if (of_property_read_u32(np, "reg", &base))543 continue;544 545 ctlr = spi_alloc_host(dev, sizeof(*ctx));546 if (!ctlr) {547 of_node_put(np);548 break;549 }550 551 ctlr->dev.of_node = np;552 ctlr->num_chipselect = of_get_available_child_count(np) ?: 1;553 ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;554 ctlr->max_transfer_size = fsi_spi_max_transfer_size;555 ctlr->transfer_one_message = fsi_spi_transfer_one_message;556 557 ctx = spi_controller_get_devdata(ctlr);558 ctx->dev = &ctlr->dev;559 ctx->bridge = bridge;560 ctx->base = base + SPI_FSI_BASE;561 562 rc = devm_spi_register_controller(dev, ctlr);563 if (rc)564 spi_controller_put(ctlr);565 else566 num_controllers_registered++;567 }568 569 if (!num_controllers_registered)570 return -ENODEV;571 572 return 0;573}574 575static const struct fsi_device_id fsi_spi_ids[] = {576 { FSI_ENGID_SPI, FSI_VERSION_ANY },577 { }578};579MODULE_DEVICE_TABLE(fsi, fsi_spi_ids);580 581static struct fsi_driver fsi_spi_driver = {582 .id_table = fsi_spi_ids,583 .drv = {584 .name = "spi-fsi",585 .bus = &fsi_bus_type,586 .probe = fsi_spi_probe,587 },588};589module_fsi_driver(fsi_spi_driver);590 591MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>");592MODULE_DESCRIPTION("FSI attached SPI controller");593MODULE_LICENSE("GPL");594