1 /*
2 * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <errno.h>
8
9 #include "cfi_drv.h"
10
11
12
13 /*
14 * This memory is organized as an interleaved memory of two chips
15 * with a 16 bit word. It means that every 32 bit access is going
16 * to access to two different chips. This is very important when
17 * we send commands or read status of the chips.
18 */
19
20 /*
21 * DWS ready poll retries. The number of retries in this driver have been
22 * obtained empirically from Juno. FVP implements a zero wait state NOR flash
23 * model
24 */
25 #define DWS_WORD_PROGRAM_RETRIES 1000
26 #define DWS_WORD_ERASE_RETRIES 3000000
27 #define DWS_WORD_LOCK_RETRIES 1000
28
29 /* Helper macro to detect end of command */
30 #define NOR_CMD_END (NOR_DWS | (NOR_DWS << 16l))
31 #define NOR_CMD_END_8BIT (NOR_DWS)
32
33
34 /* Helper macros to access two flash banks in parallel */
35 #define NOR_2X16(d) ((d << 16) | (d & 0xffff))
36
mmio_write_32(uintptr_t addr,uint32_t value)37 static inline void mmio_write_32(uintptr_t addr, uint32_t value)
38 {
39 *(volatile uint32_t*)addr = value;
40 }
41
mmio_write_8(uintptr_t addr,uint8_t value)42 static inline void mmio_write_8(uintptr_t addr, uint8_t value)
43 {
44 *(volatile uint8_t*)addr = value;
45 }
46
mmio_read_32(uintptr_t addr)47 static inline uint32_t mmio_read_32(uintptr_t addr)
48 {
49 return *(volatile uint32_t*)addr;
50 }
51
nor_cfi_reg_read(uintptr_t addr)52 uint8_t nor_cfi_reg_read(uintptr_t addr){
53 return *(volatile uint8_t*)addr;
54 }
55
nor_cfi_reg_write(uintptr_t addr,uint32_t value)56 void nor_cfi_reg_write(uintptr_t addr, uint32_t value){
57 *(volatile uint32_t*)addr = value;
58 }
59
nor_status(uintptr_t base_addr)60 static unsigned int nor_status(uintptr_t base_addr)
61 {
62 unsigned long status;
63
64 nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG);
65 status = mmio_read_32(base_addr);
66 status |= status >> 16; /* merge status from both flash banks */
67
68 return status & 0xFFFF;
69 }
70
nor_send_cmd(uintptr_t base_addr,unsigned long cmd)71 void nor_send_cmd(uintptr_t base_addr, unsigned long cmd)
72 {
73 mmio_write_32(base_addr, NOR_2X16(cmd));
74 }
75
nor_send_cmd_byte(uintptr_t base_addr,unsigned long cmd)76 void nor_send_cmd_byte(uintptr_t base_addr, unsigned long cmd)
77 {
78 mmio_write_8(base_addr, cmd);
79 }
80
81 /*
82 * Poll Write State Machine.
83 * Return values:
84 * 0 = WSM ready
85 * -EBUSY = WSM busy after the number of retries
86 */
nor_poll_dws(uintptr_t base_addr,unsigned long int retries)87 static enum cfi_error_t nor_poll_dws(uintptr_t base_addr, unsigned long int retries)
88 {
89 unsigned long status;
90
91 do {
92 nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG);
93 status = mmio_read_32(base_addr);
94 if ((status & NOR_CMD_END) == NOR_CMD_END)
95 return 0;
96 } while (retries-- > 0);
97
98 return -CFI_ERR_DEV_BUSY;
99 }
100
101 /*
102 * Poll Write State Machine.
103 * Return values:
104 * 0 = WSM ready
105 * -EBUSY = WSM busy after the number of retries
106 */
nor_poll_dws_byte(uintptr_t base_addr,unsigned long int retries)107 static enum cfi_error_t nor_poll_dws_byte(uintptr_t base_addr, unsigned long int retries)
108 {
109 unsigned long status;
110
111 do {
112 nor_send_cmd_byte(base_addr, NOR_CMD_READ_STATUS_REG);
113 status = nor_cfi_reg_read(base_addr);
114 if ((status & NOR_CMD_END_8BIT) == NOR_CMD_END_8BIT)
115 return 0;
116 } while (retries-- > 0);
117
118 return -CFI_ERR_DEV_BUSY;
119 }
120
121 /*
122 * Return values:
123 * 0 = success
124 * -EPERM = Device protected or Block locked
125 * -EIO = General I/O error
126 */
nor_full_status_check(uintptr_t base_addr)127 static enum cfi_error_t nor_full_status_check(uintptr_t base_addr)
128 {
129 unsigned long status;
130
131 /* Full status check */
132 status = nor_status(base_addr);
133
134 if (status & (NOR_PS | NOR_BLS | NOR_ESS | NOR_PSS))
135 return -CFI_ERR_DEV_PROTECTED;
136 if (status & (NOR_VPPS | NOR_ES))
137 return -CFI_ERR_GENERAL_IO;
138 return 0;
139 }
140
141
142 /*
143 * This function programs a word in the flash. Be aware that it only
144 * can reset bits that were previously set. It cannot set bits that
145 * were previously reset. The resulting bits = old_bits & new bits.
146 * Return values:
147 * 0 = success
148 * otherwise it returns a negative value
149 */
nor_word_program(uintptr_t base_addr,unsigned long data)150 enum cfi_error_t nor_word_program(uintptr_t base_addr, unsigned long data)
151 {
152 uint32_t status;
153 int ret;
154
155 nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
156
157 /* Set the device in write word mode */
158 nor_send_cmd(base_addr, NOR_CMD_WORD_PROGRAM);
159 mmio_write_32(base_addr, data);
160
161 ret = nor_poll_dws(base_addr, DWS_WORD_PROGRAM_RETRIES);
162 if (ret == 0) {
163 /* Full status check */
164 nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG);
165 status = mmio_read_32(base_addr);
166
167 if (status & (NOR_PS | NOR_BLS)) {
168 nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
169 ret = -CFI_ERR_DEV_PROTECTED;
170 }
171 }
172
173 if (ret == 0)
174 ret = nor_full_status_check(base_addr);
175 nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);
176
177 return ret;
178 }
179
180
nor_byte_program(uintptr_t base_addr,uint8_t data)181 enum cfi_error_t nor_byte_program(uintptr_t base_addr, uint8_t data)
182 {
183 uint32_t status;
184 int ret;
185
186 nor_send_cmd_byte(base_addr, NOR_CMD_CLEAR_STATUS_REG);
187
188 /* Set the device in write byte mode */
189 nor_send_cmd_byte(base_addr, NOR_CMD_WORD_PROGRAM);
190 mmio_write_8(base_addr, data);
191
192 ret = nor_poll_dws_byte(base_addr, DWS_WORD_PROGRAM_RETRIES);
193 if (ret == 0) {
194 /* Full status check */
195 nor_send_cmd_byte(base_addr, NOR_CMD_READ_STATUS_REG);
196 status = nor_cfi_reg_read(base_addr);
197
198 if (status & (NOR_PS | NOR_BLS)) {
199 nor_send_cmd_byte(base_addr, NOR_CMD_CLEAR_STATUS_REG);
200 ret = -CFI_ERR_DEV_PROTECTED;
201 }
202 }
203
204
205 nor_send_cmd_byte(base_addr, NOR_CMD_READ_ARRAY);
206
207 return ret;
208 }
209
210 /*
211 * Erase a full 256K block
212 * Return values:
213 * 0 = success
214 * otherwise it returns a negative value
215 */
nor_erase(uintptr_t base_addr)216 enum cfi_error_t nor_erase(uintptr_t base_addr)
217 {
218 int ret;
219
220 nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
221
222 nor_send_cmd(base_addr, NOR_CMD_BLOCK_ERASE);
223 nor_send_cmd(base_addr, NOR_CMD_BLOCK_ERASE_ACK);
224
225 ret = nor_poll_dws(base_addr, DWS_WORD_ERASE_RETRIES);
226 if (ret == 0)
227 ret = nor_full_status_check(base_addr);
228 nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);
229
230 return ret;
231 }
232
nor_erase_byte(uintptr_t base_addr)233 enum cfi_error_t nor_erase_byte(uintptr_t base_addr)
234 {
235 enum cfi_error_t ret;
236
237 nor_send_cmd_byte(base_addr, NOR_CMD_CLEAR_STATUS_REG);
238
239 nor_send_cmd_byte(base_addr, NOR_CMD_BLOCK_ERASE);
240 nor_send_cmd_byte(base_addr, NOR_CMD_BLOCK_ERASE_ACK);
241
242 ret = nor_poll_dws_byte(base_addr, DWS_WORD_ERASE_RETRIES);
243
244 nor_send_cmd_byte(base_addr, NOR_CMD_READ_ARRAY);
245
246 return ret;
247 }
248
249 /*
250 * Lock a full 256 block
251 * Return values:
252 * 0 = success
253 * otherwise it returns a negative value
254 */
nor_lock(uintptr_t base_addr)255 enum cfi_error_t nor_lock(uintptr_t base_addr)
256 {
257 enum cfi_error_t ret;
258
259 nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
260
261 nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK);
262 nor_send_cmd(base_addr, NOR_LOCK_BLOCK);
263
264 ret = nor_poll_dws(base_addr, DWS_WORD_LOCK_RETRIES);
265 if (ret == 0)
266 ret = nor_full_status_check(base_addr);
267 nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);
268
269 return ret;
270 }
271
272 /*
273 * unlock a full 256 block
274 * Return values:
275 * 0 = success
276 * otherwise it returns a negative value
277 */
nor_unlock(uintptr_t base_addr)278 enum cfi_error_t nor_unlock(uintptr_t base_addr)
279 {
280 enum cfi_error_t ret;
281
282 nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
283
284 nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK);
285 nor_send_cmd(base_addr, NOR_UNLOCK_BLOCK);
286
287 ret = nor_poll_dws(base_addr, DWS_WORD_LOCK_RETRIES);
288 if (ret == 0)
289 ret = nor_full_status_check(base_addr);
290 nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);
291
292 return ret;
293 }
294
295
296
nor_id_check(uintptr_t base_addr)297 unsigned int nor_id_check(uintptr_t base_addr)
298 {
299 unsigned long status,status1,status2;
300
301 nor_send_cmd(base_addr, NOR_CMD_READ_ID_CODE);
302 status = mmio_read_32(base_addr);
303 status1 = mmio_read_32(base_addr+1*4);
304 status2 = mmio_read_32(base_addr+2*4);
305
306 CFI_FLASH_LOG_MSG("STATUS ID: %X \n",status);
307 CFI_FLASH_LOG_MSG("STATUS ID: %X \n",status1);
308 CFI_FLASH_LOG_MSG("STATUS ID: %X \n",status2);
309 status |= status >> 16; /* merge status from both flash banks */
310
311 CFI_FLASH_LOG_MSG("STATUS ID: %X \n",status);
312
313 return status & 0xFFFF;
314 }
315