main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. main.c
  5. Abstract:
  6. This module implements the entry point for the UEFI firmware running on top
  7. of the Raspberry Pi 2.
  8. Author:
  9. Chris Stevens 19-Mar-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. // ---------------------------------------------------------------- Definitions
  23. //
  24. #define FIRMWARE_IMAGE_NAME "rpi2fw.elf"
  25. //
  26. // Define the core timer's crystal clock frequency: 19.2 MHz.
  27. //
  28. #define BCM2836_CORE_TIMER_CRYSTAL_CLOCK_FREQUENCY 19200000
  29. //
  30. // Define the maximum pre-scaler value.
  31. //
  32. #define BCM2836_CORE_TIMER_MAX_PRE_SCALER 0x80000000
  33. //
  34. // ------------------------------------------------------ Data Type Definitions
  35. //
  36. /*++
  37. Structure Description:
  38. This structure defines the data necessary to set the BCM2709's ARM clock
  39. rate.
  40. Members:
  41. Header - Stores a header that defines the total size of the messages being
  42. sent to and received from the mailbox.
  43. ArmClockRate - Stores a message setting the ARM core's clock rate.
  44. EndTag - Stores the tag to denote the end of the mailbox message.
  45. --*/
  46. typedef struct _EFI_BCM2709_SET_CLOCK_RATE {
  47. BCM2709_MAILBOX_HEADER Header;
  48. BCM2709_MAILBOX_SET_CLOCK_RATE ArmClockRate;
  49. UINT32 EndTag;
  50. } EFI_BCM2709_SET_CLOCK_RATE, *PEFI_BCM2709_SET_CLOCK_RATE;
  51. //
  52. // ----------------------------------------------- Internal Function Prototypes
  53. //
  54. EFI_STATUS
  55. EfipBcm2836InitializeUart (
  56. VOID
  57. );
  58. EFI_STATUS
  59. EfipBcm2836InitializeArmClock (
  60. VOID
  61. );
  62. EFI_STATUS
  63. EfipBcm2836InitializeApbClock (
  64. VOID
  65. );
  66. EFI_STATUS
  67. EfipBcm2836InitializeCoreTimerClock (
  68. VOID
  69. );
  70. UINT32
  71. EfipBcm2836GetGtFrequency (
  72. VOID
  73. );
  74. //
  75. // -------------------------------------------------------------------- Globals
  76. //
  77. //
  78. // Variables defined in the linker script that mark the start and end of the
  79. // image.
  80. //
  81. extern INT8 _end;
  82. extern INT8 __executable_start;
  83. //
  84. // Store a template to set the Raspberry Pi 2's ARM clock frequency.
  85. //
  86. EFI_BCM2709_SET_CLOCK_RATE EfiRpi2SetClockTemplate = {
  87. {
  88. sizeof(EFI_BCM2709_SET_CLOCK_RATE),
  89. 0
  90. },
  91. {
  92. {
  93. BCM2709_MAILBOX_TAG_SET_CLOCK_RATE,
  94. sizeof(UINT32) * 3,
  95. sizeof(UINT32) * 3
  96. },
  97. BCM2709_MAILBOX_CLOCK_ID_ARM,
  98. 0,
  99. 0
  100. },
  101. 0
  102. };
  103. EFI_BCM2709_GET_CLOCK_RATE EfiRpi2GetClockTemplate = {
  104. {
  105. sizeof(EFI_BCM2709_GET_CLOCK_RATE),
  106. 0
  107. },
  108. {
  109. {
  110. BCM2709_MAILBOX_TAG_GET_CLOCK_MAX_RATE,
  111. sizeof(UINT32) * 2,
  112. sizeof(UINT32) * 2
  113. },
  114. BCM2709_MAILBOX_CLOCK_ID_ARM,
  115. 0
  116. },
  117. 0
  118. };
  119. //
  120. // ------------------------------------------------------------------ Functions
  121. //
  122. VOID
  123. EfiRpi2Main (
  124. VOID *TopOfStack,
  125. UINTN StackSize
  126. )
  127. /*++
  128. Routine Description:
  129. This routine is the C entry point for the firmware.
  130. Arguments:
  131. TopOfStack - Supplies the top of the stack that has been set up for the
  132. loader.
  133. StackSize - Supplies the total size of the stack set up for the loader, in
  134. bytes.
  135. Return Value:
  136. This routine does not return.
  137. --*/
  138. {
  139. UINTN FirmwareSize;
  140. EFI_STATUS Status;
  141. //
  142. // Force GPIO pins 14 and 15 to the UART (rather than the mini-UART) before
  143. // debugging comes online.
  144. //
  145. Status = EfipBcm2836InitializeUart();
  146. if (EFI_ERROR(Status)) {
  147. return;
  148. }
  149. //
  150. // Initialize UEFI enough to get into the debugger.
  151. //
  152. FirmwareSize = (UINTN)&_end - (UINTN)&__executable_start;
  153. EfiCoreMain((VOID *)-1,
  154. &__executable_start,
  155. FirmwareSize,
  156. FIRMWARE_IMAGE_NAME,
  157. TopOfStack - StackSize,
  158. StackSize);
  159. return;
  160. }
  161. EFI_STATUS
  162. EfiPlatformInitialize (
  163. UINT32 Phase
  164. )
  165. /*++
  166. Routine Description:
  167. This routine performs platform-specific firmware initialization.
  168. Arguments:
  169. Phase - Supplies the iteration number this routine is being called on.
  170. Phase zero occurs very early, just after the debugger comes up.
  171. Phase one occurs a bit later, after timer and interrupt services are
  172. initialized. Phase two happens right before boot, after all platform
  173. devices have been enumerated.
  174. Return Value:
  175. EFI status code.
  176. --*/
  177. {
  178. EFI_STATUS Status;
  179. Status = EFI_SUCCESS;
  180. if (Phase == 0) {
  181. Status = EfipBcm2709Initialize((VOID *)BCM2836_BASE);
  182. if (EFI_ERROR(Status)) {
  183. goto PlatformInitializeEnd;
  184. }
  185. Status = EfipBcm2836SmpInitialize(0);
  186. if (EFI_ERROR(Status)) {
  187. goto PlatformInitializeEnd;
  188. }
  189. } else if (Phase == 1) {
  190. Status = EfipBcm2836InitializeArmClock();
  191. if (EFI_ERROR(Status)) {
  192. goto PlatformInitializeEnd;
  193. }
  194. Status = EfipBcm2709UsbInitialize();
  195. if (EFI_ERROR(Status)) {
  196. goto PlatformInitializeEnd;
  197. }
  198. Status = EfipBcm2836SmpInitialize(1);
  199. if (EFI_ERROR(Status)) {
  200. goto PlatformInitializeEnd;
  201. }
  202. Status = EfipRpi2CreateSmbiosTables();
  203. if (EFI_ERROR(Status)) {
  204. goto PlatformInitializeEnd;
  205. }
  206. } else if (Phase == 2) {
  207. Status = EfipBcm2836SmpInitialize(2);
  208. if (EFI_ERROR(Status)) {
  209. goto PlatformInitializeEnd;
  210. }
  211. Status = EfipBcm2836InitializeApbClock();
  212. if (EFI_ERROR(Status)) {
  213. goto PlatformInitializeEnd;
  214. }
  215. Status = EfipBcm2836InitializeCoreTimerClock();
  216. if (EFI_ERROR(Status)) {
  217. goto PlatformInitializeEnd;
  218. }
  219. }
  220. PlatformInitializeEnd:
  221. return Status;
  222. }
  223. EFI_STATUS
  224. EfiPlatformEnumerateDevices (
  225. VOID
  226. )
  227. /*++
  228. Routine Description:
  229. This routine enumerates and connects any builtin devices the platform
  230. contains.
  231. Arguments:
  232. None.
  233. Return Value:
  234. EFI status code.
  235. --*/
  236. {
  237. EFI_STATUS Status;
  238. Status = EfipBcm2709EnumerateSd();
  239. if (EFI_ERROR(Status)) {
  240. return Status;
  241. }
  242. EfipBcm2709EnumerateVideo();
  243. EfipBcm2709EnumerateSerial();
  244. Status = EfipEnumerateRamDisks();
  245. if (EFI_ERROR(Status)) {
  246. return Status;
  247. }
  248. return EFI_SUCCESS;
  249. }
  250. //
  251. // --------------------------------------------------------- Internal Functions
  252. //
  253. EFI_STATUS
  254. EfipBcm2836InitializeUart (
  255. VOID
  256. )
  257. /*++
  258. Routine Description:
  259. This routine initializes the PL011 UART making sure that it is exposed on
  260. GPIO pins 14 and 15. On some versions of the Raspberry Pi, the mini-UART is
  261. exposed on said pins.
  262. Arguments:
  263. None.
  264. Return Value:
  265. EFI status code.
  266. --*/
  267. {
  268. EFI_STATUS Status;
  269. //
  270. // The BCM2709 device must be initialized before using GPIO.
  271. //
  272. Status = EfipBcm2709Initialize((VOID *)BCM2836_BASE);
  273. if (EFI_ERROR(Status)) {
  274. goto InitializeUartEnd;
  275. }
  276. Status = EfipBcm2709GpioFunctionSelect(BCM2709_GPIO_RECEIVE_PIN,
  277. BCM2709_GPIO_FUNCTION_SELECT_ALT_0);
  278. if (EFI_ERROR(Status)) {
  279. goto InitializeUartEnd;
  280. }
  281. Status = EfipBcm2709GpioFunctionSelect(BCM2709_GPIO_TRANSMIT_PIN,
  282. BCM2709_GPIO_FUNCTION_SELECT_ALT_0);
  283. if (EFI_ERROR(Status)) {
  284. goto InitializeUartEnd;
  285. }
  286. InitializeUartEnd:
  287. return Status;
  288. }
  289. EFI_STATUS
  290. EfipBcm2836InitializeArmClock (
  291. VOID
  292. )
  293. /*++
  294. Routine Description:
  295. This routine initializes the ARM clock to its maximu supported frequency.
  296. The firmware initializes it to less than the maximum (i.e. 600Mhz, rather
  297. than the 900Mhz max on the RPI 2).
  298. Arguments:
  299. None.
  300. Return Value:
  301. EFI status code.
  302. --*/
  303. {
  304. EFI_BCM2709_GET_CLOCK_RATE GetClockRate;
  305. EFI_BCM2709_SET_CLOCK_RATE SetClockRate;
  306. EFI_STATUS Status;
  307. //
  308. // Get the maximum supported ARM core clock rate from the mailbox.
  309. //
  310. EfiCopyMem(&GetClockRate,
  311. &EfiRpi2GetClockTemplate,
  312. sizeof(EFI_BCM2709_GET_CLOCK_RATE));
  313. Status = EfipBcm2709MailboxSendCommand(BCM2709_MAILBOX_PROPERTIES_CHANNEL,
  314. &GetClockRate,
  315. sizeof(EFI_BCM2709_GET_CLOCK_RATE),
  316. FALSE);
  317. if (EFI_ERROR(Status)) {
  318. return Status;
  319. }
  320. //
  321. // Set the ARM core clock rate to the maximum.
  322. //
  323. EfiCopyMem(&SetClockRate,
  324. &EfiRpi2SetClockTemplate,
  325. sizeof(EFI_BCM2709_SET_CLOCK_RATE));
  326. SetClockRate.ArmClockRate.Rate = GetClockRate.ClockRate.Rate;
  327. Status = EfipBcm2709MailboxSendCommand(BCM2709_MAILBOX_PROPERTIES_CHANNEL,
  328. &SetClockRate,
  329. sizeof(EFI_BCM2709_SET_CLOCK_RATE),
  330. TRUE);
  331. return Status;
  332. }
  333. EFI_STATUS
  334. EfipBcm2836InitializeApbClock (
  335. VOID
  336. )
  337. /*++
  338. Routine Description:
  339. This routine initializes the APB clock. This is the video cores clock and
  340. can be configured via config.txt. Initialization simply consists of reading
  341. the clock and updating the BCM2 ACPI table if necessary.
  342. Arguments:
  343. None.
  344. Return Value:
  345. EFI status code.
  346. --*/
  347. {
  348. EFI_BCM2709_GET_CLOCK_RATE GetClockRate;
  349. EFI_STATUS Status;
  350. PBCM2709_TABLE Table;
  351. //
  352. // Get the current video core clock rate from the mailbox.
  353. //
  354. EfiCopyMem(&GetClockRate,
  355. &EfiRpi2GetClockTemplate,
  356. sizeof(EFI_BCM2709_GET_CLOCK_RATE));
  357. GetClockRate.ClockRate.TagHeader.Tag = BCM2709_MAILBOX_TAG_GET_CLOCK_RATE;
  358. GetClockRate.ClockRate.ClockId = BCM2709_MAILBOX_CLOCK_ID_VIDEO;
  359. Status = EfipBcm2709MailboxSendCommand(BCM2709_MAILBOX_PROPERTIES_CHANNEL,
  360. &GetClockRate,
  361. sizeof(EFI_BCM2709_GET_CLOCK_RATE),
  362. FALSE);
  363. if (EFI_ERROR(Status)) {
  364. goto InitializeApbClockEnd;
  365. }
  366. //
  367. // Get the Broadcom ACPI table.
  368. //
  369. Table = EfiGetAcpiTable(BCM2709_SIGNATURE, NULL);
  370. if (Table == NULL) {
  371. Status = EFI_NOT_FOUND;
  372. goto InitializeApbClockEnd;
  373. }
  374. if (Table->ApbClockFrequency != GetClockRate.ClockRate.Rate) {
  375. Table->ApbClockFrequency = GetClockRate.ClockRate.Rate;
  376. EfiAcpiChecksumTable(Table,
  377. Table->Header.Length,
  378. OFFSET_OF(DESCRIPTION_HEADER, Checksum));
  379. }
  380. InitializeApbClockEnd:
  381. return Status;
  382. }
  383. EFI_STATUS
  384. EfipBcm2836InitializeCoreTimerClock (
  385. VOID
  386. )
  387. /*++
  388. Routine Description:
  389. This routine initializes the ARM core's timer clock. This backs the ARM
  390. Generic Timer.
  391. Arguments:
  392. None.
  393. Return Value:
  394. EFI status code.
  395. --*/
  396. {
  397. UINT32 Divider;
  398. UINT32 Frequency;
  399. UINT32 PreScaler;
  400. UINT32 TimerControl;
  401. //
  402. // Use the 19.2 MHz crystal clock to back the ARM Generic Timer.
  403. //
  404. TimerControl = BCM2836_CORE_TIMER_CONTROL_INCREMENT_BY_1 |
  405. BCM2836_CORE_TIMER_CONTROL_CRYSTAL_CLOCK;
  406. EfiWriteRegister32((VOID*)BCM2836_CORE_TIMER_CONTROL, TimerControl);
  407. //
  408. // Get the programmed frequency and try to match the pre-scaler so the
  409. // clock runs at the targeted frequency.
  410. //
  411. Frequency = EfipBcm2836GetGtFrequency();
  412. if (Frequency > BCM2836_CORE_TIMER_CRYSTAL_CLOCK_FREQUENCY) {
  413. return EFI_UNSUPPORTED;
  414. }
  415. //
  416. // The frequency is obtained by dividing 19.2 MHz by the divider. The
  417. // divider is obtained by dividing 2^31 by the pre-scaler. Determine the
  418. // appropriate pre-scaler for the frequency.
  419. //
  420. Divider = BCM2836_CORE_TIMER_CRYSTAL_CLOCK_FREQUENCY / Frequency;
  421. PreScaler = BCM2836_CORE_TIMER_MAX_PRE_SCALER / Divider;
  422. EfiWriteRegister32((VOID*)BCM2836_CORE_TIMER_PRE_SCALER, PreScaler);
  423. return EFI_SUCCESS;
  424. }