NuttX RTOS for PinePhone: Exploring USB

📝 20 Feb 2023

PinePhone talks to LTE Modem over USB

PinePhone talks to LTE Modem over USB

Over the past 17 articles we talked about porting to Pine64 PinePhone a Real-Time Operating System: Apache NuttX RTOS.

Today NuttX can run Touchscreen Apps on PinePhone… But it ain’t done yet till we can make Phone Calls and send Text Messages!

In this article we’ll dive into PinePhone’s USB Controller

Our journey down the PinePhone USB Rabbit Hole begins with a curious comment…

Quectel EG25-G LTE Modem inside PinePhone

Quectel EG25-G LTE Modem inside PinePhone

§1 PinePhone + NuttX = Feature Phone

Now that NuttX can run Touchscreen Apps on PinePhone… What next?

We might turn PinePhone on NuttX into a Feature Phone, thanks to an inspiring comment on YouTube…

“I’d like to use or build a ‘feature-phone’-style UI for the PinePhone someday”

“Is there USB support (In NuttX, and your port)? I think that would be the first step in getting the modem to work”

(Source)

Excellent Idea! We’ll turn NuttX on PinePhone into a Feature Phone

Just Voice Calls and SMS, using PinePhone’s LTE Modem.

(LTE Modem is the hardware inside PinePhone that handles 4G Voice Calls, SMS and Mobile Data)

Why is this useful?

Maybe we can pop a microSD Card (and SIM) into any PinePhone…

And turn it instantly into an Emergency Phone with NuttX?

What if there’s no LTE Network Coverage? Like in a Natural Disaster?

The Long-Range, Low-Power LoRa Network might be good for search and rescue communications.

We could attach the PineDio LoRa Add-On Case to turn PinePhone into a LoRa Communicator.

(More about this)

Will PinePhone on NuttX become a fully-functional smartphone?

Maybe someday? We’re still lacking plenty of drivers: WiFi, Bluetooth LE, GPS, Audio, …

Probably better to start as a Feature Phone (or LoRa Communicator) and build up.

Let’s talk about PinePhone’s LTE Modem…

Quectel EG25-G LTE Modem

Quectel EG25-G LTE Modem

§2 Quectel EG25-G LTE Modem

What’s this LTE Modem?

Check out the article…

Inside PinePhone is the Quectel EG25-G LTE Modem for 4G Voice Calls, SMS, Mobile Data and GPS (pic above)…

To control the LTE Modem, we send AT Commands

So to dial the number 1711, we send this AT Command…

ATD1711;

(EG25-G runs on Qualcomm MDM 9607 with a Cortex-A7 CPU inside)

How to send the AT Commands to LTE Modem?

The LTE Modem accepts AT Commands in two ways (pic below)…

So if we’re sending and receiving lots of 4G Mobile Data, USB is the better way.

(UART Interface is probably sufficient for a Feature Phone)

(More about this)

Quectel EG25-G LTE Modem in PinePhone Schematic (Page 15)

Quectel EG25-G LTE Modem in PinePhone Schematic (Page 15)

§3 LTE Modem talks USB

How is the LTE Modem connected to PinePhone?

Check out the article…

According to the PinePhone Schematic (Page 15), the Quectel EG25-G LTE Modem connects to the Allwinner A64 SoC on the USB Pins…

Which is Port USB1 of the Allwinner A64 SoC. (Pic above)

(LTE Modem Audio goes to Port PCM0)

Only 2 pins?

That’s because USB 2.0 runs on 2 data wires and 2 power wires…

(Due to Differential Signalling)

What about USB0-DP and USB0-DM?

Port USB0 of the Allwinner A64 SoC is exposed as the External USB Port on PinePhone.

(Port USB0 supports USB OTG, Port USB1 doesn’t)

Beware! The USB Port Names look confusing in the Allwinner A64 User Manual

USB PortAlternate NameBase Address
Port USB0USB-OTG-EHCI / OHCI0x01C1 A000 (USB_HCI0)
Port USB1USB-EHCI0 / OHCI00x01C1 B000 (USB_HCI1)

