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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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