From 4d5e29a680fc68f02b069a0780d7c71063219b18 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Thu, 29 Aug 2013 19:01:56 +0530 Subject: sf: Divide spi_flash into multiple parts Divided the spi_flash framework into mutiple parts for - spi_flash.c: spi flash core file, interaction for spi/qspi driver to spi_flash framework. - spi_flash_ops.c spi flash preffered operations, erase,write and read. - spi_flash_probe.c spi flash probing, easy to extend probing functionality. This change will support to extend the functionality in a proper manner. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/Makefile | 2 +- drivers/mtd/spi/spi_flash.c | 571 +------------------------------------- drivers/mtd/spi/spi_flash_ops.c | 314 +++++++++++++++++++++ drivers/mtd/spi/spi_flash_probe.c | 276 ++++++++++++++++++ 4 files changed, 596 insertions(+), 567 deletions(-) create mode 100644 drivers/mtd/spi/spi_flash_ops.c create mode 100644 drivers/mtd/spi/spi_flash_probe.c diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 191138ad18..193cb5d0e9 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -14,7 +14,7 @@ COBJS-$(CONFIG_SPL_SPI_LOAD) += spi_spl_load.o COBJS-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o endif -COBJS-$(CONFIG_SPI_FLASH) += spi_flash.o +COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe.o spi_flash_ops.o spi_flash.o COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o COBJS-$(CONFIG_SPI_FLASH_EON) += eon.o COBJS-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.o diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 5d5055ff38..ddbdda0dc2 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -8,23 +8,7 @@ */ #include -#include -#include #include -#include -#include - -#include "spi_flash_internal.h" - -DECLARE_GLOBAL_DATA_PTR; - -static void spi_flash_addr(u32 addr, u8 *cmd) -{ - /* cmd[0] is actual command */ - cmd[1] = addr >> 16; - cmd[2] = addr >> 8; - cmd[3] = addr >> 0; -} static int spi_flash_read_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, @@ -52,564 +36,19 @@ static int spi_flash_read_write(struct spi_slave *spi, return ret; } -int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) -{ - return spi_flash_cmd_read(spi, &cmd, 1, response, len); -} - int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, void *data, size_t data_len) { return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len); } -int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, - const void *data, size_t data_len) -{ - return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); -} - -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 status; - u8 check_status = 0x0; - u8 poll_bit = STATUS_WIP; - u8 cmd = flash->poll_cmd; - - if (cmd == CMD_FLAG_STATUS) { - poll_bit = STATUS_PEC; - check_status = poll_bit; - } - - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); - if (ret) { - debug("SF: fail to read %s status register\n", - cmd == CMD_READ_STATUS ? "read" : "flag"); - return ret; - } - - timebase = get_timer(0); - do { - WATCHDOG_RESET(); - - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) - return -1; - - if ((status & poll_bit) == check_status) - break; - - } while (get_timer(timebase) < timeout); - - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if ((status & poll_bit) == check_status) - return 0; - - /* Timed out */ - debug("SF: time out!\n"); - return -1; -} - -int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, const void *buf, size_t buf_len) -{ - struct spi_slave *spi = flash->spi; - unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; - int ret; - - if (buf == NULL) - timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: unable to claim SPI bus\n"); - return ret; - } - - ret = spi_flash_cmd_write_enable(flash); - if (ret < 0) { - debug("SF: enabling write failed\n"); - return ret; - } - - ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); - if (ret < 0) { - debug("SF: write cmd failed\n"); - return ret; - } - - ret = spi_flash_cmd_wait_ready(flash, timeout); - if (ret < 0) { - debug("SF: write %s timed out\n", - timeout == SPI_FLASH_PROG_TIMEOUT ? - "program" : "page erase"); - return ret; - } - - spi_release_bus(spi); - - return ret; -} - -int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) -{ - u32 erase_size; - u8 cmd[4]; - int ret = -1; - - erase_size = flash->sector_size; - if (offset % erase_size || len % erase_size) { - debug("SF: Erase offset/length not multiple of erase size\n"); - return -1; - } - - if (erase_size == 4096) - cmd[0] = CMD_ERASE_4K; - else - cmd[0] = CMD_ERASE_64K; - - while (len) { -#ifdef CONFIG_SPI_FLASH_BAR - u8 bank_sel; - - bank_sel = offset / SPI_FLASH_16MB_BOUN; - - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); - if (ret) { - debug("SF: fail to set bank%d\n", bank_sel); - return ret; - } -#endif - spi_flash_addr(offset, cmd); - - debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], - cmd[2], cmd[3], offset); - - ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); - if (ret < 0) { - debug("SF: erase failed\n"); - break; - } - - offset += erase_size; - len -= erase_size; - } - - return ret; -} - -int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, - size_t len, const void *buf) -{ - unsigned long byte_addr, page_size; - size_t chunk_len, actual; - u8 cmd[4]; - int ret = -1; - - page_size = flash->page_size; - - cmd[0] = CMD_PAGE_PROGRAM; - for (actual = 0; actual < len; actual += chunk_len) { -#ifdef CONFIG_SPI_FLASH_BAR - u8 bank_sel; - - bank_sel = offset / SPI_FLASH_16MB_BOUN; - - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); - if (ret) { - debug("SF: fail to set bank%d\n", bank_sel); - return ret; - } -#endif - byte_addr = offset % page_size; - chunk_len = min(len - actual, page_size - byte_addr); - - if (flash->spi->max_write_size) - chunk_len = min(chunk_len, flash->spi->max_write_size); - - spi_flash_addr(offset, cmd); - - debug("PP: 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); - - ret = spi_flash_write_common(flash, cmd, sizeof(cmd), - buf + actual, chunk_len); - if (ret < 0) { - debug("SF: write failed\n"); - break; - } - - offset += chunk_len; - } - - return ret; -} - -int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len) -{ - struct spi_slave *spi = flash->spi; - int ret; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: unable to claim SPI bus\n"); - return ret; - } - - ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); - if (ret < 0) { - debug("SF: read cmd failed\n"); - return ret; - } - - spi_release_bus(spi); - - return ret; -} - -int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, - size_t len, void *data) -{ - u8 cmd[5], bank_sel = 0; - u32 remain_len, read_len; - int ret = -1; - - /* Handle memory-mapped SPI */ - if (flash->memory_map) { - memcpy(data, flash->memory_map + offset, len); - return 0; - } - - cmd[0] = CMD_READ_ARRAY_FAST; - cmd[4] = 0x00; - - while (len) { -#ifdef CONFIG_SPI_FLASH_BAR - bank_sel = offset / SPI_FLASH_16MB_BOUN; - - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); - if (ret) { - debug("SF: fail to set bank%d\n", bank_sel); - return ret; - } -#endif - remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); - if (len < remain_len) - read_len = len; - else - read_len = remain_len; - - spi_flash_addr(offset, cmd); - - ret = spi_flash_read_common(flash, cmd, sizeof(cmd), - data, read_len); - if (ret < 0) { - debug("SF: read failed\n"); - break; - } - - offset += read_len; - len -= read_len; - data += read_len; - } - - return ret; -} - -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) -{ - u8 cmd; - int ret; - - cmd = CMD_WRITE_STATUS; - ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); - if (ret < 0) { - debug("SF: fail to write status register\n"); - return ret; - } - - return 0; -} - -#ifdef CONFIG_SPI_FLASH_BAR -int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) -{ - u8 cmd; - int ret; - - if (flash->bank_curr == bank_sel) { - debug("SF: not require to enable bank%d\n", bank_sel); - return 0; - } - - cmd = flash->bank_write_cmd; - ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); - if (ret < 0) { - debug("SF: fail to write bank register\n"); - return ret; - } - flash->bank_curr = bank_sel; - - return 0; -} - -int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) -{ - u8 cmd; - u8 curr_bank = 0; - - /* discover bank cmds */ - switch (idcode0) { - case SPI_FLASH_SPANSION_IDCODE0: - flash->bank_read_cmd = CMD_BANKADDR_BRRD; - flash->bank_write_cmd = CMD_BANKADDR_BRWR; - break; - case SPI_FLASH_STMICRO_IDCODE0: - case SPI_FLASH_WINBOND_IDCODE0: - flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; - flash->bank_write_cmd = CMD_EXTNADDR_WREAR; - break; - default: - printf("SF: Unsupported bank commands %02x\n", idcode0); - return -1; - } - - /* read the bank reg - on which bank the flash is in currently */ - cmd = flash->bank_read_cmd; - if (flash->size > SPI_FLASH_16MB_BOUN) { - if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { - debug("SF: fail to read bank addr register\n"); - return -1; - } - flash->bank_curr = curr_bank; - } else { - flash->bank_curr = curr_bank; - } - - return 0; -} -#endif - -#ifdef CONFIG_OF_CONTROL -int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) -{ - fdt_addr_t addr; - fdt_size_t size; - int node; - - /* If there is no node, do nothing */ - node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); - if (node < 0) - return 0; - - addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); - if (addr == FDT_ADDR_T_NONE) { - debug("%s: Cannot decode address\n", __func__); - return 0; - } - - if (flash->size != size) { - debug("%s: Memory map must cover entire device\n", __func__); - return -1; - } - flash->memory_map = (void *)addr; - - return 0; -} -#endif /* CONFIG_OF_CONTROL */ - -/* - * The following table holds all device probe functions - * - * shift: number of continuation bytes before the ID - * idcode: the expected IDCODE or 0xff for non JEDEC devices - * probe: the function to call - * - * Non JEDEC devices should be ordered in the table such that - * the probe functions with best detection algorithms come first. - * - * Several matching entries are permitted, they will be tried - * in sequence until a probe function returns non NULL. - * - * IDCODE_CONT_LEN may be redefined if a device needs to declare a - * larger "shift" value. IDCODE_PART_LEN generally shouldn't be - * changed. This is the max number of bytes probe functions may - * examine when looking up part-specific identification info. - * - * Probe functions will be given the idcode buffer starting at their - * manu id byte (the "idcode" in the table below). In other words, - * all of the continuation bytes will be skipped (the "shift" below). - */ -#define IDCODE_CONT_LEN 0 -#define IDCODE_PART_LEN 5 -static const struct { - const u8 shift; - const u8 idcode; - struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); -} flashes[] = { - /* Keep it sorted by define name */ -#ifdef CONFIG_SPI_FLASH_ATMEL - { 0, 0x1f, spi_flash_probe_atmel, }, -#endif -#ifdef CONFIG_SPI_FLASH_EON - { 0, 0x1c, spi_flash_probe_eon, }, -#endif -#ifdef CONFIG_SPI_FLASH_GIGADEVICE - { 0, 0xc8, spi_flash_probe_gigadevice, }, -#endif -#ifdef CONFIG_SPI_FLASH_MACRONIX - { 0, 0xc2, spi_flash_probe_macronix, }, -#endif -#ifdef CONFIG_SPI_FLASH_SPANSION - { 0, 0x01, spi_flash_probe_spansion, }, -#endif -#ifdef CONFIG_SPI_FLASH_SST - { 0, 0xbf, spi_flash_probe_sst, }, -#endif -#ifdef CONFIG_SPI_FLASH_STMICRO - { 0, 0x20, spi_flash_probe_stmicro, }, -#endif -#ifdef CONFIG_SPI_FLASH_WINBOND - { 0, 0xef, spi_flash_probe_winbond, }, -#endif -#ifdef CONFIG_SPI_FRAM_RAMTRON - { 6, 0xc2, spi_fram_probe_ramtron, }, -# undef IDCODE_CONT_LEN -# define IDCODE_CONT_LEN 6 -#endif - /* Keep it sorted by best detection */ -#ifdef CONFIG_SPI_FLASH_STMICRO - { 0, 0xff, spi_flash_probe_stmicro, }, -#endif -#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC - { 0, 0xff, spi_fram_probe_ramtron, }, -#endif -}; -#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) - -struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int spi_mode) -{ - struct spi_slave *spi; - struct spi_flash *flash = NULL; - int ret, i, shift; - u8 idcode[IDCODE_LEN], *idp; - - spi = spi_setup_slave(bus, cs, max_hz, spi_mode); - if (!spi) { - printf("SF: Failed to set up slave\n"); - return NULL; - } - - ret = spi_claim_bus(spi); - if (ret) { - debug("SF: Failed to claim SPI bus: %d\n", ret); - goto err_claim_bus; - } - - /* Read the ID codes */ - ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); - if (ret) - goto err_read_id; - -#ifdef DEBUG - printf("SF: Got idcodes\n"); - print_buffer(0, idcode, 1, sizeof(idcode), 0); -#endif - - /* count the number of continuation bytes */ - for (shift = 0, idp = idcode; - shift < IDCODE_CONT_LEN && *idp == 0x7f; - ++shift, ++idp) - continue; - - /* search the table for matches in shift and id */ - for (i = 0; i < ARRAY_SIZE(flashes); ++i) - if (flashes[i].shift == shift && flashes[i].idcode == *idp) { - /* we have a match, call probe */ - flash = flashes[i].probe(spi, idp); - if (flash) - break; - } - - if (!flash) { - printf("SF: Unsupported manufacturer %02x\n", *idp); - goto err_manufacturer_probe; - } - -#ifdef CONFIG_SPI_FLASH_BAR - /* Configure the BAR - disover bank cmds and read current bank */ - ret = spi_flash_bank_config(flash, *idp); - if (ret < 0) - goto err_manufacturer_probe; -#endif - -#ifdef CONFIG_OF_CONTROL - if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { - debug("SF: FDT decode error\n"); - goto err_manufacturer_probe; - } -#endif -#ifndef CONFIG_SPL_BUILD - printf("SF: Detected %s with page size ", flash->name); - print_size(flash->sector_size, ", total "); - print_size(flash->size, ""); - if (flash->memory_map) - printf(", mapped at %p", flash->memory_map); - puts("\n"); -#endif -#ifndef CONFIG_SPI_FLASH_BAR - if (flash->size > SPI_FLASH_16MB_BOUN) { - puts("SF: Warning - Only lower 16MiB accessible,"); - puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); - } -#endif - - spi_release_bus(spi); - - return flash; - -err_manufacturer_probe: -err_read_id: - spi_release_bus(spi); -err_claim_bus: - spi_free_slave(spi); - return NULL; -} - -void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, - const char *name) +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) { - struct spi_flash *flash; - void *ptr; - - ptr = malloc(size); - if (!ptr) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - memset(ptr, '\0', size); - flash = (struct spi_flash *)(ptr + offset); - - /* Set up some basic fields - caller will sort out sizes */ - flash->spi = spi; - flash->name = name; - flash->poll_cmd = CMD_READ_STATUS; - - flash->read = spi_flash_cmd_read_fast; - flash->write = spi_flash_cmd_write_multi; - flash->erase = spi_flash_cmd_erase; - - return flash; + return spi_flash_cmd_read(spi, &cmd, 1, response, len); } -void spi_flash_free(struct spi_flash *flash) +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) { - spi_free_slave(flash->spi); - free(flash); + return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); } diff --git a/drivers/mtd/spi/spi_flash_ops.c b/drivers/mtd/spi/spi_flash_ops.c new file mode 100644 index 0000000000..6133363f42 --- /dev/null +++ b/drivers/mtd/spi/spi_flash_ops.c @@ -0,0 +1,314 @@ +/* + * SPI flash operations + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +#include "spi_flash_internal.h" + +static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) +{ + u8 cmd; + int ret; + + cmd = CMD_WRITE_STATUS; + ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); + if (ret < 0) { + debug("SF: fail to write status register\n"); + return ret; + } + + return 0; +} + +#ifdef CONFIG_SPI_FLASH_BAR +int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) +{ + u8 cmd; + int ret; + + if (flash->bank_curr == bank_sel) { + debug("SF: not require to enable bank%d\n", bank_sel); + return 0; + } + + cmd = flash->bank_write_cmd; + ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); + if (ret < 0) { + debug("SF: fail to write bank register\n"); + return ret; + } + flash->bank_curr = bank_sel; + + return 0; +} +#endif + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + u8 check_status = 0x0; + u8 poll_bit = STATUS_WIP; + u8 cmd = flash->poll_cmd; + + if (cmd == CMD_FLAG_STATUS) { + poll_bit = STATUS_PEC; + check_status = poll_bit; + } + + ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); + if (ret) { + debug("SF: fail to read %s status register\n", + cmd == CMD_READ_STATUS ? "read" : "flag"); + return ret; + } + + timebase = get_timer(0); + do { + WATCHDOG_RESET(); + + ret = spi_xfer(spi, 8, NULL, &status, 0); + if (ret) + return -1; + + if ((status & poll_bit) == check_status) + break; + + } while (get_timer(timebase) < timeout); + + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + if ((status & poll_bit) == check_status) + return 0; + + /* Timed out */ + debug("SF: time out!\n"); + return -1; +} + +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, const void *buf, size_t buf_len) +{ + struct spi_slave *spi = flash->spi; + unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; + int ret; + + if (buf == NULL) + timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: unable to claim SPI bus\n"); + return ret; + } + + ret = spi_flash_cmd_write_enable(flash); + if (ret < 0) { + debug("SF: enabling write failed\n"); + return ret; + } + + ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); + if (ret < 0) { + debug("SF: write cmd failed\n"); + return ret; + } + + ret = spi_flash_cmd_wait_ready(flash, timeout); + if (ret < 0) { + debug("SF: write %s timed out\n", + timeout == SPI_FLASH_PROG_TIMEOUT ? + "program" : "page erase"); + return ret; + } + + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + u32 erase_size; + u8 cmd[4]; + int ret = -1; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + debug("SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + if (erase_size == 4096) + cmd[0] = CMD_ERASE_4K; + else + cmd[0] = CMD_ERASE_64K; + + while (len) { +#ifdef CONFIG_SPI_FLASH_BAR + u8 bank_sel; + + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + spi_flash_addr(offset, cmd); + + debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); + if (ret < 0) { + debug("SF: erase failed\n"); + break; + } + + offset += erase_size; + len -= erase_size; + } + + return ret; +} + +int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + unsigned long byte_addr, page_size; + size_t chunk_len, actual; + u8 cmd[4]; + int ret = -1; + + page_size = flash->page_size; + + cmd[0] = CMD_PAGE_PROGRAM; + for (actual = 0; actual < len; actual += chunk_len) { +#ifdef CONFIG_SPI_FLASH_BAR + u8 bank_sel; + + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + byte_addr = offset % page_size; + chunk_len = min(len - actual, page_size - byte_addr); + + if (flash->spi->max_write_size) + chunk_len = min(chunk_len, flash->spi->max_write_size); + + spi_flash_addr(offset, cmd); + + debug("PP: 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); + + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), + buf + actual, chunk_len); + if (ret < 0) { + debug("SF: write failed\n"); + break; + } + + offset += chunk_len; + } + + return ret; +} + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: unable to claim SPI bus\n"); + return ret; + } + + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + if (ret < 0) { + debug("SF: read cmd failed\n"); + return ret; + } + + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + u8 cmd[5], bank_sel = 0; + u32 remain_len, read_len; + int ret = -1; + + /* Handle memory-mapped SPI */ + if (flash->memory_map) { + memcpy(data, flash->memory_map + offset, len); + return 0; + } + + cmd[0] = CMD_READ_ARRAY_FAST; + cmd[4] = 0x00; + + while (len) { +#ifdef CONFIG_SPI_FLASH_BAR + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); + if (len < remain_len) + read_len = len; + else + read_len = remain_len; + + spi_flash_addr(offset, cmd); + + ret = spi_flash_read_common(flash, cmd, sizeof(cmd), + data, read_len); + if (ret < 0) { + debug("SF: read failed\n"); + break; + } + + offset += read_len; + len -= read_len; + data += read_len; + } + + return ret; +} diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c new file mode 100644 index 0000000000..32ec578d0d --- /dev/null +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -0,0 +1,276 @@ +/* + * SPI flash probing + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include + +#include "spi_flash_internal.h" + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_SPI_FLASH_BAR +int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) +{ + u8 cmd; + u8 curr_bank = 0; + + /* discover bank cmds */ + switch (idcode0) { + case SPI_FLASH_SPANSION_IDCODE0: + flash->bank_read_cmd = CMD_BANKADDR_BRRD; + flash->bank_write_cmd = CMD_BANKADDR_BRWR; + break; + case SPI_FLASH_STMICRO_IDCODE0: + case SPI_FLASH_WINBOND_IDCODE0: + flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; + flash->bank_write_cmd = CMD_EXTNADDR_WREAR; + break; + default: + printf("SF: Unsupported bank commands %02x\n", idcode0); + return -1; + } + + /* read the bank reg - on which bank the flash is in currently */ + cmd = flash->bank_read_cmd; + if (flash->size > SPI_FLASH_16MB_BOUN) { + if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { + debug("SF: fail to read bank addr register\n"); + return -1; + } + flash->bank_curr = curr_bank; + } else { + flash->bank_curr = curr_bank; + } + + return 0; +} +#endif + +#ifdef CONFIG_OF_CONTROL +int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) +{ + fdt_addr_t addr; + fdt_size_t size; + int node; + + /* If there is no node, do nothing */ + node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); + if (node < 0) + return 0; + + addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); + if (addr == FDT_ADDR_T_NONE) { + debug("%s: Cannot decode address\n", __func__); + return 0; + } + + if (flash->size != size) { + debug("%s: Memory map must cover entire device\n", __func__); + return -1; + } + flash->memory_map = (void *)addr; + + return 0; +} +#endif /* CONFIG_OF_CONTROL */ + +/* + * The following table holds all device probe functions + * + * shift: number of continuation bytes before the ID + * idcode: the expected IDCODE or 0xff for non JEDEC devices + * probe: the function to call + * + * Non JEDEC devices should be ordered in the table such that + * the probe functions with best detection algorithms come first. + * + * Several matching entries are permitted, they will be tried + * in sequence until a probe function returns non NULL. + * + * IDCODE_CONT_LEN may be redefined if a device needs to declare a + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be + * changed. This is the max number of bytes probe functions may + * examine when looking up part-specific identification info. + * + * Probe functions will be given the idcode buffer starting at their + * manu id byte (the "idcode" in the table below). In other words, + * all of the continuation bytes will be skipped (the "shift" below). + */ +#define IDCODE_CONT_LEN 0 +#define IDCODE_PART_LEN 5 +static const struct { + const u8 shift; + const u8 idcode; + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); +} flashes[] = { + /* Keep it sorted by define name */ +#ifdef CONFIG_SPI_FLASH_ATMEL + { 0, 0x1f, spi_flash_probe_atmel, }, +#endif +#ifdef CONFIG_SPI_FLASH_EON + { 0, 0x1c, spi_flash_probe_eon, }, +#endif +#ifdef CONFIG_SPI_FLASH_GIGADEVICE + { 0, 0xc8, spi_flash_probe_gigadevice, }, +#endif +#ifdef CONFIG_SPI_FLASH_MACRONIX + { 0, 0xc2, spi_flash_probe_macronix, }, +#endif +#ifdef CONFIG_SPI_FLASH_SPANSION + { 0, 0x01, spi_flash_probe_spansion, }, +#endif +#ifdef CONFIG_SPI_FLASH_SST + { 0, 0xbf, spi_flash_probe_sst, }, +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0x20, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FLASH_WINBOND + { 0, 0xef, spi_flash_probe_winbond, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON + { 6, 0xc2, spi_fram_probe_ramtron, }, +# undef IDCODE_CONT_LEN +# define IDCODE_CONT_LEN 6 +#endif + /* Keep it sorted by best detection */ +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0xff, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { 0, 0xff, spi_fram_probe_ramtron, }, +#endif +}; +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + int ret, i, shift; + u8 idcode[IDCODE_LEN], *idp; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printf("SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + debug("SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + +#ifdef DEBUG + printf("SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* count the number of continuation bytes */ + for (shift = 0, idp = idcode; + shift < IDCODE_CONT_LEN && *idp == 0x7f; + ++shift, ++idp) + continue; + + /* search the table for matches in shift and id */ + for (i = 0; i < ARRAY_SIZE(flashes); ++i) + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { + /* we have a match, call probe */ + flash = flashes[i].probe(spi, idp); + if (flash) + break; + } + + if (!flash) { + printf("SF: Unsupported manufacturer %02x\n", *idp); + goto err_manufacturer_probe; + } + +#ifdef CONFIG_SPI_FLASH_BAR + /* Configure the BAR - disover bank cmds and read current bank */ + ret = spi_flash_bank_config(flash, *idp); + if (ret < 0) + goto err_manufacturer_probe; +#endif + +#ifdef CONFIG_OF_CONTROL + if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { + debug("SF: FDT decode error\n"); + goto err_manufacturer_probe; + } +#endif +#ifndef CONFIG_SPL_BUILD + printf("SF: Detected %s with page size ", flash->name); + print_size(flash->sector_size, ", total "); + print_size(flash->size, ""); + if (flash->memory_map) + printf(", mapped at %p", flash->memory_map); + puts("\n"); +#endif +#ifndef CONFIG_SPI_FLASH_BAR + if (flash->size > SPI_FLASH_16MB_BOUN) { + puts("SF: Warning - Only lower 16MiB accessible,"); + puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); + } +#endif + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, + const char *name) +{ + struct spi_flash *flash; + void *ptr; + + ptr = malloc(size); + if (!ptr) { + debug("SF: Failed to allocate memory\n"); + return NULL; + } + memset(ptr, '\0', size); + flash = (struct spi_flash *)(ptr + offset); + + /* Set up some basic fields - caller will sort out sizes */ + flash->spi = spi; + flash->name = name; + flash->poll_cmd = CMD_READ_STATUS; + + flash->read = spi_flash_cmd_read_fast; + flash->write = spi_flash_cmd_write_multi; + flash->erase = spi_flash_cmd_erase; + + return flash; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} -- cgit v1.2.3 From 4d4ec9927f92014195bc5ba79ad43e1103256639 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Tue, 24 Sep 2013 16:01:23 +0530 Subject: sf: probe: Add new spi_flash_probe support Added new spi_flash_probe support, currently added N25Q* flash part attributes support. Updated the sector_size attributes as per the flash parts. Looks fine for with this sector_size for computing the size of flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/Makefile | 2 +- drivers/mtd/spi/spi_flash_probe.c | 229 ++++++++++++------------- drivers/mtd/spi/spi_flash_probe_legacy.c | 276 +++++++++++++++++++++++++++++++ 3 files changed, 385 insertions(+), 122 deletions(-) create mode 100644 drivers/mtd/spi/spi_flash_probe_legacy.c diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 193cb5d0e9..a10c8506af 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -14,7 +14,7 @@ COBJS-$(CONFIG_SPL_SPI_LOAD) += spi_spl_load.o COBJS-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o endif -COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe.o spi_flash_ops.o spi_flash.o +COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe_legacy.o spi_flash_ops.o spi_flash.o COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o COBJS-$(CONFIG_SPI_FLASH_EON) += eon.o COBJS-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.o diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 32ec578d0d..3e13837fe5 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -18,6 +18,98 @@ DECLARE_GLOBAL_DATA_PTR; +/* + * struct spi_flash_params - SPI/QSPI flash device params structure + * + * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) + * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id]) + * @ext_jedec: Device ext_jedec ID + * @sector_size: Sector size of this device + * @nr_sectors: No.of sectors on this device + */ +struct spi_flash_params { + const char *name; + u32 jedec; + u16 ext_jedec; + u32 sector_size; + u32 nr_sectors; +}; + +static const struct spi_flash_params spi_flash_params_table[] = { +#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ + {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64}, + {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64}, + {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128}, + {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128}, + {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256}, + {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256}, + {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512}, + {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512}, + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024}, + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024}, + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048}, + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048}, +#endif + /* + * TODO: + * ATMEL + * EON + * GIGADEVICE + * MACRONIX + * RAMTRON + * SPANSION + * SST + * STMICRO (M25*) + * WINBOND + */ +}; + +struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) +{ + const struct spi_flash_params *params; + struct spi_flash *flash; + int i; + u16 jedec = idcode[1] << 8 | idcode[2]; + + /* Get the flash id (jedec = manuf_id + dev_id) */ + for (i = 0; i < ARRAY_SIZE(spi_flash_params_table); i++) { + params = &spi_flash_params_table[i]; + if ((params->jedec >> 16) == idcode[0]) { + if ((params->jedec & 0xFFFF) == jedec) + break; + } + } + + if (i == ARRAY_SIZE(spi_flash_params_table)) { + printf("SF: Unsupported flash ID: manuf %02x, jedec %04x\n", + idcode[0], jedec); + return NULL; + } + + flash = malloc(sizeof(*flash)); + if (!flash) { + debug("SF: Failed to allocate spi_flash\n"); + return NULL; + } + memset(flash, '\0', sizeof(*flash)); + + flash->spi = spi; + flash->name = params->name; + flash->poll_cmd = CMD_READ_STATUS; + + /* Assign spi_flash ops */ + flash->write = spi_flash_cmd_write_multi; + flash->erase = spi_flash_cmd_erase; + flash->read = spi_flash_cmd_read_fast; + + /* Compute the flash size */ + flash->page_size = 256; + flash->sector_size = params->sector_size; + flash->size = flash->sector_size * params->nr_sectors; + + return flash; +} + #ifdef CONFIG_SPI_FLASH_BAR int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) { @@ -84,89 +176,22 @@ int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) } #endif /* CONFIG_OF_CONTROL */ -/* - * The following table holds all device probe functions - * - * shift: number of continuation bytes before the ID - * idcode: the expected IDCODE or 0xff for non JEDEC devices - * probe: the function to call - * - * Non JEDEC devices should be ordered in the table such that - * the probe functions with best detection algorithms come first. - * - * Several matching entries are permitted, they will be tried - * in sequence until a probe function returns non NULL. - * - * IDCODE_CONT_LEN may be redefined if a device needs to declare a - * larger "shift" value. IDCODE_PART_LEN generally shouldn't be - * changed. This is the max number of bytes probe functions may - * examine when looking up part-specific identification info. - * - * Probe functions will be given the idcode buffer starting at their - * manu id byte (the "idcode" in the table below). In other words, - * all of the continuation bytes will be skipped (the "shift" below). - */ -#define IDCODE_CONT_LEN 0 -#define IDCODE_PART_LEN 5 -static const struct { - const u8 shift; - const u8 idcode; - struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); -} flashes[] = { - /* Keep it sorted by define name */ -#ifdef CONFIG_SPI_FLASH_ATMEL - { 0, 0x1f, spi_flash_probe_atmel, }, -#endif -#ifdef CONFIG_SPI_FLASH_EON - { 0, 0x1c, spi_flash_probe_eon, }, -#endif -#ifdef CONFIG_SPI_FLASH_GIGADEVICE - { 0, 0xc8, spi_flash_probe_gigadevice, }, -#endif -#ifdef CONFIG_SPI_FLASH_MACRONIX - { 0, 0xc2, spi_flash_probe_macronix, }, -#endif -#ifdef CONFIG_SPI_FLASH_SPANSION - { 0, 0x01, spi_flash_probe_spansion, }, -#endif -#ifdef CONFIG_SPI_FLASH_SST - { 0, 0xbf, spi_flash_probe_sst, }, -#endif -#ifdef CONFIG_SPI_FLASH_STMICRO - { 0, 0x20, spi_flash_probe_stmicro, }, -#endif -#ifdef CONFIG_SPI_FLASH_WINBOND - { 0, 0xef, spi_flash_probe_winbond, }, -#endif -#ifdef CONFIG_SPI_FRAM_RAMTRON - { 6, 0xc2, spi_fram_probe_ramtron, }, -# undef IDCODE_CONT_LEN -# define IDCODE_CONT_LEN 6 -#endif - /* Keep it sorted by best detection */ -#ifdef CONFIG_SPI_FLASH_STMICRO - { 0, 0xff, spi_flash_probe_stmicro, }, -#endif -#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC - { 0, 0xff, spi_fram_probe_ramtron, }, -#endif -}; -#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) - struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int spi_mode) { struct spi_slave *spi; struct spi_flash *flash = NULL; - int ret, i, shift; - u8 idcode[IDCODE_LEN], *idp; + u8 idcode[5], *idp; + int ret; + /* Setup spi_slave */ spi = spi_setup_slave(bus, cs, max_hz, spi_mode); if (!spi) { printf("SF: Failed to set up slave\n"); return NULL; } + /* Claim spi bus */ ret = spi_claim_bus(spi); if (ret) { debug("SF: Failed to claim SPI bus: %d\n", ret); @@ -175,45 +200,33 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, /* Read the ID codes */ ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); - if (ret) + if (ret) { + printf("SF: Failed to get idcodes\n"); goto err_read_id; + } #ifdef DEBUG printf("SF: Got idcodes\n"); print_buffer(0, idcode, 1, sizeof(idcode), 0); #endif - /* count the number of continuation bytes */ - for (shift = 0, idp = idcode; - shift < IDCODE_CONT_LEN && *idp == 0x7f; - ++shift, ++idp) - continue; - - /* search the table for matches in shift and id */ - for (i = 0; i < ARRAY_SIZE(flashes); ++i) - if (flashes[i].shift == shift && flashes[i].idcode == *idp) { - /* we have a match, call probe */ - flash = flashes[i].probe(spi, idp); - if (flash) - break; - } - - if (!flash) { - printf("SF: Unsupported manufacturer %02x\n", *idp); - goto err_manufacturer_probe; - } + /* Validate ID's from flash dev table */ + idp = idcode; + flash = spi_flash_validate_ids(spi, idp); + if (!flash) + goto err_read_id; #ifdef CONFIG_SPI_FLASH_BAR - /* Configure the BAR - disover bank cmds and read current bank */ + /* Configure the BAR - discover bank cmds and read current bank */ ret = spi_flash_bank_config(flash, *idp); if (ret < 0) - goto err_manufacturer_probe; + goto err_read_id; #endif #ifdef CONFIG_OF_CONTROL if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { debug("SF: FDT decode error\n"); - goto err_manufacturer_probe; + goto err_read_id; } #endif #ifndef CONFIG_SPL_BUILD @@ -231,11 +244,11 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, } #endif + /* Release spi bus */ spi_release_bus(spi); return flash; -err_manufacturer_probe: err_read_id: spi_release_bus(spi); err_claim_bus: @@ -243,32 +256,6 @@ err_claim_bus: return NULL; } -void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, - const char *name) -{ - struct spi_flash *flash; - void *ptr; - - ptr = malloc(size); - if (!ptr) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - memset(ptr, '\0', size); - flash = (struct spi_flash *)(ptr + offset); - - /* Set up some basic fields - caller will sort out sizes */ - flash->spi = spi; - flash->name = name; - flash->poll_cmd = CMD_READ_STATUS; - - flash->read = spi_flash_cmd_read_fast; - flash->write = spi_flash_cmd_write_multi; - flash->erase = spi_flash_cmd_erase; - - return flash; -} - void spi_flash_free(struct spi_flash *flash) { spi_free_slave(flash->spi); diff --git a/drivers/mtd/spi/spi_flash_probe_legacy.c b/drivers/mtd/spi/spi_flash_probe_legacy.c new file mode 100644 index 0000000000..32ec578d0d --- /dev/null +++ b/drivers/mtd/spi/spi_flash_probe_legacy.c @@ -0,0 +1,276 @@ +/* + * SPI flash probing + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include + +#include "spi_flash_internal.h" + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_SPI_FLASH_BAR +int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) +{ + u8 cmd; + u8 curr_bank = 0; + + /* discover bank cmds */ + switch (idcode0) { + case SPI_FLASH_SPANSION_IDCODE0: + flash->bank_read_cmd = CMD_BANKADDR_BRRD; + flash->bank_write_cmd = CMD_BANKADDR_BRWR; + break; + case SPI_FLASH_STMICRO_IDCODE0: + case SPI_FLASH_WINBOND_IDCODE0: + flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; + flash->bank_write_cmd = CMD_EXTNADDR_WREAR; + break; + default: + printf("SF: Unsupported bank commands %02x\n", idcode0); + return -1; + } + + /* read the bank reg - on which bank the flash is in currently */ + cmd = flash->bank_read_cmd; + if (flash->size > SPI_FLASH_16MB_BOUN) { + if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { + debug("SF: fail to read bank addr register\n"); + return -1; + } + flash->bank_curr = curr_bank; + } else { + flash->bank_curr = curr_bank; + } + + return 0; +} +#endif + +#ifdef CONFIG_OF_CONTROL +int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) +{ + fdt_addr_t addr; + fdt_size_t size; + int node; + + /* If there is no node, do nothing */ + node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); + if (node < 0) + return 0; + + addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); + if (addr == FDT_ADDR_T_NONE) { + debug("%s: Cannot decode address\n", __func__); + return 0; + } + + if (flash->size != size) { + debug("%s: Memory map must cover entire device\n", __func__); + return -1; + } + flash->memory_map = (void *)addr; + + return 0; +} +#endif /* CONFIG_OF_CONTROL */ + +/* + * The following table holds all device probe functions + * + * shift: number of continuation bytes before the ID + * idcode: the expected IDCODE or 0xff for non JEDEC devices + * probe: the function to call + * + * Non JEDEC devices should be ordered in the table such that + * the probe functions with best detection algorithms come first. + * + * Several matching entries are permitted, they will be tried + * in sequence until a probe function returns non NULL. + * + * IDCODE_CONT_LEN may be redefined if a device needs to declare a + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be + * changed. This is the max number of bytes probe functions may + * examine when looking up part-specific identification info. + * + * Probe functions will be given the idcode buffer starting at their + * manu id byte (the "idcode" in the table below). In other words, + * all of the continuation bytes will be skipped (the "shift" below). + */ +#define IDCODE_CONT_LEN 0 +#define IDCODE_PART_LEN 5 +static const struct { + const u8 shift; + const u8 idcode; + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); +} flashes[] = { + /* Keep it sorted by define name */ +#ifdef CONFIG_SPI_FLASH_ATMEL + { 0, 0x1f, spi_flash_probe_atmel, }, +#endif +#ifdef CONFIG_SPI_FLASH_EON + { 0, 0x1c, spi_flash_probe_eon, }, +#endif +#ifdef CONFIG_SPI_FLASH_GIGADEVICE + { 0, 0xc8, spi_flash_probe_gigadevice, }, +#endif +#ifdef CONFIG_SPI_FLASH_MACRONIX + { 0, 0xc2, spi_flash_probe_macronix, }, +#endif +#ifdef CONFIG_SPI_FLASH_SPANSION + { 0, 0x01, spi_flash_probe_spansion, }, +#endif +#ifdef CONFIG_SPI_FLASH_SST + { 0, 0xbf, spi_flash_probe_sst, }, +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0x20, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FLASH_WINBOND + { 0, 0xef, spi_flash_probe_winbond, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON + { 6, 0xc2, spi_fram_probe_ramtron, }, +# undef IDCODE_CONT_LEN +# define IDCODE_CONT_LEN 6 +#endif + /* Keep it sorted by best detection */ +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0xff, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { 0, 0xff, spi_fram_probe_ramtron, }, +#endif +}; +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + int ret, i, shift; + u8 idcode[IDCODE_LEN], *idp; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printf("SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + debug("SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + +#ifdef DEBUG + printf("SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* count the number of continuation bytes */ + for (shift = 0, idp = idcode; + shift < IDCODE_CONT_LEN && *idp == 0x7f; + ++shift, ++idp) + continue; + + /* search the table for matches in shift and id */ + for (i = 0; i < ARRAY_SIZE(flashes); ++i) + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { + /* we have a match, call probe */ + flash = flashes[i].probe(spi, idp); + if (flash) + break; + } + + if (!flash) { + printf("SF: Unsupported manufacturer %02x\n", *idp); + goto err_manufacturer_probe; + } + +#ifdef CONFIG_SPI_FLASH_BAR + /* Configure the BAR - disover bank cmds and read current bank */ + ret = spi_flash_bank_config(flash, *idp); + if (ret < 0) + goto err_manufacturer_probe; +#endif + +#ifdef CONFIG_OF_CONTROL + if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { + debug("SF: FDT decode error\n"); + goto err_manufacturer_probe; + } +#endif +#ifndef CONFIG_SPL_BUILD + printf("SF: Detected %s with page size ", flash->name); + print_size(flash->sector_size, ", total "); + print_size(flash->size, ""); + if (flash->memory_map) + printf(", mapped at %p", flash->memory_map); + puts("\n"); +#endif +#ifndef CONFIG_SPI_FLASH_BAR + if (flash->size > SPI_FLASH_16MB_BOUN) { + puts("SF: Warning - Only lower 16MiB accessible,"); + puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); + } +#endif + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, + const char *name) +{ + struct spi_flash *flash; + void *ptr; + + ptr = malloc(size); + if (!ptr) { + debug("SF: Failed to allocate memory\n"); + return NULL; + } + memset(ptr, '\0', size); + flash = (struct spi_flash *)(ptr + offset); + + /* Set up some basic fields - caller will sort out sizes */ + flash->spi = spi; + flash->name = name; + flash->poll_cmd = CMD_READ_STATUS; + + flash->read = spi_flash_cmd_read_fast; + flash->write = spi_flash_cmd_write_multi; + flash->erase = spi_flash_cmd_erase; + + return flash; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} -- cgit v1.2.3 From 53752c90e02031e89ff8f52f85c0da3c982ea70b Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Mon, 5 Aug 2013 16:17:37 +0530 Subject: sf: probe: Add support for M25P* flash parts Added M25P* parts are which are avilable in spi_flash_probe_legacy.c. Updated the sector_size attributes as per the flash parts. Looks fine for with this sector_size for computing the size of flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 3e13837fe5..7d8ed6e47a 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -37,6 +37,14 @@ struct spi_flash_params { static const struct spi_flash_params spi_flash_params_table[] = { #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ + {"M25P10", 0x202011, 0x0, 32 * 1024, 4}, + {"M25P20", 0x202012, 0x0, 64 * 1024, 4}, + {"M25P40", 0x202013, 0x0, 64 * 1024, 8}, + {"M25P80", 0x202014, 0x0, 64 * 1024, 16}, + {"M25P16", 0x202015, 0x0, 64 * 1024, 32}, + {"M25P32", 0x202016, 0x0, 64 * 1024, 64}, + {"M25P64", 0x202017, 0x0, 64 * 1024, 128}, + {"M25P128", 0x202018, 0x0, 256 * 1024, 64}, {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64}, {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64}, {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128}, @@ -59,7 +67,6 @@ static const struct spi_flash_params spi_flash_params_table[] = { * RAMTRON * SPANSION * SST - * STMICRO (M25*) * WINBOND */ }; -- cgit v1.2.3 From 0d7663fe7d1713dea6e4259f279f543bfa2fb441 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Tue, 6 Aug 2013 20:00:00 +0530 Subject: sf: probe: Add support for EN25Q* flash parts Added EN25Q* parts are which are avilable in spi_flash_probe_legacy.c. Updated the sector_size attributes as per the flash parts. Looks fine for with this sector_size for computing the size of flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 7d8ed6e47a..e64b0102f7 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -36,6 +36,10 @@ struct spi_flash_params { }; static const struct spi_flash_params spi_flash_params_table[] = { +#ifdef CONFIG_SPI_FLASH_EON /* EON */ + {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64}, + {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256}, +#endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ {"M25P10", 0x202011, 0x0, 32 * 1024, 4}, {"M25P20", 0x202012, 0x0, 64 * 1024, 4}, @@ -61,7 +65,6 @@ static const struct spi_flash_params spi_flash_params_table[] = { /* * TODO: * ATMEL - * EON * GIGADEVICE * MACRONIX * RAMTRON -- cgit v1.2.3 From 18500e26ce2c0fd0449ce66a66e35c237a8b717b Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Mon, 5 Aug 2013 16:20:27 +0530 Subject: sf: probe: Add support for GD25* flash parts Added GD25* parts are which are avilable in spi_flash_probe_legacy.c. Updated the sector_size attributes as per the flash parts. Looks fine for with this sector_size for computing the size of flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index e64b0102f7..a66bcf90f0 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -40,6 +40,10 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64}, {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256}, #endif +#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ + {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128}, + {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64}, +#endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ {"M25P10", 0x202011, 0x0, 32 * 1024, 4}, {"M25P20", 0x202012, 0x0, 64 * 1024, 4}, @@ -65,7 +69,6 @@ static const struct spi_flash_params spi_flash_params_table[] = { /* * TODO: * ATMEL - * GIGADEVICE * MACRONIX * RAMTRON * SPANSION -- cgit v1.2.3 From db7e258412d80cd66181912b2ca8b9b974037b4b Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Mon, 5 Aug 2013 17:26:16 +0530 Subject: sf: probe: Add support for MX25L* flash parts Added MX25L* parts are which are avilable in spi_flash_probe_legacy.c. Updated the sector_size attributes as per the flash parts. Looks fine for with this sector_size for computing the size of flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index a66bcf90f0..7b36f60a9a 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -44,6 +44,15 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128}, {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64}, #endif +#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ + {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8}, + {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16}, + {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32}, + {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64}, + {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128}, + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256}, + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256}, +#endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ {"M25P10", 0x202011, 0x0, 32 * 1024, 4}, {"M25P20", 0x202012, 0x0, 64 * 1024, 4}, @@ -69,7 +78,6 @@ static const struct spi_flash_params spi_flash_params_table[] = { /* * TODO: * ATMEL - * MACRONIX * RAMTRON * SPANSION * SST -- cgit v1.2.3 From 80701e54d3c5f02dd508250401d64f9328b94219 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 28 Sep 2013 16:57:56 +0530 Subject: sf: probe: Add support for W25* flash parts Added W25* parts are which are avilable in spi_flash_probe_legacy.c. Updated the sector_size attributes as per the flash parts. Looks fine for with this sector_size for computing the size of flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 7b36f60a9a..62fbd4f306 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -75,13 +75,44 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048}, {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048}, #endif +#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ + {"W25P80", 0xef2014, 0x0, 64 * 1024, 16}, + {"W25P16", 0xef2015, 0x0, 64 * 1024, 32}, + {"W25P32", 0xef2016, 0x0, 64 * 1024, 64}, + {"W25X40", 0xef3013, 0x0, 64 * 1024, 8}, + {"W25X16", 0xef3015, 0x0, 64 * 1024, 32}, + {"W25X32", 0xef3016, 0x0, 64 * 1024, 64}, + {"W25X64", 0xef3017, 0x0, 64 * 1024, 128}, + {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16}, + {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32}, + {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64}, + {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128}, + {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256}, + {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512}, + {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16}, + {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32}, + {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64}, + {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128}, + {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256}, +#endif + /* + * Note: + * Below paired flash devices has similar spi_flash_params params. + * (W25Q80BL, W25Q80BV) + * (W25Q16CL, W25Q16DV) + * (W25Q32BV, W25Q32FV_SPI) + * (W25Q64CV, W25Q64FV_SPI) + * (W25Q128BV, W25Q128FV_SPI) + * (W25Q32DW, W25Q32FV_QPI) + * (W25Q64DW, W25Q64FV_QPI) + * (W25Q128FW, W25Q128FV_QPI) + */ /* * TODO: * ATMEL * RAMTRON * SPANSION * SST - * WINBOND */ }; -- cgit v1.2.3 From 74bec16eb5c5bb46305ee5ccc67250f286e6288c Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 28 Sep 2013 16:49:37 +0530 Subject: sf: probe: Add support for S25FL* flash parts Added S25FL* parts are which are avilable in spi_flash_probe_legacy.c. Updated the sector_size attributes as per the flash parts. Looks fine for with this sector_size for computing the size of flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 62fbd4f306..a9ac5711d8 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -53,6 +53,19 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256}, {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256}, #endif +#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ + {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16}, + {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32}, + {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64}, + {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128}, + {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64}, + {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256}, + {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64}, + {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128}, + {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256}, + {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512}, + {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024}, +#endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ {"M25P10", 0x202011, 0x0, 32 * 1024, 4}, {"M25P20", 0x202012, 0x0, 64 * 1024, 4}, @@ -98,6 +111,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { /* * Note: * Below paired flash devices has similar spi_flash_params params. + * (S25FL129P_64K, S25FL128S_64K) * (W25Q80BL, W25Q80BV) * (W25Q16CL, W25Q16DV) * (W25Q32BV, W25Q32FV_SPI) @@ -111,7 +125,6 @@ static const struct spi_flash_params spi_flash_params_table[] = { * TODO: * ATMEL * RAMTRON - * SPANSION * SST */ }; @@ -122,19 +135,25 @@ struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) struct spi_flash *flash; int i; u16 jedec = idcode[1] << 8 | idcode[2]; + u16 ext_jedec = idcode[3] << 8 | idcode[4]; - /* Get the flash id (jedec = manuf_id + dev_id) */ + /* Get the flash id (jedec = manuf_id + dev_id, ext_jedec) */ for (i = 0; i < ARRAY_SIZE(spi_flash_params_table); i++) { params = &spi_flash_params_table[i]; if ((params->jedec >> 16) == idcode[0]) { - if ((params->jedec & 0xFFFF) == jedec) - break; + if ((params->jedec & 0xFFFF) == jedec) { + if (params->ext_jedec == 0) + break; + else if (params->ext_jedec == ext_jedec) + break; + } } } if (i == ARRAY_SIZE(spi_flash_params_table)) { - printf("SF: Unsupported flash ID: manuf %02x, jedec %04x\n", - idcode[0], jedec); + printf("SF: Unsupported flash IDs: "); + printf("manuf %02x, jedec %04x, ext_jedec %04x\n", + idcode[0], jedec, ext_jedec); return NULL; } -- cgit v1.2.3 From 26dcc5415b78b8378c7819036600c3749178b087 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Mon, 5 Aug 2013 17:36:02 +0530 Subject: sf: probe: Add support for SST25* flash parts Added SST25* parts are which are avilable in spi_flash_probe_legacy.c. Updated the sector_size attributes as per the flash parts. Looks fine for with this sector_size for computing the size of flash. Signed-off-by: Jagannadha Sutradharudu Teki Tested-by: Eric Nelson --- drivers/mtd/spi/spi_flash_probe.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index a9ac5711d8..d0955bf6c9 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -88,6 +88,18 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048}, {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048}, #endif +#ifdef CONFIG_SPI_FLASH_SST /* SST */ + {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8}, + {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16}, + {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32}, + {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64}, + {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128}, + {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1}, + {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2}, + {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4}, + {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8}, + {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16}, +#endif #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ {"W25P80", 0xef2014, 0x0, 64 * 1024, 16}, {"W25P16", 0xef2015, 0x0, 64 * 1024, 32}, @@ -125,7 +137,6 @@ static const struct spi_flash_params spi_flash_params_table[] = { * TODO: * ATMEL * RAMTRON - * SST */ }; -- cgit v1.2.3 From a74db0a4f33f8c0f0c89263d82e94494aa755b16 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Tue, 6 Aug 2013 20:01:08 +0530 Subject: sf: probe: Add support for AT45DB* flash parts Added AT45DB* parts are which are avilable in spi_flash_probe_legacy.c. Updated the sector_size attributes as per the flash parts. Looks fine for with this sector_size for computing the size of flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index d0955bf6c9..af43272c46 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -36,6 +36,15 @@ struct spi_flash_params { }; static const struct spi_flash_params spi_flash_params_table[] = { +#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ + {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4}, + {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8}, + {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8}, + {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16}, + {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32}, + {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64}, + {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128}, +#endif #ifdef CONFIG_SPI_FLASH_EON /* EON */ {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64}, {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256}, @@ -135,7 +144,6 @@ static const struct spi_flash_params spi_flash_params_table[] = { */ /* * TODO: - * ATMEL * RAMTRON */ }; -- cgit v1.2.3 From b7797422e3c749a323a703e90004656b288a5dca Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 28 Sep 2013 17:06:03 +0530 Subject: sf: probe: Give proper spacing on flash table params Given proper spacing between flash table params. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 154 +++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index af43272c46..b6cf60ca3e 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -37,97 +37,97 @@ struct spi_flash_params { static const struct spi_flash_params spi_flash_params_table[] = { #ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ - {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4}, - {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8}, - {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8}, - {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16}, - {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32}, - {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64}, - {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128}, + {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4}, + {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8}, + {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8}, + {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16}, + {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32}, + {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64}, + {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128}, #endif #ifdef CONFIG_SPI_FLASH_EON /* EON */ - {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64}, - {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256}, + {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64}, + {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256}, #endif #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ - {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128}, - {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64}, + {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128}, + {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64}, #endif #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ - {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8}, - {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16}, - {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32}, - {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64}, - {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128}, - {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256}, - {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256}, + {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8}, + {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16}, + {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32}, + {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64}, + {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128}, + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256}, + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256}, #endif #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ - {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16}, - {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32}, - {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64}, - {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128}, - {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64}, - {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256}, - {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64}, - {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128}, - {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256}, - {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512}, - {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024}, + {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16}, + {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32}, + {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64}, + {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128}, + {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64}, + {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256}, + {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64}, + {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128}, + {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256}, + {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512}, + {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024}, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - {"M25P10", 0x202011, 0x0, 32 * 1024, 4}, - {"M25P20", 0x202012, 0x0, 64 * 1024, 4}, - {"M25P40", 0x202013, 0x0, 64 * 1024, 8}, - {"M25P80", 0x202014, 0x0, 64 * 1024, 16}, - {"M25P16", 0x202015, 0x0, 64 * 1024, 32}, - {"M25P32", 0x202016, 0x0, 64 * 1024, 64}, - {"M25P64", 0x202017, 0x0, 64 * 1024, 128}, - {"M25P128", 0x202018, 0x0, 256 * 1024, 64}, - {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64}, - {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64}, - {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128}, - {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128}, - {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256}, - {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256}, - {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512}, - {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512}, - {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024}, - {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024}, - {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048}, - {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048}, + {"M25P10", 0x202011, 0x0, 32 * 1024, 4}, + {"M25P20", 0x202012, 0x0, 64 * 1024, 4}, + {"M25P40", 0x202013, 0x0, 64 * 1024, 8}, + {"M25P80", 0x202014, 0x0, 64 * 1024, 16}, + {"M25P16", 0x202015, 0x0, 64 * 1024, 32}, + {"M25P32", 0x202016, 0x0, 64 * 1024, 64}, + {"M25P64", 0x202017, 0x0, 64 * 1024, 128}, + {"M25P128", 0x202018, 0x0, 256 * 1024, 64}, + {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64}, + {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64}, + {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128}, + {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128}, + {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256}, + {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256}, + {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512}, + {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512}, + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024}, + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024}, + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048}, + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048}, #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ - {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8}, - {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16}, - {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32}, - {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64}, - {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128}, - {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1}, - {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2}, - {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4}, - {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8}, - {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16}, + {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8}, + {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16}, + {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32}, + {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64}, + {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128}, + {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1}, + {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2}, + {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4}, + {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8}, + {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16}, #endif #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ - {"W25P80", 0xef2014, 0x0, 64 * 1024, 16}, - {"W25P16", 0xef2015, 0x0, 64 * 1024, 32}, - {"W25P32", 0xef2016, 0x0, 64 * 1024, 64}, - {"W25X40", 0xef3013, 0x0, 64 * 1024, 8}, - {"W25X16", 0xef3015, 0x0, 64 * 1024, 32}, - {"W25X32", 0xef3016, 0x0, 64 * 1024, 64}, - {"W25X64", 0xef3017, 0x0, 64 * 1024, 128}, - {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16}, - {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32}, - {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64}, - {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128}, - {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256}, - {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512}, - {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16}, - {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32}, - {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64}, - {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128}, - {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256}, + {"W25P80", 0xef2014, 0x0, 64 * 1024, 16}, + {"W25P16", 0xef2015, 0x0, 64 * 1024, 32}, + {"W25P32", 0xef2016, 0x0, 64 * 1024, 64}, + {"W25X40", 0xef3013, 0x0, 64 * 1024, 8}, + {"W25X16", 0xef3015, 0x0, 64 * 1024, 32}, + {"W25X32", 0xef3016, 0x0, 64 * 1024, 64}, + {"W25X64", 0xef3017, 0x0, 64 * 1024, 128}, + {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16}, + {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32}, + {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64}, + {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128}, + {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256}, + {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512}, + {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16}, + {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32}, + {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64}, + {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128}, + {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256}, #endif /* * Note: -- cgit v1.2.3 From 10ca45d005a96e810b5a225b08135fc24da62ee9 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 2 Oct 2013 19:34:53 +0530 Subject: sf: probe: Add support for SST_WP Most of the SST flashes needs to write up using SST_WP, AAI Word Program, so added a flag param on spi_flash_params table. SST flashes, which supports SST_WP need to use a WP write sst_write_wp instead of common flash write. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_internal.h | 5 ++ drivers/mtd/spi/spi_flash_ops.c | 93 ++++++++++++++++++++ drivers/mtd/spi/spi_flash_probe.c | 160 ++++++++++++++++++----------------- include/spi_flash.h | 7 ++ 4 files changed, 188 insertions(+), 77 deletions(-) diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index af1afa96c9..ce34ce0c34 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -75,6 +75,11 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, size_t len, const void *buf); +#ifdef CONFIG_SPI_FLASH_SST +int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, + const void *buf); +#endif + /* * Enable writing on the SPI flash. */ diff --git a/drivers/mtd/spi/spi_flash_ops.c b/drivers/mtd/spi/spi_flash_ops.c index 6133363f42..79381b1893 100644 --- a/drivers/mtd/spi/spi_flash_ops.c +++ b/drivers/mtd/spi/spi_flash_ops.c @@ -312,3 +312,96 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, return ret; } + +#ifdef CONFIG_SPI_FLASH_SST +static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) +{ + int ret; + u8 cmd[4] = { + CMD_SST_BP, + offset >> 16, + offset >> 8, + offset, + }; + + debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset); + + ret = spi_flash_cmd_write_enable(flash); + if (ret) + return ret; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); + if (ret) + return ret; + + return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); +} + +int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, + const void *buf) +{ + size_t actual, cmd_len; + int ret; + u8 cmd[4]; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + /* If the data is not word aligned, write out leading single byte */ + actual = offset % 2; + if (actual) { + ret = sst_byte_write(flash, offset, buf); + if (ret) + goto done; + } + offset += actual; + + ret = spi_flash_cmd_write_enable(flash); + if (ret) + goto done; + + cmd_len = 4; + cmd[0] = CMD_SST_AAI_WP; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + + for (; actual < len - 1; actual += 2) { + debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual, + cmd[0], offset); + + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, + buf + actual, 2); + if (ret) { + debug("SF: sst word program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + cmd_len = 1; + offset += 2; + } + + if (!ret) + ret = spi_flash_cmd_write_disable(flash); + + /* If there is a single trailing byte, write it out */ + if (!ret && actual != len) + ret = sst_byte_write(flash, offset, buf + actual); + + done: + debug("SF: sst: program %s %zu bytes @ 0x%zx\n", + ret ? "failure" : "success", len, offset - actual); + + spi_release_bus(flash->spi); + return ret; +} +#endif diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index b6cf60ca3e..199eab89b0 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -26,6 +26,7 @@ DECLARE_GLOBAL_DATA_PTR; * @ext_jedec: Device ext_jedec ID * @sector_size: Sector size of this device * @nr_sectors: No.of sectors on this device + * @flags: Importent param, for flash specific behaviour */ struct spi_flash_params { const char *name; @@ -33,101 +34,102 @@ struct spi_flash_params { u16 ext_jedec; u32 sector_size; u32 nr_sectors; + u16 flags; }; static const struct spi_flash_params spi_flash_params_table[] = { #ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ - {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4}, - {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8}, - {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8}, - {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16}, - {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32}, - {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64}, - {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128}, + {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, 0}, + {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0}, + {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0}, + {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0}, + {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0}, + {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0}, + {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0}, #endif #ifdef CONFIG_SPI_FLASH_EON /* EON */ - {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64}, - {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256}, + {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, + {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ - {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128}, - {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64}, + {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0}, + {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0}, #endif #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ - {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8}, - {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16}, - {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32}, - {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64}, - {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128}, - {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256}, - {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256}, + {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, + {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, + {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, + {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, + {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ - {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16}, - {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32}, - {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64}, - {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128}, - {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64}, - {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256}, - {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64}, - {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128}, - {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256}, - {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512}, - {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024}, + {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0}, + {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0}, + {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0}, + {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0}, + {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0}, + {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0}, + {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0}, + {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0}, + {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0}, + {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0}, + {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0}, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - {"M25P10", 0x202011, 0x0, 32 * 1024, 4}, - {"M25P20", 0x202012, 0x0, 64 * 1024, 4}, - {"M25P40", 0x202013, 0x0, 64 * 1024, 8}, - {"M25P80", 0x202014, 0x0, 64 * 1024, 16}, - {"M25P16", 0x202015, 0x0, 64 * 1024, 32}, - {"M25P32", 0x202016, 0x0, 64 * 1024, 64}, - {"M25P64", 0x202017, 0x0, 64 * 1024, 128}, - {"M25P128", 0x202018, 0x0, 256 * 1024, 64}, - {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64}, - {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64}, - {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128}, - {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128}, - {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256}, - {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256}, - {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512}, - {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512}, - {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024}, - {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024}, - {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048}, - {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048}, + {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0}, + {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0}, + {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0}, + {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0}, + {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0}, + {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0}, + {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0}, + {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0}, + {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, 0}, + {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, 0}, + {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, 0}, + {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, 0}, + {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, 0}, + {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, 0}, + {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, 0}, + {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, 0}, + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, 0}, + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, 0}, + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, 0}, + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, 0}, #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ - {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8}, - {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16}, - {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32}, - {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64}, - {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128}, - {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1}, - {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2}, - {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4}, - {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8}, - {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16}, + {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SST_WP}, + {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SST_WP}, + {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SST_WP}, + {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SST_WP}, + {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0}, + {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SST_WP}, + {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SST_WP}, + {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SST_WP}, + {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SST_WP}, + {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SST_WP}, #endif #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ - {"W25P80", 0xef2014, 0x0, 64 * 1024, 16}, - {"W25P16", 0xef2015, 0x0, 64 * 1024, 32}, - {"W25P32", 0xef2016, 0x0, 64 * 1024, 64}, - {"W25X40", 0xef3013, 0x0, 64 * 1024, 8}, - {"W25X16", 0xef3015, 0x0, 64 * 1024, 32}, - {"W25X32", 0xef3016, 0x0, 64 * 1024, 64}, - {"W25X64", 0xef3017, 0x0, 64 * 1024, 128}, - {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16}, - {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32}, - {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64}, - {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128}, - {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256}, - {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512}, - {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16}, - {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32}, - {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64}, - {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128}, - {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256}, + {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0}, + {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0}, + {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0}, + {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0}, + {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0}, + {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0}, + {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0}, + {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, 0}, + {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, 0}, + {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, 0}, + {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, 0}, + {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, 0}, + {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, 0}, + {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, 0}, + {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, 0}, + {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, 0}, + {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, 0}, + {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, 0}, #endif /* * Note: @@ -189,6 +191,10 @@ struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) /* Assign spi_flash ops */ flash->write = spi_flash_cmd_write_multi; +#ifdef CONFIG_SPI_FLASH_SST + if (params->flags & SST_WP) + flash->write = sst_write_wp; +#endif flash->erase = spi_flash_cmd_erase; flash->read = spi_flash_cmd_read_fast; diff --git a/include/spi_flash.h b/include/spi_flash.h index bfc59aa701..de262ed12d 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -17,6 +17,13 @@ #include #include +/* SST specific macros */ +#ifdef CONFIG_SPI_FLASH_SST +# define SST_WP 0x01 /* Supports AAI word program */ +# define CMD_SST_BP 0x02 /* Byte Program */ +# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ +#endif + struct spi_flash { struct spi_slave *spi; -- cgit v1.2.3 From 54024c15668ec5e8c261536e9bbc9d22dd01f3e6 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Thu, 26 Sep 2013 13:16:45 +0530 Subject: sf: probe: Add support to clear flash BP# bits Few of the flashes(Atmel, Macronix and SST) require to clear BP# bits in flash power ups. So clear these BP# bits at probe time, so-that the flash is ready for user operations. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 199eab89b0..46591343d2 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -203,6 +203,13 @@ struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) flash->sector_size = params->sector_size; flash->size = flash->sector_size * params->nr_sectors; + /* Flash powers up read-only, so clear BP# bits */ +#if defined(CONFIG_SPI_FLASH_ATMEL) || \ + defined(CONFIG_SPI_FLASH_MACRONIX) || \ + defined(CONFIG_SPI_FLASH_SST) + spi_flash_cmd_write_status(flash, 0); +#endif + return flash; } -- cgit v1.2.3 From f4f51a8ff894d34eb332f0d11f6c73c7bf509848 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 2 Oct 2013 19:36:58 +0530 Subject: sf: probe: Add support for erase sector selection flag SECT_4K, SECT_32K and SECT_64K opeartions are performed to to specific flash by adding a SECT* flag on respective spi_flash_params.flag param. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_ops.c | 8 +- drivers/mtd/spi/spi_flash_probe.c | 166 ++++++++++++++++++++------------------ include/spi_flash.h | 10 ++- 3 files changed, 100 insertions(+), 84 deletions(-) diff --git a/drivers/mtd/spi/spi_flash_ops.c b/drivers/mtd/spi/spi_flash_ops.c index 79381b1893..c408e27b61 100644 --- a/drivers/mtd/spi/spi_flash_ops.c +++ b/drivers/mtd/spi/spi_flash_ops.c @@ -153,17 +153,13 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) u8 cmd[4]; int ret = -1; - erase_size = flash->sector_size; + erase_size = flash->erase_size; if (offset % erase_size || len % erase_size) { debug("SF: Erase offset/length not multiple of erase size\n"); return -1; } - if (erase_size == 4096) - cmd[0] = CMD_ERASE_4K; - else - cmd[0] = CMD_ERASE_64K; - + cmd[0] = flash->erase_cmd; while (len) { #ifdef CONFIG_SPI_FLASH_BAR u8 bank_sel; diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 46591343d2..9c2e11521f 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -39,97 +39,97 @@ struct spi_flash_params { static const struct spi_flash_params spi_flash_params_table[] = { #ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ - {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, 0}, - {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0}, - {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0}, - {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0}, - {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0}, - {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0}, - {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0}, + {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, SECT_4K}, + {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, SECT_4K}, + {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, SECT_4K}, + {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, SECT_4K}, + {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, SECT_4K}, + {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, SECT_4K}, + {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_EON /* EON */ - {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, - {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, + {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, + {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ - {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0}, - {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0}, + {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K}, + {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ - {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, - {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, - {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, - {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, - {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, - {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, - {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, + {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, + {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, + {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, + {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, + {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ - {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0}, - {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0}, - {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0}, - {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0}, - {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0}, - {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0}, - {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0}, - {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0}, - {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0}, - {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0}, - {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0}, + {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0}, + {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0}, + {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0}, + {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0}, + {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0}, + {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0}, + {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0}, + {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0}, + {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0}, + {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0}, + {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0}, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0}, - {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0}, - {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0}, - {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0}, - {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0}, - {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0}, - {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0}, - {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0}, - {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, 0}, - {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, 0}, - {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, 0}, - {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, 0}, - {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, 0}, - {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, 0}, - {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, 0}, - {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, 0}, - {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, 0}, - {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, 0}, - {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, 0}, - {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, 0}, + {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0}, + {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0}, + {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0}, + {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0}, + {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0}, + {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0}, + {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0}, + {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0}, + {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, SECT_4K}, + {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, SECT_4K}, + {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, SECT_4K}, + {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, SECT_4K}, + {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, SECT_4K}, + {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, SECT_4K}, + {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, SECT_4K}, + {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, SECT_4K}, + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, SECT_4K}, + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, SECT_4K}, + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, SECT_4K}, + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ - {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SST_WP}, - {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SST_WP}, - {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SST_WP}, - {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SST_WP}, - {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0}, - {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SST_WP}, - {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SST_WP}, - {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SST_WP}, - {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SST_WP}, - {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SST_WP}, + {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, + {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, + {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WP}, + {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WP}, + {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, SECT_4K}, + {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WP}, + {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WP}, + {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WP}, + {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, + {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, #endif #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ - {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0}, - {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0}, - {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0}, - {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0}, - {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0}, - {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0}, - {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0}, - {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, 0}, - {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, 0}, - {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, 0}, - {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, 0}, - {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, 0}, - {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, 0}, - {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, 0}, - {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, 0}, - {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, 0}, - {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, 0}, - {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, 0}, + {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0}, + {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0}, + {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0}, + {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, SECT_4K}, + {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, SECT_4K}, + {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, SECT_4K}, + {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, SECT_4K}, + {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, SECT_4K}, + {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, SECT_4K}, + {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, SECT_4K}, + {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, SECT_4K}, + {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, SECT_4K}, #endif /* * Note: @@ -203,6 +203,18 @@ struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) flash->sector_size = params->sector_size; flash->size = flash->sector_size * params->nr_sectors; + /* Compute erase sector and command */ + if (params->flags & SECT_4K) { + flash->erase_cmd = CMD_ERASE_4K; + flash->erase_size = 4096; + } else if (params->flags & SECT_32K) { + flash->erase_cmd = CMD_ERASE_32K; + flash->erase_size = 32768; + } else { + flash->erase_cmd = CMD_ERASE_64K; + flash->erase_size = flash->sector_size; + } + /* Flash powers up read-only, so clear BP# bits */ #if defined(CONFIG_SPI_FLASH_ATMEL) || \ defined(CONFIG_SPI_FLASH_MACRONIX) || \ diff --git a/include/spi_flash.h b/include/spi_flash.h index de262ed12d..0d40e6c975 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -17,6 +17,10 @@ #include #include +/* SECT flags */ +#define SECT_4K (1 << 1) +#define SECT_32K (1 << 2) + /* SST specific macros */ #ifdef CONFIG_SPI_FLASH_SST # define SST_WP 0x01 /* Supports AAI word program */ @@ -33,8 +37,10 @@ struct spi_flash { u32 size; /* Write (page) size */ u32 page_size; - /* Erase (sector) size */ + /* Sector size */ u32 sector_size; + /* Erase size */ + u32 erase_size; #ifdef CONFIG_SPI_FLASH_BAR /* Bank read cmd */ u8 bank_read_cmd; @@ -45,6 +51,8 @@ struct spi_flash { #endif /* Poll cmd - for flash erase/program */ u8 poll_cmd; + /* Erase cmd 4K, 32K, 64K */ + u8 erase_cmd; void *memory_map; /* Address of read-only SPI flash access */ int (*read)(struct spi_flash *flash, u32 offset, -- cgit v1.2.3 From 0f6232801cee4f45dbdb0cec45f71172c9b617ca Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 2 Oct 2013 19:37:43 +0530 Subject: sf: probe: Add support for flag status polling From Micron, 512MB onwards, flash requires to poll flag status instead of read status- hence added E_FSR flag on spectific flash parts. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 16 +++++++++++----- include/spi_flash.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 9c2e11521f..8ea69158e7 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -94,10 +94,10 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, SECT_4K}, {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, SECT_4K}, {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, SECT_4K}, - {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, SECT_4K}, - {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, SECT_4K}, - {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, SECT_4K}, - {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, SECT_4K}, + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, @@ -187,7 +187,6 @@ struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) flash->spi = spi; flash->name = params->name; - flash->poll_cmd = CMD_READ_STATUS; /* Assign spi_flash ops */ flash->write = spi_flash_cmd_write_multi; @@ -215,6 +214,13 @@ struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) flash->erase_size = flash->sector_size; } + /* Poll cmd seclection */ + flash->poll_cmd = CMD_READ_STATUS; +#ifdef CONFIG_SPI_FLASH_STMICRO + if (params->flags & E_FSR) + flash->poll_cmd = CMD_FLAG_STATUS; +#endif + /* Flash powers up read-only, so clear BP# bits */ #if defined(CONFIG_SPI_FLASH_ATMEL) || \ defined(CONFIG_SPI_FLASH_MACRONIX) || \ diff --git a/include/spi_flash.h b/include/spi_flash.h index 0d40e6c975..09af55dee5 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -20,6 +20,7 @@ /* SECT flags */ #define SECT_4K (1 << 1) #define SECT_32K (1 << 2) +#define E_FSR (1 << 3) /* SST specific macros */ #ifdef CONFIG_SPI_FLASH_SST -- cgit v1.2.3 From 32ebd1a7d51818a327f2e23570d6bfc542c68e12 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Thu, 26 Sep 2013 14:24:58 +0530 Subject: sf: probe: Simply the BAR configuration logic Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_internal.h | 8 ----- drivers/mtd/spi/spi_flash_probe.c | 66 +++++++++++------------------------- 2 files changed, 20 insertions(+), 54 deletions(-) diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index ce34ce0c34..61de2378fd 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -31,11 +31,6 @@ #define SPI_FLASH_16MB_BOUN 0x1000000 -/* Manufacture ID's */ -#define SPI_FLASH_SPANSION_IDCODE0 0x01 -#define SPI_FLASH_STMICRO_IDCODE0 0x20 -#define SPI_FLASH_WINBOND_IDCODE0 0xef - #ifdef CONFIG_SPI_FLASH_BAR /* Bank addr access commands */ # define CMD_BANKADDR_BRWR 0x17 @@ -102,9 +97,6 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); #ifdef CONFIG_SPI_FLASH_BAR /* Program the bank address register */ int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel); - -/* Configure the BAR - discover the bank cmds */ -int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0); #endif /* diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 8ea69158e7..cc30ad1a8c 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -221,54 +221,36 @@ struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) flash->poll_cmd = CMD_FLAG_STATUS; #endif - /* Flash powers up read-only, so clear BP# bits */ -#if defined(CONFIG_SPI_FLASH_ATMEL) || \ - defined(CONFIG_SPI_FLASH_MACRONIX) || \ - defined(CONFIG_SPI_FLASH_SST) - spi_flash_cmd_write_status(flash, 0); -#endif - - return flash; -} - #ifdef CONFIG_SPI_FLASH_BAR -int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) -{ - u8 cmd; + /* Configure the BAR - discover bank cmds and read current bank */ u8 curr_bank = 0; - - /* discover bank cmds */ - switch (idcode0) { - case SPI_FLASH_SPANSION_IDCODE0: - flash->bank_read_cmd = CMD_BANKADDR_BRRD; - flash->bank_write_cmd = CMD_BANKADDR_BRWR; - break; - case SPI_FLASH_STMICRO_IDCODE0: - case SPI_FLASH_WINBOND_IDCODE0: - flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; - flash->bank_write_cmd = CMD_EXTNADDR_WREAR; - break; - default: - printf("SF: Unsupported bank commands %02x\n", idcode0); - return -1; - } - - /* read the bank reg - on which bank the flash is in currently */ - cmd = flash->bank_read_cmd; if (flash->size > SPI_FLASH_16MB_BOUN) { - if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { + flash->bank_read_cmd = (idcode[0] == 0x01) ? + CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR; + flash->bank_write_cmd = (idcode[0] == 0x01) ? + CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR; + + if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1, + &curr_bank, 1)) { debug("SF: fail to read bank addr register\n"); - return -1; + return NULL; } flash->bank_curr = curr_bank; } else { flash->bank_curr = curr_bank; } +#endif - return 0; -} + /* Flash powers up read-only, so clear BP# bits */ +#if defined(CONFIG_SPI_FLASH_ATMEL) || \ + defined(CONFIG_SPI_FLASH_MACRONIX) || \ + defined(CONFIG_SPI_FLASH_SST) + spi_flash_cmd_write_status(flash, 0); #endif + return flash; +} + #ifdef CONFIG_OF_CONTROL int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) { @@ -302,7 +284,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, { struct spi_slave *spi; struct spi_flash *flash = NULL; - u8 idcode[5], *idp; + u8 idcode[5]; int ret; /* Setup spi_slave */ @@ -332,18 +314,10 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, #endif /* Validate ID's from flash dev table */ - idp = idcode; - flash = spi_flash_validate_ids(spi, idp); + flash = spi_flash_validate_ids(spi, idcode); if (!flash) goto err_read_id; -#ifdef CONFIG_SPI_FLASH_BAR - /* Configure the BAR - discover bank cmds and read current bank */ - ret = spi_flash_bank_config(flash, *idp); - if (ret < 0) - goto err_read_id; -#endif - #ifdef CONFIG_OF_CONTROL if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { debug("SF: FDT decode error\n"); -- cgit v1.2.3 From 7ab35d922d80e151f9fe6a785a736b0d8612c589 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sat, 28 Sep 2013 18:10:43 +0530 Subject: sf: Add proper comment style on spi_flash structure Added proper comment style on spi_flash structure to make more readable. Signed-off-by: Jagannadha Sutradharudu Teki --- include/spi_flash.h | 67 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/include/spi_flash.h b/include/spi_flash.h index 09af55dee5..7ffc7b239e 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -29,39 +29,50 @@ # define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ #endif +/** + * struct spi_flash - SPI flash structure + * + * @spi: SPI slave + * @name: Name of SPI flash + * @size: Total flash size + * @page_size: Write (page) size + * @sector_size: Sector size + * @erase_size: Erase size + * @bank_read_cmd: Bank read cmd + * @bank_write_cmd: Bank write cmd + * @bank_curr: Current flash bank + * @poll_cmd: Poll cmd - for flash erase/program + * @erase_cmd: Erase cmd 4K, 32K, 64K + * @memory_map: Address of read-only SPI flash access + * @read: Flash read ops: Read len bytes at offset into buf + * Supported cmds: Fast Array Read + * @write: Flash write ops: Write len bytes from buf into offeset + * Supported cmds: Page Program + * @erase: Flash erase ops: Erase len bytes from offset + * Supported cmds: Sector erase 4K, 32K, 64K + * return 0 - Sucess, 1 - Failure + */ struct spi_flash { struct spi_slave *spi; + const char *name; - const char *name; - - /* Total flash size */ - u32 size; - /* Write (page) size */ - u32 page_size; - /* Sector size */ - u32 sector_size; - /* Erase size */ - u32 erase_size; + u32 size; + u32 page_size; + u32 sector_size; + u32 erase_size; #ifdef CONFIG_SPI_FLASH_BAR - /* Bank read cmd */ - u8 bank_read_cmd; - /* Bank write cmd */ - u8 bank_write_cmd; - /* Current flash bank */ - u8 bank_curr; + u8 bank_read_cmd; + u8 bank_write_cmd; + u8 bank_curr; #endif - /* Poll cmd - for flash erase/program */ - u8 poll_cmd; - /* Erase cmd 4K, 32K, 64K */ - u8 erase_cmd; - - void *memory_map; /* Address of read-only SPI flash access */ - int (*read)(struct spi_flash *flash, u32 offset, - size_t len, void *buf); - int (*write)(struct spi_flash *flash, u32 offset, - size_t len, const void *buf); - int (*erase)(struct spi_flash *flash, u32 offset, - size_t len); + u8 poll_cmd; + u8 erase_cmd; + + void *memory_map; + int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf); + int (*write)(struct spi_flash *flash, u32 offset, size_t len, + const void *buf); + int (*erase)(struct spi_flash *flash, u32 offset, size_t len); }; /** -- cgit v1.2.3 From af1679bc30b11b90f9f6650d211b3fe350f4044f Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Tue, 24 Sep 2013 16:03:45 +0530 Subject: sf: ramtron: Add support for separate flash driver Compared to other spi flashes, ramtron has a different probing and implementation on flash ops, hence moved ramtron probe code into ramtron driver. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/Makefile | 5 +- drivers/mtd/spi/ramtron.c | 123 +++++++++++++- drivers/mtd/spi/spi_flash_probe.c | 4 - drivers/mtd/spi/spi_flash_probe_legacy.c | 276 ------------------------------- include/configs/top9000.h | 1 - 5 files changed, 125 insertions(+), 284 deletions(-) delete mode 100644 drivers/mtd/spi/spi_flash_probe_legacy.c diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index a10c8506af..2605e57e07 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -14,7 +14,10 @@ COBJS-$(CONFIG_SPL_SPI_LOAD) += spi_spl_load.o COBJS-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o endif -COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe_legacy.o spi_flash_ops.o spi_flash.o +ifdef CONFIG_CMD_SF +COBJS-y += spi_flash.o +endif +COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe.o spi_flash_ops.o COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o COBJS-$(CONFIG_SPI_FLASH_EON) += eon.o COBJS-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.o diff --git a/drivers/mtd/spi/ramtron.c b/drivers/mtd/spi/ramtron.c index 38f9d69169..c9701d05b3 100644 --- a/drivers/mtd/spi/ramtron.c +++ b/drivers/mtd/spi/ramtron.c @@ -214,7 +214,8 @@ static int ramtron_erase(struct spi_flash *flash, u32 offset, size_t len) * nore: we are called here with idcode pointing to the first non-0x7f byte * already! */ -struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode) +static struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, + u8 *idcode) { const struct ramtron_spi_fram_params *params; struct ramtron_spi_fram *sn; @@ -270,7 +271,7 @@ struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode) return NULL; found: - sn = spi_flash_alloc(struct ramtron_spi_fram, spi, params->name); + sn = malloc(sizeof(*sn)); if (!sn) { debug("SF: Failed to allocate memory\n"); return NULL; @@ -285,3 +286,121 @@ found: return &sn->flash; } + +/* + * The following table holds all device probe functions + * (All flashes are removed and implemented a common probe at + * spi_flash_probe.c) + * + * shift: number of continuation bytes before the ID + * idcode: the expected IDCODE or 0xff for non JEDEC devices + * probe: the function to call + * + * Non JEDEC devices should be ordered in the table such that + * the probe functions with best detection algorithms come first. + * + * Several matching entries are permitted, they will be tried + * in sequence until a probe function returns non NULL. + * + * IDCODE_CONT_LEN may be redefined if a device needs to declare a + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be + * changed. This is the max number of bytes probe functions may + * examine when looking up part-specific identification info. + * + * Probe functions will be given the idcode buffer starting at their + * manu id byte (the "idcode" in the table below). In other words, + * all of the continuation bytes will be skipped (the "shift" below). + */ +#define IDCODE_CONT_LEN 0 +#define IDCODE_PART_LEN 5 +static const struct { + const u8 shift; + const u8 idcode; + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); +} flashes[] = { + /* Keep it sorted by define name */ +#ifdef CONFIG_SPI_FRAM_RAMTRON + { 6, 0xc2, spi_fram_probe_ramtron, }, +# undef IDCODE_CONT_LEN +# define IDCODE_CONT_LEN 6 +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { 0, 0xff, spi_fram_probe_ramtron, }, +#endif +}; +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + int ret, i, shift; + u8 idcode[IDCODE_LEN], *idp; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printf("SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + debug("SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + +#ifdef DEBUG + printf("SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* count the number of continuation bytes */ + for (shift = 0, idp = idcode; + shift < IDCODE_CONT_LEN && *idp == 0x7f; + ++shift, ++idp) + continue; + + /* search the table for matches in shift and id */ + for (i = 0; i < ARRAY_SIZE(flashes); ++i) + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { + /* we have a match, call probe */ + flash = flashes[i].probe(spi, idp); + if (flash) + break; + } + + if (!flash) { + printf("SF: Unsupported manufacturer %02x\n", *idp); + goto err_manufacturer_probe; + } + + printf("SF: Detected %s with page size ", flash->name); + print_size(flash->sector_size, ", total "); + print_size(flash->size, ""); + if (flash->memory_map) + printf(", mapped at %p", flash->memory_map); + puts("\n"); + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index cc30ad1a8c..c432b043c5 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -144,10 +144,6 @@ static const struct spi_flash_params spi_flash_params_table[] = { * (W25Q64DW, W25Q64FV_QPI) * (W25Q128FW, W25Q128FV_QPI) */ - /* - * TODO: - * RAMTRON - */ }; struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) diff --git a/drivers/mtd/spi/spi_flash_probe_legacy.c b/drivers/mtd/spi/spi_flash_probe_legacy.c deleted file mode 100644 index 32ec578d0d..0000000000 --- a/drivers/mtd/spi/spi_flash_probe_legacy.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * SPI flash probing - * - * Copyright (C) 2008 Atmel Corporation - * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik - * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include - -#include "spi_flash_internal.h" - -DECLARE_GLOBAL_DATA_PTR; - -#ifdef CONFIG_SPI_FLASH_BAR -int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) -{ - u8 cmd; - u8 curr_bank = 0; - - /* discover bank cmds */ - switch (idcode0) { - case SPI_FLASH_SPANSION_IDCODE0: - flash->bank_read_cmd = CMD_BANKADDR_BRRD; - flash->bank_write_cmd = CMD_BANKADDR_BRWR; - break; - case SPI_FLASH_STMICRO_IDCODE0: - case SPI_FLASH_WINBOND_IDCODE0: - flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; - flash->bank_write_cmd = CMD_EXTNADDR_WREAR; - break; - default: - printf("SF: Unsupported bank commands %02x\n", idcode0); - return -1; - } - - /* read the bank reg - on which bank the flash is in currently */ - cmd = flash->bank_read_cmd; - if (flash->size > SPI_FLASH_16MB_BOUN) { - if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { - debug("SF: fail to read bank addr register\n"); - return -1; - } - flash->bank_curr = curr_bank; - } else { - flash->bank_curr = curr_bank; - } - - return 0; -} -#endif - -#ifdef CONFIG_OF_CONTROL -int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) -{ - fdt_addr_t addr; - fdt_size_t size; - int node; - - /* If there is no node, do nothing */ - node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); - if (node < 0) - return 0; - - addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); - if (addr == FDT_ADDR_T_NONE) { - debug("%s: Cannot decode address\n", __func__); - return 0; - } - - if (flash->size != size) { - debug("%s: Memory map must cover entire device\n", __func__); - return -1; - } - flash->memory_map = (void *)addr; - - return 0; -} -#endif /* CONFIG_OF_CONTROL */ - -/* - * The following table holds all device probe functions - * - * shift: number of continuation bytes before the ID - * idcode: the expected IDCODE or 0xff for non JEDEC devices - * probe: the function to call - * - * Non JEDEC devices should be ordered in the table such that - * the probe functions with best detection algorithms come first. - * - * Several matching entries are permitted, they will be tried - * in sequence until a probe function returns non NULL. - * - * IDCODE_CONT_LEN may be redefined if a device needs to declare a - * larger "shift" value. IDCODE_PART_LEN generally shouldn't be - * changed. This is the max number of bytes probe functions may - * examine when looking up part-specific identification info. - * - * Probe functions will be given the idcode buffer starting at their - * manu id byte (the "idcode" in the table below). In other words, - * all of the continuation bytes will be skipped (the "shift" below). - */ -#define IDCODE_CONT_LEN 0 -#define IDCODE_PART_LEN 5 -static const struct { - const u8 shift; - const u8 idcode; - struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); -} flashes[] = { - /* Keep it sorted by define name */ -#ifdef CONFIG_SPI_FLASH_ATMEL - { 0, 0x1f, spi_flash_probe_atmel, }, -#endif -#ifdef CONFIG_SPI_FLASH_EON - { 0, 0x1c, spi_flash_probe_eon, }, -#endif -#ifdef CONFIG_SPI_FLASH_GIGADEVICE - { 0, 0xc8, spi_flash_probe_gigadevice, }, -#endif -#ifdef CONFIG_SPI_FLASH_MACRONIX - { 0, 0xc2, spi_flash_probe_macronix, }, -#endif -#ifdef CONFIG_SPI_FLASH_SPANSION - { 0, 0x01, spi_flash_probe_spansion, }, -#endif -#ifdef CONFIG_SPI_FLASH_SST - { 0, 0xbf, spi_flash_probe_sst, }, -#endif -#ifdef CONFIG_SPI_FLASH_STMICRO - { 0, 0x20, spi_flash_probe_stmicro, }, -#endif -#ifdef CONFIG_SPI_FLASH_WINBOND - { 0, 0xef, spi_flash_probe_winbond, }, -#endif -#ifdef CONFIG_SPI_FRAM_RAMTRON - { 6, 0xc2, spi_fram_probe_ramtron, }, -# undef IDCODE_CONT_LEN -# define IDCODE_CONT_LEN 6 -#endif - /* Keep it sorted by best detection */ -#ifdef CONFIG_SPI_FLASH_STMICRO - { 0, 0xff, spi_flash_probe_stmicro, }, -#endif -#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC - { 0, 0xff, spi_fram_probe_ramtron, }, -#endif -}; -#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) - -struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int spi_mode) -{ - struct spi_slave *spi; - struct spi_flash *flash = NULL; - int ret, i, shift; - u8 idcode[IDCODE_LEN], *idp; - - spi = spi_setup_slave(bus, cs, max_hz, spi_mode); - if (!spi) { - printf("SF: Failed to set up slave\n"); - return NULL; - } - - ret = spi_claim_bus(spi); - if (ret) { - debug("SF: Failed to claim SPI bus: %d\n", ret); - goto err_claim_bus; - } - - /* Read the ID codes */ - ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); - if (ret) - goto err_read_id; - -#ifdef DEBUG - printf("SF: Got idcodes\n"); - print_buffer(0, idcode, 1, sizeof(idcode), 0); -#endif - - /* count the number of continuation bytes */ - for (shift = 0, idp = idcode; - shift < IDCODE_CONT_LEN && *idp == 0x7f; - ++shift, ++idp) - continue; - - /* search the table for matches in shift and id */ - for (i = 0; i < ARRAY_SIZE(flashes); ++i) - if (flashes[i].shift == shift && flashes[i].idcode == *idp) { - /* we have a match, call probe */ - flash = flashes[i].probe(spi, idp); - if (flash) - break; - } - - if (!flash) { - printf("SF: Unsupported manufacturer %02x\n", *idp); - goto err_manufacturer_probe; - } - -#ifdef CONFIG_SPI_FLASH_BAR - /* Configure the BAR - disover bank cmds and read current bank */ - ret = spi_flash_bank_config(flash, *idp); - if (ret < 0) - goto err_manufacturer_probe; -#endif - -#ifdef CONFIG_OF_CONTROL - if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { - debug("SF: FDT decode error\n"); - goto err_manufacturer_probe; - } -#endif -#ifndef CONFIG_SPL_BUILD - printf("SF: Detected %s with page size ", flash->name); - print_size(flash->sector_size, ", total "); - print_size(flash->size, ""); - if (flash->memory_map) - printf(", mapped at %p", flash->memory_map); - puts("\n"); -#endif -#ifndef CONFIG_SPI_FLASH_BAR - if (flash->size > SPI_FLASH_16MB_BOUN) { - puts("SF: Warning - Only lower 16MiB accessible,"); - puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); - } -#endif - - spi_release_bus(spi); - - return flash; - -err_manufacturer_probe: -err_read_id: - spi_release_bus(spi); -err_claim_bus: - spi_free_slave(spi); - return NULL; -} - -void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, - const char *name) -{ - struct spi_flash *flash; - void *ptr; - - ptr = malloc(size); - if (!ptr) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - memset(ptr, '\0', size); - flash = (struct spi_flash *)(ptr + offset); - - /* Set up some basic fields - caller will sort out sizes */ - flash->spi = spi; - flash->name = name; - flash->poll_cmd = CMD_READ_STATUS; - - flash->read = spi_flash_cmd_read_fast; - flash->write = spi_flash_cmd_write_multi; - flash->erase = spi_flash_cmd_erase; - - return flash; -} - -void spi_flash_free(struct spi_flash *flash) -{ - spi_free_slave(flash->spi); - free(flash); -} diff --git a/include/configs/top9000.h b/include/configs/top9000.h index 65dabde54f..a6d692872c 100644 --- a/include/configs/top9000.h +++ b/include/configs/top9000.h @@ -120,7 +120,6 @@ #define CONFIG_ATMEL_SPI0 /* SPI used for FRAM is SPI0 */ #define FRAM_SPI_BUS 0 #define FRAM_CS_NUM 0 -#define CONFIG_SPI_FLASH /* RAMTRON FRAM on SPI bus */ #define CONFIG_SPI_FRAM_RAMTRON #define CONFIG_SF_DEFAULT_SPEED 1000000 /* be conservative here... */ #define CONFIG_SF_DEFAULT_MODE SPI_MODE_0 -- cgit v1.2.3 From 6af8dc3ebccb3b1e4b2e479315e49545e7f53150 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Thu, 29 Aug 2013 19:28:09 +0530 Subject: sf: Remove unneeded flash drivers files Now the common probing is handled in spi_flash_probe.c hence removed the unneeded flash drivers. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/Makefile | 8 - drivers/mtd/spi/atmel.c | 544 ----------------------------------- drivers/mtd/spi/eon.c | 60 ---- drivers/mtd/spi/gigadevice.c | 65 ----- drivers/mtd/spi/macronix.c | 98 ------- drivers/mtd/spi/spansion.c | 141 --------- drivers/mtd/spi/spi_flash_internal.h | 11 - drivers/mtd/spi/sst.c | 238 --------------- drivers/mtd/spi/stmicro.c | 202 ------------- drivers/mtd/spi/winbond.c | 141 --------- 10 files changed, 1508 deletions(-) delete mode 100644 drivers/mtd/spi/atmel.c delete mode 100644 drivers/mtd/spi/eon.c delete mode 100644 drivers/mtd/spi/gigadevice.c delete mode 100644 drivers/mtd/spi/macronix.c delete mode 100644 drivers/mtd/spi/spansion.c delete mode 100644 drivers/mtd/spi/sst.c delete mode 100644 drivers/mtd/spi/stmicro.c delete mode 100644 drivers/mtd/spi/winbond.c diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 2605e57e07..56781345b3 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -18,14 +18,6 @@ ifdef CONFIG_CMD_SF COBJS-y += spi_flash.o endif COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe.o spi_flash_ops.o -COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o -COBJS-$(CONFIG_SPI_FLASH_EON) += eon.o -COBJS-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.o -COBJS-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.o -COBJS-$(CONFIG_SPI_FLASH_SPANSION) += spansion.o -COBJS-$(CONFIG_SPI_FLASH_SST) += sst.o -COBJS-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.o -COBJS-$(CONFIG_SPI_FLASH_WINBOND) += winbond.o COBJS-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o COBJS-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c deleted file mode 100644 index f34df43f58..0000000000 --- a/drivers/mtd/spi/atmel.c +++ /dev/null @@ -1,544 +0,0 @@ -/* - * Atmel SPI DataFlash support - * - * Copyright (C) 2008 Atmel Corporation - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include - -#include "spi_flash_internal.h" - -/* AT45-specific commands */ -#define CMD_AT45_READ_STATUS 0xd7 -#define CMD_AT45_ERASE_PAGE 0x81 -#define CMD_AT45_LOAD_PROG_BUF1 0x82 -#define CMD_AT45_LOAD_BUF1 0x84 -#define CMD_AT45_LOAD_PROG_BUF2 0x85 -#define CMD_AT45_LOAD_BUF2 0x87 -#define CMD_AT45_PROG_BUF1 0x88 -#define CMD_AT45_PROG_BUF2 0x89 - -/* AT45 status register bits */ -#define AT45_STATUS_P2_PAGE_SIZE (1 << 0) -#define AT45_STATUS_READY (1 << 7) - -/* DataFlash family IDs, as obtained from the second idcode byte */ -#define DF_FAMILY_AT26F 0 -#define DF_FAMILY_AT45 1 -#define DF_FAMILY_AT26DF 2 /* AT25DF and AT26DF */ - -struct atmel_spi_flash_params { - u8 idcode1; - /* Log2 of page size in power-of-two mode */ - u8 l2_page_size; - u8 pages_per_block; - u8 blocks_per_sector; - u8 nr_sectors; - const char *name; -}; - -/* spi_flash needs to be first so upper layers can free() it */ -struct atmel_spi_flash { - struct spi_flash flash; - const struct atmel_spi_flash_params *params; -}; - -static inline struct atmel_spi_flash * -to_atmel_spi_flash(struct spi_flash *flash) -{ - return container_of(flash, struct atmel_spi_flash, flash); -} - -static const struct atmel_spi_flash_params atmel_spi_flash_table[] = { - { - .idcode1 = 0x22, - .l2_page_size = 8, - .pages_per_block = 8, - .blocks_per_sector = 16, - .nr_sectors = 4, - .name = "AT45DB011D", - }, - { - .idcode1 = 0x23, - .l2_page_size = 8, - .pages_per_block = 8, - .blocks_per_sector = 16, - .nr_sectors = 8, - .name = "AT45DB021D", - }, - { - .idcode1 = 0x24, - .l2_page_size = 8, - .pages_per_block = 8, - .blocks_per_sector = 32, - .nr_sectors = 8, - .name = "AT45DB041D", - }, - { - .idcode1 = 0x25, - .l2_page_size = 8, - .pages_per_block = 8, - .blocks_per_sector = 32, - .nr_sectors = 16, - .name = "AT45DB081D", - }, - { - .idcode1 = 0x26, - .l2_page_size = 9, - .pages_per_block = 8, - .blocks_per_sector = 32, - .nr_sectors = 16, - .name = "AT45DB161D", - }, - { - .idcode1 = 0x27, - .l2_page_size = 9, - .pages_per_block = 8, - .blocks_per_sector = 64, - .nr_sectors = 64, - .name = "AT45DB321D", - }, - { - .idcode1 = 0x28, - .l2_page_size = 10, - .pages_per_block = 8, - .blocks_per_sector = 32, - .nr_sectors = 32, - .name = "AT45DB642D", - }, - { - .idcode1 = 0x47, - .l2_page_size = 8, - .pages_per_block = 16, - .blocks_per_sector = 16, - .nr_sectors = 64, - .name = "AT25DF321", - }, -}; - -static int at45_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 cmd = CMD_AT45_READ_STATUS; - u8 status; - - timebase = get_timer(0); - - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); - if (ret) - return -1; - - do { - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) - return -1; - - if (status & AT45_STATUS_READY) - break; - } while (get_timer(timebase) < timeout); - - /* Deactivate CS */ - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if (status & AT45_STATUS_READY) - return 0; - - /* Timed out */ - return -1; -} - -/* - * Assemble the address part of a command for AT45 devices in - * non-power-of-two page size mode. - */ -static void at45_build_address(struct atmel_spi_flash *asf, u8 *cmd, u32 offset) -{ - unsigned long page_addr; - unsigned long byte_addr; - unsigned long page_size; - unsigned int page_shift; - - /* - * The "extra" space per page is the power-of-two page size - * divided by 32. - */ - page_shift = asf->params->l2_page_size; - page_size = (1 << page_shift) + (1 << (page_shift - 5)); - page_shift++; - page_addr = offset / page_size; - byte_addr = offset % page_size; - - cmd[0] = page_addr >> (16 - page_shift); - cmd[1] = page_addr << (page_shift - 8) | (byte_addr >> 8); - cmd[2] = byte_addr; -} - -static int dataflash_read_fast_at45(struct spi_flash *flash, - u32 offset, size_t len, void *buf) -{ - struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); - u8 cmd[5]; - - cmd[0] = CMD_READ_ARRAY_FAST; - at45_build_address(asf, cmd + 1, offset); - cmd[4] = 0x00; - - return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len); -} - -/* - * TODO: the two write funcs (_p2/_at45) should get unified ... - */ -static int dataflash_write_p2(struct spi_flash *flash, - u32 offset, size_t len, const void *buf) -{ - struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); - unsigned long page_size; - u32 addr = offset; - size_t chunk_len; - size_t actual; - int ret; - u8 cmd[4]; - - /* - * TODO: This function currently uses only page buffer #1. We can - * speed this up by using both buffers and loading one buffer while - * the other is being programmed into main memory. - */ - - page_size = (1 << asf->params->l2_page_size); - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - for (actual = 0; actual < len; actual += chunk_len) { - chunk_len = min(len - actual, page_size - (addr % page_size)); - - /* Use the same address bits for both commands */ - cmd[0] = CMD_AT45_LOAD_BUF1; - cmd[1] = addr >> 16; - cmd[2] = addr >> 8; - cmd[3] = addr; - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, - buf + actual, chunk_len); - if (ret < 0) { - debug("SF: Loading AT45 buffer failed\n"); - goto out; - } - - cmd[0] = CMD_AT45_PROG_BUF1; - ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); - if (ret < 0) { - debug("SF: AT45 page programming failed\n"); - goto out; - } - - ret = at45_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: AT45 page programming timed out\n"); - goto out; - } - - addr += chunk_len; - } - - debug("SF: AT45: Successfully programmed %zu bytes @ 0x%x\n", - len, offset); - ret = 0; - -out: - spi_release_bus(flash->spi); - return ret; -} - -static int dataflash_write_at45(struct spi_flash *flash, - u32 offset, size_t len, const void *buf) -{ - struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); - unsigned long page_addr; - unsigned long byte_addr; - unsigned long page_size; - unsigned int page_shift; - size_t chunk_len; - size_t actual; - int ret; - u8 cmd[4]; - - /* - * TODO: This function currently uses only page buffer #1. We can - * speed this up by using both buffers and loading one buffer while - * the other is being programmed into main memory. - */ - - page_shift = asf->params->l2_page_size; - page_size = (1 << page_shift) + (1 << (page_shift - 5)); - page_shift++; - page_addr = offset / page_size; - byte_addr = offset % page_size; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - for (actual = 0; actual < len; actual += chunk_len) { - chunk_len = min(len - actual, page_size - byte_addr); - - /* Use the same address bits for both commands */ - cmd[0] = CMD_AT45_LOAD_BUF1; - cmd[1] = page_addr >> (16 - page_shift); - cmd[2] = page_addr << (page_shift - 8) | (byte_addr >> 8); - cmd[3] = byte_addr; - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, - buf + actual, chunk_len); - if (ret < 0) { - debug("SF: Loading AT45 buffer failed\n"); - goto out; - } - - cmd[0] = CMD_AT45_PROG_BUF1; - ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); - if (ret < 0) { - debug("SF: AT45 page programming failed\n"); - goto out; - } - - ret = at45_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: AT45 page programming timed out\n"); - goto out; - } - - page_addr++; - byte_addr = 0; - } - - debug("SF: AT45: Successfully programmed %zu bytes @ 0x%x\n", - len, offset); - ret = 0; - -out: - spi_release_bus(flash->spi); - return ret; -} - -/* - * TODO: the two erase funcs (_p2/_at45) should get unified ... - */ -static int dataflash_erase_p2(struct spi_flash *flash, u32 offset, size_t len) -{ - struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); - unsigned long page_size; - - size_t actual; - int ret; - u8 cmd[4]; - - /* - * TODO: This function currently uses page erase only. We can - * probably speed things up by using block and/or sector erase - * when possible. - */ - - page_size = (1 << asf->params->l2_page_size); - - if (offset % page_size || len % page_size) { - debug("SF: Erase offset/length not multiple of page size\n"); - return -1; - } - - cmd[0] = CMD_AT45_ERASE_PAGE; - cmd[3] = 0x00; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - for (actual = 0; actual < len; actual += page_size) { - cmd[1] = offset >> 16; - cmd[2] = offset >> 8; - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); - if (ret < 0) { - debug("SF: AT45 page erase failed\n"); - goto out; - } - - ret = at45_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret < 0) { - debug("SF: AT45 page erase timed out\n"); - goto out; - } - - offset += page_size; - } - - debug("SF: AT45: Successfully erased %zu bytes @ 0x%x\n", - len, offset); - ret = 0; - -out: - spi_release_bus(flash->spi); - return ret; -} - -static int dataflash_erase_at45(struct spi_flash *flash, u32 offset, size_t len) -{ - struct atmel_spi_flash *asf = to_atmel_spi_flash(flash); - unsigned long page_addr; - unsigned long page_size; - unsigned int page_shift; - size_t actual; - int ret; - u8 cmd[4]; - - /* - * TODO: This function currently uses page erase only. We can - * probably speed things up by using block and/or sector erase - * when possible. - */ - - page_shift = asf->params->l2_page_size; - page_size = (1 << page_shift) + (1 << (page_shift - 5)); - page_shift++; - page_addr = offset / page_size; - - if (offset % page_size || len % page_size) { - debug("SF: Erase offset/length not multiple of page size\n"); - return -1; - } - - cmd[0] = CMD_AT45_ERASE_PAGE; - cmd[3] = 0x00; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - for (actual = 0; actual < len; actual += page_size) { - cmd[1] = page_addr >> (16 - page_shift); - cmd[2] = page_addr << (page_shift - 8); - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0); - if (ret < 0) { - debug("SF: AT45 page erase failed\n"); - goto out; - } - - ret = at45_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret < 0) { - debug("SF: AT45 page erase timed out\n"); - goto out; - } - - page_addr++; - } - - debug("SF: AT45: Successfully erased %zu bytes @ 0x%x\n", - len, offset); - ret = 0; - -out: - spi_release_bus(flash->spi); - return ret; -} - -struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode) -{ - const struct atmel_spi_flash_params *params; - unsigned page_size; - unsigned int family; - struct atmel_spi_flash *asf; - unsigned int i; - int ret; - u8 status; - - for (i = 0; i < ARRAY_SIZE(atmel_spi_flash_table); i++) { - params = &atmel_spi_flash_table[i]; - if (params->idcode1 == idcode[1]) - break; - } - - if (i == ARRAY_SIZE(atmel_spi_flash_table)) { - debug("SF: Unsupported DataFlash ID %02x\n", - idcode[1]); - return NULL; - } - - asf = spi_flash_alloc(struct atmel_spi_flash, spi, params->name); - if (!asf) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - - asf->params = params; - - /* Assuming power-of-two page size initially. */ - page_size = 1 << params->l2_page_size; - - family = idcode[1] >> 5; - - switch (family) { - case DF_FAMILY_AT45: - /* - * AT45 chips have configurable page size. The status - * register indicates which configuration is active. - */ - ret = spi_flash_cmd(spi, CMD_AT45_READ_STATUS, &status, 1); - if (ret) - goto err; - - debug("SF: AT45 status register: %02x\n", status); - - if (!(status & AT45_STATUS_P2_PAGE_SIZE)) { - asf->flash.read = dataflash_read_fast_at45; - asf->flash.write = dataflash_write_at45; - asf->flash.erase = dataflash_erase_at45; - page_size += 1 << (params->l2_page_size - 5); - } else { - asf->flash.write = dataflash_write_p2; - asf->flash.erase = dataflash_erase_p2; - } - - asf->flash.page_size = page_size; - asf->flash.sector_size = page_size; - break; - - case DF_FAMILY_AT26F: - case DF_FAMILY_AT26DF: - asf->flash.page_size = page_size; - asf->flash.sector_size = 4096; - /* clear SPRL# bit for locked flash */ - spi_flash_cmd_write_status(&asf->flash, 0); - break; - - default: - debug("SF: Unsupported DataFlash family %u\n", family); - goto err; - } - - asf->flash.size = page_size * params->pages_per_block - * params->blocks_per_sector - * params->nr_sectors; - - return &asf->flash; - -err: - free(asf); - return NULL; -} diff --git a/drivers/mtd/spi/eon.c b/drivers/mtd/spi/eon.c deleted file mode 100644 index 25cfc1252c..0000000000 --- a/drivers/mtd/spi/eon.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * (C) Copyright 2010, ucRobotics Inc. - * Author: Chong Huang - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include - -#include "spi_flash_internal.h" - -struct eon_spi_flash_params { - u8 idcode1; - u16 nr_sectors; - const char *name; -}; - -static const struct eon_spi_flash_params eon_spi_flash_table[] = { - { - .idcode1 = 0x16, - .nr_sectors = 1024, - .name = "EN25Q32B", - }, - { - .idcode1 = 0x18, - .nr_sectors = 4096, - .name = "EN25Q128", - }, -}; - -struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) -{ - const struct eon_spi_flash_params *params; - struct spi_flash *flash; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(eon_spi_flash_table); ++i) { - params = &eon_spi_flash_table[i]; - if (params->idcode1 == idcode[2]) - break; - } - - if (i == ARRAY_SIZE(eon_spi_flash_table)) { - debug("SF: Unsupported EON ID %02x\n", idcode[1]); - return NULL; - } - - flash = spi_flash_alloc_base(spi, params->name); - if (!flash) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - - flash->page_size = 256; - flash->sector_size = 256 * 16 * 16; - flash->size = 256 * 16 * params->nr_sectors; - - return flash; -} diff --git a/drivers/mtd/spi/gigadevice.c b/drivers/mtd/spi/gigadevice.c deleted file mode 100644 index b42581a70f..0000000000 --- a/drivers/mtd/spi/gigadevice.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Gigadevice SPI flash driver - * Copyright 2013, Samsung Electronics Co., Ltd. - * Author: Banajit Goswami - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include - -#include "spi_flash_internal.h" - -struct gigadevice_spi_flash_params { - uint16_t id; - uint16_t nr_blocks; - const char *name; -}; - -static const struct gigadevice_spi_flash_params gigadevice_spi_flash_table[] = { - { - .id = 0x6016, - .nr_blocks = 64, - .name = "GD25LQ", - }, - { - .id = 0x4017, - .nr_blocks = 128, - .name = "GD25Q64B", - }, -}; - -struct spi_flash *spi_flash_probe_gigadevice(struct spi_slave *spi, u8 *idcode) -{ - const struct gigadevice_spi_flash_params *params; - struct spi_flash *flash; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(gigadevice_spi_flash_table); i++) { - params = &gigadevice_spi_flash_table[i]; - if (params->id == ((idcode[1] << 8) | idcode[2])) - break; - } - - if (i == ARRAY_SIZE(gigadevice_spi_flash_table)) { - debug("SF: Unsupported Gigadevice ID %02x%02x\n", - idcode[1], idcode[2]); - return NULL; - } - - flash = spi_flash_alloc_base(spi, params->name); - if (!flash) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - /* page_size */ - flash->page_size = 256; - /* sector_size = page_size * pages_per_sector */ - flash->sector_size = flash->page_size * 16; - /* size = sector_size * sector_per_block * number of blocks */ - flash->size = flash->sector_size * 16 * params->nr_blocks; - - return flash; -} diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c deleted file mode 100644 index 70435eb5a3..0000000000 --- a/drivers/mtd/spi/macronix.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2009(C) Marvell International Ltd. and its affiliates - * Prafulla Wadaskar - * - * Based on drivers/mtd/spi/stmicro.c - * - * Copyright 2008, Network Appliance Inc. - * Jason McMullan - * - * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. - * TsiChung Liew (Tsi-Chung.Liew@freescale.com) - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include - -#include "spi_flash_internal.h" - -struct macronix_spi_flash_params { - u16 idcode; - u16 nr_blocks; - const char *name; -}; - -static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { - { - .idcode = 0x2013, - .nr_blocks = 8, - .name = "MX25L4005", - }, - { - .idcode = 0x2014, - .nr_blocks = 16, - .name = "MX25L8005", - }, - { - .idcode = 0x2015, - .nr_blocks = 32, - .name = "MX25L1605D", - }, - { - .idcode = 0x2016, - .nr_blocks = 64, - .name = "MX25L3205D", - }, - { - .idcode = 0x2017, - .nr_blocks = 128, - .name = "MX25L6405D", - }, - { - .idcode = 0x2018, - .nr_blocks = 256, - .name = "MX25L12805D", - }, - { - .idcode = 0x2618, - .nr_blocks = 256, - .name = "MX25L12855E", - }, -}; - -struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) -{ - const struct macronix_spi_flash_params *params; - struct spi_flash *flash; - unsigned int i; - u16 id = idcode[2] | idcode[1] << 8; - - for (i = 0; i < ARRAY_SIZE(macronix_spi_flash_table); i++) { - params = ¯onix_spi_flash_table[i]; - if (params->idcode == id) - break; - } - - if (i == ARRAY_SIZE(macronix_spi_flash_table)) { - debug("SF: Unsupported Macronix ID %04x\n", id); - return NULL; - } - - flash = spi_flash_alloc_base(spi, params->name); - if (!flash) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - - flash->page_size = 256; - flash->sector_size = 256 * 16 * 16; - flash->size = flash->sector_size * params->nr_blocks; - - /* Clear BP# bits for read-only flash */ - spi_flash_cmd_write_status(flash, 0); - - return flash; -} diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c deleted file mode 100644 index fa7ac8c932..0000000000 --- a/drivers/mtd/spi/spansion.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2009 Freescale Semiconductor, Inc. - * - * Author: Mingkai Hu (Mingkai.hu@freescale.com) - * Based on stmicro.c by Wolfgang Denk (wd@denx.de), - * TsiChung Liew (Tsi-Chung.Liew@freescale.com), - * and Jason McMullan (mcmullan@netapp.com) - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include - -#include "spi_flash_internal.h" - -struct spansion_spi_flash_params { - u16 idcode1; - u16 idcode2; - u16 pages_per_sector; - u16 nr_sectors; - const char *name; -}; - -static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { - { - .idcode1 = 0x0213, - .idcode2 = 0, - .pages_per_sector = 256, - .nr_sectors = 16, - .name = "S25FL008A", - }, - { - .idcode1 = 0x0214, - .idcode2 = 0, - .pages_per_sector = 256, - .nr_sectors = 32, - .name = "S25FL016A", - }, - { - .idcode1 = 0x0215, - .idcode2 = 0, - .pages_per_sector = 256, - .nr_sectors = 64, - .name = "S25FL032A", - }, - { - .idcode1 = 0x0216, - .idcode2 = 0, - .pages_per_sector = 256, - .nr_sectors = 128, - .name = "S25FL064A", - }, - { - .idcode1 = 0x2018, - .idcode2 = 0x0301, - .pages_per_sector = 256, - .nr_sectors = 256, - .name = "S25FL128P_64K", - }, - { - .idcode1 = 0x2018, - .idcode2 = 0x0300, - .pages_per_sector = 1024, - .nr_sectors = 64, - .name = "S25FL128P_256K", - }, - { - .idcode1 = 0x0215, - .idcode2 = 0x4d00, - .pages_per_sector = 256, - .nr_sectors = 64, - .name = "S25FL032P", - }, - { - .idcode1 = 0x0216, - .idcode2 = 0x4d00, - .pages_per_sector = 256, - .nr_sectors = 128, - .name = "S25FL064P", - }, - { - .idcode1 = 0x2018, - .idcode2 = 0x4d01, - .pages_per_sector = 256, - .nr_sectors = 256, - .name = "S25FL129P_64K/S25FL128S_64K", - }, - { - .idcode1 = 0x0219, - .idcode2 = 0x4d01, - .pages_per_sector = 256, - .nr_sectors = 512, - .name = "S25FL256S_64K", - }, - { - .idcode1 = 0x0220, - .idcode2 = 0x4d01, - .pages_per_sector = 256, - .nr_sectors = 1024, - .name = "S25FL512S_64K", - }, -}; - -struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) -{ - const struct spansion_spi_flash_params *params; - struct spi_flash *flash; - unsigned int i; - unsigned short jedec, ext_jedec; - - jedec = idcode[1] << 8 | idcode[2]; - ext_jedec = idcode[3] << 8 | idcode[4]; - - for (i = 0; i < ARRAY_SIZE(spansion_spi_flash_table); i++) { - params = &spansion_spi_flash_table[i]; - if (params->idcode1 == jedec) { - if (params->idcode2 == ext_jedec) - break; - } - } - - if (i == ARRAY_SIZE(spansion_spi_flash_table)) { - debug("SF: Unsupported SPANSION ID %04x %04x\n", - jedec, ext_jedec); - return NULL; - } - - flash = spi_flash_alloc_base(spi, params->name); - if (!flash) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - - flash->page_size = 256; - flash->sector_size = 256 * params->pages_per_sector; - flash->size = flash->sector_size * params->nr_sectors; - - return flash; -} diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index 61de2378fd..86966f61e9 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -124,14 +124,3 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); /* Erase sectors. */ int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len); - -/* Manufacturer-specific probe functions */ -struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); -struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); -struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode); -struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode); -struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode); -struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); -struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode); -struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode); -struct spi_flash *spi_flash_probe_gigadevice(struct spi_slave *spi, u8 *idcode); diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c deleted file mode 100644 index 256867c844..0000000000 --- a/drivers/mtd/spi/sst.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Driver for SST serial flashes - * - * (C) Copyright 2000-2002 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * Copyright 2008, Network Appliance Inc. - * Jason McMullan - * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. - * TsiChung Liew (Tsi-Chung.Liew@freescale.com) - * Copyright (c) 2008-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include - -#include "spi_flash_internal.h" - -#define CMD_SST_BP 0x02 /* Byte Program */ -#define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ - -#define SST_SR_WIP (1 << 0) /* Write-in-Progress */ -#define SST_SR_WEL (1 << 1) /* Write enable */ -#define SST_SR_BP0 (1 << 2) /* Block Protection 0 */ -#define SST_SR_BP1 (1 << 3) /* Block Protection 1 */ -#define SST_SR_BP2 (1 << 4) /* Block Protection 2 */ -#define SST_SR_AAI (1 << 6) /* Addressing mode */ -#define SST_SR_BPL (1 << 7) /* BP bits lock */ - -#define SST_FEAT_WP (1 << 0) /* Supports AAI word program */ -#define SST_FEAT_MBP (1 << 1) /* Supports multibyte program */ - -struct sst_spi_flash_params { - u8 idcode1; - u8 flags; - u16 nr_sectors; - const char *name; -}; - -struct sst_spi_flash { - struct spi_flash flash; - const struct sst_spi_flash_params *params; -}; - -static const struct sst_spi_flash_params sst_spi_flash_table[] = { - { - .idcode1 = 0x8d, - .flags = SST_FEAT_WP, - .nr_sectors = 128, - .name = "SST25VF040B", - }, - { - .idcode1 = 0x8e, - .flags = SST_FEAT_WP, - .nr_sectors = 256, - .name = "SST25VF080B", - }, - { - .idcode1 = 0x41, - .flags = SST_FEAT_WP, - .nr_sectors = 512, - .name = "SST25VF016B", - }, - { - .idcode1 = 0x4a, - .flags = SST_FEAT_WP, - .nr_sectors = 1024, - .name = "SST25VF032B", - }, - { - .idcode1 = 0x4b, - .flags = SST_FEAT_MBP, - .nr_sectors = 2048, - .name = "SST25VF064C", - }, - { - .idcode1 = 0x01, - .flags = SST_FEAT_WP, - .nr_sectors = 16, - .name = "SST25WF512", - }, - { - .idcode1 = 0x02, - .flags = SST_FEAT_WP, - .nr_sectors = 32, - .name = "SST25WF010", - }, - { - .idcode1 = 0x03, - .flags = SST_FEAT_WP, - .nr_sectors = 64, - .name = "SST25WF020", - }, - { - .idcode1 = 0x04, - .flags = SST_FEAT_WP, - .nr_sectors = 128, - .name = "SST25WF040", - }, - { - .idcode1 = 0x05, - .flags = SST_FEAT_WP, - .nr_sectors = 256, - .name = "SST25WF080", - }, -}; - -static int -sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) -{ - int ret; - u8 cmd[4] = { - CMD_SST_BP, - offset >> 16, - offset >> 8, - offset, - }; - - debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", - spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset); - - ret = spi_flash_cmd_write_enable(flash); - if (ret) - return ret; - - ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); - if (ret) - return ret; - - return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); -} - -static int -sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, const void *buf) -{ - size_t actual, cmd_len; - int ret; - u8 cmd[4]; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - /* If the data is not word aligned, write out leading single byte */ - actual = offset % 2; - if (actual) { - ret = sst_byte_write(flash, offset, buf); - if (ret) - goto done; - } - offset += actual; - - ret = spi_flash_cmd_write_enable(flash); - if (ret) - goto done; - - cmd_len = 4; - cmd[0] = CMD_SST_AAI_WP; - cmd[1] = offset >> 16; - cmd[2] = offset >> 8; - cmd[3] = offset; - - for (; actual < len - 1; actual += 2) { - debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", - spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual, - cmd[0], offset); - - ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, - buf + actual, 2); - if (ret) { - debug("SF: sst word program failed\n"); - break; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret) - break; - - cmd_len = 1; - offset += 2; - } - - if (!ret) - ret = spi_flash_cmd_write_disable(flash); - - /* If there is a single trailing byte, write it out */ - if (!ret && actual != len) - ret = sst_byte_write(flash, offset, buf + actual); - - done: - debug("SF: sst: program %s %zu bytes @ 0x%zx\n", - ret ? "failure" : "success", len, offset - actual); - - spi_release_bus(flash->spi); - return ret; -} - -struct spi_flash * -spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) -{ - const struct sst_spi_flash_params *params; - struct sst_spi_flash *stm; - size_t i; - - for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) { - params = &sst_spi_flash_table[i]; - if (params->idcode1 == idcode[2]) - break; - } - - if (i == ARRAY_SIZE(sst_spi_flash_table)) { - debug("SF: Unsupported SST ID %02x\n", idcode[1]); - return NULL; - } - - stm = spi_flash_alloc(struct sst_spi_flash, spi, params->name); - if (!stm) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - - stm->params = params; - - if (stm->params->flags & SST_FEAT_WP) - stm->flash.write = sst_write_wp; - stm->flash.page_size = 256; - stm->flash.sector_size = 4096; - stm->flash.size = stm->flash.sector_size * params->nr_sectors; - - /* Flash powers up read-only, so clear BP# bits */ - spi_flash_cmd_write_status(&stm->flash, 0); - - return &stm->flash; -} diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c deleted file mode 100644 index c5fa64e376..0000000000 --- a/drivers/mtd/spi/stmicro.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * (C) Copyright 2000-2002 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * Copyright 2008, Network Appliance Inc. - * Jason McMullan - * - * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. - * TsiChung Liew (Tsi-Chung.Liew@freescale.com) - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include - -#include "spi_flash_internal.h" - -/* M25Pxx-specific commands */ -#define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ - -struct stmicro_spi_flash_params { - u16 id; - u16 pages_per_sector; - u16 nr_sectors; - const char *name; -}; - -static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { - { - .id = 0x2011, - .pages_per_sector = 128, - .nr_sectors = 4, - .name = "M25P10", - }, - { - .id = 0x2015, - .pages_per_sector = 256, - .nr_sectors = 32, - .name = "M25P16", - }, - { - .id = 0x2012, - .pages_per_sector = 256, - .nr_sectors = 4, - .name = "M25P20", - }, - { - .id = 0x2016, - .pages_per_sector = 256, - .nr_sectors = 64, - .name = "M25P32", - }, - { - .id = 0x2013, - .pages_per_sector = 256, - .nr_sectors = 8, - .name = "M25P40", - }, - { - .id = 0x2017, - .pages_per_sector = 256, - .nr_sectors = 128, - .name = "M25P64", - }, - { - .id = 0x2014, - .pages_per_sector = 256, - .nr_sectors = 16, - .name = "M25P80", - }, - { - .id = 0x2018, - .pages_per_sector = 1024, - .nr_sectors = 64, - .name = "M25P128", - }, - { - .id = 0xba16, - .pages_per_sector = 256, - .nr_sectors = 64, - .name = "N25Q32", - }, - { - .id = 0xbb16, - .pages_per_sector = 256, - .nr_sectors = 64, - .name = "N25Q32A", - }, - { - .id = 0xba17, - .pages_per_sector = 256, - .nr_sectors = 128, - .name = "N25Q064", - }, - { - .id = 0xbb17, - .pages_per_sector = 256, - .nr_sectors = 128, - .name = "N25Q64A", - }, - { - .id = 0xba18, - .pages_per_sector = 256, - .nr_sectors = 256, - .name = "N25Q128", - }, - { - .id = 0xbb18, - .pages_per_sector = 256, - .nr_sectors = 256, - .name = "N25Q128A", - }, - { - .id = 0xba19, - .pages_per_sector = 256, - .nr_sectors = 512, - .name = "N25Q256", - }, - { - .id = 0xbb19, - .pages_per_sector = 256, - .nr_sectors = 512, - .name = "N25Q256A", - }, - { - .id = 0xba20, - .pages_per_sector = 256, - .nr_sectors = 1024, - .name = "N25Q512", - }, - { - .id = 0xbb20, - .pages_per_sector = 256, - .nr_sectors = 1024, - .name = "N25Q512A", - }, - { - .id = 0xba21, - .pages_per_sector = 256, - .nr_sectors = 2048, - .name = "N25Q1024", - }, - { - .id = 0xbb21, - .pages_per_sector = 256, - .nr_sectors = 2048, - .name = "N25Q1024A", - }, -}; - -struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode) -{ - const struct stmicro_spi_flash_params *params; - struct spi_flash *flash; - unsigned int i; - u16 id; - - if (idcode[0] == 0xff) { - i = spi_flash_cmd(spi, CMD_M25PXX_RES, - idcode, 4); - if (i) - return NULL; - if ((idcode[3] & 0xf0) == 0x10) { - idcode[0] = 0x20; - idcode[1] = 0x20; - idcode[2] = idcode[3] + 1; - } else { - return NULL; - } - } - - id = ((idcode[1] << 8) | idcode[2]); - - for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) { - params = &stmicro_spi_flash_table[i]; - if (params->id == id) - break; - } - - if (i == ARRAY_SIZE(stmicro_spi_flash_table)) { - debug("SF: Unsupported STMicro ID %04x\n", id); - return NULL; - } - - flash = spi_flash_alloc_base(spi, params->name); - if (!flash) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - - flash->page_size = 256; - flash->sector_size = 256 * params->pages_per_sector; - flash->size = flash->sector_size * params->nr_sectors; - - /* for >= 512MiB flashes, use flag status instead of read_status */ - if (flash->size >= 0x4000000) - flash->poll_cmd = CMD_FLAG_STATUS; - - return flash; -} diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c deleted file mode 100644 index b31911a405..0000000000 --- a/drivers/mtd/spi/winbond.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2008, Network Appliance Inc. - * Author: Jason McMullan netapp.com> - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include - -#include "spi_flash_internal.h" - -struct winbond_spi_flash_params { - uint16_t id; - uint16_t nr_blocks; - const char *name; -}; - -static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { - { - .id = 0x2014, - .nr_blocks = 16, - .name = "W25P80", - }, - { - .id = 0x2015, - .nr_blocks = 32, - .name = "W25P16", - }, - { - .id = 0x2016, - .nr_blocks = 64, - .name = "W25P32", - }, - { - .id = 0x3013, - .nr_blocks = 8, - .name = "W25X40", - }, - { - .id = 0x3015, - .nr_blocks = 32, - .name = "W25X16", - }, - { - .id = 0x3016, - .nr_blocks = 64, - .name = "W25X32", - }, - { - .id = 0x3017, - .nr_blocks = 128, - .name = "W25X64", - }, - { - .id = 0x4014, - .nr_blocks = 16, - .name = "W25Q80BL/W25Q80BV", - }, - { - .id = 0x4015, - .nr_blocks = 32, - .name = "W25Q16CL/W25Q16DV", - }, - { - .id = 0x4016, - .nr_blocks = 64, - .name = "W25Q32BV/W25Q32FV_SPI", - }, - { - .id = 0x4017, - .nr_blocks = 128, - .name = "W25Q64CV/W25Q64FV_SPI", - }, - { - .id = 0x4018, - .nr_blocks = 256, - .name = "W25Q128BV/W25Q128FV_SPI", - }, - { - .id = 0x4019, - .nr_blocks = 512, - .name = "W25Q256", - }, - { - .id = 0x5014, - .nr_blocks = 16, - .name = "W25Q80BW", - }, - { - .id = 0x6015, - .nr_blocks = 32, - .name = "W25Q16DW", - }, - { - .id = 0x6016, - .nr_blocks = 64, - .name = "W25Q32DW/W25Q32FV_QPI", - }, - { - .id = 0x6017, - .nr_blocks = 128, - .name = "W25Q64DW/W25Q64FV_QPI", - }, - { - .id = 0x6018, - .nr_blocks = 256, - .name = "W25Q128FW/W25Q128FV_QPI", - }, -}; - -struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) -{ - const struct winbond_spi_flash_params *params; - struct spi_flash *flash; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) { - params = &winbond_spi_flash_table[i]; - if (params->id == ((idcode[1] << 8) | idcode[2])) - break; - } - - if (i == ARRAY_SIZE(winbond_spi_flash_table)) { - debug("SF: Unsupported Winbond ID %02x%02x\n", - idcode[1], idcode[2]); - return NULL; - } - - flash = spi_flash_alloc_base(spi, params->name); - if (!flash) { - debug("SF: Failed to allocate memory\n"); - return NULL; - } - - flash->page_size = 256; - flash->sector_size = (idcode[1] == 0x20) ? 65536 : 4096; - flash->size = 4096 * 16 * params->nr_blocks; - - return flash; -} -- cgit v1.2.3 From fda41259b87b566aef29367273862083701f031f Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Tue, 6 Aug 2013 16:20:23 +0530 Subject: sf: probe: Add support for EN25Q64 Add support for EON EN25Q64 SPI flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index c432b043c5..883bc276ee 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -49,6 +49,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { #endif #ifdef CONFIG_SPI_FLASH_EON /* EON */ {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, + {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K}, {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ -- cgit v1.2.3 From f0be6ded71bc9ed1b6240a113acef8a2a0cc61b2 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 28 Aug 2013 12:17:56 +0530 Subject: sf: probe: Add support for S25FL256S_256K Add support for Spansion S25FL256S_256K SPI flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 883bc276ee..badbbf5593 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -75,6 +75,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0}, {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0}, {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0}, + {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, 0}, {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0}, {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0}, #endif @@ -195,7 +196,7 @@ struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) flash->read = spi_flash_cmd_read_fast; /* Compute the flash size */ - flash->page_size = 256; + flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; flash->sector_size = params->sector_size; flash->size = flash->sector_size * params->nr_sectors; -- cgit v1.2.3 From af878522b524cb5821075e008ad79f9cb12440ba Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 28 Aug 2013 12:18:56 +0530 Subject: sf: probe: Add support for S25FL512S_256K Add support for Spansion S25FL512S_256K SPI flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index badbbf5593..d9be30f36f 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -77,6 +77,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0}, {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, 0}, {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0}, + {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0}, {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0}, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ -- cgit v1.2.3 From 567901c8e09cf2aefe5cf0ab2b8b62fd83986d55 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sun, 15 Sep 2013 23:04:16 +0530 Subject: sf: probe: Use print_size arg as page_size Use flash->page_size arg in print_size() instead of flash->sector_size while printing detected flas part details. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index d9be30f36f..68290bb2d8 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -325,7 +325,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, #endif #ifndef CONFIG_SPL_BUILD printf("SF: Detected %s with page size ", flash->name); - print_size(flash->sector_size, ", total "); + print_size(flash->page_size, ", total "); print_size(flash->size, ""); if (flash->memory_map) printf(", mapped at %p", flash->memory_map); -- cgit v1.2.3 From 3ea708f0d3cd0a13772f8fe86870d99925b0a868 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Sun, 15 Sep 2013 23:06:12 +0530 Subject: sf: probe: Print erase_size while printing flash details Included erase_size while printing probed flash details. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 68290bb2d8..8abb27dde6 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -325,7 +325,8 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, #endif #ifndef CONFIG_SPL_BUILD printf("SF: Detected %s with page size ", flash->name); - print_size(flash->page_size, ", total "); + print_size(flash->page_size, ", erase size "); + print_size(flash->erase_size, ", total "); print_size(flash->size, ""); if (flash->memory_map) printf(", mapped at %p", flash->memory_map); -- cgit v1.2.3 From 532f2f111cdbcd11a422dfd3a53f63ac657df0bd Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 28 Aug 2013 14:57:03 +0530 Subject: sf: ops: Add static qualifier to spi_flash_cmd_bankaddr_write Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_internal.h | 5 ----- drivers/mtd/spi/spi_flash_ops.c | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index 86966f61e9..1f9f1700ad 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -94,11 +94,6 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) /* Program the status register. */ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); -#ifdef CONFIG_SPI_FLASH_BAR -/* Program the bank address register */ -int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel); -#endif - /* * Same as spi_flash_cmd_read() except it also claims/releases the SPI * bus. Used as common part of the ->read() operation. diff --git a/drivers/mtd/spi/spi_flash_ops.c b/drivers/mtd/spi/spi_flash_ops.c index c408e27b61..b4e1c40fc9 100644 --- a/drivers/mtd/spi/spi_flash_ops.c +++ b/drivers/mtd/spi/spi_flash_ops.c @@ -39,7 +39,7 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) } #ifdef CONFIG_SPI_FLASH_BAR -int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) +static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) { u8 cmd; int ret; -- cgit v1.2.3 From 06655386327589408adcc8bf8f3d2e93bddfb093 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 28 Aug 2013 14:46:49 +0530 Subject: sf: probe: Add support for MX25L25635F Add support for Macronix MX25L25635F SPI flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 8abb27dde6..aa7ea1a2b1 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -63,6 +63,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, + {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0}, {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ -- cgit v1.2.3 From 9719695b24d53c93664bb5ab8e7775cbf8dc524d Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 28 Aug 2013 14:49:13 +0530 Subject: sf: probe: Add support for MX25L51235F Add support for Macronix MX25L51235F SPI flash. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/spi_flash_probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index aa7ea1a2b1..1806fd12b5 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -64,6 +64,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0}, + {"MX25L51235F", 0xc2201A, 0x0, 64 * 1024, 1024, 0}, {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, #endif #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ -- cgit v1.2.3 From 30b0ca631895b1bcaa19dfe605f347564e56d1b7 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 7 Aug 2013 21:36:25 +0530 Subject: sf: Remove spi_flash_do_alloc references Added a support for common probe, hence removed removed spi_flash_do_alloc reference. Signed-off-by: Jagannadha Sutradharudu Teki --- include/spi_flash.h | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/include/spi_flash.h b/include/spi_flash.h index 7ffc7b239e..a5395161e6 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -75,44 +75,6 @@ struct spi_flash { int (*erase)(struct spi_flash *flash, u32 offset, size_t len); }; -/** - * spi_flash_do_alloc - Allocate a new spi flash structure - * - * The structure is allocated and cleared with default values for - * read, write and erase, which the caller can modify. The caller must set - * up size, page_size and sector_size. - * - * Use the helper macro spi_flash_alloc() to call this. - * - * @offset: Offset of struct spi_slave within slave structure - * @size: Size of slave structure - * @spi: SPI slave - * @name: Name of SPI flash device - */ -void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, - const char *name); - -/** - * spi_flash_alloc - Allocate a new SPI flash structure - * - * @_struct: Name of structure to allocate (e.g. struct ramtron_spi_fram). This - * structure must contain a member 'struct spi_flash *flash'. - * @spi: SPI slave - * @name: Name of SPI flash device - */ -#define spi_flash_alloc(_struct, spi, name) \ - spi_flash_do_alloc(offsetof(_struct, flash), sizeof(_struct), \ - spi, name) - -/** - * spi_flash_alloc_base - Allocate a new SPI flash structure with no private data - * - * @spi: SPI slave - * @name: Name of SPI flash device - */ -#define spi_flash_alloc_base(spi, name) \ - spi_flash_do_alloc(0, sizeof(struct spi_flash), spi, name) - struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int spi_mode); void spi_flash_free(struct spi_flash *flash); -- cgit v1.2.3 From a5e8199a13a61eab0a0da9217e74dacd190fcaba Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 2 Oct 2013 19:38:49 +0530 Subject: sf: spi_flash cleanups More cleanups on spi_flash side: - Removed unneeded comments. - Rearranged macros in proper location. - Rearranged func declerations - Renamed few function names. - Added License headers. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/Makefile | 4 +- drivers/mtd/spi/spi_flash_internal.h | 119 ++++++++++++++++++++--------------- drivers/mtd/spi/spi_flash_ops.c | 6 +- drivers/mtd/spi/spi_flash_probe.c | 14 ++--- include/spi_flash.h | 16 +---- 5 files changed, 85 insertions(+), 74 deletions(-) diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 56781345b3..0fa867db4c 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -17,8 +17,8 @@ endif ifdef CONFIG_CMD_SF COBJS-y += spi_flash.o endif -COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe.o spi_flash_ops.o -COBJS-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o +COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe.o spi_flash_ops.o +COBJS-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o COBJS-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o COBJS := $(COBJS-y) diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index 1f9f1700ad..29a14f4df6 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -2,37 +2,43 @@ * SPI flash internal definitions * * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * + * Licensed under the GPL-2 or later. */ -/* Common parameters -- kind of high, but they should only occur when there - * is a problem (and well your system already is broken), so err on the side - * of caution in case we're dealing with slower SPI buses and/or processors. - */ -#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) -#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) -#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) +#ifndef _SPI_FLASH_INTERNAL_H_ +#define _SPI_FLASH_INTERNAL_H_ -/* Common commands */ -#define CMD_READ_ID 0x9f +#define SPI_FLASH_16MB_BOUN 0x1000000 -#define CMD_READ_ARRAY_SLOW 0x03 -#define CMD_READ_ARRAY_FAST 0x0b +/* SECT flags */ +#define SECT_4K (1 << 1) +#define SECT_32K (1 << 2) +#define E_FSR (1 << 3) + +/* Erase commands */ +#define CMD_ERASE_4K 0x20 +#define CMD_ERASE_32K 0x52 +#define CMD_ERASE_CHIP 0xc7 +#define CMD_ERASE_64K 0xd8 +/* Write commands */ #define CMD_WRITE_STATUS 0x01 #define CMD_PAGE_PROGRAM 0x02 #define CMD_WRITE_DISABLE 0x04 #define CMD_READ_STATUS 0x05 -#define CMD_FLAG_STATUS 0x70 #define CMD_WRITE_ENABLE 0x06 -#define CMD_ERASE_4K 0x20 -#define CMD_ERASE_32K 0x52 -#define CMD_ERASE_64K 0xd8 -#define CMD_ERASE_CHIP 0xc7 +#define CMD_READ_CONFIG 0x35 +#define CMD_FLAG_STATUS 0x70 -#define SPI_FLASH_16MB_BOUN 0x1000000 +/* Read commands */ +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ID 0x9f -#ifdef CONFIG_SPI_FLASH_BAR /* Bank addr access commands */ +#ifdef CONFIG_SPI_FLASH_BAR # define CMD_BANKADDR_BRWR 0x17 # define CMD_BANKADDR_BRRD 0x16 # define CMD_EXTNADDR_WREAR 0xC5 @@ -43,6 +49,21 @@ #define STATUS_WIP 0x01 #define STATUS_PEC 0x80 +/* Flash timeout values */ +#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) + +/* SST specific */ +#ifdef CONFIG_SPI_FLASH_SST +# define SST_WP 0x01 /* Supports AAI word program */ +# define CMD_SST_BP 0x02 /* Byte Program */ +# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ + +int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, + const void *buf); +#endif + /* Send a single-byte command to the device and read the response */ int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); @@ -53,9 +74,6 @@ int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, void *data, size_t data_len); -int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, - size_t len, void *data); - /* * Send a multi-byte command to the device followed by (optional) * data. Used for programming the flash array, etc. @@ -63,43 +81,34 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, const void *data, size_t data_len); -/* - * Write the requested data out breaking it up into multiple write - * commands as needed per the write size. - */ -int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, - size_t len, const void *buf); -#ifdef CONFIG_SPI_FLASH_SST -int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, - const void *buf); -#endif +/* Flash erase(sectors) operation, support all possible erase commands */ +int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); -/* - * Enable writing on the SPI flash. - */ +/* Program the status register */ +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); + +/* Set quad enbale bit */ +int spi_flash_set_qeb(struct spi_flash *flash); + +/* Enable writing on the SPI flash */ static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) { return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); } -/* - * Disable writing on the SPI flash. - */ +/* Disable writing on the SPI flash */ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) { return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0); } -/* Program the status register. */ -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); - /* - * Same as spi_flash_cmd_read() except it also claims/releases the SPI - * bus. Used as common part of the ->read() operation. + * Send the read status command to the device and wait for the wip + * (write-in-progress) bit to clear itself. */ -int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len); +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); + /* * Used for spi_flash write operation * - SPI claim @@ -112,10 +121,22 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, size_t cmd_len, const void *buf, size_t buf_len); /* - * Send the read status command to the device and wait for the wip - * (write-in-progress) bit to clear itself. + * Flash write operation, support all possible write commands. + * Write the requested data out breaking it up into multiple write + * commands as needed per the write size. */ -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); +int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, + size_t len, const void *buf); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Flash read operation, support all possible read commands */ +int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, + size_t len, void *data); -/* Erase sectors. */ -int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len); +#endif /* _SPI_FLASH_INTERNAL_H_ */ diff --git a/drivers/mtd/spi/spi_flash_ops.c b/drivers/mtd/spi/spi_flash_ops.c index b4e1c40fc9..882c8f5f5c 100644 --- a/drivers/mtd/spi/spi_flash_ops.c +++ b/drivers/mtd/spi/spi_flash_ops.c @@ -147,7 +147,7 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, return ret; } -int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) +int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) { u32 erase_size; u8 cmd[4]; @@ -190,7 +190,7 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) return ret; } -int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, +int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, size_t len, const void *buf) { unsigned long byte_addr, page_size; @@ -260,7 +260,7 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, return ret; } -int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, +int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data) { u8 cmd[5], bank_sel = 0; diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c index 1806fd12b5..e9fd013234 100644 --- a/drivers/mtd/spi/spi_flash_probe.c +++ b/drivers/mtd/spi/spi_flash_probe.c @@ -18,7 +18,7 @@ DECLARE_GLOBAL_DATA_PTR; -/* +/** * struct spi_flash_params - SPI/QSPI flash device params structure * * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) @@ -151,7 +151,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { */ }; -struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) +struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) { const struct spi_flash_params *params; struct spi_flash *flash; @@ -190,13 +190,13 @@ struct spi_flash *spi_flash_validate_ids(struct spi_slave *spi, u8 *idcode) flash->name = params->name; /* Assign spi_flash ops */ - flash->write = spi_flash_cmd_write_multi; + flash->write = spi_flash_cmd_write_ops; #ifdef CONFIG_SPI_FLASH_SST if (params->flags & SST_WP) flash->write = sst_write_wp; #endif - flash->erase = spi_flash_cmd_erase; - flash->read = spi_flash_cmd_read_fast; + flash->erase = spi_flash_cmd_erase_ops; + flash->read = spi_flash_cmd_read_ops; /* Compute the flash size */ flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; @@ -314,8 +314,8 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, print_buffer(0, idcode, 1, sizeof(idcode), 0); #endif - /* Validate ID's from flash dev table */ - flash = spi_flash_validate_ids(spi, idcode); + /* Validate params from spi_flash_params table */ + flash = spi_flash_validate_params(spi, idcode); if (!flash) goto err_read_id; diff --git a/include/spi_flash.h b/include/spi_flash.h index a5395161e6..b7cce12ef9 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -1,7 +1,8 @@ /* - * Interface to SPI flash + * Common SPI flash Interface * * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. * * See file CREDITS for list of people who contributed to this * project. @@ -10,6 +11,7 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ + #ifndef _SPI_FLASH_H_ #define _SPI_FLASH_H_ @@ -17,18 +19,6 @@ #include #include -/* SECT flags */ -#define SECT_4K (1 << 1) -#define SECT_32K (1 << 2) -#define E_FSR (1 << 3) - -/* SST specific macros */ -#ifdef CONFIG_SPI_FLASH_SST -# define SST_WP 0x01 /* Supports AAI word program */ -# define CMD_SST_BP 0x02 /* Byte Program */ -# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ -#endif - /** * struct spi_flash - SPI flash structure * -- cgit v1.2.3 From 1b1bd9a7b3d6ac65fc73cd05dc7cb013e453e14b Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Wed, 25 Sep 2013 15:47:36 +0530 Subject: spi: spi cleanups - Rearranged multi-line comment style. - Add tabs. - Add spaces. Signed-off-by: Jagannadha Sutradharudu Teki --- include/spi.h | 87 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/include/spi.h b/include/spi.h index c0dab578bf..c44ebe8874 100644 --- a/include/spi.h +++ b/include/spi.h @@ -29,10 +29,11 @@ #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ /* Header byte that marks the start of the message */ -#define SPI_PREAMBLE_END_BYTE 0xec +#define SPI_PREAMBLE_END_BYTE 0xec -/*----------------------------------------------------------------------- - * Representation of a SPI slave, i.e. what we're communicating with. +/** + * struct spi_slave: Representation of a SPI slave, + * i.e. what we're communicating with. * * Drivers are expected to extend this with controller-specific data. * @@ -42,12 +43,12 @@ * be written at once, excluding command bytes. */ struct spi_slave { - unsigned int bus; - unsigned int cs; + unsigned int bus; + unsigned int cs; unsigned int max_write_size; }; -/*----------------------------------------------------------------------- +/** * Initialization, must be called once on start up. * * TODO: I don't think we really need this. @@ -60,10 +61,10 @@ void spi_init(void); * Allocate and zero all fields in the spi slave, and set the bus/chip * select. Use the helper macro spi_alloc_slave() to call this. * - * @offset: Offset of struct spi_slave within slave structure - * @size: Size of slave structure - * @bus: Bus ID of the slave chip. - * @cs: Chip select ID of the slave chip on the specified bus. + * @offset: Offset of struct spi_slave within slave structure. + * @size: Size of slave structure. + * @bus: Bus ID of the slave chip. + * @cs: Chip select ID of the slave chip on the specified bus. */ void *spi_do_alloc_slave(int offset, int size, unsigned int bus, unsigned int cs); @@ -74,10 +75,10 @@ void *spi_do_alloc_slave(int offset, int size, unsigned int bus, * Allocate and zero all fields in the spi slave, and set the bus/chip * select. * - * @_struct: Name of structure to allocate (e.g. struct tegra_spi). This - * structure must contain a member 'struct spi_slave *slave'. - * @bus: Bus ID of the slave chip. - * @cs: Chip select ID of the slave chip on the specified bus. + * @_struct: Name of structure to allocate (e.g. struct tegra_spi). + * This structure must contain a member 'struct spi_slave *slave'. + * @bus: Bus ID of the slave chip. + * @cs: Chip select ID of the slave chip on the specified bus. */ #define spi_alloc_slave(_struct, bus, cs) \ spi_do_alloc_slave(offsetof(_struct, slave), \ @@ -89,13 +90,13 @@ void *spi_do_alloc_slave(int offset, int size, unsigned int bus, * Allocate and zero all fields in the spi slave, and set the bus/chip * select. * - * @bus: Bus ID of the slave chip. - * @cs: Chip select ID of the slave chip on the specified bus. + * @bus: Bus ID of the slave chip. + * @cs: Chip select ID of the slave chip on the specified bus. */ #define spi_alloc_slave_base(bus, cs) \ spi_do_alloc_slave(0, sizeof(struct spi_slave), bus, cs) -/*----------------------------------------------------------------------- +/** * Set up communications parameters for a SPI slave. * * This must be called once for each slave. Note that this function @@ -103,10 +104,10 @@ void *spi_do_alloc_slave(int offset, int size, unsigned int bus, * contents of spi_slave so that the hardware can be easily * initialized later. * - * bus: Bus ID of the slave chip. - * cs: Chip select ID of the slave chip on the specified bus. - * max_hz: Maximum SCK rate in Hz. - * mode: Clock polarity, clock phase and other parameters. + * @bus: Bus ID of the slave chip. + * @cs: Chip select ID of the slave chip on the specified bus. + * @max_hz: Maximum SCK rate in Hz. + * @mode: Clock polarity, clock phase and other parameters. * * Returns: A spi_slave reference that can be used in subsequent SPI * calls, or NULL if one or more of the parameters are not supported. @@ -114,14 +115,14 @@ void *spi_do_alloc_slave(int offset, int size, unsigned int bus, struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode); -/*----------------------------------------------------------------------- +/** * Free any memory associated with a SPI slave. * - * slave: The SPI slave + * @slave: The SPI slave */ void spi_free_slave(struct spi_slave *slave); -/*----------------------------------------------------------------------- +/** * Claim the bus and prepare it for communication with a given slave. * * This must be called before doing any transfers with a SPI slave. It @@ -130,25 +131,25 @@ void spi_free_slave(struct spi_slave *slave); * allowed to claim the same bus for several slaves without releasing * the bus in between. * - * slave: The SPI slave + * @slave: The SPI slave * * Returns: 0 if the bus was claimed successfully, or a negative value * if it wasn't. */ int spi_claim_bus(struct spi_slave *slave); -/*----------------------------------------------------------------------- +/** * Release the SPI bus * * This must be called once for every call to spi_claim_bus() after * all transfers have finished. It may disable any SPI hardware as * appropriate. * - * slave: The SPI slave + * @slave: The SPI slave */ void spi_release_bus(struct spi_slave *slave); -/*----------------------------------------------------------------------- +/** * SPI transfer * * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks @@ -161,19 +162,19 @@ void spi_release_bus(struct spi_slave *slave); * temporary variables, this is OK). * * spi_xfer() interface: - * slave: The SPI slave which will be sending/receiving the data. - * bitlen: How many bits to write and read. - * dout: Pointer to a string of bits to send out. The bits are + * @slave: The SPI slave which will be sending/receiving the data. + * @bitlen: How many bits to write and read. + * @dout: Pointer to a string of bits to send out. The bits are * held in a byte array and are sent MSB first. - * din: Pointer to a string of bits that will be filled in. - * flags: A bitwise combination of SPI_XFER_* flags. + * @din: Pointer to a string of bits that will be filled in. + * @flags: A bitwise combination of SPI_XFER_* flags. * - * Returns: 0 on success, not 0 on failure + * Returns: 0 on success, not 0 on failure */ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags); -/*----------------------------------------------------------------------- +/** * Determine if a SPI chipselect is valid. * This function is provided by the board if the low-level SPI driver * needs it to determine if a given chipselect is actually valid. @@ -183,7 +184,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, */ int spi_cs_is_valid(unsigned int bus, unsigned int cs); -/*----------------------------------------------------------------------- +/** * Activate a SPI chipselect. * This function is provided by the board code when using a driver * that can't control its chipselects automatically (e.g. @@ -192,7 +193,7 @@ int spi_cs_is_valid(unsigned int bus, unsigned int cs); */ void spi_cs_activate(struct spi_slave *slave); -/*----------------------------------------------------------------------- +/** * Deactivate a SPI chipselect. * This function is provided by the board code when using a driver * that can't control its chipselects automatically (e.g. @@ -201,18 +202,18 @@ void spi_cs_activate(struct spi_slave *slave); */ void spi_cs_deactivate(struct spi_slave *slave); -/*----------------------------------------------------------------------- +/** * Set transfer speed. * This sets a new speed to be applied for next spi_xfer(). - * slave: The SPI slave - * hz: The transfer speed + * @slave: The SPI slave + * @hz: The transfer speed */ void spi_set_speed(struct spi_slave *slave, uint hz); -/*----------------------------------------------------------------------- +/** * Write 8 bits, then read 8 bits. - * slave: The SPI slave we're communicating with - * byte: Byte to be written + * @slave: The SPI slave we're communicating with + * @byte: Byte to be written * * Returns: The value that was read, or a negative value on error. * -- cgit v1.2.3 From 898e76c938eb169fd19733d4e4c44ba26c6dbd87 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Thu, 26 Sep 2013 16:00:15 +0530 Subject: sf: Rename spi_flash files Renamed: spi_flash.c -> sf.c spi_flash_internal.h -> sf_internal.h spi_flash_ops.c -> sf_ops.c spi_flash_probe.c -> sf_probe.c Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/Makefile | 4 +- drivers/mtd/spi/sf.c | 54 +++++ drivers/mtd/spi/sf_internal.h | 142 ++++++++++++ drivers/mtd/spi/sf_ops.c | 403 +++++++++++++++++++++++++++++++++++ drivers/mtd/spi/sf_probe.c | 360 +++++++++++++++++++++++++++++++ drivers/mtd/spi/spi_flash.c | 54 ----- drivers/mtd/spi/spi_flash_internal.h | 142 ------------ drivers/mtd/spi/spi_flash_ops.c | 403 ----------------------------------- drivers/mtd/spi/spi_flash_probe.c | 360 ------------------------------- 9 files changed, 961 insertions(+), 961 deletions(-) create mode 100644 drivers/mtd/spi/sf.c create mode 100644 drivers/mtd/spi/sf_internal.h create mode 100644 drivers/mtd/spi/sf_ops.c create mode 100644 drivers/mtd/spi/sf_probe.c delete mode 100644 drivers/mtd/spi/spi_flash.c delete mode 100644 drivers/mtd/spi/spi_flash_internal.h delete mode 100644 drivers/mtd/spi/spi_flash_ops.c delete mode 100644 drivers/mtd/spi/spi_flash_probe.c diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 0fa867db4c..86ffc59d03 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -15,9 +15,9 @@ COBJS-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o endif ifdef CONFIG_CMD_SF -COBJS-y += spi_flash.o +COBJS-y += sf.o endif -COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe.o spi_flash_ops.o +COBJS-$(CONFIG_SPI_FLASH) += sf_probe.o sf_ops.o COBJS-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o COBJS-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o diff --git a/drivers/mtd/spi/sf.c b/drivers/mtd/spi/sf.c new file mode 100644 index 0000000000..ddbdda0dc2 --- /dev/null +++ b/drivers/mtd/spi/sf.c @@ -0,0 +1,54 @@ +/* + * SPI flash interface + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * + * Licensed under the GPL-2 or later. + */ + +#include +#include + +static int spi_flash_read_write(struct spi_slave *spi, + const u8 *cmd, size_t cmd_len, + const u8 *data_out, u8 *data_in, + size_t data_len) +{ + unsigned long flags = SPI_XFER_BEGIN; + int ret; + + if (data_len == 0) + flags |= SPI_XFER_END; + + ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); + 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); + if (ret) + debug("SF: Failed to transfer %zu bytes of data: %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len); +} + +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +{ + return spi_flash_cmd_read(spi, &cmd, 1, response, len); +} + +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); +} diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h new file mode 100644 index 0000000000..29a14f4df6 --- /dev/null +++ b/drivers/mtd/spi/sf_internal.h @@ -0,0 +1,142 @@ +/* + * SPI flash internal definitions + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _SPI_FLASH_INTERNAL_H_ +#define _SPI_FLASH_INTERNAL_H_ + +#define SPI_FLASH_16MB_BOUN 0x1000000 + +/* SECT flags */ +#define SECT_4K (1 << 1) +#define SECT_32K (1 << 2) +#define E_FSR (1 << 3) + +/* Erase commands */ +#define CMD_ERASE_4K 0x20 +#define CMD_ERASE_32K 0x52 +#define CMD_ERASE_CHIP 0xc7 +#define CMD_ERASE_64K 0xd8 + +/* Write commands */ +#define CMD_WRITE_STATUS 0x01 +#define CMD_PAGE_PROGRAM 0x02 +#define CMD_WRITE_DISABLE 0x04 +#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06 +#define CMD_READ_CONFIG 0x35 +#define CMD_FLAG_STATUS 0x70 + +/* Read commands */ +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ID 0x9f + +/* Bank addr access commands */ +#ifdef CONFIG_SPI_FLASH_BAR +# define CMD_BANKADDR_BRWR 0x17 +# define CMD_BANKADDR_BRRD 0x16 +# define CMD_EXTNADDR_WREAR 0xC5 +# define CMD_EXTNADDR_RDEAR 0xC8 +#endif + +/* Common status */ +#define STATUS_WIP 0x01 +#define STATUS_PEC 0x80 + +/* Flash timeout values */ +#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) + +/* SST specific */ +#ifdef CONFIG_SPI_FLASH_SST +# define SST_WP 0x01 /* Supports AAI word program */ +# define CMD_SST_BP 0x02 /* Byte Program */ +# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ + +int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, + const void *buf); +#endif + +/* Send a single-byte command to the device and read the response */ +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); + +/* + * Send a multi-byte command to the device and read the response. Used + * for flash array reads, etc. + */ +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* + * Send a multi-byte command to the device followed by (optional) + * data. Used for programming the flash array, etc. + */ +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len); + + +/* Flash erase(sectors) operation, support all possible erase commands */ +int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); + +/* Program the status register */ +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); + +/* Set quad enbale bit */ +int spi_flash_set_qeb(struct spi_flash *flash); + +/* Enable writing on the SPI flash */ +static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) +{ + return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); +} + +/* Disable writing on the SPI flash */ +static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) +{ + return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0); +} + +/* + * Send the read status command to the device and wait for the wip + * (write-in-progress) bit to clear itself. + */ +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); + +/* + * Used for spi_flash write operation + * - SPI claim + * - spi_flash_cmd_write_enable + * - spi_flash_cmd_write + * - spi_flash_cmd_wait_ready + * - SPI release + */ +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, const void *buf, size_t buf_len); + +/* + * Flash write operation, support all possible write commands. + * Write the requested data out breaking it up into multiple write + * commands as needed per the write size. + */ +int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, + size_t len, const void *buf); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Flash read operation, support all possible read commands */ +int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +#endif /* _SPI_FLASH_INTERNAL_H_ */ diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c new file mode 100644 index 0000000000..c009af5c20 --- /dev/null +++ b/drivers/mtd/spi/sf_ops.c @@ -0,0 +1,403 @@ +/* + * SPI flash operations + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include + +#include "sf_internal.h" + +static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) +{ + u8 cmd; + int ret; + + cmd = CMD_WRITE_STATUS; + ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); + if (ret < 0) { + debug("SF: fail to write status register\n"); + return ret; + } + + return 0; +} + +#ifdef CONFIG_SPI_FLASH_BAR +static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) +{ + u8 cmd; + int ret; + + if (flash->bank_curr == bank_sel) { + debug("SF: not require to enable bank%d\n", bank_sel); + return 0; + } + + cmd = flash->bank_write_cmd; + ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); + if (ret < 0) { + debug("SF: fail to write bank register\n"); + return ret; + } + flash->bank_curr = bank_sel; + + return 0; +} +#endif + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + u8 check_status = 0x0; + u8 poll_bit = STATUS_WIP; + u8 cmd = flash->poll_cmd; + + if (cmd == CMD_FLAG_STATUS) { + poll_bit = STATUS_PEC; + check_status = poll_bit; + } + + ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); + if (ret) { + debug("SF: fail to read %s status register\n", + cmd == CMD_READ_STATUS ? "read" : "flag"); + return ret; + } + + timebase = get_timer(0); + do { + WATCHDOG_RESET(); + + ret = spi_xfer(spi, 8, NULL, &status, 0); + if (ret) + return -1; + + if ((status & poll_bit) == check_status) + break; + + } while (get_timer(timebase) < timeout); + + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + if ((status & poll_bit) == check_status) + return 0; + + /* Timed out */ + debug("SF: time out!\n"); + return -1; +} + +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, const void *buf, size_t buf_len) +{ + struct spi_slave *spi = flash->spi; + unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; + int ret; + + if (buf == NULL) + timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: unable to claim SPI bus\n"); + return ret; + } + + ret = spi_flash_cmd_write_enable(flash); + if (ret < 0) { + debug("SF: enabling write failed\n"); + return ret; + } + + ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); + if (ret < 0) { + debug("SF: write cmd failed\n"); + return ret; + } + + ret = spi_flash_cmd_wait_ready(flash, timeout); + if (ret < 0) { + debug("SF: write %s timed out\n", + timeout == SPI_FLASH_PROG_TIMEOUT ? + "program" : "page erase"); + return ret; + } + + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) +{ + u32 erase_size; + u8 cmd[4]; + int ret = -1; + + erase_size = flash->erase_size; + if (offset % erase_size || len % erase_size) { + debug("SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + cmd[0] = flash->erase_cmd; + while (len) { +#ifdef CONFIG_SPI_FLASH_BAR + u8 bank_sel; + + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + spi_flash_addr(offset, cmd); + + debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); + if (ret < 0) { + debug("SF: erase failed\n"); + break; + } + + offset += erase_size; + len -= erase_size; + } + + return ret; +} + +int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + unsigned long byte_addr, page_size; + size_t chunk_len, actual; + u8 cmd[4]; + int ret = -1; + + page_size = flash->page_size; + + cmd[0] = CMD_PAGE_PROGRAM; + for (actual = 0; actual < len; actual += chunk_len) { +#ifdef CONFIG_SPI_FLASH_BAR + u8 bank_sel; + + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + byte_addr = offset % page_size; + chunk_len = min(len - actual, page_size - byte_addr); + + if (flash->spi->max_write_size) + chunk_len = min(chunk_len, flash->spi->max_write_size); + + spi_flash_addr(offset, cmd); + + debug("PP: 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); + + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), + buf + actual, chunk_len); + if (ret < 0) { + debug("SF: write failed\n"); + break; + } + + offset += chunk_len; + } + + return ret; +} + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: unable to claim SPI bus\n"); + return ret; + } + + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + if (ret < 0) { + debug("SF: read cmd failed\n"); + return ret; + } + + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + u8 cmd[5], bank_sel = 0; + u32 remain_len, read_len; + int ret = -1; + + /* Handle memory-mapped SPI */ + if (flash->memory_map) { + memcpy(data, flash->memory_map + offset, len); + return 0; + } + + cmd[0] = CMD_READ_ARRAY_FAST; + cmd[4] = 0x00; + + while (len) { +#ifdef CONFIG_SPI_FLASH_BAR + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); + if (len < remain_len) + read_len = len; + else + read_len = remain_len; + + spi_flash_addr(offset, cmd); + + ret = spi_flash_read_common(flash, cmd, sizeof(cmd), + data, read_len); + if (ret < 0) { + debug("SF: read failed\n"); + break; + } + + offset += read_len; + len -= read_len; + data += read_len; + } + + return ret; +} + +#ifdef CONFIG_SPI_FLASH_SST +static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) +{ + int ret; + u8 cmd[4] = { + CMD_SST_BP, + offset >> 16, + offset >> 8, + offset, + }; + + debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset); + + ret = spi_flash_cmd_write_enable(flash); + if (ret) + return ret; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); + if (ret) + return ret; + + return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); +} + +int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, + const void *buf) +{ + size_t actual, cmd_len; + int ret; + u8 cmd[4]; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: Unable to claim SPI bus\n"); + return ret; + } + + /* If the data is not word aligned, write out leading single byte */ + actual = offset % 2; + if (actual) { + ret = sst_byte_write(flash, offset, buf); + if (ret) + goto done; + } + offset += actual; + + ret = spi_flash_cmd_write_enable(flash); + if (ret) + goto done; + + cmd_len = 4; + cmd[0] = CMD_SST_AAI_WP; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + + for (; actual < len - 1; actual += 2) { + debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual, + cmd[0], offset); + + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, + buf + actual, 2); + if (ret) { + debug("SF: sst word program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + cmd_len = 1; + offset += 2; + } + + if (!ret) + ret = spi_flash_cmd_write_disable(flash); + + /* If there is a single trailing byte, write it out */ + if (!ret && actual != len) + ret = sst_byte_write(flash, offset, buf + actual); + + done: + debug("SF: sst: program %s %zu bytes @ 0x%zx\n", + ret ? "failure" : "success", len, offset - actual); + + spi_release_bus(flash->spi); + return ret; +} +#endif diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c new file mode 100644 index 0000000000..8f56c63bf1 --- /dev/null +++ b/drivers/mtd/spi/sf_probe.c @@ -0,0 +1,360 @@ +/* + * SPI flash probing + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include + +#include "sf_internal.h" + +DECLARE_GLOBAL_DATA_PTR; + +/** + * struct spi_flash_params - SPI/QSPI flash device params structure + * + * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) + * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id]) + * @ext_jedec: Device ext_jedec ID + * @sector_size: Sector size of this device + * @nr_sectors: No.of sectors on this device + * @flags: Importent param, for flash specific behaviour + */ +struct spi_flash_params { + const char *name; + u32 jedec; + u16 ext_jedec; + u32 sector_size; + u32 nr_sectors; + u16 flags; +}; + +static const struct spi_flash_params spi_flash_params_table[] = { +#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ + {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, SECT_4K}, + {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, SECT_4K}, + {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, SECT_4K}, + {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, SECT_4K}, + {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, SECT_4K}, + {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, SECT_4K}, + {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, SECT_4K}, +#endif +#ifdef CONFIG_SPI_FLASH_EON /* EON */ + {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, + {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K}, + {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, +#endif +#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ + {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K}, + {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K}, +#endif +#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ + {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, + {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, + {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, + {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, + {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, + {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0}, + {"MX25L51235F", 0xc2201A, 0x0, 64 * 1024, 1024, 0}, + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, +#endif +#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ + {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0}, + {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0}, + {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0}, + {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0}, + {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0}, + {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0}, + {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0}, + {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0}, + {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0}, + {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, 0}, + {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0}, + {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0}, + {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0}, +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ + {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0}, + {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0}, + {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0}, + {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0}, + {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0}, + {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0}, + {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0}, + {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0}, + {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, SECT_4K}, + {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, SECT_4K}, + {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, SECT_4K}, + {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, SECT_4K}, + {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, SECT_4K}, + {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, SECT_4K}, + {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, SECT_4K}, + {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, SECT_4K}, + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, +#endif +#ifdef CONFIG_SPI_FLASH_SST /* SST */ + {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, + {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, + {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WP}, + {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WP}, + {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, SECT_4K}, + {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WP}, + {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WP}, + {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WP}, + {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, + {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, +#endif +#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ + {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0}, + {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0}, + {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0}, + {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, SECT_4K}, + {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, SECT_4K}, + {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, SECT_4K}, + {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, SECT_4K}, + {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, SECT_4K}, + {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, SECT_4K}, + {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, SECT_4K}, + {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, SECT_4K}, + {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, SECT_4K}, + {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, SECT_4K}, + {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, SECT_4K}, +#endif + /* + * Note: + * Below paired flash devices has similar spi_flash_params params. + * (S25FL129P_64K, S25FL128S_64K) + * (W25Q80BL, W25Q80BV) + * (W25Q16CL, W25Q16DV) + * (W25Q32BV, W25Q32FV_SPI) + * (W25Q64CV, W25Q64FV_SPI) + * (W25Q128BV, W25Q128FV_SPI) + * (W25Q32DW, W25Q32FV_QPI) + * (W25Q64DW, W25Q64FV_QPI) + * (W25Q128FW, W25Q128FV_QPI) + */ +}; + +struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) +{ + const struct spi_flash_params *params; + struct spi_flash *flash; + int i; + u16 jedec = idcode[1] << 8 | idcode[2]; + u16 ext_jedec = idcode[3] << 8 | idcode[4]; + + /* Get the flash id (jedec = manuf_id + dev_id, ext_jedec) */ + for (i = 0; i < ARRAY_SIZE(spi_flash_params_table); i++) { + params = &spi_flash_params_table[i]; + if ((params->jedec >> 16) == idcode[0]) { + if ((params->jedec & 0xFFFF) == jedec) { + if (params->ext_jedec == 0) + break; + else if (params->ext_jedec == ext_jedec) + break; + } + } + } + + if (i == ARRAY_SIZE(spi_flash_params_table)) { + printf("SF: Unsupported flash IDs: "); + printf("manuf %02x, jedec %04x, ext_jedec %04x\n", + idcode[0], jedec, ext_jedec); + return NULL; + } + + flash = malloc(sizeof(*flash)); + if (!flash) { + debug("SF: Failed to allocate spi_flash\n"); + return NULL; + } + memset(flash, '\0', sizeof(*flash)); + + flash->spi = spi; + flash->name = params->name; + + /* Assign spi_flash ops */ + flash->write = spi_flash_cmd_write_ops; +#ifdef CONFIG_SPI_FLASH_SST + if (params->flags & SST_WP) + flash->write = sst_write_wp; +#endif + flash->erase = spi_flash_cmd_erase_ops; + flash->read = spi_flash_cmd_read_ops; + + /* Compute the flash size */ + flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; + flash->sector_size = params->sector_size; + flash->size = flash->sector_size * params->nr_sectors; + + /* Compute erase sector and command */ + if (params->flags & SECT_4K) { + flash->erase_cmd = CMD_ERASE_4K; + flash->erase_size = 4096; + } else if (params->flags & SECT_32K) { + flash->erase_cmd = CMD_ERASE_32K; + flash->erase_size = 32768; + } else { + flash->erase_cmd = CMD_ERASE_64K; + flash->erase_size = flash->sector_size; + } + + /* Poll cmd seclection */ + flash->poll_cmd = CMD_READ_STATUS; +#ifdef CONFIG_SPI_FLASH_STMICRO + if (params->flags & E_FSR) + flash->poll_cmd = CMD_FLAG_STATUS; +#endif + +#ifdef CONFIG_SPI_FLASH_BAR + /* Configure the BAR - discover bank cmds and read current bank */ + u8 curr_bank = 0; + if (flash->size > SPI_FLASH_16MB_BOUN) { + flash->bank_read_cmd = (idcode[0] == 0x01) ? + CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR; + flash->bank_write_cmd = (idcode[0] == 0x01) ? + CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR; + + if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1, + &curr_bank, 1)) { + debug("SF: fail to read bank addr register\n"); + return NULL; + } + flash->bank_curr = curr_bank; + } else { + flash->bank_curr = curr_bank; + } +#endif + + /* Flash powers up read-only, so clear BP# bits */ +#if defined(CONFIG_SPI_FLASH_ATMEL) || \ + defined(CONFIG_SPI_FLASH_MACRONIX) || \ + defined(CONFIG_SPI_FLASH_SST) + spi_flash_cmd_write_status(flash, 0); +#endif + + return flash; +} + +#ifdef CONFIG_OF_CONTROL +int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) +{ + fdt_addr_t addr; + fdt_size_t size; + int node; + + /* If there is no node, do nothing */ + node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); + if (node < 0) + return 0; + + addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); + if (addr == FDT_ADDR_T_NONE) { + debug("%s: Cannot decode address\n", __func__); + return 0; + } + + if (flash->size != size) { + debug("%s: Memory map must cover entire device\n", __func__); + return -1; + } + flash->memory_map = (void *)addr; + + return 0; +} +#endif /* CONFIG_OF_CONTROL */ + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + u8 idcode[5]; + int ret; + + /* Setup spi_slave */ + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printf("SF: Failed to set up slave\n"); + return NULL; + } + + /* Claim spi bus */ + ret = spi_claim_bus(spi); + if (ret) { + debug("SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) { + printf("SF: Failed to get idcodes\n"); + goto err_read_id; + } + +#ifdef DEBUG + printf("SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* Validate params from spi_flash_params table */ + flash = spi_flash_validate_params(spi, idcode); + if (!flash) + goto err_read_id; + +#ifdef CONFIG_OF_CONTROL + if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { + debug("SF: FDT decode error\n"); + goto err_read_id; + } +#endif +#ifndef CONFIG_SPL_BUILD + printf("SF: Detected %s with page size ", flash->name); + print_size(flash->page_size, ", erase size "); + print_size(flash->erase_size, ", total "); + print_size(flash->size, ""); + if (flash->memory_map) + printf(", mapped at %p", flash->memory_map); + puts("\n"); +#endif +#ifndef CONFIG_SPI_FLASH_BAR + if (flash->size > SPI_FLASH_16MB_BOUN) { + puts("SF: Warning - Only lower 16MiB accessible,"); + puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); + } +#endif + + /* Release spi bus */ + spi_release_bus(spi); + + return flash; + +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c deleted file mode 100644 index ddbdda0dc2..0000000000 --- a/drivers/mtd/spi/spi_flash.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SPI flash interface - * - * Copyright (C) 2008 Atmel Corporation - * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik - * - * Licensed under the GPL-2 or later. - */ - -#include -#include - -static int spi_flash_read_write(struct spi_slave *spi, - const u8 *cmd, size_t cmd_len, - const u8 *data_out, u8 *data_in, - size_t data_len) -{ - unsigned long flags = SPI_XFER_BEGIN; - int ret; - - if (data_len == 0) - flags |= SPI_XFER_END; - - ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); - 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); - if (ret) - debug("SF: Failed to transfer %zu bytes of data: %d\n", - data_len, ret); - } - - return ret; -} - -int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len) -{ - return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len); -} - -int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) -{ - return spi_flash_cmd_read(spi, &cmd, 1, response, len); -} - -int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, - const void *data, size_t data_len) -{ - return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); -} diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h deleted file mode 100644 index 29a14f4df6..0000000000 --- a/drivers/mtd/spi/spi_flash_internal.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * SPI flash internal definitions - * - * Copyright (C) 2008 Atmel Corporation - * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _SPI_FLASH_INTERNAL_H_ -#define _SPI_FLASH_INTERNAL_H_ - -#define SPI_FLASH_16MB_BOUN 0x1000000 - -/* SECT flags */ -#define SECT_4K (1 << 1) -#define SECT_32K (1 << 2) -#define E_FSR (1 << 3) - -/* Erase commands */ -#define CMD_ERASE_4K 0x20 -#define CMD_ERASE_32K 0x52 -#define CMD_ERASE_CHIP 0xc7 -#define CMD_ERASE_64K 0xd8 - -/* Write commands */ -#define CMD_WRITE_STATUS 0x01 -#define CMD_PAGE_PROGRAM 0x02 -#define CMD_WRITE_DISABLE 0x04 -#define CMD_READ_STATUS 0x05 -#define CMD_WRITE_ENABLE 0x06 -#define CMD_READ_CONFIG 0x35 -#define CMD_FLAG_STATUS 0x70 - -/* Read commands */ -#define CMD_READ_ARRAY_SLOW 0x03 -#define CMD_READ_ARRAY_FAST 0x0b -#define CMD_READ_ID 0x9f - -/* Bank addr access commands */ -#ifdef CONFIG_SPI_FLASH_BAR -# define CMD_BANKADDR_BRWR 0x17 -# define CMD_BANKADDR_BRRD 0x16 -# define CMD_EXTNADDR_WREAR 0xC5 -# define CMD_EXTNADDR_RDEAR 0xC8 -#endif - -/* Common status */ -#define STATUS_WIP 0x01 -#define STATUS_PEC 0x80 - -/* Flash timeout values */ -#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) -#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) -#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) - -/* SST specific */ -#ifdef CONFIG_SPI_FLASH_SST -# define SST_WP 0x01 /* Supports AAI word program */ -# define CMD_SST_BP 0x02 /* Byte Program */ -# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ - -int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, - const void *buf); -#endif - -/* Send a single-byte command to the device and read the response */ -int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); - -/* - * Send a multi-byte command to the device and read the response. Used - * for flash array reads, etc. - */ -int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len); - -/* - * Send a multi-byte command to the device followed by (optional) - * data. Used for programming the flash array, etc. - */ -int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, - const void *data, size_t data_len); - - -/* Flash erase(sectors) operation, support all possible erase commands */ -int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); - -/* Program the status register */ -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); - -/* Set quad enbale bit */ -int spi_flash_set_qeb(struct spi_flash *flash); - -/* Enable writing on the SPI flash */ -static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) -{ - return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); -} - -/* Disable writing on the SPI flash */ -static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) -{ - return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0); -} - -/* - * Send the read status command to the device and wait for the wip - * (write-in-progress) bit to clear itself. - */ -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); - -/* - * Used for spi_flash write operation - * - SPI claim - * - spi_flash_cmd_write_enable - * - spi_flash_cmd_write - * - spi_flash_cmd_wait_ready - * - SPI release - */ -int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, const void *buf, size_t buf_len); - -/* - * Flash write operation, support all possible write commands. - * Write the requested data out breaking it up into multiple write - * commands as needed per the write size. - */ -int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, - size_t len, const void *buf); - -/* - * Same as spi_flash_cmd_read() except it also claims/releases the SPI - * bus. Used as common part of the ->read() operation. - */ -int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len); - -/* Flash read operation, support all possible read commands */ -int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, - size_t len, void *data); - -#endif /* _SPI_FLASH_INTERNAL_H_ */ diff --git a/drivers/mtd/spi/spi_flash_ops.c b/drivers/mtd/spi/spi_flash_ops.c deleted file mode 100644 index 882c8f5f5c..0000000000 --- a/drivers/mtd/spi/spi_flash_ops.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * SPI flash operations - * - * Copyright (C) 2008 Atmel Corporation - * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik - * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include - -#include "spi_flash_internal.h" - -static void spi_flash_addr(u32 addr, u8 *cmd) -{ - /* cmd[0] is actual command */ - cmd[1] = addr >> 16; - cmd[2] = addr >> 8; - cmd[3] = addr >> 0; -} - -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) -{ - u8 cmd; - int ret; - - cmd = CMD_WRITE_STATUS; - ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); - if (ret < 0) { - debug("SF: fail to write status register\n"); - return ret; - } - - return 0; -} - -#ifdef CONFIG_SPI_FLASH_BAR -static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) -{ - u8 cmd; - int ret; - - if (flash->bank_curr == bank_sel) { - debug("SF: not require to enable bank%d\n", bank_sel); - return 0; - } - - cmd = flash->bank_write_cmd; - ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); - if (ret < 0) { - debug("SF: fail to write bank register\n"); - return ret; - } - flash->bank_curr = bank_sel; - - return 0; -} -#endif - -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 status; - u8 check_status = 0x0; - u8 poll_bit = STATUS_WIP; - u8 cmd = flash->poll_cmd; - - if (cmd == CMD_FLAG_STATUS) { - poll_bit = STATUS_PEC; - check_status = poll_bit; - } - - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); - if (ret) { - debug("SF: fail to read %s status register\n", - cmd == CMD_READ_STATUS ? "read" : "flag"); - return ret; - } - - timebase = get_timer(0); - do { - WATCHDOG_RESET(); - - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) - return -1; - - if ((status & poll_bit) == check_status) - break; - - } while (get_timer(timebase) < timeout); - - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if ((status & poll_bit) == check_status) - return 0; - - /* Timed out */ - debug("SF: time out!\n"); - return -1; -} - -int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, const void *buf, size_t buf_len) -{ - struct spi_slave *spi = flash->spi; - unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; - int ret; - - if (buf == NULL) - timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: unable to claim SPI bus\n"); - return ret; - } - - ret = spi_flash_cmd_write_enable(flash); - if (ret < 0) { - debug("SF: enabling write failed\n"); - return ret; - } - - ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); - if (ret < 0) { - debug("SF: write cmd failed\n"); - return ret; - } - - ret = spi_flash_cmd_wait_ready(flash, timeout); - if (ret < 0) { - debug("SF: write %s timed out\n", - timeout == SPI_FLASH_PROG_TIMEOUT ? - "program" : "page erase"); - return ret; - } - - spi_release_bus(spi); - - return ret; -} - -int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) -{ - u32 erase_size; - u8 cmd[4]; - int ret = -1; - - erase_size = flash->erase_size; - if (offset % erase_size || len % erase_size) { - debug("SF: Erase offset/length not multiple of erase size\n"); - return -1; - } - - cmd[0] = flash->erase_cmd; - while (len) { -#ifdef CONFIG_SPI_FLASH_BAR - u8 bank_sel; - - bank_sel = offset / SPI_FLASH_16MB_BOUN; - - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); - if (ret) { - debug("SF: fail to set bank%d\n", bank_sel); - return ret; - } -#endif - spi_flash_addr(offset, cmd); - - debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], - cmd[2], cmd[3], offset); - - ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); - if (ret < 0) { - debug("SF: erase failed\n"); - break; - } - - offset += erase_size; - len -= erase_size; - } - - return ret; -} - -int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, - size_t len, const void *buf) -{ - unsigned long byte_addr, page_size; - size_t chunk_len, actual; - u8 cmd[4]; - int ret = -1; - - page_size = flash->page_size; - - cmd[0] = CMD_PAGE_PROGRAM; - for (actual = 0; actual < len; actual += chunk_len) { -#ifdef CONFIG_SPI_FLASH_BAR - u8 bank_sel; - - bank_sel = offset / SPI_FLASH_16MB_BOUN; - - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); - if (ret) { - debug("SF: fail to set bank%d\n", bank_sel); - return ret; - } -#endif - byte_addr = offset % page_size; - chunk_len = min(len - actual, page_size - byte_addr); - - if (flash->spi->max_write_size) - chunk_len = min(chunk_len, flash->spi->max_write_size); - - spi_flash_addr(offset, cmd); - - debug("PP: 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); - - ret = spi_flash_write_common(flash, cmd, sizeof(cmd), - buf + actual, chunk_len); - if (ret < 0) { - debug("SF: write failed\n"); - break; - } - - offset += chunk_len; - } - - return ret; -} - -int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, - size_t cmd_len, void *data, size_t data_len) -{ - struct spi_slave *spi = flash->spi; - int ret; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: unable to claim SPI bus\n"); - return ret; - } - - ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); - if (ret < 0) { - debug("SF: read cmd failed\n"); - return ret; - } - - spi_release_bus(spi); - - return ret; -} - -int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, - size_t len, void *data) -{ - u8 cmd[5], bank_sel = 0; - u32 remain_len, read_len; - int ret = -1; - - /* Handle memory-mapped SPI */ - if (flash->memory_map) { - memcpy(data, flash->memory_map + offset, len); - return 0; - } - - cmd[0] = CMD_READ_ARRAY_FAST; - cmd[4] = 0x00; - - while (len) { -#ifdef CONFIG_SPI_FLASH_BAR - bank_sel = offset / SPI_FLASH_16MB_BOUN; - - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); - if (ret) { - debug("SF: fail to set bank%d\n", bank_sel); - return ret; - } -#endif - remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); - if (len < remain_len) - read_len = len; - else - read_len = remain_len; - - spi_flash_addr(offset, cmd); - - ret = spi_flash_read_common(flash, cmd, sizeof(cmd), - data, read_len); - if (ret < 0) { - debug("SF: read failed\n"); - break; - } - - offset += read_len; - len -= read_len; - data += read_len; - } - - return ret; -} - -#ifdef CONFIG_SPI_FLASH_SST -static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) -{ - int ret; - u8 cmd[4] = { - CMD_SST_BP, - offset >> 16, - offset >> 8, - offset, - }; - - debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", - spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset); - - ret = spi_flash_cmd_write_enable(flash); - if (ret) - return ret; - - ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); - if (ret) - return ret; - - return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); -} - -int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, - const void *buf) -{ - size_t actual, cmd_len; - int ret; - u8 cmd[4]; - - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); - return ret; - } - - /* If the data is not word aligned, write out leading single byte */ - actual = offset % 2; - if (actual) { - ret = sst_byte_write(flash, offset, buf); - if (ret) - goto done; - } - offset += actual; - - ret = spi_flash_cmd_write_enable(flash); - if (ret) - goto done; - - cmd_len = 4; - cmd[0] = CMD_SST_AAI_WP; - cmd[1] = offset >> 16; - cmd[2] = offset >> 8; - cmd[3] = offset; - - for (; actual < len - 1; actual += 2) { - debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", - spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual, - cmd[0], offset); - - ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, - buf + actual, 2); - if (ret) { - debug("SF: sst word program failed\n"); - break; - } - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret) - break; - - cmd_len = 1; - offset += 2; - } - - if (!ret) - ret = spi_flash_cmd_write_disable(flash); - - /* If there is a single trailing byte, write it out */ - if (!ret && actual != len) - ret = sst_byte_write(flash, offset, buf + actual); - - done: - debug("SF: sst: program %s %zu bytes @ 0x%zx\n", - ret ? "failure" : "success", len, offset - actual); - - spi_release_bus(flash->spi); - return ret; -} -#endif diff --git a/drivers/mtd/spi/spi_flash_probe.c b/drivers/mtd/spi/spi_flash_probe.c deleted file mode 100644 index e9fd013234..0000000000 --- a/drivers/mtd/spi/spi_flash_probe.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * SPI flash probing - * - * Copyright (C) 2008 Atmel Corporation - * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik - * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include - -#include "spi_flash_internal.h" - -DECLARE_GLOBAL_DATA_PTR; - -/** - * struct spi_flash_params - SPI/QSPI flash device params structure - * - * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) - * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id]) - * @ext_jedec: Device ext_jedec ID - * @sector_size: Sector size of this device - * @nr_sectors: No.of sectors on this device - * @flags: Importent param, for flash specific behaviour - */ -struct spi_flash_params { - const char *name; - u32 jedec; - u16 ext_jedec; - u32 sector_size; - u32 nr_sectors; - u16 flags; -}; - -static const struct spi_flash_params spi_flash_params_table[] = { -#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ - {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, SECT_4K}, - {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, SECT_4K}, - {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, SECT_4K}, - {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, SECT_4K}, - {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, SECT_4K}, - {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, SECT_4K}, - {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, SECT_4K}, -#endif -#ifdef CONFIG_SPI_FLASH_EON /* EON */ - {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, - {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K}, - {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, -#endif -#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ - {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K}, - {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K}, -#endif -#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ - {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, - {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, - {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, - {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, - {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, - {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, - {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0}, - {"MX25L51235F", 0xc2201A, 0x0, 64 * 1024, 1024, 0}, - {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, -#endif -#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ - {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0}, - {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0}, - {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0}, - {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0}, - {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0}, - {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0}, - {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0}, - {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0}, - {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0}, - {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, 0}, - {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0}, - {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0}, - {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0}, -#endif -#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ - {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0}, - {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0}, - {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0}, - {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0}, - {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0}, - {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0}, - {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0}, - {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0}, - {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, SECT_4K}, - {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, SECT_4K}, - {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, SECT_4K}, - {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, SECT_4K}, - {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, SECT_4K}, - {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, SECT_4K}, - {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, SECT_4K}, - {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, SECT_4K}, - {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, - {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, - {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, - {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, -#endif -#ifdef CONFIG_SPI_FLASH_SST /* SST */ - {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, - {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, - {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WP}, - {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WP}, - {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, SECT_4K}, - {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WP}, - {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WP}, - {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WP}, - {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, - {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, -#endif -#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ - {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0}, - {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0}, - {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0}, - {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, SECT_4K}, - {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, SECT_4K}, - {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, SECT_4K}, - {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, SECT_4K}, - {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, SECT_4K}, - {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, SECT_4K}, - {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, SECT_4K}, - {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, SECT_4K}, - {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, SECT_4K}, - {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, SECT_4K}, - {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, SECT_4K}, - {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, SECT_4K}, - {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, SECT_4K}, - {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, SECT_4K}, - {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, SECT_4K}, -#endif - /* - * Note: - * Below paired flash devices has similar spi_flash_params params. - * (S25FL129P_64K, S25FL128S_64K) - * (W25Q80BL, W25Q80BV) - * (W25Q16CL, W25Q16DV) - * (W25Q32BV, W25Q32FV_SPI) - * (W25Q64CV, W25Q64FV_SPI) - * (W25Q128BV, W25Q128FV_SPI) - * (W25Q32DW, W25Q32FV_QPI) - * (W25Q64DW, W25Q64FV_QPI) - * (W25Q128FW, W25Q128FV_QPI) - */ -}; - -struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) -{ - const struct spi_flash_params *params; - struct spi_flash *flash; - int i; - u16 jedec = idcode[1] << 8 | idcode[2]; - u16 ext_jedec = idcode[3] << 8 | idcode[4]; - - /* Get the flash id (jedec = manuf_id + dev_id, ext_jedec) */ - for (i = 0; i < ARRAY_SIZE(spi_flash_params_table); i++) { - params = &spi_flash_params_table[i]; - if ((params->jedec >> 16) == idcode[0]) { - if ((params->jedec & 0xFFFF) == jedec) { - if (params->ext_jedec == 0) - break; - else if (params->ext_jedec == ext_jedec) - break; - } - } - } - - if (i == ARRAY_SIZE(spi_flash_params_table)) { - printf("SF: Unsupported flash IDs: "); - printf("manuf %02x, jedec %04x, ext_jedec %04x\n", - idcode[0], jedec, ext_jedec); - return NULL; - } - - flash = malloc(sizeof(*flash)); - if (!flash) { - debug("SF: Failed to allocate spi_flash\n"); - return NULL; - } - memset(flash, '\0', sizeof(*flash)); - - flash->spi = spi; - flash->name = params->name; - - /* Assign spi_flash ops */ - flash->write = spi_flash_cmd_write_ops; -#ifdef CONFIG_SPI_FLASH_SST - if (params->flags & SST_WP) - flash->write = sst_write_wp; -#endif - flash->erase = spi_flash_cmd_erase_ops; - flash->read = spi_flash_cmd_read_ops; - - /* Compute the flash size */ - flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; - flash->sector_size = params->sector_size; - flash->size = flash->sector_size * params->nr_sectors; - - /* Compute erase sector and command */ - if (params->flags & SECT_4K) { - flash->erase_cmd = CMD_ERASE_4K; - flash->erase_size = 4096; - } else if (params->flags & SECT_32K) { - flash->erase_cmd = CMD_ERASE_32K; - flash->erase_size = 32768; - } else { - flash->erase_cmd = CMD_ERASE_64K; - flash->erase_size = flash->sector_size; - } - - /* Poll cmd seclection */ - flash->poll_cmd = CMD_READ_STATUS; -#ifdef CONFIG_SPI_FLASH_STMICRO - if (params->flags & E_FSR) - flash->poll_cmd = CMD_FLAG_STATUS; -#endif - -#ifdef CONFIG_SPI_FLASH_BAR - /* Configure the BAR - discover bank cmds and read current bank */ - u8 curr_bank = 0; - if (flash->size > SPI_FLASH_16MB_BOUN) { - flash->bank_read_cmd = (idcode[0] == 0x01) ? - CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR; - flash->bank_write_cmd = (idcode[0] == 0x01) ? - CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR; - - if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1, - &curr_bank, 1)) { - debug("SF: fail to read bank addr register\n"); - return NULL; - } - flash->bank_curr = curr_bank; - } else { - flash->bank_curr = curr_bank; - } -#endif - - /* Flash powers up read-only, so clear BP# bits */ -#if defined(CONFIG_SPI_FLASH_ATMEL) || \ - defined(CONFIG_SPI_FLASH_MACRONIX) || \ - defined(CONFIG_SPI_FLASH_SST) - spi_flash_cmd_write_status(flash, 0); -#endif - - return flash; -} - -#ifdef CONFIG_OF_CONTROL -int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) -{ - fdt_addr_t addr; - fdt_size_t size; - int node; - - /* If there is no node, do nothing */ - node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); - if (node < 0) - return 0; - - addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); - if (addr == FDT_ADDR_T_NONE) { - debug("%s: Cannot decode address\n", __func__); - return 0; - } - - if (flash->size != size) { - debug("%s: Memory map must cover entire device\n", __func__); - return -1; - } - flash->memory_map = (void *)addr; - - return 0; -} -#endif /* CONFIG_OF_CONTROL */ - -struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int spi_mode) -{ - struct spi_slave *spi; - struct spi_flash *flash = NULL; - u8 idcode[5]; - int ret; - - /* Setup spi_slave */ - spi = spi_setup_slave(bus, cs, max_hz, spi_mode); - if (!spi) { - printf("SF: Failed to set up slave\n"); - return NULL; - } - - /* Claim spi bus */ - ret = spi_claim_bus(spi); - if (ret) { - debug("SF: Failed to claim SPI bus: %d\n", ret); - goto err_claim_bus; - } - - /* Read the ID codes */ - ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); - if (ret) { - printf("SF: Failed to get idcodes\n"); - goto err_read_id; - } - -#ifdef DEBUG - printf("SF: Got idcodes\n"); - print_buffer(0, idcode, 1, sizeof(idcode), 0); -#endif - - /* Validate params from spi_flash_params table */ - flash = spi_flash_validate_params(spi, idcode); - if (!flash) - goto err_read_id; - -#ifdef CONFIG_OF_CONTROL - if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { - debug("SF: FDT decode error\n"); - goto err_read_id; - } -#endif -#ifndef CONFIG_SPL_BUILD - printf("SF: Detected %s with page size ", flash->name); - print_size(flash->page_size, ", erase size "); - print_size(flash->erase_size, ", total "); - print_size(flash->size, ""); - if (flash->memory_map) - printf(", mapped at %p", flash->memory_map); - puts("\n"); -#endif -#ifndef CONFIG_SPI_FLASH_BAR - if (flash->size > SPI_FLASH_16MB_BOUN) { - puts("SF: Warning - Only lower 16MiB accessible,"); - puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); - } -#endif - - /* Release spi bus */ - spi_release_bus(spi); - - return flash; - -err_read_id: - spi_release_bus(spi); -err_claim_bus: - spi_free_slave(spi); - return NULL; -} - -void spi_flash_free(struct spi_flash *flash) -{ - spi_free_slave(flash->spi); - free(flash); -} -- cgit v1.2.3 From 364995499c14461c59bc16031b2a8f618f520b32 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Thu, 26 Sep 2013 15:55:52 +0530 Subject: doc: SPI: Add status.txt for tracking SPI subsys status doc/SPI/status.txt added to track the u-boot SPI subsystem status. Signed-off-by: Jagannadha Sutradharudu Teki --- doc/SPI/status.txt | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 doc/SPI/status.txt diff --git a/doc/SPI/status.txt b/doc/SPI/status.txt new file mode 100644 index 0000000000..6050e4ac0d --- /dev/null +++ b/doc/SPI/status.txt @@ -0,0 +1,28 @@ +Status on SPI subsystem: +======================= + +SPI COMMAND (common/cmd_sf, cmd_spi): +- + +SPI FLASH (drivers/mtd/spi): +- sf_probe.c: SPI flash probing code. +- sf_ops.c: SPI flash operations code. +- sf.c: SPI flash interface, which interacts controller driver. +- Bank Address Register (Accessing flashes > 16Mbytes in 3-byte addressing) +- Common probe support for all supported flash vendors except, ramtron. + +SPI DRIVERS (drivers/spi): +- + +TODO: +- Runtime detection of spi_flash params(if possible) +- Extended read commands support(dual read, dual IO read) +- Quad Page Program support. +- Quad Read support(quad fast read, quad IO read) +- Dual flash connection topology support(accessing two spi flash memories with single cs) +- Banking support on dual flash connection topology. +- Need proper cleanups on spi_flash and drivers. + +-- +Jagannadha Sutradharudu Teki +18-09-2013. -- cgit v1.2.3 From 0ab449beec5287ca600eca8c9bc7fe052af99162 Mon Sep 17 00:00:00 2001 From: Priyanka Jain Date: Thu, 3 Oct 2013 21:07:00 +0530 Subject: sf: probe: Add support for EN25S64 Add support for EON EN25S64 SPI flash. Signed-off-by: Priyanka Jain Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 8f56c63bf1..15256369e0 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -51,6 +51,7 @@ static const struct spi_flash_params spi_flash_params_table[] = { {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K}, {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, + {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0}, #endif #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K}, -- cgit v1.2.3 From c97a9b3275997b09729aaf11bd8ace08478447a2 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Mon, 7 Oct 2013 15:52:59 +0530 Subject: omap5: add qspi support Add QSPI definitions and clock configuration support. Signed-off-by: Matt Porter Signed-off-by: Sourav Poddar Reviewed-by: Jagannadha Sutradharudu Teki --- arch/arm/cpu/armv7/omap5/hw_data.c | 8 ++++++++ arch/arm/cpu/armv7/omap5/prcm-regs.c | 1 + arch/arm/include/asm/arch-omap5/omap.h | 3 +++ arch/arm/include/asm/arch-omap5/spl.h | 1 + arch/arm/include/asm/omap_common.h | 1 + 5 files changed, 14 insertions(+) diff --git a/arch/arm/cpu/armv7/omap5/hw_data.c b/arch/arm/cpu/armv7/omap5/hw_data.c index fbbc486621..c00bfb8d30 100644 --- a/arch/arm/cpu/armv7/omap5/hw_data.c +++ b/arch/arm/cpu/armv7/omap5/hw_data.c @@ -426,6 +426,10 @@ void enable_basic_clocks(void) #ifdef CONFIG_DRIVER_TI_CPSW (*prcm)->cm_gmac_gmac_clkctrl, #endif + +#ifdef CONFIG_TI_QSPI + (*prcm)->cm_l4per_qspi_clkctrl, +#endif 0 }; @@ -454,6 +458,10 @@ void enable_basic_clocks(void) clk_modules_explicit_en_essential, 1); +#ifdef CONFIG_TI_QSPI + setbits_le32((*prcm)->cm_l4per_qspi_clkctrl, (1<<24)); +#endif + /* Enable SCRM OPT clocks for PER and CORE dpll */ setbits_le32((*prcm)->cm_wkupaon_scrm_clkctrl, OPTFCLKEN_SCRM_PER_MASK); diff --git a/arch/arm/cpu/armv7/omap5/prcm-regs.c b/arch/arm/cpu/armv7/omap5/prcm-regs.c index 5a3d52c11a..7a7caded03 100644 --- a/arch/arm/cpu/armv7/omap5/prcm-regs.c +++ b/arch/arm/cpu/armv7/omap5/prcm-regs.c @@ -921,6 +921,7 @@ struct prcm_regs const dra7xx_prcm = { .cm_l4per_gpio8_clkctrl = 0x4a009818, .cm_l4per_mmcsd3_clkctrl = 0x4a009820, .cm_l4per_mmcsd4_clkctrl = 0x4a009828, + .cm_l4per_qspi_clkctrl = 0x4a009838, .cm_l4per_uart1_clkctrl = 0x4a009840, .cm_l4per_uart2_clkctrl = 0x4a009848, .cm_l4per_uart3_clkctrl = 0x4a009850, diff --git a/arch/arm/include/asm/arch-omap5/omap.h b/arch/arm/include/asm/arch-omap5/omap.h index e9a51d3403..414d37a5a7 100644 --- a/arch/arm/include/asm/arch-omap5/omap.h +++ b/arch/arm/include/asm/arch-omap5/omap.h @@ -61,6 +61,9 @@ /* GPMC */ #define OMAP54XX_GPMC_BASE 0x50000000 +/* QSPI */ +#define QSPI_BASE 0x4B300000 + /* * Hardware Register Details */ diff --git a/arch/arm/include/asm/arch-omap5/spl.h b/arch/arm/include/asm/arch-omap5/spl.h index fe8b0c01ad..57f0de5ffe 100644 --- a/arch/arm/include/asm/arch-omap5/spl.h +++ b/arch/arm/include/asm/arch-omap5/spl.h @@ -15,6 +15,7 @@ #define BOOT_DEVICE_MMC1 5 #define BOOT_DEVICE_MMC2 6 #define BOOT_DEVICE_MMC2_2 7 +#define BOOT_DEVICE_SPI 10 #define MMC_BOOT_DEVICES_START BOOT_DEVICE_MMC1 #define MMC_BOOT_DEVICES_END BOOT_DEVICE_MMC2_2 diff --git a/arch/arm/include/asm/omap_common.h b/arch/arm/include/asm/omap_common.h index 61fee9f06d..3a998cc10c 100644 --- a/arch/arm/include/asm/omap_common.h +++ b/arch/arm/include/asm/omap_common.h @@ -266,6 +266,7 @@ struct prcm_regs { u32 cm_l4per_mmcsd4_clkctrl; u32 cm_l4per_msprohg_clkctrl; u32 cm_l4per_slimbus2_clkctrl; + u32 cm_l4per_qspi_clkctrl; u32 cm_l4per_uart1_clkctrl; u32 cm_l4per_uart2_clkctrl; u32 cm_l4per_uart3_clkctrl; -- cgit v1.2.3 From 62d206dc3126914f187cfb72e8a7c6cf84c19b7c Mon Sep 17 00:00:00 2001 From: "Poddar, Sourav" Date: Mon, 7 Oct 2013 15:53:00 +0530 Subject: armv7: hw_data: change clock divider setting. Clock requirement for qspi clk is 192 Mhz. According to the below formulae, f dpll = f ref * 2 * m /(n + 1) clockoutx2_Hmn = f dpll / (hmn+ 1) fref = 20 Mhz, m = 96, n = 4 gives f dpll = 768 Mhz For clockoutx2_Hmn to be 768, hmn + 1 should be 4. Signed-off-by: Sourav Poddar Reviewed-by: Jagannadha Sutradharudu Teki --- arch/arm/cpu/armv7/omap5/hw_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv7/omap5/hw_data.c b/arch/arm/cpu/armv7/omap5/hw_data.c index c00bfb8d30..a1b249e734 100644 --- a/arch/arm/cpu/armv7/omap5/hw_data.c +++ b/arch/arm/cpu/armv7/omap5/hw_data.c @@ -170,7 +170,7 @@ static const struct dpll_params per_dpll_params_768mhz_es2[NUM_SYS_CLKS] = { static const struct dpll_params per_dpll_params_768mhz_dra7xx[NUM_SYS_CLKS] = { {32, 0, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 12 MHz */ - {96, 4, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 20 MHz */ + {96, 4, 4, 1, 3, 4, 4, 2, -1, -1, -1, -1}, /* 20 MHz */ {160, 6, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 16.8 MHz */ {20, 0, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 19.2 MHz */ {192, 12, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1}, /* 26 MHz */ -- cgit v1.2.3 From 004f15b6000e220b74433b190e60805ce8776d92 Mon Sep 17 00:00:00 2001 From: "Poddar, Sourav" Date: Mon, 7 Oct 2013 15:53:01 +0530 Subject: sf: Add memory mapped read support Qspi controller can have a memory mapped port which can be used for data read. Added support to enable memory mapped port read. This patch enables the following: - It enables exchange of memory map address between mtd and qspi through the introduction of "memory_map" flag. - Add support to communicate to the driver that memory mapped transfer is to be started through introduction of new flags like "SPI_XFER_MEM_MAP" and "SPI_XFER_MEM_MAP_END". This will enable the spi controller to do memory mapped configurations if required. Signed-off-by: Sourav Poddar Reviewed-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/sf_ops.c | 2 ++ drivers/mtd/spi/sf_probe.c | 1 + include/spi.h | 3 +++ 3 files changed, 6 insertions(+) diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index c009af5c20..2396e2272f 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -269,7 +269,9 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, /* Handle memory-mapped SPI */ if (flash->memory_map) { + spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP); memcpy(data, flash->memory_map + offset, len); + spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END); return 0; } diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 15256369e0..6aa7086c41 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -203,6 +203,7 @@ struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; flash->sector_size = params->sector_size; flash->size = flash->sector_size * params->nr_sectors; + flash->memory_map = spi->memory_map; /* Compute erase sector and command */ if (params->flags & SECT_4K) { diff --git a/include/spi.h b/include/spi.h index c44ebe8874..c2086fc62e 100644 --- a/include/spi.h +++ b/include/spi.h @@ -27,6 +27,8 @@ /* SPI transfer flags */ #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ +#define SPI_XFER_MMAP 0x08 /* Memory Mapped start */ +#define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ /* Header byte that marks the start of the message */ #define SPI_PREAMBLE_END_BYTE 0xec @@ -46,6 +48,7 @@ struct spi_slave { unsigned int bus; unsigned int cs; unsigned int max_write_size; + void *memory_map; }; /** -- cgit v1.2.3 From 1d0933eaf976ba4f3ca00356f7124b1d12ddf168 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Mon, 7 Oct 2013 15:53:02 +0530 Subject: spi: add TI QSPI driver Adds a SPI master driver for the TI QSPI peripheral. - Added quad read support. - Added memory mapped support. Signed-off-by: Matt Porter Signed-off-by: Sourav Poddar Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/spi/Makefile | 1 + drivers/spi/ti_qspi.c | 311 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 312 insertions(+) create mode 100644 drivers/spi/ti_qspi.c diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 91d24cea58..e5941b09f6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -38,6 +38,7 @@ COBJS-$(CONFIG_FDT_SPI) += fdt_spi.o COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o COBJS-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o COBJS-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o +COBJS-$(CONFIG_TI_QSPI) += ti_qspi.o COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o COBJS-$(CONFIG_ZYNQ_SPI) += zynq_spi.o diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c new file mode 100644 index 0000000000..5a5b482769 --- /dev/null +++ b/drivers/spi/ti_qspi.c @@ -0,0 +1,311 @@ +/* + * TI QSPI driver + * + * Copyright (C) 2013, Texas Instruments, Incorporated + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +/* ti qpsi register bit masks */ +#define QSPI_TIMEOUT 2000000 +#define QSPI_FCLK 192000000 +/* clock control */ +#define QSPI_CLK_EN (1 << 31) +#define QSPI_CLK_DIV_MAX 0xffff +/* command */ +#define QSPI_EN_CS(n) (n << 28) +#define QSPI_WLEN(n) ((n-1) << 19) +#define QSPI_3_PIN (1 << 18) +#define QSPI_RD_SNGL (1 << 16) +#define QSPI_WR_SNGL (2 << 16) +#define QSPI_INVAL (4 << 16) +#define QSPI_RD_QUAD (7 << 16) +/* device control */ +#define QSPI_DD(m, n) (m << (3 + n*8)) +#define QSPI_CKPHA(n) (1 << (2 + n*8)) +#define QSPI_CSPOL(n) (1 << (1 + n*8)) +#define QSPI_CKPOL(n) (1 << (n*8)) +/* status */ +#define QSPI_WC (1 << 1) +#define QSPI_BUSY (1 << 0) +#define QSPI_WC_BUSY (QSPI_WC | QSPI_BUSY) +#define QSPI_XFER_DONE QSPI_WC +#define MM_SWITCH 0x01 +#define MEM_CS 0x100 +#define MEM_CS_UNSELECT 0xfffff0ff +#define MMAP_START_ADDR 0x5c000000 +#define CORE_CTRL_IO 0x4a002558 + +#define QSPI_CMD_READ (0x3 << 0) +#define QSPI_CMD_READ_QUAD (0x6b << 0) +#define QSPI_CMD_READ_FAST (0x0b << 0) +#define QSPI_SETUP0_NUM_A_BYTES (0x2 << 8) +#define QSPI_SETUP0_NUM_D_BYTES_NO_BITS (0x0 << 10) +#define QSPI_SETUP0_NUM_D_BYTES_8_BITS (0x1 << 10) +#define QSPI_SETUP0_READ_NORMAL (0x0 << 12) +#define QSPI_SETUP0_READ_QUAD (0x3 << 12) +#define QSPI_CMD_WRITE (0x2 << 16) +#define QSPI_NUM_DUMMY_BITS (0x0 << 24) + +/* ti qspi register set */ +struct ti_qspi_regs { + u32 pid; + u32 pad0[3]; + u32 sysconfig; + u32 pad1[3]; + u32 int_stat_raw; + u32 int_stat_en; + u32 int_en_set; + u32 int_en_ctlr; + u32 intc_eoi; + u32 pad2[3]; + u32 clk_ctrl; + u32 dc; + u32 cmd; + u32 status; + u32 data; + u32 setup0; + u32 setup1; + u32 setup2; + u32 setup3; + u32 memswitch; + u32 data1; + u32 data2; + u32 data3; +}; + +/* ti qspi slave */ +struct ti_qspi_slave { + struct spi_slave slave; + struct ti_qspi_regs *base; + unsigned int mode; + u32 cmd; + u32 dc; +}; + +static inline struct ti_qspi_slave *to_ti_qspi_slave(struct spi_slave *slave) +{ + return container_of(slave, struct ti_qspi_slave, slave); +} + +static void ti_spi_setup_spi_register(struct ti_qspi_slave *qslave) +{ + struct spi_slave *slave = &qslave->slave; + u32 memval = 0; + + slave->memory_map = (void *)MMAP_START_ADDR; + + memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES | + QSPI_SETUP0_NUM_D_BYTES_NO_BITS | + QSPI_SETUP0_READ_NORMAL | QSPI_CMD_WRITE | + QSPI_NUM_DUMMY_BITS; + + writel(memval, &qslave->base->setup0); +} + +static void ti_spi_set_speed(struct spi_slave *slave, uint hz) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + uint clk_div; + + debug("ti_spi_set_speed: hz: %d, clock divider %d\n", hz, clk_div); + + if (!hz) + clk_div = 0; + else + clk_div = (QSPI_FCLK / hz) - 1; + + /* disable SCLK */ + writel(readl(&qslave->base->clk_ctrl) & ~QSPI_CLK_EN, + &qslave->base->clk_ctrl); + + /* assign clk_div values */ + if (clk_div < 0) + clk_div = 0; + else if (clk_div > QSPI_CLK_DIV_MAX) + clk_div = QSPI_CLK_DIV_MAX; + + /* enable SCLK */ + writel(QSPI_CLK_EN | clk_div, &qslave->base->clk_ctrl); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return 1; +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* CS handled in xfer */ + return; +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + + debug("spi_cs_deactivate: 0x%08x\n", (u32)slave); + + writel(qslave->cmd | QSPI_INVAL, &qslave->base->cmd); +} + +void spi_init(void) +{ + /* nothing to do */ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct ti_qspi_slave *qslave; + + qslave = spi_alloc_slave(struct ti_qspi_slave, bus, cs); + if (!qslave) { + printf("SPI_error: Fail to allocate ti_qspi_slave\n"); + return NULL; + } + + qslave->base = (struct ti_qspi_regs *)QSPI_BASE; + qslave->mode = mode; + + ti_spi_set_speed(&qslave->slave, max_hz); + +#ifdef CONFIG_TI_SPI_MMAP + ti_spi_setup_spi_register(qslave); +#endif + + return &qslave->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + free(qslave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + + debug("spi_claim_bus: bus:%i cs:%i\n", slave->bus, slave->cs); + + qslave->dc = 0; + if (qslave->mode & SPI_CPHA) + qslave->dc |= QSPI_CKPHA(slave->cs); + if (qslave->mode & SPI_CPOL) + qslave->dc |= QSPI_CKPOL(slave->cs); + if (qslave->mode & SPI_CS_HIGH) + qslave->dc |= QSPI_CSPOL(slave->cs); + + writel(qslave->dc, &qslave->base->dc); + writel(0, &qslave->base->cmd); + writel(0, &qslave->base->data); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + + debug("spi_release_bus: bus:%i cs:%i\n", slave->bus, slave->cs); + + writel(0, &qslave->base->dc); + writel(0, &qslave->base->cmd); + writel(0, &qslave->base->data); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct ti_qspi_slave *qslave = to_ti_qspi_slave(slave); + uint words = bitlen >> 3; /* fixed 8-bit word length */ + const uchar *txp = dout; + uchar *rxp = din; + uint status; + int timeout, val; + + debug("spi_xfer: bus:%i cs:%i bitlen:%i words:%i flags:%lx\n", + slave->bus, slave->cs, bitlen, words, flags); + + /* Setup mmap flags */ + if (flags & SPI_XFER_MMAP) { + writel(MM_SWITCH, &qslave->base->memswitch); + val = readl(CORE_CTRL_IO); + val |= MEM_CS; + writel(val, CORE_CTRL_IO); + return 0; + } else if (flags & SPI_XFER_MMAP_END) { + writel(~MM_SWITCH, &qslave->base->memswitch); + val = readl(CORE_CTRL_IO); + val &= MEM_CS_UNSELECT; + writel(val, CORE_CTRL_IO); + return 0; + } + + if (bitlen == 0) + return -1; + + if (bitlen % 8) { + debug("spi_xfer: Non byte aligned SPI transfer\n"); + return -1; + } + + /* Setup command reg */ + qslave->cmd = 0; + qslave->cmd |= QSPI_WLEN(8); + qslave->cmd |= QSPI_EN_CS(slave->cs); + if (flags & SPI_3WIRE) + qslave->cmd |= QSPI_3_PIN; + qslave->cmd |= 0xfff; + + while (words--) { + if (txp) { + debug("tx cmd %08x dc %08x data %02x\n", + qslave->cmd | QSPI_WR_SNGL, qslave->dc, *txp); + writel(*txp++, &qslave->base->data); + writel(qslave->cmd | QSPI_WR_SNGL, + &qslave->base->cmd); + status = readl(&qslave->base->status); + timeout = QSPI_TIMEOUT; + while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) { + if (--timeout < 0) { + printf("spi_xfer: TX timeout!\n"); + return -1; + } + status = readl(&qslave->base->status); + } + debug("tx done, status %08x\n", status); + } + if (rxp) { + qslave->cmd |= QSPI_RD_SNGL; + debug("rx cmd %08x dc %08x\n", + qslave->cmd, qslave->dc); + writel(qslave->cmd, &qslave->base->cmd); + status = readl(&qslave->base->status); + timeout = QSPI_TIMEOUT; + while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) { + if (--timeout < 0) { + printf("spi_xfer: RX timeout!\n"); + return -1; + } + status = readl(&qslave->base->status); + } + *rxp++ = readl(&qslave->base->data); + debug("rx done, status %08x, read %02x\n", + status, *(rxp-1)); + } + } + + /* Terminate frame */ + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + return 0; +} -- cgit v1.2.3 From 247cdf041351329cce2e24ab1080a83db4f3d254 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Mon, 7 Oct 2013 15:53:03 +0530 Subject: dra7xx_evm: add SPL API, QSPI, and serial flash support Enables support for SPI SPL, QSPI and Spansion serial flash device on the EVM. Configures pin muxes for QSPI mode. Signed-off-by: Matt Porter Signed-off-by: Sourav Poddar Reviewed-by: Jagannadha Sutradharudu Teki --- board/ti/dra7xx/mux_data.h | 10 ++++++++++ include/configs/dra7xx_evm.h | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/board/ti/dra7xx/mux_data.h b/board/ti/dra7xx/mux_data.h index 0a86594c6b..6965cc57d2 100644 --- a/board/ti/dra7xx/mux_data.h +++ b/board/ti/dra7xx/mux_data.h @@ -51,5 +51,15 @@ const struct pad_conf_entry core_padconf_array_essential[] = { {RGMII0_RXD2, (IEN | M0) }, {RGMII0_RXD1, (IEN | M0) }, {RGMII0_RXD0, (IEN | M0) }, + {GPMC_A13, (IEN | PDIS | M1)}, /* QSPI1_RTCLK */ + {GPMC_A14, (IEN | PDIS | M1)}, /* QSPI1_D[3] */ + {GPMC_A15, (IEN | PDIS | M1)}, /* QSPI1_D[2] */ + {GPMC_A16, (IEN | PDIS | M1)}, /* QSPI1_D[1] */ + {GPMC_A17, (IEN | PDIS | M1)}, /* QSPI1_D[0] */ + {GPMC_A18, (M1)}, /* QSPI1_SCLK */ + {GPMC_A3, (IEN | PDIS | M1)}, /* QSPI1_CS2 */ + {GPMC_A4, (IEN | PDIS | M1)}, /* QSPI1_CS3 */ + {GPMC_CS2, (IEN | PTU | PDIS | M1)}, /* QSPI1_CS0 */ + {GPMC_CS3, (IEN | PTU | PDIS | M1)}, /* QSPI1_CS1*/ }; #endif /* _MUX_DATA_DRA7XX_H_ */ diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h index 7b120de213..51e0e801a2 100644 --- a/include/configs/dra7xx_evm.h +++ b/include/configs/dra7xx_evm.h @@ -48,4 +48,23 @@ #define CONFIG_PHYLIB #define CONFIG_PHY_ADDR 2 +/* SPI */ +#undef CONFIG_OMAP3_SPI +#define CONFIG_TI_QSPI +#define CONFIG_SPI_FLASH +#define CONFIG_SPI_FLASH_SPANSION +#define CONFIG_CMD_SF +#define CONFIG_CMD_SPI +#define CONFIG_TI_SPI_MMAP +#define CONFIG_SF_DEFAULT_SPEED 48000000 +#define CONFIG_DEFAULT_SPI_MODE SPI_MODE_3 + +/* SPI SPL */ +#define CONFIG_SPL_SPI_SUPPORT +#define CONFIG_SPL_SPI_LOAD +#define CONFIG_SPL_SPI_FLASH_SUPPORT +#define CONFIG_SPL_SPI_BUS 0 +#define CONFIG_SPL_SPI_CS 0 +#define CONFIG_SYS_SPI_U_BOOT_OFFS 0x20000 + #endif /* __CONFIG_DRA7XX_EVM_H */ -- cgit v1.2.3 From 2f24223ae150d9496694885cee401f4525b72acb Mon Sep 17 00:00:00 2001 From: "Poddar, Sourav" Date: Mon, 7 Oct 2013 15:53:04 +0530 Subject: README: qspi usecase and testing documentation. Contains documentation and testing details for qspi flash interface. Signed-off-by: Sourav Poddar Reviewed-by: Jagannadha Sutradharudu Teki --- doc/SPI/README.ti_qspi_dra_test | 48 +++++++++++++++++++++++++++++++++++++++++ doc/SPI/README.ti_qspi_flash | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 doc/SPI/README.ti_qspi_dra_test create mode 100644 doc/SPI/README.ti_qspi_flash diff --git a/doc/SPI/README.ti_qspi_dra_test b/doc/SPI/README.ti_qspi_dra_test new file mode 100644 index 0000000000..fe37857236 --- /dev/null +++ b/doc/SPI/README.ti_qspi_dra_test @@ -0,0 +1,48 @@ +------------------------------------------------- + Simple steps used to test the QSPI at U-Boot +------------------------------------------------- + +For #1, build the patched U-Boot and load MLO/u-boot.img + +---------------------------------- +Boot from another medium like MMC +---------------------------------- + +U-Boot# mmc dev 0 +mmc0 is current device +U-Boot# fatload mmc 0 0x82000000 MLO +reading MLO +55872 bytes read in 8 ms (6.7 MiB/s) +U-Boot# fatload mmc 0 0x83000000 u-boot.img +reading u-boot.img +248600 bytes read in 19 ms (12.5 MiB/s) + +-------------------------------------------------- +Commands to erase/write u-boot/mlo to flash device +-------------------------------------------------- +U-Boot# sf probe 0 +SF: Detected S25FL256S_64K with page size 256 Bytes, erase size 64 KiB, total 32 MiB, mapped at 5c000000 +SF: Warning - Only lower 16MiB accessible, Full access #define CONFIG_SPI_FLASH_BAR +U-Boot# sf erase 0 0x10000 +SF: 65536 bytes @ 0x0 Erased: OK +U-Boot# sf erase 0x20000 0x10000 +SF: 65536 bytes @ 0x20000 Erased: OK +U-Boot# sf erase 0x30000 0x10000 +SF: 65536 bytes @ 0x30000 Erased: OK +U-Boot# sf erase 0x40000 0x10000 +SF: 65536 bytes @ 0x40000 Erased: OK +U-Boot# sf erase 0x50000 0x10000 +SF: 65536 bytes @ 0x50000 Erased: OK +U-Boot# sf erase 0x60000 0x10000 +SF: 65536 bytes @ 0x60000 Erased: OK +U-Boot# sf write 82000000 0 0x10000 +SF: 65536 bytes @ 0x0 Written: OK +U-Boot# sf write 83000000 0x20000 0x60000 +SF: 393216 bytes @ 0x20000 Written: OK + +For #2, set sysboot to QSPI-1 boot mode(SYSBOOT[5:0] = 100110) and power +on. ROM should find the GP header at offset 0 and load/execute SPL. SPL +then detects that ROM was in QSPI-1 mode (boot code 10) and attempts to +find a U-Boot image header at offset 0x20000 (set in the config file) +and proceeds to load that image using the U-Boot image payload offset/size +from the header. It will then start U-Boot. diff --git a/doc/SPI/README.ti_qspi_flash b/doc/SPI/README.ti_qspi_flash new file mode 100644 index 0000000000..1b86d01a0e --- /dev/null +++ b/doc/SPI/README.ti_qspi_flash @@ -0,0 +1,47 @@ +QSPI U-boot support +------------------ + +Host processor is connected to serial flash device via qpsi +interface. QSPI is a kind of spi module that allows single, +dual and quad read access to external spi devices. The module +has a memory mapped interface which provide direct interface +for accessing data form external spi devices. + +The one QSPI in the device is primarily intended for fast booting +from Quad SPI flash devices. + +Usecase +------- + +MLO/u-boot.img will be flashed from SD/MMC to the flash device +using serial flash erase and write commands. Then, switch settings +will be changed to qspi boot. Then, the ROM code will read MLO +from the predefined location in the flash, where it was flashed and +execute it after storing it in SDRAM. Then, the MLO will read +u-boot.img from flash and execute it from SDRAM. + +SPI mode +------- +SPI mode uses mtd spi framework for transfer and reception of data. +Can be used in: +1. Normal mode: use single pin for transfers +2. Dual Mode: use two pins for transfers. +3. Quad mode: use four pin for transfer + +Memory mapped read mode +----------------------- +In this, SPI controller is configured using configuration port and then +controler is switched to memory mapped port for data read. + +Driver +------ +drivers/qspi/ti_qspi.c + - Newly created file which is responsible for configuring the + qspi controller and also for providing the low level api which + is responsible for transferring the datas from host controller + to flash device and vice versa. + +Testing +------- +A seperated file named README.dra_qspi_test has been created which gives all the +details about the commands required to test qspi at u-boot level. -- cgit v1.2.3 From ce22b922dd1fdd3f6cb25660e6e845d4f1cb4f70 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Mon, 7 Oct 2013 19:34:56 +0530 Subject: sf: Minor cleanups - Add spaces, tabs - Commenting. - Rearrange code. - Add static qualifier for missing func. - Remove memory_map from ramtron.c - Ramtron: spi_flash_internal.h -> sf_internal.h Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/ramtron.c | 4 +--- drivers/mtd/spi/sf_internal.h | 8 ++++---- drivers/mtd/spi/sf_probe.c | 7 ++++--- include/spi.h | 22 +++++++++++----------- include/spi_flash.h | 4 ++-- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/drivers/mtd/spi/ramtron.c b/drivers/mtd/spi/ramtron.c index c9701d05b3..7367e7ab22 100644 --- a/drivers/mtd/spi/ramtron.c +++ b/drivers/mtd/spi/ramtron.c @@ -36,7 +36,7 @@ #include #include #include -#include "spi_flash_internal.h" +#include "sf_internal.h" /* * Properties of supported FRAMs @@ -383,8 +383,6 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, printf("SF: Detected %s with page size ", flash->name); print_size(flash->sector_size, ", total "); print_size(flash->size, ""); - if (flash->memory_map) - printf(", mapped at %p", flash->memory_map); puts("\n"); spi_release_bus(spi); diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 29a14f4df6..12d02f9e41 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -13,7 +13,7 @@ #define SPI_FLASH_16MB_BOUN 0x1000000 /* SECT flags */ -#define SECT_4K (1 << 1) +#define SECT_4K (1 << 1) #define SECT_32K (1 << 2) #define E_FSR (1 << 3) @@ -29,8 +29,8 @@ #define CMD_WRITE_DISABLE 0x04 #define CMD_READ_STATUS 0x05 #define CMD_WRITE_ENABLE 0x06 -#define CMD_READ_CONFIG 0x35 -#define CMD_FLAG_STATUS 0x70 +#define CMD_READ_CONFIG 0x35 +#define CMD_FLAG_STATUS 0x70 /* Read commands */ #define CMD_READ_ARRAY_SLOW 0x03 @@ -57,7 +57,7 @@ /* SST specific */ #ifdef CONFIG_SPI_FLASH_SST # define SST_WP 0x01 /* Supports AAI word program */ -# define CMD_SST_BP 0x02 /* Byte Program */ +# define CMD_SST_BP 0x02 /* Byte Program */ # define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 6aa7086c41..4251b1be19 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -152,7 +152,8 @@ static const struct spi_flash_params spi_flash_params_table[] = { */ }; -struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) +static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, + u8 *idcode) { const struct spi_flash_params *params; struct spi_flash *flash; @@ -189,6 +190,7 @@ struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) flash->spi = spi; flash->name = params->name; + flash->memory_map = spi->memory_map; /* Assign spi_flash ops */ flash->write = spi_flash_cmd_write_ops; @@ -203,7 +205,6 @@ struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; flash->sector_size = params->sector_size; flash->size = flash->sector_size * params->nr_sectors; - flash->memory_map = spi->memory_map; /* Compute erase sector and command */ if (params->flags & SECT_4K) { @@ -224,8 +225,8 @@ struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, u8 *idcode) flash->poll_cmd = CMD_FLAG_STATUS; #endif + /* Configure the BAR - discover bank cmds and read current bank */ #ifdef CONFIG_SPI_FLASH_BAR - /* Configure the BAR - discover bank cmds and read current bank */ u8 curr_bank = 0; if (flash->size > SPI_FLASH_16MB_BOUN) { flash->bank_read_cmd = (idcode[0] == 0x01) ? diff --git a/include/spi.h b/include/spi.h index c2086fc62e..5164d437b9 100644 --- a/include/spi.h +++ b/include/spi.h @@ -25,24 +25,24 @@ #define SPI_PREAMBLE 0x80 /* Skip preamble bytes */ /* SPI transfer flags */ -#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ -#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ -#define SPI_XFER_MMAP 0x08 /* Memory Mapped start */ -#define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ +#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ +#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ +#define SPI_XFER_MMAP 0x08 /* Memory Mapped start */ +#define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ /* Header byte that marks the start of the message */ -#define SPI_PREAMBLE_END_BYTE 0xec +#define SPI_PREAMBLE_END_BYTE 0xec /** - * struct spi_slave: Representation of a SPI slave, - * i.e. what we're communicating with. + * struct spi_slave - Representation of a SPI slave * * Drivers are expected to extend this with controller-specific data. * - * bus: ID of the bus that the slave is attached to. - * cs: ID of the chip select connected to the slave. - * max_write_size: If non-zero, the maximum number of bytes which can - * be written at once, excluding command bytes. + * @bus: ID of the bus that the slave is attached to. + * @cs: ID of the chip select connected to the slave. + * @max_write_size: If non-zero, the maximum number of bytes which can + * be written at once, excluding command bytes. + * @memory_map: Address of read-only SPI flash access. */ struct spi_slave { unsigned int bus; diff --git a/include/spi_flash.h b/include/spi_flash.h index b7cce12ef9..1ff5af4dfc 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -27,13 +27,13 @@ * @size: Total flash size * @page_size: Write (page) size * @sector_size: Sector size - * @erase_size: Erase size + * @erase_size: Erase size * @bank_read_cmd: Bank read cmd * @bank_write_cmd: Bank write cmd * @bank_curr: Current flash bank * @poll_cmd: Poll cmd - for flash erase/program * @erase_cmd: Erase cmd 4K, 32K, 64K - * @memory_map: Address of read-only SPI flash access + * @memory_map: Address of read-only SPI flash access * @read: Flash read ops: Read len bytes at offset into buf * Supported cmds: Fast Array Read * @write: Flash write ops: Write len bytes from buf into offeset -- cgit v1.2.3 From adbb5860e5d00771ecc04a1480a85e94ef0e187e Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Mon, 7 Oct 2013 17:21:20 +0530 Subject: sf: ramtron: Remove page_size print There is no page_size for ramtron flashes, so just print the detected flash and it's size. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/mtd/spi/ramtron.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/spi/ramtron.c b/drivers/mtd/spi/ramtron.c index 7367e7ab22..d50da37c89 100644 --- a/drivers/mtd/spi/ramtron.c +++ b/drivers/mtd/spi/ramtron.c @@ -380,8 +380,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, goto err_manufacturer_probe; } - printf("SF: Detected %s with page size ", flash->name); - print_size(flash->sector_size, ", total "); + printf("SF: Detected %s with total size ", flash->name); print_size(flash->size, ""); puts("\n"); -- cgit v1.2.3 From 3cfcf774c270ecf6289203d88f859d1f91cb318e Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Mon, 7 Oct 2013 17:33:20 +0530 Subject: doc: SPI: Update SPI status track Updated SPI/status.txt, with memory_map and TODO. Signed-off-by: Jagannadha Sutradharudu Teki --- doc/SPI/status.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/SPI/status.txt b/doc/SPI/status.txt index 6050e4ac0d..62c3c85417 100644 --- a/doc/SPI/status.txt +++ b/doc/SPI/status.txt @@ -9,13 +9,15 @@ SPI FLASH (drivers/mtd/spi): - sf_ops.c: SPI flash operations code. - sf.c: SPI flash interface, which interacts controller driver. - Bank Address Register (Accessing flashes > 16Mbytes in 3-byte addressing) +- Added memory_mapped support for read operations. - Common probe support for all supported flash vendors except, ramtron. SPI DRIVERS (drivers/spi): - TODO: -- Runtime detection of spi_flash params(if possible) +- Runtime detection of spi_flash params, SFDP(if possible) +- Add support for multibus build/accessing. - Extended read commands support(dual read, dual IO read) - Quad Page Program support. - Quad Read support(quad fast read, quad IO read) @@ -26,3 +28,4 @@ TODO: -- Jagannadha Sutradharudu Teki 18-09-2013. +07-10-2013. -- cgit v1.2.3 From fc9ae1bac45a40bdc9b8756757b645dc8d5b781c Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Tue, 8 Oct 2013 16:20:03 +0530 Subject: exynos: Export timer_get_us() to get microsecond timer This function, if implemented by the board, provides a microsecond timer. The granularity may be larger than 1us if hardware does not support this. Signed-off-by: Simon Glass Signed-off-by: Rajeshwari S Shinde Reviewed-by: Jagannadha Sutradharudu Teki --- include/common.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/common.h b/include/common.h index f1a590a15e..bed43168fe 100644 --- a/include/common.h +++ b/include/common.h @@ -596,6 +596,12 @@ void ddr_enable_ecc(unsigned int dram_size); #endif #endif +/* + * Return the current value of a monotonically increasing microsecond timer. + * Granularity may be larger than 1us if hardware does not support this. + */ +ulong timer_get_us(void); + /* $(CPU)/cpu.c */ static inline int cpumask_next(int cpu, unsigned int mask) { -- cgit v1.2.3 From 8d203afdd3bf54ad5b2523cdacaff4ac35da6b08 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Tue, 8 Oct 2013 16:20:04 +0530 Subject: spi: exynos: Support a delay after deactivate For devices that need some time to react after a spi transaction finishes, add the ability to set a delay. Implement this as a delay on the first/next transaction to avoid any delay in the fairly common case where a SPI transaction is followed by other processing. Signed-off-by: Simon Glass Signed-off-by: Rajeshwari S Shinde Reviewed-by: Jagannadha Sutradharudu Teki --- drivers/spi/exynos_spi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index efc8b1e3a5..d7fdaacebd 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -26,6 +26,7 @@ struct spi_bus { struct exynos_spi *regs; int inited; /* 1 if this bus is ready for use */ int node; + uint deactivate_delay_us; /* Delay to wait after deactivate */ }; /* A list of spi buses that we know about */ @@ -40,6 +41,8 @@ struct exynos_spi_slave { enum periph_id periph_id; /* Peripheral ID for this device */ unsigned int fifo_size; int skip_preamble; + struct spi_bus *bus; /* Pointer to our SPI bus info */ + ulong last_transaction_us; /* Time of last transaction end */ }; static struct spi_bus *spi_get_bus(unsigned dev_index) @@ -85,6 +88,7 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs, } bus = &spi_bus[busnum]; + spi_slave->bus = bus; spi_slave->regs = bus->regs; spi_slave->mode = mode; spi_slave->periph_id = bus->periph_id; @@ -95,6 +99,7 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs, spi_slave->fifo_size = 256; spi_slave->skip_preamble = 0; + spi_slave->last_transaction_us = timer_get_us(); spi_slave->freq = bus->frequency; if (max_hz) @@ -359,9 +364,22 @@ void spi_cs_activate(struct spi_slave *slave) { struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); + /* If it's too soon to do another transaction, wait */ + if (spi_slave->bus->deactivate_delay_us && + spi_slave->last_transaction_us) { + ulong delay_us; /* The delay completed so far */ + delay_us = timer_get_us() - spi_slave->last_transaction_us; + if (delay_us < spi_slave->bus->deactivate_delay_us) + udelay(spi_slave->bus->deactivate_delay_us - delay_us); + } + clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT); debug("Activate CS, bus %d\n", spi_slave->slave.bus); spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE; + + /* Remember time of this transaction so we can honour the bus delay */ + if (spi_slave->bus->deactivate_delay_us) + spi_slave->last_transaction_us = timer_get_us(); } /** @@ -411,6 +429,8 @@ static int spi_get_config(const void *blob, int node, struct spi_bus *bus) /* Use 500KHz as a suitable default */ bus->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", 500000); + bus->deactivate_delay_us = fdtdec_get_int(blob, node, + "spi-deactivate-delay", 0); return 0; } -- cgit v1.2.3 From 120af1572a3647bb87eff2f62dd8f8a919ee71f0 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Tue, 8 Oct 2013 16:20:05 +0530 Subject: spi: exynos: Minimise access to SPI FIFO level Accessing SPI registers is slow, but access to the FIFO level register in particular seems to be extraordinarily expensive (I measure up to 600ns). Perhaps it is required to synchronise with the SPI byte output logic which might run at 1/8th of the 40MHz SPI speed (just a guess). Reduce access to this register by filling up and emptying FIFOs more completely, rather than just one word each time around the inner loop. Since the rxfifo value will now likely be much greater that what we read before we fill the txfifo, we only fill the txfifo halfway. This is because if the txfifo is empty, but the rxfifo has data in it, then writing too much data to the txfifo may overflow the rxfifo as data arrives. This speeds up SPI flash reading from about 1MB/s to about 2MB/s on snow. Signed-off-by: Simon Glass Signed-off-by: Rajeshwari S Shinde Reviewed-by: Jagannadha Sutradharudu Teki --- drivers/spi/exynos_spi.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index d7fdaacebd..7407d6cc12 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -247,24 +247,27 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, /* Keep the fifos full/empty. */ spi_get_fifo_levels(regs, &rx_lvl, &tx_lvl); - if (tx_lvl < spi_slave->fifo_size && out_bytes) { + while (tx_lvl < spi_slave->fifo_size/2 && out_bytes) { temp = txp ? *txp++ : 0xff; writel(temp, ®s->tx_data); out_bytes--; + tx_lvl++; } if (rx_lvl > 0) { - temp = readl(®s->rx_data); - if (spi_slave->skip_preamble) { - if (temp == SPI_PREAMBLE_END_BYTE) { - spi_slave->skip_preamble = 0; - stopping = 0; + while (rx_lvl > 0) { + temp = readl(®s->rx_data); + if (spi_slave->skip_preamble) { + if (temp == SPI_PREAMBLE_END_BYTE) { + spi_slave->skip_preamble = 0; + stopping = 0; + } + } else { + if (rxp || stopping) + *rxp++ = temp; + in_bytes--; } - } else { - if (rxp || stopping) - *rxp++ = temp; - in_bytes--; - } - toread--; + toread--; + rx_lvl--; } else if (!toread) { /* * We have run out of input data, but haven't read -- cgit v1.2.3 From c4a796329d00ce46de6b5afeb1fdabec82830677 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Tue, 8 Oct 2013 16:20:06 +0530 Subject: spi: exynos: Support word transfers Since SPI register access is so expensive, it is worth transferring data a word at a time if we can. This complicates the driver unfortunately. Use the byte-swapping feature to avoid having to convert to/from big endian in software. This change increases speed from about 2MB/s to about 4.5MB/s. Signed-off-by: Simon Glass Signed-off-by: Rajeshwari S Shinde Reviewed-by: Jagannadha Sutradharudu Teki --- arch/arm/include/asm/arch-exynos/spi.h | 11 ++++- drivers/spi/exynos_spi.c | 76 +++++++++++++++++++++++++++------- 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/arch/arm/include/asm/arch-exynos/spi.h b/arch/arm/include/asm/arch-exynos/spi.h index fb23aa69c2..147c1a7304 100644 --- a/arch/arm/include/asm/arch-exynos/spi.h +++ b/arch/arm/include/asm/arch-exynos/spi.h @@ -22,7 +22,7 @@ struct exynos_spi { unsigned int rx_data; /* 0x1c */ unsigned int pkt_cnt; /* 0x20 */ unsigned char reserved2[4]; - unsigned char reserved3[4]; + unsigned int swap_cfg; /* 0x28 */ unsigned int fb_clk; /* 0x2c */ unsigned char padding[0xffd0]; }; @@ -62,5 +62,14 @@ struct exynos_spi { /* Packet Count */ #define SPI_PACKET_CNT_EN (1 << 16) +/* Swap config */ +#define SPI_TX_SWAP_EN (1 << 0) +#define SPI_TX_BYTE_SWAP (1 << 2) +#define SPI_TX_HWORD_SWAP (1 << 3) +#define SPI_TX_BYTE_SWAP (1 << 2) +#define SPI_RX_SWAP_EN (1 << 4) +#define SPI_RX_BYTE_SWAP (1 << 6) +#define SPI_RX_HWORD_SWAP (1 << 7) + #endif /* __ASSEMBLY__ */ #endif diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index 7407d6cc12..699c57eb6d 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -204,12 +204,29 @@ static void spi_get_fifo_levels(struct exynos_spi *regs, * * @param regs SPI peripheral registers * @param count Number of bytes to transfer + * @param step Number of bytes to transfer in each packet (1 or 4) */ -static void spi_request_bytes(struct exynos_spi *regs, int count) +static void spi_request_bytes(struct exynos_spi *regs, int count, int step) { + /* For word address we need to swap bytes */ + if (step == 4) { + setbits_le32(®s->mode_cfg, + SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD); + count /= 4; + setbits_le32(®s->swap_cfg, SPI_TX_SWAP_EN | SPI_RX_SWAP_EN | + SPI_TX_BYTE_SWAP | SPI_RX_BYTE_SWAP | + SPI_TX_HWORD_SWAP | SPI_RX_HWORD_SWAP); + } else { + /* Select byte access and clear the swap configuration */ + clrbits_le32(®s->mode_cfg, + SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD); + writel(0, ®s->swap_cfg); + } + assert(count && count < (1 << 16)); setbits_le32(®s->ch_cfg, SPI_CH_RST); clrbits_le32(®s->ch_cfg, SPI_CH_RST); + writel(count | SPI_PACKET_CNT_EN, ®s->pkt_cnt); } @@ -224,17 +241,27 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, int toread; unsigned start = get_timer(0); int stopping; + int step; out_bytes = in_bytes = todo; stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE); + /* + * Try to transfer words if we can. This helps read performance at + * SPI clock speeds above about 20MHz. + */ + step = 1; + if (!((todo | (uintptr_t)rxp | (uintptr_t)txp) & 3) && + !spi_slave->skip_preamble) + step = 4; + /* * If there's something to send, do a software reset and set a * transaction size. */ - spi_request_bytes(regs, todo); + spi_request_bytes(regs, todo, step); /* * Bytes are transmitted/received in pairs. Wait to receive all the @@ -247,14 +274,26 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, /* Keep the fifos full/empty. */ spi_get_fifo_levels(regs, &rx_lvl, &tx_lvl); + + /* + * Don't completely fill the txfifo, since we don't want our + * rxfifo to overflow, and it may already contain data. + */ while (tx_lvl < spi_slave->fifo_size/2 && out_bytes) { - temp = txp ? *txp++ : 0xff; + if (!txp) + temp = -1; + else if (step == 4) + temp = *(uint32_t *)txp; + else + temp = *txp; writel(temp, ®s->tx_data); - out_bytes--; - tx_lvl++; + out_bytes -= step; + if (txp) + txp += step; + tx_lvl += step; } - if (rx_lvl > 0) { - while (rx_lvl > 0) { + if (rx_lvl >= step) { + while (rx_lvl >= step) { temp = readl(®s->rx_data); if (spi_slave->skip_preamble) { if (temp == SPI_PREAMBLE_END_BYTE) { @@ -262,12 +301,15 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, stopping = 0; } } else { - if (rxp || stopping) - *rxp++ = temp; - in_bytes--; + if (rxp || stopping) { + *rxp = temp; + rxp += step; + } + in_bytes -= step; } - toread--; - rx_lvl--; + toread -= step; + rx_lvl -= step; + } } else if (!toread) { /* * We have run out of input data, but haven't read @@ -279,7 +321,7 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, out_bytes = in_bytes; toread = in_bytes; txp = NULL; - spi_request_bytes(regs, toread); + spi_request_bytes(regs, toread, step); } if (spi_slave->skip_preamble && get_timer(start) > 100) { printf("SPI timeout: in_bytes=%d, out_bytes=%d, ", @@ -323,10 +365,14 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, if ((flags & SPI_XFER_BEGIN)) spi_cs_activate(slave); - /* Exynos SPI limits each transfer to 65535 bytes */ + /* + * Exynos SPI limits each transfer to 65535 transfers. To keep + * things simple, allow a maximum of 65532 bytes. We could allow + * more in word mode, but the performance difference is small. + */ bytelen = bitlen / 8; for (upto = 0; !ret && upto < bytelen; upto += todo) { - todo = min(bytelen - upto, (1 << 16) - 1); + todo = min(bytelen - upto, (1 << 16) - 4); ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags); if (ret) break; -- cgit v1.2.3