diff options
33 files changed, 1695 insertions, 2317 deletions
| diff --git a/arch/arm/cpu/armv7/omap5/hw_data.c b/arch/arm/cpu/armv7/omap5/hw_data.c index fbbc48662..a1b249e73 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   */ @@ -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 5a3d52c11..7a7caded0 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-exynos/spi.h b/arch/arm/include/asm/arch-exynos/spi.h index fb23aa69c..147c1a730 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/arch/arm/include/asm/arch-omap5/omap.h b/arch/arm/include/asm/arch-omap5/omap.h index e9a51d340..414d37a5a 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 fe8b0c01a..57f0de5ff 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 61fee9f06..3a998cc10 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; diff --git a/board/ti/dra7xx/mux_data.h b/board/ti/dra7xx/mux_data.h index 0a86594c6..6965cc57d 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/doc/SPI/README.ti_qspi_dra_test b/doc/SPI/README.ti_qspi_dra_test new file mode 100644 index 000000000..fe3785723 --- /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 000000000..1b86d01a0 --- /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. diff --git a/doc/SPI/status.txt b/doc/SPI/status.txt new file mode 100644 index 000000000..62c3c8541 --- /dev/null +++ b/doc/SPI/status.txt @@ -0,0 +1,31 @@ +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) +- 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, 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) +- 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 <jagannadh.teki@gmail.com> +18-09-2013. +07-10-2013. 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; -} diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 91d24cea5..e5941b09f 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/exynos_spi.c b/drivers/spi/exynos_spi.c index efc8b1e3a..699c57eb6 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) @@ -199,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);  } @@ -219,6 +241,7 @@ 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; @@ -226,10 +249,19 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,  					!(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 @@ -242,24 +274,42 @@ 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) { -			temp = txp ? *txp++ : 0xff; + +		/* +		 * 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) { +			if (!txp) +				temp = -1; +			else if (step == 4) +				temp = *(uint32_t *)txp; +			else +				temp = *txp;  			writel(temp, ®s->tx_data); -			out_bytes--; +			out_bytes -= step; +			if (txp) +				txp += step; +			tx_lvl += step;  		} -		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; +		if (rx_lvl >= step) { +			while (rx_lvl >= step) { +				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; +						rxp += step; +					} +					in_bytes -= step;  				} -			} else { -				if (rxp || stopping) -					*rxp++ = temp; -				in_bytes--; +				toread -= step; +				rx_lvl -= step;  			} -			toread--;  		} else if (!toread) {  			/*  			 * We have run out of input data, but haven't read @@ -271,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, ", @@ -315,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; @@ -359,9 +413,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 +478,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;  } diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c new file mode 100644 index 000000000..5a5b48276 --- /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 <common.h> +#include <asm/io.h> +#include <asm/arch/omap.h> +#include <malloc.h> +#include <spi.h> + +/* 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; +} diff --git a/include/common.h b/include/common.h index f1a590a15..bed43168f 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)  { diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h index 7b120de21..51e0e801a 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 */ diff --git a/include/configs/top9000.h b/include/configs/top9000.h index 65dabde54..a6d692872 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 diff --git a/include/spi.h b/include/spi.h index c0dab578b..5164d437b 100644 --- a/include/spi.h +++ b/include/spi.h @@ -25,29 +25,33 @@  #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_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 -/*----------------------------------------------------------------------- - * 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; -	unsigned int	cs; +	unsigned int bus; +	unsigned int cs;  	unsigned int max_write_size; +	void *memory_map;  }; -/*----------------------------------------------------------------------- +/**   * Initialization, must be called once on start up.   *   * TODO: I don't think we really need this. @@ -60,10 +64,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 +78,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 +93,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 +107,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 +118,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 +134,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 +165,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 +187,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 +196,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 +205,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.   * diff --git a/include/spi_flash.h b/include/spi_flash.h index bfc59aa70..1ff5af4df 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,75 +19,52 @@  #include <linux/types.h>  #include <linux/compiler.h> +/** + * 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; -	/* Erase (sector) size */ -	u32		sector_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; +	u8 poll_cmd; +	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); +	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);  }; -/** - * 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); |