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