main.c 13 KB

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