Pomera DM250 Tinkering

The KING JIM Pomera DM250 "digital typewriter" is a small Linux-powered ARM computer that boots up into a custom word processor application. I've been tinkering with it to try to get OpenBSD booted on it. I'd normally wait until the end and write up a proper article explaining everything, but this process is taking a lot longer than I expected so I figured I'd document it all as I go.

Pomera DM250 ripped apart

Background

Click to expand

KING JIM has made a number of portable word processors starting with the DM5, the DM10 and DM20 with fold-out keyboards, then the DM100 and DM200 which share the form factor with its latest DM250.

I only know of KING JIM because stsp@ has their Portabook x86 machine that has required a handful of tweaks to get OpenBSD working on it.

The DM250 was only sold in Japan, but the manufacturer recently launched an Indiegogo campaign to launch a US version ("DM250US") with an ANSI keyboard layout and defaulting to English in the software (the Japanese model has English support in its software and can use the keyboard in English, though with its slightly different layout). I learned about this on the writerDeck subreddit which I subscribe to for some reason.

The unit measures 10.35" wide by 4.72" tall, with a height of 0.7" when closed. It has a 7" 1024x600 full-color TFT LCD screen, though the DM250's custom word processing software only uses black and white. It weighs 1.4 lbs and has a soft-touch rubber coating on its case. Its DM250US now has a US layout, though the arrow keys were unfortunately moved from an inverted "T" layout on the Japanese DM250 to a horizontal layout.

The DM250 is powered by a Rockchip RK3128 quad-core ARM Cortex-A7 processor with 1GB of RAM and about 8GB of eMMC storage. It has a full-size SD card slot and USB-C for charging. It has an AMPAK AP6236 Wi-Fi and Bluetooth SDIO chip which is based on the Broadcom BCM43436.

2025-03-14

I backed the Indiegogo campaign on February 19th and used Buyee to buy a Japanese model DM250 while I waited for the US campaign to end and for mine to ship out. The Japanese DM250 arrived on the 13th and with the aid of this website, I was able to boot into a Debian build and start inspecting how the device worked. I also took backups of the eMMC flash to be able to recover to it if I screw things up.

I haven't really been interested in the random armv7 boards that run OpenBSD because they all seemed to be similar while also each having quirks that make them unusable for daily use due to lacking driver support or cheap hardware. The DM250 appealed to me because it was a complete computer with keyboard and screen, not just a lone board with an ethernet port. (Although I'm sure I will eventually come up short on complete driver support on this machine too.)

It can turn on "instantly" due to some proprietary software called "LINEOWarp" which integrates into u-boot and the Linux kernel and basically hibernates the machine after booting and writes out its RAM to the eMMC. Upon opening the lid, u-boot directly reads the WARP image and loads it into RAM, bypassing the Linux kernel boot process. I first heard about this type of software from dosdude1's Honda infotainment video which has a similar need for "instant on".

2025-03-19

Trying to get OpenBSD loaded will require updating u-boot on the DM250 to a newer release with EFI support. EFI support was added in 2015 but the DM250 has a build from 2014.

But I can't really mess with u-boot until I get access to the UART on the device and I haven't been able to find the UART pins. I tried booting to Linux and printing random garbage to the serial port while I probed every pin on the board with my Saleae looking for serial data. For some reason nothing came out anywhere.

Eventually I found this page which shows where the UART pins are, which I definitely probed and found nothing while Debian was running. But once I kept leads on those pins while powering on, I could see u-boot output. Now I can actually see what's going on.

U-Boot 2014.10-RK3128-06 (Mar 17 2022 - 14:28:55)

CPU: rk3128
CPU's clock information:
	arm pll = 816000000HZ
	periph pll = 594000000HZ
	ddr pll = 600000000HZ
	codec pll = 400000000HZ
Board:  Rockchip platform Board
Uboot as second level loader
DRAM:  Found dram banks:1
Adding bank:0000000060000000(0000000040000000)
512 MiB
[...]

I'm not sure why u-boot shows 512 MB of RAM there when the DM250 has 1 GB, especially when that bank output shows a size of 0x40000000 (1,073,741,824 bytes).

2025-03-31

While trying to solder wires to the UART pins, I damaged one of the pads :/ The device still works otherwise so I'll just sell this one and wait for my US model to arrive.

I learned that Rockchip SoCs have a neat feature where if the firmware fails to load a bootloader from eMMC or SDMMC, it will automatically launch into a "MaskROM" mode where it becomes a ugen device over its USB-C cable and allows the attached computer to directly read and write data to the eMMC. This way the device can never really be bricked which makes me more confident testing u-boot changes.

This MaskROM mode works even before SDRAM is initialized, so the first thing that has to be done is sending it a RAM training blob, then a more complete usbplug blob which allows more complicated commands over USB. This can be done with rkflashtool or xrock which both work on OpenBSD.

