• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 *
3 *  Copyright (c) 2015, Hisilicon Limited. All rights reserved.
4 *  Copyright (c) 2015, Linaro Limited. All rights reserved.
5 *
6 *  This program and the accompanying materials
7 *  are licensed and made available under the terms and conditions of the BSD License
8 *  which accompanies this distribution.  The full text of the license may be found at
9 *  http://opensource.org/licenses/bsd-license.php
10 *
11 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 *
14 **/
15 
16 
17 #include <Uefi.h>
18 #include <Library/DebugLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/ArmLib.h>
21 #include <Library/PcdLib.h>
22 #include <Protocol/NorFlashProtocol.h>
23 #include <Library/DxeServicesTableLib.h>
24 #include <Protocol/Cpu.h>
25 #include "NorFlashHw.h"
26 
27 
28 EFI_STATUS Erase(
29    IN UNI_NOR_FLASH_PROTOCOL   *This,
30    IN  UINT32                   Offset,
31    IN  UINT32                   Length
32   );
33 
34 EFI_STATUS  Write(
35   IN UNI_NOR_FLASH_PROTOCOL   *This,
36   IN  UINT32                  Offset,
37   IN  UINT8                  *Buffer,
38   UINT32                     ulLength
39   );
40 
41 EFI_STATUS Read(
42   IN UNI_NOR_FLASH_PROTOCOL   *This,
43   IN UINT32                   Offset,
44   IN OUT UINT8               *Buffer,
45   IN UINT32                   ulLen
46   );
47 
48 UNI_NOR_FLASH_PROTOCOL gUniNorFlash = {
49     Erase,
50     Write,
51     Read
52 };
53 
54 
55 EFI_STATUS
Read(IN UNI_NOR_FLASH_PROTOCOL * This,IN UINT32 Offset,IN OUT UINT8 * Buffer,IN UINT32 ulLen)56 EFIAPI Read(
57   IN UNI_NOR_FLASH_PROTOCOL   *This,
58   IN UINT32                   Offset,
59   IN OUT UINT8               *Buffer,
60   IN UINT32                    ulLen
61   )
62 {
63     UINT32       index;
64     UINT64 ullAddr;
65     UINT32 ullCnt = 0;
66     UINT32 *puiBuffer32 = NULL;
67     UINT32 *puiDst32 = NULL;
68     UINT8 *pucBuffer8 = NULL;
69     UINT8 *pucDst8 = NULL;
70 
71     if (Offset + ulLen > (gFlashInfo[gIndex.InfIndex].SingleChipSize * gFlashInfo[gIndex.InfIndex].ParallelNum))
72     {
73         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Exceed the flash scope!\n", __FUNCTION__,__LINE__));
74         return EFI_INVALID_PARAMETER;
75     }
76     if (0 == ulLen)
77     {
78         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Length is Zero!\n", __FUNCTION__,__LINE__));
79         return EFI_INVALID_PARAMETER;
80     }
81     if (NULL == Buffer)
82     {
83         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Buffer is NULL!\n", __FUNCTION__,__LINE__));
84         return EFI_BAD_BUFFER_SIZE;
85     }
86 
87 
88     ullAddr = gIndex.Base + Offset;
89 
90     pucBuffer8 = (UINT8 *)Buffer;
91     pucDst8    = (UINT8 *)((UINTN)ullAddr);
92 
93 
94     if (ulLen < FOUR_BYTE_UNIT)
95     {
96         for(index = 0; index< ulLen; index++)
97         {
98             *pucBuffer8++ = *pucDst8++;
99         }
100     }
101     else
102     {
103 
104         ullCnt = Offset % FOUR_BYTE_UNIT;
105         ullCnt = FOUR_BYTE_UNIT - ullCnt;
106 
107         for(index = 0; index < ullCnt; index++)
108         {
109             *pucBuffer8++ = *pucDst8++;
110         }
111 
112         ulLen -= ullCnt;
113 
114         puiBuffer32 = (UINT32 *)pucBuffer8;
115         puiDst32    = (UINT32 *)pucDst8;
116         ullCnt      = ulLen / FOUR_BYTE_UNIT;
117 
118         for(index = 0; index < ullCnt; index++)
119         {
120             *puiBuffer32++ = *puiDst32++;
121         }
122 
123         ullCnt     = ulLen % FOUR_BYTE_UNIT;
124         pucBuffer8 = (UINT8 *)puiBuffer32;
125         pucDst8    = (UINT8 *)puiDst32;
126 
127         for(index = 0; index < ullCnt; index++)
128         {
129             *pucBuffer8++ = *pucDst8++;
130         }
131     }
132 
133     return EFI_SUCCESS;
134 }
135 
136 
137 
WriteAfterErase_Fill(IN const UINT32 Offset,IN const UINT8 * Buffer,IN const UINT32 Length)138 static EFI_STATUS WriteAfterErase_Fill(
139     IN  const UINT32       Offset,
140     IN  const UINT8       *Buffer,
141     IN  const UINT32       Length
142     )
143 {
144     EFI_STATUS Status;
145     UINT32 Loop;
146     UINT32 DataOffset;
147     UINT32 NewOffset;
148     UINT8 *NewDataUnit;
149 
150     UINT32 FlashUnitLength;
151 
152     FlashUnitLength = gFlashInfo[gIndex.InfIndex].BufferProgramSize << gFlashInfo[gIndex.InfIndex].ParallelNum;
153 
154     if (0 == Length)
155     {
156         return EFI_SUCCESS;
157     }
158     if ((Offset % FlashUnitLength + Length) > FlashUnitLength)
159     {
160         DEBUG ((EFI_D_INFO, "[%a]:[%dL]:Exceed the Flash Size!\n", __FUNCTION__,__LINE__));
161         return EFI_UNSUPPORTED;
162     }
163 
164 
165     Status = gBS->AllocatePool(EfiBootServicesData, FlashUnitLength, (VOID *)&NewDataUnit);
166     if (EFI_ERROR(Status))
167     {
168         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Allocate Pool failed, %r!\n", __FUNCTION__,__LINE__, Status));
169         return Status;
170     }
171 
172 
173     NewOffset = Offset - (Offset % FlashUnitLength);
174 
175     gBS->CopyMem((VOID *)NewDataUnit, (VOID *)(UINTN)(gIndex.Base + NewOffset), FlashUnitLength);
176 
177     DataOffset = Offset % FlashUnitLength;
178     for (Loop = 0; Loop < Length; Loop ++)
179     {
180         NewDataUnit[(UINT32)(DataOffset + Loop)] = Buffer[Loop];
181     }
182 
183     Status = BufferWrite(NewOffset, (void *)NewDataUnit, FlashUnitLength);
184     if (EFI_ERROR(Status))
185     {
186         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:BufferWrite %r!\n", __FUNCTION__,__LINE__, Status));
187         return Status;
188     }
189 
190     (void)gBS->FreePool((VOID *)NewDataUnit);
191     return Status;
192 }
193 
194 
WriteAfterErase_Final(IN UINT32 Offset,IN UINT8 * Buffer,IN UINT32 Length)195 static EFI_STATUS WriteAfterErase_Final(
196     IN  UINT32       Offset,
197     IN  UINT8       *Buffer,
198     IN  UINT32       Length
199     )
200 {
201     EFI_STATUS Status;
202     UINT32 Loop;
203     UINT32 FlashUnitLength;
204 
205     FlashUnitLength = gFlashInfo[gIndex.InfIndex].BufferProgramSize << gFlashInfo[gIndex.InfIndex].ParallelNum;
206 
207     if (0 == Length)
208     {
209         return EFI_SUCCESS;
210     }
211 
212     if (0 != (Offset % FlashUnitLength))
213     {
214         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: Offset must be a multiple of 0x%x!\n", __FUNCTION__,__LINE__,FlashUnitLength));
215         return EFI_UNSUPPORTED;
216     }
217 
218 
219     Loop = Length / FlashUnitLength;
220     while (Loop --)
221     {
222         Status = BufferWrite(Offset, (void *)Buffer, FlashUnitLength);
223         if (EFI_ERROR(Status))
224         {
225             DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:BufferWrite Failed: %r!\n", __FUNCTION__,__LINE__, Status));
226             return EFI_DEVICE_ERROR;
227         }
228         Offset += FlashUnitLength;
229         Buffer += FlashUnitLength;
230     }
231 
232 
233     Length = Length % FlashUnitLength;
234     if (Length)
235     {
236         Status = WriteAfterErase_Fill(Offset, Buffer, Length);
237         if (EFI_ERROR(Status))
238         {
239             DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:WriteAfterErase_Fill failed,%r!\n", __FUNCTION__,__LINE__, Status));
240             return Status;
241         }
242     }
243 
244     return EFI_SUCCESS;
245 }
246 
247 EFI_STATUS
WriteAfterErase(UINT32 TempBase,UINT32 Offset,UINT8 * Buffer,UINT32 Length)248 WriteAfterErase(
249     UINT32       TempBase,
250     UINT32       Offset,
251     UINT8       *Buffer,
252     UINT32       Length
253   )
254 {
255     EFI_STATUS Status;
256     UINT32 FlashUnitLength;
257 
258     FlashUnitLength = gFlashInfo[gIndex.InfIndex].BufferProgramSize << gFlashInfo[gIndex.InfIndex].ParallelNum;
259 
260     if (0 == Length)
261     {
262         return EFI_SUCCESS;
263     }
264 
265 
266     if (Offset % FlashUnitLength)
267     {
268         UINT32 TempLength;
269 
270 
271         TempLength = FlashUnitLength - (Offset % FlashUnitLength);
272         if (TempLength > Length)
273         {
274             TempLength = Length;
275         }
276         Status = WriteAfterErase_Fill(Offset, Buffer, TempLength);
277         if (EFI_ERROR(Status))
278         {
279             DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: %r!\n", __FUNCTION__,__LINE__, Status));
280             return Status;
281         }
282 
283         Offset += TempLength;
284         Length -= TempLength;
285         Buffer += TempLength;
286 
287         //Desc:if Offset >= gOneFlashSize,modify base
288         if (0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
289         {
290             TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize;
291             gIndex.Base = TempBase;
292             Offset = 0;
293         }
294     }
295 
296 
297     Status = WriteAfterErase_Final(Offset, Buffer, Length);
298     if (EFI_ERROR(Status))
299     {
300         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: %r!\n", __FUNCTION__,__LINE__, Status));
301         return Status;
302     }
303 
304     return EFI_SUCCESS;
305 }
306 
307 
308 EFI_STATUS
FlashSectorErase(UINT32 TempBase,UINT32 Offset,UINT32 Length)309 FlashSectorErase(
310     UINT32      TempBase,
311     UINT32      Offset,
312     UINT32      Length
313   )
314 {
315     EFI_STATUS  Status;
316     UINT32 SectorOffset;
317     UINT8 *StaticBuffer;
318     UINT8 *Buffer;
319     UINT32 TempOffset;
320     UINT32 TempLength;
321     UINT32 LeftLength;
322 
323 
324     if (0 == Length)
325     {
326         return EFI_SUCCESS;
327     }
328 
329     LeftLength = gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum));
330     if (LeftLength < Length)
331     {
332         return EFI_UNSUPPORTED;
333     }
334 
335 
336     SectorOffset = Offset - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum));
337 
338     Status = gBS->AllocatePool(EfiBootServicesData, gFlashInfo[gIndex.InfIndex].BlockSize * (UINTN)gFlashInfo[gIndex.InfIndex].ParallelNum, (VOID *)&StaticBuffer);
339     if (EFI_ERROR(Status))
340     {
341         return Status;
342     }
343 
344     Buffer = StaticBuffer;
345 
346     gBS->CopyMem((VOID *)Buffer, (VOID *)(UINTN)(TempBase + SectorOffset),
347                  (gFlashInfo[gIndex.InfIndex].BlockSize * (UINTN)gFlashInfo[gIndex.InfIndex].ParallelNum));
348 
349 
350     Status = SectorErase(TempBase, SectorOffset);
351     if (EFI_ERROR(Status))
352     {
353         goto DO;
354     }
355 
356 
357     TempOffset = SectorOffset;
358     TempLength = Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum);
359 
360     Status = WriteAfterErase(TempBase, TempOffset, Buffer, TempLength);
361     if (EFI_ERROR(Status))
362     {
363         goto DO;
364     }
365 
366 
367     Buffer = Buffer + TempLength + Length;
368     TempOffset = Offset + Length;
369     TempLength = SectorOffset + (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum) - TempOffset;
370 
371     Status = WriteAfterErase(TempBase, TempOffset, Buffer, TempLength);
372     if (EFI_ERROR(Status))
373     {
374         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: %r!\n", __FUNCTION__,__LINE__,Status));
375         goto DO;
376     }
377 
378     (void)gBS->FreePool((VOID *)StaticBuffer);
379     return EFI_SUCCESS;
380 
381 DO:
382     (void)gBS->FreePool((VOID *)StaticBuffer);
383     return Status;
384 }
385 
386 
387 EFI_STATUS
Erase(IN UNI_NOR_FLASH_PROTOCOL * This,IN UINT32 Offset,IN UINT32 Length)388 EFIAPI Erase(
389    IN UNI_NOR_FLASH_PROTOCOL   *This,
390    IN UINT32                   Offset,
391    IN UINT32                   Length
392   )
393 {
394     EFI_STATUS  Status = EFI_SUCCESS;
395     UINT32 Sectors;
396     UINT32 TempLength;
397     UINT32 TempBase;
398     UINT32 Loop;
399 
400 
401     if (Offset + Length > (gFlashInfo[gIndex.InfIndex].SingleChipSize * gFlashInfo[gIndex.InfIndex].ParallelNum))
402     {
403         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Exceed the Flash Size!\n", __FUNCTION__,__LINE__));
404         return EFI_ABORTED;
405     }
406     if (0 == Length)
407     {
408         return EFI_SUCCESS;
409     }
410 
411 
412     Sectors = ((Offset + Length - 1) / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) - (Offset / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) + 1;
413     TempBase = gIndex.Base;
414 
415     //if Offset >= gOneFlashSize,modify base
416     if(0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
417     {
418         TempBase +=  gFlashInfo[gIndex.InfIndex].SingleChipSize * (Offset/gFlashInfo[gIndex.InfIndex].SingleChipSize);
419         Offset = Offset - (Offset & gFlashInfo[gIndex.InfIndex].SingleChipSize);
420     }
421 
422     for (Loop = 0; Loop <= Sectors; Loop ++)
423     {
424 
425         TempLength = gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum));
426 
427 
428         if (TempLength > Length)
429         {
430             TempLength = Length;
431         }
432 
433         Status = FlashSectorErase(TempBase, Offset, TempLength);
434         if (EFI_ERROR(Status))
435         {
436             DEBUG ((EFI_D_ERROR, "[%a]:[%dL]: FlashErase One Sector Error, Status = %r!\n", __FUNCTION__,__LINE__,Status));
437             return Status;
438         }
439 
440         Offset += TempLength;
441 
442          //if Offset >= gOneFlashSize,modify base
443         if (0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
444         {
445             TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize;
446             Offset = 0;
447         }
448         Length -= TempLength;
449     }
450 
451     return Status;
452 }
453 
454 
455 EFI_STATUS
Write(IN UNI_NOR_FLASH_PROTOCOL * This,IN UINT32 Offset,IN UINT8 * Buffer,UINT32 ulLength)456 EFIAPI Write(
457   IN UNI_NOR_FLASH_PROTOCOL   *This,
458   IN UINT32                   Offset,
459   IN UINT8                   *Buffer,
460   UINT32                     ulLength
461   )
462 {
463     EFI_STATUS  Status;
464     UINT32     TempLength;
465     UINT32       TempBase;
466     UINT32           Loop;
467     UINT32        Sectors;
468 
469     if((Offset + ulLength) > (gFlashInfo[gIndex.InfIndex].SingleChipSize * gFlashInfo[gIndex.InfIndex].ParallelNum))
470     {
471         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Exceed the Flash Size!\n", __FUNCTION__,__LINE__));
472         return EFI_INVALID_PARAMETER;
473     }
474     if (0 == ulLength)
475     {
476         return EFI_SUCCESS;
477     }
478 
479 
480     Sectors = ((Offset + ulLength - 1) / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) - (Offset / (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum)) + 1;
481     TempBase = gIndex.Base;
482 
483     //if Offset >= gOneFlashSize,modify base
484     if(0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
485     {
486         TempBase +=  gFlashInfo[gIndex.InfIndex].SingleChipSize * (Offset/gFlashInfo[gIndex.InfIndex].SingleChipSize);
487         Offset = Offset - (Offset & gFlashInfo[gIndex.InfIndex].SingleChipSize);
488     }
489 
490     for (Loop = 0; Loop <= Sectors; Loop ++)
491     {
492 
493         TempLength = gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum - (Offset % (gFlashInfo[gIndex.InfIndex].BlockSize * gFlashInfo[gIndex.InfIndex].ParallelNum));
494 
495 
496         if (TempLength > ulLength)
497         {
498             TempLength = ulLength;
499         }
500 
501 
502         if (TRUE == IsNeedToWrite(TempBase, Offset, Buffer, TempLength))
503         {
504             Status = FlashSectorErase(TempBase, Offset, TempLength);
505             if (EFI_ERROR(Status))
506             {
507                 DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:FlashErase One Sector Error, Status = %r!\n", __FUNCTION__,__LINE__,Status));
508                 return Status;
509             }
510 
511 
512             Status = WriteAfterErase(TempBase, Offset, Buffer, TempLength);
513             if (EFI_ERROR(Status))
514             {
515                 DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:WriteAfterErase Status = %r!\n", __FUNCTION__,__LINE__,Status));
516                 return Status;
517             }
518         }
519 
520         Offset += TempLength;
521         Buffer += TempLength;
522 
523          //if Offset >= gOneFlashSize,modify base
524         if (0 < (Offset / gFlashInfo[gIndex.InfIndex].SingleChipSize))
525         {
526             TempBase += gFlashInfo[gIndex.InfIndex].SingleChipSize;
527             Offset = 0;
528         }
529         ulLength -= TempLength;
530     }
531 
532     return EFI_SUCCESS;
533 }
534 
535 
SetFlashAttributeToUncache(VOID)536 VOID SetFlashAttributeToUncache(VOID)
537 {
538     EFI_CPU_ARCH_PROTOCOL             *gCpu           = NULL;
539     EFI_STATUS Status;
540 
541     Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
542     if (EFI_ERROR(Status))
543     {
544         DEBUG((EFI_D_ERROR, "LocateProtocol gEfiCpuArchProtocolGuid Status = %r !\n", Status));
545     }
546 
547     Status = gCpu->SetMemoryAttributes(
548                      gCpu,
549                      PcdGet64(PcdNORFlashBase),
550                      PcdGet32(PcdNORFlashCachableSize),
551                      EFI_MEMORY_UC
552                      );
553 
554     if (EFI_ERROR(Status))
555     {
556         DEBUG((EFI_D_ERROR, "gCpu->SetMemoryAttributes Status = %r !\n", Status));
557     }
558 
559 }
560 
561 EFI_STATUS
InitializeFlash(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)562 EFIAPI InitializeFlash (
563   IN EFI_HANDLE         ImageHandle,
564   IN EFI_SYSTEM_TABLE  *SystemTable)
565 {
566     EFI_STATUS Status;
567 
568 
569     gIndex.Base = (UINT32)PcdGet64(PcdNORFlashBase);
570 
571     SetFlashAttributeToUncache();
572     Status = FlashInit(gIndex.Base);
573     if (EFI_ERROR(Status))
574     {
575         DEBUG((EFI_D_ERROR, "Init Flash Error !\n"));
576         return Status;
577     }
578     else
579     {
580         DEBUG((EFI_D_ERROR, "Init Flash OK!\n"));
581     }
582 
583     Status = gBS->InstallProtocolInterface (
584                             &ImageHandle,
585                             &gUniNorFlashProtocolGuid,
586                             EFI_NATIVE_INTERFACE,
587                             &gUniNorFlash);
588     if(EFI_SUCCESS != Status)
589     {
590         DEBUG ((EFI_D_ERROR, "[%a]:[%dL]:Install Protocol Interface %r!\n", __FUNCTION__,__LINE__,Status));
591     }
592 
593     return Status;
594 }
595