Merge branch 'master' of git://git.denx.de/u-boot-spi
This commit is contained in:
		
						commit
						10fcda8e25
					
				
							
								
								
									
										6
									
								
								README
								
								
								
								
							
							
						
						
									
										6
									
								
								README
								
								
								
								
							|  | @ -2756,6 +2756,12 @@ CBFS (Coreboot Filesystem) support | ||||||
| 		Define this option to use the Bank addr/Extended addr | 		Define this option to use the Bank addr/Extended addr | ||||||
| 		support on SPI flashes which has size > 16Mbytes. | 		support on SPI flashes which has size > 16Mbytes. | ||||||
| 
 | 
 | ||||||
|  | 		CONFIG_SF_DUAL_FLASH		Dual flash memories | ||||||
|  | 
 | ||||||
|  | 		Define this option to use dual flash support where two flash | ||||||
|  | 		memories can be connected with a given cs line. | ||||||
|  | 		currently Xilinx Zynq qspi support these type of connections. | ||||||
|  | 
 | ||||||
| - SystemACE Support: | - SystemACE Support: | ||||||
| 		CONFIG_SYSTEMACE | 		CONFIG_SYSTEMACE | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -358,7 +358,8 @@ static void show_time(struct test_info *test, int stage) | ||||||
| 	int bps;	/* Bits per second */ | 	int bps;	/* Bits per second */ | ||||||
| 
 | 
 | ||||||
| 	speed = (long long)test->bytes * 1000; | 	speed = (long long)test->bytes * 1000; | ||||||
| 	do_div(speed, test->time_ms[stage] * 1024); | 	if (test->time_ms[stage]) | ||||||
|  | 		do_div(speed, test->time_ms[stage] * 1024); | ||||||
| 	bps = speed * 8; | 	bps = speed * 8; | ||||||
| 
 | 
 | ||||||
| 	printf("%d %s: %d ticks, %d KiB/s %d.%03d Mbps\n", stage, | 	printf("%d %s: %d ticks, %d KiB/s %d.%03d Mbps\n", stage, | ||||||
|  | @ -446,11 +447,13 @@ static int do_spi_flash_test(int argc, char * const argv[]) | ||||||
| { | { | ||||||
| 	unsigned long offset; | 	unsigned long offset; | ||||||
| 	unsigned long len; | 	unsigned long len; | ||||||
| 	uint8_t *buf = (uint8_t *)CONFIG_SYS_TEXT_BASE; | 	uint8_t *buf, *from; | ||||||
| 	char *endp; | 	char *endp; | ||||||
| 	uint8_t *vbuf; | 	uint8_t *vbuf; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
|  | 	if (argc < 3) | ||||||
|  | 		return -1; | ||||||
| 	offset = simple_strtoul(argv[1], &endp, 16); | 	offset = simple_strtoul(argv[1], &endp, 16); | ||||||
| 	if (*argv[1] == 0 || *endp != 0) | 	if (*argv[1] == 0 || *endp != 0) | ||||||
| 		return -1; | 		return -1; | ||||||
|  | @ -460,17 +463,18 @@ static int do_spi_flash_test(int argc, char * const argv[]) | ||||||
| 
 | 
 | ||||||
| 	vbuf = malloc(len); | 	vbuf = malloc(len); | ||||||
| 	if (!vbuf) { | 	if (!vbuf) { | ||||||
| 		printf("Cannot allocate memory\n"); | 		printf("Cannot allocate memory (%lu bytes)\n", len); | ||||||
| 		return 1; | 		return 1; | ||||||
| 	} | 	} | ||||||
| 	buf = malloc(len); | 	buf = malloc(len); | ||||||
| 	if (!buf) { | 	if (!buf) { | ||||||
| 		free(vbuf); | 		free(vbuf); | ||||||
| 		printf("Cannot allocate memory\n"); | 		printf("Cannot allocate memory (%lu bytes)\n", len); | ||||||
| 		return 1; | 		return 1; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	memcpy(buf, (char *)CONFIG_SYS_TEXT_BASE, len); | 	from = map_sysmem(CONFIG_SYS_TEXT_BASE, 0); | ||||||
|  | 	memcpy(buf, from, len); | ||||||
| 	ret = spi_flash_test(flash, buf, len, offset, vbuf); | 	ret = spi_flash_test(flash, buf, len, offset, vbuf); | ||||||
| 	free(vbuf); | 	free(vbuf); | ||||||
| 	free(buf); | 	free(buf); | ||||||
|  |  | ||||||
|  | @ -0,0 +1,92 @@ | ||||||
|  | SPI/QSPI Dual flash connection modes: | ||||||
|  | ===================================== | ||||||
|  | 
 | ||||||
|  | This describes how SPI/QSPI flash memories are connected to a given | ||||||
|  | controller in a single chip select line. | ||||||
|  | 
 | ||||||
|  | Current spi_flash framework supports, single flash memory connected | ||||||
|  | to a given controller with single chip select line, but there are some | ||||||
|  | hw logics(ex: xilinx zynq qspi) that describes two/dual memories are | ||||||
|  | connected with a single chip select line from a controller. | ||||||
|  | 
 | ||||||
|  | "dual_flash" from include/spi.h describes these types of connection mode | ||||||
|  | 
 | ||||||
|  | Possible connections: | ||||||
|  | -------------------- | ||||||
|  | SF_SINGLE_FLASH: | ||||||
|  |        - single spi flash memory connected with single chip select line. | ||||||
|  | 
 | ||||||
|  |   +------------+             CS         +---------------+ | ||||||
|  |   |            |----------------------->|               | | ||||||
|  |   | Controller |         I0[3:0]        | Flash memory  | | ||||||
|  |   | SPI/QSPI   |<======================>| (SPI/QSPI)    | | ||||||
|  |   |            |           CLK          |               | | ||||||
|  |   |            |----------------------->|               | | ||||||
|  |   +------------+                        +---------------+ | ||||||
|  | 
 | ||||||
|  | SF_DUAL_STACKED_FLASH: | ||||||
|  |        - dual spi/qspi flash memories are connected with a single chipselect | ||||||
|  |          line and these two memories are operating stacked fasion with shared buses. | ||||||
|  |        - xilinx zynq qspi controller has implemented this feature [1] | ||||||
|  | 
 | ||||||
|  |   +------------+        CS             +---------------+ | ||||||
|  |   |            |---------------------->|               | | ||||||
|  |   |            |              I0[3:0]  | Upper Flash   | | ||||||
|  |   |            |            +=========>| memory        | | ||||||
|  |   |            |            |     CLK  | (SPI/QSPI)    | | ||||||
|  |   |            |            |    +---->|               | | ||||||
|  |   | Controller |        CS  |    |     +---------------+ | ||||||
|  |   | SPI/QSPI   |------------|----|---->|               | | ||||||
|  |   |            |    I0[3:0] |    |     | Lower Flash   | | ||||||
|  |   |            |<===========+====|====>| memory        | | ||||||
|  |   |            |          CLK    |     | (SPI/QSPI)    | | ||||||
|  |   |            |-----------------+---->|               | | ||||||
|  |   +------------+                       +---------------+ | ||||||
|  | 
 | ||||||
|  |        - two memory flash devices should has same hw part attributes (like size, | ||||||
|  |          vendor..etc) | ||||||
|  |        - Configurations: | ||||||
|  |                on LQSPI_CFG register, Enable TWO_MEM[BIT:30] on LQSPI_CFG | ||||||
|  |                Enable U_PAGE[BIT:28] if U_PAGE flag set - upper memory | ||||||
|  |                Disable U_PAGE[BIT:28] if U_PAGE flag unset - lower memory | ||||||
|  |        - Operation: | ||||||
|  |                accessing memories serially like one after another. | ||||||
|  |                by default, if U_PAGE is unset lower memory should accessible, | ||||||
|  |                once user wants to access upper memory need to set U_PAGE. | ||||||
|  | 
 | ||||||
|  | SPI_FLASH_CONN_DUALPARALLEL: | ||||||
|  | 	- dual spi/qspi flash memories are connected with a single chipselect | ||||||
|  | 	  line and these two memories are operating parallel with separate buses. | ||||||
|  | 	- xilinx zynq qspi controller has implemented this feature [1] | ||||||
|  | 
 | ||||||
|  |   +-------------+           CS		+---------------+ | ||||||
|  |   |		|---------------------->|		| | ||||||
|  |   | 		|        I0[3:0]	| Upper Flash	| | ||||||
|  |   | 		|<=====================>| memory	| | ||||||
|  |   |		|	   CLK		| (SPI/QSPI)	| | ||||||
|  |   |		|---------------------->|		| | ||||||
|  |   | Controller	|	    CS		+---------------+ | ||||||
|  |   | SPI/QSPI	|---------------------->|		| | ||||||
|  |   | 		|        I0[3:0]	| Lower Flash	| | ||||||
|  |   | 		|<=====================>| memory	| | ||||||
|  |   |		|	   CLK		| (SPI/QSPI)	| | ||||||
|  |   |		|---------------------->|		| | ||||||
|  |   +-------------+			+---------------+ | ||||||
|  | 
 | ||||||
|  | 	- two memory flash devices should has same hw part attributes (like size, | ||||||
|  | 	  vendor..etc) | ||||||
|  | 	- Configurations: | ||||||
|  | 		Need to enable SEP_BUS[BIT:29],TWO_MEM[BIT:30] on LQSPI_CFG register. | ||||||
|  | 	- Operation: | ||||||
|  | 		Even bits, i.e. bit 0, 2, 4 ., of a data word is located in the lower memory | ||||||
|  | 		and odd bits, i.e. bit 1, 3, 5, ., of a data word is located in the upper memory. | ||||||
|  | 
 | ||||||
|  | Note: Technically there is only one CS line from the controller, but | ||||||
|  | zynq qspi controller has an internal hw logic to enable additional CS | ||||||
|  | when controller is configured for dual memories. | ||||||
|  | 
 | ||||||
|  | [1] http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf | ||||||
|  | 
 | ||||||
|  | -- | ||||||
|  | Jagannadha Sutradharudu Teki <jaganna@xilinx.com> | ||||||
|  | 05-01-2014. | ||||||
|  | @ -0,0 +1,41 @@ | ||||||
|  | SPI Flash test on Faraday A369 EVB: | ||||||
|  | ================================== | ||||||
|  | 
 | ||||||
|  | U-Boot 2014.01-rc2-g3444b6f (Dec 20 2013 - 10:58:40) | ||||||
|  | 
 | ||||||
|  | CPU:   FA626TE 528 MHz | ||||||
|  | AHB:   132 MHz | ||||||
|  | APB:   66 MHz | ||||||
|  | I2C:   ready | ||||||
|  | DRAM:  256 MiB | ||||||
|  | MMU:   on | ||||||
|  | NAND:  512 MiB | ||||||
|  | MMC:   ftsdc010: 0 | ||||||
|  | *** Warning - bad CRC, using default environment | ||||||
|  | 
 | ||||||
|  | In:    serial | ||||||
|  | Out:   serial | ||||||
|  | Err:   serial | ||||||
|  | Net:   FTGMAC100#0 | ||||||
|  | Hit any key to stop autoboot:  0 | ||||||
|  | => sf probe 0:0 | ||||||
|  | SF: Detected MX25L1605D with page size 256 Bytes, erase size 64 KiB, total 2 MiB | ||||||
|  | => sf read 0x10800000 0 0x400 | ||||||
|  | SF: 1024 bytes @ 0x0 Read: OK | ||||||
|  | => md 0x10800000 | ||||||
|  | 10800000: ea000013 e59ff014 e59ff014 e59ff014    ................ | ||||||
|  | 10800010: e59ff014 e59ff014 e59ff014 e59ff014    ................ | ||||||
|  | 10800020: 1ff7b0c0 1ff7b120 1ff7b180 1ff7b1e0    .... ........... | ||||||
|  | 10800030: 1ff7b240 1ff7b2a0 1ff7b300 deadbeef    @............... | ||||||
|  | 10800040: 10800000 0002c1f0 0007409c 00032048    .........@..H .. | ||||||
|  | 10800050: 1fd6af40 e10f0000 e3c0001f e38000d3    @............... | ||||||
|  | 10800060: e129f000 eb000001 eb000223 e12fff1e    ..).....#...../. | ||||||
|  | 10800070: e3a00000 ee070f1e ee080f17 ee070f15    ................ | ||||||
|  | 10800080: ee070f9a ee110f10 e3c00c03 e3c00087    ................ | ||||||
|  | 10800090: e3c00a02 e3800002 e3800a01 ee010f10    ................ | ||||||
|  | 108000a0: e1a0c00e eb007a68 e1a0e00c e1a0f00e    ....hz.......... | ||||||
|  | 108000b0: e1a00000 e1a00000 e1a00000 e1a00000    ................ | ||||||
|  | 108000c0: e51fd078 e58de000 e14fe000 e58de004    x.........O..... | ||||||
|  | 108000d0: e3a0d013 e169f00d e1a0e00f e1b0f00e    ......i......... | ||||||
|  | 108000e0: e24dd048 e88d1fff e51f20a0 e892000c    H.M...... ...... | ||||||
|  | 108000f0: e28d0048 e28d5034 e1a0100e e885000f    H...4P.......... | ||||||
|  | @ -11,6 +11,11 @@ SPI FLASH (drivers/mtd/spi): | ||||||
| - Bank Address Register (Accessing flashes > 16Mbytes in 3-byte addressing) | - Bank Address Register (Accessing flashes > 16Mbytes in 3-byte addressing) | ||||||
| - Added memory_mapped support for read operations. | - Added memory_mapped support for read operations. | ||||||
| - Common probe support for all supported flash vendors except, ramtron. | - Common probe support for all supported flash vendors except, ramtron. | ||||||
|  | - 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. | ||||||
| 
 | 
 | ||||||
| SPI DRIVERS (drivers/spi): | SPI DRIVERS (drivers/spi): | ||||||
| - | - | ||||||
|  | @ -18,14 +23,10 @@ SPI DRIVERS (drivers/spi): | ||||||
| TODO: | TODO: | ||||||
| - Runtime detection of spi_flash params, SFDP(if possible) | - Runtime detection of spi_flash params, SFDP(if possible) | ||||||
| - Add support for multibus build/accessing. | - 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. | - Need proper cleanups on spi_flash and drivers. | ||||||
| 
 | 
 | ||||||
| -- | -- | ||||||
| Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com> | Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com> | ||||||
| 18-09-2013. | 18-09-2013. | ||||||
| 07-10-2013. | 07-10-2013. | ||||||
|  | 08-01-2014. | ||||||
|  |  | ||||||
|  | @ -10,8 +10,8 @@ obj-$(CONFIG_SPL_SPI_LOAD)	+= spi_spl_load.o | ||||||
| obj-$(CONFIG_SPL_SPI_BOOT)	+= fsl_espi_spl.o | obj-$(CONFIG_SPL_SPI_BOOT)	+= fsl_espi_spl.o | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| obj-$(CONFIG_CMD_SF)        += sf.o | obj-$(CONFIG_CMD_SF) += sf.o | ||||||
| obj-$(CONFIG_SPI_FLASH) += sf_probe.o sf_ops.o | obj-$(CONFIG_SPI_FLASH) += sf_params.o sf_probe.o sf_ops.o | ||||||
| obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o | obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o | ||||||
| obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o | obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o | ||||||
| obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o | obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o | ||||||
|  |  | ||||||
|  | @ -18,6 +18,10 @@ static int spi_flash_read_write(struct spi_slave *spi, | ||||||
| 	unsigned long flags = SPI_XFER_BEGIN; | 	unsigned long flags = SPI_XFER_BEGIN; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_SF_DUAL_FLASH | ||||||
|  | 	if (spi->flags & SPI_XFER_U_PAGE) | ||||||
|  | 		flags |= SPI_XFER_U_PAGE; | ||||||
|  | #endif | ||||||
| 	if (data_len == 0) | 	if (data_len == 0) | ||||||
| 		flags |= SPI_XFER_END; | 		flags |= SPI_XFER_END; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,12 +10,15 @@ | ||||||
| #ifndef _SF_INTERNAL_H_ | #ifndef _SF_INTERNAL_H_ | ||||||
| #define _SF_INTERNAL_H_ | #define _SF_INTERNAL_H_ | ||||||
| 
 | 
 | ||||||
|  | #define SPI_FLASH_3B_ADDR_LEN		3 | ||||||
|  | #define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN) | ||||||
| #define SPI_FLASH_16MB_BOUN		0x1000000 | #define SPI_FLASH_16MB_BOUN		0x1000000 | ||||||
| 
 | 
 | ||||||
| /* SECT flags */ | /* CFI Manufacture ID's */ | ||||||
| #define SECT_4K				(1 << 1) | #define SPI_FLASH_CFI_MFR_SPANSION	0x01 | ||||||
| #define SECT_32K			(1 << 2) | #define SPI_FLASH_CFI_MFR_STMICRO	0x20 | ||||||
| #define E_FSR				(1 << 3) | #define SPI_FLASH_CFI_MFR_MACRONIX	0xc2 | ||||||
|  | #define SPI_FLASH_CFI_MFR_WINBOND	0xef | ||||||
| 
 | 
 | ||||||
| /* Erase commands */ | /* Erase commands */ | ||||||
| #define CMD_ERASE_4K			0x20 | #define CMD_ERASE_4K			0x20 | ||||||
|  | @ -28,6 +31,7 @@ | ||||||
| #define CMD_PAGE_PROGRAM		0x02 | #define CMD_PAGE_PROGRAM		0x02 | ||||||
| #define CMD_WRITE_DISABLE		0x04 | #define CMD_WRITE_DISABLE		0x04 | ||||||
| #define CMD_READ_STATUS			0x05 | #define CMD_READ_STATUS			0x05 | ||||||
|  | #define CMD_QUAD_PAGE_PROGRAM		0x32 | ||||||
| #define CMD_READ_STATUS1		0x35 | #define CMD_READ_STATUS1		0x35 | ||||||
| #define CMD_WRITE_ENABLE		0x06 | #define CMD_WRITE_ENABLE		0x06 | ||||||
| #define CMD_READ_CONFIG			0x35 | #define CMD_READ_CONFIG			0x35 | ||||||
|  | @ -36,6 +40,10 @@ | ||||||
| /* Read commands */ | /* Read commands */ | ||||||
| #define CMD_READ_ARRAY_SLOW		0x03 | #define CMD_READ_ARRAY_SLOW		0x03 | ||||||
| #define CMD_READ_ARRAY_FAST		0x0b | #define CMD_READ_ARRAY_FAST		0x0b | ||||||
|  | #define CMD_READ_DUAL_OUTPUT_FAST	0x3b | ||||||
|  | #define CMD_READ_DUAL_IO_FAST		0xbb | ||||||
|  | #define CMD_READ_QUAD_OUTPUT_FAST	0x6b | ||||||
|  | #define CMD_READ_QUAD_IO_FAST		0xeb | ||||||
| #define CMD_READ_ID			0x9f | #define CMD_READ_ID			0x9f | ||||||
| 
 | 
 | ||||||
| /* Bank addr access commands */ | /* Bank addr access commands */ | ||||||
|  | @ -47,8 +55,10 @@ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* Common status */ | /* Common status */ | ||||||
| #define STATUS_WIP			0x01 | #define STATUS_WIP			(1 << 0) | ||||||
| #define STATUS_PEC			0x80 | #define STATUS_QEB_WINSPAN		(1 << 1) | ||||||
|  | #define STATUS_QEB_MXIC			(1 << 6) | ||||||
|  | #define STATUS_PEC			(1 << 7) | ||||||
| 
 | 
 | ||||||
| /* Flash timeout values */ | /* Flash timeout values */ | ||||||
| #define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ) | #define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ) | ||||||
|  | @ -86,11 +96,17 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, | ||||||
| /* Flash erase(sectors) operation, support all possible erase commands */ | /* Flash erase(sectors) operation, support all possible erase commands */ | ||||||
| int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); | ||||||
| 
 | 
 | ||||||
| /* Program the status register */ | /* Read the status register */ | ||||||
| int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); | int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); | ||||||
| 
 | 
 | ||||||
| /* Set quad enbale bit */ | /* Program the status register */ | ||||||
| int spi_flash_set_qeb(struct spi_flash *flash); | int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); | ||||||
|  | 
 | ||||||
|  | /* Read the config register */ | ||||||
|  | int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc); | ||||||
|  | 
 | ||||||
|  | /* Program the config register */ | ||||||
|  | int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc); | ||||||
| 
 | 
 | ||||||