We’ll talk only about Port USB1 (Non-OTG), since it’s connected to the LTE Modem.

(More about EHCI)

So PinePhone talks to the LTE Modem on USB Serial?

Correct! Here are the USB Endpoints exposed by the LTE Modem (which we’ll decipher later)…

$ sudo lsusb -v

Bus 002 Device 002: ID 2c7c:0125 Quectel Wireless Solutions Co., Ltd. EC25 LTE modem
Device Descriptor:
  idVendor           0x2c7c Quectel Wireless Solutions Co., Ltd.
  idProduct          0x0125 EC25 LTE modem
  iManufacturer           1 Quectel
  iProduct                2 EG25-G

  Configuration Descriptor:
    bNumInterfaces          5
    Interface Descriptor:
      bInterfaceNumber        0
        bEndpointAddress     0x81  EP 1 IN
        bEndpointAddress     0x01  EP 1 OUT

    Interface Descriptor:
      bInterfaceNumber        1
        bEndpointAddress     0x83  EP 3 IN
        bEndpointAddress     0x82  EP 2 IN
        bEndpointAddress     0x02  EP 2 OUT

    Interface Descriptor:
      bInterfaceNumber        2
        bEndpointAddress     0x85  EP 5 IN
        bEndpointAddress     0x84  EP 4 IN
        bEndpointAddress     0x03  EP 3 OUT

    Interface Descriptor:
      bInterfaceNumber        3
        bEndpointAddress     0x87  EP 7 IN
        bEndpointAddress     0x86  EP 6 IN
        bEndpointAddress     0x04  EP 4 OUT

    Interface Descriptor:
      bInterfaceNumber        4
        bEndpointAddress     0x89  EP 9 IN
        bEndpointAddress     0x88  EP 8 IN
        bEndpointAddress     0x05  EP 5 OUT

(Source)

But first we need to build the PinePhone USB Driver for NuttX…

Sorry Elmo… Allwinner A64’s USB Controller isn’t documented

Sorry Elmo… Allwinner A64’s USB Controller isn’t documented

§4 Document the USB Controller

To turn PinePhone into a Feature Phone (Voice Calls and SMS only)…

What NuttX Drivers would we need?

We need a NuttX Driver for the PinePhone’s Quectel LTE Modem… Which talks over USB Serial.

Thus we also need a NuttX Driver for PinePhone’s Allwinner A64 USB Controller.

So we check the USB Controller docs?

Allwinner A64’s USB Controller is officially documented in…

Which doesn’t say much about the USB Controller!

Allwinner A64’s Official Docs are horrigibly lacking…

But thanks to the Sunxi Community we have a valuable tip on the USB Controller…

“All Allwinner A-series SoCs come with one USB OTG controller”

“The controller has been identified as a Mentor Graphics Inventra HDRC (High-speed Dual Role Controller), which is supported by the musb driver”

“However, the register addresses are scrambled”

(Source)

Aha! Allwinner A64’s USB Controller is actually a Mentor Graphics USB Controller!

USB Registers are scrambled? Like eggs?

Actually it means that Allwinner A64’s USB Registers are located in different addresses from the Mentor Graphics ones.

(Everything else works exactly the same way)

The Sunxi Community has helpfully documented the Scrambled USB Registers

What’s a USB OTG Controller?

OTG refers to USB On-The-Go, which supports both USB Host Mode and USB Device Mode.

(Also known as “Dual-Role”)

Let’s find a Reference Driver for the Mentor Graphics USB Controller…

USB Controller in PinePhone Device Tree

USB Controller in PinePhone Device Tree

§5 Search for USB Driver

UPDATE: There’s an easier way to build the PinePhone USB Driver…

How to find a driver for Allwinner A64’s USB Controller?

PinePhone’s Device Tree describes the Hardware Configuration of PinePhone…

According to the Device Tree, PinePhone’s USB Drivers are listed as (pic above)…

