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