$ doas xrock maskrom rk3128_ddr_300MHz_v2.12.bin rk3128_usbplug_v2.63.bin

After uploading the blobs, the device detaches and reattaches into its USB loader mode:

ugen0 at uhub3 port 3 "vendor 0x2207 product 0x310c" rev 2.00/1.00 addr 9
ugen0 detached
ugen0 at uhub3 port 3 "RockChip USB-MSC" rev 2.00/1.00 addr 9

If the flashed u-boot does boot but it's broken, one can short the eMMC to ground while the board is being powered on and force it into MaskROM mode. On the DM250, this can be done by shorting TP501 to ground.

2025-04-02

My DM250US arrived. A quick teardown shows it's basically the same hardware but with a different version silkscreened.

Pomera DM250 US board
UART pins TP802-TP804

The keyboard keys feel slightly smaller in size and rougher in texture. u-boot appears to be the same version but the build date is newer:

U-Boot 2014.10-RK3128-06 (Oct 07 2024 - 17:22:56)

The kernel is still Linux 3.10.0 with WARP patches. The DTB stored on the eMMC is mostly the same but with these additions:

bq27z558-battery@55 {
	compatible = "ti,bq27z561";
	reg = <0x55>;
	gpios = <0x76 0x12 0x01 0x75 0x0d 0x01>;
	status = "okay";
};

bq256xx-charger@6b {
	compatible = "ti,bq25620";
	reg = <0x6b>;
	gpios = <0x76 0x11 0x01>;
	ti,watchdog-timeout-ms = <0x00>;
	charge-current-limit-microamp = <0x2bf200>;
	charge-voltage-limit-microvolt = <0x408b70>;
	input-current-limit-microamp = <0x2dc6c0>;
	minimal-system-voltage-microvolt = "\0.c";
	pre-charge-control-microamp = <0x8d9a0>;
	termination-control-microamp = <0x249f0>;
	ti,no-thermistor = <0x01>;
	status = "okay";
};

2025-04-03

I got this pogo-pin clip from Adafruit to access the UART pins without having to solder to them and potentially damage them again. It's definitely made it much easier to reliably access the UART across multiple reboots.

2025-04-14

I've been trying to get different u-boot trees compiling and booting but none were working except the one from KING JIM. I tried rockchip-linux/u-boot and linux-rockchip/u-boot-rockchip but neither boot (or at least don't output anything to uart1.

Geniatech make the XPI-3128 which is basically the rk3128-evb evaluation board that exists in u-boot. While digging around their documentation, I found this huge tarball that includes a snapshot of their u-boot tree which is based on newer 2017.09 and has most of the necessary Rockchip drivers. I'm not sure why Rockchip is so special that they can't do everything in the official upstream u-boot tree…

With a few changes to build with a newer gcc, setting CONFIG_DEBUG_UART_BASE to 0x20064000 (uart1 instead of uart2), adding some custom uart initialization code to arch/arm/mach-rockchip/rk3128/rk3128.c, and adding an rk3128-specific timer driver, I now have a working build of u-boot that has EFI support!

U-Boot 2017.09-g5d36672-dirty (Apr 12 2025 - 12:31:04 -0500)

Model: KING JIM Pomera DM250US
DRAM:  512 MiB
Sysmem: init
Relocation Offset: 00000000, fdt: 00000000
Using default environment

dwmmc@10214000: 1, dwmmc@1021c000: 0
mmc_init: err -110, timer:41969
switch to partitions #0, OK
mmc0(part 0) is current device
Bootdev: mmc 0
MMC0: High Speed, 52Mhz
PartType: RKPARM
rockchip_get_boot_mode: Could not found misc partition
boot mode: normal
Found DTB in resource part
DTB: rk-kernel.dtb
CLK: (uboot. arm: enter 600000 KHz, init 600000 KHz, kernel 0N/A)
  apll 600000 KHz
  dpll 600000 KHz
  cpll 400000 KHz
  gpll 594000 KHz
  armclk 600000 KHz
  aclk_cpu 148500 KHz
  hclk_cpu 74250 KHz
  pclk_cpu 74250 KHz
  aclk_peri 148500 KHz
  hclk_peri 74250 KHz
  pclk_peri 74250 KHz
=> mmcinfo 
Device: dwmmc@1021c000
Manufacturer ID: 11
OEM: 100
Name: 008GB 
Timing Interface: High Speed
Tran Speed: 52000000
Rd Block Len: 512
MMC version 5.1
High Capacity: Yes
Capacity: 7.3 GiB
Bus Width: 8-bit
Erase Group Size: 512 KiB
HC WP Group Size: 4 MiB
User Capacity: 7.3 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH
=> bootefi
bootefi - Boots an EFI payload from memory

