diff options
Diffstat (limited to 'drivers/mtd')
| -rw-r--r-- | drivers/mtd/mtdcore.c | 14 | ||||
| -rw-r--r-- | drivers/mtd/mtdpart.c | 12 | ||||
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 18 | ||||
| -rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 3 | ||||
| -rw-r--r-- | drivers/mtd/spi/Makefile | 15 | ||||
| -rw-r--r-- | drivers/mtd/spi/atmel.c | 544 | ||||
| -rw-r--r-- | drivers/mtd/spi/eon.c | 60 | ||||
| -rw-r--r-- | drivers/mtd/spi/gigadevice.c | 65 | ||||
| -rw-r--r-- | drivers/mtd/spi/macronix.c | 98 | ||||
| -rw-r--r-- | drivers/mtd/spi/ramtron.c | 122 | ||||
| -rw-r--r-- | drivers/mtd/spi/sf.c | 54 | ||||
| -rw-r--r-- | drivers/mtd/spi/sf_internal.h (renamed from drivers/mtd/spi/spi_flash_internal.h) | 138 | ||||
| -rw-r--r-- | drivers/mtd/spi/sf_ops.c | 405 | ||||
| -rw-r--r-- | drivers/mtd/spi/sf_probe.c | 363 | ||||
| -rw-r--r-- | drivers/mtd/spi/spansion.c | 141 | ||||
| -rw-r--r-- | drivers/mtd/spi/spi_flash.c | 615 | ||||
| -rw-r--r-- | drivers/mtd/spi/sst.c | 238 | ||||
| -rw-r--r-- | drivers/mtd/spi/stmicro.c | 202 | ||||
| -rw-r--r-- | drivers/mtd/spi/winbond.c | 141 | 
19 files changed, 1051 insertions, 2197 deletions
| diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 49c08145a..deda5f244 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -217,11 +217,23 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)  int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,  	     u_char *buf)  { +	int ret_code;  	if (from < 0 || from > mtd->size || len > mtd->size - from)  		return -EINVAL;  	if (!len)  		return 0; -	return mtd->_read(mtd, from, len, retlen, buf); + +	/* +	 * In the absence of an error, drivers return a non-negative integer +	 * representing the maximum number of bitflips that were corrected on +	 * any one ecc region (if applicable; zero otherwise). +	 */ +	ret_code = mtd->_read(mtd, from, len, retlen, buf); +	if (unlikely(ret_code < 0)) +		return ret_code; +	if (mtd->ecc_strength == 0) +		return 0;	/* device lacks ecc */ +	return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;  }  int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 9dfe7bbc9..146ce11eb 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -53,12 +53,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,  	stats = part->master->ecc_stats;  	res = mtd_read(part->master, from + part->offset, len, retlen, buf); -	if (unlikely(res)) { -		if (mtd_is_bitflip(res)) -			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; -		if (mtd_is_eccerr(res)) -			mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed; -	} +	if (unlikely(mtd_is_eccerr(res))) +		mtd->ecc_stats.failed += +			part->master->ecc_stats.failed - stats.failed; +	else +		mtd->ecc_stats.corrected += +			part->master->ecc_stats.corrected - stats.corrected;  	return res;  } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 9e05cef41..d4d586c94 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1238,6 +1238,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  		mtd->oobavail : mtd->oobsize;  	uint8_t *bufpoi, *oob, *buf; +	unsigned int max_bitflips = 0;  	stats = mtd->ecc_stats; @@ -1265,7 +1266,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  			chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); -			/* Now read the page into the buffer */ +			/* +			 * Now read the page into the buffer.  Absent an error, +			 * the read methods return max bitflips per ecc step. +			 */  			if (unlikely(ops->mode == MTD_OPS_RAW))  				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,  							      oob_required, @@ -1284,15 +1288,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  				break;  			} +			max_bitflips = max_t(unsigned int, max_bitflips, ret); +  			/* Transfer not aligned data */  			if (!aligned) {  				if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&  				    !(mtd->ecc_stats.failed - stats.failed) && -				    (ops->mode != MTD_OPS_RAW)) +				    (ops->mode != MTD_OPS_RAW)) {  					chip->pagebuf = realpage; -				else +					chip->pagebuf_bitflips = ret; +				} else {  					/* Invalidate page cache */  					chip->pagebuf = -1; +				}  				memcpy(buf, chip->buffers->databuf + col, bytes);  			} @@ -1310,6 +1318,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  		} else {  			memcpy(buf, chip->buffers->databuf + col, bytes);  			buf += bytes; +			max_bitflips = max_t(unsigned int, max_bitflips, +					     chip->pagebuf_bitflips);  		}  		readlen -= bytes; @@ -1341,7 +1351,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  	if (mtd->ecc_stats.failed - stats.failed)  		return -EBADMSG; -	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +	return max_bitflips;  }  /** diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index ddfe7e7c7..067f8ef18 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -969,7 +969,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,  	if (mtd->ecc_stats.failed - stats.failed)  		return -EBADMSG; -	return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +	/* return max bitflips per ecc step; ONENANDs correct 1 bit only */ +	return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;  }  /** diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 191138ad1..86ffc59d0 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -14,16 +14,11 @@ 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_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 +ifdef CONFIG_CMD_SF +COBJS-y        += sf.o +endif +COBJS-$(CONFIG_SPI_FLASH) += sf_probe.o sf_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/atmel.c b/drivers/mtd/spi/atmel.c deleted file mode 100644 index f34df43f5..000000000 --- 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 <common.h> -#include <malloc.h> -#include <spi_flash.h> - -#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 25cfc1252..000000000 --- a/drivers/mtd/spi/eon.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * (C) Copyright 2010, ucRobotics Inc. - * Author: Chong Huang <chuang@ucrobotics.com> - * Licensed under the GPL-2 or later. - */ - -#include <common.h> -#include <malloc.h> -#include <spi_flash.h> - -#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 b42581a70..000000000 --- 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 <banajit.g@samsung.com> - * - * SPDX-License-Identifier:	GPL-2.0+ - */ - -#include <common.h> -#include <malloc.h> -#include <spi_flash.h> - -#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 70435eb5a..000000000 --- a/drivers/mtd/spi/macronix.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2009(C) Marvell International Ltd. and its affiliates - * Prafulla Wadaskar <prafulla@marvell.com> - * - * Based on drivers/mtd/spi/stmicro.c - * - * Copyright 2008, Network Appliance Inc. - * Jason McMullan <mcmullan@netapp.com> - * - * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. - * TsiChung Liew (Tsi-Chung.Liew@freescale.com) - * - * SPDX-License-Identifier:	GPL-2.0+ - */ - -#include <common.h> -#include <malloc.h> -#include <spi_flash.h> - -#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/ramtron.c b/drivers/mtd/spi/ramtron.c index 38f9d6916..d50da37c8 100644 --- a/drivers/mtd/spi/ramtron.c +++ b/drivers/mtd/spi/ramtron.c @@ -36,7 +36,7 @@  #include <common.h>  #include <malloc.h>  #include <spi_flash.h> -#include "spi_flash_internal.h" +#include "sf_internal.h"  /*   * Properties of supported FRAMs @@ -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,118 @@ 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 total size ", flash->name); +	print_size(flash->size, ""); +	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/sf.c b/drivers/mtd/spi/sf.c new file mode 100644 index 000000000..ddbdda0dc --- /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 <common.h> +#include <spi.h> + +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/sf_internal.h index af1afa96c..12d02f9e4 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -2,42 +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 SPI_FLASH_16MB_BOUN		0x1000000 +#define CMD_READ_CONFIG			0x35 +#define CMD_FLAG_STATUS			0x70 -/* Manufacture ID's */ -#define SPI_FLASH_SPANSION_IDCODE0	0x01 -#define SPI_FLASH_STMICRO_IDCODE0	0x20 -#define SPI_FLASH_WINBOND_IDCODE0	0xef +/* 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 @@ -48,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); @@ -58,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. @@ -68,46 +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); -/* - * Enable writing on the SPI flash. - */ +/* 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. - */ +/* 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); - -#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 -  /* - * 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 @@ -120,21 +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); -/* Erase sectors. */ -int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len); +/* + * 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); -/* 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); +#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 000000000..2396e2272 --- /dev/null +++ b/drivers/mtd/spi/sf_ops.c @@ -0,0 +1,405 @@ +/* + * 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 <common.h> +#include <spi.h> +#include <spi_flash.h> +#include <watchdog.h> + +#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) { +		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; +	} + +	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 000000000..4251b1be1 --- /dev/null +++ b/drivers/mtd/spi/sf_probe.c @@ -0,0 +1,363 @@ +/* + * 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 <common.h> +#include <fdtdec.h> +#include <malloc.h> +#include <spi.h> +#include <spi_flash.h> + +#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}, +	{"EN25S64",	   0x1c3817, 0x0,	64 * 1024,   128,		     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) +	 */ +}; + +static 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; +	flash->memory_map = spi->memory_map; + +	/* 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 + +	/* Configure the BAR - discover bank cmds and read current bank */ +#ifdef CONFIG_SPI_FLASH_BAR +	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/spansion.c b/drivers/mtd/spi/spansion.c deleted file mode 100644 index fa7ac8c93..000000000 --- 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 <common.h> -#include <malloc.h> -#include <spi_flash.h> - -#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.c b/drivers/mtd/spi/spi_flash.c deleted file mode 100644 index 5d5055ff3..000000000 --- a/drivers/mtd/spi/spi_flash.c +++ /dev/null @@ -1,615 +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 <common.h> -#include <fdtdec.h> -#include <malloc.h> -#include <spi.h> -#include <spi_flash.h> -#include <watchdog.h> - -#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, -				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(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) -{ -	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/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c deleted file mode 100644 index 256867c84..000000000 --- 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 <mcmullan@netapp.com> - * 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 <common.h> -#include <malloc.h> -#include <spi_flash.h> - -#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 c5fa64e37..000000000 --- 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 <mcmullan@netapp.com> - * - * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. - * TsiChung Liew (Tsi-Chung.Liew@freescale.com) - * - * SPDX-License-Identifier:	GPL-2.0+ - */ - -#include <common.h> -#include <malloc.h> -#include <spi_flash.h> - -#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 b31911a40..000000000 --- a/drivers/mtd/spi/winbond.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2008, Network Appliance Inc. - * Author: Jason McMullan <mcmullan <at> netapp.com> - * Licensed under the GPL-2 or later. - */ - -#include <common.h> -#include <malloc.h> -#include <spi_flash.h> - -#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; -} |