Audio for RK3399

November 30, 2019 — Leave a comment

Last two weeks I’ve been working on audio support for Firefly-RK3399. Full support requires a number of things that are not quite there or not available in the mainline FreeBSD kernel. The main low-level hardware functionality consists of two parts: I2S block in the SoC and RT5640 audiocodec that converts digital audio to an analog signal. They talk to each other using the I2S protocol. A little bit higher is FDT virtual “devices” called simple-audio-card. This part is responsible for coordinating the setup of both hardware components: make sure they agree on a number of channels, a number of bits per sample and clock specifics of the I2S protocol. There is no code for it in the FreeBSD kernel, so I had to just hardcode these things in both hardware drivers.

The other obviously missing part was I2S clocks in the CRU unit drivers. This was easily fixable by just consulting with RK3399 TRM. Still, having added the clocks support I couldn’t get the signal on the physical pin. Thanks to manu@ who pointed out that some stuff might be missing in io-domain and power regulators area it was resolved too after setting bit 1 of GRF_IO_VSEL register

With all these bits in place, I was able to get sound out of headphones, but it was distorted. My first instinct was to blame mismatch of clocks/formats between I2S and codec, so I spent two very frustrating days experimenting with setting polarities and data formats just to find out that there is GPIO that controls headphone output on Firefly-RK3399. This is Firefly-specific bit and only referenced in the Firefly fork of the Rockchip fork of the Linux kernel. The way it’s implemented loud noises still can pass through the filter to headphones, so at max volume, you can here laud parts as a series of pops and grunts. By manually configuring GPIO4_C5 (gpioc4/pin21) I finally was able to get clear sound out of the Firefly.

On the bright side now I know how to convert an I2S stream captured by a Saleae logic analyzer to wav file: https://github.com/roel0/PCM2Wav-py

The next step is to check how much work would it take to implement the simple-audio-card part. The (very hacky) WIP is at https://github.com/gonzoua/freebsd/commits/rk3399_audio

Recreating Sneakers scene

September 28, 2019 — Leave a comment

(Not a FreeBSD topic)

A long time ago, in my teens, I watched movie Sneakers and was very impressed by it. It was exactly how I imagined hackers at work: bare PCBs, signal probes, de-scrambling encrypted information right on the screen. I was so impressed by the latter part that I went to re-create a bit of “No more secrets” scene using the only technologies I knew back then: Turbo Pascal running on MS-DOS. It wasn’t an exact replica but it was close enough and I was quite happy with the result. The program itself hasn’t survived my numerous moves from one apartment to another and got lost along with all the floppy discs sometime in the early aughts.

Recently I re-watched the movie and turned out that it holds up pretty well and still fun to watch. I thought that it would be a fun experience to re-create my small demo and check if I still remember any of the Pascal and DOS APIs. Equipped with Pascal for PC book published in ’91, some MS-DOS guides from the internet and a Guinness 4-pack I walked a short walk down the memory lane and it was fun. The result is published on Github. The demo in action:

FreeBSD support for pyu2f

September 22, 2019 — Leave a comment

After long hiatus (because $JOB) I’m trying to find some time to spend on FreeBSD-related projects, looking for small ones that can be done over weekend or a bit more. One of the ideas came from Ed Maste’s twitter: implement FreeBSD support for pyu2f. Since I already spent some time working on FreeBSD U2F support for Chromium it felt like a good small project.

The challenging part of the project was not U2F/HID but interfacing ioctl with Python, something I have never done before. It wasn’t super complex and I learned about Python’s ctype module.

Even more challenging though was to find a code to verify the implementation. Turned out there was no script to run end-to-end test. The closest I managed to find was this code in Xpra project. I used it as a base to write following test that registers app and then signs a pseudo challenge. It only verifies the interface part and doesn’t care about the actual signatures/keys:

import os
from pyu2f import u2f
from pyu2f import model

ORIGIN = 'https://kernelnomicon.org'
APP_ID = 'wordpress'
REGISTRATION_DAT = 'registration.dat'

