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