| /* Enable writing on the SPI flash */ | /* Enable writing on the SPI flash */ | ||||||
| static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) | static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <common.h> | #include <common.h> | ||||||
|  | #include <malloc.h> | ||||||
| #include <spi.h> | #include <spi.h> | ||||||
| #include <spi_flash.h> | #include <spi_flash.h> | ||||||
| #include <watchdog.h> | #include <watchdog.h> | ||||||
|  | @ -23,13 +24,28 @@ static void spi_flash_addr(u32 addr, u8 *cmd) | ||||||
| 	cmd[3] = addr >> 0; | 	cmd[3] = addr >> 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) | int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 	u8 cmd; | ||||||
|  | 
 | ||||||
|  | 	cmd = CMD_READ_STATUS; | ||||||
|  | 	ret = spi_flash_read_common(flash, &cmd, 1, rs, 1); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		debug("SF: fail to read status register\n"); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws) | ||||||
| { | { | ||||||
| 	u8 cmd; | 	u8 cmd; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	cmd = CMD_WRITE_STATUS; | 	cmd = CMD_WRITE_STATUS; | ||||||
| 	ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); | 	ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		debug("SF: fail to write status register\n"); | 		debug("SF: fail to write status register\n"); | ||||||
| 		return ret; | 		return ret; | ||||||
|  | @ -38,6 +54,44 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | ||||||
|  | int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 	u8 cmd; | ||||||
|  | 
 | ||||||
|  | 	cmd = CMD_READ_CONFIG; | ||||||
|  | 	ret = spi_flash_read_common(flash, &cmd, 1, rc, 1); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		debug("SF: fail to read config register\n"); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) | ||||||
|  | { | ||||||
|  | 	u8 data[2]; | ||||||
|  | 	u8 cmd; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = spi_flash_cmd_read_status(flash, &data[0]); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	cmd = CMD_WRITE_STATUS; | ||||||
|  | 	data[1] = wc; | ||||||
|  | 	ret = spi_flash_write_common(flash, &cmd, 1, &data, 2); | ||||||
|  | 	if (ret) { | ||||||
|  | 		debug("SF: fail to write config register\n"); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef CONFIG_SPI_FLASH_BAR | #ifdef CONFIG_SPI_FLASH_BAR | ||||||
| static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) | static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) | ||||||
| { | { | ||||||
|  | @ -65,7 +119,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset) | ||||||
| 	u8 bank_sel; | 	u8 bank_sel; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	bank_sel = offset / SPI_FLASH_16MB_BOUN; | 	bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift); | ||||||
| 
 | 
 | ||||||