usb@1c19000 {
  compatible = "allwinner,sun8i-a33-musb";
  ...
phy@1c19400 {
  compatible = "allwinner,sun50i-a64-usb-phy";

(Source)

What are MUSB and USB PHY?

Thus we search for these USB Driver Names on GitHub Code Search

allwinner,sun8i-a33-musb
allwinner,sun50i-a64-usb-phy

Which uncovers the Allwinner A64 USB Driver that we seek (for FreeBSD, NetBSD and Linux)…

§6 FreeBSD USB Driver

We found a Reference Driver for Allwinner A64 USB Controller?

Yep! Earlier we discovered the name of the Allwinner A64 USB Driver: “allwinner,sun8i-a33-musb”

GitHub Code Search says that the Allwinner A64 USB Driver for FreeBSD is…

MUSB refers to the Mentor Graphics USB Controller.

OTG refers to USB On-The-Go, which supports both USB Host Mode and USB Device Mode.

(We’ll stick to USB Host Mode for today)

But where’s the actual code for the USB Driver?

The Mentor Graphics USB Driver is implemented here…

Why two files: musb_otg.c and musb_otg_allwinner.c?

Remember that the Allwinner A64 USB Controller is identical to the Mentor Graphics one… Except that the USB Registers are scrambled?

That’s why we need musb_otg_allwinner.c to unscramble the USB Registers, specifically for Allwinner A64.

(Like this)

What about the USB Physical Layer for FreeBSD?

The USB Physical Layer for Allwinner A64 is implemented here…

This driver controls the Physical Layer (physical wires) that carries the USB signals.

(But we won’t touch it today)

OK we’ve seen the FreeBSD Drivers… What about other operating systems?

GitHub Code Search also uncovers the NetBSD Drivers for Allwinner A64 USB…

But today we’ll study the FreeBSD Driver because it’s easier to read.

Transmit Control Data as Host in Mentor Graphics USB Controller (Page 126)

Transmit Control Data as Host in Mentor Graphics USB Controller (Page 126)

§7 Inside the FreeBSD Driver

Do we copy the FreeBSD Driver into NuttX?

Sorry that sounds mighty irresponsible… If we don’t understand the code! (Just like ChatGPT)

Remember that the Allwinner A64 USB Controller is based on the design by Mentor Graphics

Hence to understand the driver internals, we shall match the FreeBSD Driver Code with the Mentor Graphics Doc.

(Kinda like Rosetta Stone)

Where do we start?

The Mentor Graphics Doc describes Transmitting Control Data (as a Host)…

See Section 21.2.3 “Control Transactions as a Host - Out Data Phase as a Host”. (Page 126, pic above)

(USB Out Transaction is explained here)

This seems to match the FreeBSD Driver Code for musbotg_host_ctrl_data_tx in musb_otg.c

musbotg_host_ctrl_data_tx in musb_otg.c

(Source)

To figure out how it works, we compare the code with the doc side-by-side…

Matching the FreeBSD Driver Code with the Mentor Graphics Doc

Matching the FreeBSD Driver Code with the Mentor Graphics Doc will be an interesting educational exercise…

Which we’ll cover in the next article!

§8 USB Drivers in NuttX

UPDATE: There’s an easier way to build the PinePhone USB Driver…

We found the FreeBSD Driver for Allwinner A64 USB…

How will we adapt it for NuttX RTOS?

First we understand how USB Drivers work in NuttX

The NuttX doc describes the Detection and Enumeration of USB Devices

Each USB Host Device Controller supports two methods that are used to detect and enumeration newly connected devices…

wait: Wait for a device to be connected or disconnected

enumerate: Enumerate the device connected to a root hub port

Then the NuttX doc explains the USB Enumeration Process

As part of this enumeration process, the driver will

(1) Get the Device’s Configuration Descriptor

(2) Extract the Class ID info from the Configuration Descriptor

(USB Descriptors look like this)

So our PinePhone USB Driver needs to implement this USB Enumeration?

Yep! To prepare for our upcoming implementation of the PinePhone USB Driver, let’s look at the NuttX Driver for STM32 USB Controller…

§9 STM32 USB Driver for NuttX

UPDATE: There’s an easier way to build the PinePhone USB Driver…

We’re about to implement our NuttX Driver for PinePhone USB…

Can we learn something from the NuttX Driver for STM32 USB?

Let’s find out! The NuttX USB Driver for STM32 is implemented at…

We see these in the NuttX Filenames…

How does the STM32 Driver enumerate USB Devices?

That’s done in stm32_enumerate

stm32_ctrlout in NuttX looks similar to musbotg_host_ctrl_data_tx in FreeBSD that we saw earlier…

Aha! We found the Rosetta Stone that matches…

This will be super helpful as we port the Allwinner A64 USB Driver to NuttX.

stm32_ctrlout in NuttX looks similar to musbotg_host_ctrl_data_tx in FreeBSD

stm32_ctrlout in NuttX looks similar to musbotg_host_ctrl_data_tx in FreeBSD

§10 What’s Next

Porting the PinePhone USB Driver to NuttX will be a super long journey… The FreeBSD driver has 4,000 lines of code 😲

UPDATE: There’s an easier way to build the PinePhone USB Driver…

But stay tuned for updates! Meanwhile please check out the other articles on NuttX for PinePhone…

Many Thanks to my GitHub Sponsors for supporting my work! This article wouldn’t have been possible without your support.

Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…

lupyuen.github.io/src/usb2.md

USB Controller Block Diagram in Allwinner A64 User Manual (Page 583)

USB Controller Block Diagram in Allwinner A64 User Manual (Page 583)

§11 Appendix: Enhanced Host Controller Interface for USB

Read the article…

Lwazi Dube noted that USB Enhanced Host Controller Interface 1.0 (EHCI) is implemented for the Allwinner A64 USB Controller. (Pic above)

Thus we have an easier way to build the NuttX USB Driver for PinePhone!

Let’s find out why…

(PinePhone’s LTE Modem is connected to Port USB1, which is HCI0 in the lower half of the pic)

What’s EHCI?

According to the EHCI Spec

“The Enhanced Host Controller Interface (EHCI) specification describes the Register-Level Interface for a Host Controller for the Universal Serial Bus (USB) Revision 2.0”

“The specification includes a description of the Hardware and Software Interface between System Software and the Host Controller Hardware”

Which means we can build the NuttX USB Driver for PinePhone… By simply talking to the (Memory-Mapped) EHCI Registers on Allwinner A64’s USB Controller!

What are the EHCI Registers?

The Standard EHCI Registers are documented here…

(Version 1.1 Addendum isn’t relevant because Allwinner A64 only implements Version 1.0 of the spec)

Allwinner A64 implements the EHCI Registers for Port USB1 at Base Address 0x01C1 B000 (USB_HCI1, pic below)

Refer to the Allwinner A64 User Manual

USB Host Register List in Allwinner A64 User Manual (Page 585)

PinePhone’s LTE Modem is connected on EHCI?

Yep we confirmed it with lsusb

$ lsusb -t -v
/:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=ohci-platform/1p, 12M
    ID 1d6b:0001 Linux Foundation 1.1 root hub
/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=ehci-platform/1p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ohci-platform/1p, 12M
    ID 1d6b:0001 Linux Foundation 1.1 root hub
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-platform/1p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 1: Dev 2, If 0, Class=Vendor Specific Class, Driver=option, 480M
        ID 2c7c:0125 Quectel Wireless Solutions Co., Ltd. EC25 LTE modem
    |__ Port 1: Dev 2, If 1, Class=Vendor Specific Class, Driver=option, 480M
        ID 2c7c:0125 Quectel Wireless Solutions Co., Ltd. EC25 LTE modem
    |__ Port 1: Dev 2, If 2, Class=Vendor Specific Class, Driver=option, 480M
        ID 2c7c:0125 Quectel Wireless Solutions Co., Ltd. EC25 LTE modem
    |__ Port 1: Dev 2, If 3, Class=Vendor Specific Class, Driver=option, 480M
        ID 2c7c:0125 Quectel Wireless Solutions Co., Ltd. EC25 LTE modem
    |__ Port 1: Dev 2, If 4, Class=Vendor Specific Class, Driver=qmi_wwan, 480M
        ID 2c7c:0125 Quectel Wireless Solutions Co., Ltd. EC25 LTE modem

EHCI also appears in the PinePhone Device Tree: sun50i-a64-pinephone-1.2.dts

usb@1c1a000 {
  compatible = "allwinner,sun50i-a64-ehci\0generic-ehci";
  reg = <0x1c1a000 0x100>;
  interrupts = <0x00 0x48 0x04>;
  clocks = <0x02 0x2c 0x02 0x2a 0x02 0x5b>;
  resets = <0x02 0x15 0x02 0x13>;
  status = "okay";
};

usb@1c1a400 {
  compatible = "allwinner,sun50i-a64-ohci\0generic-ohci";
  reg = <0x1c1a400 0x100>;
  interrupts = <0x00 0x49 0x04>;
  clocks = <0x02 0x2c 0x02 0x5b>;
  resets = <0x02 0x15>;
  status = "okay";
};

usb@1c1b000 {
  compatible = "allwinner,sun50i-a64-ehci\0generic-ehci";
  reg = <0x1c1b000 0x100>;
  interrupts = <0x00 0x4a 0x04>;
  clocks = <0x02 0x2d 0x02 0x2b 0x02 0x5d>;
  resets = <0x02 0x16 0x02 0x14>;
  phys = <0x31 0x01>;
  phy-names = "usb";
  status = "okay";
};

usb@1c1b400 {
  compatible = "allwinner,sun50i-a64-ohci\0generic-ohci";
  reg = <0x1c1b400 0x100>;
  interrupts = <0x00 0x4b 0x04>;
  clocks = <0x02 0x2d 0x02 0x5d>;
  resets = <0x02 0x16>;
  phys = <0x31 0x01>;
  phy-names = "usb";
  status = "okay";
};

Which says that PinePhone uses the Generic Platform EHCI Driver.

There’s another EHCI Port at 0x01C1 A000?

Yep there are two USB Ports in Allwinner A64: USB0 and USB1.

Port USB0 Base Address isn’t documented, but it appears in the Memory Mapping (Page 73) of the Allwinner A64 User Manual

USB PortAlternate NameBase Address
Port USB0USB-OTG-EHCI / OHCI0x01C1 A000 (USB_HCI0)
Port USB1USB-EHCI0 / OHCI00x01C1 B000 (USB_HCI1)

We’ll talk only about Port USB1 (Non-OTG), since it’s connected to the LTE Modem.

How will we build the EHCI Driver for PinePhone?

Lwazi found these EHCI Drivers in NuttX

I’ll port the i.MX RT EHCI Driver to PinePhone and Allwinner A64, since it’s the newest one.

Check the updates here…

What about the LTE Modem Driver for NuttX?

This NuttX Driver for Quectel EC20 LTE Modem might be helpful…

Stay tuned for updates!

Pine64 PineDio LoRa Gateway (left) with PineDio LoRa Add-On Case (right)

Pine64 PineDio LoRa Gateway (left) with PineDio LoRa Add-On Case (right)

§12 Appendix: LoRa Communicator for PinePhone on NuttX

Earlier we talked about turning PinePhone on NuttX into a Feature Phone for Emergency Use

What if there’s no LTE Network Coverage? Like in a Natural Disaster?

The Long-Range, Low-Power LoRa Network might be good for search and rescue communications.

(Short Text Messages only plus GPS Geolocation, non-guaranteed message delivery)

To turn PinePhone into a LoRa Communicator, just attach the LoRa Add-On Case to PinePhone (pic above)…

We might use JF’s LoRa Driver (which handles the I2C-to-SPI Bridge)…

Or the LoRa Driver that we’ve ported to NuttX…

Or maybe Meshtastic, since it has a complete LoRa Mesh Messaging App

Meshtastic was built with Arduino (C++). To compile it on NuttX we could use the Portduino Library