1
0

smp.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. smp.c
  5. Abstract:
  6. This module implements support routines for the application processors on
  7. BCM2836 SoCs.
  8. Author:
  9. Chris Stevens 19-Apr-2015
  10. Environment:
  11. Firmware
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/lib/types.h>
  17. #include <minoca/fw/acpitabs.h>
  18. #include <minoca/soc/b2709os.h>
  19. #include <uefifw.h>
  20. #include "rpi2fw.h"
  21. //
  22. // --------------------------------------------------------------------- Macros
  23. //
  24. //
  25. // This macro sets the jump address for the given CPU.
  26. //
  27. #define BCM2836_SET_CPU_JUMP_ADDRESS(_CpuId, _JumpAddress) \
  28. EfiWriteRegister32( \
  29. (VOID *)BCM2836_CPU_0_MAILBOX_3_SET + ((_CpuId) * 0x10), \
  30. (_JumpAddress))
  31. //
  32. // This macros reads and clears a core's jump address to check to see that is
  33. // has come to life.
  34. //
  35. #define BCM2836_READ_CPU_JUMP_ADDRESS(_CpuId) \
  36. EfiReadRegister32((VOID *)BCM2836_CPU_0_MAILBOX_3_CLEAR + \
  37. ((_CpuId) * 0x10))
  38. //
  39. // This macro enables IRQs on a particular core.
  40. //
  41. #define BCM2836_CPU_ENABLE_IRQS(_CpuId) \
  42. EfiWriteRegister32((VOID *)BCM2836_CPU_0_MAILBOX_INTERRUPT_CONTROL + \
  43. ((_CpuId) * 0x4), \
  44. 0x1)
  45. //
  46. // ---------------------------------------------------------------- Definitions
  47. //
  48. #define BCM2836_CPU_COUNT 4
  49. #define BCM2836_CPU_0_PARKED_ADDRESS 0x01FFA000
  50. #define BCM2836_CPU_1_PARKED_ADDRESS 0x01FFB000
  51. #define BCM2836_CPU_2_PARKED_ADDRESS 0x01FFC000
  52. #define BCM2836_CPU_3_PARKED_ADDRESS 0x01FFD000
  53. #define BCM2836_CPU_PARKED_ADDRESS_SIZE 0x1000
  54. #define BCM2836_CPU_TOTAL_PARKED_ADDRESS_SIZE \
  55. (BCM2836_CPU_COUNT * BCM2836_CPU_PARKED_ADDRESS_SIZE)
  56. #define ARM_PARKING_PROTOCOL_FIRMWARE_OFFSET 0x0800
  57. //
  58. // Define which bits of the MPIDR are valid processor ID bits.
  59. //
  60. #define ARM_PROCESSOR_ID_MASK 0x00FFFFFF
  61. //
  62. // ------------------------------------------------------ Data Type Definitions
  63. //
  64. //
  65. // ----------------------------------------------- Internal Function Prototypes
  66. //
  67. VOID
  68. EfipBcm2836ProcessorStartup (
  69. VOID
  70. );
  71. UINT32
  72. EfipBcm2836GetMultiprocessorIdRegister (
  73. VOID
  74. );
  75. VOID
  76. EfipBcm2836SendEvent (
  77. VOID
  78. );
  79. EFI_STATUS
  80. EfipBcm2836UpdateAcpi (
  81. UINT32 ProcessorIdBase
  82. );
  83. //
  84. // -------------------------------------------------------------------- Globals
  85. //
  86. //
  87. // Define the variables other cores read to boot.
  88. //
  89. volatile UINT32 EfiBcm2836ProcessorId;
  90. VOID volatile *EfiBcm2836JumpAddress;
  91. extern UINT8 EfipBcm2836ParkingLoop;
  92. extern UINT8 EfipBcm2836ParkingLoopEnd;
  93. //
  94. // ------------------------------------------------------------------ Functions
  95. //
  96. EFI_STATUS
  97. EfipBcm2836SmpInitialize (
  98. UINT32 Phase
  99. )
  100. /*++
  101. Routine Description:
  102. This routine initializes and parks the application processors on the
  103. BCM2836.
  104. Arguments:
  105. Phase - Supplies the iteration number this routine is being called on.
  106. Phase zero occurs very early, just after the debugger comes up.
  107. Phase one occurs a bit later, after timer, interrupt services, and the
  108. memory core are initialized.
  109. Return Value:
  110. EFI status code.
  111. --*/
  112. {
  113. VOID *Cpu[BCM2836_CPU_COUNT];
  114. UINT32 IdBase;
  115. UINT32 Index;
  116. UINTN Pages;
  117. EFI_PHYSICAL_ADDRESS ParkedAddress;
  118. UINTN ParkingLoopSize;
  119. EFI_STATUS Status;
  120. //
  121. // Get the MPIDR of the current core to determine the base CPU ID.
  122. //
  123. IdBase = EfipBcm2836GetMultiprocessorIdRegister() & ARM_PROCESSOR_ID_MASK;
  124. //
  125. // Phase 0 initializes all of the cores and then parks the non-boot cores.
  126. // They are currently parked within page zero, but UEFI memory
  127. // initialization zeroes that page in order to reclaim it. As a result, the
  128. // cores need to be parked elsewhere before being parked at the final
  129. // destination.
  130. //
  131. if (Phase == 0) {
  132. //
  133. // Enable IRQs on all cores.
  134. //
  135. for (Index = 0; Index < BCM2836_CPU_COUNT; Index += 1) {
  136. BCM2836_CPU_ENABLE_IRQS(Index);
  137. }
  138. //
  139. // Park the application cores to the first space.
  140. //
  141. for (Index = 1; Index < BCM2836_CPU_COUNT; Index += 1) {
  142. EfiBcm2836ProcessorId = IdBase + Index;
  143. //
  144. // Poke the CPU to fire it up.
  145. //
  146. BCM2836_SET_CPU_JUMP_ADDRESS(Index,
  147. (UINTN)EfipBcm2836ProcessorStartup);
  148. //
  149. // Wait for the CPU to come to life.
  150. //
  151. while (BCM2836_READ_CPU_JUMP_ADDRESS(Index) != (UINTN)NULL) {
  152. NOTHING;
  153. }
  154. //
  155. // Wait for the processor ID to be cleared. For some reason marking
  156. // the variable as volatile doesn't seem to prevent optimization.
  157. //
  158. while (EfiReadRegister32((UINT32 *)&EfiBcm2836ProcessorId) != 0) {
  159. NOTHING;
  160. }
  161. }
  162. //
  163. // Phase 1 moves the application processors to their final parking
  164. // location in allocated memory. These parking locations are then passed
  165. // along to higher level systems via ACPI.
  166. //
  167. } else if (Phase == 1) {
  168. //
  169. // Allocate the pages for the firmware parked spaces.
  170. //
  171. Pages = EFI_SIZE_TO_PAGES(BCM2836_CPU_TOTAL_PARKED_ADDRESS_SIZE);
  172. ParkedAddress = BCM2836_CPU_0_PARKED_ADDRESS;
  173. Status = EfiAllocatePages(AllocateAddress,
  174. EfiACPIMemoryNVS,
  175. Pages,
  176. &ParkedAddress);
  177. if (EFI_ERROR(Status)) {
  178. return Status;
  179. }
  180. EfiSetMem((VOID *)(UINTN)ParkedAddress,
  181. BCM2836_CPU_TOTAL_PARKED_ADDRESS_SIZE,
  182. 0);
  183. //
  184. // Initialize the parked address for each CPU, write -1 to the
  185. // processor number location, and copy the parking protocol loop into
  186. // the place for each CPU.
  187. //
  188. ParkingLoopSize = (UINTN)&EfipBcm2836ParkingLoopEnd -
  189. (UINTN)&EfipBcm2836ParkingLoop;
  190. for (Index = 0; Index < BCM2836_CPU_COUNT; Index += 1) {
  191. Cpu[Index] = (VOID *)((UINTN)ParkedAddress +
  192. (BCM2836_CPU_PARKED_ADDRESS_SIZE * Index));
  193. *((UINT32 *)Cpu[Index]) = -1;
  194. EfiCopyMem(Cpu[Index] + ARM_PARKING_PROTOCOL_FIRMWARE_OFFSET,
  195. &EfipBcm2836ParkingLoop,
  196. ParkingLoopSize);
  197. }
  198. EfiCoreInvalidateInstructionCacheRange(
  199. (VOID *)(UINTN)ParkedAddress,
  200. BCM2836_CPU_TOTAL_PARKED_ADDRESS_SIZE);
  201. //
  202. // Park each of the application cores.
  203. //
  204. for (Index = 1; Index < BCM2836_CPU_COUNT; Index += 1) {
  205. EfiBcm2836JumpAddress = Cpu[Index] +
  206. ARM_PARKING_PROTOCOL_FIRMWARE_OFFSET;
  207. EfiBcm2836ProcessorId = IdBase + Index;
  208. //
  209. // Send an event to the cores, only the one with the matching ID
  210. // should proceed.
  211. //
  212. EfipBcm2836SendEvent();
  213. //
  214. // Make sure the core moves on.
  215. //
  216. while (EfiReadRegister32((UINT32 *)&EfiBcm2836JumpAddress) !=
  217. (UINT32)NULL) {
  218. NOTHING;
  219. }
  220. }
  221. } else {
  222. Status = EfipBcm2836UpdateAcpi(IdBase);
  223. if (EFI_ERROR(Status)) {
  224. return Status;
  225. }
  226. }
  227. return EFI_SUCCESS;
  228. }
  229. //
  230. // --------------------------------------------------------- Internal Functions
  231. //
  232. EFI_STATUS
  233. EfipBcm2836UpdateAcpi (
  234. UINT32 ProcessorIdBase
  235. )
  236. /*++
  237. Routine Description:
  238. This routine updates the BCM2 ACPI table with the current platform's SMP
  239. information.
  240. Arguments:
  241. ProcessorIdBase - Supplies the base ID for the BCM2836's ARM cores.
  242. Return Value:
  243. EFI status code.
  244. --*/
  245. {
  246. PBCM2709_CPU_ENTRY CpuEntry;
  247. PBCM2709_GENERIC_ENTRY CurrentEntry;
  248. UINT32 ProcessorCount;
  249. EFI_STATUS Status;
  250. PBCM2709_TABLE Table;
  251. Table = EfiGetAcpiTable(BCM2709_SIGNATURE, NULL);
  252. if (Table == NULL) {
  253. Status = EFI_NOT_FOUND;
  254. goto UpdateAcpiEnd;
  255. }
  256. //
  257. // Update the processor ID for each CPU entry in the table. Different
  258. // BCM2836 devices have different sets of MPIDR values.
  259. //
  260. ProcessorCount = 0;
  261. CurrentEntry = (PBCM2709_GENERIC_ENTRY)(Table + 1);
  262. while ((UINTN)CurrentEntry <
  263. ((UINTN)Table + Table->Header.Length)) {
  264. if ((CurrentEntry->Type == Bcm2709EntryTypeCpu) &&
  265. (CurrentEntry->Length == sizeof(BCM2709_CPU_ENTRY))) {
  266. CpuEntry = (PBCM2709_CPU_ENTRY)CurrentEntry;
  267. CpuEntry->ProcessorId = ProcessorIdBase + ProcessorCount;
  268. ProcessorCount += 1;
  269. if (ProcessorCount == BCM2836_CPU_COUNT) {
  270. break;
  271. }
  272. }
  273. CurrentEntry = (PBCM2709_GENERIC_ENTRY)((PUCHAR)CurrentEntry +
  274. CurrentEntry->Length);
  275. }
  276. //
  277. // Now that the table has been modified, recompute the checksum.
  278. //
  279. EfiAcpiChecksumTable(Table,
  280. Table->Header.Length,
  281. OFFSET_OF(DESCRIPTION_HEADER, Checksum));
  282. Status = EFI_SUCCESS;
  283. UpdateAcpiEnd:
  284. return Status;
  285. }