Commit 3163aaa63fced54bbd6fd190ece0f89b473076ab
1 parent
4e09cc1e2c
Exists in
master
and in
50 other branches
sf: Add quad read/write commands support
This patch add quad commands support like - QUAD_PAGE_PROGRAM => for write program - QUAD_OUTPUT_FAST ->> for read program Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
Showing 5 changed files with 113 additions and 89 deletions Inline Diff
drivers/mtd/spi/sf_internal.h
1 | /* | 1 | /* |
2 | * SPI flash internal definitions | 2 | * SPI flash internal definitions |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Atmel Corporation | 4 | * Copyright (C) 2008 Atmel Corporation |
5 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | 5 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. |
6 | * | 6 | * |
7 | * SPDX-License-Identifier: GPL-2.0+ | 7 | * SPDX-License-Identifier: GPL-2.0+ |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #ifndef _SF_INTERNAL_H_ | 10 | #ifndef _SF_INTERNAL_H_ |
11 | #define _SF_INTERNAL_H_ | 11 | #define _SF_INTERNAL_H_ |
12 | 12 | ||
13 | #define SPI_FLASH_16MB_BOUN 0x1000000 | 13 | #define SPI_FLASH_16MB_BOUN 0x1000000 |
14 | 14 | ||
15 | /* SECT flags */ | 15 | /* SECT flags */ |
16 | #define SECT_4K (1 << 1) | 16 | #define SECT_4K (1 << 1) |
17 | #define SECT_32K (1 << 2) | 17 | #define SECT_32K (1 << 2) |
18 | #define E_FSR (1 << 3) | 18 | #define E_FSR (1 << 3) |
19 | 19 | ||
20 | /* Erase commands */ | 20 | /* Erase commands */ |
21 | #define CMD_ERASE_4K 0x20 | 21 | #define CMD_ERASE_4K 0x20 |
22 | #define CMD_ERASE_32K 0x52 | 22 | #define CMD_ERASE_32K 0x52 |
23 | #define CMD_ERASE_CHIP 0xc7 | 23 | #define CMD_ERASE_CHIP 0xc7 |
24 | #define CMD_ERASE_64K 0xd8 | 24 | #define CMD_ERASE_64K 0xd8 |
25 | 25 | ||
26 | /* Write commands */ | 26 | /* Write commands */ |
27 | #define CMD_WRITE_STATUS 0x01 | 27 | #define CMD_WRITE_STATUS 0x01 |
28 | #define CMD_PAGE_PROGRAM 0x02 | 28 | #define CMD_PAGE_PROGRAM 0x02 |
29 | #define CMD_WRITE_DISABLE 0x04 | 29 | #define CMD_WRITE_DISABLE 0x04 |
30 | #define CMD_READ_STATUS 0x05 | 30 | #define CMD_READ_STATUS 0x05 |
31 | #define CMD_QUAD_PAGE_PROGRAM 0x32 | ||
31 | #define CMD_READ_STATUS1 0x35 | 32 | #define CMD_READ_STATUS1 0x35 |
32 | #define CMD_WRITE_ENABLE 0x06 | 33 | #define CMD_WRITE_ENABLE 0x06 |
33 | #define CMD_READ_CONFIG 0x35 | 34 | #define CMD_READ_CONFIG 0x35 |
34 | #define CMD_FLAG_STATUS 0x70 | 35 | #define CMD_FLAG_STATUS 0x70 |
35 | 36 | ||
36 | /* Read commands */ | 37 | /* Read commands */ |
37 | #define CMD_READ_ARRAY_SLOW 0x03 | 38 | #define CMD_READ_ARRAY_SLOW 0x03 |
38 | #define CMD_READ_ARRAY_FAST 0x0b | 39 | #define CMD_READ_ARRAY_FAST 0x0b |
39 | #define CMD_READ_DUAL_OUTPUT_FAST 0x3b | 40 | #define CMD_READ_DUAL_OUTPUT_FAST 0x3b |
40 | #define CMD_READ_DUAL_IO_FAST 0xbb | 41 | #define CMD_READ_DUAL_IO_FAST 0xbb |
42 | #define CMD_READ_QUAD_OUTPUT_FAST 0x6b | ||
41 | #define CMD_READ_ID 0x9f | 43 | #define CMD_READ_ID 0x9f |
42 | 44 | ||
43 | /* Bank addr access commands */ | 45 | /* Bank addr access commands */ |
44 | #ifdef CONFIG_SPI_FLASH_BAR | 46 | #ifdef CONFIG_SPI_FLASH_BAR |
45 | # define CMD_BANKADDR_BRWR 0x17 | 47 | # define CMD_BANKADDR_BRWR 0x17 |
46 | # define CMD_BANKADDR_BRRD 0x16 | 48 | # define CMD_BANKADDR_BRRD 0x16 |
47 | # define CMD_EXTNADDR_WREAR 0xC5 | 49 | # define CMD_EXTNADDR_WREAR 0xC5 |
48 | # define CMD_EXTNADDR_RDEAR 0xC8 | 50 | # define CMD_EXTNADDR_RDEAR 0xC8 |
49 | #endif | 51 | #endif |
50 | 52 | ||
51 | /* Common status */ | 53 | /* Common status */ |
52 | #define STATUS_WIP 0x01 | 54 | #define STATUS_WIP 0x01 |
53 | #define STATUS_PEC 0x80 | 55 | #define STATUS_PEC 0x80 |
54 | 56 | ||
55 | /* Flash timeout values */ | 57 | /* Flash timeout values */ |
56 | #define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) | 58 | #define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) |
57 | #define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) | 59 | #define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) |
58 | #define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) | 60 | #define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) |
59 | 61 | ||
60 | /* SST specific */ | 62 | /* SST specific */ |
61 | #ifdef CONFIG_SPI_FLASH_SST | 63 | #ifdef CONFIG_SPI_FLASH_SST |
62 | # define SST_WP 0x01 /* Supports AAI word program */ | 64 | # define SST_WP 0x01 /* Supports AAI word program */ |
63 | # define CMD_SST_BP 0x02 /* Byte Program */ | 65 | # define CMD_SST_BP 0x02 /* Byte Program */ |
64 | # define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ | 66 | # define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */ |
65 | 67 | ||
66 | int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, | 68 | int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, |
67 | const void *buf); | 69 | const void *buf); |
68 | #endif | 70 | #endif |
69 | 71 | ||
70 | /* Send a single-byte command to the device and read the response */ | 72 | /* Send a single-byte command to the device and read the response */ |
71 | int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); | 73 | int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); |
72 | 74 | ||
73 | /* | 75 | /* |
74 | * Send a multi-byte command to the device and read the response. Used | 76 | * Send a multi-byte command to the device and read the response. Used |
75 | * for flash array reads, etc. | 77 | * for flash array reads, etc. |
76 | */ | 78 | */ |
77 | int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, | 79 | int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, |
78 | size_t cmd_len, void *data, size_t data_len); | 80 | size_t cmd_len, void *data, size_t data_len); |
79 | 81 | ||
80 | /* | 82 | /* |
81 | * Send a multi-byte command to the device followed by (optional) | 83 | * Send a multi-byte command to the device followed by (optional) |
82 | * data. Used for programming the flash array, etc. | 84 | * data. Used for programming the flash array, etc. |
83 | */ | 85 | */ |
84 | int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, | 86 | int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, |
85 | const void *data, size_t data_len); | 87 | const void *data, size_t data_len); |
86 | 88 | ||
87 | 89 | ||
88 | /* Flash erase(sectors) operation, support all possible erase commands */ | 90 | /* Flash erase(sectors) operation, support all possible erase commands */ |
89 | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); | 91 | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); |
90 | 92 | ||
91 | /* Program the status register */ | 93 | /* Program the status register */ |
92 | int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); | 94 | int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); |
93 | 95 | ||
94 | /* Set quad enbale bit */ | 96 | /* Set quad enbale bit */ |
95 | int spi_flash_set_qeb(struct spi_flash *flash); | 97 | int spi_flash_set_qeb(struct spi_flash *flash); |
96 | 98 | ||
97 | /* Enable writing on the SPI flash */ | 99 | /* Enable writing on the SPI flash */ |
98 | static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) | 100 | static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) |
99 | { | 101 | { |
100 | return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); | 102 | return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); |
101 | } | 103 | } |
102 | 104 | ||
103 | /* Disable writing on the SPI flash */ | 105 | /* Disable writing on the SPI flash */ |
104 | static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) | 106 | static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) |
105 | { | 107 | { |
106 | return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0); | 108 | return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0); |
107 | } | 109 | } |
108 | 110 | ||
109 | /* | 111 | /* |
110 | * Send the read status command to the device and wait for the wip | 112 | * Send the read status command to the device and wait for the wip |
111 | * (write-in-progress) bit to clear itself. | 113 | * (write-in-progress) bit to clear itself. |
112 | */ | 114 | */ |
113 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); | 115 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); |
114 | 116 | ||
115 | /* | 117 | /* |
116 | * Used for spi_flash write operation | 118 | * Used for spi_flash write operation |
117 | * - SPI claim | 119 | * - SPI claim |
118 | * - spi_flash_cmd_write_enable | 120 | * - spi_flash_cmd_write_enable |
119 | * - spi_flash_cmd_write | 121 | * - spi_flash_cmd_write |
120 | * - spi_flash_cmd_wait_ready | 122 | * - spi_flash_cmd_wait_ready |
121 | * - SPI release | 123 | * - SPI release |
122 | */ | 124 | */ |
123 | int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, | 125 | int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, |
124 | size_t cmd_len, const void *buf, size_t buf_len); | 126 | size_t cmd_len, const void *buf, size_t buf_len); |
125 | 127 | ||
126 | /* | 128 | /* |
127 | * Flash write operation, support all possible write commands. | 129 | * Flash write operation, support all possible write commands. |
128 | * Write the requested data out breaking it up into multiple write | 130 | * Write the requested data out breaking it up into multiple write |
129 | * commands as needed per the write size. | 131 | * commands as needed per the write size. |
130 | */ | 132 | */ |
131 | int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, | 133 | int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, |
132 | size_t len, const void *buf); | 134 | size_t len, const void *buf); |
133 | 135 | ||
134 | /* | 136 | /* |
135 | * Same as spi_flash_cmd_read() except it also claims/releases the SPI | 137 | * Same as spi_flash_cmd_read() except it also claims/releases the SPI |
136 | * bus. Used as common part of the ->read() operation. | 138 | * bus. Used as common part of the ->read() operation. |
137 | */ | 139 | */ |
138 | int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, | 140 | int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, |
139 | size_t cmd_len, void *data, size_t data_len); | 141 | size_t cmd_len, void *data, size_t data_len); |
140 | 142 | ||
141 | /* Flash read operation, support all possible read commands */ | 143 | /* Flash read operation, support all possible read commands */ |
142 | int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, | 144 | int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, |
143 | size_t len, void *data); | 145 | size_t len, void *data); |
144 | 146 | ||
145 | #endif /* _SF_INTERNAL_H_ */ | 147 | #endif /* _SF_INTERNAL_H_ */ |
146 | 148 |
drivers/mtd/spi/sf_ops.c
1 | /* | 1 | /* |
2 | * SPI flash operations | 2 | * SPI flash operations |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Atmel Corporation | 4 | * Copyright (C) 2008 Atmel Corporation |
5 | * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik | 5 | * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik |
6 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | 6 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. |
7 | * | 7 | * |
8 | * SPDX-License-Identifier: GPL-2.0+ | 8 | * SPDX-License-Identifier: GPL-2.0+ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <common.h> | 11 | #include <common.h> |
12 | #include <spi.h> | 12 | #include <spi.h> |
13 | #include <spi_flash.h> | 13 | #include <spi_flash.h> |
14 | #include <watchdog.h> | 14 | #include <watchdog.h> |
15 | 15 | ||
16 | #include "sf_internal.h" | 16 | #include "sf_internal.h" |
17 | 17 | ||
18 | static void spi_flash_addr(u32 addr, u8 *cmd) | 18 | static void spi_flash_addr(u32 addr, u8 *cmd) |
19 | { | 19 | { |
20 | /* cmd[0] is actual command */ | 20 | /* cmd[0] is actual command */ |
21 | cmd[1] = addr >> 16; | 21 | cmd[1] = addr >> 16; |
22 | cmd[2] = addr >> 8; | 22 | cmd[2] = addr >> 8; |
23 | cmd[3] = addr >> 0; | 23 | cmd[3] = addr >> 0; |
24 | } | 24 | } |
25 | 25 | ||
26 | int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) | 26 | int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) |
27 | { | 27 | { |
28 | u8 cmd; | 28 | u8 cmd; |
29 | int ret; | 29 | int ret; |
30 | 30 | ||
31 | cmd = CMD_WRITE_STATUS; | 31 | cmd = CMD_WRITE_STATUS; |
32 | ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); | 32 | ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); |
33 | if (ret < 0) { | 33 | if (ret < 0) { |
34 | debug("SF: fail to write status register\n"); | 34 | debug("SF: fail to write status register\n"); |
35 | return ret; | 35 | return ret; |
36 | } | 36 | } |
37 | 37 | ||
38 | return 0; | 38 | return 0; |
39 | } | 39 | } |
40 | 40 | ||
41 | #ifdef CONFIG_SPI_FLASH_BAR | 41 | #ifdef CONFIG_SPI_FLASH_BAR |
42 | static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) | 42 | static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) |
43 | { | 43 | { |
44 | u8 cmd; | 44 | u8 cmd; |
45 | int ret; | 45 | int ret; |
46 | 46 | ||
47 | if (flash->bank_curr == bank_sel) { | 47 | if (flash->bank_curr == bank_sel) { |
48 | debug("SF: not require to enable bank%d\n", bank_sel); | 48 | debug("SF: not require to enable bank%d\n", bank_sel); |
49 | return 0; | 49 | return 0; |
50 | } | 50 | } |
51 | 51 | ||
52 | cmd = flash->bank_write_cmd; | 52 | cmd = flash->bank_write_cmd; |
53 | ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); | 53 | ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); |
54 | if (ret < 0) { | 54 | if (ret < 0) { |
55 | debug("SF: fail to write bank register\n"); | 55 | debug("SF: fail to write bank register\n"); |
56 | return ret; | 56 | return ret; |
57 | } | 57 | } |
58 | flash->bank_curr = bank_sel; | 58 | flash->bank_curr = bank_sel; |
59 | 59 | ||
60 | return 0; | 60 | return 0; |
61 | } | 61 | } |
62 | 62 | ||
63 | static int spi_flash_bank(struct spi_flash *flash, u32 offset) | 63 | static int spi_flash_bank(struct spi_flash *flash, u32 offset) |
64 | { | 64 | { |
65 | u8 bank_sel; | 65 | u8 bank_sel; |
66 | int ret; | 66 | int ret; |
67 | 67 | ||
68 | bank_sel = offset / SPI_FLASH_16MB_BOUN; | 68 | bank_sel = offset / SPI_FLASH_16MB_BOUN; |
69 | 69 | ||
70 | ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | 70 | ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); |
71 | if (ret) { | 71 | if (ret) { |
72 | debug("SF: fail to set bank%d\n", bank_sel); | 72 | debug("SF: fail to set bank%d\n", bank_sel); |
73 | return ret; | 73 | return ret; |
74 | } | 74 | } |
75 | 75 | ||
76 | return 0; | 76 | return 0; |
77 | } | 77 | } |
78 | #endif | 78 | #endif |
79 | 79 | ||
80 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) | 80 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) |
81 | { | 81 | { |
82 | struct spi_slave *spi = flash->spi; | 82 | struct spi_slave *spi = flash->spi; |
83 | unsigned long timebase; | 83 | unsigned long timebase; |
84 | int ret; | 84 | int ret; |
85 | u8 status; | 85 | u8 status; |
86 | u8 check_status = 0x0; | 86 | u8 check_status = 0x0; |
87 | u8 poll_bit = STATUS_WIP; | 87 | u8 poll_bit = STATUS_WIP; |
88 | u8 cmd = flash->poll_cmd; | 88 | u8 cmd = flash->poll_cmd; |
89 | 89 | ||
90 | if (cmd == CMD_FLAG_STATUS) { | 90 | if (cmd == CMD_FLAG_STATUS) { |
91 | poll_bit = STATUS_PEC; | 91 | poll_bit = STATUS_PEC; |
92 | check_status = poll_bit; | 92 | check_status = poll_bit; |
93 | } | 93 | } |
94 | 94 | ||
95 | ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); | 95 | ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); |
96 | if (ret) { | 96 | if (ret) { |
97 | debug("SF: fail to read %s status register\n", | 97 | debug("SF: fail to read %s status register\n", |
98 | cmd == CMD_READ_STATUS ? "read" : "flag"); | 98 | cmd == CMD_READ_STATUS ? "read" : "flag"); |
99 | return ret; | 99 | return ret; |
100 | } | 100 | } |
101 | 101 | ||
102 | timebase = get_timer(0); | 102 | timebase = get_timer(0); |
103 | do { | 103 | do { |
104 | WATCHDOG_RESET(); | 104 | WATCHDOG_RESET(); |
105 | 105 | ||
106 | ret = spi_xfer(spi, 8, NULL, &status, 0); | 106 | ret = spi_xfer(spi, 8, NULL, &status, 0); |
107 | if (ret) | 107 | if (ret) |
108 | return -1; | 108 | return -1; |
109 | 109 | ||
110 | if ((status & poll_bit) == check_status) | 110 | if ((status & poll_bit) == check_status) |
111 | break; | 111 | break; |
112 | 112 | ||
113 | } while (get_timer(timebase) < timeout); | 113 | } while (get_timer(timebase) < timeout); |
114 | 114 | ||
115 | spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); | 115 | spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); |
116 | 116 | ||
117 | if ((status & poll_bit) == check_status) | 117 | if ((status & poll_bit) == check_status) |
118 | return 0; | 118 | return 0; |
119 | 119 | ||
120 | /* Timed out */ | 120 | /* Timed out */ |
121 | debug("SF: time out!\n"); | 121 | debug("SF: time out!\n"); |
122 | return -1; | 122 | return -1; |
123 | } | 123 | } |
124 | 124 | ||
125 | int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, | 125 | int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, |
126 | size_t cmd_len, const void *buf, size_t buf_len) | 126 | size_t cmd_len, const void *buf, size_t buf_len) |
127 | { | 127 | { |
128 | struct spi_slave *spi = flash->spi; | 128 | struct spi_slave *spi = flash->spi; |
129 | unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; | 129 | unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; |
130 | int ret; | 130 | int ret; |
131 | 131 | ||
132 | if (buf == NULL) | 132 | if (buf == NULL) |
133 | timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; | 133 | timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; |
134 | 134 | ||
135 | ret = spi_claim_bus(flash->spi); | 135 | ret = spi_claim_bus(flash->spi); |
136 | if (ret) { | 136 | if (ret) { |
137 | debug("SF: unable to claim SPI bus\n"); | 137 | debug("SF: unable to claim SPI bus\n"); |
138 | return ret; | 138 | return ret; |
139 | } | 139 | } |
140 | 140 | ||
141 | ret = spi_flash_cmd_write_enable(flash); | 141 | ret = spi_flash_cmd_write_enable(flash); |
142 | if (ret < 0) { | 142 | if (ret < 0) { |
143 | debug("SF: enabling write failed\n"); | 143 | debug("SF: enabling write failed\n"); |
144 | return ret; | 144 | return ret; |
145 | } | 145 | } |
146 | 146 | ||
147 | ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); | 147 | ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); |
148 | if (ret < 0) { | 148 | if (ret < 0) { |
149 | debug("SF: write cmd failed\n"); | 149 | debug("SF: write cmd failed\n"); |
150 | return ret; | 150 | return ret; |
151 | } | 151 | } |
152 | 152 | ||
153 | ret = spi_flash_cmd_wait_ready(flash, timeout); | 153 | ret = spi_flash_cmd_wait_ready(flash, timeout); |
154 | if (ret < 0) { | 154 | if (ret < 0) { |
155 | debug("SF: write %s timed out\n", | 155 | debug("SF: write %s timed out\n", |
156 | timeout == SPI_FLASH_PROG_TIMEOUT ? | 156 | timeout == SPI_FLASH_PROG_TIMEOUT ? |
157 | "program" : "page erase"); | 157 | "program" : "page erase"); |
158 | return ret; | 158 | return ret; |
159 | } | 159 | } |
160 | 160 | ||
161 | spi_release_bus(spi); | 161 | spi_release_bus(spi); |
162 | 162 | ||
163 | return ret; | 163 | return ret; |
164 | } | 164 | } |
165 | 165 | ||
166 | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) | 166 | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) |
167 | { | 167 | { |
168 | u32 erase_size; | 168 | u32 erase_size; |
169 | u8 cmd[4]; | 169 | u8 cmd[4]; |
170 | int ret = -1; | 170 | int ret = -1; |
171 | 171 | ||
172 | erase_size = flash->erase_size; | 172 | erase_size = flash->erase_size; |
173 | if (offset % erase_size || len % erase_size) { | 173 | if (offset % erase_size || len % erase_size) { |
174 | debug("SF: Erase offset/length not multiple of erase size\n"); | 174 | debug("SF: Erase offset/length not multiple of erase size\n"); |
175 | return -1; | 175 | return -1; |
176 | } | 176 | } |
177 | 177 | ||
178 | cmd[0] = flash->erase_cmd; | 178 | cmd[0] = flash->erase_cmd; |
179 | while (len) { | 179 | while (len) { |
180 | #ifdef CONFIG_SPI_FLASH_BAR | 180 | #ifdef CONFIG_SPI_FLASH_BAR |
181 | ret = spi_flash_bank(flash, offset); | 181 | ret = spi_flash_bank(flash, offset); |
182 | if (ret < 0) | 182 | if (ret < 0) |
183 | return ret; | 183 | return ret; |
184 | #endif | 184 | #endif |
185 | spi_flash_addr(offset, cmd); | 185 | spi_flash_addr(offset, cmd); |
186 | 186 | ||
187 | debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], | 187 | debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], |
188 | cmd[2], cmd[3], offset); | 188 | cmd[2], cmd[3], offset); |
189 | 189 | ||
190 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); | 190 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); |
191 | if (ret < 0) { | 191 | if (ret < 0) { |
192 | debug("SF: erase failed\n"); | 192 | debug("SF: erase failed\n"); |
193 | break; | 193 | break; |
194 | } | 194 | } |
195 | 195 | ||
196 | offset += erase_size; | 196 | offset += erase_size; |
197 | len -= erase_size; | 197 | len -= erase_size; |
198 | } | 198 | } |
199 | 199 | ||
200 | return ret; | 200 | return ret; |
201 | } | 201 | } |
202 | 202 | ||
203 | int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, | 203 | int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, |
204 | size_t len, const void *buf) | 204 | size_t len, const void *buf) |
205 | { | 205 | { |
206 | unsigned long byte_addr, page_size; | 206 | unsigned long byte_addr, page_size; |
207 | size_t chunk_len, actual; | 207 | size_t chunk_len, actual; |
208 | u8 cmd[4]; | 208 | u8 cmd[4]; |
209 | int ret = -1; | 209 | int ret = -1; |
210 | 210 | ||
211 | page_size = flash->page_size; | 211 | page_size = flash->page_size; |
212 | 212 | ||
213 | cmd[0] = CMD_PAGE_PROGRAM; | 213 | cmd[0] = flash->write_cmd; |
214 | for (actual = 0; actual < len; actual += chunk_len) { | 214 | for (actual = 0; actual < len; actual += chunk_len) { |
215 | #ifdef CONFIG_SPI_FLASH_BAR | 215 | #ifdef CONFIG_SPI_FLASH_BAR |
216 | ret = spi_flash_bank(flash, offset); | 216 | ret = spi_flash_bank(flash, offset); |
217 | if (ret < 0) | 217 | if (ret < 0) |
218 | return ret; | 218 | return ret; |
219 | #endif | 219 | #endif |
220 | byte_addr = offset % page_size; | 220 | byte_addr = offset % page_size; |
221 | chunk_len = min(len - actual, page_size - byte_addr); | 221 | chunk_len = min(len - actual, page_size - byte_addr); |
222 | 222 | ||
223 | if (flash->spi->max_write_size) | 223 | if (flash->spi->max_write_size) |
224 | chunk_len = min(chunk_len, flash->spi->max_write_size); | 224 | chunk_len = min(chunk_len, flash->spi->max_write_size); |
225 | 225 | ||
226 | spi_flash_addr(offset, cmd); | 226 | spi_flash_addr(offset, cmd); |
227 | 227 | ||
228 | debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", | 228 | debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", |
229 | buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); | 229 | buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); |
230 | 230 | ||
231 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), | 231 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), |
232 | buf + actual, chunk_len); | 232 | buf + actual, chunk_len); |
233 | if (ret < 0) { | 233 | if (ret < 0) { |
234 | debug("SF: write failed\n"); | 234 | debug("SF: write failed\n"); |
235 | break; | 235 | break; |
236 | } | 236 | } |
237 | 237 | ||
238 | offset += chunk_len; | 238 | offset += chunk_len; |
239 | } | 239 | } |
240 | 240 | ||
241 | return ret; | 241 | return ret; |
242 | } | 242 | } |
243 | 243 | ||
244 | int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, | 244 | int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, |
245 | size_t cmd_len, void *data, size_t data_len) | 245 | size_t cmd_len, void *data, size_t data_len) |
246 | { | 246 | { |
247 | struct spi_slave *spi = flash->spi; | 247 | struct spi_slave *spi = flash->spi; |
248 | int ret; | 248 | int ret; |
249 | 249 | ||
250 | ret = spi_claim_bus(flash->spi); | 250 | ret = spi_claim_bus(flash->spi); |
251 | if (ret) { | 251 | if (ret) { |
252 | debug("SF: unable to claim SPI bus\n"); | 252 | debug("SF: unable to claim SPI bus\n"); |
253 | return ret; | 253 | return ret; |
254 | } | 254 | } |
255 | 255 | ||
256 | ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); | 256 | ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); |
257 | if (ret < 0) { | 257 | if (ret < 0) { |
258 | debug("SF: read cmd failed\n"); | 258 | debug("SF: read cmd failed\n"); |
259 | return ret; | 259 | return ret; |
260 | } | 260 | } |
261 | 261 | ||
262 | spi_release_bus(spi); | 262 | spi_release_bus(spi); |
263 | 263 | ||
264 | return ret; | 264 | return ret; |
265 | } | 265 | } |
266 | 266 | ||
267 | int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, | 267 | int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, |
268 | size_t len, void *data) | 268 | size_t len, void *data) |
269 | { | 269 | { |
270 | u8 cmd[5], bank_sel = 0; | 270 | u8 cmd[5], bank_sel = 0; |
271 | u32 remain_len, read_len; | 271 | u32 remain_len, read_len; |
272 | int ret = -1; | 272 | int ret = -1; |
273 | 273 | ||
274 | /* Handle memory-mapped SPI */ | 274 | /* Handle memory-mapped SPI */ |
275 | if (flash->memory_map) { | 275 | if (flash->memory_map) { |
276 | ret = spi_claim_bus(flash->spi); | 276 | ret = spi_claim_bus(flash->spi); |
277 | if (ret) { | 277 | if (ret) { |
278 | debug("SF: unable to claim SPI bus\n"); | 278 | debug("SF: unable to claim SPI bus\n"); |
279 | return ret; | 279 | return ret; |
280 | } | 280 | } |
281 | spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP); | 281 | spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP); |
282 | memcpy(data, flash->memory_map + offset, len); | 282 | memcpy(data, flash->memory_map + offset, len); |
283 | spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END); | 283 | spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP_END); |
284 | spi_release_bus(flash->spi); | 284 | spi_release_bus(flash->spi); |
285 | return 0; | 285 | return 0; |
286 | } | 286 | } |
287 | 287 | ||
288 | cmd[0] = flash->read_cmd; | 288 | cmd[0] = flash->read_cmd; |
289 | cmd[4] = 0x00; | 289 | cmd[4] = 0x00; |
290 | 290 | ||
291 | while (len) { | 291 | while (len) { |
292 | #ifdef CONFIG_SPI_FLASH_BAR | 292 | #ifdef CONFIG_SPI_FLASH_BAR |
293 | bank_sel = offset / SPI_FLASH_16MB_BOUN; | 293 | bank_sel = offset / SPI_FLASH_16MB_BOUN; |
294 | 294 | ||
295 | ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | 295 | ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); |
296 | if (ret) { | 296 | if (ret) { |
297 | debug("SF: fail to set bank%d\n", bank_sel); | 297 | debug("SF: fail to set bank%d\n", bank_sel); |
298 | return ret; | 298 | return ret; |
299 | } | 299 | } |
300 | #endif | 300 | #endif |
301 | remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset; | 301 | remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset; |
302 | if (len < remain_len) | 302 | if (len < remain_len) |
303 | read_len = len; | 303 | read_len = len; |
304 | else | 304 | else |
305 | read_len = remain_len; | 305 | read_len = remain_len; |
306 | 306 | ||
307 | spi_flash_addr(offset, cmd); | 307 | spi_flash_addr(offset, cmd); |
308 | 308 | ||
309 | ret = spi_flash_read_common(flash, cmd, sizeof(cmd), | 309 | ret = spi_flash_read_common(flash, cmd, sizeof(cmd), |
310 | data, read_len); | 310 | data, read_len); |
311 | if (ret < 0) { | 311 | if (ret < 0) { |
312 | debug("SF: read failed\n"); | 312 | debug("SF: read failed\n"); |
313 | break; | 313 | break; |
314 | } | 314 | } |
315 | 315 | ||
316 | offset += read_len; | 316 | offset += read_len; |
317 | len -= read_len; | 317 | len -= read_len; |
318 | data += read_len; | 318 | data += read_len; |
319 | } | 319 | } |
320 | 320 | ||
321 | return ret; | 321 | return ret; |
322 | } | 322 | } |
323 | 323 | ||
324 | #ifdef CONFIG_SPI_FLASH_SST | 324 | #ifdef CONFIG_SPI_FLASH_SST |
325 | static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) | 325 | static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) |
326 | { | 326 | { |
327 | int ret; | 327 | int ret; |
328 | u8 cmd[4] = { | 328 | u8 cmd[4] = { |
329 | CMD_SST_BP, | 329 | CMD_SST_BP, |
330 | offset >> 16, | 330 | offset >> 16, |
331 | offset >> 8, | 331 | offset >> 8, |
332 | offset, | 332 | offset, |
333 | }; | 333 | }; |
334 | 334 | ||
335 | debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", | 335 | debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", |
336 | spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset); | 336 | spi_w8r8(flash->spi, CMD_READ_STATUS), buf, cmd[0], offset); |
337 | 337 | ||
338 | ret = spi_flash_cmd_write_enable(flash); | 338 | ret = spi_flash_cmd_write_enable(flash); |
339 | if (ret) | 339 | if (ret) |
340 | return ret; | 340 | return ret; |
341 | 341 | ||
342 | ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); | 342 | ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); |
343 | if (ret) | 343 | if (ret) |
344 | return ret; | 344 | return ret; |
345 | 345 | ||
346 | return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); | 346 | return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); |
347 | } | 347 | } |
348 | 348 | ||
349 | int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, | 349 | int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, |
350 | const void *buf) | 350 | const void *buf) |
351 | { | 351 | { |
352 | size_t actual, cmd_len; | 352 | size_t actual, cmd_len; |
353 | int ret; | 353 | int ret; |
354 | u8 cmd[4]; | 354 | u8 cmd[4]; |
355 | 355 | ||
356 | ret = spi_claim_bus(flash->spi); | 356 | ret = spi_claim_bus(flash->spi); |
357 | if (ret) { | 357 | if (ret) { |
358 | debug("SF: Unable to claim SPI bus\n"); | 358 | debug("SF: Unable to claim SPI bus\n"); |
359 | return ret; | 359 | return ret; |
360 | } | 360 | } |
361 | 361 | ||
362 | /* If the data is not word aligned, write out leading single byte */ | 362 | /* If the data is not word aligned, write out leading single byte */ |
363 | actual = offset % 2; | 363 | actual = offset % 2; |
364 | if (actual) { | 364 | if (actual) { |
365 | ret = sst_byte_write(flash, offset, buf); | 365 | ret = sst_byte_write(flash, offset, buf); |
366 | if (ret) | 366 | if (ret) |
367 | goto done; | 367 | goto done; |
368 | } | 368 | } |
369 | offset += actual; | 369 | offset += actual; |
370 | 370 | ||
371 | ret = spi_flash_cmd_write_enable(flash); | 371 | ret = spi_flash_cmd_write_enable(flash); |
372 | if (ret) | 372 | if (ret) |
373 | goto done; | 373 | goto done; |
374 | 374 | ||
375 | cmd_len = 4; | 375 | cmd_len = 4; |
376 | cmd[0] = CMD_SST_AAI_WP; | 376 | cmd[0] = CMD_SST_AAI_WP; |
377 | cmd[1] = offset >> 16; | 377 | cmd[1] = offset >> 16; |
378 | cmd[2] = offset >> 8; | 378 | cmd[2] = offset >> 8; |
379 | cmd[3] = offset; | 379 | cmd[3] = offset; |
380 | 380 | ||
381 | for (; actual < len - 1; actual += 2) { | 381 | for (; actual < len - 1; actual += 2) { |
382 | debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", | 382 | debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", |
383 | spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual, | 383 | spi_w8r8(flash->spi, CMD_READ_STATUS), buf + actual, |
384 | cmd[0], offset); | 384 | cmd[0], offset); |
385 | 385 | ||
386 | ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, | 386 | ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, |
387 | buf + actual, 2); | 387 | buf + actual, 2); |
388 | if (ret) { | 388 | if (ret) { |
389 | debug("SF: sst word program failed\n"); | 389 | debug("SF: sst word program failed\n"); |
390 | break; | 390 | break; |
391 | } | 391 | } |
392 | 392 | ||
393 | ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); | 393 | ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); |
394 | if (ret) | 394 | if (ret) |
395 | break; | 395 | break; |
396 | 396 | ||
397 | cmd_len = 1; | 397 | cmd_len = 1; |
398 | offset += 2; | 398 | offset += 2; |
399 | } | 399 | } |
400 | 400 | ||
401 | if (!ret) | 401 | if (!ret) |
402 | ret = spi_flash_cmd_write_disable(flash); | 402 | ret = spi_flash_cmd_write_disable(flash); |
403 | 403 | ||
404 | /* If there is a single trailing byte, write it out */ | 404 | /* If there is a single trailing byte, write it out */ |
405 | if (!ret && actual != len) | 405 | if (!ret && actual != len) |
406 | ret = sst_byte_write(flash, offset, buf + actual); | 406 | ret = sst_byte_write(flash, offset, buf + actual); |
407 | 407 | ||
408 | done: | 408 | done: |
409 | debug("SF: sst: program %s %zu bytes @ 0x%zx\n", | 409 | debug("SF: sst: program %s %zu bytes @ 0x%zx\n", |
410 | ret ? "failure" : "success", len, offset - actual); | 410 | ret ? "failure" : "success", len, offset - actual); |
411 | 411 | ||
412 | spi_release_bus(flash->spi); | 412 | spi_release_bus(flash->spi); |
413 | return ret; | 413 | return ret; |
414 | } | 414 | } |
415 | #endif | 415 | #endif |
416 | 416 |
drivers/mtd/spi/sf_probe.c
1 | /* | 1 | /* |
2 | * SPI flash probing | 2 | * SPI flash probing |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Atmel Corporation | 4 | * Copyright (C) 2008 Atmel Corporation |
5 | * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik | 5 | * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik |
6 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | 6 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. |
7 | * | 7 | * |
8 | * SPDX-License-Identifier: GPL-2.0+ | 8 | * SPDX-License-Identifier: GPL-2.0+ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <common.h> | 11 | #include <common.h> |
12 | #include <fdtdec.h> | 12 | #include <fdtdec.h> |
13 | #include <malloc.h> | 13 | #include <malloc.h> |
14 | #include <spi.h> | 14 | #include <spi.h> |
15 | #include <spi_flash.h> | 15 | #include <spi_flash.h> |
16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
17 | 17 | ||
18 | #include "sf_internal.h" | 18 | #include "sf_internal.h" |
19 | 19 | ||
20 | DECLARE_GLOBAL_DATA_PTR; | 20 | DECLARE_GLOBAL_DATA_PTR; |
21 | 21 | ||
22 | /** | 22 | /** |
23 | * struct spi_flash_params - SPI/QSPI flash device params structure | 23 | * struct spi_flash_params - SPI/QSPI flash device params structure |
24 | * | 24 | * |
25 | * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) | 25 | * @name: Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) |
26 | * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id]) | 26 | * @jedec: Device jedec ID (0x[1byte_manuf_id][2byte_dev_id]) |
27 | * @ext_jedec: Device ext_jedec ID | 27 | * @ext_jedec: Device ext_jedec ID |
28 | * @sector_size: Sector size of this device | 28 | * @sector_size: Sector size of this device |
29 | * @nr_sectors: No.of sectors on this device | 29 | * @nr_sectors: No.of sectors on this device |
30 | * @e_rd_cmd: Enum list for read commands | 30 | * @e_rd_cmd: Enum list for read commands |
31 | * @flags: Importent param, for flash specific behaviour | 31 | * @flags: Importent param, for flash specific behaviour |
32 | */ | 32 | */ |
33 | struct spi_flash_params { | 33 | struct spi_flash_params { |
34 | const char *name; | 34 | const char *name; |
35 | u32 jedec; | 35 | u32 jedec; |
36 | u16 ext_jedec; | 36 | u16 ext_jedec; |
37 | u32 sector_size; | 37 | u32 sector_size; |
38 | u32 nr_sectors; | 38 | u32 nr_sectors; |
39 | u8 e_rd_cmd; | 39 | u8 e_rd_cmd; |
40 | u16 flags; | 40 | u16 flags; |
41 | }; | 41 | }; |
42 | 42 | ||
43 | static const struct spi_flash_params spi_flash_params_table[] = { | 43 | static const struct spi_flash_params spi_flash_params_table[] = { |
44 | #ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ | 44 | #ifdef CONFIG_SPI_FLASH_ATMEL /* ATMEL */ |
45 | {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, 0, SECT_4K}, | 45 | {"AT45DB011D", 0x1f2200, 0x0, 64 * 1024, 4, 0, SECT_4K}, |
46 | {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0, SECT_4K}, | 46 | {"AT45DB021D", 0x1f2300, 0x0, 64 * 1024, 8, 0, SECT_4K}, |
47 | {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0, SECT_4K}, | 47 | {"AT45DB041D", 0x1f2400, 0x0, 64 * 1024, 8, 0, SECT_4K}, |
48 | {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0, SECT_4K}, | 48 | {"AT45DB081D", 0x1f2500, 0x0, 64 * 1024, 16, 0, SECT_4K}, |
49 | {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0, SECT_4K}, | 49 | {"AT45DB161D", 0x1f2600, 0x0, 64 * 1024, 32, 0, SECT_4K}, |
50 | {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0, SECT_4K}, | 50 | {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, 0, SECT_4K}, |
51 | {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0, SECT_4K}, | 51 | {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, 0, SECT_4K}, |
52 | {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, 0, SECT_4K}, | 52 | {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, 0, SECT_4K}, |
53 | #endif | 53 | #endif |
54 | #ifdef CONFIG_SPI_FLASH_EON /* EON */ | 54 | #ifdef CONFIG_SPI_FLASH_EON /* EON */ |
55 | {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0, 0}, | 55 | {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, 0, 0}, |
56 | {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, | 56 | {"EN25Q64", 0x1c3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, |
57 | {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0, 0}, | 57 | {"EN25Q128B", 0x1c3018, 0x0, 64 * 1024, 256, 0, 0}, |
58 | {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0, 0}, | 58 | {"EN25S64", 0x1c3817, 0x0, 64 * 1024, 128, 0, 0}, |
59 | #endif | 59 | #endif |
60 | #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ | 60 | #ifdef CONFIG_SPI_FLASH_GIGADEVICE /* GIGADEVICE */ |
61 | {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0, SECT_4K}, | 61 | {"GD25Q64B", 0xc84017, 0x0, 64 * 1024, 128, 0, SECT_4K}, |
62 | {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0, SECT_4K}, | 62 | {"GD25LQ32", 0xc86016, 0x0, 64 * 1024, 64, 0, SECT_4K}, |
63 | #endif | 63 | #endif |
64 | #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ | 64 | #ifdef CONFIG_SPI_FLASH_MACRONIX /* MACRONIX */ |
65 | {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0, 0}, | 65 | {"MX25L2006E", 0xc22012, 0x0, 64 * 1024, 4, 0, 0}, |
66 | {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0, 0}, | 66 | {"MX25L4005", 0xc22013, 0x0, 64 * 1024, 8, 0, 0}, |
67 | {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0, 0}, | 67 | {"MX25L8005", 0xc22014, 0x0, 64 * 1024, 16, 0, 0}, |
68 | {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0, 0}, | 68 | {"MX25L1605D", 0xc22015, 0x0, 64 * 1024, 32, 0, 0}, |
69 | {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0, 0}, | 69 | {"MX25L3205D", 0xc22016, 0x0, 64 * 1024, 64, 0, 0}, |
70 | {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0, 0}, | 70 | {"MX25L6405D", 0xc22017, 0x0, 64 * 1024, 128, 0, 0}, |
71 | {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0, 0}, | 71 | {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, 0, 0}, |
72 | {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0, 0}, | 72 | {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, 0, 0}, |
73 | {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, 0, 0}, | 73 | {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, 0, 0}, |
74 | {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0, 0}, | 74 | {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, 0, 0}, |
75 | #endif | 75 | #endif |
76 | #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ | 76 | #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ |
77 | {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0, 0}, | 77 | {"S25FL008A", 0x010213, 0x0, 64 * 1024, 16, 0, 0}, |
78 | {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0, 0}, | 78 | {"S25FL016A", 0x010214, 0x0, 64 * 1024, 32, 0, 0}, |
79 | {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0, 0}, | 79 | {"S25FL032A", 0x010215, 0x0, 64 * 1024, 64, 0, 0}, |
80 | {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0, 0}, | 80 | {"S25FL064A", 0x010216, 0x0, 64 * 1024, 128, 0, 0}, |
81 | {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0, 0}, | 81 | {"S25FL128P_256K", 0x012018, 0x0300, 256 * 1024, 64, 0, 0}, |
82 | {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0, 0}, | 82 | {"S25FL128P_64K", 0x012018, 0x0301, 64 * 1024, 256, 0, 0}, |
83 | {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0, 0}, | 83 | {"S25FL032P", 0x010215, 0x4d00, 64 * 1024, 64, 0, 0}, |
84 | {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0, 0}, | 84 | {"S25FL064P", 0x010216, 0x4d00, 64 * 1024, 128, 0, 0}, |
85 | {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0, 0}, | 85 | {"S25FL128S_64K", 0x012018, 0x4d01, 64 * 1024, 256, 0, 0}, |
86 | {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, RD_EXTN, 0}, | 86 | {"S25FL256S_256K", 0x010219, 0x4d00, 64 * 1024, 512, RD_FULL, WR_QPP}, |
87 | {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_EXTN, 0}, | 87 | {"S25FL256S_64K", 0x010219, 0x4d01, 64 * 1024, 512, RD_FULL, WR_QPP}, |
88 | {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0, 0}, | 88 | {"S25FL512S_256K", 0x010220, 0x4d00, 64 * 1024, 1024, 0, 0}, |
89 | {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0, 0}, | 89 | {"S25FL512S_64K", 0x010220, 0x4d01, 64 * 1024, 1024, 0, 0}, |
90 | #endif | 90 | #endif |
91 | #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ | 91 | #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ |
92 | {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0, 0}, | 92 | {"M25P10", 0x202011, 0x0, 32 * 1024, 4, 0, 0}, |
93 | {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0, 0}, | 93 | {"M25P20", 0x202012, 0x0, 64 * 1024, 4, 0, 0}, |
94 | {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0, 0}, | 94 | {"M25P40", 0x202013, 0x0, 64 * 1024, 8, 0, 0}, |
95 | {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0, 0}, | 95 | {"M25P80", 0x202014, 0x0, 64 * 1024, 16, 0, 0}, |
96 | {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0, 0}, | 96 | {"M25P16", 0x202015, 0x0, 64 * 1024, 32, 0, 0}, |
97 | {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0, 0}, | 97 | {"M25P32", 0x202016, 0x0, 64 * 1024, 64, 0, 0}, |
98 | {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0, 0}, | 98 | {"M25P64", 0x202017, 0x0, 64 * 1024, 128, 0, 0}, |
99 | {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0, 0}, | 99 | {"M25P128", 0x202018, 0x0, 256 * 1024, 64, 0, 0}, |
100 | {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, 0, SECT_4K}, | 100 | {"N25Q32", 0x20ba16, 0x0, 64 * 1024, 64, 0, SECT_4K}, |
101 | {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, 0, SECT_4K}, | 101 | {"N25Q32A", 0x20bb16, 0x0, 64 * 1024, 64, 0, SECT_4K}, |
102 | {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, 0, SECT_4K}, | 102 | {"N25Q64", 0x20ba17, 0x0, 64 * 1024, 128, 0, SECT_4K}, |
103 | {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, 0, SECT_4K}, | 103 | {"N25Q64A", 0x20bb17, 0x0, 64 * 1024, 128, 0, SECT_4K}, |
104 | {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, 0, SECT_4K}, | 104 | {"N25Q128", 0x20ba18, 0x0, 64 * 1024, 256, 0, SECT_4K}, |
105 | {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, 0, SECT_4K}, | 105 | {"N25Q128A", 0x20bb18, 0x0, 64 * 1024, 256, 0, SECT_4K}, |
106 | {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, 0, SECT_4K}, | 106 | {"N25Q256", 0x20ba19, 0x0, 64 * 1024, 512, 0, SECT_4K}, |
107 | {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, 0, SECT_4K}, | 107 | {"N25Q256A", 0x20bb19, 0x0, 64 * 1024, 512, 0, SECT_4K}, |
108 | {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, 0, E_FSR | SECT_4K}, | 108 | {"N25Q512", 0x20ba20, 0x0, 64 * 1024, 1024, 0, E_FSR | SECT_4K}, |
109 | {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, 0, E_FSR | SECT_4K}, | 109 | {"N25Q512A", 0x20bb20, 0x0, 64 * 1024, 1024, 0, E_FSR | SECT_4K}, |
110 | {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, 0, E_FSR | SECT_4K}, | 110 | {"N25Q1024", 0x20ba21, 0x0, 64 * 1024, 2048, 0, E_FSR | SECT_4K}, |
111 | {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, 0, E_FSR | SECT_4K}, | 111 | {"N25Q1024A", 0x20bb21, 0x0, 64 * 1024, 2048, 0, E_FSR | SECT_4K}, |
112 | #endif | 112 | #endif |
113 | #ifdef CONFIG_SPI_FLASH_SST /* SST */ | 113 | #ifdef CONFIG_SPI_FLASH_SST /* SST */ |
114 | {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, | 114 | {"SST25VF040B", 0xbf258d, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, |
115 | {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, | 115 | {"SST25VF080B", 0xbf258e, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, |
116 | {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, 0, SECT_4K | SST_WP}, | 116 | {"SST25VF016B", 0xbf2541, 0x0, 64 * 1024, 32, 0, SECT_4K | SST_WP}, |
117 | {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, 0, SECT_4K | SST_WP}, | 117 | {"SST25VF032B", 0xbf254a, 0x0, 64 * 1024, 64, 0, SECT_4K | SST_WP}, |
118 | {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0, SECT_4K}, | 118 | {"SST25VF064C", 0xbf254b, 0x0, 64 * 1024, 128, 0, SECT_4K}, |
119 | {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, 0, SECT_4K | SST_WP}, | 119 | {"SST25WF512", 0xbf2501, 0x0, 64 * 1024, 1, 0, SECT_4K | SST_WP}, |
120 | {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, 0, SECT_4K | SST_WP}, | 120 | {"SST25WF010", 0xbf2502, 0x0, 64 * 1024, 2, 0, SECT_4K | SST_WP}, |
121 | {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, 0, SECT_4K | SST_WP}, | 121 | {"SST25WF020", 0xbf2503, 0x0, 64 * 1024, 4, 0, SECT_4K | SST_WP}, |
122 | {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, | 122 | {"SST25WF040", 0xbf2504, 0x0, 64 * 1024, 8, 0, SECT_4K | SST_WP}, |
123 | {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, | 123 | {"SST25WF080", 0xbf2505, 0x0, 64 * 1024, 16, 0, SECT_4K | SST_WP}, |
124 | #endif | 124 | #endif |
125 | #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ | 125 | #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ |
126 | {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0, 0}, | 126 | {"W25P80", 0xef2014, 0x0, 64 * 1024, 16, 0, 0}, |
127 | {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0, 0}, | 127 | {"W25P16", 0xef2015, 0x0, 64 * 1024, 32, 0, 0}, |
128 | {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0, 0}, | 128 | {"W25P32", 0xef2016, 0x0, 64 * 1024, 64, 0, 0}, |
129 | {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0, SECT_4K}, | 129 | {"W25X40", 0xef3013, 0x0, 64 * 1024, 8, 0, SECT_4K}, |
130 | {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0, SECT_4K}, | 130 | {"W25X16", 0xef3015, 0x0, 64 * 1024, 32, 0, SECT_4K}, |
131 | {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0, SECT_4K}, | 131 | {"W25X32", 0xef3016, 0x0, 64 * 1024, 64, 0, SECT_4K}, |
132 | {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, | 132 | {"W25X64", 0xef3017, 0x0, 64 * 1024, 128, 0, SECT_4K}, |
133 | {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, 0, SECT_4K}, | 133 | {"W25Q80BL", 0xef4014, 0x0, 64 * 1024, 16, 0, SECT_4K}, |
134 | {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, 0, SECT_4K}, | 134 | {"W25Q16CL", 0xef4015, 0x0, 64 * 1024, 32, 0, SECT_4K}, |
135 | {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, 0, SECT_4K}, | 135 | {"W25Q32BV", 0xef4016, 0x0, 64 * 1024, 64, 0, SECT_4K}, |
136 | {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, 0, SECT_4K}, | 136 | {"W25Q64CV", 0xef4017, 0x0, 64 * 1024, 128, 0, SECT_4K}, |
137 | {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, 0, SECT_4K}, | 137 | {"W25Q128BV", 0xef4018, 0x0, 64 * 1024, 256, 0, SECT_4K}, |
138 | {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, 0, SECT_4K}, | 138 | {"W25Q256", 0xef4019, 0x0, 64 * 1024, 512, 0, SECT_4K}, |
139 | {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, 0, SECT_4K}, | 139 | {"W25Q80BW", 0xef5014, 0x0, 64 * 1024, 16, 0, SECT_4K}, |
140 | {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, 0, SECT_4K}, | 140 | {"W25Q16DW", 0xef6015, 0x0, 64 * 1024, 32, 0, SECT_4K}, |
141 | {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, 0, SECT_4K}, | 141 | {"W25Q32DW", 0xef6016, 0x0, 64 * 1024, 64, 0, SECT_4K}, |
142 | {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, 0, SECT_4K}, | 142 | {"W25Q64DW", 0xef6017, 0x0, 64 * 1024, 128, 0, SECT_4K}, |
143 | {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, 0, SECT_4K}, | 143 | {"W25Q128FW", 0xef6018, 0x0, 64 * 1024, 256, 0, SECT_4K}, |
144 | #endif | 144 | #endif |
145 | /* | 145 | /* |
146 | * Note: | 146 | * Note: |
147 | * Below paired flash devices has similar spi_flash params. | 147 | * Below paired flash devices has similar spi_flash params. |
148 | * (S25FL129P_64K, S25FL128S_64K) | 148 | * (S25FL129P_64K, S25FL128S_64K) |
149 | * (W25Q80BL, W25Q80BV) | 149 | * (W25Q80BL, W25Q80BV) |
150 | * (W25Q16CL, W25Q16DV) | 150 | * (W25Q16CL, W25Q16DV) |
151 | * (W25Q32BV, W25Q32FV_SPI) | 151 | * (W25Q32BV, W25Q32FV_SPI) |
152 | * (W25Q64CV, W25Q64FV_SPI) | 152 | * (W25Q64CV, W25Q64FV_SPI) |
153 | * (W25Q128BV, W25Q128FV_SPI) | 153 | * (W25Q128BV, W25Q128FV_SPI) |
154 | * (W25Q32DW, W25Q32FV_QPI) | 154 | * (W25Q32DW, W25Q32FV_QPI) |
155 | * (W25Q64DW, W25Q64FV_QPI) | 155 | * (W25Q64DW, W25Q64FV_QPI) |
156 | * (W25Q128FW, W25Q128FV_QPI) | 156 | * (W25Q128FW, W25Q128FV_QPI) |
157 | */ | 157 | */ |
158 | }; | 158 | }; |
159 | 159 | ||
160 | /* Read commands array */ | 160 | /* Read commands array */ |
161 | static u8 spi_read_cmds_array[] = { | 161 | static u8 spi_read_cmds_array[] = { |
162 | CMD_READ_ARRAY_SLOW, | 162 | CMD_READ_ARRAY_SLOW, |
163 | CMD_READ_DUAL_OUTPUT_FAST, | 163 | CMD_READ_DUAL_OUTPUT_FAST, |
164 | CMD_READ_DUAL_IO_FAST, | 164 | CMD_READ_DUAL_IO_FAST, |
165 | CMD_READ_QUAD_OUTPUT_FAST, | ||
165 | }; | 166 | }; |
166 | 167 | ||
167 | static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, | 168 | static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, |
168 | u8 *idcode) | 169 | u8 *idcode) |
169 | { | 170 | { |
170 | const struct spi_flash_params *params; | 171 | const struct spi_flash_params *params; |
171 | struct spi_flash *flash; | 172 | struct spi_flash *flash; |
172 | int i; | 173 | int i; |
173 | u8 cmd; | 174 | u8 cmd; |
174 | u16 jedec = idcode[1] << 8 | idcode[2]; | 175 | u16 jedec = idcode[1] << 8 | idcode[2]; |
175 | u16 ext_jedec = idcode[3] << 8 | idcode[4]; | 176 | u16 ext_jedec = idcode[3] << 8 | idcode[4]; |
176 | 177 | ||
177 | /* Get the flash id (jedec = manuf_id + dev_id, ext_jedec) */ | 178 | /* Get the flash id (jedec = manuf_id + dev_id, ext_jedec) */ |
178 | for (i = 0; i < ARRAY_SIZE(spi_flash_params_table); i++) { | 179 | for (i = 0; i < ARRAY_SIZE(spi_flash_params_table); i++) { |
179 | params = &spi_flash_params_table[i]; | 180 | params = &spi_flash_params_table[i]; |
180 | if ((params->jedec >> 16) == idcode[0]) { | 181 | if ((params->jedec >> 16) == idcode[0]) { |
181 | if ((params->jedec & 0xFFFF) == jedec) { | 182 | if ((params->jedec & 0xFFFF) == jedec) { |
182 | if (params->ext_jedec == 0) | 183 | if (params->ext_jedec == 0) |
183 | break; | 184 | break; |
184 | else if (params->ext_jedec == ext_jedec) | 185 | else if (params->ext_jedec == ext_jedec) |
185 | break; | 186 | break; |
186 | } | 187 | } |
187 | } | 188 | } |
188 | } | 189 | } |
189 | 190 | ||
190 | if (i == ARRAY_SIZE(spi_flash_params_table)) { | 191 | if (i == ARRAY_SIZE(spi_flash_params_table)) { |
191 | printf("SF: Unsupported flash IDs: "); | 192 | printf("SF: Unsupported flash IDs: "); |
192 | printf("manuf %02x, jedec %04x, ext_jedec %04x\n", | 193 | printf("manuf %02x, jedec %04x, ext_jedec %04x\n", |
193 | idcode[0], jedec, ext_jedec); | 194 | idcode[0], jedec, ext_jedec); |
194 | return NULL; | 195 | return NULL; |
195 | } | 196 | } |
196 | 197 | ||
197 | flash = malloc(sizeof(*flash)); | 198 | flash = malloc(sizeof(*flash)); |
198 | if (!flash) { | 199 | if (!flash) { |
199 | debug("SF: Failed to allocate spi_flash\n"); | 200 | debug("SF: Failed to allocate spi_flash\n"); |
200 | return NULL; | 201 | return NULL; |
201 | } | 202 | } |
202 | memset(flash, '\0', sizeof(*flash)); | 203 | memset(flash, '\0', sizeof(*flash)); |
203 | 204 | ||
204 | /* Assign spi data */ | 205 | /* Assign spi data */ |
205 | flash->spi = spi; | 206 | flash->spi = spi; |
206 | flash->name = params->name; | 207 | flash->name = params->name; |
207 | flash->memory_map = spi->memory_map; | 208 | flash->memory_map = spi->memory_map; |
208 | 209 | ||
209 | /* Assign spi_flash ops */ | 210 | /* Assign spi_flash ops */ |
210 | flash->write = spi_flash_cmd_write_ops; | 211 | flash->write = spi_flash_cmd_write_ops; |
211 | #ifdef CONFIG_SPI_FLASH_SST | 212 | #ifdef CONFIG_SPI_FLASH_SST |
212 | if (params->flags & SST_WP) | 213 | if (params->flags & SST_WP) |
213 | flash->write = sst_write_wp; | 214 | flash->write = sst_write_wp; |
214 | #endif | 215 | #endif |
215 | flash->erase = spi_flash_cmd_erase_ops; | 216 | flash->erase = spi_flash_cmd_erase_ops; |
216 | flash->read = spi_flash_cmd_read_ops; | 217 | flash->read = spi_flash_cmd_read_ops; |
217 | 218 | ||
218 | /* Compute the flash size */ | 219 | /* Compute the flash size */ |
219 | flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; | 220 | flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; |
220 | flash->sector_size = params->sector_size; | 221 | flash->sector_size = params->sector_size; |
221 | flash->size = flash->sector_size * params->nr_sectors; | 222 | flash->size = flash->sector_size * params->nr_sectors; |
222 | 223 | ||
223 | /* Compute erase sector and command */ | 224 | /* Compute erase sector and command */ |
224 | if (params->flags & SECT_4K) { | 225 | if (params->flags & SECT_4K) { |
225 | flash->erase_cmd = CMD_ERASE_4K; | 226 | flash->erase_cmd = CMD_ERASE_4K; |
226 | flash->erase_size = 4096; | 227 | flash->erase_size = 4096; |
227 | } else if (params->flags & SECT_32K) { | 228 | } else if (params->flags & SECT_32K) { |
228 | flash->erase_cmd = CMD_ERASE_32K; | 229 | flash->erase_cmd = CMD_ERASE_32K; |
229 | flash->erase_size = 32768; | 230 | flash->erase_size = 32768; |
230 | } else { | 231 | } else { |
231 | flash->erase_cmd = CMD_ERASE_64K; | 232 | flash->erase_cmd = CMD_ERASE_64K; |
232 | flash->erase_size = flash->sector_size; | 233 | flash->erase_size = flash->sector_size; |
233 | } | 234 | } |
234 | 235 | ||
235 | /* Look for the fastest read cmd */ | 236 | /* Look for the fastest read cmd */ |
236 | cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); | 237 | cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); |
237 | if (cmd) { | 238 | if (cmd) { |
238 | cmd = spi_read_cmds_array[cmd - 1]; | 239 | cmd = spi_read_cmds_array[cmd - 1]; |
239 | flash->read_cmd = cmd; | 240 | flash->read_cmd = cmd; |
240 | } else { | 241 | } else { |
241 | /* Go for for default supported read cmd */ | 242 | /* Go for for default supported read cmd */ |
242 | flash->read_cmd = CMD_READ_ARRAY_FAST; | 243 | flash->read_cmd = CMD_READ_ARRAY_FAST; |
243 | } | 244 | } |
245 | |||
246 | /* Not require to look for fastest only two write cmds yet */ | ||
247 | if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) | ||
248 | flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; | ||
249 | else | ||
250 | /* Go for default supported write cmd */ | ||
251 | flash->write_cmd = CMD_PAGE_PROGRAM; | ||
244 | 252 | ||
245 | /* Poll cmd seclection */ | 253 | /* Poll cmd seclection */ |
246 | flash->poll_cmd = CMD_READ_STATUS; | 254 | flash->poll_cmd = CMD_READ_STATUS; |
247 | #ifdef CONFIG_SPI_FLASH_STMICRO | 255 | #ifdef CONFIG_SPI_FLASH_STMICRO |
248 | if (params->flags & E_FSR) | 256 | if (params->flags & E_FSR) |
249 | flash->poll_cmd = CMD_FLAG_STATUS; | 257 | flash->poll_cmd = CMD_FLAG_STATUS; |
250 | #endif | 258 | #endif |
251 | 259 | ||
252 | /* Configure the BAR - discover bank cmds and read current bank */ | 260 | /* Configure the BAR - discover bank cmds and read current bank */ |
253 | #ifdef CONFIG_SPI_FLASH_BAR | 261 | #ifdef CONFIG_SPI_FLASH_BAR |
254 | u8 curr_bank = 0; | 262 | u8 curr_bank = 0; |
255 | if (flash->size > SPI_FLASH_16MB_BOUN) { | 263 | if (flash->size > SPI_FLASH_16MB_BOUN) { |
256 | flash->bank_read_cmd = (idcode[0] == 0x01) ? | 264 | flash->bank_read_cmd = (idcode[0] == 0x01) ? |
257 | CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR; | 265 | CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR; |
258 | flash->bank_write_cmd = (idcode[0] == 0x01) ? | 266 | flash->bank_write_cmd = (idcode[0] == 0x01) ? |
259 | CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR; | 267 | CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR; |
260 | 268 | ||
261 | if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1, | 269 | if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1, |
262 | &curr_bank, 1)) { | 270 | &curr_bank, 1)) { |
263 | debug("SF: fail to read bank addr register\n"); | 271 | debug("SF: fail to read bank addr register\n"); |
264 | return NULL; | 272 | return NULL; |
265 | } | 273 | } |
266 | flash->bank_curr = curr_bank; | 274 | flash->bank_curr = curr_bank; |
267 | } else { | 275 | } else { |
268 | flash->bank_curr = curr_bank; | 276 | flash->bank_curr = curr_bank; |
269 | } | 277 | } |
270 | #endif | 278 | #endif |
271 | 279 | ||
272 | /* Flash powers up read-only, so clear BP# bits */ | 280 | /* Flash powers up read-only, so clear BP# bits */ |
273 | #if defined(CONFIG_SPI_FLASH_ATMEL) || \ | 281 | #if defined(CONFIG_SPI_FLASH_ATMEL) || \ |
274 | defined(CONFIG_SPI_FLASH_MACRONIX) || \ | 282 | defined(CONFIG_SPI_FLASH_MACRONIX) || \ |
275 | defined(CONFIG_SPI_FLASH_SST) | 283 | defined(CONFIG_SPI_FLASH_SST) |
276 | spi_flash_cmd_write_status(flash, 0); | 284 | spi_flash_cmd_write_status(flash, 0); |
277 | #endif | 285 | #endif |
278 | 286 | ||
279 | return flash; | 287 | return flash; |
280 | } | 288 | } |
281 | 289 | ||
282 | #ifdef CONFIG_OF_CONTROL | 290 | #ifdef CONFIG_OF_CONTROL |
283 | int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) | 291 | int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) |
284 | { | 292 | { |
285 | fdt_addr_t addr; | 293 | fdt_addr_t addr; |
286 | fdt_size_t size; | 294 | fdt_size_t size; |
287 | int node; | 295 | int node; |
288 | 296 | ||
289 | /* If there is no node, do nothing */ | 297 | /* If there is no node, do nothing */ |
290 | node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); | 298 | node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); |
291 | if (node < 0) | 299 | if (node < 0) |
292 | return 0; | 300 | return 0; |
293 | 301 | ||
294 | addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); | 302 | addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); |
295 | if (addr == FDT_ADDR_T_NONE) { | 303 | if (addr == FDT_ADDR_T_NONE) { |
296 | debug("%s: Cannot decode address\n", __func__); | 304 | debug("%s: Cannot decode address\n", __func__); |
297 | return 0; | 305 | return 0; |
298 | } | 306 | } |
299 | 307 | ||
300 | if (flash->size != size) { | 308 | if (flash->size != size) { |
301 | debug("%s: Memory map must cover entire device\n", __func__); | 309 | debug("%s: Memory map must cover entire device\n", __func__); |
302 | return -1; | 310 | return -1; |
303 | } | 311 | } |
304 | flash->memory_map = map_sysmem(addr, size); | 312 | flash->memory_map = map_sysmem(addr, size); |
305 | 313 | ||
306 | return 0; | 314 | return 0; |
307 | } | 315 | } |
308 | #endif /* CONFIG_OF_CONTROL */ | 316 | #endif /* CONFIG_OF_CONTROL */ |
309 | 317 | ||
310 | static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) | 318 | static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi) |
311 | { | 319 | { |
312 | struct spi_flash *flash = NULL; | 320 | struct spi_flash *flash = NULL; |
313 | u8 idcode[5]; | 321 | u8 idcode[5]; |
314 | int ret; | 322 | int ret; |
315 | 323 | ||
316 | /* Setup spi_slave */ | 324 | /* Setup spi_slave */ |
317 | if (!spi) { | 325 | if (!spi) { |
318 | printf("SF: Failed to set up slave\n"); | 326 | printf("SF: Failed to set up slave\n"); |
319 | return NULL; | 327 | return NULL; |
320 | } | 328 | } |
321 | 329 | ||
322 | /* Claim spi bus */ | 330 | /* Claim spi bus */ |
323 | ret = spi_claim_bus(spi); | 331 | ret = spi_claim_bus(spi); |
324 | if (ret) { | 332 | if (ret) { |
325 | debug("SF: Failed to claim SPI bus: %d\n", ret); | 333 | debug("SF: Failed to claim SPI bus: %d\n", ret); |
326 | goto err_claim_bus; | 334 | goto err_claim_bus; |
327 | } | 335 | } |
328 | 336 | ||
329 | /* Read the ID codes */ | 337 | /* Read the ID codes */ |
330 | ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); | 338 | ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); |
331 | if (ret) { | 339 | if (ret) { |
332 | printf("SF: Failed to get idcodes\n"); | 340 | printf("SF: Failed to get idcodes\n"); |
333 | goto err_read_id; | 341 | goto err_read_id; |
334 | } | 342 | } |
335 | 343 | ||
336 | #ifdef DEBUG | 344 | #ifdef DEBUG |
337 | printf("SF: Got idcodes\n"); | 345 | printf("SF: Got idcodes\n"); |
338 | print_buffer(0, idcode, 1, sizeof(idcode), 0); | 346 | print_buffer(0, idcode, 1, sizeof(idcode), 0); |
339 | #endif | 347 | #endif |
340 | 348 | ||
341 | /* Validate params from spi_flash_params table */ | 349 | /* Validate params from spi_flash_params table */ |
342 | flash = spi_flash_validate_params(spi, idcode); | 350 | flash = spi_flash_validate_params(spi, idcode); |
343 | if (!flash) | 351 | if (!flash) |
344 | goto err_read_id; | 352 | goto err_read_id; |
345 | 353 | ||
346 | #ifdef CONFIG_OF_CONTROL | 354 | #ifdef CONFIG_OF_CONTROL |
347 | if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { | 355 | if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { |
348 | debug("SF: FDT decode error\n"); | 356 | debug("SF: FDT decode error\n"); |
349 | goto err_read_id; | 357 | goto err_read_id; |
350 | } | 358 | } |
351 | #endif | 359 | #endif |
352 | #ifndef CONFIG_SPL_BUILD | 360 | #ifndef CONFIG_SPL_BUILD |
353 | printf("SF: Detected %s with page size ", flash->name); | 361 | printf("SF: Detected %s with page size ", flash->name); |
354 | print_size(flash->page_size, ", erase size "); | 362 | print_size(flash->page_size, ", erase size "); |
355 | print_size(flash->erase_size, ", total "); | 363 | print_size(flash->erase_size, ", total "); |
356 | print_size(flash->size, ""); | 364 | print_size(flash->size, ""); |
357 | if (flash->memory_map) | 365 | if (flash->memory_map) |
358 | printf(", mapped at %p", flash->memory_map); | 366 | printf(", mapped at %p", flash->memory_map); |
359 | puts("\n"); | 367 | puts("\n"); |
360 | #endif | 368 | #endif |
361 | #ifndef CONFIG_SPI_FLASH_BAR | 369 | #ifndef CONFIG_SPI_FLASH_BAR |
362 | if (flash->size > SPI_FLASH_16MB_BOUN) { | 370 | if (flash->size > SPI_FLASH_16MB_BOUN) { |
363 | puts("SF: Warning - Only lower 16MiB accessible,"); | 371 | puts("SF: Warning - Only lower 16MiB accessible,"); |
364 | puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); | 372 | puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); |
365 | } | 373 | } |
366 | #endif | 374 | #endif |
367 | 375 | ||
368 | /* Release spi bus */ | 376 | /* Release spi bus */ |
369 | spi_release_bus(spi); | 377 | spi_release_bus(spi); |
370 | 378 | ||
371 | return flash; | 379 | return flash; |
372 | 380 | ||
373 | err_read_id: | 381 | err_read_id: |
374 | spi_release_bus(spi); | 382 | spi_release_bus(spi); |
375 | err_claim_bus: | 383 | err_claim_bus: |
376 | spi_free_slave(spi); | 384 | spi_free_slave(spi); |
377 | return NULL; | 385 | return NULL; |
378 | } | 386 | } |
379 | 387 | ||
380 | struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, | 388 | struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, |
381 | unsigned int max_hz, unsigned int spi_mode) | 389 | unsigned int max_hz, unsigned int spi_mode) |
382 | { | 390 | { |
383 | struct spi_slave *spi; | 391 | struct spi_slave *spi; |
384 | 392 | ||
385 | spi = spi_setup_slave(bus, cs, max_hz, spi_mode); | 393 | spi = spi_setup_slave(bus, cs, max_hz, spi_mode); |
386 | return spi_flash_probe_slave(spi); | 394 | return spi_flash_probe_slave(spi); |
387 | } | 395 | } |
388 | 396 | ||
389 | #ifdef CONFIG_OF_SPI_FLASH | 397 | #ifdef CONFIG_OF_SPI_FLASH |
390 | struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, | 398 | struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, |
391 | int spi_node) | 399 | int spi_node) |
392 | { | 400 | { |
393 | struct spi_slave *spi; | 401 | struct spi_slave *spi; |
394 | 402 | ||
395 | spi = spi_setup_slave_fdt(blob, slave_node, spi_node); | 403 | spi = spi_setup_slave_fdt(blob, slave_node, spi_node); |
396 | return spi_flash_probe_slave(spi); | 404 | return spi_flash_probe_slave(spi); |
397 | } | 405 | } |
398 | #endif | 406 | #endif |
399 | 407 | ||
400 | void spi_flash_free(struct spi_flash *flash) | 408 | void spi_flash_free(struct spi_flash *flash) |
401 | { | 409 | { |
402 | spi_free_slave(flash->spi); | 410 | spi_free_slave(flash->spi); |
403 | free(flash); | 411 | free(flash); |
404 | } | 412 | } |
405 | 413 |
include/spi.h
1 | /* | 1 | /* |
2 | * Common SPI Interface: Controller-specific definitions | 2 | * Common SPI Interface: Controller-specific definitions |
3 | * | 3 | * |
4 | * (C) Copyright 2001 | 4 | * (C) Copyright 2001 |
5 | * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. | 5 | * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. |
6 | * | 6 | * |
7 | * SPDX-License-Identifier: GPL-2.0+ | 7 | * SPDX-License-Identifier: GPL-2.0+ |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #ifndef _SPI_H_ | 10 | #ifndef _SPI_H_ |
11 | #define _SPI_H_ | 11 | #define _SPI_H_ |
12 | 12 | ||
13 | /* SPI mode flags */ | 13 | /* SPI mode flags */ |
14 | #define SPI_CPHA 0x01 /* clock phase */ | 14 | #define SPI_CPHA 0x01 /* clock phase */ |
15 | #define SPI_CPOL 0x02 /* clock polarity */ | 15 | #define SPI_CPOL 0x02 /* clock polarity */ |
16 | #define SPI_MODE_0 (0|0) /* (original MicroWire) */ | 16 | #define SPI_MODE_0 (0|0) /* (original MicroWire) */ |
17 | #define SPI_MODE_1 (0|SPI_CPHA) | 17 | #define SPI_MODE_1 (0|SPI_CPHA) |
18 | #define SPI_MODE_2 (SPI_CPOL|0) | 18 | #define SPI_MODE_2 (SPI_CPOL|0) |
19 | #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) | 19 | #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) |
20 | #define SPI_CS_HIGH 0x04 /* CS active high */ | 20 | #define SPI_CS_HIGH 0x04 /* CS active high */ |
21 | #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ | 21 | #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ |
22 | #define SPI_3WIRE 0x10 /* SI/SO signals shared */ | 22 | #define SPI_3WIRE 0x10 /* SI/SO signals shared */ |
23 | #define SPI_LOOP 0x20 /* loopback mode */ | 23 | #define SPI_LOOP 0x20 /* loopback mode */ |
24 | #define SPI_SLAVE 0x40 /* slave mode */ | 24 | #define SPI_SLAVE 0x40 /* slave mode */ |
25 | #define SPI_PREAMBLE 0x80 /* Skip preamble bytes */ | 25 | #define SPI_PREAMBLE 0x80 /* Skip preamble bytes */ |
26 | 26 | ||
27 | /* SPI transfer flags */ | 27 | /* SPI transfer flags */ |
28 | #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ | 28 | #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ |
29 | #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ | 29 | #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ |
30 | #define SPI_XFER_MMAP 0x08 /* Memory Mapped start */ | 30 | #define SPI_XFER_MMAP 0x08 /* Memory Mapped start */ |
31 | #define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ | 31 | #define SPI_XFER_MMAP_END 0x10 /* Memory Mapped End */ |
32 | #define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END) | 32 | #define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END) |
33 | 33 | ||
34 | /* SPI TX operation modes */ | ||
35 | #define SPI_OPM_TX_QPP 1 << 0 | ||
36 | |||
34 | /* SPI RX operation modes */ | 37 | /* SPI RX operation modes */ |
35 | #define SPI_OPM_RX_AS 1 << 0 | 38 | #define SPI_OPM_RX_AS 1 << 0 |
36 | #define SPI_OPM_RX_DOUT 1 << 1 | 39 | #define SPI_OPM_RX_DOUT 1 << 1 |
37 | #define SPI_OPM_RX_DIO 1 << 2 | 40 | #define SPI_OPM_RX_DIO 1 << 2 |
38 | #define SPI_OPM_RX_EXTN SPI_OPM_RX_AS | SPI_OPM_RX_DOUT | SPI_OPM_RX_DIO | 41 | #define SPI_OPM_RX_QOF 1 << 3 |
42 | #define SPI_OPM_RX_EXTN SPI_OPM_RX_AS | SPI_OPM_RX_DOUT | \ | ||
43 | SPI_OPM_RX_DIO | SPI_OPM_RX_QOF | ||
39 | 44 | ||
40 | /* Header byte that marks the start of the message */ | 45 | /* Header byte that marks the start of the message */ |
41 | #define SPI_PREAMBLE_END_BYTE 0xec | 46 | #define SPI_PREAMBLE_END_BYTE 0xec |
42 | 47 | ||
43 | #define SPI_DEFAULT_WORDLEN 8 | 48 | #define SPI_DEFAULT_WORDLEN 8 |
44 | 49 | ||
45 | /** | 50 | /** |
46 | * struct spi_slave - Representation of a SPI slave | 51 | * struct spi_slave - Representation of a SPI slave |
47 | * | 52 | * |
48 | * Drivers are expected to extend this with controller-specific data. | 53 | * Drivers are expected to extend this with controller-specific data. |
49 | * | 54 | * |
50 | * @bus: ID of the bus that the slave is attached to. | 55 | * @bus: ID of the bus that the slave is attached to. |
51 | * @cs: ID of the chip select connected to the slave. | 56 | * @cs: ID of the chip select connected to the slave. |
52 | * @op_mode_rx: SPI RX operation mode. | 57 | * @op_mode_rx: SPI RX operation mode. |
58 | * @op_mode_tx: SPI TX operation mode. | ||
53 | * @wordlen: Size of SPI word in number of bits | 59 | * @wordlen: Size of SPI word in number of bits |
54 | * @max_write_size: If non-zero, the maximum number of bytes which can | 60 | * @max_write_size: If non-zero, the maximum number of bytes which can |
55 | * be written at once, excluding command bytes. | 61 | * be written at once, excluding command bytes. |
56 | * @memory_map: Address of read-only SPI flash access. | 62 | * @memory_map: Address of read-only SPI flash access. |
57 | */ | 63 | */ |
58 | struct spi_slave { | 64 | struct spi_slave { |
59 | unsigned int bus; | 65 | unsigned int bus; |
60 | unsigned int cs; | 66 | unsigned int cs; |
61 | u8 op_mode_rx; | 67 | u8 op_mode_rx; |
68 | u8 op_mode_tx; | ||
62 | unsigned int wordlen; | 69 | unsigned int wordlen; |
63 | unsigned int max_write_size; | 70 | unsigned int max_write_size; |
64 | void *memory_map; | 71 | void *memory_map; |
65 | }; | 72 | }; |
66 | 73 | ||
67 | /** | 74 | /** |
68 | * Initialization, must be called once on start up. | 75 | * Initialization, must be called once on start up. |
69 | * | 76 | * |
70 | * TODO: I don't think we really need this. | 77 | * TODO: I don't think we really need this. |
71 | */ | 78 | */ |
72 | void spi_init(void); | 79 | void spi_init(void); |
73 | 80 | ||
74 | /** | 81 | /** |
75 | * spi_do_alloc_slave - Allocate a new SPI slave (internal) | 82 | * spi_do_alloc_slave - Allocate a new SPI slave (internal) |
76 | * | 83 | * |
77 | * Allocate and zero all fields in the spi slave, and set the bus/chip | 84 | * Allocate and zero all fields in the spi slave, and set the bus/chip |
78 | * select. Use the helper macro spi_alloc_slave() to call this. | 85 | * select. Use the helper macro spi_alloc_slave() to call this. |
79 | * | 86 | * |
80 | * @offset: Offset of struct spi_slave within slave structure. | 87 | * @offset: Offset of struct spi_slave within slave structure. |
81 | * @size: Size of slave structure. | 88 | * @size: Size of slave structure. |
82 | * @bus: Bus ID of the slave chip. | 89 | * @bus: Bus ID of the slave chip. |
83 | * @cs: Chip select ID of the slave chip on the specified bus. | 90 | * @cs: Chip select ID of the slave chip on the specified bus. |
84 | */ | 91 | */ |
85 | void *spi_do_alloc_slave(int offset, int size, unsigned int bus, | 92 | void *spi_do_alloc_slave(int offset, int size, unsigned int bus, |
86 | unsigned int cs); | 93 | unsigned int cs); |
87 | 94 | ||
88 | /** | 95 | /** |
89 | * spi_alloc_slave - Allocate a new SPI slave | 96 | * spi_alloc_slave - Allocate a new SPI slave |
90 | * | 97 | * |
91 | * Allocate and zero all fields in the spi slave, and set the bus/chip | 98 | * Allocate and zero all fields in the spi slave, and set the bus/chip |
92 | * select. | 99 | * select. |
93 | * | 100 | * |
94 | * @_struct: Name of structure to allocate (e.g. struct tegra_spi). | 101 | * @_struct: Name of structure to allocate (e.g. struct tegra_spi). |
95 | * This structure must contain a member 'struct spi_slave *slave'. | 102 | * This structure must contain a member 'struct spi_slave *slave'. |
96 | * @bus: Bus ID of the slave chip. | 103 | * @bus: Bus ID of the slave chip. |
97 | * @cs: Chip select ID of the slave chip on the specified bus. | 104 | * @cs: Chip select ID of the slave chip on the specified bus. |
98 | */ | 105 | */ |
99 | #define spi_alloc_slave(_struct, bus, cs) \ | 106 | #define spi_alloc_slave(_struct, bus, cs) \ |
100 | spi_do_alloc_slave(offsetof(_struct, slave), \ | 107 | spi_do_alloc_slave(offsetof(_struct, slave), \ |
101 | sizeof(_struct), bus, cs) | 108 | sizeof(_struct), bus, cs) |
102 | 109 | ||
103 | /** | 110 | /** |
104 | * spi_alloc_slave_base - Allocate a new SPI slave with no private data | 111 | * spi_alloc_slave_base - Allocate a new SPI slave with no private data |
105 | * | 112 | * |
106 | * Allocate and zero all fields in the spi slave, and set the bus/chip | 113 | * Allocate and zero all fields in the spi slave, and set the bus/chip |
107 | * select. | 114 | * select. |
108 | * | 115 | * |
109 | * @bus: Bus ID of the slave chip. | 116 | * @bus: Bus ID of the slave chip. |
110 | * @cs: Chip select ID of the slave chip on the specified bus. | 117 | * @cs: Chip select ID of the slave chip on the specified bus. |
111 | */ | 118 | */ |
112 | #define spi_alloc_slave_base(bus, cs) \ | 119 | #define spi_alloc_slave_base(bus, cs) \ |
113 | spi_do_alloc_slave(0, sizeof(struct spi_slave), bus, cs) | 120 | spi_do_alloc_slave(0, sizeof(struct spi_slave), bus, cs) |
114 | 121 | ||
115 | /** | 122 | /** |
116 | * Set up communications parameters for a SPI slave. | 123 | * Set up communications parameters for a SPI slave. |
117 | * | 124 | * |
118 | * This must be called once for each slave. Note that this function | 125 | * This must be called once for each slave. Note that this function |
119 | * usually doesn't touch any actual hardware, it only initializes the | 126 | * usually doesn't touch any actual hardware, it only initializes the |
120 | * contents of spi_slave so that the hardware can be easily | 127 | * contents of spi_slave so that the hardware can be easily |
121 | * initialized later. | 128 | * initialized later. |
122 | * | 129 | * |
123 | * @bus: Bus ID of the slave chip. | 130 | * @bus: Bus ID of the slave chip. |
124 | * @cs: Chip select ID of the slave chip on the specified bus. | 131 | * @cs: Chip select ID of the slave chip on the specified bus. |
125 | * @max_hz: Maximum SCK rate in Hz. | 132 | * @max_hz: Maximum SCK rate in Hz. |
126 | * @mode: Clock polarity, clock phase and other parameters. | 133 | * @mode: Clock polarity, clock phase and other parameters. |
127 | * | 134 | * |
128 | * Returns: A spi_slave reference that can be used in subsequent SPI | 135 | * Returns: A spi_slave reference that can be used in subsequent SPI |
129 | * calls, or NULL if one or more of the parameters are not supported. | 136 | * calls, or NULL if one or more of the parameters are not supported. |
130 | */ | 137 | */ |
131 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | 138 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, |
132 | unsigned int max_hz, unsigned int mode); | 139 | unsigned int max_hz, unsigned int mode); |
133 | 140 | ||
134 | /** | 141 | /** |
135 | * Free any memory associated with a SPI slave. | 142 | * Free any memory associated with a SPI slave. |
136 | * | 143 | * |
137 | * @slave: The SPI slave | 144 | * @slave: The SPI slave |
138 | */ | 145 | */ |
139 | void spi_free_slave(struct spi_slave *slave); | 146 | void spi_free_slave(struct spi_slave *slave); |
140 | 147 | ||
141 | /** | 148 | /** |
142 | * Claim the bus and prepare it for communication with a given slave. | 149 | * Claim the bus and prepare it for communication with a given slave. |
143 | * | 150 | * |
144 | * This must be called before doing any transfers with a SPI slave. It | 151 | * This must be called before doing any transfers with a SPI slave. It |
145 | * will enable and initialize any SPI hardware as necessary, and make | 152 | * will enable and initialize any SPI hardware as necessary, and make |
146 | * sure that the SCK line is in the correct idle state. It is not | 153 | * sure that the SCK line is in the correct idle state. It is not |
147 | * allowed to claim the same bus for several slaves without releasing | 154 | * allowed to claim the same bus for several slaves without releasing |
148 | * the bus in between. | 155 | * the bus in between. |
149 | * | 156 | * |
150 | * @slave: The SPI slave | 157 | * @slave: The SPI slave |
151 | * | 158 | * |
152 | * Returns: 0 if the bus was claimed successfully, or a negative value | 159 | * Returns: 0 if the bus was claimed successfully, or a negative value |
153 | * if it wasn't. | 160 | * if it wasn't. |
154 | */ | 161 | */ |
155 | int spi_claim_bus(struct spi_slave *slave); | 162 | int spi_claim_bus(struct spi_slave *slave); |
156 | 163 | ||
157 | /** | 164 | /** |
158 | * Release the SPI bus | 165 | * Release the SPI bus |
159 | * | 166 | * |
160 | * This must be called once for every call to spi_claim_bus() after | 167 | * This must be called once for every call to spi_claim_bus() after |
161 | * all transfers have finished. It may disable any SPI hardware as | 168 | * all transfers have finished. It may disable any SPI hardware as |
162 | * appropriate. | 169 | * appropriate. |
163 | * | 170 | * |
164 | * @slave: The SPI slave | 171 | * @slave: The SPI slave |
165 | */ | 172 | */ |
166 | void spi_release_bus(struct spi_slave *slave); | 173 | void spi_release_bus(struct spi_slave *slave); |
167 | 174 | ||
168 | /** | 175 | /** |
169 | * Set the word length for SPI transactions | 176 | * Set the word length for SPI transactions |
170 | * | 177 | * |
171 | * Set the word length (number of bits per word) for SPI transactions. | 178 | * Set the word length (number of bits per word) for SPI transactions. |
172 | * | 179 | * |
173 | * @slave: The SPI slave | 180 | * @slave: The SPI slave |
174 | * @wordlen: The number of bits in a word | 181 | * @wordlen: The number of bits in a word |
175 | * | 182 | * |
176 | * Returns: 0 on success, -1 on failure. | 183 | * Returns: 0 on success, -1 on failure. |
177 | */ | 184 | */ |
178 | int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen); | 185 | int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen); |
179 | 186 | ||
180 | /** | 187 | /** |
181 | * SPI transfer | 188 | * SPI transfer |
182 | * | 189 | * |
183 | * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks | 190 | * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks |
184 | * "bitlen" bits in the SPI MISO port. That's just the way SPI works. | 191 | * "bitlen" bits in the SPI MISO port. That's just the way SPI works. |
185 | * | 192 | * |
186 | * The source of the outgoing bits is the "dout" parameter and the | 193 | * The source of the outgoing bits is the "dout" parameter and the |
187 | * destination of the input bits is the "din" parameter. Note that "dout" | 194 | * destination of the input bits is the "din" parameter. Note that "dout" |
188 | * and "din" can point to the same memory location, in which case the | 195 | * and "din" can point to the same memory location, in which case the |
189 | * input data overwrites the output data (since both are buffered by | 196 | * input data overwrites the output data (since both are buffered by |
190 | * temporary variables, this is OK). | 197 | * temporary variables, this is OK). |
191 | * | 198 | * |
192 | * spi_xfer() interface: | 199 | * spi_xfer() interface: |
193 | * @slave: The SPI slave which will be sending/receiving the data. | 200 | * @slave: The SPI slave which will be sending/receiving the data. |
194 | * @bitlen: How many bits to write and read. | 201 | * @bitlen: How many bits to write and read. |
195 | * @dout: Pointer to a string of bits to send out. The bits are | 202 | * @dout: Pointer to a string of bits to send out. The bits are |
196 | * held in a byte array and are sent MSB first. | 203 | * held in a byte array and are sent MSB first. |
197 | * @din: Pointer to a string of bits that will be filled in. | 204 | * @din: Pointer to a string of bits that will be filled in. |
198 | * @flags: A bitwise combination of SPI_XFER_* flags. | 205 | * @flags: A bitwise combination of SPI_XFER_* flags. |
199 | * | 206 | * |
200 | * Returns: 0 on success, not 0 on failure | 207 | * Returns: 0 on success, not 0 on failure |
201 | */ | 208 | */ |
202 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, | 209 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, |
203 | void *din, unsigned long flags); | 210 | void *din, unsigned long flags); |
204 | 211 | ||
205 | /** | 212 | /** |
206 | * Determine if a SPI chipselect is valid. | 213 | * Determine if a SPI chipselect is valid. |
207 | * This function is provided by the board if the low-level SPI driver | 214 | * This function is provided by the board if the low-level SPI driver |
208 | * needs it to determine if a given chipselect is actually valid. | 215 | * needs it to determine if a given chipselect is actually valid. |
209 | * | 216 | * |
210 | * Returns: 1 if bus:cs identifies a valid chip on this board, 0 | 217 | * Returns: 1 if bus:cs identifies a valid chip on this board, 0 |
211 | * otherwise. | 218 | * otherwise. |
212 | */ | 219 | */ |
213 | int spi_cs_is_valid(unsigned int bus, unsigned int cs); | 220 | int spi_cs_is_valid(unsigned int bus, unsigned int cs); |
214 | 221 | ||
215 | /** | 222 | /** |
216 | * Activate a SPI chipselect. | 223 | * Activate a SPI chipselect. |
217 | * This function is provided by the board code when using a driver | 224 | * This function is provided by the board code when using a driver |
218 | * that can't control its chipselects automatically (e.g. | 225 | * that can't control its chipselects automatically (e.g. |
219 | * common/soft_spi.c). When called, it should activate the chip select | 226 | * common/soft_spi.c). When called, it should activate the chip select |
220 | * to the device identified by "slave". | 227 | * to the device identified by "slave". |
221 | */ | 228 | */ |
222 | void spi_cs_activate(struct spi_slave *slave); | 229 | void spi_cs_activate(struct spi_slave *slave); |
223 | 230 | ||
224 | /** | 231 | /** |
225 | * Deactivate a SPI chipselect. | 232 | * Deactivate a SPI chipselect. |
226 | * This function is provided by the board code when using a driver | 233 | * This function is provided by the board code when using a driver |
227 | * that can't control its chipselects automatically (e.g. | 234 | * that can't control its chipselects automatically (e.g. |
228 | * common/soft_spi.c). When called, it should deactivate the chip | 235 | * common/soft_spi.c). When called, it should deactivate the chip |
229 | * select to the device identified by "slave". | 236 | * select to the device identified by "slave". |
230 | */ | 237 | */ |
231 | void spi_cs_deactivate(struct spi_slave *slave); | 238 | void spi_cs_deactivate(struct spi_slave *slave); |
232 | 239 | ||
233 | /** | 240 | /** |
234 | * Set transfer speed. | 241 | * Set transfer speed. |
235 | * This sets a new speed to be applied for next spi_xfer(). | 242 | * This sets a new speed to be applied for next spi_xfer(). |
236 | * @slave: The SPI slave | 243 | * @slave: The SPI slave |
237 | * @hz: The transfer speed | 244 | * @hz: The transfer speed |
238 | */ | 245 | */ |
239 | void spi_set_speed(struct spi_slave *slave, uint hz); | 246 | void spi_set_speed(struct spi_slave *slave, uint hz); |
240 | 247 | ||
241 | /** | 248 | /** |
242 | * Write 8 bits, then read 8 bits. | 249 | * Write 8 bits, then read 8 bits. |
243 | * @slave: The SPI slave we're communicating with | 250 | * @slave: The SPI slave we're communicating with |
244 | * @byte: Byte to be written | 251 | * @byte: Byte to be written |
245 | * | 252 | * |
246 | * Returns: The value that was read, or a negative value on error. | 253 | * Returns: The value that was read, or a negative value on error. |
247 | * | 254 | * |
248 | * TODO: This function probably shouldn't be inlined. | 255 | * TODO: This function probably shouldn't be inlined. |
249 | */ | 256 | */ |
250 | static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) | 257 | static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) |
251 | { | 258 | { |
252 | unsigned char dout[2]; | 259 | unsigned char dout[2]; |
253 | unsigned char din[2]; | 260 | unsigned char din[2]; |
254 | int ret; | 261 | int ret; |
255 | 262 | ||
256 | dout[0] = byte; | 263 | dout[0] = byte; |
257 | dout[1] = 0; | 264 | dout[1] = 0; |
258 | 265 | ||
259 | ret = spi_xfer(slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END); | 266 | ret = spi_xfer(slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END); |
260 | return ret < 0 ? ret : din[1]; | 267 | return ret < 0 ? ret : din[1]; |
261 | } | 268 | } |
262 | 269 | ||
263 | /** | 270 | /** |
264 | * Set up a SPI slave for a particular device tree node | 271 | * Set up a SPI slave for a particular device tree node |
265 | * | 272 | * |
266 | * This calls spi_setup_slave() with the correct bus number. Call | 273 | * This calls spi_setup_slave() with the correct bus number. Call |
267 | * spi_free_slave() to free it later. | 274 | * spi_free_slave() to free it later. |
268 | * | 275 | * |
269 | * @param blob: Device tree blob | 276 | * @param blob: Device tree blob |
270 | * @param slave_node: Slave node to use | 277 | * @param slave_node: Slave node to use |
271 | * @param spi_node: SPI peripheral node to use | 278 | * @param spi_node: SPI peripheral node to use |
272 | * @return pointer to new spi_slave structure | 279 | * @return pointer to new spi_slave structure |
273 | */ | 280 | */ |
274 | struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node, | 281 | struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node, |
275 | int spi_node); | 282 | int spi_node); |
276 | 283 | ||
277 | /** | 284 | /** |
278 | * spi_base_setup_slave_fdt() - helper function to set up a SPI slace | 285 | * spi_base_setup_slave_fdt() - helper function to set up a SPI slace |
279 | * | 286 | * |
280 | * This decodes SPI properties from the slave node to determine the | 287 | * This decodes SPI properties from the slave node to determine the |
281 | * chip select and SPI parameters. | 288 | * chip select and SPI parameters. |
282 | * | 289 | * |
283 | * @blob: Device tree blob | 290 | * @blob: Device tree blob |
284 | * @busnum: Bus number to use | 291 | * @busnum: Bus number to use |
285 | * @node: Device tree node for the SPI bus | 292 | * @node: Device tree node for the SPI bus |
286 | */ | 293 | */ |
287 | struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum, | 294 | struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum, |
288 | int node); | 295 | int node); |
289 | 296 | ||
290 | #endif /* _SPI_H_ */ | 297 | #endif /* _SPI_H_ */ |
291 | 298 |
include/spi_flash.h
1 | /* | 1 | /* |
2 | * Common SPI flash Interface | 2 | * Common SPI flash Interface |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Atmel Corporation | 4 | * Copyright (C) 2008 Atmel Corporation |
5 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | 5 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. |
6 | * | 6 | * |
7 | * See file CREDITS for list of people who contributed to this | 7 | * See file CREDITS for list of people who contributed to this |
8 | * project. | 8 | * project. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or | 10 | * This program is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU General Public License | 11 | * modify it under the terms of the GNU General Public License |
12 | * version 2 as published by the Free Software Foundation. | 12 | * version 2 as published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #ifndef _SPI_FLASH_H_ | 15 | #ifndef _SPI_FLASH_H_ |
16 | #define _SPI_FLASH_H_ | 16 | #define _SPI_FLASH_H_ |
17 | 17 | ||
18 | #include <spi.h> | 18 | #include <spi.h> |
19 | #include <linux/types.h> | 19 | #include <linux/types.h> |
20 | #include <linux/compiler.h> | 20 | #include <linux/compiler.h> |
21 | 21 | ||
22 | /* Enum list - Extended read commands */ | 22 | /* No enum list for write commands only QPP */ |
23 | #define WR_QPP 1 << 4 | ||
24 | |||
25 | /* Enum list - Full read commands */ | ||
23 | enum spi_read_cmds { | 26 | enum spi_read_cmds { |
24 | ARRAY_SLOW = 1 << 0, | 27 | ARRAY_SLOW = 1 << 0, |
25 | DUAL_OUTPUT_FAST = 1 << 1, | 28 | DUAL_OUTPUT_FAST = 1 << 1, |
26 | DUAL_IO_FAST = 1 << 2, | 29 | DUAL_IO_FAST = 1 << 2, |
30 | QUAD_OUTPUT_FAST = 1 << 3, | ||
27 | }; | 31 | }; |
28 | #define RD_EXTN ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST | 32 | #define RD_EXTN ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST |
33 | #define RD_FULL RD_EXTN | QUAD_OUTPUT_FAST | ||
29 | 34 | ||
30 | /** | 35 | /** |
31 | * struct spi_flash - SPI flash structure | 36 | * struct spi_flash - SPI flash structure |
32 | * | 37 | * |
33 | * @spi: SPI slave | 38 | * @spi: SPI slave |
34 | * @name: Name of SPI flash | 39 | * @name: Name of SPI flash |
35 | * @size: Total flash size | 40 | * @size: Total flash size |
36 | * @page_size: Write (page) size | 41 | * @page_size: Write (page) size |
37 | * @sector_size: Sector size | 42 | * @sector_size: Sector size |
38 | * @erase_size: Erase size | 43 | * @erase_size: Erase size |
39 | * @bank_read_cmd: Bank read cmd | 44 | * @bank_read_cmd: Bank read cmd |
40 | * @bank_write_cmd: Bank write cmd | 45 | * @bank_write_cmd: Bank write cmd |
41 | * @bank_curr: Current flash bank | 46 | * @bank_curr: Current flash bank |
42 | * @poll_cmd: Poll cmd - for flash erase/program | 47 | * @poll_cmd: Poll cmd - for flash erase/program |
43 | * @erase_cmd: Erase cmd 4K, 32K, 64K | 48 | * @erase_cmd: Erase cmd 4K, 32K, 64K |
44 | * @read_cmd: Read cmd - Array Fast and Extn read | 49 | * @read_cmd: Read cmd - Array Fast, Extn read and quad read. |
50 | * @write_cmd: Write cmd - page and quad program. | ||
45 | * @memory_map: Address of read-only SPI flash access | 51 | * @memory_map: Address of read-only SPI flash access |
46 | * @read: Flash read ops: Read len bytes at offset into buf | 52 | * @read: Flash read ops: Read len bytes at offset into buf |
47 | * Supported cmds: Fast Array Read | 53 | * Supported cmds: Fast Array Read |
48 | * @write: Flash write ops: Write len bytes from buf into offeset | 54 | * @write: Flash write ops: Write len bytes from buf into offeset |
49 | * Supported cmds: Page Program | 55 | * Supported cmds: Page Program |
50 | * @erase: Flash erase ops: Erase len bytes from offset | 56 | * @erase: Flash erase ops: Erase len bytes from offset |
51 | * Supported cmds: Sector erase 4K, 32K, 64K | 57 | * Supported cmds: Sector erase 4K, 32K, 64K |
52 | * return 0 - Sucess, 1 - Failure | 58 | * return 0 - Sucess, 1 - Failure |
53 | */ | 59 | */ |
54 | struct spi_flash { | 60 | struct spi_flash { |
55 | struct spi_slave *spi; | 61 | struct spi_slave *spi; |
56 | const char *name; | 62 | const char *name; |
57 | 63 | ||
58 | u32 size; | 64 | u32 size; |
59 | u32 page_size; | 65 | u32 page_size; |
60 | u32 sector_size; | 66 | u32 sector_size; |
61 | u32 erase_size; | 67 | u32 erase_size; |
62 | #ifdef CONFIG_SPI_FLASH_BAR | 68 | #ifdef CONFIG_SPI_FLASH_BAR |
63 | u8 bank_read_cmd; | 69 | u8 bank_read_cmd; |
64 | u8 bank_write_cmd; | 70 | u8 bank_write_cmd; |
65 | u8 bank_curr; | 71 | u8 bank_curr; |
66 | #endif | 72 | #endif |
67 | u8 poll_cmd; | 73 | u8 poll_cmd; |
68 | u8 erase_cmd; | 74 | u8 erase_cmd; |
69 | u8 read_cmd; | 75 | u8 read_cmd; |
76 | u8 write_cmd; | ||
70 | 77 | ||
71 | void *memory_map; | 78 | void *memory_map; |
72 | int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf); | 79 | int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf); |
73 | int (*write)(struct spi_flash *flash, u32 offset, size_t len, | 80 | int (*write)(struct spi_flash *flash, u32 offset, size_t len, |
74 | const void *buf); | 81 | const void *buf); |
75 | int (*erase)(struct spi_flash *flash, u32 offset, size_t len); | 82 | int (*erase)(struct spi_flash *flash, u32 offset, size_t len); |
76 | }; | 83 | }; |
77 | 84 | ||
78 | struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, | 85 | struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, |
79 | unsigned int max_hz, unsigned int spi_mode); | 86 | unsigned int max_hz, unsigned int spi_mode); |
80 | 87 | ||
81 | /** | 88 | /** |
82 | * Set up a new SPI flash from an fdt node | 89 | * Set up a new SPI flash from an fdt node |
83 | * | 90 | * |
84 | * @param blob Device tree blob | 91 | * @param blob Device tree blob |
85 | * @param slave_node Pointer to this SPI slave node in the device tree | 92 | * @param slave_node Pointer to this SPI slave node in the device tree |
86 | * @param spi_node Cached pointer to the SPI interface this node belongs | 93 | * @param spi_node Cached pointer to the SPI interface this node belongs |
87 | * to | 94 | * to |
88 | * @return 0 if ok, -1 on error | 95 | * @return 0 if ok, -1 on error |
89 | */ | 96 | */ |
90 | struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, | 97 | struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node, |
91 | int spi_node); | 98 | int spi_node); |
92 | 99 | ||
93 | void spi_flash_free(struct spi_flash *flash); | 100 | void spi_flash_free(struct spi_flash *flash); |
94 | 101 | ||
95 | static inline int spi_flash_read(struct spi_flash *flash, u32 offset, | 102 | static inline int spi_flash_read(struct spi_flash *flash, u32 offset, |
96 | size_t len, void *buf) | 103 | size_t len, void *buf) |
97 | { | 104 | { |
98 | return flash->read(flash, offset, len, buf); | 105 | return flash->read(flash, offset, len, buf); |
99 | } | 106 | } |
100 | 107 | ||
101 | static inline int spi_flash_write(struct spi_flash *flash, u32 offset, | 108 | static inline int spi_flash_write(struct spi_flash *flash, u32 offset, |
102 | size_t len, const void *buf) | 109 | size_t len, const void *buf) |
103 | { | 110 | { |
104 | return flash->write(flash, offset, len, buf); | 111 | return flash->write(flash, offset, len, buf); |
105 | } | 112 | } |
106 | 113 | ||
107 | static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, | 114 | static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, |
108 | size_t len) | 115 | size_t len) |
109 | { | 116 | { |
110 | return flash->erase(flash, offset, len); | 117 | return flash->erase(flash, offset, len); |
111 | } | 118 | } |
112 | 119 | ||
113 | void spi_boot(void) __noreturn; | 120 | void spi_boot(void) __noreturn; |
114 | 121 | ||
115 | #endif /* _SPI_FLASH_H_ */ | 122 | #endif /* _SPI_FLASH_H_ */ |
116 | 123 |