blob: 6e563c9f04ee4c1b9646cea4a81449c9116644e4 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <debug.h>
9#include <mmio.h>
10#include <string.h>
11#include "io_vexpress_nor_internal.h"
12#include "norflash.h"
13
14/* Device Id information */
15#define NOR_DEVICE_ID_LOCK_CONFIGURATION 0x02
16#define NOR_DEVICE_ID_BLOCK_LOCKED (1 << 0)
17#define NOR_DEVICE_ID_BLOCK_LOCKED_DOWN (1 << 1)
18
19/* Status Register Bits */
20#define NOR_SR_BIT_WRITE ((1 << 23) | (1 << 7))
21#define NOR_SR_BIT_ERASE ((1 << 21) | (1 << 5))
22#define NOR_SR_BIT_PROGRAM ((1 << 20) | (1 << 4))
23#define NOR_SR_BIT_VPP ((1 << 19) | (1 << 3))
24#define NOR_SR_BIT_BLOCK_LOCKED ((1 << 17) | (1 << 1))
25
26/*
27 * On chip buffer size for buffered programming operations
28 * There are 2 chips, each chip can buffer up to 32 (16-bit)words.
29 * Therefore the total size of the buffer is 2 x 32 x 2 = 128 bytes.
30 */
31#define NOR_MAX_BUFFER_SIZE_IN_BYTES 128
32#define NOR_MAX_BUFFER_SIZE_IN_WORDS (NOR_MAX_BUFFER_SIZE_IN_BYTES / 4)
33
34#define MAX_BUFFERED_PROG_ITERATIONS 1000
35#define LOW_16_BITS 0x0000FFFF
36#define FOLD_32BIT_INTO_16BIT(value) ((value >> 16) | (value & LOW_16_BITS))
37#define BOUNDARY_OF_32_WORDS 0x7F
38
39#define CHECK_VPP_RANGE_ERROR(status_register, address) \
40 do { \
41 if ((status_register) & NOR_SR_BIT_VPP) { \
42 ERROR("%s (address:0x%X): " \
43 "VPP Range Error\n", __func__, address);\
44 err = IO_FAIL; \
45 } \
46 } while (0)
47
48#define CHECK_BLOCK_LOCK_ERROR(status_register, address) \
49 do { \
50 if ((status_register) & NOR_SR_BIT_BLOCK_LOCKED) { \
51 ERROR("%s (address:0x%X): Device Protect " \
52 "Error\n", __func__, address); \
53 err = IO_FAIL; \
54 } \
55 } while (0)
56
57#define CHECK_BLOCK_ERASE_ERROR(status_register, block_offset) \
58 do { \
59 if ((status_register) & NOR_SR_BIT_ERASE) { \
60 ERROR("%s (block_offset=0x%08x: " \
61 "Block Erase Error status_register" \
62 ":0x%x\n", __func__, block_offset, \
63 status_register); \
64 err = IO_FAIL; \
65 } \
66 } while (0)
67
68#define CHECK_SR_BIT_PROGRAM_ERROR(status_register, address) \
69 do { \
70 if ((status_register) & NOR_SR_BIT_PROGRAM) { \
71 ERROR("%s(address:0x%X): Program Error\n", \
72 __func__, address); \
73 err = IO_FAIL; \
74 } \
75 } while (0)
76
77/* Helper macros to access two flash banks in parallel */
78#define NOR_2X16(d) ((d << 16) | (d & 0xffff))
79
80static inline void nor_send_cmd(uintptr_t base_addr, unsigned long cmd)
81{
82 mmio_write_32(base_addr, NOR_2X16(cmd));
83}
84
85static uint32_t flash_read_status(const io_nor_flash_spec_t *device)
86{
87 /* Prepare to read the status register */
88 nor_send_cmd(device->device_address, NOR_CMD_READ_STATUS_REG);
89
90 return mmio_read_32(device->device_address);
91}
92
93static uint32_t flash_wait_until_complete(const io_nor_flash_spec_t *device)
94{
95 uint32_t lock_status;
96
97 /* Wait until the status register gives us the all clear */
98 do {
99 lock_status = flash_read_status(device);
100 } while ((lock_status & NOR_SR_BIT_WRITE) != NOR_SR_BIT_WRITE);
101
102 return lock_status;
103}
104
105static int flash_block_is_locked(uint32_t block_offset)
106{
107 uint32_t lock_status;
108
109 uintptr_t addr = block_offset + (NOR_DEVICE_ID_LOCK_CONFIGURATION << 2);
110
111 /* Send command for reading device id */
112 nor_send_cmd(addr, NOR_CMD_READ_ID_CODE);
113
114 /* Read block lock status */
115 lock_status = mmio_read_32(addr);
116
117 /* Decode block lock status */
118 lock_status = FOLD_32BIT_INTO_16BIT(lock_status);
119
120 if ((lock_status & NOR_DEVICE_ID_BLOCK_LOCKED_DOWN) != 0)
121 WARN("flash_block_is_locked: Block LOCKED DOWN\n");
122
123 return lock_status & NOR_DEVICE_ID_BLOCK_LOCKED;
124}
125
126
127static void flash_perform_lock_operation(const io_nor_flash_spec_t *device,
128 uint32_t block_offset,
129 uint32_t lock_operation)
130{
131 assert ((lock_operation == NOR_UNLOCK_BLOCK) ||
132 (lock_operation == NOR_LOCK_BLOCK));
133
134 /* Request a lock setup */
135 nor_send_cmd(block_offset, NOR_CMD_LOCK_UNLOCK);
136
137 /* Request lock or unlock */
138 nor_send_cmd(block_offset, lock_operation);
139
140 /* Wait until status register shows device is free */
141 flash_wait_until_complete(device);
142
143 /* Put device back into Read Array mode */
144 nor_send_cmd(block_offset, NOR_CMD_READ_ARRAY);
145}
146
147static void flash_unlock_block_if_necessary(const io_nor_flash_spec_t *device,
148 uint32_t block_offset)
149{
150 if (flash_block_is_locked(block_offset) != 0)
151 flash_perform_lock_operation(device, block_offset,
152 NOR_UNLOCK_BLOCK);
153}
154
155
156static int flash_erase_block(const io_nor_flash_spec_t *device,
157 uint32_t block_offset)
158{
159 int err = IO_SUCCESS;
160 uint32_t status_register;
161
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200162 /* Request a block erase and then confirm it */
163 nor_send_cmd(block_offset, NOR_CMD_BLOCK_ERASE);
164 nor_send_cmd(block_offset, NOR_CMD_BLOCK_ERASE_ACK);
165
166 /* Wait for the write to complete and then check for any errors;
167 * i.e. check the Status Register */
168 status_register = flash_wait_until_complete(device);
169
170 CHECK_VPP_RANGE_ERROR(status_register, block_offset);
171
172 if ((status_register & (NOR_SR_BIT_ERASE | NOR_SR_BIT_PROGRAM)) ==
173 (NOR_SR_BIT_ERASE | NOR_SR_BIT_PROGRAM)) {
174 ERROR("%s(block_offset=0x%08x: "
175 "Command Sequence Error\n", __func__, block_offset);
176 err = IO_FAIL;
177 }
178
179 CHECK_BLOCK_ERASE_ERROR(status_register, block_offset);
180
181 CHECK_BLOCK_LOCK_ERROR(status_register, block_offset);
182
183 if (err) {
184 /* Clear the Status Register */
185 nor_send_cmd(device->device_address, NOR_CMD_CLEAR_STATUS_REG);
186 }
187
188 /* Put device back into Read Array mode */
189 nor_send_cmd(device->device_address, NOR_CMD_READ_ARRAY);
190
191 return err;
192}
193
194/*
195 * Writes data to the NOR Flash using the Buffered Programming method.
196 *
197 * The maximum size of the on-chip buffer is 32-words, because of hardware
198 * restrictions. Therefore this function will only handle buffers up to 32
199 * words or 128 bytes. To deal with larger buffers, call this function again.
200 *
201 * This function presumes that both the offset and the offset+BufferSize
202 * fit entirely within the NOR Flash. Therefore these conditions will not
203 * be checked here.
204 *
205 * In buffered programming, if the target address is not at the beginning of a
206 * 32-bit word boundary, then programming time is doubled and power consumption
207 * is increased. Therefore, it is a requirement to align buffer writes to
208 * 32-bit word boundaries.
209 */
210static int flash_write_buffer(const io_nor_flash_spec_t *device,
211 uint32_t offset,
212 const uint32_t *buffer,
213 uint32_t buffer_size)
214{
215 int err = IO_SUCCESS;
216 uint32_t size_in_words;
217 uint32_t count;
218 volatile uint32_t *data;
219 uint32_t timeout;
220 int is_buffer_available = 0;
221 uint32_t status_register;
222
223 timeout = MAX_BUFFERED_PROG_ITERATIONS;
224 is_buffer_available = 0;
225
226 /* Check that the target offset does not cross a 32-word boundary. */
227 if ((offset & BOUNDARY_OF_32_WORDS) != 0)
228 return IO_FAIL;
229
230 /* This implementation requires the buffer to be 32bit aligned. */
231 if (((uintptr_t)buffer & (sizeof(uint32_t) - 1)) != 0)
232 return IO_FAIL;
233
234 /* Check there are some data to program */
235 assert(buffer_size > 0);
236
237 /* Check that the buffer size does not exceed the maximum hardware
238 * buffer size on chip.
239 */
240 assert(buffer_size <= NOR_MAX_BUFFER_SIZE_IN_BYTES);
241
242 /* Check that the buffer size is a multiple of 32-bit words */
243 assert((buffer_size % 4) == 0);
244
245 /* Pre-programming conditions checked, now start the algorithm. */
246
247 /* Prepare the data destination address */
248 data = (uint32_t *)(uintptr_t)offset;
249
250 /* Check the availability of the buffer */
251 do {
252 /* Issue the Buffered Program Setup command */
253 nor_send_cmd(offset, NOR_CMD_BUFFERED_PROGRAM);
254
255 /* Read back the status register bit#7 from the same offset */
256 if (((*data) & NOR_SR_BIT_WRITE) == NOR_SR_BIT_WRITE)
257 is_buffer_available = 1;
258
259 /* Update the loop counter */
260 timeout--;
261 } while ((timeout > 0) && (is_buffer_available == 0));
262
263 /* The buffer was not available for writing */
264 if (timeout == 0) {
265 err = IO_FAIL;
266 goto exit;
267 }
268
269 /* From now on we work in 32-bit words */
270 size_in_words = buffer_size / sizeof(uint32_t);
271
272 /* Write the word count, which is (buffer_size_in_words - 1),
273 * because word count 0 means one word. */
274 nor_send_cmd(offset, size_in_words - 1);
275
276 /* Write the data to the NOR Flash, advancing each address by 4 bytes */
277 for (count = 0; count < size_in_words; count++, data++, buffer++)
278 *data = *buffer;
279
280 /* Issue the Buffered Program Confirm command, to start the programming
281 * operation */
282 nor_send_cmd(device->device_address, NOR_CMD_BUFFERED_PROGRAM_ACK);
283
284 /* Wait for the write to complete and then check for any errors;
285 * i.e. check the Status Register */
286 status_register = flash_wait_until_complete(device);
287
288 /* Perform a full status check:
289 * Mask the relevant bits of Status Register.
290 * Everything should be zero, if not, we have a problem */
291
292 CHECK_VPP_RANGE_ERROR(status_register, offset);
293
294 CHECK_SR_BIT_PROGRAM_ERROR(status_register, offset);
295
296 CHECK_BLOCK_LOCK_ERROR(status_register, offset);
297
298 if (err != IO_SUCCESS) {
299 /* Clear the Status Register */
300 nor_send_cmd(device->device_address,
301 NOR_CMD_CLEAR_STATUS_REG);
302 }
303
304exit:
305 /* Put device back into Read Array mode */
306 nor_send_cmd(device->device_address, NOR_CMD_READ_ARRAY);
307
308 return err;
309}
310
311static int flash_write_single_word(const io_nor_flash_spec_t *device,
312 int32_t offset, uint32_t data)
313{
314 int err = IO_SUCCESS;
315 uint32_t status_register;
316
317 /* NOR Flash Programming: Request a write single word command */
318 nor_send_cmd(offset, NOR_CMD_WORD_PROGRAM);
319
320 /* Store the word into NOR Flash; */
321 mmio_write_32(offset, data);
322
323 /* Wait for the write to complete and then check for any errors;
324 * i.e. check the Status Register */
325 status_register = flash_wait_until_complete(device);
326
327 /* Perform a full status check: */
328 /* Mask the relevant bits of Status Register.
329 * Everything should be zero, if not, we have a problem */
330
331 CHECK_VPP_RANGE_ERROR(status_register, offset);
332
333 CHECK_SR_BIT_PROGRAM_ERROR(status_register, offset);
334
335 CHECK_BLOCK_LOCK_ERROR(status_register, offset);
336
337 if (err != IO_SUCCESS)
338 /* Clear the Status Register */
339 nor_send_cmd(device->device_address,
340 NOR_CMD_CLEAR_STATUS_REG);
341
342 /* Put device back into Read Array mode */
343 nor_send_cmd(device->device_address, NOR_CMD_READ_ARRAY);
344
345 return err;
346}
347
348int flash_block_write(file_state_t *fp, uint32_t offset,
349 const uintptr_t buffer, size_t *written)
350{
351 int ret;
352 uintptr_t buffer_ptr = buffer;
353 uint32_t buffer_size;
354 uint32_t remaining = fp->block_spec->block_size;
355 uint32_t flash_pos = fp->block_spec->region_address + offset;
356 uint32_t block_offset = flash_pos;
357
358 /* address passed should be block aligned */
359 assert(!(offset % fp->block_spec->block_size));
360
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200361 /* Unlock block */
362 flash_unlock_block_if_necessary(fp->block_spec, block_offset);
363
364 /* Erase one block */
365 ret = flash_erase_block(fp->block_spec, flash_pos);
366
367 if (ret != IO_SUCCESS)
368 /* Perform lock operation as we unlocked it */
369 goto lock_block;
370
371 /* Start by using NOR Flash buffer while the buffer size is a multiple
372 * of 32-bit */
373 while ((remaining >= sizeof(uint32_t)) && (ret == IO_SUCCESS)) {
374 if (remaining >= NOR_MAX_BUFFER_SIZE_IN_BYTES)
375 buffer_size = NOR_MAX_BUFFER_SIZE_IN_BYTES;
376 else
377 /* Copy the remaining 32bit words of the buffer */
378 buffer_size = remaining & (sizeof(uint32_t) - 1);
379
380 ret = flash_write_buffer(fp->block_spec, flash_pos,
381 (const uint32_t *)buffer_ptr, buffer_size);
382 flash_pos += buffer_size;
383 remaining -= buffer_size;
384 buffer_ptr += buffer_size;
385
386 }
387
388 /* Write the remaining bytes */
389 while ((remaining > 0) && (ret == IO_SUCCESS)) {
390 ret = flash_write_single_word(fp->block_spec,
391 flash_pos++, buffer_ptr++);
392 remaining--;
393 }
394
395 if (ret == IO_SUCCESS)
396 *written = fp->block_spec->block_size;
397
398lock_block:
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200399 /* Lock the block once done */
400 flash_perform_lock_operation(fp->block_spec,
401 block_offset,
402 NOR_LOCK_BLOCK);
403
404 return ret;
405}
406
407/* In case of partial write we need to save the block into a temporary buffer */
408static char block_buffer[NOR_FLASH_BLOCK_SIZE];
409
410int flash_partial_write(file_state_t *fp, uint32_t offset,
411 const uintptr_t buffer, size_t length, size_t *written)
412{
413 uintptr_t block_start;
414 uint32_t block_size;
415 uint32_t block_offset;
416 int ret;
417
418 assert((fp != NULL) && (fp->block_spec != NULL));
419 assert(written != NULL);
420
421 block_size = fp->block_spec->block_size;
422 /* Start address of the block to write */
423 block_start = (offset / block_size) * block_size;
424
425 /* Ensure 'block_buffer' is big enough to contain a copy of the block.
426 * 'block_buffer' is reserved at build time - so it might not match */
427 assert(sizeof(block_buffer) >= block_size);
428
429 /*
430 * Check the buffer fits inside a single block.
431 * It must not span several blocks
432 */
433 assert((offset / block_size) ==
434 ((offset + length - 1) / block_size));
435
436 /* Make a copy of the block from flash to a temporary buffer */
437 memcpy(block_buffer, (void *)(fp->block_spec->region_address +
438 block_start), block_size);
439
440 /* Calculate the offset of the buffer into the block */
441 block_offset = offset % block_size;
442
443 /* update the content of the block buffer */
444 memcpy(block_buffer + block_offset, (void *)buffer, length);
445
446 /* Write the block buffer back */
447 ret = flash_block_write(fp, block_start,
448 (uintptr_t)block_buffer, written);
449 if (ret == IO_SUCCESS)
450 *written = length;
451
452 return ret;
453}