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
|
* This agreement shall be governed in all respects by the laws of the State *
|
27
|
* of California and by the laws of the United States of America. *
|
28
|
* *
|
29
|
******************************************************************************/
|
30
|
|
31
|
#include <errno.h>
|
32
|
#include <io.h>
|
33
|
#include <string.h>
|
34
|
#include <stddef.h>
|
35
|
#include "sys/param.h"
|
36
|
#include "alt_types.h"
|
37
|
#include "altera_epcq_controller2_regs.h"
|
38
|
#include "altera_epcq_controller2.h"
|
39
|
#include "priv/alt_busy_sleep.h"
|
40
|
#include "sys/alt_debug.h"
|
41
|
#include "sys/alt_cache.h"
|
42
|
|
43
|
|
44
|
ALT_INLINE alt_32 static alt_epcq_validate_read_write_arguments(alt_epcq_controller2_dev *flash_info,alt_u32 offset, alt_u32 length);
|
45
|
alt_32 static alt_epcq_poll_for_write_in_progress(alt_epcq_controller2_dev* epcq_flash_info);
|
46
|
|
47
|
|
48
|
* Public API
|
49
|
*
|
50
|
* Refer to 窶弑sing Flash Devices窶� in the
|
51
|
* Developing Programs Using the Hardware Abstraction Layer chapter
|
52
|
* of the Nios II Software Developer窶冱 Handbook.
|
53
|
*/
|
54
|
|
55
|
|
56
|
|
57
|
* alt_epcq_controller2_lock
|
58
|
*
|
59
|
* Locks the range of the memory sectors, which
|
60
|
* protected from write and erase.
|
61
|
*
|
62
|
* Arguments:
|
63
|
* - *flash_info: Pointer to general flash device structure.
|
64
|
* - sectors_to_lock: Block protection bits in EPCQ ==> Bit4 | Bit3 | Bit2 | Bit1 | Bit0
|
65
|
* TB | BP3 | BP2 | BP1 | BP0
|
66
|
* For details of setting sectors protection, please refer to EPCQ datasheet.
|
67
|
*
|
68
|
* Returns:
|
69
|
* 0 -> success
|
70
|
* -EINVAL -> Invalid arguments
|
71
|
* -ETIME -> Time out and skipping the looping after 0.7 sec.
|
72
|
* -ENOLCK -> Sectors lock failed.
|
73
|
**/
|
74
|
int alt_epcq_controller2_lock(alt_flash_dev *flash_info, alt_u32 sectors_to_lock)
|
75
|
{
|
76
|
alt_u32 mem_op_value = 0;
|
77
|
alt_epcq_controller2_dev* epcq_flash_info = NULL;
|
78
|
alt_u32 result = 0;
|
79
|
alt_32 status = 0;
|
80
|
|
81
|
|
82
|
if(NULL == flash_info || 0 > sectors_to_lock)
|
83
|
{
|
84
|
return -EINVAL;
|
85
|
}
|
86
|
|
87
|
epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
|
88
|
|
89
|
|
90
|
|
91
|
mem_op_value = ALTERA_EPCQ_CONTROLLER2_MEM_OP_WRITE_ENABLE_CMD;
|
92
|
|
93
|
|
94
|
IOWR_ALTERA_EPCQ_CONTROLLER2_MEM_OP(epcq_flash_info->csr_base, mem_op_value);
|
95
|
|
96
|
|
97
|
|
98
|
mem_op_value = sectors_to_lock << 8;
|
99
|
|
100
|
|
101
|
mem_op_value |= ALTERA_EPCQ_CONTROLLER2_MEM_OP_SECTOR_PROTECT_CMD;
|
102
|
|
103
|
|
104
|
IOWR_ALTERA_EPCQ_CONTROLLER2_MEM_OP(epcq_flash_info->csr_base, mem_op_value);
|
105
|
|
106
|
|
107
|
status = alt_epcq_poll_for_write_in_progress(epcq_flash_info);
|
108
|
if(status != 0)
|
109
|
{
|
110
|
return status;
|
111
|
}
|
112
|
|
113
|
status = IORD_ALTERA_EPCQ_CONTROLLER2_STATUS(epcq_flash_info->csr_base);
|
114
|
result |= (status >> 2) & 0x07;
|
115
|
result |= (status >> 3) & 0x08;
|
116
|
result |= (status >> 1) & 0x10;
|
117
|
|
118
|
if(result != sectors_to_lock)
|
119
|
{
|
120
|
|
121
|
}
|
122
|
|
123
|
return 0;
|
124
|
}
|
125
|
|
126
|
|
127
|
* alt_epcq_controller2_get_info
|
128
|
*
|
129
|
* Pass the table of erase blocks to the user. This flash will return a single
|
130
|
* flash_region that gives the number and size of sectors for the device used.
|
131
|
*
|
132
|
* Arguments:
|
133
|
* - *fd: Pointer to general flash device structure.
|
134
|
* - **info: Pointer to flash region
|
135
|
* - *number_of_regions: Pointer to number of regions
|
136
|
*
|
137
|
* For details of setting sectors protection, please refer to EPCQ datasheet.
|
138
|
*
|
139
|
* Returns:
|
140
|
* 0 -> success
|
141
|
* -EINVAL -> Invalid arguments
|
142
|
* -EIO -> Could be hardware problem.
|
143
|
**/
|
144
|
int alt_epcq_controller2_get_info
|
145
|
(
|
146
|
alt_flash_fd *fd,
|
147
|
flash_region **info,
|
148
|
int *number_of_regions
|
149
|
)
|
150
|
{
|
151
|
alt_flash_dev* flash = NULL;
|
152
|
|
153
|
|
154
|
if(NULL == fd || NULL == info || NULL == number_of_regions)
|
155
|
{
|
156
|
return -EINVAL;
|
157
|
}
|
158
|
|
159
|
flash = (alt_flash_dev*)fd;
|
160
|
|
161
|
*number_of_regions = flash->number_of_regions;
|
162
|
|
163
|
if (!flash->number_of_regions)
|
164
|
{
|
165
|
return -EIO;
|
166
|
}
|
167
|
else
|
168
|
{
|
169
|
*info = &flash->region_info[0];
|
170
|
}
|
171
|
|
172
|
return 0;
|
173
|
}
|
174
|
|
175
|
|
176
|
* alt_epcq_controller2_erase_block
|
177
|
*
|
178
|
* This function erases a single flash sector.
|
179
|
*
|
180
|
* Arguments:
|
181
|
* - *flash_info: Pointer to EPCQ flash device structure.
|
182
|
* - block_offset: byte-addressed offset, from start of flash, of the sector to be erased
|
183
|
*
|
184
|
* Returns:
|
185
|
* 0 -> success
|
186
|
* -EINVAL -> Invalid arguments
|
187
|
* -EIO -> write failed, sector might be protected
|
188
|
**/
|
189
|
int alt_epcq_controller2_erase_block(alt_flash_dev *flash_info, int block_offset)
|
190
|
{
|
191
|
alt_32 ret_code = 0;
|
192
|
alt_u32 mem_op_value = 0;
|
193
|
alt_epcq_controller2_dev* epcq_flash_info = NULL;
|
194
|
alt_u32 sector_number = 0;
|
195
|
|
196
|
|
197
|
if(NULL == flash_info)
|
198
|
{
|
199
|
return -EINVAL;
|
200
|
}
|
201
|
|
202
|
epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
|
203
|
|
204
|
|
205
|
* Sanity checks that block_offset is within the flash memory span and that the
|
206
|
* block offset is sector aligned.
|
207
|
*
|
208
|
*/
|
209
|
if((block_offset < 0)
|
210
|
|| (block_offset >= epcq_flash_info->size_in_bytes)
|
211
|
|| (block_offset & (epcq_flash_info->sector_size - 1)) != 0)
|
212
|
{
|
213
|
return -EINVAL;
|
214
|
}
|
215
|
|
216
|
|
217
|
sector_number = (block_offset/(epcq_flash_info->sector_size));
|
218
|
|
219
|
|
220
|
mem_op_value = (sector_number << 8) & ALTERA_EPCQ_CONTROLLER2_MEM_OP_SECTOR_VALUE_MASK;
|
221
|
|
222
|
|
223
|
mem_op_value |= ALTERA_EPCQ_CONTROLLER2_MEM_OP_WRITE_ENABLE_CMD;
|
224
|
|
225
|
|
226
|
IOWR_ALTERA_EPCQ_CONTROLLER2_MEM_OP(epcq_flash_info->csr_base, mem_op_value);
|
227
|
|
228
|
|
229
|
mem_op_value = (sector_number << 8) & ALTERA_EPCQ_CONTROLLER2_MEM_OP_SECTOR_VALUE_MASK;
|
230
|
|
231
|
|
232
|
mem_op_value |= ALTERA_EPCQ_CONTROLLER2_MEM_OP_SECTOR_ERASE_CMD;
|
233
|
|
234
|
|
235
|
IOWR_ALTERA_EPCQ_CONTROLLER2_MEM_OP(epcq_flash_info->csr_base, mem_op_value);
|
236
|
|
237
|
|
238
|
if((IORD_ALTERA_EPCQ_CONTROLLER2_ISR(epcq_flash_info->csr_base) &
|
239
|
ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_ERASE_MASK) ==
|
240
|
ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_ERASE_ACTIVE)
|
241
|
{
|
242
|
|
243
|
|
244
|
IOWR_ALTERA_EPCQ_CONTROLLER2_ISR(epcq_flash_info->csr_base,
|
245
|
ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_ERASE_MASK );
|
246
|
return -EIO;
|
247
|
}
|
248
|
|
249
|
return ret_code;
|
250
|
}
|
251
|
|
252
|
|
253
|
* alt_epcq_controller2_write_block
|
254
|
*
|
255
|
* This function writes one block/sector of data to flash. The length of the write can NOT
|
256
|
* spill into the adjacent sector.
|
257
|
*
|
258
|
* It assumes that someone has already erased the appropriate sector(s).
|
259
|
*
|
260
|
* Arguments:
|
261
|
* - *flash_info: Pointer to EPCQ flash device structure.
|
262
|
* - block_offset: byte-addressed offset, from the start of flash, of the sector to written to
|
263
|
* - data-offset: Byte offset (unaligned access) of write into flash memory.
|
264
|
* For best performance, word(32 bits - aligned access) offset of write is recommended.
|
265
|
* - *src_addr: source buffer
|
266
|
* - length: size of writing
|
267
|
*
|
268
|
* Returns:
|
269
|
* 0 -> success
|
270
|
* -EINVAL -> Invalid arguments
|
271
|
* -EIO -> write failed, sector might be protected
|
272
|
**/
|
273
|
int alt_epcq_controller2_write_block
|
274
|
(
|
275
|
alt_flash_dev *flash_info,
|
276
|
int block_offset,
|
277
|
int data_offset,
|
278
|
const void *data,
|
279
|
int length
|
280
|
)
|
281
|
{
|
282
|
alt_u32 buffer_offset = 0;
|
283
|
alt_u32 remaining_length = length;
|
284
|
alt_u32 write_offset = data_offset;
|
285
|
|
286
|
alt_epcq_controller2_dev *epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
|
287
|
|
288
|
|
289
|
* Sanity checks that data offset is not larger then a sector, that block offset is
|
290
|
* sector aligned and within the valid flash memory range and a write doesn't spill into
|
291
|
* the adjacent flash sector.
|
292
|
*/
|
293
|
if(block_offset < 0
|
294
|
|| data_offset < 0
|
295
|
|| NULL == flash_info
|
296
|
|| NULL == data
|
297
|
|| data_offset >= epcq_flash_info->size_in_bytes
|
298
|
|| block_offset >= epcq_flash_info->size_in_bytes
|
299
|
|| length > (epcq_flash_info->sector_size - (data_offset - block_offset))
|
300
|
|| length < 0
|
301
|
|| (block_offset & (epcq_flash_info->sector_size - 1)) != 0)
|
302
|
{
|
303
|
return -EINVAL;
|
304
|
}
|
305
|
|
306
|
|
307
|
* Do writes one 32-bit word at a time.
|
308
|
* We need to make sure that we pad the first few bytes so they're word aligned if they are
|
309
|
* not already.
|
310
|
*/
|
311
|
while (remaining_length > 0)
|
312
|
{
|
313
|
alt_u32 word_to_write = 0xFFFFFFFF;
|
314
|
alt_u32 padding = 0;
|
315
|
alt_u32 bytes_to_copy = sizeof(alt_u32);
|
316
|
|
317
|
|
318
|
* we need to make sure the write is word aligned
|
319
|
* this should only be true at most 1 time
|
320
|
*/
|
321
|
if (0 != (write_offset & (sizeof(alt_u32) - 1)))
|
322
|
{
|
323
|
|
324
|
* data is not word aligned
|
325
|
* calculate padding bytes need to add before start of a data offset
|
326
|
*/
|
327
|
padding = write_offset & (sizeof(alt_u32) - 1);
|
328
|
|
329
|
|
330
|
bytes_to_copy -= padding;
|
331
|
|
332
|
if(bytes_to_copy > remaining_length)
|
333
|
{
|
334
|
bytes_to_copy = remaining_length;
|
335
|
}
|
336
|
|
337
|
write_offset = write_offset - padding;
|
338
|
if(0 != (write_offset & (sizeof(alt_u32) - 1)))
|
339
|
{
|
340
|
return -EINVAL;
|
341
|
}
|
342
|
}
|
343
|
else
|
344
|
{
|
345
|
if(bytes_to_copy > remaining_length)
|
346
|
{
|
347
|
bytes_to_copy = remaining_length;
|
348
|
}
|
349
|
}
|
350
|
|
351
|
|
352
|
memcpy((((void*)&word_to_write)) + padding, ((void*)data) + buffer_offset, bytes_to_copy);
|
353
|
|
354
|
|
355
|
buffer_offset += bytes_to_copy;
|
356
|
remaining_length -= bytes_to_copy;
|
357
|
|
358
|
|
359
|
IOWR_32DIRECT(epcq_flash_info->data_base, write_offset, word_to_write);
|
360
|
if (IORD_32DIRECT(epcq_flash_info->data_base, write_offset) != word_to_write)
|
361
|
{
|
362
|
IOWR_32DIRECT(epcq_flash_info->data_base, write_offset, word_to_write);
|
363
|
}
|
364
|
|
365
|
|
366
|
if((IORD_ALTERA_EPCQ_CONTROLLER2_ISR(epcq_flash_info->csr_base) &
|
367
|
ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_WRITE_MASK) ==
|
368
|
ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_WRITE_ACTIVE)
|
369
|
{
|
370
|
|
371
|
IOWR_ALTERA_EPCQ_CONTROLLER2_ISR(epcq_flash_info->csr_base,
|
372
|
ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_WRITE_MASK );
|
373
|
return -EIO;
|
374
|
}
|
375
|
|
376
|
|
377
|
write_offset = write_offset + sizeof(alt_u32);
|
378
|
}
|
379
|
|
380
|
return 0;
|
381
|
}
|
382
|
|
383
|
|
384
|
* alt_epcq_controller2_write
|
385
|
*
|
386
|
* Program the data into the flash at the selected address.
|
387
|
*
|
388
|
* The different between this function and alt_epcq_controller2_write_block function
|
389
|
* is that this function (alt_epcq_controller2_write) will automatically erase a block as needed
|
390
|
* Arguments:
|
391
|
* - *flash_info: Pointer to EPCQ flash device structure.
|
392
|
* - offset: Byte offset (unaligned access) of write to flash memory. For best performance,
|
393
|
* word(32 bits - aligned access) offset of write is recommended.
|
394
|
* - *src_addr: source buffer
|
395
|
* - length: size of writing
|
396
|
*
|
397
|
* Returns:
|
398
|
* 0 -> success
|
399
|
* -EINVAL -> Invalid arguments
|
400
|
* -EIO -> write failed, sector might be protected
|
401
|
*
|
402
|
**/
|
403
|
int alt_epcq_controller2_write(
|
404
|
alt_flash_dev *flash_info,
|
405
|
int offset,
|
406
|
const void *src_addr,
|
407
|
int length
|
408
|
)
|
409
|
{
|
410
|
alt_32 ret_code = 0;
|
411
|
|
412
|
alt_epcq_controller2_dev *epcq_flash_info = NULL;
|
413
|
|
414
|
alt_u32 write_offset = offset;
|
415
|
alt_u32 remaining_length = length;
|
416
|
alt_u32 buffer_offset = 0;
|
417
|
alt_u32 i = 0;
|
418
|
|
419
|
|
420
|
if(NULL == flash_info || NULL == src_addr)
|
421
|
{
|
422
|
return -EINVAL;
|
423
|
}
|
424
|
|
425
|
epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
|
426
|
|
427
|
|
428
|
ret_code = alt_epcq_validate_read_write_arguments(epcq_flash_info, offset, length);
|
429
|
|
430
|
if(0 != ret_code)
|
431
|
{
|
432
|
return ret_code;
|
433
|
}
|
434
|
|
435
|
|
436
|
* This loop erases and writes data one sector at a time. We check for write completion
|
437
|
* before starting the next sector.
|
438
|
*/
|
439
|
for(i = offset/epcq_flash_info->sector_size ; i < epcq_flash_info->number_of_sectors; i++)
|
440
|
{
|
441
|
alt_u32 block_offset = 0;
|
442
|
alt_u32 offset_within_current_sector = 0;
|
443
|
alt_u32 length_to_write = 0;
|
444
|
|
445
|
if(0 >= remaining_length)
|
446
|
{
|
447
|
break;
|
448
|
}
|
449
|
|
450
|
|
451
|
block_offset = write_offset & ~(epcq_flash_info->sector_size - 1);
|
452
|
|
453
|
|
454
|
if(block_offset != write_offset)
|
455
|
{
|
456
|
offset_within_current_sector = write_offset - block_offset;
|
457
|
}
|
458
|
|
459
|
|
460
|
ret_code = alt_epcq_controller2_erase_block(flash_info, block_offset);
|
461
|
|
462
|
if(0 != ret_code)
|
463
|
{
|
464
|
return ret_code;
|
465
|
}
|
466
|
|
467
|
|
468
|
length_to_write = MIN(epcq_flash_info->sector_size - offset_within_current_sector,
|
469
|
remaining_length);
|
470
|
|
471
|
|
472
|
ret_code = alt_epcq_controller2_write_block(flash_info, block_offset, write_offset,
|
473
|
src_addr + buffer_offset, length_to_write);
|
474
|
|
475
|
|
476
|
if(0 != ret_code)
|
477
|
{
|
478
|
return ret_code;
|
479
|
}
|
480
|
|
481
|
|
482
|
remaining_length -= length_to_write;
|
483
|
buffer_offset += length_to_write;
|
484
|
write_offset += length_to_write;
|
485
|
}
|
486
|
|
487
|
return ret_code;
|
488
|
}
|
489
|
|
490
|
|
491
|
* alt_epcq_controller2_read
|
492
|
*
|
493
|
* There's no real need to use this function as opposed to using memcpy directly. It does
|
494
|
* do some sanity checks on the bounds of the read.
|
495
|
*
|
496
|
* Arguments:
|
497
|
* - *flash_info: Pointer to general flash device structure.
|
498
|
* - offset: offset read from flash memory.
|
499
|
* - *dest_addr: destination buffer
|
500
|
* - length: size of reading
|
501
|
*
|
502
|
* Returns:
|
503
|
* 0 -> success
|
504
|
* -EINVAL -> Invalid arguments
|
505
|
**/
|
506
|
int alt_epcq_controller2_read
|
507
|
(
|
508
|
alt_flash_dev *flash_info,
|
509
|
int offset,
|
510
|
void *dest_addr,
|
511
|
int length
|
512
|
)
|
513
|
{
|
514
|
alt_32 ret_code = 0;
|
515
|
alt_epcq_controller2_dev *epcq_flash_info = NULL;
|
516
|
|
517
|
|
518
|
if(NULL == flash_info || NULL == dest_addr)
|
519
|
{
|
520
|
return -EINVAL;
|
521
|
}
|
522
|
|
523
|
epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
|
524
|
|
525
|
|
526
|
ret_code = alt_epcq_validate_read_write_arguments(epcq_flash_info, offset, length);
|
527
|
|
528
|
|
529
|
if(0 == ret_code)
|
530
|
{
|
531
|
memcpy(dest_addr, (alt_u8*)epcq_flash_info->data_base + offset, length);
|
532
|
}
|
533
|
|
534
|
return ret_code;
|
535
|
}
|
536
|
|
537
|
|
538
|
* altera_epcq_controller2_init
|
539
|
*
|
540
|
* alt_sys_init.c will call this function automatically through macro
|
541
|
*
|
542
|
* Information in system.h is checked against expected values that are determined by the silicon_id.
|
543
|
* If the information doesn't match then this system is configured incorrectly. Most likely the wrong
|
544
|
* type of EPCS or EPCQ device was selected when instantiating the soft IP.
|
545
|
*
|
546
|
* Arguments:
|
547
|
* - *flash: Pointer to EPCQ flash device structure.
|
548
|
*
|
549
|
* Returns:
|
550
|
* 0 -> success
|
551
|
* -EINVAL -> Invalid arguments.
|
552
|
* -ENODEV -> System is configured incorrectly.
|
553
|
**/
|
554
|
alt_32 altera_epcq_controller2_init(alt_epcq_controller2_dev *flash)
|
555
|
{
|
556
|
alt_u32 silicon_id = 0;
|
557
|
alt_u32 size_in_bytes = 0;
|
558
|
alt_u32 number_of_sectors = 0;
|
559
|
|
560
|
|
561
|
if(NULL == flash)
|
562
|
{
|
563
|
return -EINVAL;
|
564
|
}
|
565
|
|
566
|
|
567
|
if(NULL == (void *)flash->csr_base)
|
568
|
{
|
569
|
return -ENODEV;
|
570
|
}
|
571
|
|
572
|
|
573
|
|
574
|
* If flash is an EPCQ device, we read the EPCQ_RD_RDID register for the ID
|
575
|
* If flash is an EPCS device, we read the EPCQ_RD_SID register for the ID
|
576
|
*
|
577
|
* Whether or not the flash is a EPCQ or EPCS is indicated in the system.h. The system.h gets
|
578
|
* this value from the hw.tcl of the IP. If this value is set incorrectly, then things will go
|
579
|
* badly.
|
580
|
*
|
581
|
* In both cases, we can determine the number of sectors, which we can use
|
582
|
* to calculate a size. We compare that size to the system.h value to make sure
|
583
|
* the EPCQ soft IP was configured correctly.
|
584
|
*/
|
585
|
if(0 == flash->is_epcs)
|
586
|
{
|
587
|
|
588
|
silicon_id = IORD_ALTERA_EPCQ_CONTROLLER2_RDID(flash->csr_base);
|
589
|
silicon_id &= ALTERA_EPCQ_CONTROLLER2_RDID_MASK;
|
590
|
|
591
|
|
592
|
|
593
|
switch(silicon_id)
|
594
|
{
|
595
|
case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ16:
|
596
|
{
|
597
|
number_of_sectors = 32;
|
598
|
break;
|
599
|
}
|
600
|
case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ32:
|
601
|
{
|
602
|
number_of_sectors = 64;
|
603
|
break;
|
604
|
}
|
605
|
case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ64:
|
606
|
{
|
607
|
number_of_sectors = 128;
|
608
|
break;
|
609
|
}
|
610
|
case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ128:
|
611
|
{
|
612
|
number_of_sectors = 256;
|
613
|
break;
|
614
|
}
|
615
|
case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ256:
|
616
|
{
|
617
|
number_of_sectors = 512;
|
618
|
break;
|
619
|
}
|
620
|
case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ512:
|
621
|
{
|
622
|
number_of_sectors = 1024;
|
623
|
break;
|
624
|
}
|
625
|
case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ1024:
|
626
|
{
|
627
|
number_of_sectors = 2048;
|
628
|
break;
|
629
|
}
|
630
|
default:
|
631
|
{
|
632
|
return -ENODEV;
|
633
|
}
|
634
|
}
|
635
|
}
|
636
|
else {
|
637
|
|
638
|
silicon_id = IORD_ALTERA_EPCQ_CONTROLLER2_SID(flash->csr_base);
|
639
|
silicon_id &= ALTERA_EPCQ_CONTROLLER2_SID_MASK;
|
640
|
|
641
|
|
642
|
switch(silicon_id)
|
643
|
{
|
644
|
case ALTERA_EPCQ_CONTROLLER2_SID_EPCS16:
|
645
|
{
|
646
|
number_of_sectors = 32;
|
647
|
break;
|
648
|
}
|
649
|
case ALTERA_EPCQ_CONTROLLER2_SID_EPCS64:
|
650
|
{
|
651
|
number_of_sectors = 128;
|
652
|
break;
|
653
|
}
|
654
|
case ALTERA_EPCQ_CONTROLLER2_SID_EPCS128:
|
655
|
{
|
656
|
number_of_sectors = 256;
|
657
|
break;
|
658
|
}
|
659
|
default:
|
660
|
{
|
661
|
return -ENODEV;
|
662
|
}
|
663
|
}
|
664
|
}
|
665
|
|
666
|
|
667
|
size_in_bytes = number_of_sectors * flash->sector_size;
|
668
|
|
669
|
|
670
|
* Make sure calculated size is the same size given in system.h
|
671
|
* Also check number of sectors is the same number given in system.h
|
672
|
* Otherwise the EPCQ IP was not configured correctly
|
673
|
*/
|
674
|
if( size_in_bytes != flash->size_in_bytes ||
|
675
|
number_of_sectors != flash->number_of_sectors)
|
676
|
{
|
677
|
flash->dev.number_of_regions = 0;
|
678
|
return -ENODEV;
|
679
|
}
|
680
|
else
|
681
|
{
|
682
|
flash->silicon_id = silicon_id;
|
683
|
flash->number_of_sectors = number_of_sectors;
|
684
|
|
685
|
|
686
|
* populate fields of region_info required to conform to HAL API
|
687
|
* create 1 region that composed of "number_of_sectors" blocks
|
688
|
*/
|
689
|
flash->dev.number_of_regions = 1;
|
690
|
flash->dev.region_info[0].offset = 0;
|
691
|
flash->dev.region_info[0].region_size = size_in_bytes;
|
692
|
flash->dev.region_info[0].number_of_blocks = number_of_sectors;
|
693
|
flash->dev.region_info[0].block_size = flash->sector_size;
|
694
|
}
|
695
|
|
696
|
|
697
|
|
698
|
* Register this device as a valid flash device type
|
699
|
*
|
700
|
* Only register the device if it's configured correctly.
|
701
|
*/
|
702
|
alt_flash_device_register(&(flash->dev));
|
703
|
|
704
|
|
705
|
return 0;
|
706
|
}
|
707
|
|
708
|
|
709
|
|
710
|
* Private API
|
711
|
*
|
712
|
* Helper functions used by Public API functions.
|
713
|
*
|
714
|
* Arguments:
|
715
|
* - *flash_info: Pointer to EPCQ flash device structure.
|
716
|
* - offset: Offset of read/write from base address.
|
717
|
* - length: Length of read/write in bytes.
|
718
|
*
|
719
|
* Returns:
|
720
|
* 0 -> success
|
721
|
* -EINVAL -> Invalid arguments
|
722
|
*/
|
723
|
|
724
|
* Used to check that arguments to a read or write are valid
|
725
|
*/
|
726
|
ALT_INLINE alt_32 static alt_epcq_validate_read_write_arguments
|
727
|
(
|
728
|
alt_epcq_controller2_dev *flash_info,
|
729
|
alt_u32 offset,
|
730
|
alt_u32 length
|
731
|
)
|
732
|
{
|
733
|
alt_epcq_controller2_dev *epcq_flash_info = NULL;
|
734
|
alt_u32 start_address = 0;
|
735
|
alt_32 end_address = 0;
|
736
|
|
737
|
|
738
|
if(NULL == flash_info)
|
739
|
{
|
740
|
return -EINVAL;
|
741
|
}
|
742
|
|
743
|
epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
|
744
|
|
745
|
start_address = epcq_flash_info->data_base + offset;
|
746
|
end_address = start_address + length;
|
747
|
|
748
|
|
749
|
if(
|
750
|
start_address >= epcq_flash_info->data_end ||
|
751
|
end_address > epcq_flash_info->data_end ||
|
752
|
offset < 0 ||
|
753
|
length < 0
|
754
|
)
|
755
|
{
|
756
|
return -EINVAL;
|
757
|
}
|
758
|
|
759
|
return 0;
|
760
|
}
|
761
|
|
762
|
|
763
|
* Private function that polls write in progress bit EPCQ_RD_STATUS.
|
764
|
*
|
765
|
* Write in progress will be set if any of the following operations are in progress:
|
766
|
* -WRITE STATUS REGISTER
|
767
|
* -WRITE NONVOLATILE CONFIGURATION REGISTER
|
768
|
* -PROGRAM
|
769
|
* -ERASE
|
770
|
*
|
771
|
* Assumes EPCQ was configured correctly.
|
772
|
*
|
773
|
* If ALTERA_EPCQ_CONTROLLER2_1US_TIMEOUT_VALUE is set, the function will time out after
|
774
|
* a period of time determined by that value.
|
775
|
*
|
776
|
* Arguments:
|
777
|
* - *epcq_flash_info: Pointer to EPCQ flash device structure.
|
778
|
*
|
779
|
* Returns:
|
780
|
* 0 -> success
|
781
|
* -EINVAL -> Invalid arguments
|
782
|
* -ETIME -> Time out and skipping the looping after 0.7 sec.
|
783
|
*/
|
784
|
alt_32 static alt_epcq_poll_for_write_in_progress(alt_epcq_controller2_dev* epcq_flash_info)
|
785
|
{
|
786
|
|
787
|
#if ALTERA_EPCQ_CONTROLLER2_1US_TIMEOUT_VALUE > 0
|
788
|
alt_u32 timeout = ALTERA_EPCQ_CONTROLLER2_1US_TIMEOUT_VALUE;
|
789
|
alt_u16 counter = 0;
|
790
|
#endif
|
791
|
|
792
|
|
793
|
if(NULL == epcq_flash_info)
|
794
|
{
|
795
|
return -EINVAL;
|
796
|
}
|
797
|
|
798
|
|
799
|
while((IORD_ALTERA_EPCQ_CONTROLLER2_STATUS(epcq_flash_info->csr_base) &
|
800
|
ALTERA_EPCQ_CONTROLLER2_STATUS_WIP_MASK) ==
|
801
|
ALTERA_EPCQ_CONTROLLER2_STATUS_WIP_BUSY)
|
802
|
{
|
803
|
alt_busy_sleep(1);
|
804
|
#if ALTERA_EPCQ_CONTROLLER2_1US_TIMEOUT_VALUE > 0
|
805
|
if(timeout <= counter )
|
806
|
{
|
807
|
return -ETIME;
|
808
|
}
|
809
|
|
810
|
counter++;
|
811
|
#endif
|
812
|
|
813
|
}
|
814
|
|
815
|
return 0;
|
816
|
}
|
817
|
|
818
|
|