1
2
3
14
15
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
43
45
46
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
85
86
87
91
92
95
112
113
116
117
118
119
120
121
122
123
124
125
126
127
131
135
136
137
138
139
140
141
142
143
144
145
146
147
148
152
153
154
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
207
208
209
210
211
215
216
217
230
231
232
240
241
242
243
244
245
246
247
251
255
256
257
258
259
260
261
262
263
264
265
266
270
271
275
276
277
278
279
280
281
282
283
286
287
288
289
290
293
294
299
300
301
302
303
304
305
306
307
308
313
314
315
316
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
336
337
338
339
340
341
342
343
346
347
348
349
350
351
358
361
362
363
364
367
368
369
370
371
374
375
376
396
397
398
399
400
401
402
403
404
405
408
409
410
411
412
413
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
434
435
436
437
438
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
464
468
472
473
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
513
514
515
516
517
521
522
523
524
525
526
527
528
529
530
531
534
535
536
537
538
539
546
547
548
549
550
551
554
555
556
557
558
559
560
564
565
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
591
595
596
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
671
672
673
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
704
705
706
707
708
712
713
717
718
726
727
728
731
732
733
737
738
741
745
746
747
748
749
750
751
752
753
754
755
756
759
760
763
764
765
766
767
768
769
770
771
772
773
774
777
778
779
780
800
801
802
803
804
805
806
807
808
809
820
821
822
823
831
832
833
834
835
836
837
841
842
849
850
851
852
853
854
855
856
857
858
859
867
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
898
899
900
901
902
903
904
905
906
907
908
911
912
913
914
915
916
917
920
921
922
923
924
925
926
927
928
929
930
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
/* ... */
/* ... */
/* ... */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include "mxc.h"
#include <target/target.h>
#define OOB_SIZE 64
#define nfc_is_v1() (mxc_nf_info->mxc_version == MXC_VERSION_MX27 || \
mxc_nf_info->mxc_version == MXC_VERSION_MX31)...
#define nfc_is_v2() (mxc_nf_info->mxc_version == MXC_VERSION_MX25 || \
mxc_nf_info->mxc_version == MXC_VERSION_MX35)...
/* ... */
#undef _MXC_PRINT_STAT
static const char target_not_halted_err_msg[] =
"target must be halted to use mxc NAND flash controller";
static const char data_block_size_err_msg[] =
"minimal granularity is one half-word, %" PRIu32 " is incorrect";
static const char sram_buffer_bounds_err_msg[] =
"trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")";
static const char get_status_register_err_msg[] = "can't get NAND status";
static uint32_t in_sram_address;
static unsigned char sign_of_sequental_byte_read;
static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr);
static int initialize_nf_controller(struct nand_device *nand);
static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value);
static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value);
static int poll_for_complete_op(struct nand_device *nand, const char *text);
static int validate_target_state(struct nand_device *nand);
static int do_data_output(struct nand_device *nand);
static int mxc_command(struct nand_device *nand, uint8_t command);
static int mxc_address(struct nand_device *nand, uint8_t address);
NAND_DEVICE_COMMAND_HANDLER(mxc_nand_device_command)
{
struct mxc_nf_controller *mxc_nf_info;
int hwecc_needed;
mxc_nf_info = malloc(sizeof(struct mxc_nf_controller));
if (!mxc_nf_info) {
LOG_ERROR("no memory for nand controller");
return ERROR_FAIL;
}if (!mxc_nf_info) { ... }
nand->controller_priv = mxc_nf_info;
if (CMD_ARGC < 4) {
LOG_ERROR("use \"nand device mxc target mx25|mx27|mx31|mx35 noecc|hwecc [biswap]\"");
return ERROR_FAIL;
}if (CMD_ARGC < 4) { ... }
/* ... */
if (strcmp(CMD_ARGV[2], "mx25") == 0) {
mxc_nf_info->mxc_version = MXC_VERSION_MX25;
mxc_nf_info->mxc_base_addr = 0xBB000000;
mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00;
}if (strcmp(CMD_ARGV[2], "mx25") == 0) { ... } else if (strcmp(CMD_ARGV[2], "mx27") == 0) {
mxc_nf_info->mxc_version = MXC_VERSION_MX27;
mxc_nf_info->mxc_base_addr = 0xD8000000;
mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00;
}else if (strcmp(CMD_ARGV[2], "mx27") == 0) { ... } else if (strcmp(CMD_ARGV[2], "mx31") == 0) {
mxc_nf_info->mxc_version = MXC_VERSION_MX31;
mxc_nf_info->mxc_base_addr = 0xB8000000;
mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00;
}else if (strcmp(CMD_ARGV[2], "mx31") == 0) { ... } else if (strcmp(CMD_ARGV[2], "mx35") == 0) {
mxc_nf_info->mxc_version = MXC_VERSION_MX35;
mxc_nf_info->mxc_base_addr = 0xBB000000;
mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00;
}else if (strcmp(CMD_ARGV[2], "mx35") == 0) { ... }
/* ... */
hwecc_needed = strcmp(CMD_ARGV[3], "hwecc");
if (hwecc_needed == 0)
mxc_nf_info->flags.hw_ecc_enabled = 1;
else
mxc_nf_info->flags.hw_ecc_enabled = 0;
mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE;
mxc_nf_info->fin = MXC_NF_FIN_NONE;
mxc_nf_info->flags.target_little_endian =
(nand->target->endianness == TARGET_LITTLE_ENDIAN);
/* ... */
if (CMD_ARGC > 4 && strcmp(CMD_ARGV[4], "biswap") == 0) {
LOG_DEBUG("BI-swap enabled");
mxc_nf_info->flags.biswap_enabled = 1;
}if (CMD_ARGC > 4 && strcmp(CMD_ARGV[4], "biswap") == 0) { ... }
return ERROR_OK;
}{ ... }
COMMAND_HANDLER(handle_mxc_biswap_command)
{
struct nand_device *nand = NULL;
struct mxc_nf_controller *mxc_nf_info = NULL;
if (CMD_ARGC < 1 || CMD_ARGC > 2)
return ERROR_COMMAND_SYNTAX_ERROR;
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand);
if (retval != ERROR_OK) {
command_print(CMD, "invalid nand device number or name: %s", CMD_ARGV[0]);
return ERROR_COMMAND_ARGUMENT_INVALID;
}if (retval != ERROR_OK) { ... }
mxc_nf_info = nand->controller_priv;
if (CMD_ARGC == 2) {
if (strcmp(CMD_ARGV[1], "enable") == 0)
mxc_nf_info->flags.biswap_enabled = true;
else
mxc_nf_info->flags.biswap_enabled = false;
}if (CMD_ARGC == 2) { ... }
if (mxc_nf_info->flags.biswap_enabled)
command_print(CMD, "BI-swapping enabled on %s", nand->name);
else
command_print(CMD, "BI-swapping disabled on %s", nand->name);
return ERROR_OK;
}{ ... }
static const struct command_registration mxc_sub_command_handlers[] = {
{
.name = "biswap",
.mode = COMMAND_EXEC,
.handler = handle_mxc_biswap_command,
.help = "Turns on/off bad block information swapping from main area, "
"without parameter query status.",
.usage = "bank_id ['enable'|'disable']",
...},
COMMAND_REGISTRATION_DONE
...};
static const struct command_registration mxc_nand_command_handler[] = {
{
.name = "mxc",
.mode = COMMAND_ANY,
.help = "MXC NAND flash controller commands",
.chain = mxc_sub_command_handlers,
.usage = "",
...},
COMMAND_REGISTRATION_DONE
...};
static int mxc_init(struct nand_device *nand)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
int validate_target_result;
uint16_t buffsize_register_content;
uint32_t sreg_content;
uint32_t sreg = MX2_FMCR;
uint32_t sel_16bit = MX2_FMCR_NF_16BIT_SEL;
uint32_t sel_fms = MX2_FMCR_NF_FMS;
int retval;
uint16_t nand_status_content;
/* ... */
validate_target_result = validate_target_state(nand);
if (validate_target_result != ERROR_OK)
return validate_target_result;
if (nfc_is_v1()) {
target_read_u16(target, MXC_NF_BUFSIZ, &buffsize_register_content);
mxc_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f);
}if (nfc_is_v1()) { ... } else
mxc_nf_info->flags.one_kb_sram = 0;
if (mxc_nf_info->mxc_version == MXC_VERSION_MX31) {
sreg = MX3_PCSR;
sel_16bit = MX3_PCSR_NF_16BIT_SEL;
sel_fms = MX3_PCSR_NF_FMS;
}if (mxc_nf_info->mxc_version == MXC_VERSION_MX31) { ... } else if (mxc_nf_info->mxc_version == MXC_VERSION_MX25) {
sreg = MX25_RCSR;
sel_16bit = MX25_RCSR_NF_16BIT_SEL;
sel_fms = MX25_RCSR_NF_FMS;
}else if (mxc_nf_info->mxc_version == MXC_VERSION_MX25) { ... } else if (mxc_nf_info->mxc_version == MXC_VERSION_MX35) {
sreg = MX35_RCSR;
sel_16bit = MX35_RCSR_NF_16BIT_SEL;
sel_fms = MX35_RCSR_NF_FMS;
}else if (mxc_nf_info->mxc_version == MXC_VERSION_MX35) { ... }
target_read_u32(target, sreg, &sreg_content);
if (!nand->bus_width) {
nand->bus_width = (sreg_content & sel_16bit) ? 16 : 8;
}if (!nand->bus_width) { ... } else {
sreg_content |= ((nand->bus_width == 16) ? sel_16bit : 0x00000000);
target_write_u32(target, sreg, sreg_content);
}else { ... }
if (nand->bus_width == 16)
LOG_DEBUG("MXC_NF : bus is 16-bit width");
else
LOG_DEBUG("MXC_NF : bus is 8-bit width");
if (!nand->page_size)
nand->page_size = (sreg_content & sel_fms) ? 2048 : 512;
else {
sreg_content |= ((nand->page_size == 2048) ? sel_fms : 0x00000000);
target_write_u32(target, sreg, sreg_content);
}else { ... }
if (mxc_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) {
LOG_ERROR("NAND controller have only 1 kb SRAM, so "
"pagesize 2048 is incompatible with it");
}if (mxc_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) { ... } else
LOG_DEBUG("MXC_NF : NAND controller can handle pagesize of 2048");
if (nfc_is_v2() && sreg_content & MX35_RCSR_NF_4K)
LOG_ERROR("MXC driver does not have support for 4k pagesize.");
initialize_nf_controller(nand);
retval = ERROR_OK;
retval |= mxc_command(nand, NAND_CMD_STATUS);
retval |= mxc_address(nand, 0x00);
retval |= do_data_output(nand);
if (retval != ERROR_OK) {
LOG_ERROR(get_status_register_err_msg);
return ERROR_FAIL;
}if (retval != ERROR_OK) { ... }
target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content);
if (!(nand_status_content & 0x0080)) {
LOG_INFO("NAND read-only");
mxc_nf_info->flags.nand_readonly = 1;
}if (!(nand_status_content & 0x0080)) { ... } else
mxc_nf_info->flags.nand_readonly = 0;
return ERROR_OK;
}{ ... }
static int mxc_read_data(struct nand_device *nand, void *data)
{
int validate_target_result;
int try_data_output_from_nand_chip;
/* ... */
validate_target_result = validate_target_state(nand);
if (validate_target_result != ERROR_OK)
return validate_target_result;
/* ... */
try_data_output_from_nand_chip = do_data_output(nand);
if (try_data_output_from_nand_chip != ERROR_OK) {
LOG_ERROR("mxc_read_data : read data failed : '%x'",
try_data_output_from_nand_chip);
return try_data_output_from_nand_chip;
}if (try_data_output_from_nand_chip != ERROR_OK) { ... }
if (nand->bus_width == 16)
get_next_halfword_from_sram_buffer(nand, data);
else
get_next_byte_from_sram_buffer(nand, data);
return ERROR_OK;
}{ ... }
static int mxc_write_data(struct nand_device *nand, uint16_t data)
{
LOG_ERROR("write_data() not implemented");
return ERROR_NAND_OPERATION_FAILED;
}{ ... }
static int mxc_reset(struct nand_device *nand)
{
/* ... */
int validate_target_result;
validate_target_result = validate_target_state(nand);
if (validate_target_result != ERROR_OK)
return validate_target_result;
initialize_nf_controller(nand);
return ERROR_OK;
}{ ... }
static int mxc_command(struct nand_device *nand, uint8_t command)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
int validate_target_result;
int poll_result;
/* ... */
validate_target_result = validate_target_state(nand);
if (validate_target_result != ERROR_OK)
return validate_target_result;
switch (command) {
case NAND_CMD_READOOB:
command = NAND_CMD_READ0;
/* ... */
if (nfc_is_v1())
in_sram_address = MXC_NF_V1_SPARE_BUFFER0;
else
in_sram_address = MXC_NF_V2_SPARE_BUFFER0;
break;case NAND_CMD_READOOB:
case NAND_CMD_READ1:
command = NAND_CMD_READ0;
/* ... */
in_sram_address = MXC_NF_MAIN_BUFFER0 + (nand->page_size >> 1);
break;case NAND_CMD_READ1:
default:
in_sram_address = MXC_NF_MAIN_BUFFER0;
break;default
}switch (command) { ... }
target_write_u16(target, MXC_NF_FCMD, command);
/* ... */
target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FCI);
poll_result = poll_for_complete_op(nand, "command");
if (poll_result != ERROR_OK)
return poll_result;
/* ... */
sign_of_sequental_byte_read = 0;
switch (command) {
case NAND_CMD_READID:
mxc_nf_info->optype = MXC_NF_DATAOUT_NANDID;
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
break;case NAND_CMD_READID:
case NAND_CMD_STATUS:
mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS;
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
target_write_u16 (target, MXC_NF_BUFADDR, 0);
in_sram_address = 0;
break;case NAND_CMD_STATUS:
case NAND_CMD_READ0:
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE;
break;case NAND_CMD_READ0:
default:
mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE;
break;default
}switch (command) { ... }
return ERROR_OK;
}{ ... }
static int mxc_address(struct nand_device *nand, uint8_t address)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
int validate_target_result;
int poll_result;
/* ... */
validate_target_result = validate_target_state(nand);
if (validate_target_result != ERROR_OK)
return validate_target_result;
target_write_u16(target, MXC_NF_FADDR, address);
/* ... */
target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FAI);
poll_result = poll_for_complete_op(nand, "address");
if (poll_result != ERROR_OK)
return poll_result;
return ERROR_OK;
}{ ... }
static int mxc_nand_ready(struct nand_device *nand, int tout)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
uint16_t poll_complete_status;
int validate_target_result;
/* ... */
validate_target_result = validate_target_state(nand);
if (validate_target_result != ERROR_OK)
return validate_target_result;
do {
target_read_u16(target, MXC_NF_CFG2, &poll_complete_status);
if (poll_complete_status & MXC_NF_BIT_OP_DONE)
return tout;
alive_sleep(1);
...} while (tout-- > 0);
return tout;
}{ ... }
static int mxc_write_page(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size,
uint8_t *oob, uint32_t oob_size)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
int retval;
uint16_t nand_status_content;
uint16_t swap1, swap2, new_swap1;
uint8_t bufs;
int poll_result;
if (data_size % 2) {
LOG_ERROR(data_block_size_err_msg, data_size);
return ERROR_NAND_OPERATION_FAILED;
}if (data_size % 2) { ... }
if (oob_size % 2) {
LOG_ERROR(data_block_size_err_msg, oob_size);
return ERROR_NAND_OPERATION_FAILED;
}if (oob_size % 2) { ... }
if (!data) {
LOG_ERROR("nothing to program");
return ERROR_NAND_OPERATION_FAILED;
}if (!data) { ... }
/* ... */
retval = validate_target_state(nand);
if (retval != ERROR_OK)
return retval;
in_sram_address = MXC_NF_MAIN_BUFFER0;
sign_of_sequental_byte_read = 0;
retval = ERROR_OK;
retval |= mxc_command(nand, NAND_CMD_SEQIN);
retval |= mxc_address(nand, 0);
retval |= mxc_address(nand, 0);
retval |= mxc_address(nand, page & 0xff);
retval |= mxc_address(nand, (page >> 8) & 0xff);
retval |= mxc_address(nand, (page >> 16) & 0xff);
target_write_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data);
if (oob) {
if (mxc_nf_info->flags.hw_ecc_enabled) {
/* ... */
LOG_DEBUG("part of spare block will be overridden "
"by hardware ECC generator");
}if (mxc_nf_info->flags.hw_ecc_enabled) { ... }
if (nfc_is_v1())
target_write_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob);
else {
uint32_t addr = MXC_NF_V2_SPARE_BUFFER0;
while (oob_size > 0) {
uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN);
target_write_buffer(target, addr, len, oob);
addr = align_address_v2(nand, addr + len);
oob += len;
oob_size -= len;
}while (oob_size > 0) { ... }
}else { ... }
}if (oob) { ... }
if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) {
target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1);
if (oob) {
LOG_ERROR("Due to NFC Bug, oob is not correctly implemented in mxc driver");
return ERROR_NAND_OPERATION_FAILED;
}if (oob) { ... }
swap2 = 0xffff;
new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
swap2 = (swap1 << 8) | (swap2 & 0xFF);
target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1);
if (nfc_is_v1())
target_write_u16(target, MXC_NF_V1_SPARE_BUFFER3 + 4, swap2);
else
target_write_u16(target, MXC_NF_V2_SPARE_BUFFER3, swap2);
}if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) { ... }
/* ... */
if (nfc_is_v1() && nand->page_size > 512)
bufs = 4;
else
bufs = 1;
for (uint8_t i = 0; i < bufs; ++i) {
target_write_u16(target, MXC_NF_BUFADDR, i);
target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI);
poll_result = poll_for_complete_op(nand, "data input");
if (poll_result != ERROR_OK)
return poll_result;
}for (uint8_t i = 0; i < bufs; ++i) { ... }
retval |= mxc_command(nand, NAND_CMD_PAGEPROG);
if (retval != ERROR_OK)
return retval;
/* ... */
retval = ERROR_OK;
retval |= mxc_command(nand, NAND_CMD_STATUS);
target_write_u16 (target, MXC_NF_BUFADDR, 0);
mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS;
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
retval |= do_data_output(nand);
if (retval != ERROR_OK) {
LOG_ERROR(get_status_register_err_msg);
return retval;
}if (retval != ERROR_OK) { ... }
target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content);
if (nand_status_content & 0x0001) {
/* ... */
return ERROR_NAND_OPERATION_FAILED;
}if (nand_status_content & 0x0001) { ... }
#ifdef _MXC_PRINT_STAT
LOG_INFO("%d bytes newly written", data_size);
#endif
return ERROR_OK;
}{ ... }
static int mxc_read_page(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size,
uint8_t *oob, uint32_t oob_size)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
int retval;
uint8_t bufs;
uint16_t swap1, swap2, new_swap1;
if (data_size % 2) {
LOG_ERROR(data_block_size_err_msg, data_size);
return ERROR_NAND_OPERATION_FAILED;
}if (data_size % 2) { ... }
if (oob_size % 2) {
LOG_ERROR(data_block_size_err_msg, oob_size);
return ERROR_NAND_OPERATION_FAILED;
}if (oob_size % 2) { ... }
/* ... */
retval = validate_target_state(nand);
if (retval != ERROR_OK)
return retval;
retval = mxc_command(nand, NAND_CMD_READ0);
if (retval != ERROR_OK)
return retval;
retval = mxc_address(nand, 0);
if (retval != ERROR_OK)
return retval;
retval = mxc_address(nand, 0);
if (retval != ERROR_OK)
return retval;
retval = mxc_address(nand, page & 0xff);
if (retval != ERROR_OK)
return retval;
retval = mxc_address(nand, (page >> 8) & 0xff);
if (retval != ERROR_OK)
return retval;
retval = mxc_address(nand, (page >> 16) & 0xff);
if (retval != ERROR_OK)
return retval;
retval = mxc_command(nand, NAND_CMD_READSTART);
if (retval != ERROR_OK)
return retval;
if (nfc_is_v1() && nand->page_size > 512)
bufs = 4;
else
bufs = 1;
for (uint8_t i = 0; i < bufs; ++i) {
target_write_u16(target, MXC_NF_BUFADDR, i);
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
retval = do_data_output(nand);
if (retval != ERROR_OK) {
LOG_ERROR("MXC_NF : Error reading page %d", i);
return retval;
}if (retval != ERROR_OK) { ... }
}for (uint8_t i = 0; i < bufs; ++i) { ... }
if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) {
uint32_t spare_buffer3;
target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1);
if (nfc_is_v1())
spare_buffer3 = MXC_NF_V1_SPARE_BUFFER3 + 4;
else
spare_buffer3 = MXC_NF_V2_SPARE_BUFFER3;
target_read_u16(target, spare_buffer3, &swap2);
new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
swap2 = (swap1 << 8) | (swap2 & 0xFF);
target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1);
target_write_u16(target, spare_buffer3, swap2);
}if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) { ... }
if (data)
target_read_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data);
if (oob) {
if (nfc_is_v1())
target_read_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob);
else {
uint32_t addr = MXC_NF_V2_SPARE_BUFFER0;
while (oob_size > 0) {
uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN);
target_read_buffer(target, addr, len, oob);
addr = align_address_v2(nand, addr + len);
oob += len;
oob_size -= len;
}while (oob_size > 0) { ... }
}else { ... }
}if (oob) { ... }
#ifdef _MXC_PRINT_STAT
if (data_size > 0) {
/* ... */
LOG_INFO("%d bytes newly read", data_size);
}if (data_size > 0) { ... }
/* ... */#endif
return ERROR_OK;
}{ ... }
static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
uint32_t ret = addr;
if (addr > MXC_NF_V2_SPARE_BUFFER0 &&
(addr & 0x1F) == MXC_NF_SPARE_BUFFER_LEN)
ret += MXC_NF_SPARE_BUFFER_MAX - MXC_NF_SPARE_BUFFER_LEN;
else if (addr >= (mxc_nf_info->mxc_base_addr + (uint32_t)nand->page_size))
ret = MXC_NF_V2_SPARE_BUFFER0;
return ret;
}{ ... }
static int initialize_nf_controller(struct nand_device *nand)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
uint16_t work_mode = 0;
uint16_t temp;
/* ... */
target_write_u16(target, MXC_NF_CFG1, MXC_NF_BIT_RESET_EN);
if (mxc_nf_info->mxc_version == MXC_VERSION_MX27)
work_mode = MXC_NF_BIT_INT_DIS;
if (target->endianness == TARGET_BIG_ENDIAN) {
LOG_DEBUG("MXC_NF : work in Big Endian mode");
work_mode |= MXC_NF_BIT_BE_EN;
}if (target->endianness == TARGET_BIG_ENDIAN) { ... } else
LOG_DEBUG("MXC_NF : work in Little Endian mode");
if (mxc_nf_info->flags.hw_ecc_enabled) {
LOG_DEBUG("MXC_NF : work with ECC mode");
work_mode |= MXC_NF_BIT_ECC_EN;
}if (mxc_nf_info->flags.hw_ecc_enabled) { ... } else
LOG_DEBUG("MXC_NF : work without ECC mode");
if (nfc_is_v2()) {
target_write_u16(target, MXC_NF_V2_SPAS, OOB_SIZE / 2);
if (nand->page_size) {
uint16_t pages_per_block = nand->erase_size / nand->page_size;
work_mode |= MXC_NF_V2_CFG1_PPB(ffs(pages_per_block) - 6);
}if (nand->page_size) { ... }
work_mode |= MXC_NF_BIT_ECC_4BIT;
}if (nfc_is_v2()) { ... }
target_write_u16(target, MXC_NF_CFG1, work_mode);
/* ... */
target_write_u16(target, MXC_NF_BUFCFG, 2);
target_read_u16(target, MXC_NF_FWP, &temp);
if ((temp & 0x0007) == 1) {
LOG_ERROR("NAND flash is tight-locked, reset needed");
return ERROR_FAIL;
}if ((temp & 0x0007) == 1) { ... }
/* ... */
if (nfc_is_v1()) {
target_write_u16(target, MXC_NF_V1_UNLOCKSTART, 0x0000);
target_write_u16(target, MXC_NF_V1_UNLOCKEND, 0xFFFF);
}if (nfc_is_v1()) { ... } else {
target_write_u16(target, MXC_NF_V2_UNLOCKSTART0, 0x0000);
target_write_u16(target, MXC_NF_V2_UNLOCKSTART1, 0x0000);
target_write_u16(target, MXC_NF_V2_UNLOCKSTART2, 0x0000);
target_write_u16(target, MXC_NF_V2_UNLOCKSTART3, 0x0000);
target_write_u16(target, MXC_NF_V2_UNLOCKEND0, 0xFFFF);
target_write_u16(target, MXC_NF_V2_UNLOCKEND1, 0xFFFF);
target_write_u16(target, MXC_NF_V2_UNLOCKEND2, 0xFFFF);
target_write_u16(target, MXC_NF_V2_UNLOCKEND3, 0xFFFF);
}else { ... }
target_write_u16(target, MXC_NF_FWP, 4);
/* ... */
target_write_u16(target, MXC_NF_BUFADDR, 0x0000);
/* ... */
in_sram_address = MXC_NF_MAIN_BUFFER0;
sign_of_sequental_byte_read = 0;
return ERROR_OK;
}{ ... }
static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
static uint8_t even_byte;
uint16_t temp;
/* ... */
if (sign_of_sequental_byte_read == 0)
even_byte = 0;
if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) {
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
*value = 0;
sign_of_sequental_byte_read = 0;
even_byte = 0;
return ERROR_NAND_OPERATION_FAILED;
}if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) { ... } else {
if (nfc_is_v2())
in_sram_address = align_address_v2(nand, in_sram_address);
target_read_u16(target, in_sram_address, &temp);
if (even_byte) {
*value = temp >> 8;
even_byte = 0;
in_sram_address += 2;
}if (even_byte) { ... } else {
*value = temp & 0xff;
even_byte = 1;
}else { ... }
}else { ... }
sign_of_sequental_byte_read = 1;
return ERROR_OK;
}{ ... }
static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) {
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
*value = 0;
return ERROR_NAND_OPERATION_FAILED;
}if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) { ... } else {
if (nfc_is_v2())
in_sram_address = align_address_v2(nand, in_sram_address);
target_read_u16(target, in_sram_address, value);
in_sram_address += 2;
}else { ... }
return ERROR_OK;
}{ ... }
static int poll_for_complete_op(struct nand_device *nand, const char *text)
{
if (mxc_nand_ready(nand, 1000) == -1) {
LOG_ERROR("%s sending timeout", text);
return ERROR_NAND_OPERATION_FAILED;
}if (mxc_nand_ready(nand, 1000) == -1) { ... }
return ERROR_OK;
}{ ... }
static int validate_target_state(struct nand_device *nand)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
if (target->state != TARGET_HALTED) {
LOG_ERROR(target_not_halted_err_msg);
return ERROR_NAND_OPERATION_FAILED;
}if (target->state != TARGET_HALTED) { ... }
if (mxc_nf_info->flags.target_little_endian !=
(target->endianness == TARGET_LITTLE_ENDIAN)) {
/* ... */
return ERROR_NAND_OPERATION_FAILED;
}if (mxc_nf_info->flags.target_little_endian != (target->endianness == TARGET_LITTLE_ENDIAN)) { ... }
return ERROR_OK;
}{ ... }
static int ecc_status_v1(struct nand_device *nand)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
uint16_t ecc_status;
target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status);
switch (ecc_status & 0x000c) {
case 1 << 2:
LOG_INFO("main area read with 1 (correctable) error");
break;case 1 << 2:
case 2 << 2:
LOG_INFO("main area read with more than 1 (incorrectable) error");
return ERROR_NAND_OPERATION_FAILED;case 2 << 2:
}switch (ecc_status & 0x000c) { ... }
switch (ecc_status & 0x0003) {
case 1:
LOG_INFO("spare area read with 1 (correctable) error");
break;case 1:
case 2:
LOG_INFO("main area read with more than 1 (incorrectable) error");
return ERROR_NAND_OPERATION_FAILED;case 2:
}switch (ecc_status & 0x0003) { ... }
return ERROR_OK;
}{ ... }
static int ecc_status_v2(struct nand_device *nand)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
uint16_t ecc_status;
uint8_t no_subpages;
uint8_t err;
no_subpages = nand->page_size >> 9;
target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status);
do {
err = ecc_status & 0xF;
if (err > 4) {
LOG_INFO("UnCorrectable RS-ECC Error");
return ERROR_NAND_OPERATION_FAILED;
}if (err > 4) { ... } else if (err > 0)
LOG_INFO("%d Symbol Correctable RS-ECC Error", err);
ecc_status >>= 4;
...} while (--no_subpages);
return ERROR_OK;
}{ ... }
static int do_data_output(struct nand_device *nand)
{
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
struct target *target = nand->target;
int poll_result;
switch (mxc_nf_info->fin) {
case MXC_NF_FIN_DATAOUT:
/* ... */
target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_DATAOUT_TYPE(mxc_nf_info->optype));
poll_result = poll_for_complete_op(nand, "data output");
if (poll_result != ERROR_OK)
return poll_result;
mxc_nf_info->fin = MXC_NF_FIN_NONE;
/* ... */
if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) {
int ecc_status;
if (nfc_is_v1())
ecc_status = ecc_status_v1(nand);
else
ecc_status = ecc_status_v2(nand);
if (ecc_status != ERROR_OK)
return ecc_status;
}if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) { ... }
break;case MXC_NF_FIN_DATAOUT:
case MXC_NF_FIN_NONE:
break;case MXC_NF_FIN_NONE:
}switch (mxc_nf_info->fin) { ... }
return ERROR_OK;
}{ ... }
struct nand_flash_controller mxc_nand_flash_controller = {
.name = "mxc",
.nand_device_command = &mxc_nand_device_command,
.commands = mxc_nand_command_handler,
.init = &mxc_init,
.reset = &mxc_reset,
.command = &mxc_command,
.address = &mxc_address,
.write_data = &mxc_write_data,
.read_data = &mxc_read_data,
.write_page = &mxc_write_page,
.read_page = &mxc_read_page,
.nand_ready = &mxc_nand_ready,
...};