Usage:
bootefi <image address> [fdt address]
  - boot EFI payload stored at address <image address>.
	If specified, the device tree located at <fdt address> gets
	exposed as EFI configuration table.

Unfortunately only the eMMC (dwmmc@1021c000) is working but the probe of the SDMMC device at dwmmc@10214000 times out. This means I can't see an inserted SD card and begin to boot OpenBSD's EFI loader.

I think this has to do with the device not being powered up at boot. I'm still trying to figure out what is required for this to work since it works in other older Rockchip-specific u-boot trees.

2025-04-14 (Evening)

Success!

U-Boot 2017.09-gcc6b241-dirty (Apr 14 2025 - 17:20:37 -0500)

Model: KING JIM Pomera DM250US
DRAM:  512 MiB
Sysmem: init
Relocation Offset: 00000000, fdt: 00000000
Using default environment

dwmmc@10214000: 1, dwmmc@1021c000: 0
RKPARM: Invalid parameter part table
switch to partitions #0, OK
mmc1 is current device
switch to partitions #0, OK
mmc0(part 0) is current device
Bootdev: mmc 0
MMC0: High Speed, 52Mhz
PartType: RKPARM
rockchip_get_boot_mode: Could not found misc partition
boot mode: normal
Found DTB in resource part
DTB: rk-kernel.dtb
In:    serial
Out:   serial
Err:   serial
CLK: (uboot. arm: enter 600000 KHz, init 600000 KHz, kernel 0N/A)
apll 600000 KHz
dpll 600000 KHz
cpll 400000 KHz
gpll 594000 KHz
armclk 600000 KHz
aclk_cpu 148500 KHz
hclk_cpu 74250 KHz
pclk_cpu 74250 KHz
aclk_peri 148500 KHz
hclk_peri 74250 KHz
pclk_peri 74250 KHz
=> setenv fdtfile rk3128-pomera-dm250us.dtb
=> load mmc 1 ${kernel_addr_r} efi/boot/bootarm.efi
reading efi/boot/bootarm.efi
119296 bytes read in 51 ms (2.2 MiB/s)
=> bootefi ${kernel_addr_r} ${fdt_addr_r} 
## Starting EFI application at 62008000 ...
FtlInit fffffffe
Scanning disk nandc@10500000.blk...
rkparm_init_param_from_storage param read fail
RKPARM: Invalid parameter part table
Scanning disk dwmmc@10214000.blk...
Scanning disk dwmmc@1021c000.blk...
Scanning disk rksdmmc@1021c000.blk...
rkparm_init_param_from_storage param read fail
RKPARM: Invalid parameter part table
Scanning disk rksdmmc@10214000.blk...
rkparm_init_param_from_storage param read fail
RKPARM: Invalid parameter part table
Scanning disk rksdmmc@10218000.blk...
rkparm_init_param_from_storage param read fail
RKPARM: Invalid parameter part table
Found 6 disks
Adding bank: 0x60000000 - 0x80000000 (size: 0x20000000)
disks: sd0* sd1 sd2 sd3 sd4 sd5 sd6 sd7 sd8 sd9 sd10 sd11 sd12 sd13 sd14 sd15 sd16 sd17 sd18 sd19 sd20 sd21 sd22 sd23 sd24 sd25 sd26 sd27 sd28 sd29 sd30
>> OpenBSD/armv7 BOOTARM 1.23
boot>
cannot open sd0a:/etc/random.seed: No such file or directory
booting sd0a:/bsd: 2411324+767888+11506208+484492 [188357+107+388448+214048]=0x0

I added some debug printfs to the working u-boot tree and saw that it was calling rk_iomux_config(RK_UART2_IOMUX) when initializing the storage. That ends up calling rk_uart_iomux_config() which does some magic writes to the IOMUX.

Reading the GRF documentation and other pieces of code, I learned that GPIO1B needs pins 12 and 14 enabled to activate mmc0_pwren and mmc0_cmd, and GPIO1C needs pins 0, 2, 4, 6, 8, and 10 enabled to change them from JTAG and UART2 pins to those needed for eMMC.

With that, the SD card is recognized and u-boot can read files from it with its built-in FAT filesystem support. The existing config on the eMMC splits up the single drive into many different partitions like kernel, warp, ro_data, etc., which each show up as separate disks to the EFI loader.

The EFI loader is read from the SD card and loaded into memory with load mmc 1 ${kernel_addr_r} efi/boot/bootarm.efi, and then executed with bootefi ${kernel_addr_r} ${fdt_addr_r}. OpenBSD's BOOTARM.EFI loads successfully and can list files on the SD card and start reading and booting bsd.rd. Unfortunately it goes off into lala land there so I'm not sure what it's doing, but at least now I can move on to the OpenBSD part of this bringup.

Questions or comments?
Please feel free to contact me.