| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * TI QSPI driver |
|---|
| 3 | 4 | * |
|---|
| 4 | | - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com |
|---|
| 5 | + * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com |
|---|
| 5 | 6 | * Author: Sourav Poddar <sourav.poddar@ti.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GPLv2. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | 7 | */ |
|---|
| 15 | 8 | |
|---|
| 16 | 9 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 86 | 79 | #define QSPI_SPI_DATA_REG_3 (0x70) |
|---|
| 87 | 80 | |
|---|
| 88 | 81 | #define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000) |
|---|
| 89 | | - |
|---|
| 90 | | -#define QSPI_FCLK 192000000 |
|---|
| 91 | 82 | |
|---|
| 92 | 83 | /* Clock Control */ |
|---|
| 93 | 84 | #define QSPI_CLK_EN (1 << 31) |
|---|
| .. | .. |
|---|
| 324 | 315 | { |
|---|
| 325 | 316 | int wlen; |
|---|
| 326 | 317 | unsigned int cmd; |
|---|
| 318 | + u32 rx; |
|---|
| 319 | + u8 rxlen, rx_wlen; |
|---|
| 327 | 320 | u8 *rxbuf; |
|---|
| 328 | 321 | |
|---|
| 329 | 322 | rxbuf = t->rx_buf; |
|---|
| .. | .. |
|---|
| 340 | 333 | break; |
|---|
| 341 | 334 | } |
|---|
| 342 | 335 | wlen = t->bits_per_word >> 3; /* in bytes */ |
|---|
| 336 | + rx_wlen = wlen; |
|---|
| 343 | 337 | |
|---|
| 344 | 338 | while (count) { |
|---|
| 345 | 339 | dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); |
|---|
| 346 | 340 | if (qspi_is_busy(qspi)) |
|---|
| 347 | 341 | return -EBUSY; |
|---|
| 348 | 342 | |
|---|
| 343 | + switch (wlen) { |
|---|
| 344 | + case 1: |
|---|
| 345 | + /* |
|---|
| 346 | + * Optimize the 8-bit words transfers, as used by |
|---|
| 347 | + * the SPI flash devices. |
|---|
| 348 | + */ |
|---|
| 349 | + if (count >= QSPI_WLEN_MAX_BYTES) { |
|---|
| 350 | + rxlen = QSPI_WLEN_MAX_BYTES; |
|---|
| 351 | + } else { |
|---|
| 352 | + rxlen = min(count, 4); |
|---|
| 353 | + } |
|---|
| 354 | + rx_wlen = rxlen << 3; |
|---|
| 355 | + cmd &= ~QSPI_WLEN_MASK; |
|---|
| 356 | + cmd |= QSPI_WLEN(rx_wlen); |
|---|
| 357 | + break; |
|---|
| 358 | + default: |
|---|
| 359 | + rxlen = wlen; |
|---|
| 360 | + break; |
|---|
| 361 | + } |
|---|
| 362 | + |
|---|
| 349 | 363 | ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); |
|---|
| 350 | 364 | if (ti_qspi_poll_wc(qspi)) { |
|---|
| 351 | 365 | dev_err(qspi->dev, "read timed out\n"); |
|---|
| 352 | 366 | return -ETIMEDOUT; |
|---|
| 353 | 367 | } |
|---|
| 368 | + |
|---|
| 354 | 369 | switch (wlen) { |
|---|
| 355 | 370 | case 1: |
|---|
| 356 | | - *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG); |
|---|
| 371 | + /* |
|---|
| 372 | + * Optimize the 8-bit words transfers, as used by |
|---|
| 373 | + * the SPI flash devices. |
|---|
| 374 | + */ |
|---|
| 375 | + if (count >= QSPI_WLEN_MAX_BYTES) { |
|---|
| 376 | + u32 *rxp = (u32 *) rxbuf; |
|---|
| 377 | + rx = readl(qspi->base + QSPI_SPI_DATA_REG_3); |
|---|
| 378 | + *rxp++ = be32_to_cpu(rx); |
|---|
| 379 | + rx = readl(qspi->base + QSPI_SPI_DATA_REG_2); |
|---|
| 380 | + *rxp++ = be32_to_cpu(rx); |
|---|
| 381 | + rx = readl(qspi->base + QSPI_SPI_DATA_REG_1); |
|---|
| 382 | + *rxp++ = be32_to_cpu(rx); |
|---|
| 383 | + rx = readl(qspi->base + QSPI_SPI_DATA_REG); |
|---|
| 384 | + *rxp++ = be32_to_cpu(rx); |
|---|
| 385 | + } else { |
|---|
| 386 | + u8 *rxp = rxbuf; |
|---|
| 387 | + rx = readl(qspi->base + QSPI_SPI_DATA_REG); |
|---|
| 388 | + if (rx_wlen >= 8) |
|---|
| 389 | + *rxp++ = rx >> (rx_wlen - 8); |
|---|
| 390 | + if (rx_wlen >= 16) |
|---|
| 391 | + *rxp++ = rx >> (rx_wlen - 16); |
|---|
| 392 | + if (rx_wlen >= 24) |
|---|
| 393 | + *rxp++ = rx >> (rx_wlen - 24); |
|---|
| 394 | + if (rx_wlen >= 32) |
|---|
| 395 | + *rxp++ = rx; |
|---|
| 396 | + } |
|---|
| 357 | 397 | break; |
|---|
| 358 | 398 | case 2: |
|---|
| 359 | 399 | *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); |
|---|
| .. | .. |
|---|
| 362 | 402 | *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); |
|---|
| 363 | 403 | break; |
|---|
| 364 | 404 | } |
|---|
| 365 | | - rxbuf += wlen; |
|---|
| 366 | | - count -= wlen; |
|---|
| 405 | + rxbuf += rxlen; |
|---|
| 406 | + count -= rxlen; |
|---|
| 367 | 407 | } |
|---|
| 368 | 408 | |
|---|
| 369 | 409 | return 0; |
|---|
| .. | .. |
|---|
| 408 | 448 | enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; |
|---|
| 409 | 449 | struct dma_async_tx_descriptor *tx; |
|---|
| 410 | 450 | int ret; |
|---|
| 451 | + unsigned long time_left; |
|---|
| 411 | 452 | |
|---|
| 412 | 453 | tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags); |
|---|
| 413 | 454 | if (!tx) { |
|---|
| .. | .. |
|---|
| 427 | 468 | } |
|---|
| 428 | 469 | |
|---|
| 429 | 470 | dma_async_issue_pending(chan); |
|---|
| 430 | | - ret = wait_for_completion_timeout(&qspi->transfer_complete, |
|---|
| 471 | + time_left = wait_for_completion_timeout(&qspi->transfer_complete, |
|---|
| 431 | 472 | msecs_to_jiffies(len)); |
|---|
| 432 | | - if (ret <= 0) { |
|---|
| 473 | + if (time_left == 0) { |
|---|
| 433 | 474 | dmaengine_terminate_sync(chan); |
|---|
| 434 | 475 | dev_err(qspi->dev, "DMA wait_for_completion_timeout\n"); |
|---|
| 435 | 476 | return -ETIMEDOUT; |
|---|
| .. | .. |
|---|
| 535 | 576 | QSPI_SPI_SETUP_REG(spi->chip_select)); |
|---|
| 536 | 577 | } |
|---|
| 537 | 578 | |
|---|
| 579 | +static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) |
|---|
| 580 | +{ |
|---|
| 581 | + struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master); |
|---|
| 582 | + size_t max_len; |
|---|
| 583 | + |
|---|
| 584 | + if (op->data.dir == SPI_MEM_DATA_IN) { |
|---|
| 585 | + if (op->addr.val < qspi->mmap_size) { |
|---|
| 586 | + /* Limit MMIO to the mmaped region */ |
|---|
| 587 | + if (op->addr.val + op->data.nbytes > qspi->mmap_size) { |
|---|
| 588 | + max_len = qspi->mmap_size - op->addr.val; |
|---|
| 589 | + op->data.nbytes = min((size_t) op->data.nbytes, |
|---|
| 590 | + max_len); |
|---|
| 591 | + } |
|---|
| 592 | + } else { |
|---|
| 593 | + /* |
|---|
| 594 | + * Use fallback mode (SW generated transfers) above the |
|---|
| 595 | + * mmaped region. |
|---|
| 596 | + * Adjust size to comply with the QSPI max frame length. |
|---|
| 597 | + */ |
|---|
| 598 | + max_len = QSPI_FRAME; |
|---|
| 599 | + max_len -= 1 + op->addr.nbytes + op->dummy.nbytes; |
|---|
| 600 | + op->data.nbytes = min((size_t) op->data.nbytes, |
|---|
| 601 | + max_len); |
|---|
| 602 | + } |
|---|
| 603 | + } |
|---|
| 604 | + |
|---|
| 605 | + return 0; |
|---|
| 606 | +} |
|---|
| 607 | + |
|---|
| 538 | 608 | static int ti_qspi_exec_mem_op(struct spi_mem *mem, |
|---|
| 539 | 609 | const struct spi_mem_op *op) |
|---|
| 540 | 610 | { |
|---|
| .. | .. |
|---|
| 585 | 655 | |
|---|
| 586 | 656 | static const struct spi_controller_mem_ops ti_qspi_mem_ops = { |
|---|
| 587 | 657 | .exec_op = ti_qspi_exec_mem_op, |
|---|
| 658 | + .adjust_op_size = ti_qspi_adjust_op_size, |
|---|
| 588 | 659 | }; |
|---|
| 589 | 660 | |
|---|
| 590 | 661 | static int ti_qspi_start_transfer_one(struct spi_master *master, |
|---|
| .. | .. |
|---|
| 739 | 810 | |
|---|
| 740 | 811 | irq = platform_get_irq(pdev, 0); |
|---|
| 741 | 812 | if (irq < 0) { |
|---|
| 742 | | - dev_err(&pdev->dev, "no irq resource?\n"); |
|---|
| 743 | 813 | ret = irq; |
|---|
| 744 | 814 | goto free_master; |
|---|
| 745 | 815 | } |
|---|