• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3   Copyright (c) 2004  - 2016, Intel Corporation. All rights reserved.<BR>
4 
5   This program and the accompanying materials are licensed and made available under
6   the terms and conditions of the BSD License that accompanies this distribution.
7   The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php.
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 
14 
15 **/
16 
17 #include <PiDxe.h>
18 
19 #include <Library/FlashDeviceLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/BaseLib.h>
22 #include <Library/BaseMemoryLib.h>
23 #include <Guid/EventGroup.h>
24 #include <Library/SpiFlash.H>
25 
26 #define FLASH_SIZE  0x400000
27 
28 #define FLASH_DEVICE_BASE_ADDRESS (0xFFFFFFFF-FLASH_SIZE+1)
29 UINTN FlashDeviceBase = FLASH_DEVICE_BASE_ADDRESS;
30 
31 EFI_SPI_PROTOCOL *mSpiProtocol = NULL;
32 
33 EFI_STATUS
SpiFlashErase(UINT8 * BaseAddress,UINTN NumBytes)34 SpiFlashErase (
35   UINT8 *BaseAddress,
36   UINTN NumBytes
37   )
38 {
39   EFI_STATUS          Status = EFI_SUCCESS;
40   UINT32              SectorSize;
41   UINT32              SpiAddress;
42 
43   SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase;
44   SectorSize = SECTOR_SIZE_4KB;
45   while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) {
46     Status = mSpiProtocol->Execute (
47                              mSpiProtocol,
48                              SPI_SERASE,
49                              SPI_WREN,
50                              FALSE,
51                              TRUE,
52                              FALSE,
53                              (UINT32) SpiAddress,
54                              0,
55                              NULL,
56                              EnumSpiRegionBios
57                              );
58     if (EFI_ERROR (Status)) {
59       break;
60     }
61     SpiAddress += SectorSize;
62     NumBytes   -= SectorSize;
63   }
64 
65   return Status;
66 }
67 
68 
69 EFI_STATUS
SpiFlashBlockErase(UINT8 * BaseAddress,UINTN NumBytes)70 SpiFlashBlockErase (
71   UINT8 *BaseAddress,
72   UINTN NumBytes
73   )
74 {
75   EFI_STATUS          Status = EFI_SUCCESS;
76   UINT32              SectorSize;
77   UINT32              SpiAddress;
78 
79   SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase;
80   SectorSize = SECTOR_SIZE_64KB;
81   while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) {
82     Status = mSpiProtocol->Execute (
83                              mSpiProtocol,
84                              SPI_BERASE,
85                              SPI_WREN,
86                              FALSE,
87                              TRUE,
88                              FALSE,
89                              (UINT32) SpiAddress,
90                              0,
91                              NULL,
92                              EnumSpiRegionBios
93                              );
94     if (EFI_ERROR (Status)) {
95       break;
96     }
97     SpiAddress += SectorSize;
98     NumBytes   -= SectorSize;
99   }
100 
101   return Status;
102 }
103 
104 
105 static
106 EFI_STATUS
SpiFlashWrite(UINT8 * DstBufferPtr,UINT8 * Byte,IN UINTN Length)107 SpiFlashWrite (
108   UINT8 *DstBufferPtr,
109   UINT8 *Byte,
110   IN  UINTN Length
111   )
112 {
113   EFI_STATUS                Status;
114   UINT32                    NumBytes = (UINT32)Length;
115   UINT8*                    pBuf8 = Byte;
116   UINT32                    SpiAddress;
117 
118   SpiAddress = (UINT32)(UINTN)(DstBufferPtr) - (UINT32)FlashDeviceBase;
119   Status = mSpiProtocol->Execute (
120                            mSpiProtocol,
121                            SPI_PROG,
122                            SPI_WREN,
123                            TRUE,
124                            TRUE,
125                            TRUE,
126                            (UINT32)SpiAddress,
127                            NumBytes,
128                            pBuf8,
129                            EnumSpiRegionBios
130                            );
131   return Status;
132 }
133 
134 /**
135   Read the Serial Flash Status Registers.
136 
137   @param  SpiStatus         Pointer to a caller-allocated UINT8. On successful return, it contains the
138                             status data read from the Serial Flash Status Register.
139 
140 
141   @retval EFI_SUCCESS       Operation success, status is returned in SpiStatus.
142   @retval EFI_DEVICE_ERROR  The block device is not functioning correctly and the operation failed.
143 
144 **/
145 EFI_STATUS
ReadStatusRegister(UINT8 * SpiStatus)146 ReadStatusRegister (
147   UINT8   *SpiStatus
148   )
149 {
150   EFI_STATUS          Status;
151 
152   Status = mSpiProtocol->Execute (
153              mSpiProtocol,
154              SPI_RDSR,
155              SPI_WREN,
156              TRUE,
157              FALSE,
158              FALSE,
159              0,
160              1,
161              SpiStatus,
162              EnumSpiRegionBios
163              );
164   return Status;
165 }
166 
167 EFI_STATUS
SpiFlashLock(IN UINT8 * BaseAddress,IN UINTN NumBytes,IN BOOLEAN Lock)168 SpiFlashLock (
169     IN  UINT8  *BaseAddress,
170     IN  UINTN  NumBytes,
171     IN  BOOLEAN  Lock
172   )
173 {
174   EFI_STATUS          Status;
175   UINT8               SpiData;
176   UINT8               SpiStatus;
177 
178   if (Lock) {
179     SpiData = SF_SR_WPE;
180   } else {
181     SpiData = 0;
182   }
183 
184   //
185   // Always disable block protection to workaround tool issue.
186   // Feature may be re-enabled in a future bios.
187   //
188   SpiData = 0;
189   Status = mSpiProtocol->Execute (
190                            mSpiProtocol,
191                            SPI_WRSR,
192                            SPI_EWSR,
193                            TRUE,
194                            TRUE,
195                            TRUE,
196                            0,
197                            1,
198                            &SpiData,
199                            EnumSpiRegionBios
200                            );
201   if (EFI_ERROR (Status)) {
202     return Status;
203   }
204 
205   Status = ReadStatusRegister (&SpiStatus);
206   if (EFI_ERROR (Status)) {
207     return Status;
208   }
209 
210   if ((SpiStatus & SpiData) != SpiData) {
211     Status = EFI_DEVICE_ERROR;
212   }
213 
214   return Status;
215 }
216 
217 
218 /**
219   Read NumBytes bytes of data from the address specified by
220   PAddress into Buffer.
221 
222   @param[in]      PAddress          The starting physical address of the read.
223   @param[in,out]  NumBytes          On input, the number of bytes to read. On output, the number
224                                     of bytes actually read.
225   @param[out]     Buffer            The destination data buffer for the read.
226 
227   @retval         EFI_SUCCESS.      Opertion is successful.
228   @retval         EFI_DEVICE_ERROR  If there is any device errors.
229 
230 **/
231 EFI_STATUS
232 EFIAPI
LibFvbFlashDeviceRead(IN UINTN PAddress,IN OUT UINTN * NumBytes,OUT UINT8 * Buffer)233 LibFvbFlashDeviceRead (
234   IN      UINTN                           PAddress,
235   IN  OUT UINTN                           *NumBytes,
236       OUT UINT8                           *Buffer
237   )
238 {
239   CopyMem(Buffer, (VOID*)PAddress, *NumBytes);
240   return EFI_SUCCESS;
241 }
242 
243 
244 /**
245   Write NumBytes bytes of data from Buffer to the address specified by
246   PAddresss.
247 
248   @param[in]      PAddress          The starting physical address of the write.
249   @param[in,out]  NumBytes          On input, the number of bytes to write. On output,
250                                     the actual number of bytes written.
251   @param[in]      Buffer            The source data buffer for the write.
252 
253   @retval         EFI_SUCCESS.      Opertion is successful.
254   @retval         EFI_DEVICE_ERROR  If there is any device errors.
255 
256 **/
257 EFI_STATUS
258 EFIAPI
LibFvbFlashDeviceWrite(IN UINTN PAddress,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)259 LibFvbFlashDeviceWrite (
260   IN        UINTN                           PAddress,
261   IN OUT    UINTN                           *NumBytes,
262   IN        UINT8                           *Buffer
263   )
264 {
265 EFI_STATUS Status;
266   Status =  SpiFlashWrite((UINT8 *)PAddress, Buffer, *NumBytes);
267  return Status;
268 }
269 
270 
271 /**
272   Erase the block staring at PAddress.
273 
274   @param[in]  PAddress          The starting physical address of the block to be erased.
275                                 This library assume that caller garantee that the PAddress
276                                 is at the starting address of this block.
277   @param[in]  LbaLength         The length of the logical block to be erased.
278 
279   @retval     EFI_SUCCESS.      Opertion is successful.
280   @retval     EFI_DEVICE_ERROR  If there is any device errors.
281 
282 **/
283 EFI_STATUS
284 EFIAPI
LibFvbFlashDeviceBlockErase(IN UINTN PAddress,IN UINTN LbaLength)285 LibFvbFlashDeviceBlockErase (
286   IN    UINTN                     PAddress,
287   IN    UINTN                     LbaLength
288   )
289 {
290   EFI_STATUS Status;
291   Status = SpiFlashBlockErase((UINT8 *)PAddress, LbaLength);
292 
293   return Status;
294 }
295 
296 
297 /**
298   Lock or unlock the block staring at PAddress.
299 
300   @param[in]  PAddress        The starting physical address of region to be (un)locked.
301   @param[in]  LbaLength       The length of the logical block to be erased.
302   @param[in]  Lock            TRUE to lock. FALSE to unlock.
303 
304   @retval     EFI_SUCCESS.      Opertion is successful.
305   @retval     EFI_DEVICE_ERROR  If there is any device errors.
306 
307 **/
308 EFI_STATUS
309 EFIAPI
LibFvbFlashDeviceBlockLock(IN UINTN PAddress,IN UINTN LbaLength,IN BOOLEAN Lock)310 LibFvbFlashDeviceBlockLock (
311   IN    UINTN                          PAddress,
312   IN    UINTN                          LbaLength,
313   IN    BOOLEAN                        Lock
314   )
315 {
316   EFI_STATUS Status;
317 
318     Status = SpiFlashLock((UINT8*)PAddress, LbaLength, Lock);
319   return Status;
320 }
321 
322