Porting From RPI2 to RPI3

Disclaimer: I do not work for Sony, despite the disturbing percentage of my shirts, jackets, and bookbags that are PlayStation dev-related. I do, however, have many friends that work at Sony, some of which I hope will call off the corporate lawyers. JayStation is in no way associated with Sony or PlayStation, and any stupid things I say represent only my own ineptitude and silliness.

Minor Revisions

It all started when GDC superhero and primary source of my inferiority complex Graham Wihilididalolz had asked me about getting JayStation2 running on his Pi. Graham had wisely chosen to attempt this with an RPI2, since RPI3 moved to a 64-bit Cortex-A53, and therefore my RPI2-based stuff surely wouldn’t boot on such a totally different CPU.

Funny story. It didn’t boot anyway. Turns out my code was depending on a minor HW difference that was introduced between RPI2’s v1.1 and v1.2 board revisions. That ever so small change was a swapping of the old Cortex-A7 CPU for the same A53/2837 found in the RPI3. Allegedly they were having a hard time sourcing the old part, and switched to the new CPU without bothering to make a big deal of it.

At this point, I said screw it, and ported the whole thing to RPI3. This post is an open topic that I will keep adding to as I find more differences. If I’m missing anything, please let me know and I will update.

UART Clock Speed

The UART clock has gotten a bit of a speed bump on RPI3, from 3MHz to 48MHz. This was originally pointed out to me by Mike Nicolella, and later confirmed by querying clock ID 2 (UART) via mailbox property interface. However, if you are lazy and don’t feel like querying, all that’s required is the following change to the integer and fractional parts of the baud rate divisor

