]>
Commit | Line | Data |
---|---|---|
e0987e25 RM |
1 | /* |
2 | * (C) Copyright 2010 | |
3 | * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
e0987e25 RM |
6 | */ |
7 | ||
8 | /* | |
9 | * Note: RAMTRON SPI FRAMs are ferroelectric, nonvolatile RAMs | |
10 | * with an interface identical to SPI flash devices. | |
11 | * However since they behave like RAM there are no delays or | |
12 | * busy polls required. They can sustain read or write at the | |
13 | * allowed SPI bus speed, which can be 40 MHz for some devices. | |
14 | * | |
15 | * Unfortunately some RAMTRON devices do not have a means of | |
16 | * identifying them. They will leave the SO line undriven when | |
17 | * the READ-ID command is issued. It is therefore mandatory | |
18 | * that the MISO line has a proper pull-up, so that READ-ID | |
19 | * will return a row of 0xff. This 0xff pseudo-id will cause | |
20 | * probes by all vendor specific functions that are designed | |
21 | * to handle it. If the MISO line is not pulled up, READ-ID | |
22 | * could return any random noise, even mimicking another | |
23 | * device. | |
24 | * | |
25 | * We use CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC | |
26 | * to define which device will be assumed after a simple status | |
27 | * register verify. This method is prone to false positive | |
28 | * detection and should therefore be the last to be tried. | |
29 | * Enter it in the last position in the table in spi_flash.c! | |
30 | * | |
31 | * The define CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC both activates | |
32 | * compilation of the special handler and defines the device | |
33 | * to assume. | |
34 | */ | |
35 | ||
36 | #include <common.h> | |
37 | #include <malloc.h> | |
38 | #include <spi_flash.h> | |
39 | #include "spi_flash_internal.h" | |
40 | ||
e0987e25 RM |
41 | /* |
42 | * Properties of supported FRAMs | |
43 | * Note: speed is currently not used because we have no method to deliver that | |
44 | * value to the upper layers | |
45 | */ | |
46 | struct ramtron_spi_fram_params { | |
47 | u32 size; /* size in bytes */ | |
48 | u8 addr_len; /* number of address bytes */ | |
49 | u8 merge_cmd; /* some address bits are in the command byte */ | |
50 | u8 id1; /* device ID 1 (family, density) */ | |
51 | u8 id2; /* device ID 2 (sub, rev, rsvd) */ | |
52 | u32 speed; /* max. SPI clock in Hz */ | |
53 | const char *name; /* name for display and/or matching */ | |
54 | }; | |
55 | ||
56 | struct ramtron_spi_fram { | |
57 | struct spi_flash flash; | |
58 | const struct ramtron_spi_fram_params *params; | |
59 | }; | |
60 | ||
61 | static inline struct ramtron_spi_fram *to_ramtron_spi_fram(struct spi_flash | |
62 | *flash) | |
63 | { | |
64 | return container_of(flash, struct ramtron_spi_fram, flash); | |
65 | } | |
66 | ||
67 | /* | |
68 | * table describing supported FRAM chips: | |
69 | * chips without RDID command must have the values 0xff for id1 and id2 | |
70 | */ | |
71 | static const struct ramtron_spi_fram_params ramtron_spi_fram_table[] = { | |
72 | { | |
73 | .size = 32*1024, | |
74 | .addr_len = 2, | |
75 | .merge_cmd = 0, | |
76 | .id1 = 0x22, | |
77 | .id2 = 0x00, | |
78 | .speed = 40000000, | |
79 | .name = "FM25V02", | |
80 | }, | |
81 | { | |
82 | .size = 32*1024, | |
83 | .addr_len = 2, | |
84 | .merge_cmd = 0, | |
85 | .id1 = 0x22, | |
86 | .id2 = 0x01, | |
87 | .speed = 40000000, | |
88 | .name = "FM25VN02", | |
89 | }, | |
90 | { | |
91 | .size = 64*1024, | |
92 | .addr_len = 2, | |
93 | .merge_cmd = 0, | |
94 | .id1 = 0x23, | |
95 | .id2 = 0x00, | |
96 | .speed = 40000000, | |
97 | .name = "FM25V05", | |
98 | }, | |
99 | { | |
100 | .size = 64*1024, | |
101 | .addr_len = 2, | |
102 | .merge_cmd = 0, | |
103 | .id1 = 0x23, | |
104 | .id2 = 0x01, | |
105 | .speed = 40000000, | |
106 | .name = "FM25VN05", | |
107 | }, | |
108 | { | |
109 | .size = 128*1024, | |
110 | .addr_len = 3, | |
111 | .merge_cmd = 0, | |
112 | .id1 = 0x24, | |
113 | .id2 = 0x00, | |
114 | .speed = 40000000, | |
115 | .name = "FM25V10", | |
116 | }, | |
117 | { | |
118 | .size = 128*1024, | |
119 | .addr_len = 3, | |
120 | .merge_cmd = 0, | |
121 | .id1 = 0x24, | |
122 | .id2 = 0x01, | |
123 | .speed = 40000000, | |
124 | .name = "FM25VN10", | |
125 | }, | |
126 | #ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC | |
127 | { | |
128 | .size = 256*1024, | |
129 | .addr_len = 3, | |
130 | .merge_cmd = 0, | |
131 | .id1 = 0xff, | |
132 | .id2 = 0xff, | |
133 | .speed = 40000000, | |
134 | .name = "FM25H20", | |
135 | }, | |
136 | #endif | |
137 | }; | |
138 | ||
139 | static int ramtron_common(struct spi_flash *flash, | |
140 | u32 offset, size_t len, void *buf, u8 command) | |
141 | { | |
142 | struct ramtron_spi_fram *sn = to_ramtron_spi_fram(flash); | |
143 | u8 cmd[4]; | |
144 | int cmd_len; | |
145 | int ret; | |
146 | ||
147 | if (sn->params->addr_len == 3 && sn->params->merge_cmd == 0) { | |
148 | cmd[0] = command; | |
149 | cmd[1] = offset >> 16; | |
150 | cmd[2] = offset >> 8; | |
151 | cmd[3] = offset; | |
152 | cmd_len = 4; | |
153 | } else if (sn->params->addr_len == 2 && sn->params->merge_cmd == 0) { | |
154 | cmd[0] = command; | |
155 | cmd[1] = offset >> 8; | |
156 | cmd[2] = offset; | |
157 | cmd_len = 3; | |
158 | } else { | |
159 | printf("SF: unsupported addr_len or merge_cmd\n"); | |
160 | return -1; | |
161 | } | |
162 | ||
163 | /* claim the bus */ | |
164 | ret = spi_claim_bus(flash->spi); | |
165 | if (ret) { | |
166 | debug("SF: Unable to claim SPI bus\n"); | |
167 | return ret; | |
168 | } | |
169 | ||
b4c87d65 | 170 | if (command == CMD_PAGE_PROGRAM) { |
e0987e25 | 171 | /* send WREN */ |
2744a4e6 | 172 | ret = spi_flash_cmd_write_enable(flash); |
e0987e25 RM |
173 | if (ret < 0) { |
174 | debug("SF: Enabling Write failed\n"); | |
175 | goto releasebus; | |
176 | } | |
177 | } | |
178 | ||
179 | /* do the transaction */ | |
b4c87d65 | 180 | if (command == CMD_PAGE_PROGRAM) |
e0987e25 RM |
181 | ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, buf, len); |
182 | else | |
183 | ret = spi_flash_cmd_read(flash->spi, cmd, cmd_len, buf, len); | |
184 | if (ret < 0) | |
185 | debug("SF: Transaction failed\n"); | |
186 | ||
187 | releasebus: | |
188 | /* release the bus */ | |
189 | spi_release_bus(flash->spi); | |
190 | return ret; | |
191 | } | |
192 | ||
193 | static int ramtron_read(struct spi_flash *flash, | |
194 | u32 offset, size_t len, void *buf) | |
195 | { | |
196 | return ramtron_common(flash, offset, len, buf, | |
b4c87d65 | 197 | CMD_READ_ARRAY_SLOW); |
e0987e25 RM |
198 | } |
199 | ||
200 | static int ramtron_write(struct spi_flash *flash, | |
201 | u32 offset, size_t len, const void *buf) | |
202 | { | |
203 | return ramtron_common(flash, offset, len, (void *)buf, | |
b4c87d65 | 204 | CMD_PAGE_PROGRAM); |
e0987e25 RM |
205 | } |
206 | ||
f8f0757d | 207 | static int ramtron_erase(struct spi_flash *flash, u32 offset, size_t len) |
e0987e25 RM |
208 | { |
209 | debug("SF: Erase of RAMTRON FRAMs is pointless\n"); | |
210 | return -1; | |
211 | } | |
212 | ||
213 | /* | |
214 | * nore: we are called here with idcode pointing to the first non-0x7f byte | |
215 | * already! | |
216 | */ | |
217 | struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode) | |
218 | { | |
219 | const struct ramtron_spi_fram_params *params; | |
220 | struct ramtron_spi_fram *sn; | |
221 | unsigned int i; | |
222 | #ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC | |
223 | int ret; | |
224 | u8 sr; | |
225 | #endif | |
226 | ||
227 | /* NOTE: the bus has been claimed before this function is called! */ | |
228 | switch (idcode[0]) { | |
229 | case 0xc2: | |
230 | /* JEDEC conformant RAMTRON id */ | |
231 | for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { | |
232 | params = &ramtron_spi_fram_table[i]; | |
233 | if (idcode[1] == params->id1 && idcode[2] == params->id2) | |
234 | goto found; | |
235 | } | |
236 | break; | |
237 | #ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC | |
238 | case 0xff: | |
239 | /* | |
240 | * probably open MISO line, pulled up. | |
241 | * We COULD have a non JEDEC conformant FRAM here, | |
242 | * read the status register to verify | |
243 | */ | |
b4c87d65 | 244 | ret = spi_flash_cmd(spi, CMD_READ_STATUS, &sr, 1); |
e0987e25 RM |
245 | if (ret) |
246 | return NULL; | |
247 | ||
248 | /* Bits 5,4,0 are fixed 0 for all devices */ | |
249 | if ((sr & 0x31) != 0x00) | |
250 | return NULL; | |
251 | /* now find the device */ | |
252 | for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { | |
253 | params = &ramtron_spi_fram_table[i]; | |
254 | if (!strcmp(params->name, CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC)) | |
255 | goto found; | |
256 | } | |
257 | debug("SF: Unsupported non-JEDEC RAMTRON device " | |
258 | CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC "\n"); | |
259 | break; | |
260 | #endif | |
261 | default: | |
262 | break; | |
263 | } | |
264 | ||
265 | /* arriving here means no method has found a device we can handle */ | |
266 | debug("SF/ramtron: unsupported device id0=%02x id1=%02x id2=%02x\n", | |
267 | idcode[0], idcode[1], idcode[2]); | |
268 | return NULL; | |
269 | ||
270 | found: | |
c0f87dd4 | 271 | sn = spi_flash_alloc(struct ramtron_spi_fram, spi, params->name); |
e0987e25 RM |
272 | if (!sn) { |
273 | debug("SF: Failed to allocate memory\n"); | |
274 | return NULL; | |
275 | } | |
276 | ||
277 | sn->params = params; | |
e0987e25 RM |
278 | |
279 | sn->flash.write = ramtron_write; | |
280 | sn->flash.read = ramtron_read; | |
281 | sn->flash.erase = ramtron_erase; | |
282 | sn->flash.size = params->size; | |
283 | ||
e0987e25 RM |
284 | return &sn->flash; |
285 | } |