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