1 #include "Driver_NAND.h"
2
3 /* ONFI commands */
4 #define ONFI_CMD_READ_1ST 0x00 ///< Read 1st Cycle
5 #define ONFI_CMD_PROGRAM_2ND 0x10 ///< Page Program 2nd Cycle
6 #define ONFI_CMD_READ_2ND 0x30 ///< Read 2nd Cycle
7 #define ONFI_CMD_PROGRAM_1ST 0x80 ///< Page Program 1st Cycle
8 #define ONFI_CMD_RESET 0xFF ///< Reset Command
9
10 /* NAND Signal Event callback function */
11 volatile uint32_t NAND_Events;
NAND_SignalEventCallback(uint32_t dev_num,uint32_t event)12 void NAND_SignalEventCallback (uint32_t dev_num, uint32_t event) {
13 if (dev_num == 0) {
14 NAND_Events |= event;
15 }
16 else {
17 // ..
18 }
19 }
20
21 /* NAND device Power ON */
PowerOn(ARM_DRIVER_NAND * drv,uint32_t dev_num)22 void PowerOn (ARM_DRIVER_NAND *drv, uint32_t dev_num) {
23 ARM_NAND_CAPABILITIES capabilities;
24
25 // Query drivers capabilities
26 capabilities = drv->GetCapabilities();
27
28 // Initialize NAND device
29 drv->Initialize (NAND_SignalEventCallback);
30
31 // Power-on NAND driver
32 drv->PowerControl (ARM_POWER_FULL);
33
34 // Turn ON device power
35 uint32_t volt = 0U;
36
37 if (capabilities.vcc) { volt |= ARM_NAND_POWER_VCC_3V3; }
38 if (capabilities.vcc_1v8) { volt |= ARM_NAND_POWER_VCC_1V8; }
39 if (capabilities.vccq) { volt |= ARM_NAND_POWER_VCCQ_3V3; }
40 if (capabilities.vccq_1v8) { volt |= ARM_NAND_POWER_VCCQ_1V8; }
41
42 if (volt != 0U) {
43 drv->DevicePower (volt);
44 }
45
46 // Setting bus mode
47 drv->Control (0U, ARM_NAND_BUS_MODE, ARM_NAND_BUS_SDR);
48
49 // Setting bus data width
50 drv->Control (0U, ARM_NAND_BUS_DATA_WIDTH, ARM_NAND_BUS_DATA_WIDTH_8);
51
52 // Enable chip manually if needed
53 if (capabilities.ce_manual) {
54 drv->ChipEnable (dev_num, true);
55 }
56
57 // Send ONFI Reset command */
58 drv->SendCommand (dev_num, ONFI_CMD_RESET);
59 }
60
61 /* NAND device Power OFF */
PowerOff(ARM_DRIVER_NAND * drv,uint32_t dev_num)62 void PowerOff (ARM_DRIVER_NAND *drv, uint32_t dev_num) {
63 ARM_NAND_CAPABILITIES capabilities;
64
65 // Query drivers capabilities
66 capabilities = drv->GetCapabilities();
67
68 // Disable chip manually if needed
69 if (capabilities.ce_manual) {
70 drv->ChipEnable (0U, false);
71 }
72
73 // Switch OFF gracefully
74 uint32_t volt = 0U;
75
76 if (capabilities.vcc) { volt |= ARM_NAND_POWER_VCC_OFF; }
77 if (capabilities.vccq) { volt |= ARM_NAND_POWER_VCCQ_OFF; }
78 if (volt) {
79 drv->DevicePower (volt);
80 }
81 drv->PowerControl (ARM_POWER_OFF);
82 drv->Uninitialize ();
83 }
84
85 /* Read NAND page. */
ReadPage(ARM_DRIVER_NAND * drv,uint32_t row,uint8_t * data,uint32_t cnt)86 void ReadPage (ARM_DRIVER_NAND *drv, uint32_t row, uint8_t *data, uint32_t cnt) {
87 uint32_t dev_num = 0; // Device number
88 uint32_t mode;
89
90 // Send Read 1st command
91 drv->SendCommand (dev_num, ONFI_CMD_READ_1ST);
92
93 // Send address (column: 2 cycles, row: 3 cycles)
94 drv->SendAddress (dev_num, 0x00);
95 drv->SendAddress (dev_num, 0x00);
96 drv->SendAddress (dev_num, (uint8_t)(row));
97 drv->SendAddress (dev_num, (uint8_t)(row >> 8));
98 drv->SendAddress (dev_num, (uint8_t)(row >> 16));
99
100 // Send Read 2nd command
101 drv->SendCommand (dev_num, ONFI_CMD_READ_2ND);
102
103 // Wait until device ready
104 while (drv->GetDeviceBusy(dev_num) == 1) { ; }
105
106 // Use ECC algorithm number 2, ECC0 (ECC over main+spare)
107 mode = ARM_NAND_ECC(2) | ARM_NAND_ECC0;
108
109 // Transfer data from the NAND chip
110 if (drv->ReadData (dev_num, data, cnt, mode | ARM_NAND_DRIVER_DONE_EVENT) != cnt) {
111 // Wait until driver done event received
112 while ((NAND_Events & ARM_NAND_DRIVER_DONE_EVENT) == 0) { ; }
113 // Read page completed
114
115 if ((NAND_Events & ARM_NAND_EVENT_ECC_ERROR) != 0) {
116 // ECC correction failed
117 }
118 }
119 }
120
121 /* Write NAND page (ExecuteSequence interface). */
WritePage_Seq(ARM_DRIVER_NAND * drv,uint32_t row,const uint8_t * data,uint32_t cnt)122 void WritePage_Seq (ARM_DRIVER_NAND *drv, uint32_t row, const uint8_t *data, uint32_t cnt) {
123 uint32_t dev_num = 0; // Device number
124 uint32_t cmd;
125 uint32_t code;
126 uint32_t seq;
127
128 // Prepare commands to send
129 cmd = ONFI_CMD_PROGRAM_1ST | (ONFI_CMD_PROGRAM_2ND << 8);
130
131 // Construct sequence code:
132 // - Send command 1
133 // - Send 2 cycles of column address and 3 cycles of row address
134 // - Write data from memory to device
135 // - Send command 2
136 code = ARM_NAND_CODE_SEND_CMD1 |
137 ARM_NAND_CODE_SEND_ADDR_COL1 |
138 ARM_NAND_CODE_SEND_ADDR_COL2 |
139 ARM_NAND_CODE_SEND_ADDR_ROW1 |
140 ARM_NAND_CODE_SEND_ADDR_ROW2 |
141 ARM_NAND_CODE_SEND_ADDR_ROW3 |
142 ARM_NAND_CODE_WRITE_DATA |
143 ARM_NAND_CODE_SEND_CMD2 ;
144
145 // - Use ECC algorithm number 2, ECC0 (ECC over main+spare)
146 code |= ARM_NAND_ECC(2) | ARM_NAND_ECC0;
147
148 // Number of iterations in a sequence
149 seq = 1;
150
151 drv->ExecuteSequence (dev_num, // Device number
152 code, // Sequence code
153 cmd, // Command(s)
154 0, // Column address
155 row, // Row address
156 (void *)data, // Data buffer
157 cnt, // Number of data items (per iteration)
158 NULL, // Device status will not be read
159 &seq); // Number of iterations
160
161 // Wait until done
162 while (drv->GetStatus(dev_num).busy != 0) { ; }
163
164 // Page write completed
165 }
166