| 	ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | 	ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
|  | @ -73,7 +127,29 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset) | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return bank_sel; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_SF_DUAL_FLASH | ||||||
|  | static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr) | ||||||
|  | { | ||||||
|  | 	switch (flash->dual_flash) { | ||||||
|  | 	case SF_DUAL_STACKED_FLASH: | ||||||
|  | 		if (*addr >= (flash->size >> 1)) { | ||||||
|  | 			*addr -= flash->size >> 1; | ||||||
|  | 			flash->spi->flags |= SPI_XFER_U_PAGE; | ||||||
|  | 		} else { | ||||||
|  | 			flash->spi->flags &= ~SPI_XFER_U_PAGE; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case SF_DUAL_PARALLEL_FLASH: | ||||||
|  | 		*addr >>= flash->shift; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash); | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | @ -81,6 +157,7 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) | ||||||
| { | { | ||||||
| 	struct spi_slave *spi = flash->spi; | 	struct spi_slave *spi = flash->spi; | ||||||
| 	unsigned long timebase; | 	unsigned long timebase; | ||||||
|  | 	unsigned long flags = SPI_XFER_BEGIN; | ||||||
| 	int ret; | 	int ret; | ||||||
| 	u8 status; | 	u8 status; | ||||||
| 	u8 check_status = 0x0; | 	u8 check_status = 0x0; | ||||||
|  | @ -92,7 +169,11 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) | ||||||
| 		check_status = poll_bit; | 		check_status = poll_bit; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); | #ifdef CONFIG_SF_DUAL_FLASH | ||||||
|  | 	if (spi->flags & SPI_XFER_U_PAGE) | ||||||
|  | 		flags |= SPI_XFER_U_PAGE; | ||||||
|  | #endif | ||||||
|  | 	ret = spi_xfer(spi, 8, &cmd, NULL, flags); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		debug("SF: fail to read %s status register\n", | 		debug("SF: fail to read %s status register\n", | ||||||
| 		      cmd == CMD_READ_STATUS ? "read" : "flag"); | 		      cmd == CMD_READ_STATUS ? "read" : "flag"); | ||||||
|  | @ -165,8 +246,8 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, | ||||||
| 
 | 
 | ||||||
| int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) | ||||||
| { | { | ||||||
| 	u32 erase_size; | 	u32 erase_size, erase_addr; | ||||||
| 	u8 cmd[4]; | 	u8 cmd[SPI_FLASH_CMD_LEN]; | ||||||
| 	int ret = -1; | 	int ret = -1; | ||||||
| 
 | 
 | ||||||
| 	erase_size = flash->erase_size; | 	erase_size = flash->erase_size; | ||||||
|  | @ -177,15 +258,21 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) | ||||||
| 
 | 
 | ||||||
| 	cmd[0] = flash->erase_cmd; | 	cmd[0] = flash->erase_cmd; | ||||||
| 	while (len) { | 	while (len) { | ||||||
|  | 		erase_addr = offset; | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_SF_DUAL_FLASH | ||||||
|  | 		if (flash->dual_flash > SF_SINGLE_FLASH) | ||||||
|  | 			spi_flash_dual_flash(flash, &erase_addr); | ||||||
|  | #endif | ||||||
| #ifdef CONFIG_SPI_FLASH_BAR | #ifdef CONFIG_SPI_FLASH_BAR | ||||||
| 		ret = spi_flash_bank(flash, offset); | 		ret = spi_flash_bank(flash, erase_addr); | ||||||
| 		if (ret < 0) | 		if (ret < 0) | ||||||
| 			return ret; | 			return ret; | ||||||
| #endif | #endif | ||||||
| 		spi_flash_addr(offset, cmd); | 		spi_flash_addr(erase_addr, cmd); | ||||||
| 
 | 
 | ||||||
| 		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], | 		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], | ||||||
| 		      cmd[2], cmd[3], offset); | 		      cmd[2], cmd[3], erase_addr); | ||||||
| 
 | 
 | ||||||
