1 /*******************************************************************************
2 Copyright (C) 2016 Marvell International Ltd.
3 
4 SPDX-License-Identifier: BSD-2-Clause-Patent
5 
6 *******************************************************************************/
7 #include "MvSpiOrionDxe.h"
8 
9 SPI_MASTER *mSpiMasterInstance;
10 
11 STATIC
12 EFI_STATUS
13 SpiSetBaudRate (
14   IN SPI_DEVICE *Slave,
15   IN UINT32 CpuClock,
16   IN UINT32 MaxFreq
17   )
18 {
19   UINT32 Spr, BestSpr, Sppr, BestSppr, ClockDivider, Match, Reg, MinBaudDiff;
20   UINTN SpiRegBase = Slave->HostRegisterBaseAddress;
21 
22   MinBaudDiff = 0xFFFFFFFF;
23   BestSppr = 0;
24 
25   //Spr is in range 1-15 and Sppr in range 0-8
26   for (Spr = 1; Spr <= 15; Spr++) {
27     for (Sppr = 0; Sppr <= 7; Sppr++) {
28       ClockDivider = Spr * (1 << Sppr);
29 
30       if ((CpuClock / ClockDivider) > MaxFreq) {
31         continue;
32       }
33 
34       if ((CpuClock / ClockDivider) == MaxFreq) {
35         BestSpr = Spr;
36         BestSppr = Sppr;
37         Match = 1;
38         break;
39         }
40 
41       if ((MaxFreq - (CpuClock / ClockDivider)) < MinBaudDiff) {
42         MinBaudDiff = (MaxFreq - (CpuClock / ClockDivider));
43         BestSpr = Spr;
44         BestSppr = Sppr;
45       }
46     }
47 
48     if (Match == 1) {
49       break;
50     }
51   }
52 
53   if (BestSpr == 0) {
54     return (EFI_INVALID_PARAMETER);
55   }
56 
57   Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
58   Reg &= ~(SPI_SPR_MASK | SPI_SPPR_0_MASK | SPI_SPPR_HI_MASK);
59   Reg |= (BestSpr << SPI_SPR_OFFSET) |
60          ((BestSppr & 0x1) << SPI_SPPR_0_OFFSET) |
61          ((BestSppr >> 1) << SPI_SPPR_HI_OFFSET);
62   MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
63 
64   return EFI_SUCCESS;
65 }
66 
67 STATIC
68 VOID
69 SpiSetCs (
70   IN SPI_DEVICE *Slave
71   )
72 {
73   UINT32 Reg;
74   UINTN  SpiRegBase = Slave->HostRegisterBaseAddress;
75 
76   Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
77   Reg &= ~SPI_CS_NUM_MASK;
78   Reg |= (Slave->Cs << SPI_CS_NUM_OFFSET);
79   MmioWrite32 (SpiRegBase + SPI_CTRL_REG, Reg);
80 }
81 
82 STATIC
83 VOID
84 SpiActivateCs (
85   IN SPI_DEVICE *Slave
86   )
87 {
88   UINT32 Reg;
89   UINTN  SpiRegBase = Slave->HostRegisterBaseAddress;
90 
91   SpiSetCs(Slave);
92   Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
93   Reg |= SPI_CS_EN_MASK;
94   MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
95 }
96 
97 STATIC
98 VOID
99 SpiDeactivateCs (
100   IN SPI_DEVICE *Slave
101   )
102 {
103   UINT32 Reg;
104   UINTN  SpiRegBase = Slave->HostRegisterBaseAddress;
105 
106   Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
107   Reg &= ~SPI_CS_EN_MASK;
108   MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
109 }
110 
111 STATIC
112 VOID
113 SpiSetupTransfer (
114   IN MARVELL_SPI_MASTER_PROTOCOL *This,
115   IN SPI_DEVICE *Slave
116   )
117 {
118   SPI_MASTER *SpiMaster;
119   UINT32 Reg, CoreClock, SpiMaxFreq;
120   UINTN SpiRegBase;
121 
122   SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
123 
124   // Initialize values from PCDs
125   SpiRegBase  = Slave->HostRegisterBaseAddress;
126   CoreClock   = Slave->CoreClock;
127   SpiMaxFreq  = Slave->MaxFreq;
128 
129   EfiAcquireLock (&SpiMaster->Lock);
130 
131   Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
132   Reg |= SPI_BYTE_LENGTH;
133   MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
134 
135   SpiSetCs(Slave);
136 
137   SpiSetBaudRate (Slave, CoreClock, SpiMaxFreq);
138 
139   Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
140   Reg &= ~(SPI_CPOL_MASK | SPI_CPHA_MASK | SPI_TXLSBF_MASK | SPI_RXLSBF_MASK);
141 
142   switch (Slave->Mode) {
143   case SPI_MODE0:
144     break;
145   case SPI_MODE1:
146     Reg |= SPI_CPHA_MASK;
147     break;
148   case SPI_MODE2:
149     Reg |= SPI_CPOL_MASK;
150     break;
151   case SPI_MODE3:
152     Reg |= SPI_CPOL_MASK;
153     Reg |= SPI_CPHA_MASK;
154     break;
155   }
156 
157   MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
158 
159   EfiReleaseLock (&SpiMaster->Lock);
160 }
161 
162 EFI_STATUS
163 EFIAPI
164 MvSpiTransfer (
165   IN MARVELL_SPI_MASTER_PROTOCOL *This,
166   IN SPI_DEVICE *Slave,
167   IN UINTN DataByteCount,
168   IN VOID *DataOut,
169   IN VOID *DataIn,
170   IN UINTN Flag
171   )
172 {
173   SPI_MASTER *SpiMaster;
174   UINT64  Length;
175   UINT32  Iterator, Reg;
176   UINT8   *DataOutPtr = (UINT8 *)DataOut;
177   UINT8   *DataInPtr  = (UINT8 *)DataIn;
178   UINT8   DataToSend  = 0;
179   UINTN   SpiRegBase;
180 
181   SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
182 
183   SpiRegBase = Slave->HostRegisterBaseAddress;
184 
185   Length = 8 * DataByteCount;
186 
187   if (!EfiAtRuntime ()) {
188     EfiAcquireLock (&SpiMaster->Lock);
189   }
190 
191   if (Flag & SPI_TRANSFER_BEGIN) {
192     SpiActivateCs (Slave);
193   }
194 
195   // Set 8-bit mode
196   Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
197   Reg &= ~SPI_BYTE_LENGTH;
198   MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
199 
200   while (Length > 0) {
201     if (DataOut != NULL) {
202       DataToSend = *DataOutPtr & 0xFF;
203     }
204     // Transmit Data
205     MmioWrite32 (SpiRegBase + SPI_INT_CAUSE_REG, 0x0);
206     MmioWrite32 (SpiRegBase + SPI_DATA_OUT_REG, DataToSend);
207     // Wait for memory ready
208     for (Iterator = 0; Iterator < SPI_TIMEOUT; Iterator++) {
209       if (MmioRead32 (SpiRegBase + SPI_INT_CAUSE_REG)) {
210         if (DataInPtr != NULL) {
211           *DataInPtr = MmioRead32 (SpiRegBase + SPI_DATA_IN_REG);
212           DataInPtr++;
213         }
214         if (DataOutPtr != NULL) {
215           DataOutPtr++;
216         }
217         Length -= 8;
218         break;
219       }
220     }
221 
222     if (Iterator >= SPI_TIMEOUT) {
223       DEBUG ((DEBUG_ERROR, "%a: Timeout\n", __FUNCTION__));
224       return EFI_TIMEOUT;
225     }
226   }
227 
228   if (Flag & SPI_TRANSFER_END) {
229     SpiDeactivateCs (Slave);
230   }
231 
232   if (!EfiAtRuntime ()) {
233     EfiReleaseLock (&SpiMaster->Lock);
234   }
235 
236   return EFI_SUCCESS;
237 }
238 
239 EFI_STATUS
240 EFIAPI
241 MvSpiReadWrite (
242   IN  MARVELL_SPI_MASTER_PROTOCOL *This,
243   IN  SPI_DEVICE *Slave,
244   IN  UINT8 *Cmd,
245   IN  UINTN CmdSize,
246   IN  UINT8 *DataOut,
247   OUT UINT8 *DataIn,
248   IN  UINTN DataSize
249   )
250 {
251   EFI_STATUS Status;
252 
253   Status = MvSpiTransfer (This, Slave, CmdSize, Cmd, NULL, SPI_TRANSFER_BEGIN);
254   if (EFI_ERROR (Status)) {
255     Print (L"Spi Transfer Error\n");
256     return EFI_DEVICE_ERROR;
257   }
258 
259   Status = MvSpiTransfer (This, Slave, DataSize, DataOut, DataIn, SPI_TRANSFER_END);
260   if (EFI_ERROR (Status)) {
261     Print (L"Spi Transfer Error\n");
262     return EFI_DEVICE_ERROR;
263   }
264 
265   return EFI_SUCCESS;
266 }
267 
268 EFI_STATUS
269 EFIAPI
270 MvSpiInit (
271   IN MARVELL_SPI_MASTER_PROTOCOL * This
272   )
273 {
274 
275   return EFI_SUCCESS;
276 }
277 
278 SPI_DEVICE *
279 EFIAPI
280 MvSpiSetupSlave (
281   IN MARVELL_SPI_MASTER_PROTOCOL *This,
282   IN SPI_DEVICE *Slave,
283   IN UINTN Cs,
284   IN SPI_MODE Mode
285   )
286 {
287   if (!Slave) {
288     Slave = AllocateZeroPool (sizeof(SPI_DEVICE));
289     if (Slave == NULL) {
290       DEBUG((DEBUG_ERROR, "Cannot allocate memory\n"));
291       return NULL;
292     }
293 
294     Slave->Cs   = Cs;
295     Slave->Mode = Mode;
296   }
297 
298   Slave->HostRegisterBaseAddress = PcdGet32 (PcdSpiRegBase);
299   Slave->CoreClock = PcdGet32 (PcdSpiClockFrequency);
300   Slave->MaxFreq = PcdGet32 (PcdSpiMaxFrequency);
301 
302   SpiSetupTransfer (This, Slave);
303 
304   return Slave;
305 }
306 
307 EFI_STATUS
308 EFIAPI
309 MvSpiFreeSlave (
310   IN SPI_DEVICE *Slave
311   )
312 {
313   FreePool (Slave);
314 
315   return EFI_SUCCESS;
316 }
317 
318 EFI_STATUS
319 EFIAPI
320 MvSpiConfigRuntime (
321   IN SPI_DEVICE *Slave
322   )
323 {
324   EFI_STATUS Status;
325   UINTN AlignedAddress;
326 
327   //
328   // Host register base may be not aligned to the page size,
329   // which is not accepted when setting memory space attributes.
330   // Add one aligned page of memory space which covers the host
331   // controller registers.
332   //
333   AlignedAddress = Slave->HostRegisterBaseAddress & ~(SIZE_4KB - 1);
334 
335   Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo,
336                   AlignedAddress,
337                   SIZE_4KB,
338                   EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
339   if (EFI_ERROR (Status)) {
340     DEBUG ((DEBUG_ERROR, "%a: Failed to add memory space\n", __FUNCTION__));
341     return Status;
342   }
343 
344   Status = gDS->SetMemorySpaceAttributes (AlignedAddress,
345                   SIZE_4KB,
346                   EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
347   if (EFI_ERROR (Status)) {
348     DEBUG ((DEBUG_ERROR, "%a: Failed to set memory attributes\n", __FUNCTION__));
349     gDS->RemoveMemorySpace (AlignedAddress, SIZE_4KB);
350     return Status;
351   }
352 
353   return EFI_SUCCESS;
354 }
355 
356 STATIC
357 EFI_STATUS
358 SpiMasterInitProtocol (
359   IN MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol
360   )
361 {
362 
363   SpiMasterProtocol->Init        = MvSpiInit;
364   SpiMasterProtocol->SetupDevice = MvSpiSetupSlave;
365   SpiMasterProtocol->FreeDevice  = MvSpiFreeSlave;
366   SpiMasterProtocol->Transfer    = MvSpiTransfer;
367   SpiMasterProtocol->ReadWrite   = MvSpiReadWrite;
368   SpiMasterProtocol->ConfigRuntime = MvSpiConfigRuntime;
369 
370   return EFI_SUCCESS;
371 }
372 
373 EFI_STATUS
374 EFIAPI
375 MvSpiOrionEntryPoint (
376   IN EFI_HANDLE       ImageHandle,
377   IN EFI_SYSTEM_TABLE *SystemTable
378   )
379 {
380   EFI_STATUS  Status;
381 
382   mSpiMasterInstance = AllocateRuntimeZeroPool (sizeof (SPI_MASTER));
383   if (mSpiMasterInstance == NULL) {
384     return EFI_OUT_OF_RESOURCES;
385   }
386 
387   EfiInitializeLock (&mSpiMasterInstance->Lock, TPL_NOTIFY);
388 
389   SpiMasterInitProtocol (&mSpiMasterInstance->SpiMasterProtocol);
390 
391   mSpiMasterInstance->Signature = SPI_MASTER_SIGNATURE;
392 
393   Status = gBS->InstallMultipleProtocolInterfaces (
394                   &(mSpiMasterInstance->Handle),
395                   &gMarvellSpiMasterProtocolGuid,
396                   &(mSpiMasterInstance->SpiMasterProtocol),
397                   NULL
398                   );
399   if (EFI_ERROR (Status)) {
400     FreePool (mSpiMasterInstance);
401     return EFI_DEVICE_ERROR;
402   }
403 
404   return EFI_SUCCESS;
405 }
406