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
35 #include <Protocol/DriverBinding.h>
36 #include <Protocol/I2cIo.h>
37 #include <Protocol/Eeprom.h>
38
39 #include <Library/BaseLib.h>
40 #include <Library/BaseMemoryLib.h>
41 #include <Library/MemoryAllocationLib.h>
42 #include <Library/IoLib.h>
43 #include <Library/DebugLib.h>
44 #include <Library/PcdLib.h>
45 #include <Library/UefiLib.h>
46 #include <Library/UefiBootServicesTableLib.h>
47
48 #include <Pi/PiI2c.h>
49
50 #include "MvEeprom.h"
51
52 #define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16)
53
54 STATIC CONST EFI_GUID I2cGuid = I2C_GUID;
55
56 EFI_DRIVER_BINDING_PROTOCOL gDriverBindingProtocol = {
57 MvEepromSupported,
58 MvEepromStart,
59 MvEepromStop
60 };
61
62 EFI_STATUS
63 EFIAPI
MvEepromSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)64 MvEepromSupported (
65 IN EFI_DRIVER_BINDING_PROTOCOL *This,
66 IN EFI_HANDLE ControllerHandle,
67 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
68 )
69 {
70 EFI_STATUS Status = EFI_UNSUPPORTED;
71 EFI_I2C_IO_PROTOCOL *TmpI2cIo;
72 UINT8 *EepromAddresses;
73 UINT8 *EepromBuses;
74 UINTN i;
75
76 Status = gBS->OpenProtocol (
77 ControllerHandle,
78 &gEfiI2cIoProtocolGuid,
79 (VOID **) &TmpI2cIo,
80 gImageHandle,
81 ControllerHandle,
82 EFI_OPEN_PROTOCOL_BY_DRIVER
83 );
84 if (EFI_ERROR(Status)) {
85 return EFI_UNSUPPORTED;
86 }
87
88 /* get EEPROM devices' addresses from PCD */
89 EepromAddresses = PcdGetPtr (PcdEepromI2cAddresses);
90 EepromBuses = PcdGetPtr (PcdEepromI2cBuses);
91 if (EepromAddresses == 0) {
92 Status = EFI_UNSUPPORTED;
93 DEBUG((DEBUG_INFO, "MvEepromSupported: I2C device found, but it's not EEPROM\n"));
94 goto out;
95 }
96
97 Status = EFI_UNSUPPORTED;
98 for (i = 0; EepromAddresses[i] != '\0'; i++) {
99 /* I2C guid must fit and valid DeviceIndex must be provided */
100 if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) &&
101 TmpI2cIo->DeviceIndex == I2C_DEVICE_INDEX(EepromBuses[i],
102 EepromAddresses[i])) {
103 DEBUG((DEBUG_INFO, "MvEepromSupported: attached to EEPROM device\n"));
104 Status = EFI_SUCCESS;
105 break;
106 }
107 }
108
109 out:
110 gBS->CloseProtocol (
111 ControllerHandle,
112 &gEfiI2cIoProtocolGuid,
113 gImageHandle,
114 ControllerHandle
115 );
116 return Status;
117 }
118
119 EFI_STATUS
120 EFIAPI
MvEepromTransfer(IN CONST MARVELL_EEPROM_PROTOCOL * This,IN UINT16 Address,IN UINT32 Length,IN UINT8 * Buffer,IN UINT8 Operation)121 MvEepromTransfer (
122 IN CONST MARVELL_EEPROM_PROTOCOL *This,
123 IN UINT16 Address,
124 IN UINT32 Length,
125 IN UINT8 *Buffer,
126 IN UINT8 Operation
127 )
128 {
129 EFI_I2C_REQUEST_PACKET *RequestPacket;
130 UINTN RequestPacketSize;
131 EFI_STATUS Status = EFI_SUCCESS;
132 EEPROM_CONTEXT *EepromContext = EEPROM_SC_FROM_EEPROM(This);
133 UINT32 BufferLength;
134 UINT32 Transmitted = 0;
135 UINT32 CurrentAddress = Address;
136
137 ASSERT(EepromContext != NULL);
138 ASSERT(EepromContext->I2cIo != NULL);
139
140 RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION) * 2;
141 RequestPacket = AllocateZeroPool (RequestPacketSize);
142 if (RequestPacket == NULL)
143 return EFI_OUT_OF_RESOURCES;
144 /* First operation contains address, the second is buffer */
145 RequestPacket->OperationCount = 2;
146 RequestPacket->Operation[0].LengthInBytes = 2;
147 RequestPacket->Operation[0].Buffer = AllocateZeroPool ( RequestPacket->Operation[0].LengthInBytes );
148 if (RequestPacket->Operation[0].Buffer == NULL) {
149 FreePool(RequestPacket);
150 return EFI_OUT_OF_RESOURCES;
151 }
152 RequestPacket->Operation[1].Flags = (Operation == EEPROM_READ ? I2C_FLAG_READ : I2C_FLAG_NORESTART);
153
154 while (Length > 0) {
155 CurrentAddress = Address + Transmitted;
156 BufferLength = (Length <= MAX_BUFFER_LENGTH ? Length : MAX_BUFFER_LENGTH);
157 RequestPacket->Operation[0].Buffer[0] = (CurrentAddress >> 8) & 0xff;
158 RequestPacket->Operation[0].Buffer[1] = CurrentAddress & 0xff;
159 RequestPacket->Operation[1].LengthInBytes = BufferLength;
160 RequestPacket->Operation[1].Buffer = Buffer + Transmitted;
161 Status = EepromContext->I2cIo->QueueRequest(EepromContext->I2cIo, 0, NULL, RequestPacket, NULL);
162 if (EFI_ERROR(Status)) {
163 DEBUG((DEBUG_ERROR, "MvEepromTransfer: error %d during transmission\n", Status));
164 break;
165 }
166 Length -= BufferLength;
167 Transmitted += BufferLength;
168 }
169
170 FreePool(RequestPacket->Operation[0].Buffer);
171 FreePool(RequestPacket);
172 return Status;
173 }
174
175 EFI_STATUS
176 EFIAPI
MvEepromStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)177 MvEepromStart (
178 IN EFI_DRIVER_BINDING_PROTOCOL *This,
179 IN EFI_HANDLE ControllerHandle,
180 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
181 )
182 {
183 EFI_STATUS Status = EFI_SUCCESS;
184 EEPROM_CONTEXT *EepromContext;
185
186 EepromContext = AllocateZeroPool (sizeof(EEPROM_CONTEXT));
187 if (EepromContext == NULL) {
188 DEBUG((DEBUG_ERROR, "MvEeprom: allocation fail\n"));
189 return EFI_OUT_OF_RESOURCES;
190 }
191
192 EepromContext->ControllerHandle = ControllerHandle;
193 EepromContext->Signature = EEPROM_SIGNATURE;
194 EepromContext->EepromProtocol.Transfer = MvEepromTransfer;
195
196 Status = gBS->OpenProtocol (
197 ControllerHandle,
198 &gEfiI2cIoProtocolGuid,
199 (VOID **) &EepromContext->I2cIo,
200 gImageHandle,
201 ControllerHandle,
202 EFI_OPEN_PROTOCOL_BY_DRIVER
203 );
204 if (EFI_ERROR(Status)) {
205 DEBUG((DEBUG_ERROR, "MvEeprom: failed to open I2cIo\n"));
206 FreePool(EepromContext);
207 return EFI_UNSUPPORTED;
208 }
209
210 EepromContext->EepromProtocol.Identifier = EepromContext->I2cIo->DeviceIndex;
211 Status = gBS->InstallMultipleProtocolInterfaces (
212 &ControllerHandle,
213 &gMarvellEepromProtocolGuid, &EepromContext->EepromProtocol,
214 NULL
215 );
216 if (EFI_ERROR(Status)) {
217 DEBUG((DEBUG_ERROR, "MvEeprom: failed to install EEPROM protocol\n"));
218 goto fail;
219 }
220
221 return Status;
222
223 fail:
224 FreePool(EepromContext);
225 gBS->CloseProtocol (
226 ControllerHandle,
227 &gEfiI2cIoProtocolGuid,
228 gImageHandle,
229 ControllerHandle
230 );
231
232 return Status;
233 }
234
235 EFI_STATUS
236 EFIAPI
MvEepromStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)237 MvEepromStop (
238 IN EFI_DRIVER_BINDING_PROTOCOL *This,
239 IN EFI_HANDLE ControllerHandle,
240 IN UINTN NumberOfChildren,
241 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
242 )
243 {
244 MARVELL_EEPROM_PROTOCOL *EepromProtocol;
245 EFI_STATUS Status;
246 EEPROM_CONTEXT *EepromContext;
247
248 Status = gBS->OpenProtocol (
249 ControllerHandle,
250 &gMarvellEepromProtocolGuid,
251 (VOID **) &EepromProtocol,
252 This->DriverBindingHandle,
253 ControllerHandle,
254 EFI_OPEN_PROTOCOL_GET_PROTOCOL
255 );
256
257 if (EFI_ERROR (Status)) {
258 return EFI_DEVICE_ERROR;
259 }
260 EepromContext = EEPROM_SC_FROM_EEPROM(EepromProtocol);
261
262 gBS->UninstallMultipleProtocolInterfaces (
263 &ControllerHandle,
264 &gMarvellEepromProtocolGuid, &EepromContext->EepromProtocol,
265 &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol,
266 NULL
267 );
268 gBS->CloseProtocol (
269 ControllerHandle,
270 &gEfiI2cIoProtocolGuid,
271 gImageHandle,
272 ControllerHandle
273 );
274 FreePool(EepromContext);
275 return EFI_SUCCESS;
276 }
277
278 EFI_STATUS
279 EFIAPI
MvEepromInitialise(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)280 MvEepromInitialise (
281 IN EFI_HANDLE ImageHandle,
282 IN EFI_SYSTEM_TABLE *SystemTable
283 )
284 {
285 EFI_STATUS Status;
286 Status = gBS->InstallMultipleProtocolInterfaces (
287 &ImageHandle,
288 &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol,
289 NULL
290 );
291 return Status;
292 }
293