docs/porting: Create a porting guide for the BCM2711 and organize porting case studies into their own directory.
This commit is contained in:
parent
e19e1a8532
commit
b15cd35bb0
3 changed files with 389 additions and 3 deletions
|
@ -66,10 +66,14 @@ After that, try follwoing procedure.
|
|||
| | | count the time accurately or not. |
|
||||
+------+---------------+--------------------------------------------------------------------+
|
||||
|
||||
The result of porting procedure
|
||||
Porting Case Studies
|
||||
===============================
|
||||
|
||||
Although these depend on specific kernel version.
|
||||
These porting guides depend on specific kernel versions, as some code structures have changed over time. They will still
|
||||
provide a general idea on how to port.
|
||||
|
||||
.. toctree::
|
||||
port_arm_cm4.rst
|
||||
:glob:
|
||||
:maxdepth: 1
|
||||
|
||||
porting-case-studies/*
|
||||
|
|
382
Documentation/guides/porting-case-studies/bcm2711-rpi4b.rst
Normal file
382
Documentation/guides/porting-case-studies/bcm2711-rpi4b.rst
Normal file
|
@ -0,0 +1,382 @@
|
|||
Porting to the BCM2711 (Raspberry Pi 4B)
|
||||
========================================
|
||||
|
||||
This port was completed for the 12.7.0 version of the NuttX kernel, and was contributed by Matteo Golin.
|
||||
|
||||
The pull request with this initial support can be found at `apache/nuttx/pull/15188
|
||||
<https://github.com/apache/nuttx/pull/15188>`_.
|
||||
|
||||
The port required support to be written for a new chip (the BCM2711) and a new board. Matteo created journal entries
|
||||
while working on the initial port, which can be found `on his blog
|
||||
<https://linguini1.github.io/blog/2024/12/25/nuttx-bcm2711.html>`_. The details below are a more concise summary of the
|
||||
porting process.
|
||||
|
||||
Researching
|
||||
-----------
|
||||
|
||||
The first step to porting a board to NuttX was researching the board and how NuttX works.
|
||||
|
||||
The BCM2711 is a quad-core ARM Cortex A72 based SoC, and it supports both aarch64 and 32 bit ARM architectures. I
|
||||
focused on the aarch64 implementation only in this port. My first step was determining other boards already in the NuttX
|
||||
kernel that used the aarch64 architecture, because that gives me a starting point to porting this new chip and board.
|
||||
|
||||
I primarily used the blog posts written by Lup Yuen Lee about porting NuttX to the PinePhone, another ARM Cortex-A based
|
||||
device. The articles are listed `here <https://github.com/lupyuen/pinephone-nuttx>`_. Lup's articles provided me with an
|
||||
understanding of the NuttX boot process, as well as which files from the aarch64 support on NuttX were pulled into the
|
||||
build process for booting. He also showed how he created an initial UART driver using the NuttX structure for UART
|
||||
drivers, which allowed him to get NSH appearing in the console.
|
||||
|
||||
Finally, I also of course needed the BCM2711 datasheet in order to figure out which registers were available to me for
|
||||
creating peripheral drivers. The BCM2711 datasheet isn't exceptionally detailed on many of the features on the SoC, but
|
||||
it did provide enough detail to set up interrupts and get UART working.
|
||||
|
||||
Adding to the source tree
|
||||
-------------------------
|
||||
|
||||
In order to build my code with the NuttX build system, I would have to add the board and the BCM2711 chip to the source
|
||||
tree for NuttX. This way, it would appear as an available configuration via the ``tools/configure.sh`` script and I
|
||||
could select options for it with ``make menuconfig``.
|
||||
|
||||
The first thing to do was to add the chip, which goes under the ``arch/arm64`` directory because it is an ARM 64 bit
|
||||
SoC. The chip directory must be added in two places: ``arch/arm64/include/bcm2711`` and ``arch/arm64/src/bcm2711``. C
|
||||
files go in the ``src`` directory with some header files, and some specific header files go in the ``include``
|
||||
directory.
|
||||
|
||||
In addition, in order to make the BCM2711 visible as a supported chip, I had to add it as an option in
|
||||
``arch/arm64/Kconfig``. In order to do this, I just copy-pasted the entry for the Allwinner A64, since the two chips
|
||||
were very similar. I had to change a few fields (for instance, selecting ``ARCH_CORTEX_A72`` instead of
|
||||
``ARCH_CORTEX_A53``), but this was relatively simple to complete with the information about the SoC. I also needed to
|
||||
specify ``ARMV8A_HAVE_GICv2``, since that is the interrupt controller used by the BCM2711. ``ARCH_HAVE_MULTICPU``
|
||||
because it is a quad-core, and ``ARCH_USE_MMU`` because it has a memory management unit.
|
||||
|
||||
I also needed to now add the Raspberry Pi 4B board to the source tree. To do this, I copied the board folder for the
|
||||
PinePhone (``boards/arm64/a64/pinephone``) and renamed it ``raspberrypi-4b``. I also deleted many of the files in this
|
||||
folder since they weren't applicable to the Pi 4B, and substituted all mentions of the PinePhone with the Raspberry Pi
|
||||
4B (in path names and header include guards).
|
||||
|
||||
I then added the Pi 4B to the list of supported boards in ``boards/Kconfig``. For this, I just needed to create an entry
|
||||
with the name ``ARCH_BOARD_RASPBERRYPI_4B`` and write that it depends on the ``ARCH_CHIP_BCM2711``. No additional
|
||||
options necessary! In two other places in this file I also had to add some directives to make sure the Kconfig for the
|
||||
board was found properly. These set ``ARCH_BOARD`` to the name of the board directory "raspberrypi-4b" when the Pi 4B was
|
||||
selected, and ``source``'d the Kconfig under ``boards/arm64/bcm2711/raspberrypi-4b`` when selected.
|
||||
|
||||
The default configuration for this board was copied from the PinePhone's NSH configuration, which I modified to use the
|
||||
correct board name, chip, and hardware specific settings. It was still incomplete because there was no code to actually
|
||||
boot into NSH, but it was a starting point.
|
||||
|
||||
This was basically all I needed for the board to show up as a possible configuration in the source tree!
|
||||
|
||||
Mapping out the chip
|
||||
--------------------
|
||||
|
||||
To start writing code for the BCM2711, I needed to map out the chip. This included the register addresses and the memory
|
||||
mapping, which could all be found in the BCM2711 datasheet. From looking at other implementations, the register
|
||||
addresses are usually defined as C macros and kept in header files under ``arch/<architecture>/src/<chip>/hardware``.
|
||||
This is where I put them as well, defining all the register mappings the different groups within individual files (i.e.
|
||||
``bmc2711_i2c.h``, ``bcm2711_spi.h``, etc.).
|
||||
|
||||
Many peripherals had groupings of memory-mapped registers, defined using a base address and then offsets from that
|
||||
address to access the different fields. For instance, the two mini-SPI peripherals had the same structure, each with 12
|
||||
registers. The way I commonly saw these macros implemented was something like:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define BCM_AUX_SPI1_BASEADDR (BCM_AUX_BASEADDR + BCM_AUX_SPI1_OFFSET)
|
||||
|
||||
#define BCM_AUX_SPI_CNTL0_REG_OFFSET (0x00) /* SPI control register 0 */
|
||||
/* ... more register offsets */
|
||||
|
||||
/* This allows you to choose which SPI interface base address to get the register for. */
|
||||
|
||||
#define BCM_AUX_SPI_CNTL0(base) ((base) + BCM_AUX_SPI_CNTL0_REG_OFFSET)
|
||||
|
||||
In addition to the registers themselves, I also included macros to mask certain fields within the registers or set
|
||||
certain values. This makes the code less error prone later, because any mistakes made while copying the long list of
|
||||
fields and registers from the datasheet can be changed in one place.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define BCM_SPI_CNTL0_EN (1 << 11) /* Enable SPI interface */
|
||||
|
||||
In addition to the registers, I also had to map the interrupts. This was done in ``include/bcm2711/irq.h``. I copied the
|
||||
IRQ numbers from the datasheet and listed them all as macros with names. I also had to define the number of IRQS, which
|
||||
was 216 in this case. The ``MPID_TO_CORE(mpid)`` macro was copied from another arm64 implementation.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define NR_IRQS 216
|
||||
#define MPID_TO_CORE(mpid) (((mpid) >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK)
|
||||
|
||||
/* VideoCore interrupts */
|
||||
|
||||
#define BCM_IRQ_VC_BASE 96
|
||||
#define BCM_IRQ_VC(n) (BCM_IRQ_VC_BASE + n)
|
||||
|
||||
#define BCM_IRQ_VC_TIMER0 BCM_IRQ_VC(0)
|
||||
#define BCM_IRQ_VC_TIMER1 BCM_IRQ_VC(1)
|
||||
/* More interrupts ... */
|
||||
|
||||
Finally was to define the memory mapping within the ``include/bcm2711/chip.h`` file. I did so simply since I was only
|
||||
testing on the 4GB version of the BCM2711. The RAM starts at address 0, and is roughly 4GB in size. 64 MB of that is
|
||||
reserved for the memory-mapped I/O, so I had to be sure to remove that. I also defined the load address of the kernel in
|
||||
memory for the chip.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define CONFIG_RAMBANK1_ADDR (0x000000000)
|
||||
|
||||
/* Both the 4GB and 8GB ram variants use all the size in RAMBANK1 */
|
||||
|
||||
#if defined(CONFIG_RPI4B_RAM_4GB) || defined(CONFIG_RPI4B_RAM_8GB)
|
||||
#define CONFIG_RAMBANK1_SIZE GB(4) - MB(64)
|
||||
#endif /* defined(CONFIG_RPI4B_RAM_4GB) || defined(CONFIG_RPI4B_RAM_8GB) */
|
||||
|
||||
/* Raspberry Pi 4B loads NuttX at this address */
|
||||
|
||||
#define CONFIG_LOAD_BASE 0x480000
|
||||
|
||||
The same load address had to be specified in the linker script for the Raspberry Pi 4B kernel. This scripts tells the
|
||||
compiler how to lay out the kernel code in memory and what addresses to use. I was able to copy it from the PinePhone
|
||||
and just change the load address to ``0x480000``.
|
||||
|
||||
Figuring out the boot
|
||||
---------------------
|
||||
|
||||
The first thing I wanted to do was determine how much work had already been done for aarch64 that would allow me to more
|
||||
easily complete the port. In Lup's blogs, he tested out support for his core type (ARM Cortex-A53 on the PinePhone) by
|
||||
booting the aarch64 instance of QEMU with NuttX using that core. I decided to take the same approach, and was able to
|
||||
successfully boot on ARM Cortex-A72 using QEMU following his blog. This was a nice confirmation that the hardware I was
|
||||
using was already supported in NuttX for booting the OS and getting NSH working with a PL011 UART interface.
|
||||
|
||||
I cannot stress enough that the reason porting to this chip was made so much easier was because I am standing on the
|
||||
shoulders of giants. NuttX contributors had already set up the boot scripts written in assembly, timer configuration,
|
||||
interrupt handling and drivers for a lot of the standard features in aarch64 architectures. I did not have to deal with
|
||||
any of this because of them, and it really cut down on the amount of assembly I had to read and understand. I also
|
||||
barely had to write any assembly outside of debugging the boot process a little (we'll get to that later). Not to
|
||||
mention I had Lup's well-written articles to guide me.
|
||||
|
||||
In order to compile and boot the board, I had to add a definition for ``g_mmu_config``, which I was confused about and
|
||||
left empty initially just to get past the compilation stage. I also defined the ``GICR_OFFSET`` and ``GICR_BASE`` macros
|
||||
for the GICv2 interrupt controller by copying them from the Allwinner chip, which used the same controller. After
|
||||
reading further in Lup's blog, I learned that the boot script has a ``PRINT`` macro which is called early in the boot
|
||||
process, and requires an implementation of ``up_lowputc`` to print to the console. This would be the first thing I need
|
||||
to implement. This compiled, but when I booted the Pi, nothing happened.
|
||||
|
||||
After quite a while of trying different things and looking at other implementations, I noticed that many people were
|
||||
using register manipulation directly in the early print functions. I decided I would do the same, but instead of
|
||||
printing (a more complex operation), I would turn one of the GPIO pins high. I was able to measure this with my
|
||||
multimeter and confirm that the GPIO did get set, so I knew that the ``arm64_earlyprint_init`` function was getting
|
||||
called. Something was wrong with my UART configuration.
|
||||
|
||||
I then tried directly manipulating registers to put the text "hi" in the UART FIFO. When I booted again, this printed,
|
||||
but then was followed by some garbled output. It appeared that the the ``char *`` pointer passed to the print function
|
||||
was getting garbled. After troubleshooting by printing characters directly by calling my ``arm64_lowputc`` in the
|
||||
assembly boot script, I discovered that I could print a string from the C definition if I declared the string as static.
|
||||
I also investigated the elf generated by building and confirmed the string was located in ``.rodata``. I was suspicious
|
||||
that I was loading the kernel incorrectly into memory and some addresses were getting mixed up. Sure enough, I had
|
||||
defined the load address in the linker script as ``0x80000`` instead of ``0x480000``. Fixing this allowed me to see the
|
||||
boot messages properly!
|
||||
|
||||
I received this message in the console:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
----gic_validate_dist_version: No GIC version detect
|
||||
arm64_gic_initialize: no distributor detected, giving up ret=-19
|
||||
_assert: Current Version: NuttX 12.6.0-RC0 6791d4a1c4-dirty Aug 4 2024 00:38:21 arm64
|
||||
_assert: Assertion failed panic: at file: common/arm64_fatal.c:375 task: Idle_Task process: Kernel 0x481418
|
||||
|
||||
I had accidentally kept the GICv3 in my config files when copying things from other boards, and changed it to GICv2.
|
||||
That resolved the issue and presented me with a new one:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MESS:00:00:06.144520:0:----_assert: Current Version: NuttX 12.6.0-RC0 f81fb7a076-dirty Aug 4 2024 16:16:30 arm64
|
||||
_assert: Assertion failed panic: at file: common/arm64_fatal.c:375 task: Idle_Task process: Kernel 0x4811e4
|
||||
|
||||
After enabling all of the debug output in the build options, this became:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
arm64_oneshot_initialize: cycle_per_tick 54000
|
||||
arm64_fatal_error: reason = 0
|
||||
arm64_fatal_error: CurrentEL: MODE_EL1
|
||||
arm64_fatal_error: ESR_ELn: 0xbf000002
|
||||
arm64_fatal_error: FAR_ELn: 0x0
|
||||
arm64_fatal_error: ELR_ELn: 0x48a458
|
||||
print_ec_cause: SError interrupt
|
||||
|
||||
This looked like an unhandled interrupt, and after narrowing down which line was failing by adding log statements to the
|
||||
kernel code, I discovered it was due to the spinlock code. An exception was being caused by the ``ldaxr`` instruction,
|
||||
which the ARM documentation said could only be used once the MMU was enabled. I then enabled the MMU as well as its
|
||||
debug information and was greeted with the lovely error:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MESS:00:00:06.174977:0:----arm64_mmu_init: xlat tables:
|
||||
arm64_mmu_init: base table(L1): 0x4cb000, 64 entries
|
||||
arm64_mmu_init: 0: 0x4c4000
|
||||
arm64_mmu_init: 1: 0x4c5000
|
||||
arm64_mmu_init: 2: 0x4c6000
|
||||
arm64_mmu_init: 3: 0x4c7000
|
||||
arm64_mmu_init: 4: 0x4c8000
|
||||
arm64_mmu_init: 5: 0x4c9000
|
||||
arm64_mmu_init: 6: 0x4ca000
|
||||
init_xlat_tables: mmap: virt 4227858432x phys 4227858432x size 67108864x
|
||||
set_pte_table_desc:
|
||||
set_pte_table_desc: 0x4cb018: [Table] 0x4c4000
|
||||
init_xlat_tables: mmap: virt 0x phys 0x size 1006632960x
|
||||
set_pte_table_desc:
|
||||
set_pte_table_desc: 0x4cb000: [Table] 0x4c5000
|
||||
init_xlat_tables: mmap: virt 4718592x phys 4718592x size 192512x
|
||||
split_pte_block_desc: Splitting existing PTE 0x4c5010(L2)
|
||||
set_pte_table_desc:
|
||||
set_pte_table_desc: 0x4c5010: [Table] 0x4c6000
|
||||
init_xlat_tables: mmap: virt 4911104x phys 4911104x size 81920x
|
||||
init_xlat_tables: mmap: virt 4993024x phys 4993024x size 65536x
|
||||
enable_mmu_el1: MMU enabled with dcache
|
||||
nx_start: Entry
|
||||
up_allocate_heap: heap_start=0x0x4d3000, heap_size=0x47b2d000
|
||||
mm_initialize: Heap: name=Umem, start=0x4d3000 size=1202900992
|
||||
mm_addregion: [Umem] Region 1: base=0x4d32a8 size=1202900304
|
||||
arm64_fatal_error: reason = 0
|
||||
arm64_fatal_error: CurrentEL: MODE_EL1
|
||||
arm64_fatal_error: ESR_ELn: 0x96000045
|
||||
arm64_fatal_error: FAR_ELn: 0x47fffff8
|
||||
arm64_fatal_error: ELR_ELn: 0x489d28
|
||||
print_ec_cause: Data Abort taken without a change in Exception level
|
||||
_assert: Current Version: NuttX 12.6.0-RC0 96be557b64-dirty Aug 5 2024 14:56:42 arm64
|
||||
_assert: Assertion failed panic: at file: common/arm64_fatal.c:375 task: Idle_Task process: Kernel 0x481a34
|
||||
up_dump_register: stack = 0x4d2e10
|
||||
up_dump_register: x0: 0x13 x1: 0x4d32c0
|
||||
up_dump_register: x2: 0xfe215040 x3: 0xfe215040
|
||||
up_dump_register: x4: 0x0 x5: 0x0
|
||||
up_dump_register: x6: 0x1 x7: 0xdba53f65cc808a8
|
||||
up_dump_register: x8: 0xc4276feb17c016ba x9: 0xecbcfeb328124450
|
||||
up_dump_register: x10: 0xb7989dd7d34a1280 x11: 0x5ebf5f572386fdee
|
||||
up_dump_register: x12: 0x6f7c07d067f6e38 x13: 0x3f7b5adaf798b4d5
|
||||
up_dump_register: x14: 0xf3dffbe2e4cff736 x15: 0xd76b1c050c964ea0
|
||||
up_dump_register: x16: 0x6d6fa9cfeeb0eff8 x17: 0x1a051d808a830286
|
||||
up_dump_register: x18: 0x3f7b5adaf798b4bf x19: 0x4d3000
|
||||
up_dump_register: x20: 0x47fffff0 x21: 0x4d32d0
|
||||
up_dump_register: x22: 0x47b2cd30 x23: 0x4d32a8
|
||||
up_dump_register: x24: 0x4d32b0 x25: 0x4806f4
|
||||
up_dump_register: x26: 0x2f56f66b2df71556 x27: 0x74ee6bbfb5d438f4
|
||||
up_dump_register: x28: 0x7ef57ab47b85f74f x29: 0x9a7fa1cb06923003
|
||||
up_dump_register: x30: 0x489cf8
|
||||
up_dump_register:
|
||||
up_dump_register: STATUS Registers:
|
||||
up_dump_register: SPSR: 0x600002c5
|
||||
up_dump_register: ELR: 0x489d28
|
||||
up_dump_register: SP_EL0: 0x4d3000
|
||||
up_dump_register: SP_ELX: 0x4d2f40
|
||||
up_dump_register: TPIDR_EL0: 0x0
|
||||
up_dump_register: TPIDR_EL1: 0x0
|
||||
up_dump_register: EXE_DEPTH: 0x1
|
||||
|
||||
Some more debugging allowed me to determine that the ``CONFIG_RAM_START`` and ``CONFIG_RAM_SIZE`` macros in the
|
||||
defconfig for my nsh configuration were still set to the values from the PinePhone that I copied from. I set these to
|
||||
the correct values for the Raspberry Pi 4B and got much further!
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
MESS:00:00:06.211786:0:----irq_attach: In irq_attach
|
||||
irq_attach: before spin_lock_irqsave
|
||||
spin_lock_irqsave: me: 0
|
||||
spin_lock_irqsave: before spin_lock
|
||||
spin_lock: about to enter loop
|
||||
spin_lock: loop over
|
||||
spin_lock_irqsave: after spin_lock
|
||||
irq_attach: after spin_lock_irqsave
|
||||
irq_attach: before spin_unlock_irqrestore
|
||||
irq_attach: after spin_unlock_irqrestore
|
||||
arm64_serialinit: arm64_serialinit not implemented
|
||||
group_setupidlefiles: ERROR: Failed to open stdin: -38
|
||||
_assert: Current Version: NuttX 12.6.0-RC0 be262c7ad3-dirty Aug 5 2024 17:16:27 arm64
|
||||
_assert: Assertion failed : at file: init/nx_start.c:728 task: Idle_Task process: Kernel 0x48162c
|
||||
up_dump_register: stack = 0x4c0170
|
||||
up_dump_register: x0: 0x4c0170 x1: 0x0
|
||||
up_dump_register: x2: 0x0 x3: 0x0
|
||||
up_dump_register: x4: 0x0 x5: 0x0
|
||||
up_dump_register: x6: 0x3 x7: 0x0
|
||||
up_dump_register: x8: 0x4c7468 x9: 0x0
|
||||
up_dump_register: x10: 0x4c7000 x11: 0x4
|
||||
up_dump_register: x12: 0x4b8000 x13: 0x4b7000
|
||||
up_dump_register: x14: 0x1 x15: 0xfffffff7
|
||||
up_dump_register: x16: 0x48a654 x17: 0x0
|
||||
up_dump_register: x18: 0x1 x19: 0x0
|
||||
up_dump_register: x20: 0x4ac181 x21: 0x4bf430
|
||||
up_dump_register: x22: 0x0 x23: 0x4c0170
|
||||
up_dump_register: x24: 0x4c0170 x25: 0x2d8
|
||||
up_dump_register: x26: 0x240 x27: 0x4b7000
|
||||
up_dump_register: x28: 0xfdc3ed41d6862df6 x29: 0xbf8e8f7280a0100
|
||||
up_dump_register: x30: 0x481bf8
|
||||
up_dump_register:
|
||||
up_dump_register: STATUS Registers:
|
||||
up_dump_register: SPSR: 0x20000245
|
||||
up_dump_register: ELR: 0x480230
|
||||
up_dump_register: SP_EL0: 0x4c7000
|
||||
up_dump_register: SP_ELX: 0x4c6e90
|
||||
up_dump_register: TPIDR_EL0: 0x4bf430
|
||||
up_dump_register: TPIDR_EL1: 0x4bf430
|
||||
up_dump_register: EXE_DEPTH: 0x0
|
||||
dump_tasks: PID GROUP PRI POLICY TYPE NPX STATE EVENT SIGMASK STACKBASE STACKSIZE USED FILLED COMMAND
|
||||
dump_tasks: ---- --- --- -------- ------- --- ------- ---------- ---------------- 0x4c4000 4096 144 3.5% irq
|
||||
dump_task: 0 0 0 FIFO Kthread - Running 0000000000000000 0x4c5010 8176 1200 14.6% Idle_Task
|
||||
|
||||
CTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.9 | VT102 | Offline | ttyUSB0
|
||||
|
||||
We actually got into tasks now! It appears stdin failed to open because in my Mini-UART driver implementation I had the
|
||||
``attach`` and ``ioctl`` functions return ``-ENOSYS``. Just changing this to 0 for success in the interim allowed us to
|
||||
get even further, and I could see the beginnings of NSH spawning.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
mm_initialize: Heap: name=Umem, start=0x4cc000 size=4222828544
|
||||
mm_addregion: [Umem] Region 1: base=0x4cc2a8 size=4222827856
|
||||
mm_malloc: Allocated 0x4cc2d0, size 144
|
||||
mm_malloc: Allocated 0x4cc360, size 80
|
||||
gic_validate_dist_version: GICv2 detected
|
||||
up_timer_initialize: up_timer_initialize: cp15 timer(s) running at 54.0MHz
|
||||
arm64_oneshot_initialize: oneshot_initialize
|
||||
mm_malloc: Allocated 0x4cc3b0, size 48
|
||||
arm64_oneshot_initialize: cycle_per_tick 54000
|
||||
uart_register: Registering /dev/console
|
||||
mm_malloc: Allocated 0x4cc3e0, size 80
|
||||
mm_malloc: Allocated 0x4cc430, size 80
|
||||
uart_register: Registering /dev/ttys0
|
||||
mm_malloc: Allocated 0x4cc480, size 80
|
||||
mm_malloc: Allocated 0x4cc4d0, size 80
|
||||
mm_malloc: Allocated 0x4cc520, size 80
|
||||
mm_malloc: Allocated 0x4cc570, size 32
|
||||
mm_malloc: Allocated 0x4cc590, size 64
|
||||
work_start_highpri: Starting high-priority kernel worker thread(s)
|
||||
mm_malloc: Allocated 0x4cc5d0, size 336
|
||||
mm_malloc: Allocated 0x4cc720, size 8208
|
||||
nxtask_activate: hpwork pid=1,TCB=0x4cc5d0
|
||||
nx_start_application: Starting init thread
|
||||
task_spawn: name=nsh_main entry=0x48b24c file_actions=0 attr=0x4cbfa0 argv=0x4cbf98
|
||||
mm_malloc: Allocated 0x4ce730, size 1536
|
||||
mm_malloc: Allocated 0x4ced30, size 64
|
||||
mm_malloc: Allocated 0x4ced70, size 32
|
||||
mm_malloc: Allocated 0x4ced90, size 8208
|
||||
nxtask_activate: nsh_main pid=2,TCB=0x4ce730
|
||||
lib_cxx_initialize: _sinit: 0x4ad000 _einit: 0x4ad000
|
||||
mm_malloc: Allocated 0x4d0da0, size 848
|
||||
mm_free: Freeing 0x4d0da0
|
||||
mm_free: Freeing 0x4ced70
|
||||
mm_free: Freeing 0x4ced30
|
||||
nxtask_exit: nsh_main pid=2,TCB=0x4ce730
|
||||
mm_free: Freeing 0x4ced90
|
||||
mm_free: Freeing 0x4ce730
|
||||
nx_start: CPU0: Beginning Idle Loop
|
||||
|
||||
It seemed like we were waiting on an interrupt which never occurred. This was weird, because my Mini-UART driver had an
|
||||
interrupt implementation and appeared to be written just fine. This took hours of debugging, logging from interrupt
|
||||
handlers and dumping register values, but eventually I determined that the BCM2711 datasheet actually had an error where
|
||||
the TX and RX interrupt fields were swapped in the datasheet. A blog post online had mentioned this for the BCM2835, but
|
||||
it appeared to be an issue on this chip as well. Now we were booting into NSH!
|
||||
|
||||
It was at this point that the port is considered a success, since I was able to boot into NSH and successfully run the
|
||||
``ostest`` benchmark. I went on to write the start of a few more drivers, like the GPIO driver, but this completed the
|
||||
requirements for an initial port and is most of what ended up being submitted in the initial pull request.
|
Loading…
Reference in a new issue