The PinePhone is an open hardware smartphone from Pine64. It features all the stuff you'd expect from a modern smartphone, although don't expect the latest and greatest variants of each. Full schematics are available on the Pine64 wiki. Unfortunately, open hardware does not mean that full datasheets for all chips are available.
Beware the slight but incompatible changes between different hardware revisions - such as different GPIO pins being used. This page is written about the Community Edition with the v1.2b mainboard, the latest as of writing.
The PinePhone Pro is a different device with similar but incompatible hardware! (such as an entirely different CPU chip from Rockchip)
- https://linux-sunxi.org/File:Allwinner_A64_User_Manual_V1.1.pdf - includes memory map; full register documentation for several basic peripherals including GPIOs, DMA, timers...
The CPU is an Allwinner A64 (a.k.a. "sun50i"), which is also used in some of Pine64's single-board mcomputers. Although Allwinner does not release full documentation, significant reverse-engineered information is available through the linux-sunxi project. This is presumably one reason Pine64 chose this CPU.
To write an SD/eMMC image you need the mksunxiboot tool from the u-boot-tools package (may vary by distribution). [TODO: or you could just write the header yourself]
To use FEL you also need the sunxi-fel tool from the sunxi-tools package.
Since the OS controls all signs of whether the phone is powered on, it's probably a good idea to remove the battery, so that you can be sure whether the phone is on or off. Also, some aspects of battery charging are controlled by the OS, so this removes any chance of accidentally damaging it by applying incorrect settings (not sure if this is possible/likely). The cellular modem is powered directly from the battery and won't work if the battery is not inserted - but this won't be a problem until your OS is quite well developed. The CPU seems to work just fine while the battery is removed.
The CPU first boots from an integrated boot ROM, which then tries to boot from one of these sources:
- The microSD card, if present and boot signature (eGON header) is found
- The internal eMMC storage, if boot signature (eGON header) is found
- The FEL mode ROM - a USB slave mode where the host computer can read, write and execute memory.
There is also an FEL button that can theoretically be pressed to force boot in FEL mode, but on the PinePhone it is only connected to a test pad, not to an actual button.
The normal way to prepare an OS for the PinePhone is to flash a microSD card and insert it. The OS may then offer an option to install itself onto the eMMC. However, when getting started with osdev, FEL mode (which allows loading code via USB) should allow for a much faster testing cycle.
For your OS, you can choose to boot via U-boot [TODO] or directly into your own "bootloader".
Loading code via microSD/eMMC
Boot signature / eGON header starts at address 8192 and occupies (theoretically) up to 32KB. This region is often left unallocated; if you're low on microSD cards, you might be able to share one with a Raspberry Pi project for example, without constantly re-flashing it.
Loading code via FEL
FEL is executed if:
- You have no valid bootloader installed (eGON header not found) on microSD card nor eMMC
- You press the FEL key (not applicable to Pinephone)
- You call the FEL boot code directly
Third option is possible by writing a tiny stub to a microSD card. This is available in sunxi-tools by the name of fel-sdboot. Run make fel-sdboot.sunxi. It makes an 8kB file but only the first 124 bytes are used. Write the file to offset 8192 on any microSD card:
sudo dd if=fel-sdboot.sunxi of=/dev/NAME_OF_SD_CARD_DEVICE bs=8192 seek=1 count=1
and you can insert this microSD card to trigger FEL mode.
NOTE: When in FEL mode, the phone provides absolutely no visible sign that it is turned on. You can check by running lsusb on the host computer - you should see a USB device like this one:
Bus 001 Device 012: ID 1f3a:efe8 Allwinner Technology sunxi SoC OTG connector in FEL/flashing mode
and you can verify it by running sunxi-fel version:
sunxi-tools$ ./sunxi-fel version AWUSBFEX soc=00001689(A64) 00000001 ver=0001 44 08 scratchpad=00007e00 00000000 00000000
Loading code example
sunxi-fel write 0x00010000 code.bin sunxi-fel execute 0x00010000
Your code can execute BX LR to return back to the boot loader.
To see if your toolchain works you can try to run User:Immibis/PinePhone Blinky.
Why 0x00010000? According to the memory map this region 0x00010000-0x00017FFF is where the boot ROM normally loads user code,
which means it shouldn't conflict with anything used by the boot ROM (e.g. to support the USB interface). region 0x00010XXX is fine, 0x00011XXX conflicts and breaks USB. Comments in the sunxi-fel tool indicate regions 0x11c00-0x11fff (IRQ stack), 0x15c00-0x16fff (actual stack), and 0x17c00-0x17fff ("something important", probably USB-related data structures or similar) are important. Additionally, the tool uses 0x31400-0x32fff to hold backup copies of these.
It can also use 0x11000-0x113FF to hold code and data for more complex commands.
Maybe 0x18000 (SRAM C) is a good load location. 0x19400 bytes (~48k) should be available. If using SRAM C, don't set 0x01C202C4 (Bus Clock Register1) bit 0x00000001 (Gating Clock VE) to 0 as this seems to make SRAM C inaccessible. I guess it's connected to the video engine?
Alternatively you could initialize DRAM and then load your code into DRAM, as two separate steps.
Custom bootloader stuff
Skip this section if you are running your OS from U-Boot.
You might notice accessing the 2GB/3GB (depending on model) DRAM area at address 0x40000000 upwards causes the processor to hang, so you only have the SRAM areas (a few hundred kB) to play with. That's because the boot ROM doesn't initialize the DRAM controller. It only uses ROM and SRAM. On a PC, the BIOS would have initialized the memory for you, but this is an embedded system, not a PC. The bootloader is the BIOS, and you are the bootloader.
As this is a battery-powered device, power is a big issue. The system has no less than eighteen power supplies which can be turned on and off individually and have adjustable voltages. These are all controlled by the AXP803 power management chip, which also manages the battery detection and charging. There are a few power rails not controlled by the AXP803, such as the USB power output (not input).
Turning off chips you're not using will make the battery last longer! But at the beginning you probably need to turn things on. The display screen is not powered by default.
The AXP803 can be accessed by the S-TWI interface located on GPIOs PL0 and PL1. The TWI interface block hasn't been explored yet, but you can write bit-banging code using the GPIO. For details how to access those GPIOs see the. Note that I2C is an open-drain protocol, so you should switch the pins between input mode and output-0 mode. Setting them to output 1 has a small chance of damaging either the CPU or the AXP due to a logic level conflict, so don't do it. Because it's open-drain you should also enable pull-up resistors on the CPU side. (Actually it's not clear whether the AXP already has built-in pullups. Having two sets doesn't hurt, but it might waste a little bit of power)
Before accessing PL0/PL1 you must enable bit 0 (0x00000001) in register 0x01F01428. Port PL is on a separate section of the CPU from all the other GPIO ports. This bit enables the clock to this section. Otherwise the section ignores register writes.
The AXP803's I2C address is 0x68 (write) / 0x69 (read) / 0x34 (7-bit address format).
You can write a register by writing the register number and then the value (that's start signal, send 0x68, send register number, send value, stop signal). You can read a register by writing the register number and then reading the value (start signal, send 0x68, send register number, repeated start signal, send 0x69, read value, stop signal). Remember that when changing I2C transfer direction, you should send a repeated start condition and send the device address again (with the new direction). After reading one register, send ACK if you want to read the next register or NACK if you want to finish. If you send ACK and then stop, the chip's I2C interface will be left in a weird state and you'll have to . If you keep reading bytes after the first one, you read the next register, and the next.
Registers 0x00-0x03 are useful to see if your reading code works correctly; registers 0x04-0x0F are scratch registers with no purpose which you can write and then read to test the writing.
List of built-in peripherals
- CPU's SDC2 port is connected to the eMMC chip.
- CPU's SDC0 port (4 bits wide) connected to the SD card.
- GPIO PF6 detects whether a card is inserted.
Power management unit (PMU)
Chip type: AXP803
- CPU's PL0/PL1 connected to this chip's I2C port for configuration and status
- Resets the CPU when power is not okay
- Triggers NMI on CPU
- No idea why it connects to USB0 data pins
Powered by VCC-PG, VCC-WiFi, DCDC1.
RTL8723CS chip. 4-bit-wide SD interface connects to CPU's SDC1 interface (Port PG).
- CHIP_EN is controlled by a hardware switch under the back cover.
- CPU's SDC1 interface (4 bits wide) is connected to the SD interface on this chip
- UART (not BT_UART1) connects to CPU UART1. Only TX/RX/CTS. It seems RTS was accidentally not connected on the schematic, despite being labeled?
- BT_UART1 is not connected.
- CPU's PCM1 interface is connected to this chip.
- Additional GPIO connections - labeled as they appear on the schematic: BT-RST-N, BT-WAKE-AP, WL-PMU-EN, AP-WAKE-BT
Pogo pin expansion port
General purpose low-speed interface exposed via 6 pogo pins (springy pins) inside the back cover.
Power pins: DCIN directly connects to the USB port's power rail. USB-5V is the voltage the phone could output to the USB port, but doesn't have to actually output as there is a switch in the way. Software can turn on a boost converter to get 5V here, otherwise you get slightly lower than the main system voltage (3 to 5V).
Data pins: SDA/SCK/INT connect to GPIOs PE15, PE14 and PL12 respectively. The I2C pins (SDA/SCK) do connect to a hardware I2C block which is dedicated for this port.
Audio interfaces built into the CPU.
- PHONEIN, LINEIN, PHONEOUT: Unused - connected to nothing - don't even bother.
- EAROUT: is the "receiver" (top speaker when using as a phone?) Direct connection, no other power supply needed.
- LINEOUT: is the main speaker, amplified via U800. You have to tell the amplifier to actually work by outputting high(?) from GPIO pin PC7. Turn it off when unused, to avoid wasting power.
- HPOUT: to the headphone jack. There's a DETect pin which tells you if something is plugged into the port. When the back cover switch is set to disable headphones, it triggers an analog switch to connect the UART instead of the headphones, and it also overrides the detect signal so it detects nothing plugged in. It doesn't affect the microphone connection, and allegedly the analog switch might not fully isolate the sound signal from the UART, so you probably don't want to play sound.
- MIC2: is the headphone jack microphone port. For headphones without microphone it's just shorted to ground. Microphone power provided by HBIAS from CPU, through a high resistance so there is no problem even if microphone is shorted to ground.
- MIC1: is the microphone below the screen. Microphone power provided by MBIAS from CPU; interrupted by one of the switches under the back cover. Hopefully the microphone doesn't work without this power.
Headphone jack UART: It's UART0 on the CPU, PB8=TX, PB9=RX
[not researched, no idea how to make it work]
CSI occupies pins PE0 (PCLK), PE1 (MCLK), PE2 (HSYNC), PE3 (VSYNC), PE4-PE11 (D0-D7), PE12 (SCK), PE13 (SDA).
Front and rear camera both use the same CSI port, at the same time. Activating both cameras presumably causes corrupted data (but won't damage hardware due to the use of resistors for current limiting). Only use one at a time.
Each camera has its own RST and STBY pins which are pulled up (TODO: that means they're off, right?) and connected as follows:
|Front camera||Rear camera|
U1000 controls the flash LED from the battery (therefore probably requires an inserted battery)
GPIO PD24 = PD24-FLASH-TRIGOUT = EN pin
GPIO PC3 = PC3-FLASH-EN = FLASH pin
(names are swapped, yes. They can be either way around according to the schematic. TODO: which way is it really?)
Theory: GPIO PH10 enables the boost converter U1100 which creates a high voltage to power the backlight (note it's configured as constant current rather than constant voltage).
Pin configuration PH10: write 0x0000X1XX to address 0x01C20900 (upper 16 bits are unused)
Pin control PH10: bit 0x00000400 at address 0x01C2090C - set it true to enable
GPIO PL10 is a PWM signal that gets smoothed out and then alters the feedback signal received by U1100. High feedback signal causes U1100 to believe the output current is higher than it really is, so it decreases it. This is a normal way for these converters to work, and does not cause any problem. However, the author wasn't able to make this work yet, and skipped over it because the backlight did turn on even without touching PL10.
Pin configuration PL10: write 0x000XX1XX (GPIO) or 0x000XX2XX (PWM) to address 0x01F02C04 (upper 12 bits are unused)
Pin control PL10 (GPIO mode): bit 0x00000400 at address 0x01F02C10 - set it false (default value) for full brightness backlight. In reality, writing to this pin didn't do anything. Actually, the author did not get PL10 to do anything. The backlight was enabled even without touching PL10. When configured as an input, it read as low. Possibly the power rail ALDO2 has to be enabled first?
According to U1100's datasheet, you could also try adjusting the brightness by PWMing PH10, or both at once, however PH10 has no PWM hardware attached, only MIC_CLK (which maybe you could hack to get a 50% PWM). It's also not clear whether the output has enough filtering to make this not flicker. The schematic allows for the possibility to swap PL10 and PH10 (so that EN pin has the PWM hardware) by re-soldering a jumper.
[not researched, no idea how to make it work]
Also known as CTP (capacitive touch panel). Connected by TWI0 bus and 2x GPIO (interrupt + reset)
[not researched, no idea how to make it work]
MIPI-DSI connected to the CPU. Two additional GPIOs: PD7 connects to DSI-TE (?) and PD23 connects to LCD-RESET#
Front LED and rumble motor
Simple on/off switches (GPIOs) controlled by software.
To configure the LED pins for generic output, write 0xXXX111XX to address 0x01C20874. The X are bits that are irrelevant to LEDs. Default value for each X is 7, so write 0x77711177 if you're only using the LEDs and nothing else on this port. To configure the motor pin, write 0xXXXXX1XX to address 0x01C2086C. Then four of the bits in address 0x01C2087C control these features - see below.
Note the R/G/B channel order is mislabeled in the schematic (and in two different ways!) - the order below was actually tested.
|Control bit||GPIO number|
TWI1-SDA/TWI1-SCK is connected to a few sensor chips you'd expect on phones. Some alternative parts may be used depending on what was available when your phone shipped.
All these sensors communicate over I2C bus connected to TWI1-SCK (PH2) and TWI1-SDA (PH3) and are powered by DLDO1; STK3311-A also powered by GPIO0-LDO (as well as DLDO1).
Proximity and ambient light sensor: STK3311-A (U1201)
INT pin connects to GPIO PB0
6-axis (i.e. 3-axis + 3-axis) gyroscope and accelerometer: MPU6050 (U1202) or BMI120 (U1204)
INT pin connects to GPIO PH5
3-axis magnetometer: LIS3MDL (U1200) or AK09911/AF8133J (U1203): ?
DRDY pin (LIS3MDL) or RSTN (AK*) connects to GPIO PB1.
KEYADC connects to VOL+ and VOL-, forming a resistor divider with a different value depending on which one is pressed. VOL+ has priority. If VOL+ is pressed it's not possible to detect whether VOL- is also pressed. (A shame. It would've cost nothing to give them separate pins, since there are still spare pins available!)
The reset button resets the CPU by pulling down AP-RESET#. Note that it doesn't reset other chips.
The power key goes to a signal called PWRON on the AXP803.
4G cellular modem
[Not really researched, no idea how to make it work]
Powered by VDD_EXT (what is that?) and VBAT and DCDC1
VBAT is only connected to the modem when GPIO PL7 is high and the modem is enabled using the switch under the back cover.
- Connected to SIM card slot (nothing else can access the SIM card)
- CPU's PCM0 connects to modem's PCM port (digital audio data, bidirectional)
- CPU's UART3 connects to modem's UART port - well, data lines are UART3 on the CPU but control lines are all over the place and not on UART3.
- CPU's USB1 connects to modem's USB port.
- Other GPIOs: AP_READY, W_DISABLE#, RESET_N, PWRKEY
- A whole lot of unconnected interfaces, including EPHY, SGMII, dual SIM, SDC1, SDC2, WLAN_EN, BT_EN, DBG_
[Not really researched, no idea how to make it work]
The ANX7888 is a big complicated-looking chip with many ports and its own firmware. It appears to control auxiliary functions of the USB port including the DisplayPort Alternate Mode, and possibly cable detection, orientation, and . Note that the main USB D+/D- lines bypass the chip and go directly to the CPU. Likewise the USB power input goes directly to the AXP803 which automatically uses it to power the system. The phone probably will not output power by default.
- HDMI input from CPU. Also DDC I2C and HHPD pins.
- Control via CSCL/CSDA pins via TWI0-SCK (GPIO PH0) / TWI0-SDA (GPIO PH1) bus
- USB to the USB connector: SSTX, SSRX, AUX and CC wires.
- Other GPIOs: POWER_EN, RESET_N, ALERT_N, CABLE_DET
Special power signals for USB:
- GPIO PD11 tells U1300 to generate some of the power rails for the ANX.
- GPIO PD9 tells U1308 to create 5V for the USB CC1/CC2 signalling pins (the ANX chip controls the pin state).
- GPIO PD8 tells U601 to create 5V for the USB power output. This 5V (USB-5V) is only actually connected to the USB port based on DRVVBUS signal, which is connected to AXP803's N_VBUSEN signal, and the ANX7888's VBUS_CTRL signal (but NOT the CPU pin labelled DRVVBUS). TODO: so when is it active?