device = u2f.GetLocalU2FInterface(ORIGIN)

# Try to register new app or read saved registration data if it exists
if os.path.exists(REGISTRATION_DAT):
    with open(REGISTRATION_DAT, 'rb') as f:
        rd = f.read()
else:
    r = device.Register(APP_ID, b'ABCD', [])
    rd = r.registration_data
    with open(REGISTRATION_DAT, 'wb+') as f:
        f.write(rd)

# extract public key, key handle length, and key handle
pubkey = bytes(rd[1:66])
# this is for Python3, use ord(rd[66]) for Python2
khl = rd[66]
key_handle = bytes(rd[67:67 + khl])

# Try to authenticate
key = model.RegisteredKey(key_handle)
response = device.Authenticate(APP_ID, b'012345678', [key])
print (response.signature_data)
print (response.client_data)

The final result is in my fork of pyu2f repo, on freebsd branch.

Inky pHat on FreeBSD/Pi

November 14, 2018 — Leave a comment

About a month ago I purchased Inky pHat from Pimoroni, Pi hat with 220×104 red and black eInk screen. The device has an SPI interface with three additional GPIO signals: reset pin, command/data pin, and busy pin. Reset and busy pins are self-explanatory: the former resets device MCU the latter signals to the Pi whether the MCU is busy handling previous command/data. Command/data signals the type of SPI transaction that is about to be sent to Inky: low means command, high – data. It more or less matches interface to SSD1306 OLED display I played with before.

There is no datasheet or protocol description, so I used Pimoroni’s python library as a reference.

To communicate with the device over SPI, you need to apply spigen device-tree overlay and load spigen driver. For Raspberry Pi 3 you probably need a patch from this review applied. To load overlay add respective dtbo name to the fdt_overlays variable in /boot/loader.conf, e.g.:

fdt_overlays="spigen-rpi3"

I didn’t have any practical purpose for the device in mind so after several failed attempts to output RGB images in two color I ended up writing random ornament generator:

ornament

cat

I was updating my laptop to the latest HEAD today and noticed that my bash prompt looks ugly in default console color scheme. So what with one thing and another I ended up writing color themes support for vt(4). Just because it was fun thing to do. The idea is that you can redefine any ANSI color in console using variable in /boot/loader.conf, i.e.:

kern.vt.color.0.rgb="0,0,0" # color 0 is black
# or
kern.vt.color.15.rgb="#ffffff" # color 15 is white

Here is how my Tomorrow Night theme looks like:

kern.vt.color.0.rgb="#1d1f21"
kern.vt.color.1.rgb="#d77c79"
kern.vt.color.2.rgb="#c2c77b"
kern.vt.color.3.rgb="#f4cf87"
kern.vt.color.4.rgb="#93b2ca"
kern.vt.color.5.rgb="#c0a7c7"
kern.vt.color.6.rgb="#9ac9c4"
kern.vt.color.7.rgb="#d0d2d1"
kern.vt.color.8.rgb="#d0d2d1"
kern.vt.color.9.rgb="#d77c79"
kern.vt.color.10.rgb="#c2c77b"
kern.vt.color.11.rgb="#f4cf87"
kern.vt.color.12.rgb="#93b2ca"
kern.vt.color.13.rgb="#c0a7c7"
kern.vt.color.14.rgb="#9ac9c4"
kern.vt.color.15.rgb="#ffffff"

It works only with framebuffer-based console like efifb or i915kms.
Patch: console-color-theme.diff

Last year I got my hands on Minnowboard Turbot (courtesy of Frank H.) and spent some time working on communications protocols support for it. Below is short summary of what works and what doesn’t.

Minnowboard Turbot is Atom-base SoC, and standard x86 part (HDMI, network, USB) FreeBSD just works on it. The board has expansion connector that exposes I2C, SPI, and GPIO pins and can be used to talk to peripheral devices. Short summary of header pins can be found on developer.microsoft.com.

