• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2 Copyright (C) 2016 Marvell International Ltd.
3 
4 Marvell BSD License Option
5 
6 If you received this File from Marvell, you may opt to use, redistribute and/or
7 modify this File under the following licensing terms.
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
10 
11 * Redistributions of source code must retain the above copyright notice,
12   this list of conditions and the following disclaimer.
13 
14 * Redistributions in binary form must reproduce the above copyright
15   notice, this list of conditions and the following disclaimer in the
16   documentation and/or other materials provided with the distribution.
17 
18 * Neither the name of Marvell nor the names of its contributors may be
19   used to endorse or promote products derived from this software without
20   specific prior written permission.
21 
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 *******************************************************************************/
34 #include "MvSpiFlash.h"
35 
36 MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
37 SPI_FLASH_INSTANCE  *mSpiFlashInstance;
38 
39 STATIC
40 VOID
SpiFlashFormatAddress(IN UINT32 Address,IN UINT8 AddrSize,IN OUT UINT8 * Cmd)41 SpiFlashFormatAddress (
42   IN      UINT32  Address,
43   IN      UINT8   AddrSize,
44   IN OUT  UINT8   *Cmd
45   )
46 {
47   if (AddrSize == 4) {
48       Cmd[1] = Address >> 24;
49       Cmd[2] = Address >> 16;
50       Cmd[3] = Address >> 8;
51       Cmd[4] = Address;
52   } else {
53       Cmd[1] = Address >> 16;
54       Cmd[2] = Address >> 8;
55       Cmd[3] = Address;
56   }
57 }
58 
59 STATIC
60 EFI_STATUS
MvSpiFlashReadCmd(IN SPI_DEVICE * Slave,IN UINT8 * Cmd,IN UINTN CmdSize,OUT UINT8 * DataIn,IN UINTN DataSize)61 MvSpiFlashReadCmd (
62   IN  SPI_DEVICE *Slave,
63   IN  UINT8 *Cmd,
64   IN  UINTN CmdSize,
65   OUT UINT8 *DataIn,
66   IN  UINTN DataSize
67   )
68 {
69   EFI_STATUS Status;
70 
71   // Send command and gather response
72   Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd,
73     CmdSize, NULL, DataIn, DataSize);
74 
75   return Status;
76 }
77 
78 STATIC
79 EFI_STATUS
MvSpiFlashWriteEnableCmd(IN SPI_DEVICE * Slave)80 MvSpiFlashWriteEnableCmd (
81   IN  SPI_DEVICE   *Slave
82   )
83 {
84   EFI_STATUS Status;
85   UINT8 CmdEn = CMD_WRITE_ENABLE;
86 
87   // Send write_enable command
88   Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1,
89     &CmdEn, NULL, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
90 
91   return Status;
92 }
93 
94 STATIC
95 EFI_STATUS
MvSpiFlashWriteCommon(IN SPI_DEVICE * Slave,IN UINT8 * Cmd,IN UINT32 Length,IN UINT8 * Buffer,IN UINT32 BufferLength)96 MvSpiFlashWriteCommon (
97   IN SPI_DEVICE *Slave,
98   IN UINT8 *Cmd,
99   IN UINT32 Length,
100   IN UINT8* Buffer,
101   IN UINT32 BufferLength
102   )
103 {
104   UINT8 CmdStatus = CMD_READ_STATUS;
105   UINT8 State;
106   UINT32 Counter = 0xFFFFF;
107   UINT8 poll_bit = STATUS_REG_POLL_WIP;
108   UINT8 check_status = 0x0;
109 
110   CmdStatus = (UINT8)PcdGet32 (PcdSpiFlashPollCmd);
111   if (CmdStatus == CMD_FLAG_STATUS) {
112     poll_bit = STATUS_REG_POLL_PEC;
113     check_status = poll_bit;
114   }
115 
116   // Send command
117   MvSpiFlashWriteEnableCmd (Slave);
118 
119   // Write data
120   SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd, Length,
121     Buffer, NULL, BufferLength);
122 
123   // Poll status register
124   SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &CmdStatus,
125     NULL, SPI_TRANSFER_BEGIN);
126   do {
127     SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, NULL, &State,
128       0);
129     Counter--;
130     if ((State & poll_bit) == check_status)
131       break;
132   } while (Counter > 0);
133   if (Counter == 0) {
134     DEBUG((DEBUG_ERROR, "SpiFlash: Timeout while writing to spi flash\n"));
135     return EFI_DEVICE_ERROR;
136   }
137 
138   // Deactivate CS
139   SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 0, NULL, NULL, SPI_TRANSFER_END);
140 
141   return EFI_SUCCESS;
142 }
143 
144 STATIC
145 VOID
SpiFlashCmdBankaddrWrite(IN SPI_DEVICE * Slave,IN UINT8 BankSel)146 SpiFlashCmdBankaddrWrite (
147   IN SPI_DEVICE *Slave,
148   IN UINT8 BankSel
149   )
150 {
151   UINT8 Cmd = CMD_BANK_WRITE;
152 
153   MvSpiFlashWriteCommon (Slave, &Cmd, 1, &BankSel, 1);
154 }
155 
156 STATIC
157 UINT8
SpiFlashBank(IN SPI_DEVICE * Slave,IN UINT32 Offset)158 SpiFlashBank (
159   IN SPI_DEVICE *Slave,
160   IN UINT32 Offset
161   )
162 {
163   UINT8 BankSel;
164 
165   BankSel = Offset / SPI_FLASH_16MB_BOUN;
166 
167   SpiFlashCmdBankaddrWrite (Slave, BankSel);
168 
169   return BankSel;
170 }
171 
172 EFI_STATUS
MvSpiFlashErase(IN SPI_DEVICE * Slave,IN UINTN Offset,IN UINTN Length)173 MvSpiFlashErase (
174   IN SPI_DEVICE *Slave,
175   IN UINTN Offset,
176   IN UINTN Length
177   )
178 {
179   EFI_STATUS Status;
180   UINT32 AddrSize, EraseAddr;
181   UINTN EraseSize;
182   UINT8 Cmd[5];
183 
184   AddrSize  = PcdGet32 (PcdSpiFlashAddressCycles);
185   EraseSize = PcdGet64 (PcdSpiFlashEraseSize);
186 
187   // Check input parameters
188   if (Offset % EraseSize || Length % EraseSize) {
189     DEBUG((DEBUG_ERROR, "SpiFlash: Either erase offset or length "
190       "is not multiple of erase size\n"));
191     return EFI_DEVICE_ERROR;
192   }
193 
194   Cmd[0] = CMD_ERASE_64K;
195   while (Length) {
196     EraseAddr = Offset;
197 
198     SpiFlashBank (Slave, EraseAddr);
199 
200     SpiFlashFormatAddress (EraseAddr, AddrSize, Cmd);
201 
202     // Programm proper erase address
203     Status = MvSpiFlashWriteCommon (Slave, Cmd, AddrSize + 1, NULL, 0);
204       if (EFI_ERROR (Status)) {
205         DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming target address\n"));
206         return Status;
207       }
208 
209     Offset += EraseSize;
210     Length -= EraseSize;
211   }
212   return EFI_SUCCESS;
213 }
214 
215 EFI_STATUS
MvSpiFlashRead(IN SPI_DEVICE * Slave,IN UINT32 Offset,IN UINTN Length,IN VOID * Buf)216 MvSpiFlashRead (
217   IN SPI_DEVICE   *Slave,
218   IN UINT32       Offset,
219   IN UINTN        Length,
220   IN VOID         *Buf
221   )
222 {
223   EFI_STATUS Status = EFI_SUCCESS;
224   UINT8 Cmd[6];
225   UINT32 AddrSize, ReadAddr, ReadLength, RemainLength;
226   UINTN BankSel = 0;
227 
228   AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
229 
230   Cmd[0] = CMD_READ_ARRAY_FAST;
231 
232   // Sign end of address with 0 byte
233   Cmd[5] = 0;
234 
235   while (Length) {
236     ReadAddr = Offset;
237 
238     BankSel = SpiFlashBank (Slave, ReadAddr);
239 
240     RemainLength = (SPI_FLASH_16MB_BOUN * (BankSel + 1)) - Offset;
241     if (Length < RemainLength) {
242       ReadLength = Length;
243     } else {
244       ReadLength = RemainLength;
245     }
246     SpiFlashFormatAddress (ReadAddr, AddrSize, Cmd);
247     // Program proper read address and read data
248     Status = MvSpiFlashReadCmd (Slave, Cmd, AddrSize + 2, Buf, Length);
249 
250     Offset += ReadLength;
251     Length -= ReadLength;
252     Buf += ReadLength;
253   }
254 
255   return Status;
256 }
257 
258 EFI_STATUS
MvSpiFlashWrite(IN SPI_DEVICE * Slave,IN UINT32 Offset,IN UINTN Length,IN VOID * Buf)259 MvSpiFlashWrite (
260   IN SPI_DEVICE *Slave,
261   IN UINT32     Offset,
262   IN UINTN      Length,
263   IN VOID       *Buf
264   )
265 {
266   EFI_STATUS Status;
267   UINTN ByteAddr, ChunkLength, ActualIndex, PageSize;
268   UINT32 WriteAddr;
269   UINT8 Cmd[5], AddrSize;
270 
271   AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
272   PageSize = PcdGet32 (PcdSpiFlashPageSize);
273 
274   Cmd[0] = CMD_PAGE_PROGRAM;
275 
276   for (ActualIndex = 0; ActualIndex < Length; ActualIndex += ChunkLength) {
277     WriteAddr = Offset;
278 
279     SpiFlashBank (Slave, WriteAddr);
280 
281     ByteAddr = Offset % PageSize;
282 
283     ChunkLength = MIN(Length - ActualIndex, (UINT64) (PageSize - ByteAddr));
284 
285     SpiFlashFormatAddress (WriteAddr, AddrSize, Cmd);
286 
287     // Program proper write address and write data
288     Status = MvSpiFlashWriteCommon (Slave, Cmd, AddrSize + 1, Buf + ActualIndex,
289       ChunkLength);
290     if (EFI_ERROR (Status)) {
291       DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming write address\n"));
292       return Status;
293     }
294 
295     Offset += ChunkLength;
296   }
297   return EFI_SUCCESS;
298 }
299 
300 STATIC
301 EFI_STATUS
MvSpiFlashUpdateBlock(IN SPI_DEVICE * Slave,IN UINT32 Offset,IN UINTN ToUpdate,IN UINT8 * Buf,IN UINT8 * TmpBuf,IN UINTN EraseSize)302 MvSpiFlashUpdateBlock (
303   IN SPI_DEVICE *Slave,
304   IN UINT32 Offset,
305   IN UINTN ToUpdate,
306   IN UINT8 *Buf,
307   IN UINT8 *TmpBuf,
308   IN UINTN EraseSize
309   )
310 {
311   EFI_STATUS Status;
312 
313   // Read backup
314   Status = MvSpiFlashRead (Slave, Offset, EraseSize, TmpBuf);
315     if (EFI_ERROR (Status)) {
316       DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while reading old data\n"));
317       return Status;
318     }
319 
320   // Erase entire sector
321   Status = MvSpiFlashErase (Slave, Offset, EraseSize);
322   if (EFI_ERROR (Status)) {
323       DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while erasing block\n"));
324       return Status;
325     }
326 
327   // Write new data
328   MvSpiFlashWrite (Slave, Offset, ToUpdate, Buf);
329   if (EFI_ERROR (Status)) {
330       DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing new data\n"));
331       return Status;
332     }
333 
334   // Write backup
335   if (ToUpdate != EraseSize) {
336     Status = MvSpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpdate,
337       &TmpBuf[ToUpdate]);
338     if (EFI_ERROR (Status)) {
339       DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing backup\n"));
340       return Status;
341     }
342   }
343 
344   return EFI_SUCCESS;
345 }
346 
347 EFI_STATUS
MvSpiFlashUpdate(IN SPI_DEVICE * Slave,IN UINT32 Offset,IN UINTN ByteCount,IN UINT8 * Buf)348 MvSpiFlashUpdate (
349   IN SPI_DEVICE *Slave,
350   IN UINT32 Offset,
351   IN UINTN ByteCount,
352   IN UINT8 *Buf
353   )
354 {
355   EFI_STATUS Status;
356   UINT64 EraseSize, ToUpdate, Scale = 1;
357   UINT8 *TmpBuf, *End;
358 
359   EraseSize = PcdGet64 (PcdSpiFlashEraseSize);
360 
361   End = Buf + ByteCount;
362 
363   TmpBuf = (UINT8 *)AllocateZeroPool (EraseSize);
364   if (TmpBuf == NULL) {
365     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
366     return EFI_OUT_OF_RESOURCES;
367   }
368 
369   if (End - Buf >= 200)
370     Scale = (End - Buf) / 100;
371 
372   for (; Buf < End; Buf += ToUpdate, Offset += ToUpdate) {
373     ToUpdate = MIN((UINT64)(End - Buf), EraseSize);
374     Print (L"   \rUpdating, %d%%", 100 - (End - Buf) / Scale);
375     Status = MvSpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buf, TmpBuf, EraseSize);
376 
377     if (EFI_ERROR (Status)) {
378       DEBUG((DEBUG_ERROR, "SpiFlash: Error while updating\n"));
379       return Status;
380     }
381   }
382 
383   Print(L"\n");
384   FreePool (TmpBuf);
385 
386   return EFI_SUCCESS;
387 }
388 
389 EFI_STATUS
390 EFIAPI
MvSpiFlashReadId(IN SPI_DEVICE * SpiDev,IN UINT32 DataByteCount,IN OUT UINT8 * Buffer)391 MvSpiFlashReadId (
392   IN     SPI_DEVICE *SpiDev,
393   IN     UINT32     DataByteCount,
394   IN OUT UINT8      *Buffer
395   )
396 {
397   EFI_STATUS Status;
398   UINT8 *DataOut;
399 
400   DataOut = (UINT8 *) AllocateZeroPool (DataByteCount);
401   if (DataOut == NULL) {
402     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
403     return EFI_OUT_OF_RESOURCES;
404   }
405   Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, SpiDev,
406     DataByteCount, Buffer, DataOut, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
407   if (EFI_ERROR(Status)) {
408     FreePool (DataOut);
409     DEBUG((DEBUG_ERROR, "SpiFlash: Spi transfer error\n"));
410     return Status;
411   }
412 
413   // Bytes 1,2 and 3 contain SPI flash ID
414   Buffer[0] = DataOut[1];
415   Buffer[1] = DataOut[2];
416   Buffer[2] = DataOut[3];
417 
418   FreePool (DataOut);
419 
420   return EFI_SUCCESS;
421 }
422 
423 EFI_STATUS
424 EFIAPI
MvSpiFlashInit(IN MARVELL_SPI_FLASH_PROTOCOL * This,IN SPI_DEVICE * Slave)425 MvSpiFlashInit (
426   IN MARVELL_SPI_FLASH_PROTOCOL *This,
427   IN SPI_DEVICE *Slave
428   )
429 {
430   EFI_STATUS Status;
431   UINT8 Cmd, StatusRegister;
432   UINT32 AddrSize;
433 
434   AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);
435 
436   if (AddrSize == 4) {
437     // Set 4 byte address mode
438     Status = MvSpiFlashWriteEnableCmd (Slave);
439     if (EFI_ERROR (Status)) {
440       DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n"));
441       return Status;
442     }
443 
444     Cmd = CMD_4B_ADDR_ENABLE;
445     Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &Cmd, NULL,
446       SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
447     if (EFI_ERROR (Status)) {
448       DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting 4B address\n"));
449       return Status;
450     }
451   }
452 
453   // Write flash status register
454   Status = MvSpiFlashWriteEnableCmd (Slave);
455   if (EFI_ERROR (Status)) {
456     DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n"));
457     return Status;
458   }
459 
460   Cmd = CMD_WRITE_STATUS_REG;
461   StatusRegister = 0x0;
462   Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, &Cmd, 1,
463     &StatusRegister, NULL, 1);
464   if (EFI_ERROR (Status)) {
465     DEBUG((DEBUG_ERROR, "SpiFlash: Error with spi transfer\n"));
466     return Status;
467   }
468 
469   return EFI_SUCCESS;
470 }
471 
472 EFI_STATUS
MvSpiFlashInitProtocol(IN MARVELL_SPI_FLASH_PROTOCOL * SpiFlashProtocol)473 MvSpiFlashInitProtocol (
474   IN MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol
475   )
476 {
477 
478   SpiFlashProtocol->Init = MvSpiFlashInit;
479   SpiFlashProtocol->ReadId = MvSpiFlashReadId;
480   SpiFlashProtocol->Read = MvSpiFlashRead;
481   SpiFlashProtocol->Write = MvSpiFlashWrite;
482   SpiFlashProtocol->Erase = MvSpiFlashErase;
483   SpiFlashProtocol->Update = MvSpiFlashUpdate;
484 
485   return EFI_SUCCESS;
486 }
487 
488 EFI_STATUS
489 EFIAPI
MvSpiFlashEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)490 MvSpiFlashEntryPoint (
491   IN EFI_HANDLE       ImageHandle,
492   IN EFI_SYSTEM_TABLE *SystemTable
493   )
494 {
495   EFI_STATUS  Status;
496 
497   Status = gBS->LocateProtocol (
498     &gMarvellSpiMasterProtocolGuid,
499     NULL,
500     (VOID **)&SpiMasterProtocol
501   );
502   if (EFI_ERROR (Status)) {
503     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot locate SPI Master protocol\n"));
504     return EFI_DEVICE_ERROR;
505   }
506 
507   mSpiFlashInstance = AllocateZeroPool (sizeof (SPI_FLASH_INSTANCE));
508 
509   if (mSpiFlashInstance == NULL) {
510     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
511     return EFI_OUT_OF_RESOURCES;
512   }
513 
514   MvSpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol);
515 
516   mSpiFlashInstance->Signature = SPI_FLASH_SIGNATURE;
517 
518   Status = gBS->InstallMultipleProtocolInterfaces (
519                   &(mSpiFlashInstance->Handle),
520                   &gMarvellSpiFlashProtocolGuid,
521                   &(mSpiFlashInstance->SpiFlashProtocol),
522                   NULL
523                   );
524   if (EFI_ERROR (Status)) {
525     FreePool (mSpiFlashInstance);
526     DEBUG((DEBUG_ERROR, "SpiFlash: Cannot install SPI flash protocol\n"));
527     return EFI_DEVICE_ERROR;
528   }
529 
530   return EFI_SUCCESS;
531 }
532