1 /******************************************************************************
2 * *
3 * License Agreement *
4 * *
5 * Copyright (c) 2015 Altera Corporation, San Jose, California, USA. *
6 * All rights reserved. *
7 * *
8 * Permission is hereby granted, free of charge, to any person obtaining a *
9 * copy of this software and associated documentation files (the "Software"), *
10 * to deal in the Software without restriction, including without limitation *
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
12 * and/or sell copies of the Software, and to permit persons to whom the *
13 * Software is furnished to do so, subject to the following conditions: *
14 * *
15 * The above copyright notice and this permission notice shall be included in *
16 * all copies or substantial portions of the Software. *
17 * *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
24 * DEALINGS IN THE SOFTWARE. *
25 * *
26 * *
27 ******************************************************************************/
28
29 #include <errno.h>
30 #include <io.h>
31 #include <string.h>
32 #include <stddef.h>
33 #include "sys/param.h"
34 #include "alt_types.h"
35 #include "altera_epcq_controller_regs.h"
36 #include "altera_epcq_controller.h"
37 #include "priv/alt_busy_sleep.h"
38 #include "sys/alt_debug.h"
39 #include "sys/alt_cache.h"
40
41
42 ALT_INLINE alt_32 static alt_epcq_validate_read_write_arguments(alt_epcq_controller_dev *flash_info,alt_u32 offset, alt_u32 length);
43 alt_32 static alt_epcq_poll_for_write_in_progress(alt_epcq_controller_dev* epcq_flash_info);
44
45 /*
46 * Public API
47 *
48 * Refer to “Using Flash Devices” in the
49 * Developing Programs Using the Hardware Abstraction Layer chapter
50 * of the Nios II Software Developer’s Handbook.
51 */
52
53
54 /**
55 * alt_epcq_controller_lock
56 *
57 * Locks the range of the memory sectors, which
58 * protected from write and erase.
59 *
60 * Arguments:
61 * - *flash_info: Pointer to general flash device structure.
62 * - sectors_to_lock: Block protection bits in EPCQ ==> Bit4 | Bit3 | Bit2 | Bit1 | Bit0
63 * TB | BP3 | BP2 | BP1 | BP0
64 * For details of setting sectors protection, please refer to EPCQ datasheet.
65 *
66 * Returns:
67 * 0 -> success
68 * -EINVAL -> Invalid arguments
69 * -ETIME -> Time out and skipping the looping after 0.7 sec.
70 * -ENOLCK -> Sectors lock failed.
71 **/
alt_epcq_controller_lock(alt_flash_dev * flash_info,alt_u32 sectors_to_lock)72 int alt_epcq_controller_lock(alt_flash_dev *flash_info, alt_u32 sectors_to_lock)
73 {
74 alt_u32 mem_op_value = 0; /* value to write to EPCQ_MEM_OP register */
75 alt_epcq_controller_dev* epcq_flash_info = NULL;
76 alt_u32 result = 0;
77 alt_32 status = 0;
78
79 /* return -EINVAL if flash_info is NULL */
80 if(NULL == flash_info || 0 > sectors_to_lock)
81 {
82 return -EINVAL;
83 }
84
85 epcq_flash_info = (alt_epcq_controller_dev*)flash_info;
86
87 /* sector value should occupy bits 17:8 */
88 mem_op_value = sectors_to_lock << 8;
89
90 /* sector protect commands 0b11 occupies lower 2 bits */
91 mem_op_value |= ALTERA_EPCQ_CONTROLLER_MEM_OP_SECTOR_PROTECT_CMD;
92
93 /* write sector protect command to EPCQ_MEM_OP register to protect sectors */
94 IOWR_ALTERA_EPCQ_CONTROLLER_MEM_OP(epcq_flash_info->csr_base, mem_op_value);
95
96 /* poll write in progress to make sure no operation is in progress */
97 status = alt_epcq_poll_for_write_in_progress(epcq_flash_info);
98 if(status != 0)
99 {
100 return status;
101 }
102
103 status = IORD_ALTERA_EPCQ_CONTROLLER_STATUS(epcq_flash_info->csr_base);
104 result |= (status >> 2) & 0x07; /* extract out BP3 - BP0 */
105 result |= (status >> 3) & 0x08; /* extract out BP4 */
106 result |= (status >> 1) & 0x10; /* extract out TOP/BOTTOM bit */
107
108 if(result != sectors_to_lock)
109 {
110 return -ENOLCK;
111 }
112
113 return 0;
114 }
115
116 /**
117 * alt_epcq_controller_get_info
118 *
119 * Pass the table of erase blocks to the user. This flash will return a single
120 * flash_region that gives the number and size of sectors for the device used.
121 *
122 * Arguments:
123 * - *fd: Pointer to general flash device structure.
124 * - **info: Pointer to flash region
125 * - *number_of_regions: Pointer to number of regions
126 *
127 * For details of setting sectors protection, please refer to EPCQ datasheet.
128 *
129 * Returns:
130 * 0 -> success
131 * -EINVAL -> Invalid arguments
132 * -EIO -> Could be hardware problem.
133 **/
alt_epcq_controller_get_info(alt_flash_fd * fd,flash_region ** info,int * number_of_regions)134 int alt_epcq_controller_get_info
135 (
136 alt_flash_fd *fd, /** flash device descriptor */
137 flash_region **info, /** pointer to flash_region will be stored here */
138 int *number_of_regions /** number of regions will be stored here */
139 )
140 {
141 alt_flash_dev* flash = NULL;
142
143 /* return -EINVAL if fd,info and number_of_regions are NULL */
144 if(NULL == fd || NULL == info || NULL == number_of_regions)
145 {
146 return -EINVAL;
147 }
148
149 flash = (alt_flash_dev*)fd;
150
151 *number_of_regions = flash->number_of_regions;
152
153 if (!flash->number_of_regions)
154 {
155 return -EIO;
156 }
157 else
158 {
159 *info = &flash->region_info[0];
160 }
161
162 return 0;
163 }
164
165 /**
166 * alt_epcq_controller_erase_block
167 *
168 * This function erases a single flash sector.
169 *
170 * Arguments:
171 * - *flash_info: Pointer to EPCQ flash device structure.
172 * - block_offset: byte-addressed offset, from start of flash, of the sector to be erased
173 *
174 * Returns:
175 * 0 -> success
176 * -EINVAL -> Invalid arguments
177 * -EIO -> write failed, sector might be protected
178 **/
alt_epcq_controller_erase_block(alt_flash_dev * flash_info,int block_offset)179 int alt_epcq_controller_erase_block(alt_flash_dev *flash_info, int block_offset)
180 {
181 alt_32 ret_code = 0;
182 alt_u32 mem_op_value = 0; /* value to write to EPCQ_MEM_OP register */
183 alt_epcq_controller_dev* epcq_flash_info = NULL;
184 alt_u32 sector_number = 0;
185
186 /* return -EINVAL if flash_info is NULL */
187 if(NULL == flash_info)
188 {
189 return -EINVAL;
190 }
191
192 epcq_flash_info = (alt_epcq_controller_dev*)flash_info;
193
194 /*
195 * Sanity checks that block_offset is within the flash memory span and that the
196 * block offset is sector aligned.
197 *
198 */
199 if((block_offset < 0)
200 || (block_offset >= epcq_flash_info->size_in_bytes)
201 || (block_offset & (epcq_flash_info->sector_size - 1)) != 0)
202 {
203 return -EINVAL;
204 }
205
206 /* calculate current sector/block number */
207 sector_number = (block_offset/(epcq_flash_info->sector_size));
208
209 /* sector value should occupy bits 23:8 */
210 mem_op_value = (sector_number << 8) & ALTERA_EPCQ_CONTROLLER_MEM_OP_SECTOR_VALUE_MASK;
211
212 /* sector erase commands 0b10 occupies lower 2 bits */
213 mem_op_value |= ALTERA_EPCQ_CONTROLLER_MEM_OP_SECTOR_ERASE_CMD;
214
215 /* write sector erase command to EPCQ_MEM_OP register to erase sector "sector_number" */
216 IOWR_ALTERA_EPCQ_CONTROLLER_MEM_OP(epcq_flash_info->csr_base, mem_op_value);
217
218 /* check whether erase triggered a illegal erase interrupt */
219 if((IORD_ALTERA_EPCQ_CONTROLLER_ISR(epcq_flash_info->csr_base) &
220 ALTERA_EPCQ_CONTROLLER_ISR_ILLEGAL_ERASE_MASK) ==
221 ALTERA_EPCQ_CONTROLLER_ISR_ILLEGAL_ERASE_ACTIVE)
222 {
223 /* clear register */
224 /* EPCQ_ISR access is write one to clear (W1C) */
225 IOWR_ALTERA_EPCQ_CONTROLLER_ISR(epcq_flash_info->csr_base,
226 ALTERA_EPCQ_CONTROLLER_ISR_ILLEGAL_ERASE_MASK );
227 return -EIO; /* erase failed, sector might be protected */
228 }
229
230 return ret_code;
231 }
232
233 /**
234 * alt_epcq_controller_write_block
235 *
236 * This function writes one block/sector of data to flash. The length of the write can NOT
237 * spill into the adjacent sector.
238 *
239 * It assumes that someone has already erased the appropriate sector(s).
240 *
241 * Arguments:
242 * - *flash_info: Pointer to EPCQ flash device structure.
243 * - block_offset: byte-addressed offset, from the start of flash, of the sector to written to
244 * - data-offset: Byte offset (unaligned access) of write into flash memory.
245 * For best performance, word(32 bits - aligned access) offset of write is recommended.
246 * - *src_addr: source buffer
247 * - length: size of writing
248 *
249 * Returns:
250 * 0 -> success
251 * -EINVAL -> Invalid arguments
252 * -EIO -> write failed, sector might be protected
253 **/
alt_epcq_controller_write_block(alt_flash_dev * flash_info,int block_offset,int data_offset,const void * data,int length)254 int alt_epcq_controller_write_block
255 (
256 alt_flash_dev *flash_info, /** flash device info */
257 int block_offset, /** sector/block offset in byte addressing */
258 int data_offset, /** offset of write from base address */
259 const void *data, /** data to be written */
260 int length /** bytes of data to be written, >0 */
261 )
262 {
263 alt_u32 buffer_offset = 0; /** offset into data buffer to get write data */
264 alt_u32 remaining_length = length; /** length left to write */
265 alt_u32 write_offset = data_offset; /** offset into flash to write too */
266
267 alt_epcq_controller_dev *epcq_flash_info = (alt_epcq_controller_dev*)flash_info;
268
269 /*
270 * Sanity checks that data offset is not larger then a sector, that block offset is
271 * sector aligned and within the valid flash memory range and a write doesn't spill into
272 * the adjacent flash sector.
273 */
274 if(block_offset < 0
275 || data_offset < 0
276 || NULL == flash_info
277 || NULL == data
278 || data_offset >= epcq_flash_info->size_in_bytes
279 || block_offset >= epcq_flash_info->size_in_bytes
280 || length > (epcq_flash_info->sector_size - (data_offset - block_offset))
281 || length < 0
282 || (block_offset & (epcq_flash_info->sector_size - 1)) != 0)
283 {
284 return -EINVAL;
285 }
286
287 /*
288 * Do writes one 32-bit word at a time.
289 * We need to make sure that we pad the first few bytes so they're word aligned if they are
290 * not already.
291 */
292 while (remaining_length > 0)
293 {
294 alt_u32 word_to_write = 0xFFFFFFFF; /** initialize word to write to blank word */
295 alt_u32 padding = 0; /** bytes to pad the next word that is written */
296 alt_u32 bytes_to_copy = sizeof(alt_u32); /** number of bytes from source to copy */
297
298 /*
299 * we need to make sure the write is word aligned
300 * this should only be true at most 1 time
301 */
302 if (0 != (write_offset & (sizeof(alt_u32) - 1)))
303 {
304 /*
305 * data is not word aligned
306 * calculate padding bytes need to add before start of a data offset
307 */
308 padding = write_offset & (sizeof(alt_u32) - 1);
309
310 /* update variables to account for padding being added */
311 bytes_to_copy -= padding;
312
313 if(bytes_to_copy > remaining_length)
314 {
315 bytes_to_copy = remaining_length;
316 }
317
318 write_offset = write_offset - padding;
319 if(0 != (write_offset & (sizeof(alt_u32) - 1)))
320 {
321 return -EINVAL;
322 }
323 }
324 else
325 {
326 if(bytes_to_copy > remaining_length)
327 {
328 bytes_to_copy = remaining_length;
329 }
330 }
331
332 /* prepare the word to be written */
333 memcpy((((void*)&word_to_write)) + padding, ((void*)data) + buffer_offset, bytes_to_copy);
334
335 /* update offset and length variables */
336 buffer_offset += bytes_to_copy;
337 remaining_length -= bytes_to_copy;
338
339 /* write to flash 32 bits at a time */
340 IOWR_32DIRECT(epcq_flash_info->data_base, write_offset, word_to_write);
341
342 /* check whether write triggered a illegal write interrupt */
343 if((IORD_ALTERA_EPCQ_CONTROLLER_ISR(epcq_flash_info->csr_base) &
344 ALTERA_EPCQ_CONTROLLER_ISR_ILLEGAL_WRITE_MASK) ==
345 ALTERA_EPCQ_CONTROLLER_ISR_ILLEGAL_WRITE_ACTIVE)
346 {
347 /* clear register */
348 IOWR_ALTERA_EPCQ_CONTROLLER_ISR(epcq_flash_info->csr_base,
349 ALTERA_EPCQ_CONTROLLER_ISR_ILLEGAL_WRITE_MASK );
350 return -EIO; /** write failed, sector might be protected */
351 }
352
353 /* update current offset */
354 write_offset = write_offset + sizeof(alt_u32);
355 }
356
357 return 0;
358 }
359
360 /**
361 * alt_epcq_controller_write
362 *
363 * Program the data into the flash at the selected address.
364 *
365 * The different between this function and alt_epcq_controller_write_block function
366 * is that this function (alt_epcq_controller_write) will automatically erase a block as needed
367 * Arguments:
368 * - *flash_info: Pointer to EPCQ flash device structure.
369 * - offset: Byte offset (unaligned access) of write to flash memory. For best performance,
370 * word(32 bits - aligned access) offset of write is recommended.
371 * - *src_addr: source buffer
372 * - length: size of writing
373 *
374 * Returns:
375 * 0 -> success
376 * -EINVAL -> Invalid arguments
377 * -EIO -> write failed, sector might be protected
378 *
379 **/
alt_epcq_controller_write(alt_flash_dev * flash_info,int offset,const void * src_addr,int length)380 int alt_epcq_controller_write(
381 alt_flash_dev *flash_info, /** device info */
382 int offset, /** offset of write from base address */
383 const void *src_addr, /** source buffer */
384 int length /** size of writing */
385 )
386 {
387 alt_32 ret_code = 0;
388
389 alt_epcq_controller_dev *epcq_flash_info = NULL;
390
391 alt_u32 write_offset = offset; /** address of next byte to write */
392 alt_u32 remaining_length = length; /** length of write data left to be written */
393 alt_u32 buffer_offset = 0; /** offset into source buffer to get write data */
394 alt_u32 i = 0;
395
396 /* return -EINVAL if flash_info and src_addr are NULL */
397 if(NULL == flash_info || NULL == src_addr)
398 {
399 return -EINVAL;
400 }
401
402 epcq_flash_info = (alt_epcq_controller_dev*)flash_info;
403
404 /* make sure the write parameters are within the bounds of the flash */
405 ret_code = alt_epcq_validate_read_write_arguments(epcq_flash_info, offset, length);
406
407 if(0 != ret_code)
408 {
409 return ret_code;
410 }
411
412 /*
413 * This loop erases and writes data one sector at a time. We check for write completion
414 * before starting the next sector.
415 */
416 for(i = offset/epcq_flash_info->sector_size ; i < epcq_flash_info->number_of_sectors; i++)
417 {
418 alt_u32 block_offset = 0; /** block offset in byte addressing */
419 alt_u32 offset_within_current_sector = 0; /** offset into current sector to write */
420 alt_u32 length_to_write = 0; /** length to write to current sector */
421
422 if(0 >= remaining_length)
423 {
424 break; /* out of data to write */
425 }
426
427 /* calculate current sector/block offset in byte addressing */
428 block_offset = write_offset & ~(epcq_flash_info->sector_size - 1);
429
430 /* calculate offset into sector/block if there is one */
431 if(block_offset != write_offset)
432 {
433 offset_within_current_sector = write_offset - block_offset;
434 }
435
436 /* erase sector */
437 ret_code = alt_epcq_controller_erase_block(flash_info, block_offset);
438
439 if(0 != ret_code)
440 {
441 return ret_code;
442 }
443
444 /* calculate the byte size of data to be written in a sector */
445 length_to_write = MIN(epcq_flash_info->sector_size - offset_within_current_sector,
446 remaining_length);
447
448 /* write data to erased block */
449 ret_code = alt_epcq_controller_write_block(flash_info, block_offset, write_offset,
450 src_addr + buffer_offset, length_to_write);
451
452
453 if(0 != ret_code)
454 {
455 return ret_code;
456 }
457
458 /* update remaining length and buffer_offset pointer */
459 remaining_length -= length_to_write;
460 buffer_offset += length_to_write;
461 write_offset += length_to_write;
462 }
463
464 return ret_code;
465 }
466
467 /**
468 * alt_epcq_controller_read
469 *
470 * There's no real need to use this function as opposed to using memcpy directly. It does
471 * do some sanity checks on the bounds of the read.
472 *
473 * Arguments:
474 * - *flash_info: Pointer to general flash device structure.
475 * - offset: offset read from flash memory.
476 * - *dest_addr: destination buffer
477 * - length: size of reading
478 *
479 * Returns:
480 * 0 -> success
481 * -EINVAL -> Invalid arguments
482 **/
alt_epcq_controller_read(alt_flash_dev * flash_info,int offset,void * dest_addr,int length)483 int alt_epcq_controller_read
484 (
485 alt_flash_dev *flash_info, /** device info */
486 int offset, /** offset of read from base address */
487 void *dest_addr, /** destination buffer */
488 int length /** size of read */
489 )
490 {
491 alt_32 ret_code = 0;
492 alt_epcq_controller_dev *epcq_flash_info = NULL;
493
494 /* return -EINVAL if flash_info and dest_addr are NULL */
495 if(NULL == flash_info || NULL == dest_addr)
496 {
497 return -EINVAL;
498 }
499
500 epcq_flash_info = (alt_epcq_controller_dev*)flash_info;
501
502 /* validate arguments */
503 ret_code = alt_epcq_validate_read_write_arguments(epcq_flash_info, offset, length);
504
505 /* copy data from flash to destination address */
506 if(0 == ret_code)
507 {
508 memcpy(dest_addr, (alt_u8*)epcq_flash_info->data_base + offset, length);
509 }
510
511 return ret_code;
512 }
513
514 /**
515 * altera_epcq_controller_init
516 *
517 * alt_sys_init.c will call this function automatically through macro
518 *
519 * Information in system.h is checked against expected values that are determined by the silicon_id.
520 * If the information doesn't match then this system is configured incorrectly. Most likely the wrong
521 * type of EPCS or EPCQ device was selected when instantiating the soft IP.
522 *
523 * Arguments:
524 * - *flash: Pointer to EPCQ flash device structure.
525 *
526 * Returns:
527 * 0 -> success
528 * -EINVAL -> Invalid arguments.
529 * -ENODEV -> System is configured incorrectly.
530 **/
altera_epcq_controller_init(alt_epcq_controller_dev * flash)531 alt_32 altera_epcq_controller_init(alt_epcq_controller_dev *flash)
532 {
533 alt_u32 silicon_id = 0;
534 alt_u32 size_in_bytes = 0;
535 alt_u32 number_of_sectors = 0;
536
537 /* return -EINVAL if flash is NULL */
538 if(NULL == flash)
539 {
540 return -EINVAL;
541 }
542
543 /* return -ENODEV if CSR slave is not attached */
544 if(NULL == (void *)flash->csr_base)
545 {
546 return -ENODEV;
547 }
548
549
550 /*
551 * If flash is an EPCQ device, we read the EPCQ_RD_RDID register for the ID
552 * If flash is an EPCS device, we read the EPCQ_RD_SID register for the ID
553 *
554 * Whether or not the flash is a EPCQ or EPCS is indicated in the system.h. The system.h gets
555 * this value from the hw.tcl of the IP. If this value is set incorrectly, then things will go
556 * badly.
557 *
558 * In both cases, we can determine the number of sectors, which we can use
559 * to calculate a size. We compare that size to the system.h value to make sure
560 * the EPCQ soft IP was configured correctly.
561 */
562 if(0 == flash->is_epcs)
563 {
564 /* If we're an EPCQ, we read EPCQ_RD_RDID for the silicon ID */
565 silicon_id = IORD_ALTERA_EPCQ_CONTROLLER_RDID(flash->csr_base);
566 silicon_id &= ALTERA_EPCQ_CONTROLLER_RDID_MASK;
567
568 /* Determine which EPCQ device so we can figure out the number of sectors */
569 /* EPCQ share the same ID for the same capacity*/
570 switch(silicon_id)
571 {
572 case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ16:
573 {
574 number_of_sectors = 32;
575 break;
576 }
577 case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ32:
578 {
579 number_of_sectors = 64;
580 break;
581 }
582 case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ64:
583 {
584 number_of_sectors = 128;
585 break;
586 }
587 case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ128:
588 {
589 number_of_sectors = 256;
590 break;
591 }
592 case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ256:
593 {
594 number_of_sectors = 512;
595 break;
596 }
597 case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ512:
598 {
599 number_of_sectors = 1024;
600 break;
601 }
602 case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ1024:
603 {
604 number_of_sectors = 2048;
605 break;
606 }
607 default:
608 {
609 return -ENODEV;
610 }
611 }
612 }
613 else {
614 /* If we're an EPCS, we read EPCQ_RD_SID for the silicon ID */
615 silicon_id = IORD_ALTERA_EPCQ_CONTROLLER_SID(flash->csr_base);
616 silicon_id &= ALTERA_EPCQ_CONTROLLER_SID_MASK;
617
618 /* Determine which EPCS device so we can figure out various properties */
619 switch(silicon_id)
620 {
621 case ALTERA_EPCQ_CONTROLLER_SID_EPCS16:
622 {
623 number_of_sectors = 32;
624 break;
625 }
626 case ALTERA_EPCQ_CONTROLLER_SID_EPCS64:
627 {
628 number_of_sectors = 128;
629 break;
630 }
631 case ALTERA_EPCQ_CONTROLLER_SID_EPCS128:
632 {
633 number_of_sectors = 256;
634 break;
635 }
636 default:
637 {
638 return -ENODEV;
639 }
640 }
641 }
642
643 /* Calculate size of flash based on number of sectors */
644 size_in_bytes = number_of_sectors * flash->sector_size;
645
646 /*
647 * Make sure calculated size is the same size given in system.h
648 * Also check number of sectors is the same number given in system.h
649 * Otherwise the EPCQ IP was not configured correctly
650 */
651 if( size_in_bytes != flash->size_in_bytes ||
652 number_of_sectors != flash->number_of_sectors)
653 {
654 flash->dev.number_of_regions = 0;
655 return -ENODEV;
656 }
657 else
658 {
659 flash->silicon_id = silicon_id;
660 flash->number_of_sectors = number_of_sectors;
661
662 /*
663 * populate fields of region_info required to conform to HAL API
664 * create 1 region that composed of "number_of_sectors" blocks
665 */
666 flash->dev.number_of_regions = 1;
667 flash->dev.region_info[0].offset = 0;
668 flash->dev.region_info[0].region_size = size_in_bytes;
669 flash->dev.region_info[0].number_of_blocks = number_of_sectors;
670 flash->dev.region_info[0].block_size = flash->sector_size;
671 }
672
673
674 /*
675 * Register this device as a valid flash device type
676 *
677 * Only register the device if it's configured correctly.
678 */
679 alt_flash_device_register(&(flash->dev));
680
681
682 return 0;
683 }
684
685
686 /*
687 * Private API
688 *
689 * Helper functions used by Public API functions.
690 *
691 * Arguments:
692 * - *flash_info: Pointer to EPCQ flash device structure.
693 * - offset: Offset of read/write from base address.
694 * - length: Length of read/write in bytes.
695 *
696 * Returns:
697 * 0 -> success
698 * -EINVAL -> Invalid arguments
699 */
700 /**
701 * Used to check that arguments to a read or write are valid
702 */
alt_epcq_validate_read_write_arguments(alt_epcq_controller_dev * flash_info,alt_u32 offset,alt_u32 length)703 ALT_INLINE alt_32 static alt_epcq_validate_read_write_arguments
704 (
705 alt_epcq_controller_dev *flash_info, /** device info */
706 alt_u32 offset, /** offset of read/write */
707 alt_u32 length /** length of read/write */
708 )
709 {
710 alt_epcq_controller_dev *epcq_flash_info = NULL;
711 alt_u32 start_address = 0;
712 alt_32 end_address = 0;
713
714 /* return -EINVAL if flash_info is NULL */
715 if(NULL == flash_info)
716 {
717 return -EINVAL;
718 }
719
720 epcq_flash_info = (alt_epcq_controller_dev*)flash_info;
721
722 start_address = epcq_flash_info->data_base + offset; /** first address of read or write */
723 end_address = start_address + length; /** last address of read or write (not inclusive) */
724
725 /* make sure start and end address is less then the end address of the flash */
726 if(
727 start_address >= epcq_flash_info->data_end ||
728 end_address > epcq_flash_info->data_end ||
729 offset < 0 ||
730 length < 0
731 )
732 {
733 return -EINVAL;
734 }
735
736 return 0;
737 }
738
739 /*
740 * Private function that polls write in progress bit EPCQ_RD_STATUS.
741 *
742 * Write in progress will be set if any of the following operations are in progress:
743 * -WRITE STATUS REGISTER
744 * -WRITE NONVOLATILE CONFIGURATION REGISTER
745 * -PROGRAM
746 * -ERASE
747 *
748 * Assumes EPCQ was configured correctly.
749 *
750 * If ALTERA_EPCQ_CONTROLLER_1US_TIMEOUT_VALUE is set, the function will time out after
751 * a period of time determined by that value.
752 *
753 * Arguments:
754 * - *epcq_flash_info: Pointer to EPCQ flash device structure.
755 *
756 * Returns:
757 * 0 -> success
758 * -EINVAL -> Invalid arguments
759 * -ETIME -> Time out and skipping the looping after 0.7 sec.
760 */
alt_epcq_poll_for_write_in_progress(alt_epcq_controller_dev * epcq_flash_info)761 alt_32 static alt_epcq_poll_for_write_in_progress(alt_epcq_controller_dev* epcq_flash_info)
762 {
763 /* we'll want to implement timeout if a timeout value is specified */
764 #if ALTERA_EPCQ_CONTROLLER_1US_TIMEOUT_VALUE > 0
765 alt_u32 timeout = ALTERA_EPCQ_CONTROLLER_1US_TIMEOUT_VALUE;
766 alt_u16 counter = 0;
767 #endif
768
769 /* return -EINVAL if epcq_flash_info is NULL */
770 if(NULL == epcq_flash_info)
771 {
772 return -EINVAL;
773 }
774
775 /* while Write in Progress bit is set, we wait */
776 while((IORD_ALTERA_EPCQ_CONTROLLER_STATUS(epcq_flash_info->csr_base) &
777 ALTERA_EPCQ_CONTROLLER_STATUS_WIP_MASK) ==
778 ALTERA_EPCQ_CONTROLLER_STATUS_WIP_BUSY)
779 {
780 alt_busy_sleep(1); /* delay 1us */
781 #if ALTERA_EPCQ_CONTROLLER_1US_TIMEOUT_VALUE > 0
782 if(timeout <= counter )
783 {
784 return -ETIME;
785 }
786
787 counter++;
788 #endif
789
790 }
791
792 return 0;
793 }
794