| 		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); | 		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
|  | @ -204,16 +291,23 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, | ||||||
| 		size_t len, const void *buf) | 		size_t len, const void *buf) | ||||||
| { | { | ||||||
| 	unsigned long byte_addr, page_size; | 	unsigned long byte_addr, page_size; | ||||||
|  | 	u32 write_addr; | ||||||
| 	size_t chunk_len, actual; | 	size_t chunk_len, actual; | ||||||
| 	u8 cmd[4]; | 	u8 cmd[SPI_FLASH_CMD_LEN]; | ||||||
| 	int ret = -1; | 	int ret = -1; | ||||||
| 
 | 
 | ||||||
| 	page_size = flash->page_size; | 	page_size = flash->page_size; | ||||||
| 
 | 
 | ||||||
| 	cmd[0] = CMD_PAGE_PROGRAM; | 	cmd[0] = flash->write_cmd; | ||||||
| 	for (actual = 0; actual < len; actual += chunk_len) { | 	for (actual = 0; actual < len; actual += chunk_len) { | ||||||
|  | 		write_addr = offset; | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_SF_DUAL_FLASH | ||||||
|  | 		if (flash->dual_flash > SF_SINGLE_FLASH) | ||||||
|  | 			spi_flash_dual_flash(flash, &write_addr); | ||||||
|  | #endif | ||||||
| #ifdef CONFIG_SPI_FLASH_BAR | #ifdef CONFIG_SPI_FLASH_BAR | ||||||
| 		ret = spi_flash_bank(flash, offset); | 		ret = spi_flash_bank(flash, write_addr); | ||||||
| 		if (ret < 0) | 		if (ret < 0) | ||||||
| 			return ret; | 			return ret; | ||||||
| #endif | #endif | ||||||
|  | @ -223,9 +317,9 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, | ||||||
| 		if (flash->spi->max_write_size) | 		if (flash->spi->max_write_size) | ||||||
| 			chunk_len = min(chunk_len, flash->spi->max_write_size); | 			chunk_len = min(chunk_len, flash->spi->max_write_size); | ||||||
| 
 | 
 | ||||||
| 		spi_flash_addr(offset, cmd); | 		spi_flash_addr(write_addr, cmd); | ||||||
| 
 | 
 | ||||||
| 		debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", | 		debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", | ||||||
| 		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); | 		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); | ||||||
| 
 | 
 | ||||||
| 		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), | 		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), | ||||||
|  | @ -267,8 +361,9 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, | ||||||
| int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, | int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, | ||||||
| 		size_t len, void *data) | 		size_t len, void *data) | ||||||
| { | { | ||||||
| 	u8 cmd[5], bank_sel = 0; | 	u8 *cmd, cmdsz; | ||||||
| 	u32 remain_len, read_len; | 	u32 remain_len, read_len, read_addr; | ||||||
|  | 	int bank_sel = 0; | ||||||
| 	int ret = -1; | 	int ret = -1; | ||||||
| 
 | 
 | ||||||
| 	/* Handle memory-mapped SPI */ | 	/* Handle memory-mapped SPI */ | ||||||
|  | @ -285,29 +380,33 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cmd[0] = CMD_READ_ARRAY_FAST; | 	cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte; | ||||||
| 	cmd[4] = 0x00; | 	cmd = malloc(cmdsz); | ||||||
|  | 	memset(cmd, 0, cmdsz); | ||||||
| 
 | 
 | ||||||
|  | 	cmd[0] = flash->read_cmd; | ||||||
| 	while (len) { | 	while (len) { | ||||||
| #ifdef CONFIG_SPI_FLASH_BAR | 		read_addr = offset; | ||||||
| 		bank_sel = offset / SPI_FLASH_16MB_BOUN; |  | ||||||
| 
 | 
 | ||||||
| 		ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | #ifdef CONFIG_SF_DUAL_FLASH | ||||||
| 		if (ret) { | 		if (flash->dual_flash > SF_SINGLE_FLASH) | ||||||
| 			debug("SF: fail to set bank%d\n", bank_sel); | 			spi_flash_dual_flash(flash, &read_addr); | ||||||
| 			return ret; |  | ||||||
| 		} |  | ||||||
| #endif | #endif | ||||||
| 		remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset; | #ifdef CONFIG_SPI_FLASH_BAR | ||||||
|  | 		bank_sel = spi_flash_bank(flash, read_addr); | ||||||
|  | 		if (bank_sel < 0) | ||||||
|  | 			return ret; | ||||||
|  | #endif | ||||||
|  | 		remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) * | ||||||
|  | 				(bank_sel + 1)) - offset; | ||||||
| 		if (len < remain_len) | 		if (len < remain_len) | ||||||
| 			read_len = len; | 			read_len = len; | ||||||
| 		else | 		else | ||||||
| 			read_len = remain_len; | 			read_len = remain_len; | ||||||
| 
 | 
 | ||||||
| 		spi_flash_addr(offset, cmd); | 		spi_flash_addr(read_addr, cmd); | ||||||
| 
 | 
 | ||||||
| 		ret = spi_flash_read_common(flash, cmd, sizeof(cmd), | 		ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len); | ||||||
| 							data, read_len); |  | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			debug("SF: read failed\n"); | 			debug("SF: read failed\n"); | ||||||
| 			break; | 			break; | ||||||
|  |  | ||||||
|  | @ -0,0 +1,130 @@ | ||||||
|  | /*
 | ||||||
|  |  * SPI flash Params table | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier:	GPL-2.0+ | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <common.h> | ||||||
|  | #include <spi_flash.h> | ||||||
|  | 
 | ||||||
|  | #include "sf_internal.h" | ||||||
|  | 
 | ||||||
|  | /* SPI/QSPI flash device params structure */ | ||||||
|  | const struct spi_flash_params spi_flash_params_table[] = { | ||||||
|  | #ifdef CONFIG_SPI_FLASH_ATMEL		/* ATMEL */ | ||||||
|  | 	{"AT45DB011D",	   0x1f2200, 0x0,	64 * 1024,     4,	0,		    SECT_4K}, | ||||||
|  | 	{"AT45DB021D",	   0x1f2300, 0x0,	64 * 1024,     8,	0,		    SECT_4K}, | ||||||
|  | 	{"AT45DB041D",	   0x1f2400, 0x0,	64 * 1024,     8,	0,		    SECT_4K}, | ||||||
|  | 	{"AT45DB081D",	   0x1f2500, 0x0,	64 * 1024,    16,	0,		    SECT_4K}, | ||||||
|  | 	{"AT45DB161D",	   0x1f2600, 0x0,	64 * 1024,    32,	0,		    SECT_4K}, | ||||||
|  | 	{"AT45DB321D",	   0x1f2700, 0x0,	64 * 1024,    64,	0,		    SECT_4K}, | ||||||
|  | 	{"AT45DB641D",	   0x1f2800, 0x0,	64 * 1024,   128,	0,		    SECT_4K}, | ||||||
|  | 	{"AT25DF321",      0x1f4701, 0x0,	64 * 1024,    64,	0,		    SECT_4K}, | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_SPI_FLASH_EON		/* EON */ | ||||||
|  | 	{"EN25Q32B",	   0x1c3016, 0x0,	64 * 1024,    64,	0,			  0}, | ||||||
|  | 	{"EN25Q64",	   0x1c3017, 0x0,	64 * 1024,   128,	0,		    SECT_4K}, | ||||||
|  | 	{"EN25Q128B",	   0x1c3018, 0x0,       64 * 1024,   256,	0,			  0}, | ||||||
|  | 	{"EN25S64",	   0x1c3817, 0x0,	64 * 1024,   128,	0,			  0}, | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_SPI_FLASH_GIGADEVICE	/* GIGADEVICE */ | ||||||
|  | 	{"GD25Q64B",	   0xc84017, 0x0,	64 * 1024,   128,	0,		    SECT_4K}, | ||||||
|  | 	{"GD25LQ32",	   0xc86016, 0x0,	64 * 1024,    64,	0,		    SECT_4K}, | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_SPI_FLASH_MACRONIX	/* MACRONIX */ | ||||||
|  | 	{"MX25L2006E",	   0xc22012, 0x0,	64 * 1024,     4,	0,			  0}, | ||||||
|  | 	{"MX25L4005",	   0xc22013, 0x0,	64 * 1024,     8,	0,			  0}, | ||||||
|  | 	{"MX25L8005",	   0xc22014, 0x0,	64 * 1024,    16,	0,			  0}, | ||||||
|  | 	{"MX25L1605D",	   0xc22015, 0x0,	64 * 1024,    32,	0,			  0}, | ||||||
|  | 	{"MX25L3205D",	   0xc22016, 0x0,	64 * 1024,    64,	0,			  0}, | ||||||
|  | 	{"MX25L6405D",	   0xc22017, 0x0,	64 * 1024,   128,	0,			  0}, | ||||||
|  | 	{"MX25L12805",	   0xc22018, 0x0,	64 * 1024,   256, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"MX25L25635F",	   0xc22019, 0x0,	64 * 1024,   512, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"MX25L51235F",	   0xc2201a, 0x0,	64 * 1024,  1024, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"MX25L12855E",	   0xc22618, 0x0,	64 * 1024,   256, RD_FULL,		     WR_QPP}, | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_SPI_FLASH_SPANSION	/* SPANSION */ | ||||||
|  | 	{"S25FL008A",	   0x010213, 0x0,	64 * 1024,    16,	0,			  0}, | ||||||
|  | 	{"S25FL016A",	   0x010214, 0x0,	64 * 1024,    32,	0,			  0}, | ||||||
|  | 	{"S25FL032A",	   0x010215, 0x0,	64 * 1024,    64,	0,			  0}, | ||||||
|  | 	{"S25FL064A",	   0x010216, 0x0,	64 * 1024,   128,	0,			  0}, | ||||||
|  | 	{"S25FL128P_256K", 0x012018, 0x0300,   256 * 1024,    64, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"S25FL128P_64K",  0x012018, 0x0301,    64 * 1024,   256, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"S25FL032P",	   0x010215, 0x4d00,    64 * 1024,    64, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"S25FL064P",	   0x010216, 0x4d00,    64 * 1024,   128, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"S25FL128S_64K",  0x012018, 0x4d01,    64 * 1024,   256, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"S25FL256S_256K", 0x010219, 0x4d00,    64 * 1024,   512, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"S25FL256S_64K",  0x010219, 0x4d01,	64 * 1024,   512, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"S25FL512S_256K", 0x010220, 0x4d00,    64 * 1024,  1024, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"S25FL512S_64K",  0x010220, 0x4d01,    64 * 1024,  1024, RD_FULL,		     WR_QPP}, | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_SPI_FLASH_STMICRO		/* STMICRO */ | ||||||
|  | 	{"M25P10",	   0x202011, 0x0,	32 * 1024,     4,	0,			  0}, | ||||||
|  | 	{"M25P20",	   0x202012, 0x0,       64 * 1024,     4,	0,			  0}, | ||||||
|  | 	{"M25P40",	   0x202013, 0x0,       64 * 1024,     8,	0,			  0}, | ||||||
|  | 	{"M25P80",	   0x202014, 0x0,       64 * 1024,    16,	0,			  0}, | ||||||
|  | 	{"M25P16",	   0x202015, 0x0,       64 * 1024,    32,	0,			  0}, | ||||||
|  | 	{"M25P32",	   0x202016, 0x0,       64 * 1024,    64,	0,			  0}, | ||||||
|  | 	{"M25P64",	   0x202017, 0x0,       64 * 1024,   128,	0,			  0}, | ||||||
|  | 	{"M25P128",	   0x202018, 0x0,      256 * 1024,    64,	0,			  0}, | ||||||
|  | 	{"N25Q32",	   0x20ba16, 0x0,       64 * 1024,    64, RD_FULL,	   WR_QPP | SECT_4K}, | ||||||
|  | 	{"N25Q32A",	   0x20bb16, 0x0,       64 * 1024,    64, RD_FULL,	   WR_QPP | SECT_4K}, | ||||||
|  | 	{"N25Q64",	   0x20ba17, 0x0,       64 * 1024,   128, RD_FULL,	   WR_QPP | SECT_4K}, | ||||||
|  | 	{"N25Q64A",	   0x20bb17, 0x0,       64 * 1024,   128, RD_FULL,	   WR_QPP | SECT_4K}, | ||||||
|  | 	{"N25Q128",	   0x20ba18, 0x0,       64 * 1024,   256, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"N25Q128A",	   0x20bb18, 0x0,       64 * 1024,   256, RD_FULL,		     WR_QPP}, | ||||||
|  | 	{"N25Q256",	   0x20ba19, 0x0,       64 * 1024,   512, RD_FULL,	   WR_QPP | SECT_4K}, | ||||||
|  | 	{"N25Q256A",	   0x20bb19, 0x0,       64 * 1024,   512, RD_FULL,	   WR_QPP | SECT_4K}, | ||||||
|  | 	{"N25Q512",	   0x20ba20, 0x0,       64 * 1024,  1024, RD_FULL, WR_QPP | E_FSR | SECT_4K}, | ||||||
|  | 	{"N25Q512A",	   0x20bb20, 0x0,       64 * 1024,  1024, RD_FULL, WR_QPP | E_FSR | SECT_4K}, | ||||||
|  | 	{"N25Q1024",	   0x20ba21, 0x0,       64 * 1024,  2048, RD_FULL, WR_QPP | E_FSR | SECT_4K}, | ||||||
|  | 	{"N25Q1024A",	   0x20bb21, 0x0,       64 * 1024,  2048, RD_FULL, WR_QPP | E_FSR | SECT_4K}, | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_SPI_FLASH_SST		/* SST */ | ||||||
|  | 	{"SST25VF040B",	   0xbf258d, 0x0,	64 * 1024,     8,	0,          SECT_4K | SST_WP}, | ||||||
|  | 	{"SST25VF080B",	   0xbf258e, 0x0,	64 * 1024,    16,	0,	    SECT_4K | SST_WP}, | ||||||
|  | 	{"SST25VF016B",	   0xbf2541, 0x0,	64 * 1024,    32,	0,	    SECT_4K | SST_WP}, | ||||||
|  | 	{"SST25VF032B",	   0xbf254a, 0x0,	64 * 1024,    64,	0,	    SECT_4K | SST_WP}, | ||||||
|  | 	{"SST25VF064C",	   0xbf254b, 0x0,	64 * 1024,   128,	0,		     SECT_4K}, | ||||||
|  | 	{"SST25WF512",	   0xbf2501, 0x0,	64 * 1024,     1,	0,	    SECT_4K | SST_WP}, | ||||||
|  | 	{"SST25WF010",	   0xbf2502, 0x0,	64 * 1024,     2,       0,          SECT_4K | SST_WP}, | ||||||
|  | 	{"SST25WF020",	   0xbf2503, 0x0,	64 * 1024,     4,       0,	    SECT_4K | SST_WP}, | ||||||
|  | 	{"SST25WF040",	   0xbf2504, 0x0,	64 * 1024,     8,       0,	    SECT_4K | SST_WP}, | ||||||
|  | 	{"SST25WF080",	   0xbf2505, 0x0,	64 * 1024,    16,       0,	    SECT_4K | SST_WP}, | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_SPI_FLASH_WINBOND		/* WINBOND */ | ||||||
|  | 	{"W25P80",	   0xef2014, 0x0,	64 * 1024,    16,	0,		           0}, | ||||||
|  | 	{"W25P16",	   0xef2015, 0x0,	64 * 1024,    32,	0,		           0}, | ||||||
|  | 	{"W25P32",	   0xef2016, 0x0,	64 * 1024,    64,	0,		           0}, | ||||||
|  | 	{"W25X40",	   0xef3013, 0x0,	64 * 1024,     8,	0,		     SECT_4K}, | ||||||
|  | 	{"W25X16",	   0xef3015, 0x0,	64 * 1024,    32,	0,		     SECT_4K}, | ||||||
|  | 	{"W25X32",	   0xef3016, 0x0,	64 * 1024,    64,	0,		     SECT_4K}, | ||||||
|  | 	{"W25X64",	   0xef3017, 0x0,	64 * 1024,   128,	0,		     SECT_4K}, | ||||||
|  | 	{"W25Q80BL",	   0xef4014, 0x0,	64 * 1024,    16, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q16CL",	   0xef4015, 0x0,	64 * 1024,    32, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q32BV",	   0xef4016, 0x0,	64 * 1024,    64, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q64CV",	   0xef4017, 0x0,	64 * 1024,   128, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q128BV",	   0xef4018, 0x0,	64 * 1024,   256, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q256",	   0xef4019, 0x0,	64 * 1024,   512, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q80BW",	   0xef5014, 0x0,	64 * 1024,    16, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q16DW",	   0xef6015, 0x0,	64 * 1024,    32, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q32DW",	   0xef6016, 0x0,	64 * 1024,    64, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q64DW",	   0xef6017, 0x0,	64 * 1024,   128, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | 	{"W25Q128FW",	   0xef6018, 0x0,	64 * 1024,   256, RD_FULL,	    WR_QPP | SECT_4K}, | ||||||
|  | #endif | ||||||
|  | 	/*
 | ||||||
|  | 	 * Note: | ||||||
|  | 	 * Below paired flash devices has similar spi_flash 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) | ||||||
|  | 	 */ | ||||||
|  | }; | ||||||
|  | @ -19,154 +19,93 @@ | ||||||
| 
 | 
 | ||||||
| DECLARE_GLOBAL_DATA_PTR; | DECLARE_GLOBAL_DATA_PTR; | ||||||
| 
 | 
 | ||||||
| /**
 | /* Read commands array */ | ||||||
|  * struct spi_flash_params - SPI/QSPI flash device params structure | static u8 spi_read_cmds_array[] = { | ||||||
|  * | 	CMD_READ_ARRAY_SLOW, | ||||||
|  * @name:		Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) | 	CMD_READ_DUAL_OUTPUT_FAST, | ||||||
|  * @jedec:		Device jedec ID (0x[1byte_manuf_id][2byte_dev_id]) | 	CMD_READ_DUAL_IO_FAST, | ||||||
|  * @ext_jedec:		Device ext_jedec ID | 	CMD_READ_QUAD_OUTPUT_FAST, | ||||||
|  * @sector_size:	Sector size of this device | 	CMD_READ_QUAD_IO_FAST, | ||||||
|  * @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_MACRONIX | ||||||
| #ifdef CONFIG_SPI_FLASH_ATMEL		/* ATMEL */ | static int spi_flash_set_qeb_mxic(struct spi_flash *flash) | ||||||
| 	{"AT45DB011D",	   0x1f2200, 0x0,	64 * 1024,     4,	       SECT_4K}, | { | ||||||
| 	{"AT45DB021D",	   0x1f2300, 0x0,	64 * 1024,     8,	       SECT_4K}, | 	u8 qeb_status; | ||||||
| 	{"AT45DB041D",	   0x1f2400, 0x0,	64 * 1024,     8,	       SECT_4K}, | 	int ret; | ||||||
| 	{"AT45DB081D",	   0x1f2500, 0x0,	64 * 1024,    16,	       SECT_4K}, | 
 | ||||||
| 	{"AT45DB161D",	   0x1f2600, 0x0,	64 * 1024,    32,	       SECT_4K}, | 	ret = spi_flash_cmd_read_status(flash, &qeb_status); | ||||||
| 	{"AT45DB321D",	   0x1f2700, 0x0,	64 * 1024,    64,	       SECT_4K}, | 	if (ret < 0) | ||||||
| 	{"AT45DB641D",	   0x1f2800, 0x0,	64 * 1024,   128,	       SECT_4K}, | 		return ret; | ||||||
| 	{"AT25DF321",      0x1f4701, 0x0,	64 * 1024,    64,	       SECT_4K}, | 
 | ||||||
|  | 	if (qeb_status & STATUS_QEB_MXIC) { | ||||||
|  | 		debug("SF: mxic: QEB is already set\n"); | ||||||
|  | 	} else { | ||||||
|  | 		ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); | ||||||
|  | 		if (ret < 0) | ||||||
|  | 			return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef CONFIG_SPI_FLASH_EON		/* EON */ | 
 | ||||||
| 	{"EN25Q32B",	   0x1c3016, 0x0,	64 * 1024,    64,	             0}, | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | ||||||
| 	{"EN25Q64",	   0x1c3017, 0x0,	64 * 1024,   128,	       SECT_4K}, | static int spi_flash_set_qeb_winspan(struct spi_flash *flash) | ||||||
| 	{"EN25Q128B",	   0x1c3018, 0x0,       64 * 1024,   256,	             0}, | { | ||||||
| 	{"EN25S64",	   0x1c3817, 0x0,	64 * 1024,   128,		     0}, | 	u8 qeb_status; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = spi_flash_cmd_read_config(flash, &qeb_status); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	if (qeb_status & STATUS_QEB_WINSPAN) { | ||||||
|  | 		debug("SF: winspan: QEB is already set\n"); | ||||||
|  | 	} else { | ||||||
|  | 		ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); | ||||||
|  | 		if (ret < 0) | ||||||
|  | 			return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
| #endif | #endif | ||||||
| #ifdef CONFIG_SPI_FLASH_GIGADEVICE	/* GIGADEVICE */ | 
 | ||||||
| 	{"GD25Q64B",	   0xc84017, 0x0,	64 * 1024,   128,	       SECT_4K}, | static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) | ||||||
| 	{"GD25LQ32",	   0xc86016, 0x0,	64 * 1024,    64,	       SECT_4K}, | { | ||||||
|  | 	switch (idcode0) { | ||||||
|  | #ifdef CONFIG_SPI_FLASH_MACRONIX | ||||||
|  | 	case SPI_FLASH_CFI_MFR_MACRONIX: | ||||||
|  | 		return spi_flash_set_qeb_mxic(flash); | ||||||
| #endif | #endif | ||||||
| #ifdef CONFIG_SPI_FLASH_MACRONIX	/* MACRONIX */ | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | ||||||
| 	{"MX25L2006E",	   0xc22012, 0x0,	64 * 1024,     4,	             0}, | 	case SPI_FLASH_CFI_MFR_SPANSION: | ||||||
| 	{"MX25L4005",	   0xc22013, 0x0,	64 * 1024,     8,	             0}, | 	case SPI_FLASH_CFI_MFR_WINBOND: | ||||||
| 	{"MX25L8005",	   0xc22014, 0x0,	64 * 1024,    16,	             0}, | 		return spi_flash_set_qeb_winspan(flash); | ||||||
| 	{"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 | #endif | ||||||
| #ifdef CONFIG_SPI_FLASH_SPANSION	/* SPANSION */ | #ifdef CONFIG_SPI_FLASH_STMICRO | ||||||
| 	{"S25FL008A",	   0x010213, 0x0,	64 * 1024,    16,	             0}, | 	case SPI_FLASH_CFI_MFR_STMICRO: | ||||||
| 	{"S25FL016A",	   0x010214, 0x0,	64 * 1024,    32,	             0}, | 		debug("SF: QEB is volatile for %02x flash\n", idcode0); | ||||||
| 	{"S25FL032A",	   0x010215, 0x0,	64 * 1024,    64,	             0}, | 		return 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 | #endif | ||||||
| #ifdef CONFIG_SPI_FLASH_STMICRO		/* STMICRO */ | 	default: | ||||||
| 	{"M25P10",	   0x202011, 0x0,       32 * 1024,     4,	             0}, | 		printf("SF: Need set QEB func for %02x flash\n", idcode0); | ||||||
| 	{"M25P20",	   0x202012, 0x0,       64 * 1024,     4,	             0}, | 		return -1; | ||||||
| 	{"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. |  | ||||||
| 	 * (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, | static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, | ||||||
| 		u8 *idcode) | 		u8 *idcode) | ||||||
| { | { | ||||||
| 	const struct spi_flash_params *params; | 	const struct spi_flash_params *params; | ||||||
| 	struct spi_flash *flash; | 	struct spi_flash *flash; | ||||||
| 	int i; | 	u8 cmd; | ||||||
| 	u16 jedec = idcode[1] << 8 | idcode[2]; | 	u16 jedec = idcode[1] << 8 | idcode[2]; | ||||||
| 	u16 ext_jedec = idcode[3] << 8 | idcode[4]; | 	u16 ext_jedec = idcode[3] << 8 | idcode[4]; | ||||||
| 
 | 
 | ||||||
| 	/* Get the flash id (jedec = manuf_id + dev_id, ext_jedec) */ | 	params = spi_flash_params_table; | ||||||
| 	for (i = 0; i < ARRAY_SIZE(spi_flash_params_table); i++) { | 	for (; params->name != NULL; params++) { | ||||||
| 		params = &spi_flash_params_table[i]; |  | ||||||
| 		if ((params->jedec >> 16) == idcode[0]) { | 		if ((params->jedec >> 16) == idcode[0]) { | ||||||
| 			if ((params->jedec & 0xFFFF) == jedec) { | 			if ((params->jedec & 0xFFFF) == jedec) { | ||||||
| 				if (params->ext_jedec == 0) | 				if (params->ext_jedec == 0) | ||||||
|  | @ -177,7 +116,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (i == ARRAY_SIZE(spi_flash_params_table)) { | 	if (!params->name) { | ||||||
| 		printf("SF: Unsupported flash IDs: "); | 		printf("SF: Unsupported flash IDs: "); | ||||||
| 		printf("manuf %02x, jedec %04x, ext_jedec %04x\n", | 		printf("manuf %02x, jedec %04x, ext_jedec %04x\n", | ||||||
| 		       idcode[0], jedec, ext_jedec); | 		       idcode[0], jedec, ext_jedec); | ||||||
|  | @ -195,6 +134,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, | ||||||
| 	flash->spi = spi; | 	flash->spi = spi; | ||||||
| 	flash->name = params->name; | 	flash->name = params->name; | ||||||
| 	flash->memory_map = spi->memory_map; | 	flash->memory_map = spi->memory_map; | ||||||
|  | 	flash->dual_flash = flash->spi->option; | ||||||
| 
 | 
 | ||||||
| 	/* Assign spi_flash ops */ | 	/* Assign spi_flash ops */ | ||||||
| 	flash->write = spi_flash_cmd_write_ops; | 	flash->write = spi_flash_cmd_write_ops; | ||||||
|  | @ -206,23 +146,74 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, | ||||||
| 	flash->read = spi_flash_cmd_read_ops; | 	flash->read = spi_flash_cmd_read_ops; | ||||||
| 
 | 
 | ||||||
| 	/* Compute the flash size */ | 	/* Compute the flash size */ | ||||||
| 	flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; | 	flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; | ||||||
| 	flash->sector_size = params->sector_size; | 	flash->page_size = ((ext_jedec == 0x4d00) ? 512 : 256) << flash->shift; | ||||||
| 	flash->size = flash->sector_size * params->nr_sectors; | 	flash->sector_size = params->sector_size << flash->shift; | ||||||
|  | 	flash->size = flash->sector_size * params->nr_sectors << flash->shift; | ||||||
|  | #ifdef CONFIG_SF_DUAL_FLASH | ||||||
|  | 	if (flash->dual_flash & SF_DUAL_STACKED_FLASH) | ||||||
|  | 		flash->size <<= 1; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	/* Compute erase sector and command */ | 	/* Compute erase sector and command */ | ||||||
| 	if (params->flags & SECT_4K) { | 	if (params->flags & SECT_4K) { | ||||||
| 		flash->erase_cmd = CMD_ERASE_4K; | 		flash->erase_cmd = CMD_ERASE_4K; | ||||||
| 		flash->erase_size = 4096; | 		flash->erase_size = 4096 << flash->shift; | ||||||
| 	} else if (params->flags & SECT_32K) { | 	} else if (params->flags & SECT_32K) { | ||||||
| 		flash->erase_cmd = CMD_ERASE_32K; | 		flash->erase_cmd = CMD_ERASE_32K; | ||||||
| 		flash->erase_size = 32768; | 		flash->erase_size = 32768 << flash->shift; | ||||||
| 	} else { | 	} else { | ||||||
| 		flash->erase_cmd = CMD_ERASE_64K; | 		flash->erase_cmd = CMD_ERASE_64K; | ||||||
| 		flash->erase_size = flash->sector_size; | 		flash->erase_size = flash->sector_size; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Poll cmd seclection */ | 	/* Look for the fastest read cmd */ | ||||||
|  | 	cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); | ||||||
|  | 	if (cmd) { | ||||||
|  | 		cmd = spi_read_cmds_array[cmd - 1]; | ||||||
|  | 		flash->read_cmd = cmd; | ||||||
|  | 	} else { | ||||||
|  | 		/* Go for default supported read cmd */ | ||||||
|  | 		flash->read_cmd = CMD_READ_ARRAY_FAST; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Not require to look for fastest only two write cmds yet */ | ||||||
|  | 	if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) | ||||||
|  | 		flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; | ||||||
|  | 	else | ||||||
|  | 		/* Go for default supported write cmd */ | ||||||
|  | 		flash->write_cmd = CMD_PAGE_PROGRAM; | ||||||
|  | 
 | ||||||
|  | 	/* Set the quad enable bit - only for quad commands */ | ||||||
|  | 	if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || | ||||||
|  | 	    (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || | ||||||
|  | 	    (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { | ||||||
|  | 		if (spi_flash_set_qeb(flash, idcode[0])) { | ||||||
|  | 			debug("SF: Fail to set QEB for %02x\n", idcode[0]); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Read dummy_byte: dummy byte is determined based on the
 | ||||||
|  | 	 * dummy cycles of a particular command. | ||||||
|  | 	 * Fast commands - dummy_byte = dummy_cycles/8 | ||||||
|  | 	 * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 | ||||||
|  | 	 * For I/O commands except cmd[0] everything goes on no.of lines | ||||||
|  | 	 * based on particular command but incase of fast commands except | ||||||
|  | 	 * data all go on single line irrespective of command. | ||||||
|  | 	 */ | ||||||
|  | 	switch (flash->read_cmd) { | ||||||
|  | 	case CMD_READ_QUAD_IO_FAST: | ||||||
|  | 		flash->dummy_byte = 2; | ||||||
|  | 		break; | ||||||
|  | 	case CMD_READ_ARRAY_SLOW: | ||||||
|  | 		flash->dummy_byte = 0; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		flash->dummy_byte = 1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Poll cmd selection */ | ||||||
| 	flash->poll_cmd = CMD_READ_STATUS; | 	flash->poll_cmd = CMD_READ_STATUS; | ||||||
| #ifdef CONFIG_SPI_FLASH_STMICRO | #ifdef CONFIG_SPI_FLASH_STMICRO | ||||||
| 	if (params->flags & E_FSR) | 	if (params->flags & E_FSR) | ||||||
|  | @ -339,7 +330,10 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) | ||||||
| 	puts("\n"); | 	puts("\n"); | ||||||
| #endif | #endif | ||||||
| #ifndef CONFIG_SPI_FLASH_BAR | #ifndef CONFIG_SPI_FLASH_BAR | ||||||
| 	if (flash->size > SPI_FLASH_16MB_BOUN) { | 	if (((flash->dual_flash == SF_SINGLE_FLASH) && | ||||||
|  | 	     (flash->size > SPI_FLASH_16MB_BOUN)) || | ||||||
|  | 	     ((flash->dual_flash > SF_SINGLE_FLASH) && | ||||||
|  | 	     (flash->size > SPI_FLASH_16MB_BOUN << 1))) { | ||||||
| 		puts("SF: Warning - Only lower 16MiB accessible,"); | 		puts("SF: Warning - Only lower 16MiB accessible,"); | ||||||
| 		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); | 		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ obj-$(CONFIG_CF_SPI) += cf_spi.o | ||||||
| obj-$(CONFIG_CF_QSPI) += cf_qspi.o | obj-$(CONFIG_CF_QSPI) += cf_qspi.o | ||||||
| obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o | obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o | ||||||
| obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o | obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o | ||||||
|  | obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o | ||||||
| obj-$(CONFIG_ICH_SPI) +=  ich.o | obj-$(CONFIG_ICH_SPI) +=  ich.o | ||||||
| obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o | obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o | ||||||
| obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o | obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o | ||||||
|  |  | ||||||
|  | @ -0,0 +1,508 @@ | ||||||
|  | /*
 | ||||||
|  |  * (C) Copyright 2013 | ||||||
|  |  * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
 | ||||||
|  |  * Kuo-Jung Su <dantesu@gmail.com> | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier:     GPL-2.0+ | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <common.h> | ||||||
|  | #include <linux/compat.h> | ||||||
|  | #include <asm/io.h> | ||||||
|  | #include <malloc.h> | ||||||
|  | #include <spi.h> | ||||||
|  | 
 | ||||||
|  | #ifndef CONFIG_FTSSP010_BASE_LIST | ||||||
|  | #define CONFIG_FTSSP010_BASE_LIST   { CONFIG_FTSSP010_BASE } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef CONFIG_FTSSP010_GPIO_BASE | ||||||
|  | #define CONFIG_FTSSP010_GPIO_BASE   0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef CONFIG_FTSSP010_GPIO_LIST | ||||||
|  | #define CONFIG_FTSSP010_GPIO_LIST   { CONFIG_FTSSP010_GPIO_BASE } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef CONFIG_FTSSP010_CLOCK | ||||||
|  | #define CONFIG_FTSSP010_CLOCK       clk_get_rate("SSP"); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef CONFIG_FTSSP010_TIMEOUT | ||||||
|  | #define CONFIG_FTSSP010_TIMEOUT     100 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* FTSSP010 chip registers */ | ||||||
|  | struct ftssp010_regs { | ||||||
|  | 	uint32_t cr[3];/* control register */ | ||||||
|  | 	uint32_t sr;   /* status register */ | ||||||
|  | 	uint32_t icr;  /* interrupt control register */ | ||||||
|  | 	uint32_t isr;  /* interrupt status register */ | ||||||
|  | 	uint32_t dr;   /* data register */ | ||||||
|  | 	uint32_t rsvd[17]; | ||||||
|  | 	uint32_t revr; /* revision register */ | ||||||
|  | 	uint32_t fear; /* feature register */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Control Register 0  */ | ||||||
|  | #define CR0_FFMT_MASK       (7 << 12) | ||||||
|  | #define CR0_FFMT_SSP        (0 << 12) | ||||||
|  | #define CR0_FFMT_SPI        (1 << 12) | ||||||
|  | #define CR0_FFMT_MICROWIRE  (2 << 12) | ||||||
|  | #define CR0_FFMT_I2S        (3 << 12) | ||||||
|  | #define CR0_FFMT_AC97       (4 << 12) | ||||||
|  | #define CR0_FLASH           (1 << 11) | ||||||
|  | #define CR0_FSDIST(x)       (((x) & 0x03) << 8) | ||||||
|  | #define CR0_LOOP            (1 << 7)  /* loopback mode */ | ||||||
|  | #define CR0_LSB             (1 << 6)  /* LSB */ | ||||||
|  | #define CR0_FSPO            (1 << 5)  /* fs atcive low (I2S only) */ | ||||||
|  | #define CR0_FSJUSTIFY       (1 << 4) | ||||||
|  | #define CR0_OPM_SLAVE       (0 << 2) | ||||||
|  | #define CR0_OPM_MASTER      (3 << 2) | ||||||
|  | #define CR0_OPM_I2S_MSST    (3 << 2)  /* master stereo mode */ | ||||||
|  | #define CR0_OPM_I2S_MSMO    (2 << 2)  /* master mono mode */ | ||||||
|  | #define CR0_OPM_I2S_SLST    (1 << 2)  /* slave stereo mode */ | ||||||
|  | #define CR0_OPM_I2S_SLMO    (0 << 2)  /* slave mono mode */ | ||||||
|  | #define CR0_SCLKPO          (1 << 1)  /* clock polarity */ | ||||||
|  | #define CR0_SCLKPH          (1 << 0)  /* clock phase */ | ||||||
|  | 
 | ||||||
|  | /* Control Register 1 */ | ||||||
|  | #define CR1_PDL(x)   (((x) & 0xff) << 24) /* padding length */ | ||||||
|  | #define CR1_SDL(x)   ((((x) - 1) & 0x1f) << 16) /* data length */ | ||||||
|  | #define CR1_DIV(x)   (((x) - 1) & 0xffff) /* clock divider */ | ||||||
|  | 
 | ||||||
|  | /* Control Register 2 */ | ||||||
|  | #define CR2_CS(x)    (((x) & 3) << 10) /* CS/FS select */ | ||||||
|  | #define CR2_FS       (1 << 9) /* CS/FS signal level */ | ||||||
|  | #define CR2_TXEN     (1 << 8) /* tx enable */ | ||||||
|  | #define CR2_RXEN     (1 << 7) /* rx enable */ | ||||||
|  | #define CR2_RESET    (1 << 6) /* chip reset */ | ||||||
|  | #define CR2_TXFC     (1 << 3) /* tx fifo Clear */ | ||||||
|  | #define CR2_RXFC     (1 << 2) /* rx fifo Clear */ | ||||||
|  | #define CR2_TXDOE    (1 << 1) /* tx data output enable */ | ||||||
|  | #define CR2_EN       (1 << 0) /* chip enable */ | ||||||
|  | 
 | ||||||
|  | /* Status Register */ | ||||||
|  | #define SR_RFF       (1 << 0) /* rx fifo full */ | ||||||
|  | #define SR_TFNF      (1 << 1) /* tx fifo not full */ | ||||||
|  | #define SR_BUSY      (1 << 2) /* chip busy */ | ||||||
|  | #define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* rx fifo valid entries */ | ||||||
|  | #define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* tx fifo valid entries */ | ||||||
|  | 
 | ||||||
|  | /* Feature Register */ | ||||||
|  | #define FEAR_BITS(reg)   ((((reg) >>  0) & 0xff) + 1) /* data width */ | ||||||
|  | #define FEAR_RFSZ(reg)   ((((reg) >>  8) & 0xff) + 1) /* rx fifo size */ | ||||||
|  | #define FEAR_TFSZ(reg)   ((((reg) >> 16) & 0xff) + 1) /* tx fifo size */ | ||||||
|  | #define FEAR_AC97        (1 << 24) | ||||||
|  | #define FEAR_I2S         (1 << 25) | ||||||
|  | #define FEAR_SPI_MWR     (1 << 26) | ||||||
|  | #define FEAR_SSP         (1 << 27) | ||||||
|  | #define FEAR_SPDIF       (1 << 28) | ||||||
|  | 
 | ||||||
|  | /* FTGPIO010 chip registers */ | ||||||
|  | struct ftgpio010_regs { | ||||||
|  | 	uint32_t out;     /* 0x00: Data Output */ | ||||||
|  | 	uint32_t in;      /* 0x04: Data Input */ | ||||||
|  | 	uint32_t dir;     /* 0x08: Direction */ | ||||||
|  | 	uint32_t bypass;  /* 0x0c: Bypass */ | ||||||
|  | 	uint32_t set;     /* 0x10: Data Set */ | ||||||
|  | 	uint32_t clr;     /* 0x14: Data Clear */ | ||||||
|  | 	uint32_t pull_up; /* 0x18: Pull-Up Enabled */ | ||||||
|  | 	uint32_t pull_st; /* 0x1c: Pull State (0=pull-down, 1=pull-up) */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ftssp010_gpio { | ||||||
|  | 	struct ftgpio010_regs *regs; | ||||||
|  | 	uint32_t pin; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct ftssp010_spi { | ||||||
|  | 	struct spi_slave slave; | ||||||
|  | 	struct ftssp010_gpio gpio; | ||||||
|  | 	struct ftssp010_regs *regs; | ||||||
|  | 	uint32_t fifo; | ||||||
|  | 	uint32_t mode; | ||||||
|  | 	uint32_t div; | ||||||
|  | 	uint32_t clk; | ||||||
|  | 	uint32_t speed; | ||||||
|  | 	uint32_t revision; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static inline struct ftssp010_spi *to_ftssp010_spi(struct spi_slave *slave) | ||||||
|  | { | ||||||
|  | 	return container_of(slave, struct ftssp010_spi, slave); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int get_spi_chip(int bus, struct ftssp010_spi *chip) | ||||||
|  | { | ||||||
|  | 	uint32_t fear, base[] = CONFIG_FTSSP010_BASE_LIST; | ||||||
|  | 
 | ||||||
|  | 	if (bus >= ARRAY_SIZE(base) || !base[bus]) | ||||||
|  | 		return -1; | ||||||
|  | 
 | ||||||
|  | 	chip->regs = (struct ftssp010_regs *)base[bus]; | ||||||
|  | 
 | ||||||
|  | 	chip->revision = readl(&chip->regs->revr); | ||||||
|  | 
 | ||||||
|  | 	fear = readl(&chip->regs->fear); | ||||||
|  | 	chip->fifo = min_t(uint32_t, FEAR_TFSZ(fear), FEAR_RFSZ(fear)); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int get_spi_gpio(int bus, struct ftssp010_gpio *chip) | ||||||
|  | { | ||||||
|  | 	uint32_t base[] = CONFIG_FTSSP010_GPIO_LIST; | ||||||
|  | 
 | ||||||
|  | 	if (bus >= ARRAY_SIZE(base) || !base[bus]) | ||||||
|  | 		return -1; | ||||||
|  | 
 | ||||||
|  | 	chip->regs = (struct ftgpio010_regs *)(base[bus] & 0xfff00000); | ||||||
|  | 	chip->pin = base[bus] & 0x1f; | ||||||
|  | 
 | ||||||
|  | 	/* make it an output pin */ | ||||||
|  | 	setbits_le32(&chip->regs->dir, 1 << chip->pin); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ftssp010_wait(struct ftssp010_spi *chip) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_regs *regs = chip->regs; | ||||||
|  | 	int ret = -1; | ||||||
|  | 	ulong t; | ||||||
|  | 
 | ||||||
|  | 	/* wait until device idle */ | ||||||
|  | 	for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) { | ||||||
|  | 		if (readl(®s->sr) & SR_BUSY) | ||||||
|  | 			continue; | ||||||
|  | 		ret = 0; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (ret) | ||||||
|  | 		puts("ftspi010: busy timeout\n"); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ftssp010_wait_tx(struct ftssp010_spi *chip) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_regs *regs = chip->regs; | ||||||
|  | 	int ret = -1; | ||||||
|  | 	ulong t; | ||||||
|  | 
 | ||||||
|  | 	/* wait until tx fifo not full */ | ||||||
|  | 	for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) { | ||||||
|  | 		if (!(readl(®s->sr) & SR_TFNF)) | ||||||
|  | 			continue; | ||||||
|  | 		ret = 0; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (ret) | ||||||
|  | 		puts("ftssp010: tx timeout\n"); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ftssp010_wait_rx(struct ftssp010_spi *chip) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_regs *regs = chip->regs; | ||||||
|  | 	int ret = -1; | ||||||
|  | 	ulong t; | ||||||
|  | 
 | ||||||
|  | 	/* wait until rx fifo not empty */ | ||||||
|  | 	for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) { | ||||||
|  | 		if (!SR_RFVE(readl(®s->sr))) | ||||||
|  | 			continue; | ||||||
|  | 		ret = 0; | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (ret) | ||||||
|  | 		puts("ftssp010: rx timeout\n"); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ftssp010_spi_work_transfer_v2(struct ftssp010_spi *chip, | ||||||
|  | 	const void *tx_buf, void *rx_buf, int len, uint flags) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_regs *regs = chip->regs; | ||||||
|  | 	const uint8_t *txb = tx_buf; | ||||||
|  | 	uint8_t       *rxb = rx_buf; | ||||||
|  | 
 | ||||||
|  | 	while (len > 0) { | ||||||
|  | 		int i, depth = min(chip->fifo >> 2, len); | ||||||
|  | 		uint32_t xmsk = 0; | ||||||
|  | 
 | ||||||
|  | 		if (tx_buf) { | ||||||
|  | 			for (i = 0; i < depth; ++i) { | ||||||
|  | 				ftssp010_wait_tx(chip); | ||||||
|  | 				writel(*txb++, ®s->dr); | ||||||
|  | 			} | ||||||
|  | 			xmsk |= CR2_TXEN | CR2_TXDOE; | ||||||
|  | 			if ((readl(®s->cr[2]) & xmsk) != xmsk) | ||||||
|  | 				setbits_le32(®s->cr[2], xmsk); | ||||||
|  | 		} | ||||||
|  | 		if (rx_buf) { | ||||||
|  | 			xmsk |= CR2_RXEN; | ||||||
|  | 			if ((readl(®s->cr[2]) & xmsk) != xmsk) | ||||||
|  | 				setbits_le32(®s->cr[2], xmsk); | ||||||
|  | 			for (i = 0; i < depth; ++i) { | ||||||
|  | 				ftssp010_wait_rx(chip); | ||||||
|  | 				*rxb++ = (uint8_t)readl(®s->dr); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		len -= depth; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int ftssp010_spi_work_transfer_v1(struct ftssp010_spi *chip, | ||||||
|  | 	const void *tx_buf, void *rx_buf, int len, uint flags) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_regs *regs = chip->regs; | ||||||
|  | 	const uint8_t *txb = tx_buf; | ||||||
|  | 	uint8_t       *rxb = rx_buf; | ||||||
|  | 
 | ||||||
|  | 	while (len > 0) { | ||||||
|  | 		int i, depth = min(chip->fifo >> 2, len); | ||||||
|  | 		uint32_t tmp; | ||||||
|  | 
 | ||||||
|  | 		for (i = 0; i < depth; ++i) { | ||||||
|  | 			ftssp010_wait_tx(chip); | ||||||
|  | 			writel(txb ? (*txb++) : 0, ®s->dr); | ||||||
|  | 		} | ||||||
|  | 		for (i = 0; i < depth; ++i) { | ||||||
|  | 			ftssp010_wait_rx(chip); | ||||||
|  | 			tmp = readl(®s->dr); | ||||||
|  | 			if (rxb) | ||||||
|  | 				*rxb++ = (uint8_t)tmp; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		len -= depth; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void ftssp010_cs_set(struct ftssp010_spi *chip, int high) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_regs *regs = chip->regs; | ||||||
|  | 	struct ftssp010_gpio *gpio = &chip->gpio; | ||||||
|  | 	uint32_t mask; | ||||||
|  | 
 | ||||||
|  | 	/* cs pull high/low */ | ||||||
|  | 	if (chip->revision >= 0x11900) { | ||||||
|  | 		mask = CR2_CS(chip->slave.cs) | (high ? CR2_FS : 0); | ||||||
|  | 		writel(mask, ®s->cr[2]); | ||||||
|  | 	} else if (gpio->regs) { | ||||||
|  | 		mask = 1 << gpio->pin; | ||||||
|  | 		if (high) | ||||||
|  | 			writel(mask, &gpio->regs->set); | ||||||
|  | 		else | ||||||
|  | 			writel(mask, &gpio->regs->clr); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* extra delay for signal propagation */ | ||||||
|  | 	udelay_masked(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * 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. | ||||||
|  |  * | ||||||
|  |  * Returns: 1 if bus:cs identifies a valid chip on this board, 0 | ||||||
|  |  * otherwise. | ||||||
|  |  */ | ||||||
|  | int spi_cs_is_valid(unsigned int bus, unsigned int cs) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_spi chip; | ||||||
|  | 
 | ||||||
|  | 	if (get_spi_chip(bus, &chip)) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	if (!cs) | ||||||
|  | 		return 1; | ||||||
|  | 	else if ((cs < 4) && (chip.revision >= 0x11900)) | ||||||
|  | 		return 1; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * 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. | ||||||
|  |  * common/soft_spi.c). When called, it should activate the chip select | ||||||
|  |  * to the device identified by "slave". | ||||||
|  |  */ | ||||||
|  | void spi_cs_activate(struct spi_slave *slave) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_spi *chip = to_ftssp010_spi(slave); | ||||||
|  | 	struct ftssp010_regs *regs = chip->regs; | ||||||
|  | 
 | ||||||
|  | 	/* cs pull */ | ||||||
|  | 	if (chip->mode & SPI_CS_HIGH) | ||||||
|  | 		ftssp010_cs_set(chip, 1); | ||||||
|  | 	else | ||||||
|  | 		ftssp010_cs_set(chip, 0); | ||||||
|  | 
 | ||||||
|  | 	/* chip enable + fifo clear */ | ||||||
|  | 	setbits_le32(®s->cr[2], CR2_EN | CR2_TXFC | CR2_RXFC); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * 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. | ||||||
|  |  * common/soft_spi.c). When called, it should deactivate the chip | ||||||
|  |  * select to the device identified by "slave". | ||||||
|  |  */ | ||||||
|  | void spi_cs_deactivate(struct spi_slave *slave) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_spi *chip = to_ftssp010_spi(slave); | ||||||
|  | 
 | ||||||
|  | 	/* wait until chip idle */ | ||||||
|  | 	ftssp010_wait(chip); | ||||||
|  | 
 | ||||||
|  | 	/* cs pull */ | ||||||
|  | 	if (chip->mode & SPI_CS_HIGH) | ||||||
|  | 		ftssp010_cs_set(chip, 0); | ||||||
|  | 	else | ||||||
|  | 		ftssp010_cs_set(chip, 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void spi_init(void) | ||||||
|  | { | ||||||
|  | 	/* nothing to do */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_spi *chip; | ||||||
|  | 
 | ||||||
|  | 	if (mode & SPI_3WIRE) { | ||||||
|  | 		puts("ftssp010: can't do 3-wire\n"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (mode & SPI_SLAVE) { | ||||||
|  | 		puts("ftssp010: can't do slave mode\n"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (mode & SPI_PREAMBLE) { | ||||||
|  | 		puts("ftssp010: can't skip preamble bytes\n"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!spi_cs_is_valid(bus, cs)) { | ||||||
|  | 		puts("ftssp010: invalid (bus, cs)\n"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	chip = spi_alloc_slave(struct ftssp010_spi, bus, cs); | ||||||
|  | 	if (!chip) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	if (get_spi_chip(bus, chip)) | ||||||
|  | 		goto free_out; | ||||||
|  | 
 | ||||||
|  | 	if (chip->revision < 0x11900 && get_spi_gpio(bus, &chip->gpio)) { | ||||||
|  | 		puts("ftssp010: Before revision 1.19.0, its clock & cs are\n" | ||||||
|  | 		"controlled by tx engine which is not synced with rx engine,\n" | ||||||
|  | 		"so the clock & cs might be shutdown before rx engine\n" | ||||||
|  | 		"finishs its jobs.\n" | ||||||
|  | 		"If possible, please add a dedicated gpio for it.\n"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	chip->mode = mode; | ||||||
|  | 	chip->clk = CONFIG_FTSSP010_CLOCK; | ||||||
|  | 	chip->div = 2; | ||||||
|  | 	if (max_hz) { | ||||||
|  | 		while (chip->div < 0xffff) { | ||||||
|  | 			if ((chip->clk / (2 * chip->div)) <= max_hz) | ||||||
|  | 				break; | ||||||
|  | 			chip->div += 1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	chip->speed = chip->clk / (2 * chip->div); | ||||||
|  | 
 | ||||||
|  | 	return &chip->slave; | ||||||
|  | 
 | ||||||
|  | free_out: | ||||||
|  | 	free(chip); | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void spi_free_slave(struct spi_slave *slave) | ||||||
|  | { | ||||||
|  | 	free(slave); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int spi_claim_bus(struct spi_slave *slave) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_spi *chip = to_ftssp010_spi(slave); | ||||||
|  | 	struct ftssp010_regs *regs = chip->regs; | ||||||
|  | 
 | ||||||
|  | 	writel(CR1_SDL(8) | CR1_DIV(chip->div), ®s->cr[1]); | ||||||
|  | 
 | ||||||
|  | 	if (chip->revision >= 0x11900) { | ||||||
|  | 		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH, | ||||||
|  | 		       ®s->cr[0]); | ||||||
|  | 		writel(CR2_TXFC | CR2_RXFC, | ||||||
|  | 		       ®s->cr[2]); | ||||||
|  | 	} else { | ||||||
|  | 		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO, | ||||||
|  | 		       ®s->cr[0]); | ||||||
|  | 		writel(CR2_TXFC | CR2_RXFC | CR2_EN | CR2_TXDOE, | ||||||
|  | 		       ®s->cr[2]); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (chip->mode & SPI_LOOP) | ||||||
|  | 		setbits_le32(®s->cr[0], CR0_LOOP); | ||||||
|  | 
 | ||||||
|  | 	if (chip->mode & SPI_CPOL) | ||||||
|  | 		setbits_le32(®s->cr[0], CR0_SCLKPO); | ||||||
|  | 
 | ||||||
|  | 	if (chip->mode & SPI_CPHA) | ||||||
|  | 		setbits_le32(®s->cr[0], CR0_SCLKPH); | ||||||
|  | 
 | ||||||
|  | 	spi_cs_deactivate(slave); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void spi_release_bus(struct spi_slave *slave) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_spi *chip = to_ftssp010_spi(slave); | ||||||
|  | 	struct ftssp010_regs *regs = chip->regs; | ||||||
|  | 
 | ||||||
|  | 	writel(0, ®s->cr[2]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | ||||||
|  | 			 const void *dout, void *din, unsigned long flags) | ||||||
|  | { | ||||||
|  | 	struct ftssp010_spi *chip = to_ftssp010_spi(slave); | ||||||
|  | 	uint32_t len = bitlen >> 3; | ||||||
|  | 
 | ||||||
|  | 	if (flags & SPI_XFER_BEGIN) | ||||||
|  | 		spi_cs_activate(slave); | ||||||
|  | 
 | ||||||
|  | 	if (chip->revision >= 0x11900) | ||||||
|  | 		ftssp010_spi_work_transfer_v2(chip, dout, din, len, flags); | ||||||
|  | 	else | ||||||
|  | 		ftssp010_spi_work_transfer_v1(chip, dout, din, len, flags); | ||||||
|  | 
 | ||||||
|  | 	if (flags & SPI_XFER_END) | ||||||
|  | 		spi_cs_deactivate(slave); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | @ -151,7 +151,6 @@ static int sh_spi_send(struct sh_spi *ss, const unsigned char *tx_data, | ||||||
| { | { | ||||||
| 	int i, cur_len, ret = 0; | 	int i, cur_len, ret = 0; | ||||||
| 	int remain = (int)len; | 	int remain = (int)len; | ||||||
| 	unsigned long tmp; |  | ||||||
| 
 | 
 | ||||||
| 	if (len >= SH_SPI_FIFO_SIZE) | 	if (len >= SH_SPI_FIFO_SIZE) | ||||||
| 		sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1); | 		sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1); | ||||||
|  | @ -183,9 +182,7 @@ static int sh_spi_send(struct sh_spi *ss, const unsigned char *tx_data, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (flags & SPI_XFER_END) { | 	if (flags & SPI_XFER_END) { | ||||||
| 		tmp = sh_spi_read(&ss->regs->cr1); | 		sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1); | ||||||
| 		tmp = tmp & ~(SH_SPI_SSD | SH_SPI_SSDB); |  | ||||||
| 		sh_spi_write(tmp, &ss->regs->cr1); |  | ||||||
| 		sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1); | 		sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1); | ||||||
| 		udelay(100); | 		udelay(100); | ||||||
| 		write_fifo_empty_wait(ss); | 		write_fifo_empty_wait(ss); | ||||||
|  | @ -198,16 +195,13 @@ static int sh_spi_receive(struct sh_spi *ss, unsigned char *rx_data, | ||||||
| 			  unsigned int len, unsigned long flags) | 			  unsigned int len, unsigned long flags) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	unsigned long tmp; |  | ||||||
| 
 | 
 | ||||||
| 	if (len > SH_SPI_MAX_BYTE) | 	if (len > SH_SPI_MAX_BYTE) | ||||||
| 		sh_spi_write(SH_SPI_MAX_BYTE, &ss->regs->cr3); | 		sh_spi_write(SH_SPI_MAX_BYTE, &ss->regs->cr3); | ||||||
| 	else | 	else | ||||||
| 		sh_spi_write(len, &ss->regs->cr3); | 		sh_spi_write(len, &ss->regs->cr3); | ||||||
| 
 | 
 | ||||||
| 	tmp = sh_spi_read(&ss->regs->cr1); | 	sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1); | ||||||
| 	tmp = tmp & ~(SH_SPI_SSD | SH_SPI_SSDB); |  | ||||||
| 	sh_spi_write(tmp, &ss->regs->cr1); |  | ||||||
| 	sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1); | 	sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < len; i++) { | 	for (i = 0; i < len; i++) { | ||||||
|  |  | ||||||
|  | @ -30,6 +30,24 @@ | ||||||
| #define SPI_XFER_MMAP		0x08	/* Memory Mapped start */ | #define SPI_XFER_MMAP		0x08	/* Memory Mapped start */ | ||||||
| #define SPI_XFER_MMAP_END	0x10	/* Memory Mapped End */ | #define SPI_XFER_MMAP_END	0x10	/* Memory Mapped End */ | ||||||
| #define SPI_XFER_ONCE		(SPI_XFER_BEGIN | SPI_XFER_END) | #define SPI_XFER_ONCE		(SPI_XFER_BEGIN | SPI_XFER_END) | ||||||
|  | #define SPI_XFER_U_PAGE		(1 << 5) | ||||||
|  | 
 | ||||||
|  | /* SPI TX operation modes */ | ||||||
|  | #define SPI_OPM_TX_QPP		1 << 0 | ||||||
|  | 
 | ||||||
|  | /* SPI RX operation modes */ | ||||||
|  | #define SPI_OPM_RX_AS		1 << 0 | ||||||
|  | #define SPI_OPM_RX_DOUT		1 << 1 | ||||||
|  | #define SPI_OPM_RX_DIO		1 << 2 | ||||||
|  | #define SPI_OPM_RX_QOF		1 << 3 | ||||||
|  | #define SPI_OPM_RX_QIOF		1 << 4 | ||||||
|  | #define SPI_OPM_RX_EXTN		SPI_OPM_RX_AS | SPI_OPM_RX_DOUT | \ | ||||||
|  | 				SPI_OPM_RX_DIO | SPI_OPM_RX_QOF | \ | ||||||
|  | 				SPI_OPM_RX_QIOF | ||||||
|  | 
 | ||||||
|  | /* SPI bus connection options */ | ||||||
|  | #define SPI_CONN_DUAL_SHARED	1 << 0 | ||||||
|  | #define SPI_CONN_DUAL_SEPARATED	1 << 1 | ||||||
| 
 | 
 | ||||||
| /* Header byte that marks the start of the message */ | /* Header byte that marks the start of the message */ | ||||||
| #define SPI_PREAMBLE_END_BYTE	0xec | #define SPI_PREAMBLE_END_BYTE	0xec | ||||||
|  | @ -43,17 +61,25 @@ | ||||||
|  * |  * | ||||||
|  * @bus:		ID of the bus that the slave is attached to. |  * @bus:		ID of the bus that the slave is attached to. | ||||||
|  * @cs:			ID of the chip select connected to the slave. |  * @cs:			ID of the chip select connected to the slave. | ||||||
|  |  * @op_mode_rx:		SPI RX operation mode. | ||||||
|  |  * @op_mode_tx:		SPI TX operation mode. | ||||||
|  * @wordlen:		Size of SPI word in number of bits |  * @wordlen:		Size of SPI word in number of bits | ||||||
|  * @max_write_size:	If non-zero, the maximum number of bytes which can |  * @max_write_size:	If non-zero, the maximum number of bytes which can | ||||||
|  *			be written at once, excluding command bytes. |  *			be written at once, excluding command bytes. | ||||||
|  * @memory_map:		Address of read-only SPI flash access. |  * @memory_map:		Address of read-only SPI flash access. | ||||||
|  |  * @option:		Varies SPI bus options - separate, shared bus. | ||||||
|  |  * @flags:		Indication of SPI flags. | ||||||
|  */ |  */ | ||||||
| struct spi_slave { | struct spi_slave { | ||||||
| 	unsigned int bus; | 	unsigned int bus; | ||||||
| 	unsigned int cs; | 	unsigned int cs; | ||||||
|  | 	u8 op_mode_rx; | ||||||
|  | 	u8 op_mode_tx; | ||||||
| 	unsigned int wordlen; | 	unsigned int wordlen; | ||||||
| 	unsigned int max_write_size; | 	unsigned int max_write_size; | ||||||
| 	void *memory_map; | 	void *memory_map; | ||||||
|  | 	u8 option; | ||||||
|  | 	u8 flags; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  |  | ||||||
|  | @ -19,11 +19,60 @@ | ||||||
| #include <linux/types.h> | #include <linux/types.h> | ||||||
| #include <linux/compiler.h> | #include <linux/compiler.h> | ||||||
| 
 | 
 | ||||||
|  | /* sf param flags */ | ||||||
|  | #define SECT_4K		1 << 1 | ||||||
|  | #define SECT_32K	1 << 2 | ||||||
|  | #define E_FSR		1 << 3 | ||||||
|  | #define WR_QPP		1 << 4 | ||||||
|  | 
 | ||||||
|  | /* Enum list - Full read commands */ | ||||||
|  | enum spi_read_cmds { | ||||||
|  | 	ARRAY_SLOW = 1 << 0, | ||||||
|  | 	DUAL_OUTPUT_FAST = 1 << 1, | ||||||
|  | 	DUAL_IO_FAST = 1 << 2, | ||||||
|  | 	QUAD_OUTPUT_FAST = 1 << 3, | ||||||
|  | 	QUAD_IO_FAST = 1 << 4, | ||||||
|  | }; | ||||||
|  | #define RD_EXTN		ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST | ||||||
|  | #define RD_FULL		RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST | ||||||
|  | 
 | ||||||
|  | /* Dual SPI flash memories */ | ||||||
|  | enum spi_dual_flash { | ||||||
|  | 	SF_SINGLE_FLASH = 0, | ||||||
|  | 	SF_DUAL_STACKED_FLASH = 1 << 0, | ||||||
|  | 	SF_DUAL_PARALLEL_FLASH = 1 << 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * 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 | ||||||
|  |  * @e_rd_cmd:		Enum list for read commands | ||||||
|  |  * @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; | ||||||
|  | 	u8 e_rd_cmd; | ||||||
|  | 	u16 flags; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | extern const struct spi_flash_params spi_flash_params_table[]; | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct spi_flash - SPI flash structure |  * struct spi_flash - SPI flash structure | ||||||
|  * |  * | ||||||
|  * @spi:		SPI slave |  * @spi:		SPI slave | ||||||
|  * @name:		Name of SPI flash |  * @name:		Name of SPI flash | ||||||
|  |  * @dual_flash:		Indicates dual flash memories - dual stacked, parallel | ||||||
|  |  * @shift:		Flash shift useful in dual parallel | ||||||
|  * @size:		Total flash size |  * @size:		Total flash size | ||||||
|  * @page_size:		Write (page) size |  * @page_size:		Write (page) size | ||||||
|  * @sector_size:	Sector size |  * @sector_size:	Sector size | ||||||
|  | @ -33,6 +82,9 @@ | ||||||
|  * @bank_curr:		Current flash bank |  * @bank_curr:		Current flash bank | ||||||
|  * @poll_cmd:		Poll cmd - for flash erase/program |  * @poll_cmd:		Poll cmd - for flash erase/program | ||||||
|  * @erase_cmd:		Erase cmd 4K, 32K, 64K |  * @erase_cmd:		Erase cmd 4K, 32K, 64K | ||||||
|  |  * @read_cmd:		Read cmd - Array Fast, Extn read and quad read. | ||||||
|  |  * @write_cmd:		Write cmd - page and quad program. | ||||||
|  |  * @dummy_byte:		Dummy cycles for read operation. | ||||||
|  * @memory_map:		Address of read-only SPI flash access |  * @memory_map:		Address of read-only SPI flash access | ||||||
|  * @read:		Flash read ops: Read len bytes at offset into buf |  * @read:		Flash read ops: Read len bytes at offset into buf | ||||||
|  *			Supported cmds: Fast Array Read |  *			Supported cmds: Fast Array Read | ||||||
|  | @ -45,6 +97,8 @@ | ||||||
| struct spi_flash { | struct spi_flash { | ||||||
| 	struct spi_slave *spi; | 	struct spi_slave *spi; | ||||||
| 	const char *name; | 	const char *name; | ||||||
|  | 	u8 dual_flash; | ||||||
|  | 	u8 shift; | ||||||
| 
 | 
 | ||||||
| 	u32 size; | 	u32 size; | ||||||
| 	u32 page_size; | 	u32 page_size; | ||||||
|  | @ -57,6 +111,9 @@ struct spi_flash { | ||||||
| #endif | #endif | ||||||
| 	u8 poll_cmd; | 	u8 poll_cmd; | ||||||
| 	u8 erase_cmd; | 	u8 erase_cmd; | ||||||
|  | 	u8 read_cmd; | ||||||
|  | 	u8 write_cmd; | ||||||
|  | 	u8 dummy_byte; | ||||||
| 
 | 
 | ||||||
| 	void *memory_map; | 	void *memory_map; | ||||||
| 	int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf); | 	int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue