1 /** @file 2 * 3 * Copyright (c) 2020, Pete Batard <pete@akeo.ie> 4 * Copyright (c) 2019, ARM Limited. All rights reserved. 5 * Copyright (c) 2017-2020, Andrei Warkentin <andrey.warkentin@gmail.com> 6 * Copyright (c) 2016, Linaro, Ltd. All rights reserved. 7 * 8 * SPDX-License-Identifier: BSD-2-Clause-Patent 9 * 10 **/ 11 12 #include <PiDxe.h> 13 14 #include <Library/ArmLib.h> 15 #include <Library/DmaLib.h> 16 #include <Library/BaseLib.h> 17 #include <Library/BaseMemoryLib.h> 18 #include <Library/DebugLib.h> 19 #include <Library/IoLib.h> 20 #include <Library/SynchronizationLib.h> 21 #include <Library/UefiBootServicesTableLib.h> 22 #include <Library/UefiLib.h> 23 24 #include <IndustryStandard/Bcm2836.h> 25 #include <IndustryStandard/RpiMbox.h> 26 27 #include <Protocol/RpiFirmware.h> 28 29 // 30 // The number of statically allocated buffer pages 31 // 32 #define NUM_PAGES 1 33 34 STATIC VOID *mDmaBuffer; 35 STATIC VOID *mDmaBufferMapping; 36 STATIC UINTN mDmaBufferBusAddress; 37 38 STATIC SPIN_LOCK mMailboxLock; 39 40 STATIC 41 BOOLEAN 42 DrainMailbox ( 43 VOID 44 ) 45 { 46 INTN Tries; 47 UINT32 Val; 48 49 // 50 // Get rid of stale response data in the mailbox 51 // 52 Tries = 0; 53 do { 54 Val = MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_STATUS_OFFSET); 55 if (Val & (1U << BCM2836_MBOX_STATUS_EMPTY)) { 56 return TRUE; 57 } 58 ArmDataSynchronizationBarrier (); 59 MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_READ_OFFSET); 60 } while (++Tries < RPI_MBOX_MAX_TRIES); 61 62 return FALSE; 63 } 64 65 STATIC 66 BOOLEAN 67 MailboxWaitForStatusCleared ( 68 IN UINTN StatusMask 69 ) 70 { 71 INTN Tries; 72 UINT32 Val; 73 74 // 75 // Get rid of stale response data in the mailbox 76 // 77 Tries = 0; 78 do { 79 Val = MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_STATUS_OFFSET); 80 if ((Val & StatusMask) == 0) { 81 return TRUE; 82 } 83 ArmDataSynchronizationBarrier (); 84 } while (++Tries < RPI_MBOX_MAX_TRIES); 85 86 return FALSE; 87 } 88 89 STATIC 90 EFI_STATUS 91 MailboxTransaction ( 92 IN UINTN Length, 93 IN UINTN Channel, 94 OUT UINT32 *Result 95 ) 96 { 97 if (Channel >= BCM2836_MBOX_NUM_CHANNELS) { 98 return EFI_INVALID_PARAMETER; 99 } 100 101 // 102 // Get rid of stale response data in the mailbox 103 // 104 if (!DrainMailbox ()) { 105 DEBUG ((DEBUG_ERROR, "%a: timeout waiting for mailbox to drain\n", 106 __FUNCTION__)); 107 return EFI_TIMEOUT; 108 } 109 110 // 111 // Wait for the 'output register full' bit to become clear 112 // 113 if (!MailboxWaitForStatusCleared (1U << BCM2836_MBOX_STATUS_FULL)) { 114 DEBUG ((DEBUG_ERROR, "%a: timeout waiting for outbox to become empty\n", 115 __FUNCTION__)); 116 return EFI_TIMEOUT; 117 } 118 119 ArmDataSynchronizationBarrier (); 120 121 // 122 // Start the mailbox transaction 123 // 124 MmioWrite32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_WRITE_OFFSET, 125 (UINT32)((UINTN)mDmaBufferBusAddress | Channel)); 126 127 ArmDataSynchronizationBarrier (); 128 129 // 130 // Wait for the 'input register empty' bit to clear 131 // 132 if (!MailboxWaitForStatusCleared (1U << BCM2836_MBOX_STATUS_EMPTY)) { 133 DEBUG ((DEBUG_ERROR, "%a: timeout waiting for inbox to become full\n", 134 __FUNCTION__)); 135 return EFI_TIMEOUT; 136 } 137 138 // 139 // Read back the result 140 // 141 ArmDataSynchronizationBarrier (); 142 *Result = MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_READ_OFFSET); 143 ArmDataSynchronizationBarrier (); 144 145 return EFI_SUCCESS; 146 } 147 148 #pragma pack(1) 149 typedef struct { 150 UINT32 BufferSize; 151 UINT32 Response; 152 } RPI_FW_BUFFER_HEAD; 153 154 typedef struct { 155 UINT32 TagId; 156 UINT32 TagSize; 157 UINT32 TagValueSize; 158 } RPI_FW_TAG_HEAD; 159 160 typedef struct { 161 UINT32 DeviceId; 162 UINT32 PowerState; 163 } RPI_FW_POWER_STATE_TAG; 164 165 typedef struct { 166 RPI_FW_BUFFER_HEAD BufferHead; 167 RPI_FW_TAG_HEAD TagHead; 168 RPI_FW_POWER_STATE_TAG TagBody; 169 UINT32 EndTag; 170 } RPI_FW_SET_POWER_STATE_CMD; 171 #pragma pack() 172 173 STATIC 174 EFI_STATUS 175 EFIAPI 176 RpiFirmwareSetPowerState ( 177 IN UINT32 DeviceId, 178 IN BOOLEAN PowerState, 179 IN BOOLEAN Wait 180 ) 181 { 182 RPI_FW_SET_POWER_STATE_CMD *Cmd; 183 EFI_STATUS Status; 184 UINT32 Result; 185 186 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 187 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 188 return EFI_DEVICE_ERROR; 189 } 190 191 Cmd = mDmaBuffer; 192 ZeroMem (Cmd, sizeof (*Cmd)); 193 194 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 195 Cmd->BufferHead.Response = 0; 196 Cmd->TagHead.TagId = RPI_MBOX_SET_POWER_STATE; 197 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 198 Cmd->TagHead.TagValueSize = 0; 199 Cmd->TagBody.DeviceId = DeviceId; 200 Cmd->TagBody.PowerState = (PowerState ? RPI_MBOX_POWER_STATE_ENABLE : 0) | 201 (Wait ? RPI_MBOX_POWER_STATE_WAIT : 0); 202 Cmd->EndTag = 0; 203 204 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 205 206 ReleaseSpinLock (&mMailboxLock); 207 208 if (EFI_ERROR (Status) || 209 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 210 DEBUG ((DEBUG_ERROR, 211 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 212 __FUNCTION__, Status, Cmd->BufferHead.Response)); 213 Status = EFI_DEVICE_ERROR; 214 } 215 216 if (!EFI_ERROR (Status) && 217 PowerState ^ (Cmd->TagBody.PowerState & RPI_MBOX_POWER_STATE_ENABLE)) { 218 DEBUG ((DEBUG_ERROR, "%a: failed to %sable power for device %d\n", 219 __FUNCTION__, PowerState ? "en" : "dis", DeviceId)); 220 Status = EFI_DEVICE_ERROR; 221 } 222 223 return Status; 224 } 225 226 #pragma pack() 227 typedef struct { 228 UINT32 Base; 229 UINT32 Size; 230 } RPI_FW_ARM_MEMORY_TAG; 231 232 typedef struct { 233 RPI_FW_BUFFER_HEAD BufferHead; 234 RPI_FW_TAG_HEAD TagHead; 235 RPI_FW_ARM_MEMORY_TAG TagBody; 236 UINT32 EndTag; 237 } RPI_FW_GET_ARM_MEMORY_CMD; 238 #pragma pack() 239 240 STATIC 241 EFI_STATUS 242 EFIAPI 243 RpiFirmwareGetArmMemory ( 244 OUT UINT32 *Base, 245 OUT UINT32 *Size 246 ) 247 { 248 RPI_FW_GET_ARM_MEMORY_CMD *Cmd; 249 EFI_STATUS Status; 250 UINT32 Result; 251 252 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 253 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 254 return EFI_DEVICE_ERROR; 255 } 256 257 Cmd = mDmaBuffer; 258 ZeroMem (Cmd, sizeof (*Cmd)); 259 260 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 261 Cmd->BufferHead.Response = 0; 262 Cmd->TagHead.TagId = RPI_MBOX_GET_ARM_MEMSIZE; 263 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 264 Cmd->TagHead.TagValueSize = 0; 265 Cmd->EndTag = 0; 266 267 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 268 269 ReleaseSpinLock (&mMailboxLock); 270 271 if (EFI_ERROR (Status) || 272 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 273 DEBUG ((DEBUG_ERROR, 274 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 275 __FUNCTION__, Status, Cmd->BufferHead.Response)); 276 return EFI_DEVICE_ERROR; 277 } 278 279 *Base = Cmd->TagBody.Base; 280 *Size = Cmd->TagBody.Size; 281 return EFI_SUCCESS; 282 } 283 284 #pragma pack() 285 typedef struct { 286 UINT8 MacAddress[6]; 287 UINT32 Padding; 288 } RPI_FW_MAC_ADDR_TAG; 289 290 typedef struct { 291 RPI_FW_BUFFER_HEAD BufferHead; 292 RPI_FW_TAG_HEAD TagHead; 293 RPI_FW_MAC_ADDR_TAG TagBody; 294 UINT32 EndTag; 295 } RPI_FW_GET_MAC_ADDR_CMD; 296 #pragma pack() 297 298 STATIC 299 EFI_STATUS 300 EFIAPI 301 RpiFirmwareGetMacAddress ( 302 OUT UINT8 MacAddress[6] 303 ) 304 { 305 RPI_FW_GET_MAC_ADDR_CMD *Cmd; 306 EFI_STATUS Status; 307 UINT32 Result; 308 309 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 310 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 311 return EFI_DEVICE_ERROR; 312 } 313 314 Cmd = mDmaBuffer; 315 ZeroMem (Cmd, sizeof (*Cmd)); 316 317 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 318 Cmd->BufferHead.Response = 0; 319 Cmd->TagHead.TagId = RPI_MBOX_GET_MAC_ADDRESS; 320 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 321 Cmd->TagHead.TagValueSize = 0; 322 Cmd->EndTag = 0; 323 324 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 325 326 ReleaseSpinLock (&mMailboxLock); 327 328 if (EFI_ERROR (Status) || 329 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 330 DEBUG ((DEBUG_ERROR, 331 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 332 __FUNCTION__, Status, Cmd->BufferHead.Response)); 333 return EFI_DEVICE_ERROR; 334 } 335 336 CopyMem (MacAddress, Cmd->TagBody.MacAddress, sizeof (Cmd->TagBody.MacAddress)); 337 return EFI_SUCCESS; 338 } 339 340 #pragma pack() 341 typedef struct { 342 UINT64 Serial; 343 } RPI_FW_SERIAL_TAG; 344 345 typedef struct { 346 RPI_FW_BUFFER_HEAD BufferHead; 347 RPI_FW_TAG_HEAD TagHead; 348 RPI_FW_SERIAL_TAG TagBody; 349 UINT32 EndTag; 350 } RPI_FW_GET_SERIAL_CMD; 351 #pragma pack() 352 353 STATIC 354 EFI_STATUS 355 EFIAPI 356 RpiFirmwareGetSerial ( 357 OUT UINT64 *Serial 358 ) 359 { 360 RPI_FW_GET_SERIAL_CMD *Cmd; 361 EFI_STATUS Status; 362 UINT32 Result; 363 364 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 365 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 366 return EFI_DEVICE_ERROR; 367 } 368 369 Cmd = mDmaBuffer; 370 ZeroMem (Cmd, sizeof (*Cmd)); 371 372 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 373 Cmd->BufferHead.Response = 0; 374 Cmd->TagHead.TagId = RPI_MBOX_GET_BOARD_SERIAL; 375 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 376 Cmd->TagHead.TagValueSize = 0; 377 Cmd->EndTag = 0; 378 379 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 380 381 ReleaseSpinLock (&mMailboxLock); 382 383 if (EFI_ERROR (Status) || 384 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 385 DEBUG ((DEBUG_ERROR, 386 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 387 __FUNCTION__, Status, Cmd->BufferHead.Response)); 388 return EFI_DEVICE_ERROR; 389 } 390 391 *Serial = Cmd->TagBody.Serial; 392 // Some platforms return 0 or 0x0000000010000000 for serial. 393 // For those, try to use the MAC address. 394 if ((*Serial == 0) || ((*Serial & 0xFFFFFFFF0FFFFFFFULL) == 0)) { 395 Status = RpiFirmwareGetMacAddress ((UINT8*) Serial); 396 // Convert to a more user-friendly value 397 *Serial = SwapBytes64 (*Serial << 16); 398 } 399 400 return Status; 401 } 402 403 #pragma pack() 404 typedef struct { 405 UINT32 Model; 406 } RPI_FW_MODEL_TAG; 407 408 typedef struct { 409 RPI_FW_BUFFER_HEAD BufferHead; 410 RPI_FW_TAG_HEAD TagHead; 411 RPI_FW_MODEL_TAG TagBody; 412 UINT32 EndTag; 413 } RPI_FW_GET_MODEL_CMD; 414 #pragma pack() 415 416 STATIC 417 EFI_STATUS 418 EFIAPI 419 RpiFirmwareGetModel ( 420 OUT UINT32 *Model 421 ) 422 { 423 RPI_FW_GET_MODEL_CMD *Cmd; 424 EFI_STATUS Status; 425 UINT32 Result; 426 427 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 428 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 429 return EFI_DEVICE_ERROR; 430 } 431 432 Cmd = mDmaBuffer; 433 ZeroMem (Cmd, sizeof (*Cmd)); 434 435 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 436 Cmd->BufferHead.Response = 0; 437 Cmd->TagHead.TagId = RPI_MBOX_GET_BOARD_MODEL; 438 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 439 Cmd->TagHead.TagValueSize = 0; 440 Cmd->EndTag = 0; 441 442 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 443 444 ReleaseSpinLock (&mMailboxLock); 445 446 if (EFI_ERROR (Status) || 447 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 448 DEBUG ((DEBUG_ERROR, 449 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 450 __FUNCTION__, Status, Cmd->BufferHead.Response)); 451 return EFI_DEVICE_ERROR; 452 } 453 454 *Model = Cmd->TagBody.Model; 455 return EFI_SUCCESS; 456 } 457 458 #pragma pack() 459 typedef struct { 460 UINT32 Revision; 461 } RPI_FW_MODEL_REVISION_TAG; 462 463 typedef struct { 464 RPI_FW_BUFFER_HEAD BufferHead; 465 RPI_FW_TAG_HEAD TagHead; 466 RPI_FW_MODEL_REVISION_TAG TagBody; 467 UINT32 EndTag; 468 } RPI_FW_GET_REVISION_CMD; 469 #pragma pack() 470 471 STATIC 472 EFI_STATUS 473 EFIAPI 474 RpiFirmwareGetModelRevision ( 475 OUT UINT32 *Revision 476 ) 477 { 478 RPI_FW_GET_REVISION_CMD *Cmd; 479 EFI_STATUS Status; 480 UINT32 Result; 481 482 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 483 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 484 return EFI_DEVICE_ERROR; 485 } 486 487 Cmd = mDmaBuffer; 488 ZeroMem (Cmd, sizeof (*Cmd)); 489 490 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 491 Cmd->BufferHead.Response = 0; 492 Cmd->TagHead.TagId = RPI_MBOX_GET_BOARD_REVISION; 493 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 494 Cmd->TagHead.TagValueSize = 0; 495 Cmd->EndTag = 0; 496 497 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 498 499 ReleaseSpinLock (&mMailboxLock); 500 501 if (EFI_ERROR (Status) || 502 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 503 DEBUG ((DEBUG_ERROR, 504 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 505 __FUNCTION__, Status, Cmd->BufferHead.Response)); 506 return EFI_DEVICE_ERROR; 507 } 508 509 *Revision = Cmd->TagBody.Revision; 510 return EFI_SUCCESS; 511 } 512 513 STATIC 514 EFI_STATUS 515 EFIAPI 516 RpiFirmwareGetFirmwareRevision ( 517 OUT UINT32 *Revision 518 ) 519 { 520 RPI_FW_GET_REVISION_CMD *Cmd; 521 EFI_STATUS Status; 522 UINT32 Result; 523 524 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 525 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 526 return EFI_DEVICE_ERROR; 527 } 528 529 Cmd = mDmaBuffer; 530 ZeroMem (Cmd, sizeof (*Cmd)); 531 532 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 533 Cmd->BufferHead.Response = 0; 534 Cmd->TagHead.TagId = RPI_MBOX_GET_REVISION; 535 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 536 Cmd->TagHead.TagValueSize = 0; 537 Cmd->EndTag = 0; 538 539 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 540 541 ReleaseSpinLock (&mMailboxLock); 542 543 if (EFI_ERROR (Status) || 544 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 545 DEBUG ((DEBUG_ERROR, 546 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 547 __FUNCTION__, Status, Cmd->BufferHead.Response)); 548 return EFI_DEVICE_ERROR; 549 } 550 551 *Revision = Cmd->TagBody.Revision; 552 return EFI_SUCCESS; 553 } 554 555 STATIC 556 CHAR8* 557 EFIAPI 558 RpiFirmwareGetModelName ( 559 IN INTN ModelId 560 ) 561 { 562 UINT32 Revision; 563 564 // If a negative ModelId is passed, detect it. 565 if ((ModelId < 0) && (RpiFirmwareGetModelRevision (&Revision) == EFI_SUCCESS)) { 566 ModelId = (Revision >> 4) & 0xFF; 567 } 568 569 switch (ModelId) { 570 // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md 571 case 0x00: 572 return "Raspberry Pi Model A"; 573 case 0x01: 574 return "Raspberry Pi Model B"; 575 case 0x02: 576 return "Raspberry Pi Model A+"; 577 case 0x03: 578 return "Raspberry Pi Model B+"; 579 case 0x04: 580 return "Raspberry Pi 2 Model B"; 581 case 0x06: 582 return "Raspberry Pi Compute Module 1"; 583 case 0x08: 584 return "Raspberry Pi 3 Model B"; 585 case 0x09: 586 return "Raspberry Pi Zero"; 587 case 0x0A: 588 return "Raspberry Pi Compute Module 3"; 589 case 0x0C: 590 return "Raspberry Pi Zero W"; 591 case 0x0D: 592 return "Raspberry Pi 3 Model B+"; 593 case 0x0E: 594 return "Raspberry Pi 3 Model A+"; 595 case 0x10: 596 return "Raspberry Pi Compute Module 3+"; 597 case 0x11: 598 return "Raspberry Pi 4 Model B"; 599 case 0x13: 600 return "Raspberry Pi 400"; 601 case 0x14: 602 return "Raspberry Pi Compute Module 4"; 603 default: 604 return "Unknown Raspberry Pi Model"; 605 } 606 } 607 608 STATIC 609 EFI_STATUS 610 EFIAPI 611 RPiFirmwareGetModelInstalledMB ( 612 OUT UINT32 *InstalledMB 613 ) 614 { 615 EFI_STATUS Status; 616 UINT32 Revision; 617 618 Status = RpiFirmwareGetModelRevision(&Revision); 619 if (EFI_ERROR(Status)) { 620 DEBUG ((DEBUG_ERROR, "%a: Could not get the board revision: Status == %r\n", 621 __FUNCTION__, Status)); 622 return EFI_DEVICE_ERROR; 623 } 624 625 // 626 // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md 627 // Bits [20-22] indicate the amount of memory starting with 256MB (000b) 628 // and doubling in size for each value (001b = 512 MB, 010b = 1GB, etc.) 629 // 630 *InstalledMB = 256 << ((Revision >> 20) & 0x07); 631 return EFI_SUCCESS; 632 } 633 634 STATIC 635 EFI_STATUS 636 EFIAPI 637 RPiFirmwareGetModelFamily ( 638 OUT UINT32 *ModelFamily 639 ) 640 { 641 EFI_STATUS Status; 642 UINT32 Revision; 643 UINT32 ModelId; 644 645 Status = RpiFirmwareGetModelRevision(&Revision); 646 if (EFI_ERROR(Status)) { 647 DEBUG ((DEBUG_ERROR, 648 "%a: Could not get the board revision: Status == %r\n", 649 __FUNCTION__, Status)); 650 return EFI_DEVICE_ERROR; 651 } else { 652 ModelId = (Revision >> 4) & 0xFF; 653 } 654 655 switch (ModelId) { 656 // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md 657 case 0x00: // Raspberry Pi Model A 658 case 0x01: // Raspberry Pi Model B 659 case 0x02: // Raspberry Pi Model A+ 660 case 0x03: // Raspberry Pi Model B+ 661 case 0x06: // Raspberry Pi Compute Module 1 662 case 0x09: // Raspberry Pi Zero 663 case 0x0C: // Raspberry Pi Zero W 664 *ModelFamily = 1; 665 break; 666 case 0x04: // Raspberry Pi 2 Model B 667 *ModelFamily = 2; 668 break; 669 case 0x08: // Raspberry Pi 3 Model B 670 case 0x0A: // Raspberry Pi Compute Module 3 671 case 0x0D: // Raspberry Pi 3 Model B+ 672 case 0x0E: // Raspberry Pi 3 Model A+ 673 case 0x10: // Raspberry Pi Compute Module 3+ 674 *ModelFamily = 3; 675 break; 676 case 0x11: // Raspberry Pi 4 Model B 677 case 0x13: // Raspberry Pi 400 678 case 0x14: // Raspberry Pi Computer Module 4 679 *ModelFamily = 4; 680 break; 681 default: 682 *ModelFamily = 0; 683 break; 684 } 685 686 if (*ModelFamily == 0) { 687 DEBUG ((DEBUG_ERROR, 688 "%a: Unknown Raspberry Pi model family : ModelId == 0x%x\n", 689 __FUNCTION__, ModelId)); 690 return EFI_UNSUPPORTED; 691 } 692 693 return EFI_SUCCESS; 694 } 695 696 STATIC 697 CHAR8* 698 EFIAPI 699 RpiFirmwareGetManufacturerName ( 700 IN INTN ManufacturerId 701 ) 702 { 703 UINT32 Revision; 704 705 // If a negative ModelId is passed, detect it. 706 if ((ManufacturerId < 0) && (RpiFirmwareGetModelRevision (&Revision) == EFI_SUCCESS)) { 707 ManufacturerId = (Revision >> 16) & 0x0F; 708 } 709 710 switch (ManufacturerId) { 711 // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md 712 case 0x00: 713 return "Sony UK"; 714 case 0x01: 715 return "Egoman"; 716 case 0x02: 717 case 0x04: 718 return "Embest"; 719 case 0x03: 720 return "Sony Japan"; 721 case 0x05: 722 return "Stadium"; 723 default: 724 return "Unknown Manufacturer"; 725 } 726 } 727 728 STATIC 729 CHAR8* 730 EFIAPI 731 RpiFirmwareGetCpuName ( 732 IN INTN CpuId 733 ) 734 { 735 UINT32 Revision; 736 737 // If a negative CpuId is passed, detect it. 738 if ((CpuId < 0) && (RpiFirmwareGetModelRevision (&Revision) == EFI_SUCCESS)) { 739 CpuId = (Revision >> 12) & 0x0F; 740 } 741 742 switch (CpuId) { 743 // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md 744 case 0x00: 745 return "BCM2835 (ARM11)"; 746 case 0x01: 747 return "BCM2836 (ARM Cortex-A7)"; 748 case 0x02: 749 return "BCM2837 (ARM Cortex-A53)"; 750 case 0x03: 751 return "BCM2711 (ARM Cortex-A72)"; 752 default: 753 return "Unknown CPU Model"; 754 } 755 } 756 757 #pragma pack() 758 typedef struct { 759 UINT32 Width; 760 UINT32 Height; 761 } RPI_FW_FB_SIZE_TAG; 762 763 typedef struct { 764 RPI_FW_BUFFER_HEAD BufferHead; 765 RPI_FW_TAG_HEAD TagHead; 766 RPI_FW_FB_SIZE_TAG TagBody; 767 UINT32 EndTag; 768 } RPI_FW_GET_FB_SIZE_CMD; 769 770 typedef struct { 771 UINT32 Depth; 772 } RPI_FW_FB_DEPTH_TAG; 773 774 typedef struct { 775 UINT32 Pitch; 776 } RPI_FW_FB_PITCH_TAG; 777 778 typedef struct { 779 UINT32 AlignmentBase; 780 UINT32 Size; 781 } RPI_FW_FB_ALLOC_TAG; 782 783 typedef struct { 784 RPI_FW_BUFFER_HEAD BufferHead; 785 RPI_FW_TAG_HEAD FreeFbTag; 786 UINT32 EndTag; 787 } RPI_FW_FREE_FB_CMD; 788 789 typedef struct { 790 RPI_FW_BUFFER_HEAD BufferHead; 791 RPI_FW_TAG_HEAD PhysSizeTag; 792 RPI_FW_FB_SIZE_TAG PhysSize; 793 RPI_FW_TAG_HEAD VirtSizeTag; 794 RPI_FW_FB_SIZE_TAG VirtSize; 795 RPI_FW_TAG_HEAD DepthTag; 796 RPI_FW_FB_DEPTH_TAG Depth; 797 RPI_FW_TAG_HEAD AllocFbTag; 798 RPI_FW_FB_ALLOC_TAG AllocFb; 799 RPI_FW_TAG_HEAD PitchTag; 800 RPI_FW_FB_PITCH_TAG Pitch; 801 UINT32 EndTag; 802 } RPI_FW_INIT_FB_CMD; 803 #pragma pack() 804 805 STATIC 806 EFI_STATUS 807 EFIAPI 808 RpiFirmwareGetFbSize ( 809 OUT UINT32 *Width, 810 OUT UINT32 *Height 811 ) 812 { 813 RPI_FW_GET_FB_SIZE_CMD *Cmd; 814 EFI_STATUS Status; 815 UINT32 Result; 816 817 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 818 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 819 return EFI_DEVICE_ERROR; 820 } 821 822 Cmd = mDmaBuffer; 823 ZeroMem (Cmd, sizeof (*Cmd)); 824 825 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 826 Cmd->BufferHead.Response = 0; 827 Cmd->TagHead.TagId = RPI_MBOX_GET_FB_GEOMETRY; 828 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 829 Cmd->TagHead.TagValueSize = 0; 830 Cmd->EndTag = 0; 831 832 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 833 834 ReleaseSpinLock (&mMailboxLock); 835 836 if (EFI_ERROR (Status) || 837 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 838 DEBUG ((DEBUG_ERROR, 839 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 840 __FUNCTION__, Status, Cmd->BufferHead.Response)); 841 return EFI_DEVICE_ERROR; 842 } 843 844 *Width = Cmd->TagBody.Width; 845 *Height = Cmd->TagBody.Height; 846 return EFI_SUCCESS; 847 } 848 849 STATIC 850 EFI_STATUS 851 EFIAPI 852 RpiFirmwareFreeFb (VOID) 853 { 854 RPI_FW_FREE_FB_CMD *Cmd; 855 EFI_STATUS Status; 856 UINT32 Result; 857 858 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 859 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 860 return EFI_DEVICE_ERROR; 861 } 862 863 Cmd = mDmaBuffer; 864 ZeroMem (Cmd, sizeof (*Cmd)); 865 866 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 867 Cmd->BufferHead.Response = 0; 868 869 Cmd->FreeFbTag.TagId = RPI_MBOX_FREE_FB; 870 Cmd->FreeFbTag.TagSize = 0; 871 Cmd->FreeFbTag.TagValueSize = 0; 872 Cmd->EndTag = 0; 873 874 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 875 ReleaseSpinLock (&mMailboxLock); 876 877 if (EFI_ERROR (Status) || 878 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 879 DEBUG ((DEBUG_ERROR, 880 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 881 __FUNCTION__, Status, Cmd->BufferHead.Response)); 882 return EFI_DEVICE_ERROR; 883 } 884 885 return EFI_SUCCESS; 886 } 887 888 STATIC 889 EFI_STATUS 890 EFIAPI 891 RpiFirmwareAllocFb ( 892 IN UINT32 Width, 893 IN UINT32 Height, 894 IN UINT32 Depth, 895 OUT EFI_PHYSICAL_ADDRESS *FbBase, 896 OUT UINTN *FbSize, 897 OUT UINTN *Pitch 898 ) 899 { 900 RPI_FW_INIT_FB_CMD *Cmd; 901 EFI_STATUS Status; 902 UINT32 Result; 903 904 ASSERT (FbSize != NULL); 905 ASSERT (FbBase != NULL); 906 907 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 908 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 909 return EFI_DEVICE_ERROR; 910 } 911 912 Cmd = mDmaBuffer; 913 ZeroMem (Cmd, sizeof (*Cmd)); 914 915 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 916 Cmd->BufferHead.Response = 0; 917 918 Cmd->PhysSizeTag.TagId = RPI_MBOX_SET_FB_PGEOM; 919 Cmd->PhysSizeTag.TagSize = sizeof (Cmd->PhysSize); 920 Cmd->PhysSize.Width = Width; 921 Cmd->PhysSize.Height = Height; 922 Cmd->VirtSizeTag.TagId = RPI_MBOX_SET_FB_VGEOM; 923 Cmd->VirtSizeTag.TagSize = sizeof (Cmd->VirtSize); 924 Cmd->VirtSize.Width = Width; 925 Cmd->VirtSize.Height = Height; 926 Cmd->DepthTag.TagId = RPI_MBOX_SET_FB_DEPTH; 927 Cmd->DepthTag.TagSize = sizeof (Cmd->Depth); 928 Cmd->Depth.Depth = Depth; 929 Cmd->AllocFbTag.TagId = RPI_MBOX_ALLOC_FB; 930 Cmd->AllocFbTag.TagSize = sizeof (Cmd->AllocFb); 931 Cmd->AllocFb.AlignmentBase = 32; 932 Cmd->PitchTag.TagId = RPI_MBOX_GET_FB_LINELENGTH; 933 Cmd->PitchTag.TagSize = sizeof (Cmd->Pitch); 934 Cmd->EndTag = 0; 935 936 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 937 938 ReleaseSpinLock (&mMailboxLock); 939 940 if (EFI_ERROR (Status) || 941 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 942 DEBUG ((DEBUG_ERROR, 943 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 944 __FUNCTION__, Status, Cmd->BufferHead.Response)); 945 return EFI_DEVICE_ERROR; 946 } 947 948 *Pitch = Cmd->Pitch.Pitch; 949 *FbBase = Cmd->AllocFb.AlignmentBase - BCM2836_DMA_DEVICE_OFFSET; 950 *FbSize = Cmd->AllocFb.Size; 951 return EFI_SUCCESS; 952 } 953 954 #pragma pack() 955 typedef struct { 956 RPI_FW_BUFFER_HEAD BufferHead; 957 RPI_FW_TAG_HEAD TagHead; 958 UINT8 CommandLine[0]; 959 } RPI_FW_GET_COMMAND_LINE_CMD; 960 #pragma pack() 961 962 STATIC 963 EFI_STATUS 964 EFIAPI 965 RpiFirmwareGetCommmandLine ( 966 IN UINTN BufferSize, 967 OUT CHAR8 CommandLine[] 968 ) 969 { 970 RPI_FW_GET_COMMAND_LINE_CMD *Cmd; 971 EFI_STATUS Status; 972 UINT32 Result; 973 974 if ((BufferSize % sizeof (UINT32)) != 0) { 975 DEBUG ((DEBUG_ERROR, "%a: BufferSize must be a multiple of 4\n", 976 __FUNCTION__)); 977 return EFI_INVALID_PARAMETER; 978 } 979 980 if (sizeof (*Cmd) + BufferSize > EFI_PAGES_TO_SIZE (NUM_PAGES)) { 981 DEBUG ((DEBUG_ERROR, "%a: BufferSize exceeds size of DMA buffer\n", 982 __FUNCTION__)); 983 return EFI_OUT_OF_RESOURCES; 984 } 985 986 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 987 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 988 return EFI_DEVICE_ERROR; 989 } 990 991 Cmd = mDmaBuffer; 992 ZeroMem (Cmd, sizeof (*Cmd) + BufferSize + sizeof (UINT32)); 993 994 Cmd->BufferHead.BufferSize = sizeof (*Cmd) + BufferSize + sizeof (UINT32); 995 Cmd->BufferHead.Response = 0; 996 Cmd->TagHead.TagId = RPI_MBOX_GET_COMMAND_LINE; 997 Cmd->TagHead.TagSize = BufferSize; 998 Cmd->TagHead.TagValueSize = 0; 999 1000 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 1001 1002 ReleaseSpinLock (&mMailboxLock); 1003 1004 if (EFI_ERROR (Status) || 1005 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 1006 DEBUG ((DEBUG_ERROR, 1007 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 1008 __FUNCTION__, Status, Cmd->BufferHead.Response)); 1009 return EFI_DEVICE_ERROR; 1010 } 1011 1012 Cmd->TagHead.TagValueSize &= ~RPI_MBOX_VALUE_SIZE_RESPONSE_MASK; 1013 if (Cmd->TagHead.TagValueSize >= BufferSize && 1014 Cmd->CommandLine[Cmd->TagHead.TagValueSize - 1] != '\0') { 1015 DEBUG ((DEBUG_ERROR, "%a: insufficient buffer size\n", __FUNCTION__)); 1016 return EFI_OUT_OF_RESOURCES; 1017 } 1018 1019 CopyMem (CommandLine, Cmd->CommandLine, Cmd->TagHead.TagValueSize); 1020 1021 if (Cmd->TagHead.TagValueSize == 0 || 1022 CommandLine[Cmd->TagHead.TagValueSize - 1] != '\0') { 1023 // 1024 // Add a NUL terminator if required. 1025 // 1026 CommandLine[Cmd->TagHead.TagValueSize] = '\0'; 1027 } 1028 1029 return EFI_SUCCESS; 1030 } 1031 1032 #pragma pack() 1033 typedef struct { 1034 UINT32 ClockId; 1035 UINT32 ClockRate; 1036 UINT32 SkipTurbo; 1037 } RPI_FW_SET_CLOCK_RATE_TAG; 1038 1039 typedef struct { 1040 RPI_FW_BUFFER_HEAD BufferHead; 1041 RPI_FW_TAG_HEAD TagHead; 1042 RPI_FW_SET_CLOCK_RATE_TAG TagBody; 1043 UINT32 EndTag; 1044 } RPI_FW_SET_CLOCK_RATE_CMD; 1045 #pragma pack() 1046 1047 STATIC 1048 EFI_STATUS 1049 EFIAPI 1050 RpiFirmwareSetClockRate ( 1051 IN UINT32 ClockId, 1052 IN UINT32 ClockRate, 1053 IN BOOLEAN SkipTurbo 1054 ) 1055 { 1056 RPI_FW_SET_CLOCK_RATE_CMD *Cmd; 1057 EFI_STATUS Status; 1058 UINT32 Result; 1059 1060 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 1061 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 1062 return EFI_DEVICE_ERROR; 1063 } 1064 1065 Cmd = mDmaBuffer; 1066 ZeroMem (Cmd, sizeof (*Cmd)); 1067 1068 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 1069 Cmd->BufferHead.Response = 0; 1070 Cmd->TagHead.TagId = RPI_MBOX_SET_CLOCK_RATE; 1071 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 1072 Cmd->TagHead.TagValueSize = 0; 1073 Cmd->TagBody.ClockId = ClockId; 1074 Cmd->TagBody.ClockRate = ClockRate; 1075 Cmd->TagBody.SkipTurbo = SkipTurbo ? 1 : 0; 1076 Cmd->EndTag = 0; 1077 1078 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 1079 1080 ReleaseSpinLock (&mMailboxLock); 1081 1082 if (EFI_ERROR (Status) || 1083 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 1084 DEBUG ((DEBUG_ERROR, 1085 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 1086 __FUNCTION__, Status, Cmd->BufferHead.Response)); 1087 return EFI_DEVICE_ERROR; 1088 } 1089 1090 return EFI_SUCCESS; 1091 } 1092 1093 #pragma pack() 1094 typedef struct { 1095 UINT32 ClockId; 1096 UINT32 ClockRate; 1097 } RPI_FW_CLOCK_RATE_TAG; 1098 1099 typedef struct { 1100 RPI_FW_BUFFER_HEAD BufferHead; 1101 RPI_FW_TAG_HEAD TagHead; 1102 RPI_FW_CLOCK_RATE_TAG TagBody; 1103 UINT32 EndTag; 1104 } RPI_FW_GET_CLOCK_RATE_CMD; 1105 #pragma pack() 1106 1107 STATIC 1108 EFI_STATUS 1109 RpiFirmwareGetClockRate ( 1110 IN UINT32 ClockId, 1111 IN UINT32 ClockKind, 1112 OUT UINT32 *ClockRate 1113 ) 1114 { 1115 RPI_FW_GET_CLOCK_RATE_CMD *Cmd; 1116 EFI_STATUS Status; 1117 UINT32 Result; 1118 1119 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 1120 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 1121 return EFI_DEVICE_ERROR; 1122 } 1123 1124 Cmd = mDmaBuffer; 1125 ZeroMem (Cmd, sizeof (*Cmd)); 1126 1127 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 1128 Cmd->BufferHead.Response = 0; 1129 Cmd->TagHead.TagId = ClockKind; 1130 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 1131 Cmd->TagHead.TagValueSize = 0; 1132 Cmd->TagBody.ClockId = ClockId; 1133 Cmd->EndTag = 0; 1134 1135 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 1136 1137 ReleaseSpinLock (&mMailboxLock); 1138 1139 if (EFI_ERROR (Status) || 1140 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 1141 DEBUG ((DEBUG_ERROR, 1142 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 1143 __FUNCTION__, Status, Cmd->BufferHead.Response)); 1144 return EFI_DEVICE_ERROR; 1145 } 1146 1147 *ClockRate = Cmd->TagBody.ClockRate; 1148 return EFI_SUCCESS; 1149 } 1150 1151 STATIC 1152 EFI_STATUS 1153 EFIAPI 1154 RpiFirmwareGetCurrentClockState ( 1155 IN UINT32 ClockId, 1156 OUT UINT32 *ClockState 1157 ) 1158 { 1159 return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_CLOCK_STATE, ClockState); 1160 } 1161 1162 STATIC 1163 EFI_STATUS 1164 EFIAPI 1165 RpiFirmwareGetCurrentClockRate ( 1166 IN UINT32 ClockId, 1167 OUT UINT32 *ClockRate 1168 ) 1169 { 1170 return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_CLOCK_RATE, ClockRate); 1171 } 1172 1173 STATIC 1174 EFI_STATUS 1175 EFIAPI 1176 RpiFirmwareGetMaxClockRate ( 1177 IN UINT32 ClockId, 1178 OUT UINT32 *ClockRate 1179 ) 1180 { 1181 return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_MAX_CLOCK_RATE, ClockRate); 1182 } 1183 1184 STATIC 1185 EFI_STATUS 1186 EFIAPI 1187 RpiFirmwareGetMinClockRate ( 1188 IN UINT32 ClockId, 1189 OUT UINT32 *ClockRate 1190 ) 1191 { 1192 return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_MIN_CLOCK_RATE, ClockRate); 1193 } 1194 1195 #pragma pack() 1196 typedef struct { 1197 UINT32 ClockId; 1198 UINT32 ClockState; 1199 } RPI_FW_GET_CLOCK_STATE_TAG; 1200 1201 typedef struct { 1202 RPI_FW_BUFFER_HEAD BufferHead; 1203 RPI_FW_TAG_HEAD TagHead; 1204 RPI_FW_GET_CLOCK_STATE_TAG TagBody; 1205 UINT32 EndTag; 1206 } RPI_FW_SET_CLOCK_STATE_CMD; 1207 #pragma pack() 1208 1209 STATIC 1210 EFI_STATUS 1211 RpiFirmwareSetClockState ( 1212 IN UINT32 ClockId, 1213 IN UINT32 ClockState 1214 ) 1215 { 1216 RPI_FW_SET_CLOCK_STATE_CMD *Cmd; 1217 EFI_STATUS Status; 1218 UINT32 Result; 1219 1220 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 1221 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 1222 return EFI_DEVICE_ERROR; 1223 } 1224 1225 Cmd = mDmaBuffer; 1226 ZeroMem (Cmd, sizeof (*Cmd)); 1227 1228 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 1229 Cmd->BufferHead.Response = 0; 1230 Cmd->TagHead.TagId = RPI_MBOX_SET_CLOCK_STATE; 1231 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 1232 Cmd->TagHead.TagValueSize = 0; 1233 Cmd->TagBody.ClockId = ClockId; 1234 Cmd->TagBody.ClockState = ClockState; 1235 Cmd->EndTag = 0; 1236 1237 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 1238 1239 ReleaseSpinLock (&mMailboxLock); 1240 1241 if (EFI_ERROR (Status) || 1242 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 1243 DEBUG ((DEBUG_ERROR, 1244 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 1245 __FUNCTION__, Status, Cmd->BufferHead.Response)); 1246 return EFI_DEVICE_ERROR; 1247 } 1248 1249 return EFI_SUCCESS; 1250 } 1251 1252 #pragma pack() 1253 typedef struct { 1254 UINT32 Pin; 1255 UINT32 State; 1256 } RPI_FW_SET_GPIO_TAG; 1257 1258 typedef struct { 1259 RPI_FW_BUFFER_HEAD BufferHead; 1260 RPI_FW_TAG_HEAD TagHead; 1261 RPI_FW_SET_GPIO_TAG TagBody; 1262 UINT32 EndTag; 1263 } RPI_FW_SET_GPIO_CMD; 1264 #pragma pack() 1265 1266 STATIC 1267 VOID 1268 EFIAPI 1269 RpiFirmwareSetGpio ( 1270 IN UINT32 Gpio, 1271 IN BOOLEAN State 1272 ) 1273 { 1274 RPI_FW_SET_GPIO_CMD *Cmd; 1275 EFI_STATUS Status; 1276 UINT32 Result; 1277 1278 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 1279 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 1280 return; 1281 } 1282 1283 Cmd = mDmaBuffer; 1284 ZeroMem (Cmd, sizeof (*Cmd)); 1285 1286 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 1287 Cmd->BufferHead.Response = 0; 1288 Cmd->TagHead.TagId = RPI_MBOX_SET_GPIO; 1289 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 1290 /* 1291 * There's also a 128 pin offset. 1292 */ 1293 Cmd->TagBody.Pin = 128 + Gpio; 1294 Cmd->TagBody.State = State; 1295 Cmd->TagHead.TagValueSize = 0; 1296 Cmd->EndTag = 0; 1297 1298 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 1299 1300 ReleaseSpinLock (&mMailboxLock); 1301 1302 if (EFI_ERROR (Status) || 1303 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 1304 DEBUG ((DEBUG_ERROR, 1305 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 1306 __FUNCTION__, Status, Cmd->BufferHead.Response)); 1307 } 1308 } 1309 1310 STATIC 1311 VOID 1312 EFIAPI 1313 RpiFirmwareSetLed ( 1314 IN BOOLEAN On 1315 ) 1316 { 1317 RpiFirmwareSetGpio (RPI_EXP_GPIO_LED, On); 1318 } 1319 1320 #pragma pack() 1321 typedef struct { 1322 UINT32 DeviceAddress; 1323 } RPI_FW_NOTIFY_XHCI_RESET_TAG; 1324 1325 typedef struct { 1326 RPI_FW_BUFFER_HEAD BufferHead; 1327 RPI_FW_TAG_HEAD TagHead; 1328 RPI_FW_NOTIFY_XHCI_RESET_TAG TagBody; 1329 UINT32 EndTag; 1330 } RPI_FW_NOTIFY_XHCI_RESET_CMD; 1331 #pragma pack() 1332 1333 STATIC 1334 EFI_STATUS 1335 EFIAPI 1336 RpiFirmwareNotifyXhciReset ( 1337 IN UINTN BusNumber, 1338 IN UINTN DeviceNumber, 1339 IN UINTN FunctionNumber 1340 ) 1341 { 1342 RPI_FW_NOTIFY_XHCI_RESET_CMD *Cmd; 1343 EFI_STATUS Status; 1344 UINT32 Result; 1345 1346 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 1347 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 1348 return EFI_DEVICE_ERROR; 1349 } 1350 1351 Cmd = mDmaBuffer; 1352 ZeroMem (Cmd, sizeof (*Cmd)); 1353 1354 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 1355 Cmd->BufferHead.Response = 0; 1356 Cmd->TagHead.TagId = RPI_MBOX_NOTIFY_XHCI_RESET; 1357 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 1358 Cmd->TagHead.TagValueSize = 0; 1359 Cmd->TagBody.DeviceAddress = BusNumber << 20 | DeviceNumber << 15 | FunctionNumber << 12; 1360 Cmd->EndTag = 0; 1361 1362 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 1363 1364 ReleaseSpinLock (&mMailboxLock); 1365 1366 if (EFI_ERROR (Status) || 1367 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 1368 DEBUG ((DEBUG_ERROR, 1369 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 1370 __FUNCTION__, Status, Cmd->BufferHead.Response)); 1371 } 1372 1373 return Status; 1374 } 1375 1376 #pragma pack() 1377 typedef struct { 1378 UINT32 Gpio; 1379 UINT32 Direction; 1380 UINT32 Polarity; 1381 UINT32 TermEn; 1382 UINT32 TermPullUp; 1383 } RPI_FW_GPIO_GET_CFG_TAG; 1384 1385 typedef struct { 1386 RPI_FW_BUFFER_HEAD BufferHead; 1387 RPI_FW_TAG_HEAD TagHead; 1388 RPI_FW_GPIO_GET_CFG_TAG TagBody; 1389 UINT32 EndTag; 1390 } RPI_FW_NOTIFY_GPIO_GET_CFG_CMD; 1391 #pragma pack() 1392 1393 1394 STATIC 1395 EFI_STATUS 1396 EFIAPI 1397 RpiFirmwareNotifyGpioGetCfg ( 1398 IN UINTN Gpio, 1399 IN UINT32 *Polarity 1400 ) 1401 { 1402 RPI_FW_NOTIFY_GPIO_GET_CFG_CMD *Cmd; 1403 EFI_STATUS Status; 1404 UINT32 Result; 1405 1406 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 1407 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 1408 return EFI_DEVICE_ERROR; 1409 } 1410 1411 Cmd = mDmaBuffer; 1412 ZeroMem (Cmd, sizeof (*Cmd)); 1413 1414 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 1415 Cmd->BufferHead.Response = 0; 1416 Cmd->TagHead.TagId = RPI_MBOX_GET_GPIO_CONFIG; 1417 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 1418 Cmd->TagBody.Gpio = 128 + Gpio; 1419 1420 Cmd->TagHead.TagValueSize = 0; 1421 Cmd->EndTag = 0; 1422 1423 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 1424 1425 *Polarity = Cmd->TagBody.Polarity; 1426 1427 ReleaseSpinLock (&mMailboxLock); 1428 1429 if (EFI_ERROR (Status) || 1430 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 1431 DEBUG ((DEBUG_ERROR, 1432 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 1433 __FUNCTION__, Status, Cmd->BufferHead.Response)); 1434 } 1435 1436 return Status; 1437 } 1438 1439 1440 #pragma pack() 1441 typedef struct { 1442 UINT32 Gpio; 1443 UINT32 Direction; 1444 UINT32 Polarity; 1445 UINT32 TermEn; 1446 UINT32 TermPullUp; 1447 UINT32 State; 1448 } RPI_FW_GPIO_SET_CFG_TAG; 1449 1450 typedef struct { 1451 RPI_FW_BUFFER_HEAD BufferHead; 1452 RPI_FW_TAG_HEAD TagHead; 1453 RPI_FW_GPIO_SET_CFG_TAG TagBody; 1454 UINT32 EndTag; 1455 } RPI_FW_NOTIFY_GPIO_SET_CFG_CMD; 1456 #pragma pack() 1457 1458 1459 STATIC 1460 EFI_STATUS 1461 EFIAPI 1462 RpiFirmwareNotifyGpioSetCfg ( 1463 IN UINTN Gpio, 1464 IN UINTN Direction, 1465 IN UINTN State 1466 ) 1467 { 1468 RPI_FW_NOTIFY_GPIO_SET_CFG_CMD *Cmd; 1469 EFI_STATUS Status; 1470 UINT32 Result; 1471 1472 Status = RpiFirmwareNotifyGpioGetCfg (Gpio, &Result); 1473 if (EFI_ERROR (Status)) { 1474 DEBUG ((DEBUG_ERROR, "%a: Failed to get GPIO polarity\n", __FUNCTION__)); 1475 Result = 0; //default polarity 1476 } 1477 1478 1479 if (!AcquireSpinLockOrFail (&mMailboxLock)) { 1480 DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__)); 1481 return EFI_DEVICE_ERROR; 1482 } 1483 1484 Cmd = mDmaBuffer; 1485 ZeroMem (Cmd, sizeof (*Cmd)); 1486 1487 Cmd->BufferHead.BufferSize = sizeof (*Cmd); 1488 Cmd->BufferHead.Response = 0; 1489 Cmd->TagHead.TagId = RPI_MBOX_SET_GPIO_CONFIG; 1490 Cmd->TagHead.TagSize = sizeof (Cmd->TagBody); 1491 1492 Cmd->TagBody.Gpio = 128 + Gpio; 1493 Cmd->TagBody.Direction = Direction; 1494 Cmd->TagBody.Polarity = Result; 1495 Cmd->TagBody.TermEn = 0; 1496 Cmd->TagBody.TermPullUp = 0; 1497 Cmd->TagBody.State = State; 1498 1499 Cmd->TagHead.TagValueSize = 0; 1500 Cmd->EndTag = 0; 1501 1502 Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result); 1503 1504 ReleaseSpinLock (&mMailboxLock); 1505 1506 if (EFI_ERROR (Status) || 1507 Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) { 1508 DEBUG ((DEBUG_ERROR, 1509 "%a: mailbox transaction error: Status == %r, Response == 0x%x\n", 1510 __FUNCTION__, Status, Cmd->BufferHead.Response)); 1511 } 1512 1513 RpiFirmwareSetGpio (Gpio,!State); 1514 1515 1516 return Status; 1517 } 1518 1519 STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL mRpiFirmwareProtocol = { 1520 RpiFirmwareSetPowerState, 1521 RpiFirmwareGetMacAddress, 1522 RpiFirmwareGetCommmandLine, 1523 RpiFirmwareGetCurrentClockRate, 1524 RpiFirmwareGetMaxClockRate, 1525 RpiFirmwareGetMinClockRate, 1526 RpiFirmwareSetClockRate, 1527 RpiFirmwareAllocFb, 1528 RpiFirmwareFreeFb, 1529 RpiFirmwareGetFbSize, 1530 RpiFirmwareSetLed, 1531 RpiFirmwareGetSerial, 1532 RpiFirmwareGetModel, 1533 RpiFirmwareGetModelRevision, 1534 RpiFirmwareGetModelName, 1535 RPiFirmwareGetModelFamily, 1536 RpiFirmwareGetFirmwareRevision, 1537 RpiFirmwareGetManufacturerName, 1538 RpiFirmwareGetCpuName, 1539 RpiFirmwareGetArmMemory, 1540 RPiFirmwareGetModelInstalledMB, 1541 RpiFirmwareNotifyXhciReset, 1542 RpiFirmwareGetCurrentClockState, 1543 RpiFirmwareSetClockState, 1544 RpiFirmwareNotifyGpioSetCfg 1545 }; 1546 1547 /** 1548 Initialize the state information for the CPU Architectural Protocol 1549 1550 @param ImageHandle of the loaded driver 1551 @param SystemTable Pointer to the System Table 1552 1553 @retval EFI_SUCCESS Protocol registered 1554 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure 1555 @retval EFI_DEVICE_ERROR Hardware problems 1556 1557 **/ 1558 EFI_STATUS 1559 RpiFirmwareDxeInitialize ( 1560 IN EFI_HANDLE ImageHandle, 1561 IN EFI_SYSTEM_TABLE *SystemTable 1562 ) 1563 { 1564 EFI_STATUS Status; 1565 UINTN BufferSize; 1566 1567 // 1568 // We only need one of these 1569 // 1570 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gRaspberryPiFirmwareProtocolGuid); 1571 1572 InitializeSpinLock (&mMailboxLock); 1573 1574 Status = DmaAllocateBuffer (EfiBootServicesData, NUM_PAGES, &mDmaBuffer); 1575 if (EFI_ERROR (Status)) { 1576 DEBUG ((DEBUG_ERROR, "%a: failed to allocate DMA buffer (Status == %r)\n", __FUNCTION__)); 1577 return Status; 1578 } 1579 1580 BufferSize = EFI_PAGES_TO_SIZE (NUM_PAGES); 1581 Status = DmaMap (MapOperationBusMasterCommonBuffer, mDmaBuffer, &BufferSize, 1582 &mDmaBufferBusAddress, &mDmaBufferMapping); 1583 if (EFI_ERROR (Status)) { 1584 DEBUG ((DEBUG_ERROR, "%a: failed to map DMA buffer (Status == %r)\n", __FUNCTION__)); 1585 goto FreeBuffer; 1586 } 1587 1588 // 1589 // The channel index is encoded in the low bits of the bus address, 1590 // so make sure these are cleared. 1591 // 1592 ASSERT (!(mDmaBufferBusAddress & (BCM2836_MBOX_NUM_CHANNELS - 1))); 1593 1594 Status = gBS->InstallProtocolInterface (&ImageHandle, 1595 &gRaspberryPiFirmwareProtocolGuid, EFI_NATIVE_INTERFACE, 1596 &mRpiFirmwareProtocol); 1597 if (EFI_ERROR (Status)) { 1598 DEBUG ((DEBUG_ERROR, 1599 "%a: failed to install RPI firmware protocol (Status == %r)\n", 1600 __FUNCTION__, Status)); 1601 goto UnmapBuffer; 1602 } 1603 1604 return EFI_SUCCESS; 1605 1606 UnmapBuffer: 1607 DmaUnmap (mDmaBufferMapping); 1608 FreeBuffer: 1609 DmaFreeBuffer (NUM_PAGES, mDmaBuffer); 1610 1611 return Status; 1612 } 1613