blob: be766045e899296609f883da059253200085b0e9 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/******************************************************************************
2**
3** COPYRIGHT (C) 2002, 2003 Intel Corporation.
4**
5** This software as well as the software described in it is furnished under
6** license and may only be used or copied in accordance with the terms of the
7** license. The information in this file is furnished for informational use
8** only, is subject to change without notice, and should not be construed as
9** a commitment by Intel Corporation. Intel Corporation assumes no
10** responsibility or liability for any errors or inaccuracies that may appear
11** in this document or any software that may be provided in association with
12** this document.
13** Except as permitted by such license, no part of this document may be
14** reproduced, stored in a retrieval system, or transmitted in any form or by
15** any means without the express written consent of Intel Corporation.
16**
17** FILENAME: Flash.c
18**
19** PURPOSE: Contain template OEM boot code flash operations
20**
21******************************************************************************/
22
23#include "Flash.h"
24#include "nand.h"
25#include "general.h"
26#include "xllp_dfc.h"
27#include "FM.h"
28#include "ProtocolManager.h"
29#if COPYIMAGESTOFLASH
30#include "BootLoader.h"
31#endif
32#if USE_DMA
33#include "xllp_dmac.h"
34#endif
35#include "dma.h"
36#include "BBM.h"
37
38NAND_Properties_T NAND_Prop; // Only need one
39extern UINT_T NandID;
40extern UINT_T nand_data_dma, nand_cmd_dma;
41
42P_NAND_Properties_T GetNANDProperties(void)
43{
44 return &NAND_Prop;
45}
46
47UINT_T GetSpareAreaSize(FlashBootType_T fbt)
48{
49 return GetNANDProperties()->SpareAreaSize;
50}
51
52UINT_T GetBlockSize(FlashBootType_T fbt)
53{
54 return GetNANDProperties()->BlockSize;
55}
56
57UINT_T GetPageSize(FlashBootType_T fbt)
58{
59 return GetNANDProperties()->PageSize;
60}
61
62/*
63 * Function initializes NAND device and fills out Flash Properties Struct
64 */
65
66UINT_T InitializeNANDDevice(UINT8_T FlashNum, FlashBootType_T FlashBootType, UINT8_T* P_DefaultPartitionNum)
67{
68 UINT_T Retval = NoError;
69 P_NAND_Properties_T pNandP = GetNANDProperties();
70 P_FlashProperties_T pFlashP = GetFlashProperties(FlashBootType);
71 // Set Current FlashBootType so XllpDfcInit can determine why it is called.
72 SetCurrentFlashBootType(FlashBootType);
73
74 // Pick correct bus width and set the ECC type
75 switch (FlashNum)
76 {
77 case NAND_FLASH_X16_HM_P:
78 pNandP->FlashBusWidth = FlashBusWidth16;
79 pNandP->ECCMode = ECC_HAMMING;
80 break;
81 case NAND_FLASH_X16_BCH_P:
82 pNandP->FlashBusWidth = FlashBusWidth16;
83 pNandP->ECCMode = ECC_BCH;
84 break;
85 case NAND_FLASH_X8_HM_P:
86 pNandP->FlashBusWidth = FlashBusWidth8;
87 pNandP->ECCMode = ECC_HAMMING;
88 break;
89 case NAND_FLASH_X8_BCH_P:
90 pNandP->FlashBusWidth = FlashBusWidth8;
91 pNandP->ECCMode = ECC_BCH;
92 break;
93 default:
94 return DFCInitFailed;
95 }
96
97 PlatformNandClocksEnable();
98
99 Retval = XllpDfcInit(pNandP->FlashBusWidth, pNandP);
100
101 if (Retval != NoError)
102 //return DFCInitFailed;
103 return NANDNotFound;
104
105 //set ECC with the correct ECCMode
106 xdfc_enable_ecc( 1 );
107 //define functions
108 pFlashP->ReadFromFlash = &ReadNAND;
109 pFlashP->WriteToFlash = &WriteNAND;
110 pFlashP->EraseFlash = &EraseNAND;
111 pFlashP->ResetFlash = &ResetNAND;
112 pFlashP->BlockSize = pNandP->BlockSize;
113 pFlashP->PageSize = pNandP->PageSize;
114 pFlashP->NumBlocks = pNandP->NumOfBlocks;
115 pFlashP->FlashSettings.UseBBM = 1;
116 pFlashP->FlashSettings.UseSpareArea = 0;
117 pFlashP->FlashSettings.SASize = 0;
118 pFlashP->FlashSettings.UseHwEcc = 1; // default is HW ECC ON
119 pFlashP->FlashType = NAND_FLASH;
120 pFlashP->GenerateFBBT = GenerateFBBTNAND;
121 // init the TIM load address
122 //---------------------------------------
123 pFlashP->TimFlashAddress = TIMOffset_NAND;
124 pFlashP->StreamingFlash = FALSE;
125 *P_DefaultPartitionNum = NAND_DEFAULT_PART;
126 pFlashP->FinalizeFlash = NULL;
127
128 NandID = (pNandP->FlashID << 8) | pNandP->ManufacturerCode;
129
130 GetDMAReqNum(&nand_data_dma, &nand_cmd_dma);
131
132 return Retval;
133}
134
135UINT_T GetDMAReqNum(UINT_T *data, UINT_T *cmd)
136{
137 UINT_T NAND_DMA_DataReqNum = DMAC_NAND_DATA;
138 UINT_T NAND_DMA_CMDReqNum = DMAC_NAND_CMD;
139
140#if NZA3
141 switch (PlatformGetRevisionID())
142 {
143 case 0xF0:
144 case 0xF2:
145 NAND_DMA_DataReqNum = DMAC_NAND_DATA_Z2;
146 NAND_DMA_CMDReqNum = DMAC_NAND_CMD_Z2;
147 break;
148
149 case 0xF3:
150 default:
151 break;
152 }
153#endif
154
155 *data = NAND_DMA_DataReqNum;
156 *cmd = NAND_DMA_CMDReqNum;
157}
158
159/*
160 This routine will read in data from the DFC.
161*/
162 #if !SHRINK_BINARY_SIZE
163UINT_T ReadNAND_nonDMA(UINT_T Address, UINT_T Destination, UINT_T ReadAmount, FlashBootType_T FlashBootType)
164{
165 P_NAND_Properties_T pNAND_Prop;
166 pNAND_Prop = GetNANDProperties();
167
168 UINT_T temp_buffer[2]; // temp use, no data needed
169
170 // For monolithic operation call legacy read routine
171 if (pNAND_Prop->PageSize <= TWO_KB)
172 {
173 if (upload_nand_spare == TRUE)
174 {
175 return xdfc_read_nonDMA((UINT_T *)Destination, Address, ReadAmount, temp_buffer, pNAND_Prop);
176 }
177 else
178 {
179 return xdfc_read_nonDMA((UINT_T *)Destination, Address, ReadAmount, NULL, pNAND_Prop);
180 }
181 }
182 else{ // Call the new routine that reads page at a time.
183#if NAND_LP
184 return xdfc_read_LP((UINT_T *)Destination, Address, ReadAmount, NULL, pNAND_Prop);
185#else
186 return NoError;
187#endif
188 }
189}
190 #endif
191
192UINT_T ReadNAND (UINT_T Address, UINT_T Destination, UINT_T ReadAmount, FlashBootType_T FlashBootType)
193{
194 return xdfc_read(Destination, Address, ReadAmount, NULL, GetNANDProperties());
195}
196
197/*
198 WriteNAND - This function is a wrapper to work with DFC
199 */
200
201UINT_T WriteNAND (UINT_T flash_addr, UINT_T source, UINT_T WriteAmount, FlashBootType_T FlashBootType)
202{
203 UINT_T Retval = NoError;
204 P_NAND_Properties_T pNandP = GetNANDProperties();
205 P_FlashProperties_T pFlashP = GetFlashProperties(FlashBootType);
206 if (pNandP->PageSize <= TWO_KB)
207 {
208 Retval = xdfc_write((UINT_T *) source,
209 flash_addr,
210 WriteAmount,
211 pFlashP->FlashSettings.UseSpareArea,
212 pFlashP->FlashSettings.UseHwEcc,
213 pNandP);
214 }
215 else
216 {
217#if NAND_LP
218 Retval = xdfc_write_LP((UINT_T *) source,
219 flash_addr,
220 WriteAmount,
221 pFlashP->FlashSettings.UseSpareArea,
222 pNandP);
223#endif
224 }
225 return Retval; // Return value
226}
227
228/*
229 *
230 * Erases one block at a time
231 * note: if user inputs determine that a partial block should be erased,
232 * this function will erase that WHOLE block: no partial blocks allowed
233 *
234 */
235UINT_T EraseNAND (UINT_T flashoffset, UINT_T size, FlashBootType_T fbt)
236{
237 return xdfc_erase(flashoffset, GetNANDProperties());
238}
239
240//Wrapper to link the dfc reset routine to the flash API
241UINT_T ResetNAND(FlashBootType_T fbt)
242{
243 return xdfc_reset(GetNANDProperties());
244}
245
246static UINT8_T page_buffer[2048]; //temp buffer to read dummy
247UINT_T GenerateFBBTNAND(UINT16 *badblocklist)
248{
249 unsigned int Retval, SA, i, j, temp, max, zero = 0, badblocks = 0;
250 unsigned int PageSize, BlockSize, block_good;
251 unsigned int *pRB0, *pRB1;
252 P_NAND_Properties_T pNandP = GetNANDProperties();
253 P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
254 UINT_T bUseHwEcc = FALSE;
255 unsigned int *dumy_buf = page_buffer;
256 unsigned char *ptemp = 0;
257
258 PageSize = pNandP->PageSize;
259 BlockSize = pNandP->BlockSize;
260 max = (pFlashProp->NumBlocks * LEGACY_BBM_RELOC_PERCENTAGE + 99) / 100; //max number of relocation is 2% of device
261
262 ptemp = malloc(BlockSize);
263 if(ptemp == NULL)
264 return HeapExhaustedError;
265
266 //buffers used to capture the entire spare area for page 0 and 1, respectively
267 pRB0 = (unsigned int *) (((unsigned int)ptemp + 16) & 0xFFFFFFF0); //align to 16 byte aligned
268 pRB1 = (unsigned int *) (((unsigned int)pRB0 + pNandP->SpareAreaSize + 16) & 0xFFFFFFF0); //ditto
269
270 //AddMessageError(REPORT_NOTIFICATION, PlatformBusy);
271 bUseHwEcc = GetUseHwEcc(BOOT_FLASH );
272 SetUseSpareArea( 1, BOOT_FLASH );
273 SetUseHwEcc( FALSE , BOOT_FLASH); //Turn Off ECC
274
275 //Block 0 is for TIM, scan from block1
276 for (i = 1; i < pFlashProp->NumBlocks; i++)
277 {
278 // address of 1st page in each block
279 SA = i * BlockSize;
280 // Read first page(including spare area) and second page of the block.
281 Retval = xdfc_read(dumy_buf, SA , PageSize, pRB0, pNandP);
282 Retval |= xdfc_read(dumy_buf, SA + PageSize, PageSize, pRB1, pNandP);
283
284 if(Retval != NoError) break; //read failure? something wrong with driver. return
285
286 //finished reading Spare Area in both page 0 and 1
287 //now check it:
288 // if it is all FFFFs, page is good
289 // else if byte 0 or byte 6 are not FFs, factory marked bad
290 // else try a erase/write cycle to termine bad v. just needed an erase cycle
291 block_good = TRUE;
292 for(j = 0; (block_good == TRUE) && (j < xdfc_getSpareAreaSize(pNandP)); j++)
293 if( (pRB0[j] != 0xFFFFFFFF) || (pRB1[j] != 0xFFFFFFFF) )
294 block_good = FALSE; //check for non FFFFs in spare area
295
296 //is this block 'good'?
297 if(block_good == FALSE) //nope
298 { //check bytes 0 and 6 of both spare areas. if any byte != FF, block is factory bad
299 if( ((pRB0[0] & 0xFF) != 0xFF) || ((pRB0[1] & 0xFF0000) != 0xFF0000) ||
300 ((pRB1[0] & 0xFF) != 0xFF) || ((pRB1[1] & 0xFF0000) != 0xFF0000) )
301 badblocklist[badblocks++] = i;
302 else
303 { //try erase/program attempt
304 memcpy(pRB0, &zero, PageSize); //get a page worth of zeros
305 //erase the block
306 Retval = xdfc_erase(SA, pNandP);
307 //try writing all the pages to 0
308 for(j = 0; (j < BlockSize) && (Retval == NoError); j += PageSize)
309 Retval = WriteNAND (SA + j, (unsigned int) pRB0, PageSize, BOOT_FLASH);
310 //now erase the block again (to see if any bits get stuck at 0)
311 if(Retval == NoError)
312 Retval = xdfc_erase(SA, pNandP);
313 //any failure indicates a bad block
314 if(Retval != NoError)
315 badblocklist[badblocks++] = i;
316 }
317 }
318 //if we hit a critical number, return now and let the upper level handle it
319 if(badblocks >= max)
320 break;
321
322 }
323 SetUseHwEcc( bUseHwEcc , BOOT_FLASH); //Turn On ECC
324 //AddMessageError(REPORT_NOTIFICATION, PlatformReady);
325 SetUseSpareArea( 0 , BOOT_FLASH);
326 free(ptemp);
327 return badblocks;
328}
329
330UINT32 OBMI_FlashEntryAddr = 0;
331UINT32 OBMI_ImageSize = 0;
332static INT_T OBMBlock = -1;
333
334void DisableSpareAreaForOBM(UINT_T OBMSartAddr, UINT_T OBMSize)
335{
336 P_NAND_Properties_T pNandP = GetNANDProperties();
337 UINT_T BlockNum;
338 if(OBMSize > pNandP->BlockSize)
339 {
340 obm_printf("Error: OBM Size too big.\n\r");
341 }
342
343 if(OBMBlock == -1) {
344 OBMBlock = OBMSartAddr/pNandP->BlockSize;
345 }
346
347 if(OBMSize == 0){ //OBMSize == 0, means OBM block is relocating
348 BlockNum = OBMSartAddr/pNandP->BlockSize;
349 }else{
350 BlockNum = LocateBlock(OBMBlock, BOOT_FLASH);
351 }
352 OBMI_FlashEntryAddr = BlockNum * pNandP->BlockSize;
353
354 if(OBMSize != 0)
355 OBMI_ImageSize = OBMSize;
356}
357
358INT_T IsAccessOBMBlock(UINT32 Address)
359{
360 UINT32 BlockSize = GetNANDProperties()->BlockSize;
361 UINT32 BlockNum;
362 BlockNum = Address/BlockSize;
363
364 return (BlockNum == OBMBlock);
365}