.if RPI_VERSION == 3
	; Divider = 48000000 / (16 * 115200) = 26.0416666667 = ~26.
	; Frac part = (0.0416666667 * 64) + 0.5 = 3.1666666688 = ~3.
	mov r2, #26
	str r2, [r0, #UART0_IBRD]
	mov r2, #3
	str r2, [r0, #UART0_FBRD]
.endif
.if RPI_VERSION == 2 
	; Divider = 3000000 / (16 * 115200) = 1.627 = ~1.
	; Frac part = (0.627 * 64) + 0.5 = 40.6 = ~40.
	mov r2, #1
	str r2, [r0, #UART0_IBRD]
	mov r2, #40
	str r2, [r0, #UART0_FBRD]
.endif

Exact same code, you just use a different clock in the calculation.

UART GPIO Pin Config

For some reason I don’t fully understand, GPIO pins 14 and 15 had their functions changed around to default to something bluetooth related. This is even stranger, because they chose to use the pins from the only UART in the system with a stable clock. Its easy enough to fix, just set GPIO pins 14 and 15 to alt func 0 (0b100).

ldr r1, =GPIO_BASE_ADDR

; pins 14 and 15 must be manually mapped to txd0 and rxd0
; because now they are blue teeth. Use alt func 0 (0b100)
; word 0 is config for pins [0..9],
;/ and word 1 is config for pins [10..19]
ldr r2, [r1, #4]	; load word 1 for pins [10..19]
mov r3, #0b100100	; pins 14 and 15 want to be 0b100 (alt func 0)
bfi r2, r3, #12, #6	; insert config into bits [17..12]
str r2, [r1, #4]	; store it back
MMU Registers

The SMP bit, responsible for marking a CPU as part of the inner shareable domain, has changed location. It used to be bit 6 of the ACTLR register, and is now bit 6 of the CPUECTLR register.

.if RPI_VERSION == 3
	; ACTLR register changed from A7 to A52.
	; The SMP bit went to CPU ECTLR
	mrrc p15, 1, r0, r1, c15
	orr r0, r0, #( 1 << 6 )
	mcrr p15, 1, r0, r1, c15
.endif
.if RPI_VERSION == 2 
	; ACTLR ONLY WORKS ON THE A7
	mrc p15, 0, r0, c1, c0, 1
	orr r0, r0, #( 1 << 6 )
	mcr p15, 0, r0, c1, c0, 1
.endif
RGB <=> BGR

I’m not sure whether this is a hardware change, or if its related to using different GPU firmware and boot files, but the pixel order seems to have been swapped going from RPI2 to RPI3. This doesn’t affect you if you are writing render targets via the GPU, but anything written by the CPU has to be careful. The order can be changed and queried via mailbox property interface. For example

Get pixel order
Tag: 0x00040006
Request:
	Length: 0
Response:
	Length: 4
	Value:
		u32: state
State:
	0x0: BGR
	0x1: RGB

Set pixel order
Tag: 0x00048006
Request:
	Length: 4
	Value:
		u32: state (as above)
Response:
	Length: 4
	Value:
		u32: state (as above)

I’m not currently in a position to try this on my RPI2, but I would love for someone else to try and let me know what the default is.

LED Blinker

I still haven’t looked into this but its on my list. Seems the ACT LED has been moved off the GPIOs and now must be controlled via mailbox. Its not super high priority for me, but be aware this might be why your LED no longer works

First Time Setup

Disclaimer: I do not work for Sony, despite the disturbing percentage of my shirts, jackets, and bookbags that are PlayStation dev-related. I do, however, have many friends that work at Sony, some of which I hope will call off the corporate lawyers. JayStation is in no way associated with Sony or PlayStation, and any stupid things I say represent only my own ineptitude and silliness.

First of all you are going to need a Raspberry Pi 3. While you probably don’t need the exact same hardware I have, be aware things do change between revisions. For example when the Raspberry Pi 2 went from revision v1.1 to v1.2, the CPU was quietly switched from a 32-bit Cortex-A7 with BCM2836 to a 64-bit Cortex-A53 with BCM2837. Just to be safe, I’d recommend you stick to an RPI3 revision v1.2, which is what I am currently testing on. I got mine from adafruit here.

The only other hardware you’ll need aside from that is a MicroSD card, a MicroSD card writer, a USB to GPIO cable, a mini-USB to USB cable (or an actual power adapter) to power the thing, and an HDMI cable. You can probably get away with whatever you have lying about the house, but this is the cable I am using. Note that this is just what is required for initial basic setup. Down the road, other things will be needed for the JouleShock controller, JTAG debugging, and various other odds and sods.

Step 0: Syncing And Software Environment Setup

While you wait for the post to deliver all that, you might as well get your software environment set up. Many of the temporary programs I am using for dev are in my JayStation public repo, so syncing that is a good place to get started. I suggest installing either TortoiseHG Workbench or SourceTree as a client, and syncing my public JayStation2 repo. Once you have that synced, take a look at the directory structure. Some of the more useful bits include

  • kernel_loader: sits on the SD card and receives OS updates over UART
  • tools: serial terminal, and some various drivers for things
  • test_harness: tests for various things that will eventually live in the OS
  • help: premade SD card directory, and images of various program setups
  • videocore_compilers: JSSL and GOAL, in-progress shader compilers

You will need a few other things like Visual Studio 2015 Community Edition, the “latest” Yagarto ARM assembler, and some kind of make utility like what would come with Cygwin or MinGW (update: MinGW’s make seems to not work with my makefiles, as it wants the slashes to go in the opposite direction). Once those are installed, you should be able to open up jaystation2/test_harness/project/JayStationTestHarness/JayStationTestHarness.sln and rebuild the solution with no errors. Now would also be a good time to install the driver for your serial adaptor. If you bought the same one I did, the driver can be found under jaystation2/tools/silicon_labs_cp210x/

Step 1: SD Card Setup and First Boot

Go ahead and pop your MicroSD card into the writer and plug that into your computer. If the existing filesystem is FAT32, all you will need is to copy the contents of jaystation2/help/SD_card_fs_with_kernel_loader_RPI3/ to the SD card root directory. This includes files

  • start.elf: GPU firmware
  • bootcode.bin: programs GPU firmware and starts the GPU
  • fixup.dat: controls how unified memory is split between CPU and GPU
  • config.txt: options to load my bootloader at address 0
  • kernel7.img: this is my custom JayStation bootloader

Then eject the mounted SD card, pop it in your Pi, and you are ready to rock. Connect the HDMI cable from your Pi to your monitor and connect USB serial cable as shown in the image below, with black going to ground pin 6, white going to tx pin 8, and green going to rx pin 10.

Plug the USB end into your USB port, but don’t connect the power cable quite yet or you will miss the boot message. Launch the serial terminal at jaystation2/tools/terminal/Terminal.exe and configure the following settings. COM port = <whatever your device expects, usually 3>, baud = 115,200, data bits = 8, parity = none, stop bits = 1, handshaking = none, and clear the custom BR field.

Press the connect button to connect, and finally connect the power cable to the Pi. If all went right, you should be greeted with a loader welcome message and a colorful pattern on your monitor.

Step 2: Loading a Sample OS Kernel

With the loader standing by, click on the Send File button in the terminal app and select jaystation2/test_harness/kernel7.JUP, the JayStation Update file you previously built when rebuilding the JayStationTestHarness.sln Visual Studio solution in step 0. Your terminal program will show a “progress bar” while various sections load, followed by all kinds of crazy hardware test related spam. If you look at your monitor, you will see a test triangle textured with the legendary Cort “Danger” Stratton’s face.

Welcome to JayStation dev.