]> git.proxmox.com Git - mirror_edk2.git/blob - QuarkPlatformPkg/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.c
QuarkPlatformPkg/PlatformFlashAccessLib: Add progress API
[mirror_edk2.git] / QuarkPlatformPkg / Feature / Capsule / Library / PlatformFlashAccessLib / PlatformFlashAccessLibDxe.c
1 /** @file
2 Platform Flash Access library.
3
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. 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 #include <PiDxe.h>
16
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/PcdLib.h>
21 #include <Library/PlatformFlashAccessLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Protocol/Spi.h>
24
25 //
26 // SPI default opcode slots
27 //
28 #define SPI_OPCODE_JEDEC_ID_INDEX 0
29 #define SPI_OPCODE_READ_ID_INDEX 1
30 #define SPI_OPCODE_WRITE_S_INDEX 2
31 #define SPI_OPCODE_WRITE_INDEX 3
32 #define SPI_OPCODE_READ_INDEX 4
33 #define SPI_OPCODE_ERASE_INDEX 5
34 #define SPI_OPCODE_READ_S_INDEX 6
35 #define SPI_OPCODE_CHIP_ERASE_INDEX 7
36
37 #define SPI_ERASE_SECTOR_SIZE SIZE_4KB //This is the chipset requirement
38
39 STATIC EFI_PHYSICAL_ADDRESS mInternalFdAddress;
40 EFI_SPI_PROTOCOL *mSpiProtocol;
41
42 /**
43 Writes specified number of bytes from the input buffer to the address
44
45 @param[in] WriteAddress The flash address to be written.
46 @param[in, out] NumBytes The number of bytes.
47 @param[in] Buffer The data buffer to be written.
48
49 @return The status of flash write.
50 **/
51 EFI_STATUS
52 FlashFdWrite (
53 IN UINTN WriteAddress,
54 IN OUT UINTN *NumBytes,
55 IN UINT8 *Buffer
56 )
57 {
58 EFI_STATUS Status;
59
60 Status = EFI_SUCCESS;
61
62 Status = mSpiProtocol->Execute (
63 mSpiProtocol,
64 SPI_OPCODE_WRITE_INDEX, // OpcodeIndex
65 0, // PrefixOpcodeIndex
66 TRUE, // DataCycle
67 TRUE, // Atomic
68 TRUE, // ShiftOut
69 WriteAddress, // Address
70 (UINT32) (*NumBytes), // Data Number
71 Buffer,
72 EnumSpiRegionBios
73 );
74 DEBUG((DEBUG_INFO, "FlashFdWrite - 0x%x - %r\n", (UINTN)WriteAddress, Status));
75
76 AsmWbinvd ();
77
78 return Status;
79 }
80
81 /**
82 Erase a certain block from address LbaWriteAddress
83
84 @param[in] WriteAddress The flash address to be erased.
85
86 @return The status of flash erase.
87 **/
88 EFI_STATUS
89 FlashFdErase (
90 IN UINTN WriteAddress
91 )
92 {
93 EFI_STATUS Status;
94
95 Status = mSpiProtocol->Execute (
96 mSpiProtocol,
97 SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
98 0, // PrefixOpcodeIndex
99 FALSE, // DataCycle
100 TRUE, // Atomic
101 FALSE, // ShiftOut
102 WriteAddress, // Address
103 0, // Data Number
104 NULL,
105 EnumSpiRegionBios // SPI_REGION_TYPE
106 );
107 DEBUG((DEBUG_INFO, "FlashFdErase - 0x%x - %r\n", (UINTN)WriteAddress, Status));
108
109 AsmWbinvd ();
110
111 return Status;
112 }
113
114 /**
115 Perform flash write operation with progress indicator. The start and end
116 completion percentage values are passed into this function. If the requested
117 flash write operation is broken up, then completion percentage between the
118 start and end values may be passed to the provided Progress function. The
119 caller of this function is required to call the Progress function for the
120 start and end completion percentage values. This allows the Progress,
121 StartPercentage, and EndPercentage parameters to be ignored if the requested
122 flash write operation can not be broken up
123
124 @param[in] FirmwareType The type of firmware.
125 @param[in] FlashAddress The address of flash device to be accessed.
126 @param[in] FlashAddressType The type of flash device address.
127 @param[in] Buffer The pointer to the data buffer.
128 @param[in] Length The length of data buffer in bytes.
129 @param[in] Progress A function used report the progress of the
130 firmware update. This is an optional parameter
131 that may be NULL.
132 @param[in] StartPercentage The start completion percentage value that may
133 be used to report progress during the flash
134 write operation.
135 @param[in] EndPercentage The end completion percentage value that may
136 be used to report progress during the flash
137 write operation.
138
139 @retval EFI_SUCCESS The operation returns successfully.
140 @retval EFI_WRITE_PROTECTED The flash device is read only.
141 @retval EFI_UNSUPPORTED The flash device access is unsupported.
142 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
143 **/
144 EFI_STATUS
145 EFIAPI
146 PerformFlashWriteWithProgress (
147 IN PLATFORM_FIRMWARE_TYPE FirmwareType,
148 IN EFI_PHYSICAL_ADDRESS FlashAddress,
149 IN FLASH_ADDRESS_TYPE FlashAddressType,
150 IN VOID *Buffer,
151 IN UINTN Length,
152 IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, OPTIONAL
153 IN UINTN StartPercentage,
154 IN UINTN EndPercentage
155 )
156 {
157 EFI_STATUS Status;
158 UINTN SectorNum;
159 UINTN Index;
160 UINTN NumBytes;
161
162 DEBUG((DEBUG_INFO, "PerformFlashWrite - 0x%x(%x) - 0x%x\n", (UINTN)FlashAddress, (UINTN)FlashAddressType, Length));
163 if (FlashAddressType == FlashAddressTypeAbsoluteAddress) {
164 FlashAddress = FlashAddress - mInternalFdAddress;
165 }
166
167 //
168 // Erase & Write
169 //
170 SectorNum = Length / SPI_ERASE_SECTOR_SIZE;
171 for (Index = 0; Index < SectorNum; Index++){
172 if (Progress != NULL) {
173 Progress (StartPercentage + ((Index * (EndPercentage - StartPercentage)) / SectorNum));
174 }
175
176 if (CompareMem(
177 (UINT8 *)(UINTN)(FlashAddress + mInternalFdAddress) + Index * SPI_ERASE_SECTOR_SIZE,
178 (UINT8 *)Buffer + Index * SPI_ERASE_SECTOR_SIZE,
179 SPI_ERASE_SECTOR_SIZE) == 0) {
180 DEBUG((DEBUG_INFO, "Sector - 0x%x - skip\n", Index));
181 continue;
182 }
183 DEBUG((DEBUG_INFO, "Sector - 0x%x - update...\n", Index));
184
185 Status = FlashFdErase (
186 (UINTN)FlashAddress + Index * SPI_ERASE_SECTOR_SIZE
187 );
188 if (Status != EFI_SUCCESS){
189 break;
190 }
191 NumBytes = SPI_ERASE_SECTOR_SIZE;
192 Status = FlashFdWrite (
193 (UINTN)FlashAddress + Index * SPI_ERASE_SECTOR_SIZE,
194 &NumBytes,
195 (UINT8 *)Buffer + Index * SPI_ERASE_SECTOR_SIZE
196 );
197 if (Status != EFI_SUCCESS){
198 break;
199 }
200 }
201 if (Progress != NULL) {
202 Progress (EndPercentage);
203 }
204
205 return EFI_SUCCESS;
206 }
207
208 /**
209 Perform flash write operation.
210
211 @param[in] FirmwareType The type of firmware.
212 @param[in] FlashAddress The address of flash device to be accessed.
213 @param[in] FlashAddressType The type of flash device address.
214 @param[in] Buffer The pointer to the data buffer.
215 @param[in] Length The length of data buffer in bytes.
216
217 @retval EFI_SUCCESS The operation returns successfully.
218 @retval EFI_WRITE_PROTECTED The flash device is read only.
219 @retval EFI_UNSUPPORTED The flash device access is unsupported.
220 @retval EFI_INVALID_PARAMETER The input parameter is not valid.
221 **/
222 EFI_STATUS
223 EFIAPI
224 PerformFlashWrite (
225 IN PLATFORM_FIRMWARE_TYPE FirmwareType,
226 IN EFI_PHYSICAL_ADDRESS FlashAddress,
227 IN FLASH_ADDRESS_TYPE FlashAddressType,
228 IN VOID *Buffer,
229 IN UINTN Length
230 )
231 {
232 return PerformFlashWriteWithProgress (
233 FirmwareType,
234 FlashAddress,
235 FlashAddressType,
236 Buffer,
237 Length,
238 NULL,
239 0,
240 0
241 );
242 }
243
244 /**
245 Platform Flash Access Lib Constructor.
246
247 @param[in] ImageHandle The firmware allocated handle for the EFI image.
248 @param[in] SystemTable A pointer to the EFI System Table.
249
250 @retval EFI_SUCCESS Constructor returns successfully.
251 **/
252 EFI_STATUS
253 EFIAPI
254 PerformFlashAccessLibConstructor (
255 IN EFI_HANDLE ImageHandle,
256 IN EFI_SYSTEM_TABLE *SystemTable
257 )
258 {
259 EFI_STATUS Status;
260
261 mInternalFdAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32(PcdFlashAreaBaseAddress);
262 DEBUG((DEBUG_INFO, "PcdFlashAreaBaseAddress - 0x%x\n", mInternalFdAddress));
263
264 Status = gBS->LocateProtocol(&gEfiSpiProtocolGuid, NULL, (VOID **)&mSpiProtocol);
265 ASSERT_EFI_ERROR(Status);
266
267 return EFI_SUCCESS;
268 }