Commit 10fcda8e25cb9477b47a62edb716f81c9d5e1f0e
Exists in
master
and in
50 other branches
Merge branch 'master' of git://git.denx.de/u-boot-spi
Showing 16 changed files Side-by-side Diff
- README
- common/cmd_sf.c
- doc/SPI/README.dual-flash
- doc/SPI/README.ftssp010_spi_test
- doc/SPI/status.txt
- drivers/mtd/spi/Makefile
- drivers/mtd/spi/sf.c
- drivers/mtd/spi/sf_internal.h
- drivers/mtd/spi/sf_ops.c
- drivers/mtd/spi/sf_params.c
- drivers/mtd/spi/sf_probe.c
- drivers/spi/Makefile
- drivers/spi/ftssp010_spi.c
- drivers/spi/sh_spi.c
- include/spi.h
- include/spi_flash.h
README
... | ... | @@ -2756,6 +2756,12 @@ |
2756 | 2756 | Define this option to use the Bank addr/Extended addr |
2757 | 2757 | support on SPI flashes which has size > 16Mbytes. |
2758 | 2758 | |
2759 | + CONFIG_SF_DUAL_FLASH Dual flash memories | |
2760 | + | |
2761 | + Define this option to use dual flash support where two flash | |
2762 | + memories can be connected with a given cs line. | |
2763 | + currently Xilinx Zynq qspi support these type of connections. | |
2764 | + | |
2759 | 2765 | - SystemACE Support: |
2760 | 2766 | CONFIG_SYSTEMACE |
2761 | 2767 |
common/cmd_sf.c
... | ... | @@ -358,7 +358,8 @@ |
358 | 358 | int bps; /* Bits per second */ |
359 | 359 | |
360 | 360 | speed = (long long)test->bytes * 1000; |
361 | - do_div(speed, test->time_ms[stage] * 1024); | |
361 | + if (test->time_ms[stage]) | |
362 | + do_div(speed, test->time_ms[stage] * 1024); | |
362 | 363 | bps = speed * 8; |
363 | 364 | |
364 | 365 | printf("%d %s: %d ticks, %d KiB/s %d.%03d Mbps\n", stage, |
365 | 366 | |
... | ... | @@ -446,11 +447,13 @@ |
446 | 447 | { |
447 | 448 | unsigned long offset; |
448 | 449 | unsigned long len; |
449 | - uint8_t *buf = (uint8_t *)CONFIG_SYS_TEXT_BASE; | |
450 | + uint8_t *buf, *from; | |
450 | 451 | char *endp; |
451 | 452 | uint8_t *vbuf; |
452 | 453 | int ret; |
453 | 454 | |
455 | + if (argc < 3) | |
456 | + return -1; | |
454 | 457 | offset = simple_strtoul(argv[1], &endp, 16); |
455 | 458 | if (*argv[1] == 0 || *endp != 0) |
456 | 459 | return -1; |
457 | 460 | |
458 | 461 | |
... | ... | @@ -460,17 +463,18 @@ |
460 | 463 | |
461 | 464 | vbuf = malloc(len); |
462 | 465 | if (!vbuf) { |
463 | - printf("Cannot allocate memory\n"); | |
466 | + printf("Cannot allocate memory (%lu bytes)\n", len); | |
464 | 467 | return 1; |
465 | 468 | } |
466 | 469 | buf = malloc(len); |
467 | 470 | if (!buf) { |
468 | 471 | free(vbuf); |
469 | - printf("Cannot allocate memory\n"); | |
472 | + printf("Cannot allocate memory (%lu bytes)\n", len); | |
470 | 473 | return 1; |
471 | 474 | } |
472 | 475 | |
473 | - memcpy(buf, (char *)CONFIG_SYS_TEXT_BASE, len); | |
476 | + from = map_sysmem(CONFIG_SYS_TEXT_BASE, 0); | |
477 | + memcpy(buf, from, len); | |
474 | 478 | ret = spi_flash_test(flash, buf, len, offset, vbuf); |
475 | 479 | free(vbuf); |
476 | 480 | free(buf); |
doc/SPI/README.dual-flash
1 | +SPI/QSPI Dual flash connection modes: | |
2 | +===================================== | |
3 | + | |
4 | +This describes how SPI/QSPI flash memories are connected to a given | |
5 | +controller in a single chip select line. | |
6 | + | |
7 | +Current spi_flash framework supports, single flash memory connected | |
8 | +to a given controller with single chip select line, but there are some | |
9 | +hw logics(ex: xilinx zynq qspi) that describes two/dual memories are | |
10 | +connected with a single chip select line from a controller. | |
11 | + | |
12 | +"dual_flash" from include/spi.h describes these types of connection mode | |
13 | + | |
14 | +Possible connections: | |
15 | +-------------------- | |
16 | +SF_SINGLE_FLASH: | |
17 | + - single spi flash memory connected with single chip select line. | |
18 | + | |
19 | + +------------+ CS +---------------+ | |
20 | + | |----------------------->| | | |
21 | + | Controller | I0[3:0] | Flash memory | | |
22 | + | SPI/QSPI |<======================>| (SPI/QSPI) | | |
23 | + | | CLK | | | |
24 | + | |----------------------->| | | |
25 | + +------------+ +---------------+ | |
26 | + | |
27 | +SF_DUAL_STACKED_FLASH: | |
28 | + - dual spi/qspi flash memories are connected with a single chipselect | |
29 | + line and these two memories are operating stacked fasion with shared buses. | |
30 | + - xilinx zynq qspi controller has implemented this feature [1] | |
31 | + | |
32 | + +------------+ CS +---------------+ | |
33 | + | |---------------------->| | | |
34 | + | | I0[3:0] | Upper Flash | | |
35 | + | | +=========>| memory | | |
36 | + | | | CLK | (SPI/QSPI) | | |
37 | + | | | +---->| | | |
38 | + | Controller | CS | | +---------------+ | |
39 | + | SPI/QSPI |------------|----|---->| | | |
40 | + | | I0[3:0] | | | Lower Flash | | |
41 | + | |<===========+====|====>| memory | | |
42 | + | | CLK | | (SPI/QSPI) | | |
43 | + | |-----------------+---->| | | |
44 | + +------------+ +---------------+ | |
45 | + | |
46 | + - two memory flash devices should has same hw part attributes (like size, | |
47 | + vendor..etc) | |
48 | + - Configurations: | |
49 | + on LQSPI_CFG register, Enable TWO_MEM[BIT:30] on LQSPI_CFG | |
50 | + Enable U_PAGE[BIT:28] if U_PAGE flag set - upper memory | |
51 | + Disable U_PAGE[BIT:28] if U_PAGE flag unset - lower memory | |
52 | + - Operation: | |
53 | + accessing memories serially like one after another. | |
54 | + by default, if U_PAGE is unset lower memory should accessible, | |
55 | + once user wants to access upper memory need to set U_PAGE. | |
56 | + | |
57 | +SPI_FLASH_CONN_DUALPARALLEL: | |
58 | + - dual spi/qspi flash memories are connected with a single chipselect | |
59 | + line and these two memories are operating parallel with separate buses. | |
60 | + - xilinx zynq qspi controller has implemented this feature [1] | |
61 | + | |
62 | + +-------------+ CS +---------------+ | |
63 | + | |---------------------->| | | |
64 | + | | I0[3:0] | Upper Flash | | |
65 | + | |<=====================>| memory | | |
66 | + | | CLK | (SPI/QSPI) | | |
67 | + | |---------------------->| | | |
68 | + | Controller | CS +---------------+ | |
69 | + | SPI/QSPI |---------------------->| | | |
70 | + | | I0[3:0] | Lower Flash | | |
71 | + | |<=====================>| memory | | |
72 | + | | CLK | (SPI/QSPI) | | |
73 | + | |---------------------->| | | |
74 | + +-------------+ +---------------+ | |
75 | + | |
76 | + - two memory flash devices should has same hw part attributes (like size, | |
77 | + vendor..etc) | |
78 | + - Configurations: | |
79 | + Need to enable SEP_BUS[BIT:29],TWO_MEM[BIT:30] on LQSPI_CFG register. | |
80 | + - Operation: | |
81 | + Even bits, i.e. bit 0, 2, 4 ., of a data word is located in the lower memory | |
82 | + and odd bits, i.e. bit 1, 3, 5, ., of a data word is located in the upper memory. | |
83 | + | |
84 | +Note: Technically there is only one CS line from the controller, but | |
85 | +zynq qspi controller has an internal hw logic to enable additional CS | |
86 | +when controller is configured for dual memories. | |
87 | + | |
88 | +[1] http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf | |
89 | + | |
90 | +-- | |
91 | +Jagannadha Sutradharudu Teki <jaganna@xilinx.com> | |
92 | +05-01-2014. |
doc/SPI/README.ftssp010_spi_test
1 | +SPI Flash test on Faraday A369 EVB: | |
2 | +================================== | |
3 | + | |
4 | +U-Boot 2014.01-rc2-g3444b6f (Dec 20 2013 - 10:58:40) | |
5 | + | |
6 | +CPU: FA626TE 528 MHz | |
7 | +AHB: 132 MHz | |
8 | +APB: 66 MHz | |
9 | +I2C: ready | |
10 | +DRAM: 256 MiB | |
11 | +MMU: on | |
12 | +NAND: 512 MiB | |
13 | +MMC: ftsdc010: 0 | |
14 | +*** Warning - bad CRC, using default environment | |
15 | + | |
16 | +In: serial | |
17 | +Out: serial | |
18 | +Err: serial | |
19 | +Net: FTGMAC100#0 | |
20 | +Hit any key to stop autoboot: 0 | |
21 | +=> sf probe 0:0 | |
22 | +SF: Detected MX25L1605D with page size 256 Bytes, erase size 64 KiB, total 2 MiB | |
23 | +=> sf read 0x10800000 0 0x400 | |
24 | +SF: 1024 bytes @ 0x0 Read: OK | |
25 | +=> md 0x10800000 | |
26 | +10800000: ea000013 e59ff014 e59ff014 e59ff014 ................ | |
27 | +10800010: e59ff014 e59ff014 e59ff014 e59ff014 ................ | |
28 | +10800020: 1ff7b0c0 1ff7b120 1ff7b180 1ff7b1e0 .... ........... | |
29 | +10800030: 1ff7b240 1ff7b2a0 1ff7b300 deadbeef @............... | |
30 | +10800040: 10800000 0002c1f0 0007409c 00032048 .........@..H .. | |
31 | +10800050: 1fd6af40 e10f0000 e3c0001f e38000d3 @............... | |
32 | +10800060: e129f000 eb000001 eb000223 e12fff1e ..).....#...../. | |
33 | +10800070: e3a00000 ee070f1e ee080f17 ee070f15 ................ | |
34 | +10800080: ee070f9a ee110f10 e3c00c03 e3c00087 ................ | |
35 | +10800090: e3c00a02 e3800002 e3800a01 ee010f10 ................ | |
36 | +108000a0: e1a0c00e eb007a68 e1a0e00c e1a0f00e ....hz.......... | |
37 | +108000b0: e1a00000 e1a00000 e1a00000 e1a00000 ................ | |
38 | +108000c0: e51fd078 e58de000 e14fe000 e58de004 x.........O..... | |
39 | +108000d0: e3a0d013 e169f00d e1a0e00f e1b0f00e ......i......... | |
40 | +108000e0: e24dd048 e88d1fff e51f20a0 e892000c H.M...... ...... | |
41 | +108000f0: e28d0048 e28d5034 e1a0100e e885000f H...4P.......... |
doc/SPI/status.txt
... | ... | @@ -11,6 +11,11 @@ |
11 | 11 | - Bank Address Register (Accessing flashes > 16Mbytes in 3-byte addressing) |
12 | 12 | - Added memory_mapped support for read operations. |
13 | 13 | - Common probe support for all supported flash vendors except, ramtron. |
14 | +- Extended read commands support(dual read, dual IO read) | |
15 | +- Quad Page Program support. | |
16 | +- Quad Read support(quad fast read, quad IO read) | |
17 | +- Dual flash connection topology support(accessing two spi flash memories with single cs) | |
18 | +- Banking support on dual flash connection topology. | |
14 | 19 | |
15 | 20 | SPI DRIVERS (drivers/spi): |
16 | 21 | - |
17 | 22 | |
... | ... | @@ -18,15 +23,11 @@ |
18 | 23 | TODO: |
19 | 24 | - Runtime detection of spi_flash params, SFDP(if possible) |
20 | 25 | - Add support for multibus build/accessing. |
21 | -- Extended read commands support(dual read, dual IO read) | |
22 | -- Quad Page Program support. | |
23 | -- Quad Read support(quad fast read, quad IO read) | |
24 | -- Dual flash connection topology support(accessing two spi flash memories with single cs) | |
25 | -- Banking support on dual flash connection topology. | |
26 | 26 | - Need proper cleanups on spi_flash and drivers. |
27 | 27 | |
28 | 28 | -- |
29 | 29 | Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com> |
30 | 30 | 18-09-2013. |
31 | 31 | 07-10-2013. |
32 | +08-01-2014. |
drivers/mtd/spi/Makefile
... | ... | @@ -10,8 +10,8 @@ |
10 | 10 | obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o |
11 | 11 | endif |
12 | 12 | |
13 | -obj-$(CONFIG_CMD_SF) += sf.o | |
14 | -obj-$(CONFIG_SPI_FLASH) += sf_probe.o sf_ops.o | |
13 | +obj-$(CONFIG_CMD_SF) += sf.o | |
14 | +obj-$(CONFIG_SPI_FLASH) += sf_params.o sf_probe.o sf_ops.o | |
15 | 15 | obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o |
16 | 16 | obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o |
17 | 17 | obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o |
drivers/mtd/spi/sf.c
drivers/mtd/spi/sf_internal.h
... | ... | @@ -10,12 +10,15 @@ |
10 | 10 | #ifndef _SF_INTERNAL_H_ |
11 | 11 | #define _SF_INTERNAL_H_ |
12 | 12 | |
13 | +#define SPI_FLASH_3B_ADDR_LEN 3 | |
14 | +#define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN) | |
13 | 15 | #define SPI_FLASH_16MB_BOUN 0x1000000 |
14 | 16 | |
15 | -/* SECT flags */ | |
16 | -#define SECT_4K (1 << 1) | |
17 | -#define SECT_32K (1 << 2) | |
18 | -#define E_FSR (1 << 3) | |
17 | +/* CFI Manufacture ID's */ | |
18 | +#define SPI_FLASH_CFI_MFR_SPANSION 0x01 | |
19 | +#define SPI_FLASH_CFI_MFR_STMICRO 0x20 | |
20 | +#define SPI_FLASH_CFI_MFR_MACRONIX 0xc2 | |
21 | +#define SPI_FLASH_CFI_MFR_WINBOND 0xef | |
19 | 22 | |
20 | 23 | /* Erase commands */ |
21 | 24 | #define CMD_ERASE_4K 0x20 |
... | ... | @@ -28,6 +31,7 @@ |
28 | 31 | #define CMD_PAGE_PROGRAM 0x02 |
29 | 32 | #define CMD_WRITE_DISABLE 0x04 |
30 | 33 | #define CMD_READ_STATUS 0x05 |
34 | +#define CMD_QUAD_PAGE_PROGRAM 0x32 | |
31 | 35 | #define CMD_READ_STATUS1 0x35 |
32 | 36 | #define CMD_WRITE_ENABLE 0x06 |
33 | 37 | #define CMD_READ_CONFIG 0x35 |
... | ... | @@ -36,6 +40,10 @@ |
36 | 40 | /* Read commands */ |
37 | 41 | #define CMD_READ_ARRAY_SLOW 0x03 |
38 | 42 | #define CMD_READ_ARRAY_FAST 0x0b |
43 | +#define CMD_READ_DUAL_OUTPUT_FAST 0x3b | |
44 | +#define CMD_READ_DUAL_IO_FAST 0xbb | |
45 | +#define CMD_READ_QUAD_OUTPUT_FAST 0x6b | |
46 | +#define CMD_READ_QUAD_IO_FAST 0xeb | |
39 | 47 | #define CMD_READ_ID 0x9f |
40 | 48 | |
41 | 49 | /* Bank addr access commands */ |
... | ... | @@ -47,8 +55,10 @@ |
47 | 55 | #endif |
48 | 56 | |
49 | 57 | /* Common status */ |
50 | -#define STATUS_WIP 0x01 | |
51 | -#define STATUS_PEC 0x80 | |
58 | +#define STATUS_WIP (1 << 0) | |
59 | +#define STATUS_QEB_WINSPAN (1 << 1) | |
60 | +#define STATUS_QEB_MXIC (1 << 6) | |
61 | +#define STATUS_PEC (1 << 7) | |
52 | 62 | |
53 | 63 | /* Flash timeout values */ |
54 | 64 | #define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) |
55 | 65 | |
56 | 66 | |
... | ... | @@ -86,11 +96,17 @@ |
86 | 96 | /* Flash erase(sectors) operation, support all possible erase commands */ |
87 | 97 | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); |
88 | 98 | |
99 | +/* Read the status register */ | |
100 | +int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); | |
101 | + | |
89 | 102 | /* Program the status register */ |
90 | -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); | |
103 | +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); | |
91 | 104 | |
92 | -/* Set quad enbale bit */ | |
93 | -int spi_flash_set_qeb(struct spi_flash *flash); | |
105 | +/* Read the config register */ | |
106 | +int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc); | |
107 | + | |
108 | +/* Program the config register */ | |
109 | +int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc); | |
94 | 110 | |
95 | 111 | /* Enable writing on the SPI flash */ |
96 | 112 | static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) |
drivers/mtd/spi/sf_ops.c
... | ... | @@ -9,6 +9,7 @@ |
9 | 9 | */ |
10 | 10 | |
11 | 11 | #include <common.h> |
12 | +#include <malloc.h> | |
12 | 13 | #include <spi.h> |
13 | 14 | #include <spi_flash.h> |
14 | 15 | #include <watchdog.h> |
15 | 16 | |
16 | 17 | |
17 | 18 | |
... | ... | @@ -23,13 +24,28 @@ |
23 | 24 | cmd[3] = addr >> 0; |
24 | 25 | } |
25 | 26 | |
26 | -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) | |
27 | +int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs) | |
27 | 28 | { |
29 | + int ret; | |
28 | 30 | u8 cmd; |
31 | + | |
32 | + cmd = CMD_READ_STATUS; | |
33 | + ret = spi_flash_read_common(flash, &cmd, 1, rs, 1); | |
34 | + if (ret < 0) { | |
35 | + debug("SF: fail to read status register\n"); | |
36 | + return ret; | |
37 | + } | |
38 | + | |
39 | + return 0; | |
40 | +} | |
41 | + | |
42 | +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws) | |
43 | +{ | |
44 | + u8 cmd; | |
29 | 45 | int ret; |
30 | 46 | |
31 | 47 | cmd = CMD_WRITE_STATUS; |
32 | - ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); | |
48 | + ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1); | |
33 | 49 | if (ret < 0) { |
34 | 50 | debug("SF: fail to write status register\n"); |
35 | 51 | return ret; |
... | ... | @@ -38,6 +54,44 @@ |
38 | 54 | return 0; |
39 | 55 | } |
40 | 56 | |
57 | +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | |
58 | +int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc) | |
59 | +{ | |
60 | + int ret; | |
61 | + u8 cmd; | |
62 | + | |
63 | + cmd = CMD_READ_CONFIG; | |
64 | + ret = spi_flash_read_common(flash, &cmd, 1, rc, 1); | |
65 | + if (ret < 0) { | |
66 | + debug("SF: fail to read config register\n"); | |
67 | + return ret; | |
68 | + } | |
69 | + | |
70 | + return 0; | |
71 | +} | |
72 | + | |
73 | +int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) | |
74 | +{ | |
75 | + u8 data[2]; | |
76 | + u8 cmd; | |
77 | + int ret; | |
78 | + | |
79 | + ret = spi_flash_cmd_read_status(flash, &data[0]); | |
80 | + if (ret < 0) | |
81 | + return ret; | |
82 | + | |
83 | + cmd = CMD_WRITE_STATUS; | |
84 | + data[1] = wc; | |
85 | + ret = spi_flash_write_common(flash, &cmd, 1, &data, 2); | |
86 | + if (ret) { | |
87 | + debug("SF: fail to write config register\n"); | |
88 | + return ret; | |
89 | + } | |
90 | + | |
91 | + return 0; | |
92 | +} | |
93 | +#endif | |
94 | + | |
41 | 95 | #ifdef CONFIG_SPI_FLASH_BAR |
42 | 96 | static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) |
43 | 97 | { |
... | ... | @@ -65,7 +119,7 @@ |
65 | 119 | u8 bank_sel; |
66 | 120 | int ret; |
67 | 121 | |
68 | - bank_sel = offset / SPI_FLASH_16MB_BOUN; | |
122 | + bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift); | |
69 | 123 | |
70 | 124 | ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); |
71 | 125 | if (ret) { |
72 | 126 | |
73 | 127 | |
... | ... | @@ -73,14 +127,37 @@ |
73 | 127 | return ret; |
74 | 128 | } |
75 | 129 | |
76 | - return 0; | |
130 | + return bank_sel; | |
77 | 131 | } |
78 | 132 | #endif |
79 | 133 | |
134 | +#ifdef CONFIG_SF_DUAL_FLASH | |
135 | +static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr) | |
136 | +{ | |
137 | + switch (flash->dual_flash) { | |
138 | + case SF_DUAL_STACKED_FLASH: | |
139 | + if (*addr >= (flash->size >> 1)) { | |
140 | + *addr -= flash->size >> 1; | |
141 | + flash->spi->flags |= SPI_XFER_U_PAGE; | |
142 | + } else { | |
143 | + flash->spi->flags &= ~SPI_XFER_U_PAGE; | |
144 | + } | |
145 | + break; | |
146 | + case SF_DUAL_PARALLEL_FLASH: | |
147 | + *addr >>= flash->shift; | |
148 | + break; | |
149 | + default: | |
150 | + debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash); | |
151 | + break; | |
152 | + } | |
153 | +} | |
154 | +#endif | |
155 | + | |
80 | 156 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) |
81 | 157 | { |
82 | 158 | struct spi_slave *spi = flash->spi; |
83 | 159 | unsigned long timebase; |
160 | + unsigned long flags = SPI_XFER_BEGIN; | |
84 | 161 | int ret; |
85 | 162 | u8 status; |
86 | 163 | u8 check_status = 0x0; |
... | ... | @@ -92,7 +169,11 @@ |
92 | 169 | check_status = poll_bit; |
93 | 170 | } |
94 | 171 | |
95 | - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); | |
172 | +#ifdef CONFIG_SF_DUAL_FLASH | |
173 | + if (spi->flags & SPI_XFER_U_PAGE) | |
174 | + flags |= SPI_XFER_U_PAGE; | |
175 | +#endif | |
176 | + ret = spi_xfer(spi, 8, &cmd, NULL, flags); | |
96 | 177 | if (ret) { |
97 | 178 | debug("SF: fail to read %s status register\n", |
98 | 179 | cmd == CMD_READ_STATUS ? "read" : "flag"); |
... | ... | @@ -165,8 +246,8 @@ |
165 | 246 | |
166 | 247 | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) |
167 | 248 | { |
168 | - u32 erase_size; | |
169 | - u8 cmd[4]; | |
249 | + u32 erase_size, erase_addr; | |
250 | + u8 cmd[SPI_FLASH_CMD_LEN]; | |
170 | 251 | int ret = -1; |
171 | 252 | |
172 | 253 | erase_size = flash->erase_size; |
173 | 254 | |
174 | 255 | |
175 | 256 | |
... | ... | @@ -177,15 +258,21 @@ |
177 | 258 | |
178 | 259 | cmd[0] = flash->erase_cmd; |
179 | 260 | while (len) { |
261 | + erase_addr = offset; | |
262 | + | |
263 | +#ifdef CONFIG_SF_DUAL_FLASH | |
264 | + if (flash->dual_flash > SF_SINGLE_FLASH) | |
265 | + spi_flash_dual_flash(flash, &erase_addr); | |
266 | +#endif | |
180 | 267 | #ifdef CONFIG_SPI_FLASH_BAR |
181 | - ret = spi_flash_bank(flash, offset); | |
268 | + ret = spi_flash_bank(flash, erase_addr); | |
182 | 269 | if (ret < 0) |
183 | 270 | return ret; |
184 | 271 | #endif |
185 | - spi_flash_addr(offset, cmd); | |
272 | + spi_flash_addr(erase_addr, cmd); | |
186 | 273 | |
187 | 274 | debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], |
188 | - cmd[2], cmd[3], offset); | |
275 | + cmd[2], cmd[3], erase_addr); | |
189 | 276 | |
190 | 277 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); |
191 | 278 | if (ret < 0) { |
192 | 279 | |
193 | 280 | |
194 | 281 | |
195 | 282 | |
... | ... | @@ -204,16 +291,23 @@ |
204 | 291 | size_t len, const void *buf) |
205 | 292 | { |
206 | 293 | unsigned long byte_addr, page_size; |
294 | + u32 write_addr; | |
207 | 295 | size_t chunk_len, actual; |
208 | - u8 cmd[4]; | |
296 | + u8 cmd[SPI_FLASH_CMD_LEN]; | |
209 | 297 | int ret = -1; |
210 | 298 | |
211 | 299 | page_size = flash->page_size; |
212 | 300 | |
213 | - cmd[0] = CMD_PAGE_PROGRAM; | |
301 | + cmd[0] = flash->write_cmd; | |
214 | 302 | for (actual = 0; actual < len; actual += chunk_len) { |
303 | + write_addr = offset; | |
304 | + | |
305 | +#ifdef CONFIG_SF_DUAL_FLASH | |
306 | + if (flash->dual_flash > SF_SINGLE_FLASH) | |
307 | + spi_flash_dual_flash(flash, &write_addr); | |
308 | +#endif | |
215 | 309 | #ifdef CONFIG_SPI_FLASH_BAR |
216 | - ret = spi_flash_bank(flash, offset); | |
310 | + ret = spi_flash_bank(flash, write_addr); | |
217 | 311 | if (ret < 0) |
218 | 312 | return ret; |
219 | 313 | #endif |
220 | 314 | |
... | ... | @@ -223,9 +317,9 @@ |
223 | 317 | if (flash->spi->max_write_size) |
224 | 318 | chunk_len = min(chunk_len, flash->spi->max_write_size); |
225 | 319 | |
226 | - spi_flash_addr(offset, cmd); | |
320 | + spi_flash_addr(write_addr, cmd); | |
227 | 321 | |
228 | - debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", | |
322 | + debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", | |
229 | 323 | buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); |
230 | 324 | |
231 | 325 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), |
... | ... | @@ -267,8 +361,9 @@ |
267 | 361 | int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, |
268 | 362 | size_t len, void *data) |
269 | 363 | { |
270 | - u8 cmd[5], bank_sel = 0; | |
271 | - u32 remain_len, read_len; | |
364 | + u8 *cmd, cmdsz; | |
365 | + u32 remain_len, read_len, read_addr; | |
366 | + int bank_sel = 0; | |
272 | 367 | int ret = -1; |
273 | 368 | |
274 | 369 | /* Handle memory-mapped SPI */ |
275 | 370 | |
276 | 371 | |
277 | 372 | |
278 | 373 | |
279 | 374 | |
280 | 375 | |
281 | 376 | |
... | ... | @@ -285,29 +380,33 @@ |
285 | 380 | return 0; |
286 | 381 | } |
287 | 382 | |
288 | - cmd[0] = CMD_READ_ARRAY_FAST; | |
289 | - cmd[4] = 0x00; | |
383 | + cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte; | |
384 | + cmd = malloc(cmdsz); | |
385 | + memset(cmd, 0, cmdsz); | |
290 | 386 | |
387 | + cmd[0] = flash->read_cmd; | |
291 | 388 | while (len) { |
292 | -#ifdef CONFIG_SPI_FLASH_BAR | |
293 | - bank_sel = offset / SPI_FLASH_16MB_BOUN; | |
389 | + read_addr = offset; | |
294 | 390 | |
295 | - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | |
296 | - if (ret) { | |
297 | - debug("SF: fail to set bank%d\n", bank_sel); | |
391 | +#ifdef CONFIG_SF_DUAL_FLASH | |
392 | + if (flash->dual_flash > SF_SINGLE_FLASH) | |
393 | + spi_flash_dual_flash(flash, &read_addr); | |
394 | +#endif | |
395 | +#ifdef CONFIG_SPI_FLASH_BAR | |
396 | + bank_sel = spi_flash_bank(flash, read_addr); | |
397 | + if (bank_sel < 0) | |
298 | 398 | return ret; |
299 | - } | |
300 | 399 | #endif |
301 | - remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset; | |
400 | + remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) * | |
401 | + (bank_sel + 1)) - offset; | |
302 | 402 | if (len < remain_len) |
303 | 403 | read_len = len; |
304 | 404 | else |
305 | 405 | read_len = remain_len; |
306 | 406 | |
307 | - spi_flash_addr(offset, cmd); | |
407 | + spi_flash_addr(read_addr, cmd); | |
308 | 408 | |
309 | - ret = spi_flash_read_common(flash, cmd, sizeof(cmd), | |
310 | - data, read_len); | |
409 | + ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len); | |
311 | 410 | if (ret < 0) { |
312 | 411 | debug("SF: read failed\n"); |
313 | 412 | break; |
drivers/mtd/spi/sf_params.c
1 | +/* | |
2 | + * SPI flash Params table | |
3 | + * | |
4 | + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | |
5 | + * | |
6 | + * SPDX-License-Identifier: GPL-2.0+ | |
7 | + */ | |
8 | + | |
9 | +#include <common.h> | |
10 | +#include <spi_flash.h> | |
11 | + | |
12 | +#include "sf_internal.h" | |
13 | + | |
14 | +/* SPI/QSPI flash device params structure */ | |
15 | +const struct spi_flash_params spi_flash_params_table[] = { | |
16 | +#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ | |
17 | + {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, 0, SECT_4K}, | |
18 | + {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0, SECT_4K}, | |
19 | + {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0, SECT_4K}, | |
20 | + {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0, SECT_4K}, | |
21 | + {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0, SECT_4K}, | |
22 | + {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0, SECT_4K}, | |
23 | + {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0, SECT_4K}, | |
24 | + {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, 0, SECT_4K}, | |
25 | +#endif | |
26 | +#ifdef CONFIG_SPI_FLASH_EON /* EON */ | |
27 | + {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0, 0}, | |
28 | + {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, | |
29 | + {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0, 0}, | |
30 | + {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0, 0}, | |
31 | +#endif | |
32 | +#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ | |
33 | + {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0, SECT_4K}, | |
34 | + {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0, SECT_4K}, | |
35 | +#endif | |
36 | +#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ | |
37 | + {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0, 0}, | |
38 | + {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0, 0}, | |
39 | + {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0, 0}, | |
40 | + {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0, 0}, | |
41 | + {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0, 0}, | |
42 | + {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0, 0}, | |
43 | + {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, | |
44 | + {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP}, | |
45 | + {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP}, | |
46 | + {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, | |
47 | +#endif | |
48 | +#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ | |
49 | + {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0, 0}, | |
50 | + {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0, 0}, | |
51 | + {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0, 0}, | |
52 | + {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0, 0}, | |
53 | + {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, RD_FULL, WR_QPP}, | |
54 | + {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, RD_FULL, WR_QPP}, | |
55 | + {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, RD_FULL, WR_QPP}, | |
56 | + {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, RD_FULL, WR_QPP}, | |
57 | + {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, RD_FULL, WR_QPP}, | |
58 | + {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, RD_FULL, WR_QPP}, | |
59 | + {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_FULL, WR_QPP}, | |
60 | + {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, RD_FULL, WR_QPP}, | |
61 | + {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL, WR_QPP}, | |
62 | +#endif | |
63 | +#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ | |
64 | + {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0, 0}, | |
65 | + {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0, 0}, | |
66 | + {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0, 0}, | |
67 | + {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0, 0}, | |
68 | + {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0, 0}, | |
69 | + {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0, 0}, | |
70 | + {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0, 0}, | |
71 | + {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0, 0}, | |
72 | + {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K}, | |
73 | + {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K}, | |
74 | + {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K}, | |
75 | + {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K}, | |
76 | + {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, | |
77 | + {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, | |
78 | + {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K}, | |
79 | + {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K}, | |
80 | + {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K}, | |
81 | + {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP | E_FSR | SECT_4K}, | |
82 | + {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K}, | |
83 | + {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL, WR_QPP | E_FSR | SECT_4K}, | |
84 | +#endif | |
85 | +#ifdef CONFIG_SPI_FLASH_SST /* SST */ | |
86 | + {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, | |
87 | + {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, | |
88 | + {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, 0, SECT_4K | SST_WP}, | |
89 | + {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, 0, SECT_4K | SST_WP}, | |
90 | + {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0, SECT_4K}, | |
91 | + {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, 0, SECT_4K | SST_WP}, | |
92 | + {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, 0, SECT_4K | SST_WP}, | |
93 | + {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, 0, SECT_4K | SST_WP}, | |
94 | + {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, | |
95 | + {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, | |
96 | +#endif | |
97 | +#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ | |
98 | + {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0, 0}, | |
99 | + {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0, 0}, | |
100 | + {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0, 0}, | |
101 | + {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0, SECT_4K}, | |
102 | + {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0, SECT_4K}, | |
103 | + {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0, SECT_4K}, | |
104 | + {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, | |
105 | + {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K}, | |
106 | + {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K}, | |
107 | + {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K}, | |
108 | + {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K}, | |
109 | + {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K}, | |
110 | + {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP | SECT_4K}, | |
111 | + {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, RD_FULL, WR_QPP | SECT_4K}, | |
112 | + {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, RD_FULL, WR_QPP | SECT_4K}, | |
113 | + {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, RD_FULL, WR_QPP | SECT_4K}, | |
114 | + {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, RD_FULL, WR_QPP | SECT_4K}, | |
115 | + {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP | SECT_4K}, | |
116 | +#endif | |
117 | + /* | |
118 | + * Note: | |
119 | + * Below paired flash devices has similar spi_flash params. | |
120 | + * (S25FL129P_64K, S25FL128S_64K) | |
121 | + * (W25Q80BL, W25Q80BV) | |
122 | + * (W25Q16CL, W25Q16DV) | |
123 | + * (W25Q32BV, W25Q32FV_SPI) | |
124 | + * (W25Q64CV, W25Q64FV_SPI) | |
125 | + * (W25Q128BV, W25Q128FV_SPI) | |
126 | + * (W25Q32DW, W25Q32FV_QPI) | |
127 | + * (W25Q64DW, W25Q64FV_QPI) | |
128 | + * (W25Q128FW, W25Q128FV_QPI) | |
129 | + */ | |
130 | +}; |
drivers/mtd/spi/sf_probe.c
... | ... | @@ -19,154 +19,93 @@ |
19 | 19 | |
20 | 20 | DECLARE_GLOBAL_DATA_PTR; |
21 | 21 | |
22 | -/** | |
23 | - * struct spi_flash_params - SPI/QSPI flash device params structure | |
24 | - * | |
25 | - * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) | |
26 | - * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id]) | |
27 | - * @ext_jedec: Device ext_jedec ID | |
28 | - * @sector_size: Sector size of this device | |
29 | - * @nr_sectors: No.of sectors on this device | |
30 | - * @flags: Importent param, for flash specific behaviour | |
31 | - */ | |
32 | -struct spi_flash_params { | |
33 | - const char *name; | |
34 | - u32 jedec; | |
35 | - u16 ext_jedec; | |
36 | - u32 sector_size; | |
37 | - u32 nr_sectors; | |
38 | - u16 flags; | |
22 | +/* Read commands array */ | |
23 | +static u8 spi_read_cmds_array[] = { | |
24 | + CMD_READ_ARRAY_SLOW, | |
25 | + CMD_READ_DUAL_OUTPUT_FAST, | |
26 | + CMD_READ_DUAL_IO_FAST, | |
27 | + CMD_READ_QUAD_OUTPUT_FAST, | |
28 | + CMD_READ_QUAD_IO_FAST, | |
39 | 29 | }; |
40 | 30 | |
41 | -static const struct spi_flash_params spi_flash_params_table[] = { | |
42 | -#ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ | |
43 | - {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, SECT_4K}, | |
44 | - {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, SECT_4K}, | |
45 | - {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, SECT_4K}, | |
46 | - {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, SECT_4K}, | |
47 | - {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, SECT_4K}, | |
48 | - {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, SECT_4K}, | |
49 | - {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, SECT_4K}, | |
50 | - {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, SECT_4K}, | |
31 | +#ifdef CONFIG_SPI_FLASH_MACRONIX | |
32 | +static int spi_flash_set_qeb_mxic(struct spi_flash *flash) | |
33 | +{ | |
34 | + u8 qeb_status; | |
35 | + int ret; | |
36 | + | |
37 | + ret = spi_flash_cmd_read_status(flash, &qeb_status); | |
38 | + if (ret < 0) | |
39 | + return ret; | |
40 | + | |
41 | + if (qeb_status & STATUS_QEB_MXIC) { | |
42 | + debug("SF: mxic: QEB is already set\n"); | |
43 | + } else { | |
44 | + ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); | |
45 | + if (ret < 0) | |
46 | + return ret; | |
47 | + } | |
48 | + | |
49 | + return ret; | |
50 | +} | |
51 | 51 | #endif |
52 | -#ifdef CONFIG_SPI_FLASH_EON /* EON */ | |
53 | - {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0}, | |
54 | - {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, SECT_4K}, | |
55 | - {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0}, | |
56 | - {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0}, | |
52 | + | |
53 | +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | |
54 | +static int spi_flash_set_qeb_winspan(struct spi_flash *flash) | |
55 | +{ | |
56 | + u8 qeb_status; | |
57 | + int ret; | |
58 | + | |
59 | + ret = spi_flash_cmd_read_config(flash, &qeb_status); | |
60 | + if (ret < 0) | |
61 | + return ret; | |
62 | + | |
63 | + if (qeb_status & STATUS_QEB_WINSPAN) { | |
64 | + debug("SF: winspan: QEB is already set\n"); | |
65 | + } else { | |
66 | + ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); | |
67 | + if (ret < 0) | |
68 | + return ret; | |
69 | + } | |
70 | + | |
71 | + return ret; | |
72 | +} | |
57 | 73 | #endif |
58 | -#ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ | |
59 | - {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, SECT_4K}, | |
60 | - {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, SECT_4K}, | |
74 | + | |
75 | +static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) | |
76 | +{ | |
77 | + switch (idcode0) { | |
78 | +#ifdef CONFIG_SPI_FLASH_MACRONIX | |
79 | + case SPI_FLASH_CFI_MFR_MACRONIX: | |
80 | + return spi_flash_set_qeb_mxic(flash); | |
61 | 81 | #endif |
62 | -#ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ | |
63 | - {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0}, | |
64 | - {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0}, | |
65 | - {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0}, | |
66 | - {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0}, | |
67 | - {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0}, | |
68 | - {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0}, | |
69 | - {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0}, | |
70 | - {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0}, | |
71 | - {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, 0}, | |
72 | - {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0}, | |
82 | +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | |
83 | + case SPI_FLASH_CFI_MFR_SPANSION: | |
84 | + case SPI_FLASH_CFI_MFR_WINBOND: | |
85 | + return spi_flash_set_qeb_winspan(flash); | |
73 | 86 | #endif |
74 | -#ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ | |
75 | - {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0}, | |
76 | - {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0}, | |
77 | - {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0}, | |
78 | - {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0}, | |
79 | - {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0}, | |
80 | - {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0}, | |
81 | - {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0}, | |
82 | - {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0}, | |
83 | - {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0}, | |
84 | - {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, 0}, | |
85 | - {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, 0}, | |
86 | - {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0}, | |
87 | - {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0}, | |
87 | +#ifdef CONFIG_SPI_FLASH_STMICRO | |
88 | + case SPI_FLASH_CFI_MFR_STMICRO: | |
89 | + debug("SF: QEB is volatile for %02x flash\n", idcode0); | |
90 | + return 0; | |
88 | 91 | #endif |
89 | -#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ | |
90 | - {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0}, | |
91 | - {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0}, | |
92 | - {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0}, | |
93 | - {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0}, | |
94 | - {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0}, | |
95 | - {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0}, | |
96 | - {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0}, | |
97 | - {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0}, | |
98 | - {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, SECT_4K}, | |
99 | - {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, SECT_4K}, | |
100 | - {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, SECT_4K}, | |
101 | - {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, SECT_4K}, | |
102 | - {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, SECT_4K}, | |
103 | - {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, SECT_4K}, | |
104 | - {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, SECT_4K}, | |
105 | - {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, SECT_4K}, | |
106 | - {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, | |
107 | - {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, E_FSR | SECT_4K}, | |
108 | - {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, | |
109 | - {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, E_FSR | SECT_4K}, | |
110 | -#endif | |
111 | -#ifdef CONFIG_SPI_FLASH_SST /* SST */ | |
112 | - {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, | |
113 | - {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, | |
114 | - {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, SECT_4K | SST_WP}, | |
115 | - {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, SECT_4K | SST_WP}, | |
116 | - {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, SECT_4K}, | |
117 | - {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, SECT_4K | SST_WP}, | |
118 | - {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, SECT_4K | SST_WP}, | |
119 | - {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, SECT_4K | SST_WP}, | |
120 | - {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WP}, | |
121 | - {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WP}, | |
122 | -#endif | |
123 | -#ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ | |
124 | - {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0}, | |
125 | - {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0}, | |
126 | - {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0}, | |
127 | - {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, SECT_4K}, | |
128 | - {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, SECT_4K}, | |
129 | - {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, SECT_4K}, | |
130 | - {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, SECT_4K}, | |
131 | - {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, SECT_4K}, | |
132 | - {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, SECT_4K}, | |
133 | - {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, SECT_4K}, | |
134 | - {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, SECT_4K}, | |
135 | - {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, SECT_4K}, | |
136 | - {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, SECT_4K}, | |
137 | - {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, SECT_4K}, | |
138 | - {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, SECT_4K}, | |
139 | - {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, SECT_4K}, | |
140 | - {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, SECT_4K}, | |
141 | - {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, SECT_4K}, | |
142 | -#endif | |
143 | - /* | |
144 | - * Note: | |
145 | - * Below paired flash devices has similar spi_flash params. | |
146 | - * (S25FL129P_64K, S25FL128S_64K) | |
147 | - * (W25Q80BL, W25Q80BV) | |
148 | - * (W25Q16CL, W25Q16DV) | |
149 | - * (W25Q32BV, W25Q32FV_SPI) | |
150 | - * (W25Q64CV, W25Q64FV_SPI) | |
151 | - * (W25Q128BV, W25Q128FV_SPI) | |
152 | - * (W25Q32DW, W25Q32FV_QPI) | |
153 | - * (W25Q64DW, W25Q64FV_QPI) | |
154 | - * (W25Q128FW, W25Q128FV_QPI) | |
155 | - */ | |
156 | -}; | |
92 | + default: | |
93 | + printf("SF: Need set QEB func for %02x flash\n", idcode0); | |
94 | + return -1; | |
95 | + } | |
96 | +} | |
157 | 97 | |
158 | 98 | static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, |
159 | 99 | u8 *idcode) |
160 | 100 | { |
161 | 101 | const struct spi_flash_params *params; |
162 | 102 | struct spi_flash *flash; |
163 | - int i; | |
103 | + u8 cmd; | |
164 | 104 | u16 jedec = idcode[1] << 8 | idcode[2]; |
165 | 105 | u16 ext_jedec = idcode[3] << 8 | idcode[4]; |
166 | 106 | |
167 | - /* Get the flash id (jedec = manuf_id + dev_id, ext_jedec) */ | |
168 | - for (i = 0; i < ARRAY_SIZE(spi_flash_params_table); i++) { | |
169 | - params = &spi_flash_params_table[i]; | |
107 | + params = spi_flash_params_table; | |
108 | + for (; params->name != NULL; params++) { | |
170 | 109 | if ((params->jedec >> 16) == idcode[0]) { |
171 | 110 | if ((params->jedec & 0xFFFF) == jedec) { |
172 | 111 | if (params->ext_jedec == 0) |
... | ... | @@ -177,7 +116,7 @@ |
177 | 116 | } |
178 | 117 | } |
179 | 118 | |
180 | - if (i == ARRAY_SIZE(spi_flash_params_table)) { | |
119 | + if (!params->name) { | |
181 | 120 | printf("SF: Unsupported flash IDs: "); |
182 | 121 | printf("manuf %02x, jedec %04x, ext_jedec %04x\n", |
183 | 122 | idcode[0], jedec, ext_jedec); |
... | ... | @@ -195,6 +134,7 @@ |
195 | 134 | flash->spi = spi; |
196 | 135 | flash->name = params->name; |
197 | 136 | flash->memory_map = spi->memory_map; |
137 | + flash->dual_flash = flash->spi->option; | |
198 | 138 | |
199 | 139 | /* Assign spi_flash ops */ |
200 | 140 | flash->write = spi_flash_cmd_write_ops; |
201 | 141 | |
202 | 142 | |
203 | 143 | |
... | ... | @@ -206,23 +146,74 @@ |
206 | 146 | flash->read = spi_flash_cmd_read_ops; |
207 | 147 | |
208 | 148 | /* Compute the flash size */ |
209 | - flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; | |
210 | - flash->sector_size = params->sector_size; | |
211 | - flash->size = flash->sector_size * params->nr_sectors; | |
149 | + flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; | |
150 | + flash->page_size = ((ext_jedec == 0x4d00) ? 512 : 256) << flash->shift; | |
151 | + flash->sector_size = params->sector_size << flash->shift; | |
152 | + flash->size = flash->sector_size * params->nr_sectors << flash->shift; | |
153 | +#ifdef CONFIG_SF_DUAL_FLASH | |
154 | + if (flash->dual_flash & SF_DUAL_STACKED_FLASH) | |
155 | + flash->size <<= 1; | |
156 | +#endif | |
212 | 157 | |
213 | 158 | /* Compute erase sector and command */ |
214 | 159 | if (params->flags & SECT_4K) { |
215 | 160 | flash->erase_cmd = CMD_ERASE_4K; |
216 | - flash->erase_size = 4096; | |
161 | + flash->erase_size = 4096 << flash->shift; | |
217 | 162 | } else if (params->flags & SECT_32K) { |
218 | 163 | flash->erase_cmd = CMD_ERASE_32K; |
219 | - flash->erase_size = 32768; | |
164 | + flash->erase_size = 32768 << flash->shift; | |
220 | 165 | } else { |
221 | 166 | flash->erase_cmd = CMD_ERASE_64K; |
222 | 167 | flash->erase_size = flash->sector_size; |
223 | 168 | } |
224 | 169 | |
225 | - /* Poll cmd seclection */ | |
170 | + /* Look for the fastest read cmd */ | |
171 | + cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); | |
172 | + if (cmd) { | |
173 | + cmd = spi_read_cmds_array[cmd - 1]; | |
174 | + flash->read_cmd = cmd; | |
175 | + } else { | |
176 | + /* Go for default supported read cmd */ | |
177 | + flash->read_cmd = CMD_READ_ARRAY_FAST; | |
178 | + } | |
179 | + | |
180 | + /* Not require to look for fastest only two write cmds yet */ | |
181 | + if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) | |
182 | + flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; | |
183 | + else | |
184 | + /* Go for default supported write cmd */ | |
185 | + flash->write_cmd = CMD_PAGE_PROGRAM; | |
186 | + | |
187 | + /* Set the quad enable bit - only for quad commands */ | |
188 | + if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || | |
189 | + (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || | |
190 | + (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { | |
191 | + if (spi_flash_set_qeb(flash, idcode[0])) { | |
192 | + debug("SF: Fail to set QEB for %02x\n", idcode[0]); | |
193 | + return NULL; | |
194 | + } | |
195 | + } | |
196 | + | |
197 | + /* Read dummy_byte: dummy byte is determined based on the | |
198 | + * dummy cycles of a particular command. | |
199 | + * Fast commands - dummy_byte = dummy_cycles/8 | |
200 | + * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 | |
201 | + * For I/O commands except cmd[0] everything goes on no.of lines | |
202 | + * based on particular command but incase of fast commands except | |
203 | + * data all go on single line irrespective of command. | |
204 | + */ | |
205 | + switch (flash->read_cmd) { | |
206 | + case CMD_READ_QUAD_IO_FAST: | |
207 | + flash->dummy_byte = 2; | |
208 | + break; | |
209 | + case CMD_READ_ARRAY_SLOW: | |
210 | + flash->dummy_byte = 0; | |
211 | + break; | |
212 | + default: | |
213 | + flash->dummy_byte = 1; | |
214 | + } | |
215 | + | |
216 | + /* Poll cmd selection */ | |
226 | 217 | flash->poll_cmd = CMD_READ_STATUS; |
227 | 218 | #ifdef CONFIG_SPI_FLASH_STMICRO |
228 | 219 | if (params->flags & E_FSR) |
... | ... | @@ -339,7 +330,10 @@ |
339 | 330 | puts("\n"); |
340 | 331 | #endif |
341 | 332 | #ifndef CONFIG_SPI_FLASH_BAR |
342 | - if (flash->size > SPI_FLASH_16MB_BOUN) { | |
333 | + if (((flash->dual_flash == SF_SINGLE_FLASH) && | |
334 | + (flash->size > SPI_FLASH_16MB_BOUN)) || | |
335 | + ((flash->dual_flash > SF_SINGLE_FLASH) && | |
336 | + (flash->size > SPI_FLASH_16MB_BOUN << 1))) { | |
343 | 337 | puts("SF: Warning - Only lower 16MiB accessible,"); |
344 | 338 | puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); |
345 | 339 | } |
drivers/spi/Makefile
... | ... | @@ -19,6 +19,7 @@ |
19 | 19 | obj-$(CONFIG_CF_QSPI) += cf_qspi.o |
20 | 20 | obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o |
21 | 21 | obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o |
22 | +obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o | |
22 | 23 | obj-$(CONFIG_ICH_SPI) += ich.o |
23 | 24 | obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o |
24 | 25 | obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o |
drivers/spi/ftssp010_spi.c
1 | +/* | |
2 | + * (C) Copyright 2013 | |
3 | + * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/> | |
4 | + * Kuo-Jung Su <dantesu@gmail.com> | |
5 | + * | |
6 | + * SPDX-License-Identifier: GPL-2.0+ | |
7 | + */ | |
8 | + | |
9 | +#include <common.h> | |
10 | +#include <linux/compat.h> | |
11 | +#include <asm/io.h> | |
12 | +#include <malloc.h> | |
13 | +#include <spi.h> | |
14 | + | |
15 | +#ifndef CONFIG_FTSSP010_BASE_LIST | |
16 | +#define CONFIG_FTSSP010_BASE_LIST { CONFIG_FTSSP010_BASE } | |
17 | +#endif | |
18 | + | |
19 | +#ifndef CONFIG_FTSSP010_GPIO_BASE | |
20 | +#define CONFIG_FTSSP010_GPIO_BASE 0 | |
21 | +#endif | |
22 | + | |
23 | +#ifndef CONFIG_FTSSP010_GPIO_LIST | |
24 | +#define CONFIG_FTSSP010_GPIO_LIST { CONFIG_FTSSP010_GPIO_BASE } | |
25 | +#endif | |
26 | + | |
27 | +#ifndef CONFIG_FTSSP010_CLOCK | |
28 | +#define CONFIG_FTSSP010_CLOCK clk_get_rate("SSP"); | |
29 | +#endif | |
30 | + | |
31 | +#ifndef CONFIG_FTSSP010_TIMEOUT | |
32 | +#define CONFIG_FTSSP010_TIMEOUT 100 | |
33 | +#endif | |
34 | + | |
35 | +/* FTSSP010 chip registers */ | |
36 | +struct ftssp010_regs { | |
37 | + uint32_t cr[3];/* control register */ | |
38 | + uint32_t sr; /* status register */ | |
39 | + uint32_t icr; /* interrupt control register */ | |
40 | + uint32_t isr; /* interrupt status register */ | |
41 | + uint32_t dr; /* data register */ | |
42 | + uint32_t rsvd[17]; | |
43 | + uint32_t revr; /* revision register */ | |
44 | + uint32_t fear; /* feature register */ | |
45 | +}; | |
46 | + | |
47 | +/* Control Register 0 */ | |
48 | +#define CR0_FFMT_MASK (7 << 12) | |
49 | +#define CR0_FFMT_SSP (0 << 12) | |
50 | +#define CR0_FFMT_SPI (1 << 12) | |
51 | +#define CR0_FFMT_MICROWIRE (2 << 12) | |
52 | +#define CR0_FFMT_I2S (3 << 12) | |
53 | +#define CR0_FFMT_AC97 (4 << 12) | |
54 | +#define CR0_FLASH (1 << 11) | |
55 | +#define CR0_FSDIST(x) (((x) & 0x03) << 8) | |
56 | +#define CR0_LOOP (1 << 7) /* loopback mode */ | |
57 | +#define CR0_LSB (1 << 6) /* LSB */ | |
58 | +#define CR0_FSPO (1 << 5) /* fs atcive low (I2S only) */ | |
59 | +#define CR0_FSJUSTIFY (1 << 4) | |
60 | +#define CR0_OPM_SLAVE (0 << 2) | |
61 | +#define CR0_OPM_MASTER (3 << 2) | |
62 | +#define CR0_OPM_I2S_MSST (3 << 2) /* master stereo mode */ | |
63 | +#define CR0_OPM_I2S_MSMO (2 << 2) /* master mono mode */ | |
64 | +#define CR0_OPM_I2S_SLST (1 << 2) /* slave stereo mode */ | |
65 | +#define CR0_OPM_I2S_SLMO (0 << 2) /* slave mono mode */ | |
66 | +#define CR0_SCLKPO (1 << 1) /* clock polarity */ | |
67 | +#define CR0_SCLKPH (1 << 0) /* clock phase */ | |
68 | + | |
69 | +/* Control Register 1 */ | |
70 | +#define CR1_PDL(x) (((x) & 0xff) << 24) /* padding length */ | |
71 | +#define CR1_SDL(x) ((((x) - 1) & 0x1f) << 16) /* data length */ | |
72 | +#define CR1_DIV(x) (((x) - 1) & 0xffff) /* clock divider */ | |
73 | + | |
74 | +/* Control Register 2 */ | |
75 | +#define CR2_CS(x) (((x) & 3) << 10) /* CS/FS select */ | |
76 | +#define CR2_FS (1 << 9) /* CS/FS signal level */ | |
77 | +#define CR2_TXEN (1 << 8) /* tx enable */ | |
78 | +#define CR2_RXEN (1 << 7) /* rx enable */ | |
79 | +#define CR2_RESET (1 << 6) /* chip reset */ | |
80 | +#define CR2_TXFC (1 << 3) /* tx fifo Clear */ | |
81 | +#define CR2_RXFC (1 << 2) /* rx fifo Clear */ | |
82 | +#define CR2_TXDOE (1 << 1) /* tx data output enable */ | |
83 | +#define CR2_EN (1 << 0) /* chip enable */ | |
84 | + | |
85 | +/* Status Register */ | |
86 | +#define SR_RFF (1 << 0) /* rx fifo full */ | |
87 | +#define SR_TFNF (1 << 1) /* tx fifo not full */ | |
88 | +#define SR_BUSY (1 << 2) /* chip busy */ | |
89 | +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f) /* rx fifo valid entries */ | |
90 | +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* tx fifo valid entries */ | |
91 | + | |
92 | +/* Feature Register */ | |
93 | +#define FEAR_BITS(reg) ((((reg) >> 0) & 0xff) + 1) /* data width */ | |
94 | +#define FEAR_RFSZ(reg) ((((reg) >> 8) & 0xff) + 1) /* rx fifo size */ | |
95 | +#define FEAR_TFSZ(reg) ((((reg) >> 16) & 0xff) + 1) /* tx fifo size */ | |
96 | +#define FEAR_AC97 (1 << 24) | |
97 | +#define FEAR_I2S (1 << 25) | |
98 | +#define FEAR_SPI_MWR (1 << 26) | |
99 | +#define FEAR_SSP (1 << 27) | |
100 | +#define FEAR_SPDIF (1 << 28) | |
101 | + | |
102 | +/* FTGPIO010 chip registers */ | |
103 | +struct ftgpio010_regs { | |
104 | + uint32_t out; /* 0x00: Data Output */ | |
105 | + uint32_t in; /* 0x04: Data Input */ | |
106 | + uint32_t dir; /* 0x08: Direction */ | |
107 | + uint32_t bypass; /* 0x0c: Bypass */ | |
108 | + uint32_t set; /* 0x10: Data Set */ | |
109 | + uint32_t clr; /* 0x14: Data Clear */ | |
110 | + uint32_t pull_up; /* 0x18: Pull-Up Enabled */ | |
111 | + uint32_t pull_st; /* 0x1c: Pull State (0=pull-down, 1=pull-up) */ | |
112 | +}; | |
113 | + | |
114 | +struct ftssp010_gpio { | |
115 | + struct ftgpio010_regs *regs; | |
116 | + uint32_t pin; | |
117 | +}; | |
118 | + | |
119 | +struct ftssp010_spi { | |
120 | + struct spi_slave slave; | |
121 | + struct ftssp010_gpio gpio; | |
122 | + struct ftssp010_regs *regs; | |
123 | + uint32_t fifo; | |
124 | + uint32_t mode; | |
125 | + uint32_t div; | |
126 | + uint32_t clk; | |
127 | + uint32_t speed; | |
128 | + uint32_t revision; | |
129 | +}; | |
130 | + | |
131 | +static inline struct ftssp010_spi *to_ftssp010_spi(struct spi_slave *slave) | |
132 | +{ | |
133 | + return container_of(slave, struct ftssp010_spi, slave); | |
134 | +} | |
135 | + | |
136 | +static int get_spi_chip(int bus, struct ftssp010_spi *chip) | |
137 | +{ | |
138 | + uint32_t fear, base[] = CONFIG_FTSSP010_BASE_LIST; | |
139 | + | |
140 | + if (bus >= ARRAY_SIZE(base) || !base[bus]) | |
141 | + return -1; | |
142 | + | |
143 | + chip->regs = (struct ftssp010_regs *)base[bus]; | |
144 | + | |
145 | + chip->revision = readl(&chip->regs->revr); | |
146 | + | |
147 | + fear = readl(&chip->regs->fear); | |
148 | + chip->fifo = min_t(uint32_t, FEAR_TFSZ(fear), FEAR_RFSZ(fear)); | |
149 | + | |
150 | + return 0; | |
151 | +} | |
152 | + | |
153 | +static int get_spi_gpio(int bus, struct ftssp010_gpio *chip) | |
154 | +{ | |
155 | + uint32_t base[] = CONFIG_FTSSP010_GPIO_LIST; | |
156 | + | |
157 | + if (bus >= ARRAY_SIZE(base) || !base[bus]) | |
158 | + return -1; | |
159 | + | |
160 | + chip->regs = (struct ftgpio010_regs *)(base[bus] & 0xfff00000); | |
161 | + chip->pin = base[bus] & 0x1f; | |
162 | + | |
163 | + /* make it an output pin */ | |
164 | + setbits_le32(&chip->regs->dir, 1 << chip->pin); | |
165 | + | |
166 | + return 0; | |
167 | +} | |
168 | + | |
169 | +static int ftssp010_wait(struct ftssp010_spi *chip) | |
170 | +{ | |
171 | + struct ftssp010_regs *regs = chip->regs; | |
172 | + int ret = -1; | |
173 | + ulong t; | |
174 | + | |
175 | + /* wait until device idle */ | |
176 | + for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) { | |
177 | + if (readl(®s->sr) & SR_BUSY) | |
178 | + continue; | |
179 | + ret = 0; | |
180 | + break; | |
181 | + } | |
182 | + | |
183 | + if (ret) | |
184 | + puts("ftspi010: busy timeout\n"); | |
185 | + | |
186 | + return ret; | |
187 | +} | |
188 | + | |
189 | +static int ftssp010_wait_tx(struct ftssp010_spi *chip) | |
190 | +{ | |
191 | + struct ftssp010_regs *regs = chip->regs; | |
192 | + int ret = -1; | |
193 | + ulong t; | |
194 | + | |
195 | + /* wait until tx fifo not full */ | |
196 | + for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) { | |
197 | + if (!(readl(®s->sr) & SR_TFNF)) | |
198 | + continue; | |
199 | + ret = 0; | |
200 | + break; | |
201 | + } | |
202 | + | |
203 | + if (ret) | |
204 | + puts("ftssp010: tx timeout\n"); | |
205 | + | |
206 | + return ret; | |
207 | +} | |
208 | + | |
209 | +static int ftssp010_wait_rx(struct ftssp010_spi *chip) | |
210 | +{ | |
211 | + struct ftssp010_regs *regs = chip->regs; | |
212 | + int ret = -1; | |
213 | + ulong t; | |
214 | + | |
215 | + /* wait until rx fifo not empty */ | |
216 | + for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) { | |
217 | + if (!SR_RFVE(readl(®s->sr))) | |
218 | + continue; | |
219 | + ret = 0; | |
220 | + break; | |
221 | + } | |
222 | + | |
223 | + if (ret) | |
224 | + puts("ftssp010: rx timeout\n"); | |
225 | + | |
226 | + return ret; | |
227 | +} | |
228 | + | |
229 | +static int ftssp010_spi_work_transfer_v2(struct ftssp010_spi *chip, | |
230 | + const void *tx_buf, void *rx_buf, int len, uint flags) | |
231 | +{ | |
232 | + struct ftssp010_regs *regs = chip->regs; | |
233 | + const uint8_t *txb = tx_buf; | |
234 | + uint8_t *rxb = rx_buf; | |
235 | + | |
236 | + while (len > 0) { | |
237 | + int i, depth = min(chip->fifo >> 2, len); | |
238 | + uint32_t xmsk = 0; | |
239 | + | |
240 | + if (tx_buf) { | |
241 | + for (i = 0; i < depth; ++i) { | |
242 | + ftssp010_wait_tx(chip); | |
243 | + writel(*txb++, ®s->dr); | |
244 | + } | |
245 | + xmsk |= CR2_TXEN | CR2_TXDOE; | |
246 | + if ((readl(®s->cr[2]) & xmsk) != xmsk) | |
247 | + setbits_le32(®s->cr[2], xmsk); | |
248 | + } | |
249 | + if (rx_buf) { | |
250 | + xmsk |= CR2_RXEN; | |
251 | + if ((readl(®s->cr[2]) & xmsk) != xmsk) | |
252 | + setbits_le32(®s->cr[2], xmsk); | |
253 | + for (i = 0; i < depth; ++i) { | |
254 | + ftssp010_wait_rx(chip); | |
255 | + *rxb++ = (uint8_t)readl(®s->dr); | |
256 | + } | |
257 | + } | |
258 | + | |
259 | + len -= depth; | |
260 | + } | |
261 | + | |
262 | + return 0; | |
263 | +} | |
264 | + | |
265 | +static int ftssp010_spi_work_transfer_v1(struct ftssp010_spi *chip, | |
266 | + const void *tx_buf, void *rx_buf, int len, uint flags) | |
267 | +{ | |
268 | + struct ftssp010_regs *regs = chip->regs; | |
269 | + const uint8_t *txb = tx_buf; | |
270 | + uint8_t *rxb = rx_buf; | |
271 | + | |
272 | + while (len > 0) { | |
273 | + int i, depth = min(chip->fifo >> 2, len); | |
274 | + uint32_t tmp; | |
275 | + | |
276 | + for (i = 0; i < depth; ++i) { | |
277 | + ftssp010_wait_tx(chip); | |
278 | + writel(txb ? (*txb++) : 0, ®s->dr); | |
279 | + } | |
280 | + for (i = 0; i < depth; ++i) { | |
281 | + ftssp010_wait_rx(chip); | |
282 | + tmp = readl(®s->dr); | |
283 | + if (rxb) | |
284 | + *rxb++ = (uint8_t)tmp; | |
285 | + } | |
286 | + | |
287 | + len -= depth; | |
288 | + } | |
289 | + | |
290 | + return 0; | |
291 | +} | |
292 | + | |
293 | +static void ftssp010_cs_set(struct ftssp010_spi *chip, int high) | |
294 | +{ | |
295 | + struct ftssp010_regs *regs = chip->regs; | |
296 | + struct ftssp010_gpio *gpio = &chip->gpio; | |
297 | + uint32_t mask; | |
298 | + | |
299 | + /* cs pull high/low */ | |
300 | + if (chip->revision >= 0x11900) { | |
301 | + mask = CR2_CS(chip->slave.cs) | (high ? CR2_FS : 0); | |
302 | + writel(mask, ®s->cr[2]); | |
303 | + } else if (gpio->regs) { | |
304 | + mask = 1 << gpio->pin; | |
305 | + if (high) | |
306 | + writel(mask, &gpio->regs->set); | |
307 | + else | |
308 | + writel(mask, &gpio->regs->clr); | |
309 | + } | |
310 | + | |
311 | + /* extra delay for signal propagation */ | |
312 | + udelay_masked(1); | |
313 | +} | |
314 | + | |
315 | +/* | |
316 | + * Determine if a SPI chipselect is valid. | |
317 | + * This function is provided by the board if the low-level SPI driver | |
318 | + * needs it to determine if a given chipselect is actually valid. | |
319 | + * | |
320 | + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 | |
321 | + * otherwise. | |
322 | + */ | |
323 | +int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
324 | +{ | |
325 | + struct ftssp010_spi chip; | |
326 | + | |
327 | + if (get_spi_chip(bus, &chip)) | |
328 | + return 0; | |
329 | + | |
330 | + if (!cs) | |
331 | + return 1; | |
332 | + else if ((cs < 4) && (chip.revision >= 0x11900)) | |
333 | + return 1; | |
334 | + | |
335 | + return 0; | |
336 | +} | |
337 | + | |
338 | +/* | |
339 | + * Activate a SPI chipselect. | |
340 | + * This function is provided by the board code when using a driver | |
341 | + * that can't control its chipselects automatically (e.g. | |
342 | + * common/soft_spi.c). When called, it should activate the chip select | |
343 | + * to the device identified by "slave". | |
344 | + */ | |
345 | +void spi_cs_activate(struct spi_slave *slave) | |
346 | +{ | |
347 | + struct ftssp010_spi *chip = to_ftssp010_spi(slave); | |
348 | + struct ftssp010_regs *regs = chip->regs; | |
349 | + | |
350 | + /* cs pull */ | |
351 | + if (chip->mode & SPI_CS_HIGH) | |
352 | + ftssp010_cs_set(chip, 1); | |
353 | + else | |
354 | + ftssp010_cs_set(chip, 0); | |
355 | + | |
356 | + /* chip enable + fifo clear */ | |
357 | + setbits_le32(®s->cr[2], CR2_EN | CR2_TXFC | CR2_RXFC); | |
358 | +} | |
359 | + | |
360 | +/* | |
361 | + * Deactivate a SPI chipselect. | |
362 | + * This function is provided by the board code when using a driver | |
363 | + * that can't control its chipselects automatically (e.g. | |
364 | + * common/soft_spi.c). When called, it should deactivate the chip | |
365 | + * select to the device identified by "slave". | |
366 | + */ | |
367 | +void spi_cs_deactivate(struct spi_slave *slave) | |
368 | +{ | |
369 | + struct ftssp010_spi *chip = to_ftssp010_spi(slave); | |
370 | + | |
371 | + /* wait until chip idle */ | |
372 | + ftssp010_wait(chip); | |
373 | + | |
374 | + /* cs pull */ | |
375 | + if (chip->mode & SPI_CS_HIGH) | |
376 | + ftssp010_cs_set(chip, 0); | |
377 | + else | |
378 | + ftssp010_cs_set(chip, 1); | |
379 | +} | |
380 | + | |
381 | +void spi_init(void) | |
382 | +{ | |
383 | + /* nothing to do */ | |
384 | +} | |
385 | + | |
386 | +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) | |
387 | +{ | |
388 | + struct ftssp010_spi *chip; | |
389 | + | |
390 | + if (mode & SPI_3WIRE) { | |
391 | + puts("ftssp010: can't do 3-wire\n"); | |
392 | + return NULL; | |
393 | + } | |
394 | + | |
395 | + if (mode & SPI_SLAVE) { | |
396 | + puts("ftssp010: can't do slave mode\n"); | |
397 | + return NULL; | |
398 | + } | |
399 | + | |
400 | + if (mode & SPI_PREAMBLE) { | |
401 | + puts("ftssp010: can't skip preamble bytes\n"); | |
402 | + return NULL; | |
403 | + } | |
404 | + | |
405 | + if (!spi_cs_is_valid(bus, cs)) { | |
406 | + puts("ftssp010: invalid (bus, cs)\n"); | |
407 | + return NULL; | |
408 | + } | |
409 | + | |
410 | + chip = spi_alloc_slave(struct ftssp010_spi, bus, cs); | |
411 | + if (!chip) | |
412 | + return NULL; | |
413 | + | |
414 | + if (get_spi_chip(bus, chip)) | |
415 | + goto free_out; | |
416 | + | |
417 | + if (chip->revision < 0x11900 && get_spi_gpio(bus, &chip->gpio)) { | |
418 | + puts("ftssp010: Before revision 1.19.0, its clock & cs are\n" | |
419 | + "controlled by tx engine which is not synced with rx engine,\n" | |
420 | + "so the clock & cs might be shutdown before rx engine\n" | |
421 | + "finishs its jobs.\n" | |
422 | + "If possible, please add a dedicated gpio for it.\n"); | |
423 | + } | |
424 | + | |
425 | + chip->mode = mode; | |
426 | + chip->clk = CONFIG_FTSSP010_CLOCK; | |
427 | + chip->div = 2; | |
428 | + if (max_hz) { | |
429 | + while (chip->div < 0xffff) { | |
430 | + if ((chip->clk / (2 * chip->div)) <= max_hz) | |
431 | + break; | |
432 | + chip->div += 1; | |
433 | + } | |
434 | + } | |
435 | + chip->speed = chip->clk / (2 * chip->div); | |
436 | + | |
437 | + return &chip->slave; | |
438 | + | |
439 | +free_out: | |
440 | + free(chip); | |
441 | + return NULL; | |
442 | +} | |
443 | + | |
444 | +void spi_free_slave(struct spi_slave *slave) | |
445 | +{ | |
446 | + free(slave); | |
447 | +} | |
448 | + | |
449 | +int spi_claim_bus(struct spi_slave *slave) | |
450 | +{ | |
451 | + struct ftssp010_spi *chip = to_ftssp010_spi(slave); | |
452 | + struct ftssp010_regs *regs = chip->regs; | |
453 | + | |
454 | + writel(CR1_SDL(8) | CR1_DIV(chip->div), ®s->cr[1]); | |
455 | + | |
456 | + if (chip->revision >= 0x11900) { | |
457 | + writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH, | |
458 | + ®s->cr[0]); | |
459 | + writel(CR2_TXFC | CR2_RXFC, | |
460 | + ®s->cr[2]); | |
461 | + } else { | |
462 | + writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO, | |
463 | + ®s->cr[0]); | |
464 | + writel(CR2_TXFC | CR2_RXFC | CR2_EN | CR2_TXDOE, | |
465 | + ®s->cr[2]); | |
466 | + } | |
467 | + | |
468 | + if (chip->mode & SPI_LOOP) | |
469 | + setbits_le32(®s->cr[0], CR0_LOOP); | |
470 | + | |
471 | + if (chip->mode & SPI_CPOL) | |
472 | + setbits_le32(®s->cr[0], CR0_SCLKPO); | |
473 | + | |
474 | + if (chip->mode & SPI_CPHA) | |
475 | + setbits_le32(®s->cr[0], CR0_SCLKPH); | |
476 | + | |
477 | + spi_cs_deactivate(slave); | |
478 | + | |
479 | + return 0; | |
480 | +} | |
481 | + | |
482 | +void spi_release_bus(struct spi_slave *slave) | |
483 | +{ | |
484 | + struct ftssp010_spi *chip = to_ftssp010_spi(slave); | |
485 | + struct ftssp010_regs *regs = chip->regs; | |
486 | + | |
487 | + writel(0, ®s->cr[2]); | |
488 | +} | |
489 | + | |
490 | +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
491 | + const void *dout, void *din, unsigned long flags) | |
492 | +{ | |
493 | + struct ftssp010_spi *chip = to_ftssp010_spi(slave); | |
494 | + uint32_t len = bitlen >> 3; | |
495 | + | |
496 | + if (flags & SPI_XFER_BEGIN) | |
497 | + spi_cs_activate(slave); | |
498 | + | |
499 | + if (chip->revision >= 0x11900) | |
500 | + ftssp010_spi_work_transfer_v2(chip, dout, din, len, flags); | |
501 | + else | |
502 | + ftssp010_spi_work_transfer_v1(chip, dout, din, len, flags); | |
503 | + | |
504 | + if (flags & SPI_XFER_END) | |
505 | + spi_cs_deactivate(slave); | |
506 | + | |
507 | + return 0; | |
508 | +} |
drivers/spi/sh_spi.c
... | ... | @@ -151,7 +151,6 @@ |
151 | 151 | { |
152 | 152 | int i, cur_len, ret = 0; |
153 | 153 | int remain = (int)len; |
154 | - unsigned long tmp; | |
155 | 154 | |
156 | 155 | if (len >= SH_SPI_FIFO_SIZE) |
157 | 156 | sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1); |
... | ... | @@ -183,9 +182,7 @@ |
183 | 182 | } |
184 | 183 | |
185 | 184 | if (flags & SPI_XFER_END) { |
186 | - tmp = sh_spi_read(&ss->regs->cr1); | |
187 | - tmp = tmp & ~(SH_SPI_SSD | SH_SPI_SSDB); | |
188 | - sh_spi_write(tmp, &ss->regs->cr1); | |
185 | + sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1); | |
189 | 186 | sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1); |
190 | 187 | udelay(100); |
191 | 188 | write_fifo_empty_wait(ss); |
192 | 189 | |
... | ... | @@ -198,16 +195,13 @@ |
198 | 195 | unsigned int len, unsigned long flags) |
199 | 196 | { |
200 | 197 | int i; |
201 | - unsigned long tmp; | |
202 | 198 | |
203 | 199 | if (len > SH_SPI_MAX_BYTE) |
204 | 200 | sh_spi_write(SH_SPI_MAX_BYTE, &ss->regs->cr3); |
205 | 201 | else |
206 | 202 | sh_spi_write(len, &ss->regs->cr3); |
207 | 203 | |
208 | - tmp = sh_spi_read(&ss->regs->cr1); | |
209 | - tmp = tmp & ~(SH_SPI_SSD | SH_SPI_SSDB); | |
210 | - sh_spi_write(tmp, &ss->regs->cr1); | |
204 | + sh_spi_clear_bit(SH_SPI_SSD | SH_SPI_SSDB, &ss->regs->cr1); | |
211 | 205 | sh_spi_set_bit(SH_SPI_SSA, &ss->regs->cr1); |
212 | 206 | |
213 | 207 | for (i = 0; i < len; i++) { |
include/spi.h
... | ... | @@ -30,7 +30,25 @@ |
30 | 30 | #define SPI_XFER_MMAP 0x08 /* Memory Mapped start */ |
31 | 31 | #define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ |
32 | 32 | #define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END) |
33 | +#define SPI_XFER_U_PAGE (1 << 5) | |
33 | 34 | |
35 | +/* SPI TX operation modes */ | |
36 | +#define SPI_OPM_TX_QPP 1 << 0 | |
37 | + | |
38 | +/* SPI RX operation modes */ | |
39 | +#define SPI_OPM_RX_AS 1 << 0 | |
40 | +#define SPI_OPM_RX_DOUT 1 << 1 | |
41 | +#define SPI_OPM_RX_DIO 1 << 2 | |
42 | +#define SPI_OPM_RX_QOF 1 << 3 | |
43 | +#define SPI_OPM_RX_QIOF 1 << 4 | |
44 | +#define SPI_OPM_RX_EXTN SPI_OPM_RX_AS | SPI_OPM_RX_DOUT | \ | |
45 | + SPI_OPM_RX_DIO | SPI_OPM_RX_QOF | \ | |
46 | + SPI_OPM_RX_QIOF | |
47 | + | |
48 | +/* SPI bus connection options */ | |
49 | +#define SPI_CONN_DUAL_SHARED 1 << 0 | |
50 | +#define SPI_CONN_DUAL_SEPARATED 1 << 1 | |
51 | + | |
34 | 52 | /* Header byte that marks the start of the message */ |
35 | 53 | #define SPI_PREAMBLE_END_BYTE 0xec |
36 | 54 | |
37 | 55 | |
38 | 56 | |
39 | 57 | |
... | ... | @@ -43,17 +61,25 @@ |
43 | 61 | * |
44 | 62 | * @bus: ID of the bus that the slave is attached to. |
45 | 63 | * @cs: ID of the chip select connected to the slave. |
64 | + * @op_mode_rx: SPI RX operation mode. | |
65 | + * @op_mode_tx: SPI TX operation mode. | |
46 | 66 | * @wordlen: Size of SPI word in number of bits |
47 | 67 | * @max_write_size: If non-zero, the maximum number of bytes which can |
48 | 68 | * be written at once, excluding command bytes. |
49 | 69 | * @memory_map: Address of read-only SPI flash access. |
70 | + * @option: Varies SPI bus options - separate, shared bus. | |
71 | + * @flags: Indication of SPI flags. | |
50 | 72 | */ |
51 | 73 | struct spi_slave { |
52 | 74 | unsigned int bus; |
53 | 75 | unsigned int cs; |
76 | + u8 op_mode_rx; | |
77 | + u8 op_mode_tx; | |
54 | 78 | unsigned int wordlen; |
55 | 79 | unsigned int max_write_size; |
56 | 80 | void *memory_map; |
81 | + u8 option; | |
82 | + u8 flags; | |
57 | 83 | }; |
58 | 84 | |
59 | 85 | /** |
include/spi_flash.h
... | ... | @@ -19,11 +19,60 @@ |
19 | 19 | #include <linux/types.h> |
20 | 20 | #include <linux/compiler.h> |
21 | 21 | |
22 | +/* sf param flags */ | |
23 | +#define SECT_4K 1 << 1 | |
24 | +#define SECT_32K 1 << 2 | |
25 | +#define E_FSR 1 << 3 | |
26 | +#define WR_QPP 1 << 4 | |
27 | + | |
28 | +/* Enum list - Full read commands */ | |
29 | +enum spi_read_cmds { | |
30 | + ARRAY_SLOW = 1 << 0, | |
31 | + DUAL_OUTPUT_FAST = 1 << 1, | |
32 | + DUAL_IO_FAST = 1 << 2, | |
33 | + QUAD_OUTPUT_FAST = 1 << 3, | |
34 | + QUAD_IO_FAST = 1 << 4, | |
35 | +}; | |
36 | +#define RD_EXTN ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST | |
37 | +#define RD_FULL RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST | |
38 | + | |
39 | +/* Dual SPI flash memories */ | |
40 | +enum spi_dual_flash { | |
41 | + SF_SINGLE_FLASH = 0, | |
42 | + SF_DUAL_STACKED_FLASH = 1 << 0, | |
43 | + SF_DUAL_PARALLEL_FLASH = 1 << 1, | |
44 | +}; | |
45 | + | |
22 | 46 | /** |
47 | + * struct spi_flash_params - SPI/QSPI flash device params structure | |
48 | + * | |
49 | + * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) | |
50 | + * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id]) | |
51 | + * @ext_jedec: Device ext_jedec ID | |
52 | + * @sector_size: Sector size of this device | |
53 | + * @nr_sectors: No.of sectors on this device | |
54 | + * @e_rd_cmd: Enum list for read commands | |
55 | + * @flags: Importent param, for flash specific behaviour | |
56 | + */ | |
57 | +struct spi_flash_params { | |
58 | + const char *name; | |
59 | + u32 jedec; | |
60 | + u16 ext_jedec; | |
61 | + u32 sector_size; | |
62 | + u32 nr_sectors; | |
63 | + u8 e_rd_cmd; | |
64 | + u16 flags; | |
65 | +}; | |
66 | + | |
67 | +extern const struct spi_flash_params spi_flash_params_table[]; | |
68 | + | |
69 | +/** | |
23 | 70 | * struct spi_flash - SPI flash structure |
24 | 71 | * |
25 | 72 | * @spi: SPI slave |
26 | 73 | * @name: Name of SPI flash |
74 | + * @dual_flash: Indicates dual flash memories - dual stacked, parallel | |
75 | + * @shift: Flash shift useful in dual parallel | |
27 | 76 | * @size: Total flash size |
28 | 77 | * @page_size: Write (page) size |
29 | 78 | * @sector_size: Sector size |
... | ... | @@ -33,6 +82,9 @@ |
33 | 82 | * @bank_curr: Current flash bank |
34 | 83 | * @poll_cmd: Poll cmd - for flash erase/program |
35 | 84 | * @erase_cmd: Erase cmd 4K, 32K, 64K |
85 | + * @read_cmd: Read cmd - Array Fast, Extn read and quad read. | |
86 | + * @write_cmd: Write cmd - page and quad program. | |
87 | + * @dummy_byte: Dummy cycles for read operation. | |
36 | 88 | * @memory_map: Address of read-only SPI flash access |
37 | 89 | * @read: Flash read ops: Read len bytes at offset into buf |
38 | 90 | * Supported cmds: Fast Array Read |
... | ... | @@ -45,6 +97,8 @@ |
45 | 97 | struct spi_flash { |
46 | 98 | struct spi_slave *spi; |
47 | 99 | const char *name; |
100 | + u8 dual_flash; | |
101 | + u8 shift; | |
48 | 102 | |
49 | 103 | u32 size; |
50 | 104 | u32 page_size; |
... | ... | @@ -57,6 +111,9 @@ |
57 | 111 | #endif |
58 | 112 | u8 poll_cmd; |
59 | 113 | u8 erase_cmd; |
114 | + u8 read_cmd; | |
115 | + u8 write_cmd; | |
116 | + u8 dummy_byte; | |
60 | 117 | |
61 | 118 | void *memory_map; |
62 | 119 | int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf); |