GPIO

GPIO functionality on Minnowboard provided by bytgpio(4) driver (name was chosen to match OpenBSD one). There are three banks, but the most accessible is the third one available via /dev/gpioc2. All GPIO pins on the expansion header are pin number in this bank. So to set pin “GPIO 0” on the picture to HIGH you would use gpioc -f /dev/gpioc2 0 1.

To use some GPIO peripheral that has FreeBSD kernel driver you will have to describe it using hints in /boot/loader.conf. For instance there is LED D2 that is attached to pin 22. So to expose it through gpioled(4) interface you’d add following lines to /boot/loader.conf:

gpioled_load="YES"
bytgpio_load="YES"
hint.gpioled.0.at="gpiobus2"
# pin 22: (1 << 22)
hint.gpioled.0.pins="0x400000"
hint.gpioled.0.name="D2"

SPI

Driver for SPI support on Minnowboard is intelspi. Hardware supports all four SPI modes and clock frequency configuration but the driver doesn’t (yet). So it’s always mode 0 and frequency is hardcoded to 10MHz. To access it from userland you’d use spigen driver for now. As with gpio peripherlas, you’d have to add spigen via hints:

intelspi_load="YES"
hint.spigen.0.at="spibus0"

There is no spigen module, so it has to be enabled in kernel config:

device          spibus
device          spigen

I2C

I2C driver is ig4(4). There are two I2C buses, the one that is accessible from expansion header is iicbus0. As with previous two protocols devices should be defined by hints. For example:

ig4_load="YES"
hint.ds3231.0.at="iicbus0"
# 0x68 in 8-bit format
# for example only, hasn't been tested
hint.ds3231.0.addr="0xd0"

There is no ds3231 module so again, you need to enable it in kernel:

device          iicbus
device          ds3231

To use I2C from userland via /dev/iicN you’ll need to load iic(4) module.

Over years I accumulated fair number of devices I have no real use for. I ordered them either on impulse, or to add couple of $$$ to the bill to get free delivery. So in order to get at least some value from those purchases I put together goofy demo using two of such devices: I2C temperature sensor breakout from Sparkfun and 128×32 SPI OLED display from Adafruit.

I wrote two libraries to talk to TMP102 (chip in which temp sensor is based) over I2C and to SSD1306(OLED display chip) over SPI and several demos simple enough to put together in one day but flashy enough to excite my inner child and bring fond memories of MSDOS days. The SPI chip requires this fix in kernel. Userland SPI API provides only very basic functionality but luckily it was enough to talk to SSD1306.

TMP102 is I2C-only device but SSD1306 uses two signals in addition to standard SPI ones and GND/VCC: Data/Command switch and Reset. I connected them to GPIO pins 23 and 24 on my RPi. SSD1306 code is based on Adafruit’s Python library and supports only one model so far, but can easily be extended to support all three of them.

Code: https://github.com/gonzoua/freebsd-embedded-demos
Video:

If you’re trying to boot FreeBSD with latest RaspberryPi firmware – be aware that this commit changed default frequency for UART0 on at least RaspberryPi 2, so to get serial console working in u-boot/ubldr again you need to add this line to config.txt:

init_uart_clock=3000000

rfkill on Jetson TK1

December 11, 2016 — Leave a comment

If you’re trying to install half-sized mini-PCIe wifi card in Jetson TK1, be aware, that the board has rfkill feature that is enabled by default. rfkill is hardware or software controlled switch that enables/disables RF signal on the wifi card itself. In case of mini-PCIe it’s controlled by level on pin 20 of the card. On Jetson TK-1 that pin is connected to GPIO X.7 pin. So to enable wifi on the board you need to run something like:

gpioctl -cN gpio_X.7 OUT
gpioctl -N gpio_X.7 1

You can get source for current kernel FDT blob by running following command

sysctl -b hw.fdt.dtb | dtc -I dtb -O dts

Edit 27/10/2017: added -O option, looks like it’s required in newer dtc