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