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