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