From 7c3e45d12cfc9cd4ef874c4040105cae0af2e150 Mon Sep 17 00:00:00 2001 From: Siva Durga Prasad Paladugu Date: Sat, 28 Feb 2015 12:45:03 +0530 Subject: [PATCH] sf: Changes to support generic qspi Changes to support generic qspi controller in handling two separate requests and responses from two spi flash devices in dual parallel configuration. Signed-off-by: Siva Durga Prasad Paladugu Signed-off-by: Michal Simek --- drivers/mtd/spi/sf.c | 18 +++++-- drivers/mtd/spi/sf_ops.c | 105 +++++++++++++++++++++++++++++++------ drivers/mtd/spi/sf_probe.c | 77 ++++++++++++++++++++++++--- include/spi.h | 6 ++- 4 files changed, 179 insertions(+), 27 deletions(-) diff --git a/drivers/mtd/spi/sf.c b/drivers/mtd/spi/sf.c index 664e86082b1..d2f84619de7 100644 --- a/drivers/mtd/spi/sf.c +++ b/drivers/mtd/spi/sf.c @@ -15,28 +15,38 @@ static int spi_flash_read_write(struct spi_slave *spi, const u8 *data_out, u8 *data_in, size_t data_len) { - unsigned long flags = SPI_XFER_BEGIN; + unsigned long flags = 0; int ret; #ifdef CONFIG_SF_DUAL_FLASH if (spi->flags & SPI_XFER_U_PAGE) flags |= SPI_XFER_U_PAGE; +#ifdef CONFIG_SPI_GENERIC + if (spi->flags & SPI_XFER_LOWER) + flags |= SPI_XFER_LOWER; + if (spi->flags & SPI_XFER_UPPER) + flags |= SPI_XFER_UPPER; + if (spi->flags & SPI_XFER_STRIPE) + flags |= SPI_XFER_STRIPE; +#endif #endif if (data_len == 0) flags |= SPI_XFER_END; - ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); + ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags | SPI_XFER_BEGIN); if (ret) { debug("SF: Failed to send command (%zu bytes): %d\n", cmd_len, ret); } else if (data_len != 0) { ret = spi_xfer(spi, data_len * 8, data_out, data_in, - SPI_XFER_END); + flags | SPI_XFER_END); if (ret) debug("SF: Failed to transfer %zu bytes of data: %d\n", data_len, ret); } - +#ifdef CONFIG_SPI_GENERIC + spi->flags &= ~SPI_XFER_MASK; +#endif return ret; } diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index fc0ba2ab446..1ce4ab7b7fd 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -74,13 +74,34 @@ int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc) int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) { u8 data[2]; +#ifdef CONFIG_SPI_GENERIC + u8 dataup[2]; +#endif u8 cmd; int ret; +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) + flash->spi->flags |= SPI_XFER_LOWER; +#endif ret = spi_flash_cmd_read_status(flash, &data[0]); if (ret < 0) return ret; +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) { + flash->spi->flags |= SPI_XFER_UPPER; + ret = spi_flash_cmd_read_status(flash, &dataup[0]); + if (ret < 0) + return ret; + } +#endif + +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) + flash->spi->flags |= SPI_XFER_LOWER; +#endif + cmd = CMD_WRITE_STATUS; data[1] = wc; ret = spi_flash_write_common(flash, &cmd, 1, &data, 2); @@ -89,6 +110,18 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) return ret; } +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) { + flash->spi->flags |= SPI_XFER_UPPER; + dataup[1] = wc; + ret = spi_flash_write_common(flash, &cmd, 1, &dataup, 2); + if (ret) { + debug("SF: fail to write config register\n"); + return ret; + } + } +#endif + return 0; } #endif @@ -166,14 +199,18 @@ static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr) } #endif -static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout, +static int spi_flash_poll_status(struct spi_flash *flash, unsigned long timeout, u8 cmd, u8 poll_bit) { + struct spi_slave *spi = flash->spi; unsigned long timebase; - unsigned long flags = SPI_XFER_BEGIN; + unsigned long flags = 0; int ret; u8 status; u8 check_status = 0x0; +#ifdef CONFIG_SPI_GENERIC + u8 status_up; +#endif if (cmd == CMD_FLAG_STATUS) check_status = poll_bit; @@ -182,7 +219,7 @@ static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout, if (spi->flags & SPI_XFER_U_PAGE) flags |= SPI_XFER_U_PAGE; #endif - ret = spi_xfer(spi, 8, &cmd, NULL, flags); + ret = spi_xfer(spi, 8, &cmd, NULL, flags | SPI_XFER_BEGIN); if (ret) { debug("SF: fail to read %s status register\n", cmd == CMD_READ_STATUS ? "read" : "flag"); @@ -193,20 +230,50 @@ static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout, do { WATCHDOG_RESET(); - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) - return -1; - - if ((status & poll_bit) == check_status) - break; - +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash == SF_DUAL_PARALLEL_FLASH) { + ret = spi_xfer(spi, 8, NULL, &status, + flags | SPI_XFER_LOWER); + if (ret) + return -1; + ret = spi_xfer(spi, 8, NULL, &status_up, + flags | SPI_XFER_UPPER); + if (ret) + return -1; + debug("Poll Status:0x%x, Status_up:0x%x\n", status, + status_up); + + if (((status & poll_bit) == check_status) && + ((status_up & poll_bit) == check_status)) + break; + } else { +#endif + ret = spi_xfer(spi, 8, NULL, &status, flags); + if (ret) + return -1; + + debug("Poll Status:0x%x\n", status); + if ((status & poll_bit) == check_status) + break; +#ifdef CONFIG_SPI_GENERIC + } +#endif } while (get_timer(timebase) < timeout); - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + spi_xfer(spi, 0, NULL, NULL, flags | SPI_XFER_END); +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash == SF_DUAL_PARALLEL_FLASH) { + if (((status & poll_bit) == check_status) && + ((status_up & poll_bit) == check_status)) + return 0; + } else { +#endif if ((status & poll_bit) == check_status) return 0; - +#ifdef CONFIG_SPI_GENERIC + } +#endif /* Timed out */ debug("SF: time out!\n"); return -1; @@ -214,19 +281,18 @@ static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout, int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) { - struct spi_slave *spi = flash->spi; int ret; u8 poll_bit = STATUS_WIP; u8 cmd = CMD_READ_STATUS; - ret = spi_flash_poll_status(spi, timeout, cmd, poll_bit); + ret = spi_flash_poll_status(flash, timeout, cmd, poll_bit); if (ret < 0) return ret; if (flash->poll_cmd == CMD_FLAG_STATUS) { poll_bit = STATUS_PEC; cmd = CMD_FLAG_STATUS; - ret = spi_flash_poll_status(spi, timeout, cmd, poll_bit); + ret = spi_flash_poll_status(flash, timeout, cmd, poll_bit); if (ret < 0) return ret; } @@ -360,6 +426,10 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash == SF_DUAL_PARALLEL_FLASH) + flash->spi->flags |= SPI_XFER_STRIPE; +#endif ret = spi_flash_write_common(flash, cmd, sizeof(cmd), buf + actual, chunk_len); if (ret < 0) { @@ -453,6 +523,11 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, spi_flash_addr(read_addr, cmd); +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash == SF_DUAL_PARALLEL_FLASH) + flash->spi->flags |= SPI_XFER_STRIPE; +#endif + ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len); if (ret < 0) { debug("SF: read failed\n"); diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 93ee92498a4..d8fce407098 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -35,13 +35,31 @@ static u8 spi_read_cmds_array[] = { static int spi_flash_set_qeb_mxic(struct spi_flash *flash) { u8 qeb_status; +#ifdef CONFIG_SPI_GENERIC + u8 qeb_status_up; +#endif int ret; +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) + flash->spi->flags |= SPI_XFER_LOWER; +#endif + ret = spi_flash_cmd_read_status(flash, &qeb_status); if (ret < 0) return ret; - if (qeb_status & STATUS_QEB_MXIC) { +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) { + flash->spi->flags |= SPI_XFER_UPPER; + spi_flash_cmd_read_status(flash, &qeb_status_up); + } +#endif + if ((qeb_status & STATUS_QEB_MXIC) +#ifdef CONFIG_SPI_GENERIC + && (qeb_status_up & STATUS_QEB_MXIC) +#endif + ) { debug("SF: mxic: QEB is already set\n"); } else { ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); @@ -57,13 +75,31 @@ static int spi_flash_set_qeb_mxic(struct spi_flash *flash) static int spi_flash_set_qeb_winspan(struct spi_flash *flash) { u8 qeb_status; +#ifdef CONFIG_SPI_GENERIC + u8 qeb_status_up; +#endif int ret; +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) + flash->spi->flags |= SPI_XFER_LOWER; +#endif + ret = spi_flash_cmd_read_config(flash, &qeb_status); if (ret < 0) return ret; - if (qeb_status & STATUS_QEB_WINSPAN) { +#ifdef CONFIG_SPI_GENERIC + if (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) { + flash->spi->flags |= SPI_XFER_UPPER; + ret = spi_flash_cmd_read_config(flash, &qeb_status_up); + } +#endif + if ((qeb_status & STATUS_QEB_WINSPAN) +#ifdef CONFIG_SPI_GENERIC + && (qeb_status_up & STATUS_QEB_WINSPAN) +#endif + ) { debug("SF: winspan: QEB is already set\n"); } else { ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); @@ -258,11 +294,15 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, flash->bank_write_cmd = (idcode[0] == 0x01) ? CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR; - ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, - &curr_bank, 1); - if (ret) { - debug("SF: fail to read bank addr register\n"); - return ret; + if (flash->dual_flash == SF_DUAL_PARALLEL_FLASH) { + spi->flags |= SPI_XFER_LOWER; + ret = spi_flash_read_common(flash, + &flash->bank_read_cmd, + 1, &curr_bank, 1); + if (ret) { + debug("SF: fail to read bank addr register\n"); + return ret; + } } flash->bank_curr = curr_bank; } else { @@ -346,6 +386,10 @@ static int spi_enable_wp_pin(struct spi_flash *flash) int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) { u8 idcode[5]; +#ifdef CONFIG_SPI_GENERIC + u8 idcode_up[5]; + u8 i; +#endif int ret; /* Setup spi_slave */ @@ -361,6 +405,8 @@ int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) return ret; } + if (spi->option == SF_DUAL_PARALLEL_FLASH) + spi->flags |= SPI_XFER_LOWER; /* Read the ID codes */ ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); if (ret) { @@ -368,6 +414,23 @@ int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) goto err_read_id; } +#ifdef CONFIG_SPI_GENERIC + if (spi->option == SF_DUAL_PARALLEL_FLASH) { + spi->flags |= SPI_XFER_UPPER; + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode_up, + sizeof(idcode_up)); + if (ret) { + printf("SF: Failed to get idcodes\n"); + goto err_read_id; + } + for (i = 0; i < sizeof(idcode); i++) { + if (idcode[i] != idcode_up[i]) { + printf("SF: Failed to get same idcodes\n"); + goto err_read_id; + } + } + } +#endif #ifdef DEBUG printf("SF: Got idcodes\n"); print_buffer(0, idcode, 1, sizeof(idcode), 0); diff --git a/include/spi.h b/include/spi.h index ae53ba54b8f..7f2472b06c0 100644 --- a/include/spi.h +++ b/include/spi.h @@ -31,6 +31,10 @@ #define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ #define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END) #define SPI_XFER_U_PAGE (1 << 5) +#define SPI_XFER_STRIPE (1 << 6) +#define SPI_XFER_MASK (3 << 8) +#define SPI_XFER_LOWER (1 << 8) +#define SPI_XFER_UPPER (2 << 8) /* SPI TX operation modes */ #define SPI_OPM_TX_QPP (1 << 0) @@ -106,7 +110,7 @@ struct spi_slave { unsigned int max_write_size; void *memory_map; u8 option; - u8 flags; + u32 flags; }; /** -- 2.47.3