Group: Hardware/Computers/e-readers/Kobo/Aura H2O Edition 2

From LibrePlanet
Jump to: navigation, search

Contents

Warnings

This page describe research done on the Kobo Aura H2O Edition 2 e-reader.

The instructions given here are meant for research purpose: they are intended to find out if the kobo Aura H2O Edition 2 can meet the Respect Your Freedom certification with an amount of work that is not too big.

This doesn't mean that merely following the instruction will automatically make the source code respect the Free software distributions guidelines or that the device would automatically respect the Respect Your Freedom certification.

So for instance the instructions that explain how to make the display work with free software are only meant to validate that part, and didn't necessarily remove unrelated nonfree software.

Reviewed devices

  • So far only devices using the arch/arm/boot/dts/imx6sll-e60qm2.dts devicetree were reviewed.

Issues found so far

  • The WiFi firmware is under the GPLv2 but lacks source code. It needs to be reverse engineered. Hopefully it is small and the CPU ISA is known.

Priority investigations

TODO

Urgent:

  • e-paper display: validate its usability better if possible
  • verify if nothing was missed

Extra verifications:

  • u-boot source code: Read it to see if it loads any firmware
  • Linux source code: Look at the dts and drivers again to spot if something was missed
  • Hardware: describe the hardware better and look again if there is anything dodgy (unlikely to be missed with the software review though)
  • check what driver/cards the free wifi firmwares work on
  • Document the waveform data format

Later:

  • Document how to do bootloader development (device recovery, usb boot, etc)

waveform

Findings:

  • The waveform partition contains:
  • a mxcfb_waveform_data_file struct header
  • zero padding at the end

That header also contains some RAW data which seem to only contain waveform data:

  • That data was analyzed with inkwave as shown below
  • A quick look in mxc_epdc_v2_fb.c tend to indicate that there is only data in this waveform partition.
$ git clone https://github.com/fread-ink/inkwave
$ cd inkwave && make
$ ./inkwave -f wrf ../ntx-partitions-parser/partitions/waveform.img

File size: 10485760 bytes

Header info:
  Serial number: 6786
  Run type: 0x11 | Unknown
  Manufacturer code: 0xba | Unknown
  Frontplane Laminate (FPL) platform: 0x0 | 2.0
  Frontplane Laminate (FPL) lot: 208
  Frontplane Laminate (FPL) size: 0x0 | Unknown
  Frontplane Laminate (FPL) rate: 0x85 | 85Hz
  Waveform version: 32
  Waveform sub-version: 33
  Waveform type: 0x51 | Unknown
  Waveform tuning bias: Unknown
  Waveform revision: 0
  Adhesive run number: 25
  Mode version: Unknown
  Number of modes in this waveform: 8
  Number of temperature ranges in this waveform: 14
  4 or 5-bits per pixel: 5

Modes: Unknown (no mode version specified)

ntxfw and hwcfg

Findings:

  • hwcfg only contains hardware configuration data and a lot of zero padding
  • ntxfw contains backlight tables, and some unknown extra data that is not described in structs and doesn't seem to be used. Backlight still work with the unknown data removed.

Tools:

Boot flow:

  • u-boot loads that partition in memory and tells the kernel about it through kernel command line argument like ntxfw_p=<address> and ntxfw_sz=<size> in board/freescale/common/ntx_comm.c
  • The kernel picks that up in arch/arm/mach-imx/common.c

ntxcfg test:

$ cp ntxfw.img ntxfw_cleaned.img
$ dd if=/dev/zero of=ntxfw_cleaned.img seek=1427 bs=1 count=129133 conv=notrunc # zero out all the data outside of struct
$ echo -n '<--NTXFW}' | dd of=ntxfw_cleaned.img bs=1 seek=9464 count=9 conv=notrunc # Add the footer signature just in case

Result: $ hexdump -C ntxfw_cleaned.img | sed 's#^# #'

00000000  7b 4e 54 58 46 57 2d 2d  3e 00 45 36 30 51 4d 32  |{NTXFW-->.E60QM2|
00000010  00 5b 25 64 5d 3d 25 64  0a 00 00 00 00 03 00 00  |.[%d]=%d........|
00000020  00 25 73 20 67 6f 74 20  25 64 00 00 00 00 02 00  |.%s got %d......|
00000030  00 00 00 00 ff fc 5c c5  5c c5 cf ff 78 56 34 12  |......\.\...xV4.|
00000040  06 00 00 00 10 00 00 00  45 36 30 51 4d 32 5f 64  |........E60QM2_d|
00000050  75 61 6c 66 6c 5f 68 64  72 5f 31 36 31 31 31 36  |ualfl_hdr_161116|
00000060  00 00 00 00 00 00 00 00  00 00 00 00 0b 00 00 00  |................|
00000070  0a 05 00 00 00 00 00 00  00 00 00 00 ff fc 5c c5  |..............\.|
00000080  5c c5 cf ff 78 56 34 12  07 00 00 00 44 24 00 00  |\...xV4.....D$..|
00000090  45 36 30 51 4d 32 5f 64  75 61 6c 66 6c 5f 74 61  |E60QM2_dualfl_ta|
000000a0  62 5f 31 36 31 31 31 36  00 00 00 00 00 00 00 00  |b_161116........|
000000b0  00 00 00 00 54 30 00 00  00 00 00 00 00 00 00 00  |....T0..........|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000d0  00 00 00 00 00 00 00 00  36 47 54 5b 62 6a 71 78  |........6GT[bjqx|
000000e0  7d 83 87 8b 8e 90 93 95  97 99 9b 9d 9f a2 a4 a7  |}...............|
000000f0  a9 ab b0 b2 b4 b5 b6 b8  ba bb bd bf c0 c1 c2 c3  |................|
00000100  c4 c5 c6 c7 c8 c9 ca cb  cc cd ce cf d0 d1 d2 d3  |................|
00000110  d4 d5 d6 d7 d8 d9 da db  dc dd de df e0 e1 e2 e3  |................|
00000120  e4 e5 e6 e7 e8 e9 ea eb  ec ed ee ef f0 f1 f2 f3  |................|
00000130  f4 f5 f6 f7 f8 f9 fa fb  fc fd fe ff 00 00 00 00  |................|
00000140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000260  00 00 00 00 00 00 00 00  02 05 00 00 e7 05 00 00  |................|
00000270  b6 06 00 00 59 07 00 00  fb 07 00 00 18 09 00 00  |....Y...........|
00000280  5d 0a 00 00 ce 0b 00 00  f3 0c 00 00 90 0e 00 00  |]...............|
00000290  ea 0f 00 00 62 11 00 00  8e 12 00 00 82 13 00 00  |....b...........|
000002a0  d2 14 00 00 b9 15 00 00  b7 16 00 00 f3 17 00 00  |................|
000002b0  57 1a 00 00 57 1a 00 00  79 1b 00 00 9f 1d 00 00  |W...W...y.......|
000002c0  33 1f 00 00 85 21 00 00  71 23 00 00 2e 25 00 00  |3....!..q#...%..|
000002d0  06 2c 00 00 e0 2e 00 00  7a 30 00 00 1e 32 00 00  |.,......z0...2..|
000002e0  68 33 00 00 ac 35 00 00  36 38 00 00 b2 39 00 00  |h3...5..68...9..|
000002f0  c2 3d 00 00 b0 40 00 00  18 42 00 00 3a 43 00 00  |.=...@...B..:C..|
00000300  14 46 00 00 86 47 00 00  e4 48 00 00 d2 4b 00 00  |.F...G...H...K..|
00000310  3a 4d 00 00 ec 4f 00 00  86 51 00 00 4c 54 00 00  |:M...O...Q..LT..|
00000320  96 55 00 00 ac 58 00 00  2c 5b 00 00 da 5c 00 00  |.U...X..,[...\..|
00000330  86 60 00 00 74 63 00 00  f4 65 00 00 e2 68 00 00  |.`..tc...e...h..|
00000340  a8 6b 00 00 aa 6e 00 00  48 71 00 00 2c 74 00 00  |.k...n..Hq..,t..|
00000350  10 77 00 00 7a 7b 00 00  04 7e 00 00 1e 82 00 00  |.w..z{...~......|
00000360  ee 84 00 00 f4 88 00 00  c4 8b 00 00 a6 90 00 00  |................|
00000370  8e 94 00 00 8a 98 00 00  9a 9c 00 00 82 a0 00 00  |................|
00000380  56 a4 00 00 34 a8 00 00  30 ac 00 00 58 b1 00 00  |V...4...0...X...|
00000390  2c b5 00 00 90 ba 00 00  a4 bf 00 00 dc c3 00 00  |,...............|
000003a0  08 ca 00 00 52 d0 00 00  4a d8 00 00 62 de 00 00  |....R...J...b...|
000003b0  a2 e4 00 00 1c ed 00 00  16 f3 00 00 82 fa 00 00  |................|
000003c0  02 02 01 00 8c 09 01 00  b8 0f 01 00 94 1a 01 00  |................|
000003d0  ec 21 01 00 5c 2a 01 00  44 33 01 00 4c 3a 01 00  |.!..\*..D3..L:..|
000003e0  12 47 01 00 9c 53 01 00  fa 5e 01 00 10 6c 01 00  |.G...S...^...l..|
000003f0  f4 78 01 00 d8 85 01 00  00 00 00 00 00 00 00 00  |.x..............|
00000400  54 31 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |T1..............|
00000410  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000420  00 00 00 00 2a 43 4e 58  5f 67 6e 76 7a 7f 84 88  |....*CNX_gnvz...|
00000430  8a 8d 8f 92 94 96 98 9a  9c 9e a1 a3 a5 a8 ab ae  |................|
00000440  b0 b1 b2 b4 b6 b7 b9 bb  bc bd be bf c0 c1 c2 c3  |................|
00000450  c4 c5 c6 c7 c8 c9 ca cb  cc cd ce cf d0 d1 d2 d3  |................|
00000460  d4 d5 d6 d7 d8 d9 da db  dc dd de df e0 e1 e2 e3  |................|
00000470  e4 e5 e6 e7 e8 e9 ea eb  ec ed ee ef f0 f1 f2 f3  |................|
00000480  f4 f5 f6 f7 f8 f9 fa fb  00 00 00 00 00 00 00 00  |................|
00000490  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000004e0  00 00 00 00 00 00 00 00  00 00 00 00 05 01 01 02  |................|
000004f0  06 12 1b 10 2b 2e 2d 30  43 3f 42 44 45 45 47 4a  |....+.-0C?BDEEGJ|
00000500  4c 56 4e 5b 5d 55 76 63  67 65 6a 69 64 6a 6b 73  |LVN[]Uvcgejidjks|
00000510  72 6a 69 72 71 73 76 76  7d 76 7c 75 7a 7d 7c 7a  |rjirqsvv}v|uz}|z|
00000520  75 7b 78 77 7c 78 79 76  7f 80 85 80 86 80 86 86  |u{xw|xyv........|
00000530  89 88 89 8a 8a 89 8e 8f  93 94 93 93 94 9a 9a 9a  |................|
00000540  9b 9c 9d 9d a0 a0 a2 a1  a2 a3 a3 a6 a6 a8 a8 aa  |................|
00000550  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000024f0  00 00 00 00 00 00 00 00  3c 2d 2d 4e 54 58 46 57  |........<--NTXFW|
00002500  7d 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |}...............|
00002510  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
0001fe00

Firmwares

WiFi firmware

The WiFi driver rely on binary firmwares for the WiFi part.

The firmwares are provided as binary (in arrays format) in the hal/phydm/rtl8188f/halhwimg8188f_fw.c source code file, however this file is provided under the GPLv2. So it may be possible to convert the firmware binary in source code.

TODO:

  • Add in this wiki the findings documented in the reverse engineering work Willem on this firmware.
  • Investigate if the WiFi chip also has other functions (Bluetooth, FM Radio, etc)
  • Investigate if the firmware source code can easily be reconstructed
  • Investigate if the chip can work without the firmware

WiFi firmware informations found inside the driver

  • The firmware binary is really uploaded to the device chip, see
hal/phydm/phydm_hwconfig.c:2730:			READ_FIRMWARE_MP(8188F, _FW_NIC);
hal/phydm/phydm_hwconfig.c:2764:			READ_FIRMWARE_MP(8188F,_FW_NIC);

How to extract the firmware

There are generic tools to create a binary out of hex arrays, but it took me less time to write a specific program than to find such tool. I vaguely remember that one of theses tools was mentioned on a blog post on the sigrok blog, it was about something like reconstructing an I2S stream with 'unix way' tools.

firmware_extraction_utility.c

usage:

$ gcc firmware_extraction_utility.c
$ ./a.out > 8188F_FW_NIC.bin

The first 0x20 bytes are a header:

$ hexdump -C 8188F_FW_NIC.bin
00000000  f1 88 10 00 01 00 0e 00  03 25 14 55 62 52 02 00  |.........%.UbR..|
00000010  af 2f 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |./..............|

And the rest is code:

00000020  02 86 a9 02 c7 d7 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 02 c0 2d 00 00  00 00 00 00 00 00 00 00  |.....-..........|
00000040  00 00 00 02 c8 29 00 00  00 00 00 00 00 00 00 00  |.....)..........|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000060  00 00 00 02 c7 d8 00 00  00 00 00 02 c2 f0 00 00  |................|
00000070  00 00 00 02 c8 28 00 00  00 00 00 00 00 00 00 00  |.....(..........|
00000080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000000a0  02 87 b7 02 88 d5 02 80  86 02 80 89 02 a5 11 02  |................|
[...]

The code can be extracted like that:

$ dd if=8188F_FW_NIC.bin of=code.bin skip=32 bs=1

It can then be analyzed with radare2 this way:

$ r2 -a 8051 -m 0x8000 ./code.bin # r2 comes from radare2, which is an interactive disassembler.

Then we can start using radare2:

$ r2 -a 8051 -m 0x8000 ./code.bin
WARNING: using oba to load the syminfo from different mapaddress.
TODO: Must use the API instead of running commands to speedup loading times.
 -- You haxor! Me jane?
[0x00008000]> aaaa -AA
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] find and analyze function preludes (aap)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for objc references
[x] Check for vtables
[x] Finding xrefs in noncode section with anal.in=io.maps
[x] Analyze value pointers (aav)
[x] Value from 0x00008000 to 0x0000d262 (aav)
[x] 0x00008000-0x0000d262 in 0x8000-0xd262 (aav)
[Warning: No SN reg alias for current architecture.
[x] Emulate code to find computed references (aae)
[x] Type matching analysis for all functions (aaft)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Enable constraint types analysis for variables
[0x00008000]> pd
/ (fcn) fcn.00008000 181
|   fcn.00008000 ();
|           ; CODE XREF from skip (+0x128)
|       ,=< 0x00008000      0286a9         ljmp 0x86a9
       ,==< 0x00008003      02c7d7         ljmp 0xc7d7
       ||   0x00008006      00             nop
       ||   0x00008007      00             nop
       ||   0x00008008      00             nop
       ||   0x00008009      00             nop
       ||   0x0000800a      00             nop
       ||   0x0000800b      00             nop
       ||   0x0000800c      00             nop
       ||   0x0000800d      00             nop
       ||   0x0000800e      00             nop
       ||   0x0000800f      00             nop
       ||   0x00008010      00             nop
       ||   0x00008011      00             nop
       ||   0x00008012      00             nop
      ,===< 0x00008013      02c02d         ljmp 0xc02d
      |||   0x00008016      00             nop
      |||   0x00008017      00             nop
      |||   0x00008018      00             nop
      |||   0x00008019      00             nop
      |||   0x0000801a      00             nop
      |||   0x0000801b      00             nop
      |||   0x0000801c      00             nop
      |||   0x0000801d      00             nop
      |||   0x0000801e      00             nop
      |||   0x0000801f      00             nop
      |||   0x00008020      00             nop
      |||   0x00008021      00             nop
      |||   0x00008022      00             nop
     ,====< 0x00008023      02c829         ljmp 0xc829
     ||||   0x00008026      00             nop
     ||||   ; CODE XREF from skip (+0x1db)
     ||||   0x00008027      00             nop
     ||||   0x00008028      00             nop
     ||||   0x00008029      00             nop
     ||||   0x0000802a      00             nop
     ||||   0x0000802b      00             nop
     ||||   0x0000802c      00             nop
     ||||   0x0000802d      00             nop
     ||||   0x0000802e      00             nop
     ||||   0x0000802f      00             nop
     ||||   0x00008030      00             nop
     ||||   ; CODE XREF from skip (+0x1dd)
     ||||   0x00008031      00             nop
     ||||   0x00008032      00             nop
     ||||   0x00008033      00             nop
     ||||   0x00008034      00             nop
     ||||   0x00008035      00             nop
     ||||   0x00008036      00             nop
     ||||   0x00008037      00             nop
     ||||   0x00008038      00             nop
     ||||   0x00008039      00             nop
     ||||   0x0000803a      00             nop
     ||||   0x0000803b      00             nop
     ||||   0x0000803c      00             nop
     ||||   0x0000803d      00             nop
     ||||   0x0000803e      00             nop
     ||||   0x0000803f      00             nop
     ||||   0x00008040      00             nop
     ||||   0x00008041      00             nop
     ||||   0x00008042      00             nop
    ,=====< 0x00008043      02c7d8         ljmp 0xc7d8
    |||||   0x00008046      00             nop
    |||||   0x00008047      00             nop
    |||||   0x00008048      00             nop
    |||||   0x00008049      00             nop
[0x00008000]> 
  • You can then jump to functions with s <address>
  • You can continue listing code with s<address><enter> <enter>

Information on the WiFi firmware

WiFi Firmware ISA
  • The firmware uses the 8051 instruction
  • The entry point and load address is at 0x8000
Reverse engineering
  • The driver has many comments about the firmware and processor that runs the firmware. That can help a lot.
  • At the time of writing, Retdec README doesn't support the 8051 architecture yet:
Supported architectures (32b only): Intel x86, ARM, MIPS, PIC32, and PowerPC.
  • Radare2 seem to work on the firmware and has some good auto-analyze functions
  • The firmware is small:
 $ du -hs 8188F_FW_NIC.bin 
 24K	8188F_FW_NIC.bin
firmware format
  • it probably has a header and some calibration data at the begining
 => check the struct format

Touchscreen

cyttsp5

This should work without having to load any firmware.

Details:

  • This driver can use the cyttsp5_fw.bin firmware
    • The firmware seem optional at least in certain cases
    • A firmware file cannot be found on the filesystem
    • The support for loading the firmware is builtin the module but that could be because the vendor code has some issue without that code (like won't compile or similar)
    • The touchscreen works in Parabola (with ntxfw partition blanked): tested with evtest /dev/input/event1

External interfaces

USB

Several interfaces are exposed through USB:

  • It's possible to make the device switch to fastboot during boot
  • If the device is not registered, you can switch to mass-storage by selecting "no wifi" during the device boot.

Power button

Some more research is needed to understand how exactly is connected the power button:

  • It probably has to be connected to the PMIC to power up the device
  • It's also connected to an I.MX GPIO, and it's possible to get the button value through that GPIO as well, under certain conditions.

Touchscreen

Internal interfaces

Serial/UART

As it can be seen on one of the PCB pictures, near the battery, there is some holes with some markings: V, TX, RX, and a ground sign. It seems that more recent manufacturing batch lacks such markings.

V
  • At 3.3v when the device is powered on
  • At 0v when the device is off
  • You should not connect the serial port adapter to it
TX
  • Serial port TX
  • Connect to the RX of your USB<->Serial port adapter
RX
  • Serial port RX
  • Connect to the TX of your USB<->Serial port adapter
GND Ground

The holes pitch are 2.54mm (0.1 inch), so it's compatible with most common pin-headers found in electronic shops like this one. The best is to use headers that are bent, this way:

  • You could even be able to put back the cover if the pin headers height is small enough
  • You can still easily use the e-book reader with the screen towards you while still having the serial port adapter plugged in.

Soldering on theses holes is tricky as there is some transparent plastic coating on all the PCB, including the internal connectors and the components. Under that there is the classic PCB coating (which is green here).

So I used some "grain 400" sand paper to remove the plastic and green coating on the serial port pin holes.

If you're not careful enough this will also expose the ground plane, making it harder to solder without any shorts.

For the ground connector, if you remove too much coating, it will make soldering harder as the big ground plane will dissipate your soldering iron heat, preventing you from melting the tin.

Also beware that the '3v3' pin is shorted to GND when the device is off (and is at 3.3V when the device is on). So even if it seems shorted to GND, it might not be.

You also need to choose how to solder the header:

  • If the header pin goes on the battery side, then there won't be any risk of shorting the pins and if you manage to find a header that is the right size, it will stay better in place as the cable you will plug in can be exactly the size of the hole between the header and the battery. However you won't be able to close the cover anymore.
  • If the header pin goes on the opposite side of the battery, then you will be able to close the cover, but you will need to make sure that the header, the cable (and possibly the serial adapter stay in a position where they cannot cause short circuit by having their metallic part touch some of the conductive part on the e-reader PCB.

I used the following equipment to do it:

  • Lead free solder
  • TS100 Soldering iron with the free software firmware at 450 Degrees
  • A tip that is chisel-like but only one one side
  • Tivoly "Métal Peint", grain 240 "sand paper"
Voltage 3.3v
Baudrate 115200
Settings 8N1 (the default almost everywhere)

To get a shell you can login through the serial port with the user 'root':

(none) login: root
[root@(none) ~]# 

However once logged the console will probably freeze at some point. This is because the device has aggressive power management which makes the device goes into suspend.

To wake up the device, touching the screen is enough, however touching the screen all the time is not very convenient for development.

It seems to be an userspace application that makes the device goes into suspend. So we will overwrite /sys/power/state with a file that does nothing. We have ram filesystem mounted in /tmp, so we will use that to be saver (as it will not make permanent modifications):

[root@(none) ~]# mount
[...]
none on /tmp type tmpfs (rw,relatime,size=16384k)
[...]

We can overwrite /sys/power/state like that:

[root@(none) ~]# touch /tmp/state
[root@(none) ~]# mount -o bind /tmp/state /sys/power/state

This effectively prevent the device from going into suspend.

main storage

Partitions

With fdisk or by looking in /proc/partition we can see 3 partitions:

partition size function source
mmcblk0p1 256M rootfs cat /proc/cmdline: root=/dev/mmcblk0p1
mmcblk0p2 256M Backup rootfs ? after mounting it, there are some similar files. Strangely there are no kernel modules in this one.
mmcblk0p3 6.8G user data mount: /dev/mmcblk0p3 on /mnt/onboard type vfat

However if we look at update scripts or fastboot we have more partitions:

name start size (from fastboot) function source
mbr 0 1 The MBR
  • The partition is called mbr and it's at the beginning.
sn 1 1 The device serial number
  • The partition content viewed with hexdump
bootloader 2 1022 The bootloader (u-boot code)
  • The name of the partition
  • bootloader partitions are typically at the beginning
hwcfg 1024 2
  • Hardware configuration data
  • zero padding at the end
  • Kernel source code
  • I've also written a tool to analyze it to make sure that everything is understood
ntxfw 1030 255
  • Backlight configuration tables
  • Unknown data (which is probably unused) that can be removed
  • zero padding at the end
waveform 14336 20480 The waveform for the e-ink display
  • The name of the partition
  • Some e-paper displays needs some 'waveform' data to work
  • Contains some huge patterns of zero ones two that are contiguous
logo 34816 4096 empty
  • partition content viewed with hexdump
bootenv 1536 510 Probably u-boot environment
  • The name of the partition
  • The fact that u-boot typically stores its environment in a separate partition
  • The partition content contains the boot environment strings
kernel 2048 12284 The linux kernel in zImage format
  • The partition content
dtb 1286 250 The device tree binary
  • The partition content
rootfs 49152 524289 The two rootfs concatenated
  • The name of the partition
  • The location and size of the partition
  • The fact that it's recognized as ext4
vfat 1097730 14139389
  • Probably user data
  • this partition is vfat and can be mounted
  • this partition is made available if you choose to use your computer to setup the device
  • The partition name and content
  • The usage of the e-book reader
recoveryfs 573441 524289
  • A recovery partition?
  • The name of the partition
  • Contains a Linux kernel and initramfs

More detail on ntxfw partition dumped from a device compatible with the imx6sll-e60qm2.dts devicetree:

partition name
NTX_FW_TYPE_LM3630_DUALFL_HDR
NTX_FW_TYPE_LM3630_DUALFL_PERCENTTAB

Exporting the internal eMMC as a block device

After getting a shell in u-boot we can look at the list of eMMC/SD cards:

eBR-1A # mmc list
FSL_SDHC: 0 (eMMC)
FSL_SDHC: 1

The second mmc listed above doesn't seem to exist:

eBR-1A # mmc dev 1
Card did not respond to voltage select!

This is probably because the u-boot code is based on the code for a Freescale developement/evaluation board and since device manufacturers need to ship products fast they probably didn't bother removing the code for that non-existing hardware.

There is a command called 'ums' in u-boot that can export the e-MMC card through USB and make it appear as a mass storage device (like an USB key or an USB hard disk) to the computer it's connected to.

To use it you need to first connect an usb cable between your computer and the e-book reader and then type 'ums 0 mmc 0' in u-boot like that:

eBR-1A # ums 0 mmc 0
UMS: LUN 0, dev 0, hwpart 0, sector 0xe90000

You can then see it on your laptop:

$ lsblk 
[...]
sdb                         8:16   1   7.3G  0 disk  
├─sdb1                      8:17   1   256M  0 part  
├─sdb2                      8:18   1   256M  0 part  
└─sdb3                      8:19   1   6.8G  0 part

You can then use GNU ddrescue to backup the eMMC device:

ddrescue /dev/sdb kobo_emmc.img

Extracting the hidden partitions

Since the fastboot provides us the offset and that dd default is to operate on 512b at a time we can simply run the following commands:

dd if=kobo_emmc.img of=mbr.img count=1
dd if=kobo_emmc.img of=sn.img skip=1 count=1
dd if=kobo_emmc.img of=bootloader.img skip=2 count=1022
dd if=kobo_emmc.img of=hwcfg.img skip=1024 count=2
dd if=kobo_emmc.img of=ntxfw.img skip=1030 count=255
dd if=kobo_emmc.img of=waveform.img skip=14336 count=20480
dd if=kobo_emmc.img of=logo.img skip=34816 count=4096
dd if=kobo_emmc.img of=bootenv.img skip=1536 count=510
dd if=kobo_emmc.img of=kernel.img skip=2048 count=12284
dd if=kobo_emmc.img of=dtb.img skip=1286 count=250
dd if=kobo_emmc.img of=rootfs.img skip=49152 count=524289
dd if=kobo_emmc.img of=vfat.img skip=1097730 count=14139389
dd if=kobo_emmc.img of=recoveryfs.img skip=573441 count=524289

Fastboot

There is a fastboot command in u-boot. If you want to enable it from the u-boot shell you can do it like that:

# fastboot 0
ptn 0 name='mbr' start=0 len=1
ptn 1 name='sn' start=1 len=1
ptn 2 name='bootloader' start=2 len=1022
ptn 3 name='hwcfg' start=1024 len=2
ptn 4 name='ntxfw' start=1030 len=255
ptn 5 name='waveform' start=14336 len=20480
ptn 6 name='logo' start=34816 len=4096
ptn 7 name='bootenv' start=1536 len=510
ptn 8 name='kernel' start=2048 len=12284
ptn 9 name='dtb' start=1286 len=250
ptn 10 name='rootfs' start=49152 len=524289
ptn 11 name='vfat' start=1097730 len=14139389
ptn 12 name='recoveryfs' start=573441 len=524289

Here we have access to a lot more partition than with the block device export over USB.

fastboot lsusb

Here's how it looks like on lsusb

$ lsusb
Bus 001 Device 008: ID 18d1:0d02 Google Inc. Celkon A88

Triggering fastboot without access to the serial port

First run the fastboot command you want to run. You need to do that first because with this method, fastboot will be available for a very short ammount of time (about 5 seconds).

For instance if you want to boot an image named 'boot.img' you can run the follwing command:

$ fastboot boot ./boot.img

First make sure that the device is powered off. With the stock OS, it will either display 'Powered off' in the language it's configured in, or an image on how to plug the device if it never has been powered on.

Once the device is off press the power button. The device will then lit the top-right blue light. At this point press the power button again, and the device will go in fastboot mode for a very short amount of time (about 5 seconds).

PCB

Here are the chips on the top of the PCB. Caevats:

  • you need a big screen to view properly the markings as it will line-break with smaller screens
  • The markings might contain errors as they are tiny and some letter/number could be mixed up
  • I didn't disassemble it enough to see the bottom because the connectors seemed really fragile (they even had glue inside them) so if I do, I fear that I won't be able to put everything back in place. There might be some more chips on the bottom.
Usage Location Package Markings Driver(s) Documentation
512M RAM On the PCB top, near the I.MX 168-Ball PoP-FBGA
NANYA 1718
NT6TL 128M 32BQ-G0
7201166 AEP 3TW
?
? On the PCB top, near the I.MX ?
SEC 737
BO41
KLM8616EME
H56P4788D
?
System on a chip (IMX6SLL CEC) On the PCB top ? (BGA)
MCIMX6V7DVN10AB
XAA 1739
TAIW HMAAXK
Lots of drivers Reference Manual
WiFi chip (and potentially other features) On the PCB top, near the I.MX ?
REALTEK
8189PTY
H857492
GH438
The 8188f chip in the RTL8189FS out of tree driver
Main PMIC (powers down the device) On the PCB top, near the power button BGA (CSP0608-80 Package)
RICOH RC5T619
1137
Power management integrated circuit (and potentially other features) ?
TPS
65185
T1 7AI
CS6S G4
?
On the display flex cable ?
TT21000
-48L0I
1725 B03
PRD627959
PHI   □ C
041
?

Pictures

Some pictures of the top PCB taken with a camera:

Booting configuration

Findings:

  • The device doesn't have restricted boot enabled/configured.
  • How to recover the device was not found yet.
  • Building and reflashing a bootloader works.
Restricted boot details

The device tested doesn't have restricted boot configured/enabled:

  • According to the Secure Boot on ... i.MX 6 ... application note , the SRK (Super Root Key) is "An RSA key pair which forms the start of the boot-time authentication chain. [...]"
  • According to the SOC reference manuals, in the "OCOTP memory map", the SRK fuses settings are available in the OTP Bank3 (words 0 to 7 both included)
  • The SRK fuses registers were dumped and were blank:
eBR-1A # fuse sense 3 0 8
Sensing bank 3:

Word 0x00000000: 00000000 00000000 00000000 00000000
Word 0x00000004: 00000000 00000000 00000000 00000000
Boot order and recovery details

Findings:

  • The device is set to the "Internal Boot" BOOT_MODE
  • The fuses are then configured to make the device boot on MMC/eMMC
  • The boot settings can be overriden by GPIOs (BT_FUSE_SEL=0)
BOOT_MODE details

In the chapter 8.2.1 Boot mode pin settings of the SOC reference manual we have:

BOOT_MODE[1:0] Boot Type
00 Boot From Fuses
01 Serial Downloader
10 Internal Boot
11 Reserved

We are in the "Internal Boot" case here:

# devmem2 0x20D801C w # 0x76fb5000 is SRC_SMBR2
/dev/mem opened.
Memory mapped at address 0x76fb5000.
Value at address 0x20D801C (0x76fb501c): 0x2000001

Which results in:

SRC_SMBR2[25] = BOOT_MODE1 = 1
SRC_SMBR2[24] = BOOT_MODE0 = 0
BT_FUSE_SEL details

In the "8.2.5 Internal Boot mode (BOOT_MODE[1:0] = 0b10)" chapter we have: "If BT_FUSE_SEL = 0, the specific boot configuration parameters may be set using the GPIO pins rather than eFUSEs."

And in "SRC_SBMR2 field descriptions" in "Chapter 41 System Reset Controller (SRC)" we have:

Field Description
4

BT_FUSE_SEL

BT_FUSE_SEL (connected to gpio bt_fuse_sel) shows the state of the BT_FUSE_SEL fuse. See

Fusemap for additional information on this fuse.

And Looking to it on the device

# devmem2 0x20D801C w # 0x76fb5000 is SRC_SMBR2
/dev/mem opened.
Memory mapped at address 0x76fb5000.
Value at address 0x20D801C (0x76fb501c): 0x2000001

results in:

SRC_SMBR2[4] = BT_FUSE_SEL = 0
MMC/EMMC boot details

Since we're in "Internal Boot", according to the "5.1 Boot Fusemap" chapter, the following table applies:

Boot Device BOOT_CFG1[6] BOOT_CFG1[5] BOOT_CFG1[4]
Serial ROM 0 1 1
SD/eSD 1 0 X
MMC/eMMC 1 1 X

If we look at the device settings:

[root@parabola ~]# devmem2 0x20D8004 w
/dev/mem opened.
Memory mapped at address 0x76fca000.
Value at address 0x20D8004 (0x76fca004): 0x4064

we have:

BOOT_CFG1[6] = 1
BOOT_CFG1[5] = 1
BOOT_CFG1[4] = 0

which results in the MMC/eMMC being selected.

GPIO override details

In "Table 8-3. GPIO override contact assignments" in "Chapter 8 System Boot" we have:

Package pin eFuse
LCD_DAT12 BOOT_CFG2[4]
LCD_DAT13 BOOT_CFG2[5]
LCD_DAT14 BOOT_CFG2[6]

Theses seem unused:

imx6sll-e60qm2.dts:
[...]
pinctrl_lcdif_dat: lcdifdatgrp {
    fsl,pins = <
        [...]
        MX6SLL_PAD_LCD_DATA12__LCD_DATA12	0x79
        MX6SLL_PAD_LCD_DATA13__LCD_DATA13	0x79
        MX6SLL_PAD_LCD_DATA14__LCD_DATA14	0x79
        [...]
    >;
};
[...]
&lcdif {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_lcdif_dat
                &pinctrl_lcdif_ctrl>;
    display = <&display>;
    status = "disabled";
    [...]
};
[...]

stock u-boot image details

With tools/dumpimage from u-boot master:

$ tools/dumpimage -l ../ntx-partitions-parser/partitions/bootloader.img 
Image Type:   Freescale IMX Boot Image
Image Ver:    2 (i.MX53/6/7 compatible)
Mode:         DCD
Data Size:    401408 Bytes = 392.00 KiB = 0.38 MiB
Load Address: 877ff420
Entry Point:  87800000

Building u-boot

The following compiler version was used (it comes from Parabola):

$ pacman -Q -o arm-none-eabi-gcc
/usr/bin/arm-none-eabi-gcc is owned by arm-none-eabi-gcc 8.2.0-1

Building:

export ARCH=arm
export CROSS_COMPILE=arm-none-eabi-
make mx6sll_e70q02_defconfig
make -j4

Flashing:

fastboot flash bootloader u-boot.imx

Booting prompt:

eBR-1A # reset
resetting ...


U-Boot 2016.03-21136-g06b320c20e-dirty (Feb 21 2019 - 16:16:09 +0100)

CPU:   Freescale i.MX6SLL rev1.1 996 MHz (running at 792 MHz)
CPU:   Commercial temperature grade (0C to 95C) at 44C
Reset cause: WDOG
Board: MX6SLL LPDDR2 NTX
I2C:   ready
DRAM:  512 MiB
__get_sd_number(),cfg23=0,cfg24=0 
MMC:   board_mmc_init() : isd=0 
board_mmc_init() : wifi=2 
FSL_SDHC: 0, FSL_SDHC: 1
In:    serial
Out:   serial
Err:   serial
ntx_hw_early_init() 0
ram p=80000000,size=536870912
switch to partitions #0, OK
mmc0(part 0) is current device
mmc read 0x9ffffe00 0x3ff 0x1

MMC read: dev # 0, block # 1023, count 1 ... 1 blocks read: OK
mmc read 0x9ffffe00 0x400 0x1

MMC read: dev # 0, block # 1024, count 1 ... 1 blocks read: OK
ntx_hw_late_init()
mmc read 0x9ffffc00 0x1 0x1

MMC read: dev # 0, block # 1, count 1 ... 1 blocks read: OK
NTXSN not avalible !
ntx_gpio_get_value(402) : error parameter ! null ptr !
ntx_config_fastboot_layout():10 binaries partition added
ntx_config_fastboot_layout():3 mbr partition added
check_and_clean: reg 0, flag_set 0
Fastboot: Normal
Net:   CPU Net Initialization Failed
No ethernet found.
Hit any key to stop autoboot:  0 
switch to partitions #0, OK
mmc0(part 0) is current device
mmc read 0x80800000 0x7ff 0x1

MMC read: dev # 0, block # 2047, count 1 ... 1 blocks read: OK
kernel size = 5364784@80800000
mmc read 0x80800000 0x800 0x28f5

MMC read: dev # 0, block # 2048, count 10485 ... 10485 blocks read: OK
Booting from mmc ...
mmc read 0x83000000 0x505 0x1

MMC read: dev # 0, block # 1285, count 1 ... 1 blocks read: OK
dtb size = 34761@83000000
mmc read 0x83000000 0x506 0x49

MMC read: dev # 0, block # 1286, count 73 ... 73 blocks read: OK

 hwcfgp=9ffffe00,pcb=60,customer=9

ntx_gpio_get_value(402) : error parameter ! null ptr !
ESDin=0,UPGKey=-1,PWRKey=0,USBin=0x1,BootESD=0,MenuKey=0
mmc read 0x9ffffc00 0x37ff 0x1

MMC read: dev # 0, block # 14335, count 1 ... 1 blocks read: OK
mmc read 0x9fdc8a00 0x3800 0x11ba

MMC read: dev # 0, block # 14336, count 4538 ... 4538 blocks read: OK
mmc read 0x9fdc8800 0x405 0x1

MMC read: dev # 0, block # 1029, count 1 ... 1 blocks read: OK
[WARNING] Binaries load sequence should Lo->Hi !
mmc read 0x9fda8a00 0x406 0x100

MMC read: dev # 0, block # 1030, count 256 ... 256 blocks read: OK
Kernel RAM visiable size=509M->509M
hwcfg rootfstype : 2
hwcfg partition type : 2
Kernel image @ 0x80800000 [ 0x000000 - 0x51dc30 ]
## Flattened Device Tree blob at 83000000
   Booting using the fdt blob at 0x83000000
   Using Device Tree in place at 83000000, end 8300b7c8

Starting kernel ...

Devices described in code but not present on the PCB?

imx6sll-e60qm2.dts

  • No HALL sensor?
  • No mmc LEDS?
  • No mmc/SD on mmc1

Hardware versions and revisions

The hardware reviewed here had imx6sll-e60qm2.dts, but similarly looking dts are in the vendor Linux source code.

Some hardware components with critical impact on freedom are not described in the devicetree such as:

  • The WiFi chip: however no other WiFi drivers are in the kernel configuration and the WiFi driver is an external driver with source code.

Because of that we cannot know in advance if the variants are also good for freedom, without looking at them physically or inferring it from other sources such as the kernel configuration.

dts Differences with imx6sll-e60qm2.dts Comments
  • imx6sll-e60k02.dts

Small differences:

  • it uses imx6sll-ntx.dtsi instead of imx6sll-ntx_emmc.dtsi which only difference is to invert the order of the usdhc busses
  • there are some pinmux and GPIO configuration differences
  • there seem to be some differences with the eMMC (maybe it's connected on another usdhc bus)
  • other very small differences
  • imx6sll-e60ql2.dts

Big differences:

  • It uses an elan touchscreen (compatible = "elan,elan-touch";) and the driver is built in the kernel we have. The driver used doesn't seem to be able to load a firmware. However it can get the touchscreen builtin firmware version.
  • It contains a different power management chip (compatible = "fiti,fp9928";) for the display ("EPDC PMIC I2C address").

Small differences:

  • it uses imx6sll-ntx.dtsi instead of imx6sll-ntx_emmc.dtsi which only difference is to invert the order of the usdhc busses
  • there are some pinmux and GPIO configuration differences
  • there seem to be some differences with the eMMC (maybe it's connected on another usdhc bus)
  • other very small differences
TODO: Look in u-boot if there is a driver for the EPDC PMIC.
  • imx6sll-e60qp2.dts

Small differences:

  • there are some pinmux and GPIO configuration differences
  • there seem to be some differences with the eMMC (maybe it's connected on another usdhc bus)
  • other very small differences

Big differences:

  • It uses another touchscreen (compatible = "neonode,zforce-ir-touch";) and the driver is built in the kernel we have. The driver used doesn't seem to be able to load a firmware. However it can get the touchscreen builtin firmware version.
  • imx6sll-e70q02.dts

Big differences:

  • It uses a different procimity sensor (compatible = "si,si114x-als";). The driver doesn't load any firmware.
  • It uses an elan touchscreen (compatible = "elan,elan-touch";) and the driver is built in the kernel we have. The driver used doesn't seem to be able to load a firmware. However it can get the touchscreen builtin firmware version.

Small differences:

  • there are some pinmux and GPIO configuration differences
  • there seem to be some differences with the eMMC (maybe it's connected on another usdhc bus)
  • other very small differences
  • imx6sll-t05r02.dts


Big differences:

  • It has an accelerator (compatible = "si,si114x-als";). The driver used doesn't seem to be able to load a firmware.
  • It uses an elan touchscreen (compatible = "elan,elan-touch";) and the driver is built in the kernel we have. The driver used doesn't seem to be able to load a firmware. However it can get the touchscreen builtin firmware version.

Small differences:

  • there are some pinmux and GPIO configuration differences
  • there seem to be some differences with the eMMC (maybe it's connected on another usdhc bus)
  • other very small differences
  • imx6sll-evk-btwifi.dts
  • imx6sll-evk.dts
  • imx6sll-evk-reva.dts
Probably NXP evaluation boards. Not work investigating here.
  • imx6sll-lpddr2-arm2.dts
  • imx6sll-lpddr2-ntx.dts
  • imx6sll-lpddr3-arm2-csi.dts
  • imx6sll-lpddr3-arm2.dts
  • imx6sll-lpddr3-arm2-ecspi.dts
  • imx6sll-lpddr3-arm2-spdif.dts
Probably evaluation boards related dts. Not work investigating here.

Software

Kobo u-boot version

U-boot is a free software bootloader. The source code is provided by kobo.

It is based on one of the branches/commits of the freescale fork of u-boot for their I.MX System on a chip.

u-boot serial console

To get a shell in u-boot you will need to setup a serial cable, and press a key in the serial console during boot:

U-Boot 2016.03-00031-gcd5f70c (Aug 31 2017 - 13:17:25 +0800)

CPU:   Freescale i.MX6SLL rev1.1 996 MHz (running at 792 MHz)
CPU:   Commercial temperature grade (0C to 95C) at 43C
Reset cause: WDOG
Board: MX6SLL LPDDR2 NTX
I2C:   ready
DRAM:  512 MiB
__get_sd_number(),cfg23=0,cfg24=0 
MMC:   board_mmc_init() : isd=0 
board_mmc_init() : wifi=2 
FSL_SDHC: 0, FSL_SDHC: 1
In:    serial
Out:   serial
Err:   serial
ntx_hw_early_init() 0
ram p=80000000,size=536870912
switch to partitions #0, OK
mmc0(part 0) is current device
mmc read 0x9ffffe00 0x3ff 0x1

MMC read: dev # 0, block # 1023, count 1 ... 1 blocks read: OK
mmc read 0x9ffffe00 0x400 0x1

MMC read: dev # 0, block # 1024, count 1 ... 1 blocks read: OK
ntx_hw_late_init()
mmc read 0x9ffffc00 0x1 0x1

MMC read: dev # 0, block # 1, count 1 ... 1 blocks read: OK
NTXSN not avalible !
ntx_gpio_get_value(402) : error parameter ! null ptr !
ntx_config_fastboot_layout():10 binaries partition added
ntx_config_fastboot_layout():3 mbr partition added
check_and_clean: reg 0, flag_set 0
Fastboot: Normal
Net:   CPU Net Initialization Failed
No ethernet found.
Hit any key to stop autoboot:  0 
eBR-1A #

u-boot environment

Here's the u-boot environment:

eBR-1A # printenv
baudrate=115200
bootcmd=mmc dev ${mmcdev};if run loadimage; then run mmcboot; fi; 
bootcmd_mfg=run mfgtool_args;bootz ${loadaddr} ${initrd_addr} ${fdt_addr};
bootdelay=1
bootscript=echo Running bootscript from mmc ...; source
console=ttymxc0
epdc_waveform=epdc_splash.bin
fastboot_dev=mmc0
fdt_addr=0x83000000
fdt_file=undefined
fdt_high=0xffffffff
image=zImage
initrd_addr=0x83800000
initrd_high=0xffffffff
ip_dyn=yes
loadaddr=0x80800000
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
loadfdt=load_ntxdtb
loadimage=load_ntxkernel
mfgtool_args=setenv bootargs console=${console},${baudrate} rdinit=/linuxrc g_mass_storage.stall=0 g_mass_storage.removable=1 g_mass_storage.file=/fat g_mass_storage.ro=1 g_mass_storage.idVendor=0x066F g_mass_storage.idProduct=0x37FF g_mass_storage.iSerialNumber="" 
mmcargs=setenv bootargs console=${console},${baudrate} rootwait rw no_console_suspend 
mmcautodetect=no
mmcboot=echo Booting from mmc ...; run mmcargs; if run loadfdt; then bootz ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi;
mmcdev=0
mmcpart=1
script=boot.scr
stderr=serial
stdin=serial
stdout=serial

Environment size: 1203/8188 bytes

u-boot booting process

Here the u-boot boot process in uncomon and relies on custom commands like load_ntxkernel to load and execute the Linux kernel and associated data like the dtb:

bootcmd=mmc dev ${mmcdev};if run loadimage; then run mmcboot; fi; 
loadimage=load_ntxkernel

Adding extra kernel commandline arguments

You can do that in u-boot by overriding mmcargs

setenv mmcargs setenv bootargs <your extra arguments> console=\${console},\${baudrate} rootwait rw no_console_suspend

Stock OS analysis

  • The default OS forces the user to register or use some network services like Kobo, google, facebook, etc, however we can get a shell through the serial port.

Source code

  • Some Heavily modified Linux 4.1.15 source code is provided by Kobo for this device. It is most probably based on an unknown branch in Freescale's fork of Linux for I.MX system on a chip.
  • The WiFi driver source code is also provided by Kobo for this device.
  • Some less interesting userspace source code is probably also provided at the same location.

Linux 4.1.15 sources

New sources for Linux seem to have been pushed the 30 April:

  • They don't contain all the build scripts that the 3.0.35 did
  • They use the devicetre
  • They were compiled with gcc 5.3.0
  • Parabola's community/arm-none-eabi-gcc isn't able to compile it, however pcr/crosstool-ng can be installed and used to create an arm baremetal 5.4.0 gcc which is able to compile it.
How to build
Getting the kernel configuration and device tree source file name

To build it for the device we need:

  • A configuration file, hopefully in my case it can be exrtacted from the device by running the following on the device:
# zcat /proc/config.gz
  • To identify which device tree source file was used if we want to avoid reusing the one that is in the eMMC

We can start by looking the machine name:

# grep . /sys/firmware/devicetree/base/*
[...]
/sys/firmware/devicetree/base/compatible:fsl,imx6sll-lpddr3-arm2
/sys/firmware/devicetree/base/compatible:fsl,imx6sll
/sys/firmware/devicetree/base/model:Freescale i.MX6SLL NTX Board

And grepping in the source to see the matching files:

$ grep "Freescale i.MX6SLL NTX Board" -r arch/arm/boot/dts/*
arch/arm/boot/dts/imx6sll-e60k02.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-e60ql2.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-e60qm2.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-e60qp2.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-e70q02.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-lpddr2-ntx.dts:	model = "Freescale i.MX6SLL NTX Board";
arch/arm/boot/dts/imx6sll-t05r02.dts:	model = "Freescale i.MX6SLL NTX Board";

Then on my board I've the 'cyttsp5' touchscreen controller:

# cd /sys/bus/i2c/devices
# grep . 0-*/name 1-*/name 2-*/name
0-0036/name:lm3630a_bl
1-0024/name:cyttsp5_i2c_adapter
1-0068/name:tps6518x
2-0032/name:ricoh619

Now only two files are remainign:

$ grep "cyttsp5_i2c_adapter" $(grep "Freescale i.MX6SLL NTX Board" -r arch/arm/boot/dts/* | sed 's#:.*##')
arch/arm/boot/dts/imx6sll-e60k02.dts:		compatible = "cy,cyttsp5_i2c_adapter";
arch/arm/boot/dts/imx6sll-e60k02.dts:		cy,adapter_id = "cyttsp5_i2c_adapter";
arch/arm/boot/dts/imx6sll-e60qm2.dts:		compatible = "cy,cyttsp5_i2c_adapter";
arch/arm/boot/dts/imx6sll-e60qm2.dts:		cy,adapter_id = "cyttsp5_i2c_adapter";

It is possible to visualize the difference between both files in a very convenient way like this:

$ meld arch/arm/boot/dts/imx6sll-e60k02.dts arch/arm/boot/dts/imx6sll-e60qm2.dts

It shows quite some difference in the way the system on a chip pins are configured.

For instance for arch/arm/boot/dts/imx6sll-e60qm2.dts we have:

pinctrl_elan_ts_gpio_sleep: elan_ts_gpio_grp_sleep {
	fsl,pins = <
		MX6SLL_PAD_SD1_DATA3__GPIO5_IO06		0x10059 /* TP_INT */
		MX6SLL_PAD_SD1_DATA2__GPIO5_IO13		0x10059 /* TP_RST */
	>;
};

and for arch/arm/boot/dts/imx6sll-e60k02.dts we have:

pinctrl_elan_ts_gpio: elan_ts_gpio_grp {
	fsl,pins = <
		MX6SLL_PAD_GPIO4_IO24__GPIO4_IO24		0x17059 /* TP_INT */
		MX6SLL_PAD_GPIO4_IO18__GPIO4_IO18		0x10059 /* TP_RST */
		MX6SLL_PAD_GPIO4_IO17__GPIO4_IO17		0x10059 /* TP_SWDIO */
	>;
};

Fortunately the Linux kernel exports that information at runtime, and we can access it like that:

# mount -t debugfs none /sys/kernel/debug/
# cd /sys/kernel/debug/pinctrl

After grepping we can see the following line in pinctrl-handles:

type: MUX_GROUP controller 20e0000.iomuxc group: elan_ts_gpio_grp (34) function: imx6sll-lpddr3-arm2
type: CONFIGS_PIN controller 20e0000.iomuxc pin MX6SLL_PAD_GPIO4_IO24 (147) 00017059                
type: CONFIGS_PIN controller 20e0000.iomuxc pin MX6SLL_PAD_GPIO4_IO18 (146) 00010059                
type: CONFIGS_PIN controller 20e0000.iomuxc pin MX6SLL_PAD_GPIO4_IO17 (149) 00010059                

Note that to open pinctrl-handles with a text editor on the device you need to copy it somewhere first, like in /tmp/

In my case the device tree file that works for my hardware is the arch/arm/boot/dts/imx6sll-e60qm2.dts

kernel logs

runtime informations

Here's the kernel version of the device I got:

# uname -r
4.1.15-00104-gcd6a6a6

The boot kernel parameters are available in /proc/cmdline:

console=ttymxc0,115200 rootwait rw no_console_suspend hwcfg_p=0x9ffffe00 hwcfg_sz=110 waveform_p=0x9fdc8a00 waveform_sz=2323160 ntxfw_p=0x9fdc6400 ntxfw_sz=9474 mem=509M boot_port=0 rootfstype=ext4 root=/dev/mmcblk0p1 quiet
  • The kernel configuration is available at /proc/config.gz
  • The device uses a devicertee that is passed by the bootloader:
# grep . /sys/firmware/devicetree/base/*
[...]
/sys/firmware/devicetree/base/compatible:fsl,imx6sll-lpddr3-arm2
/sys/firmware/devicetree/base/compatible:fsl,imx6sll
/sys/firmware/devicetree/base/model:Freescale i.MX6SLL NTX Board

Running Parabola

The rootfs partitions are too small to install Parabola (They are 256M each), thankfully we have a big partition (6.8G) that is formatted as FAT. But we cannot easily use this as the bootloader boot command uses "root=/dev/mmcblk0p1" and we don't want to require users to use the serial console as it would require soldering.

A way to deal with that would be to set the fat partition as mmcblk0p1. This is possible since we can force the device to go in fastboot mode and overwrite the MBR that way.

Changing partition order

First dump the MBR in mbr1.img as described in this page.

Then change the partitions orders.

sfdisk -d mbr.img > mbr.txt

The following will be in mbr.txt:

mbr1.img1 : start=       49152, size=      524289, type=83
mbr1.img2 : start=      573441, size=      524289, type=83
mbr1.img3 : start=     1097730, size=    14139389, type=b

You can change it to:

mbr.img2 : start=       49152, size=      524289, type=83
mbr.img3 : start=      573441, size=      524289, type=83
mbr.img1 : start=     1097730, size=    14139389, type=b

Then we recreate a new mbr:

qemu-img create -f raw tmp.img 8G
sfdisk -f tmp.img < mbr.txt
dd if=tmp.img of=mbr2.img count=1
rm tmp.img

We can then flash that:

fastboot flash mbr mbr2.img

TODO:

  • Find if it's still possible to trigger the mount of the partition from the stock OS (which doesn't require a serial port)

Serial console with OpenRC

Then you can install OpenRC as systemd won't work with the default kernel unless you recompile it (systemd requires cgroups)

To get a serial console follow this guide https://wiki.gentoo.org/wiki/OpenRC#openrc-init and also add ttymxc0 to /etc/securetty

You also need to create a file at /etc/conf.d/agetty.ttymxc0 with this content:

# make agetty quiet
#quiet="yes"

# Set the baud rate of the terminal line
baud="115200"

# set the terminal type
term_type="linux"

# extra options to pass to agetty for this port
agetty_options=""

else the console will use 38400 bauds while it is at 115200 during the boot.

Stock kernel and modules modules

To use the stock kernel and modules seamlessly do:

mkdir -p /lib/modules/4.1.15-00104-gcd6a6a6/kernel/drivers/

If the stock rootfs is mounted on /mnt you can just copy them that way:

cp -r /mnt/drivers/mx6sll-ntx/usb/ /lib/modules/4.1.15-00104-gcd6a6a6/kernel/drivers/
cp -r /mnt/drivers/mx6sll-ntx/wifi/ /lib/modules/4.1.15-00104-gcd6a6a6/kernel/drivers/
touch /lib/modules/4.1.15-00104-gcd6a6a6/modules.order
touch /lib/modules/4.1.15-00104-gcd6a6a6/modules.builtin
depmod -a

Then you can use them as usual, for instance to get usbnet you could do:

modprobe g_ether


Making the display work

TODO:

  • The display was only validated with 1fps with Xorg and xfce4.
  • We need to check if the linux-libre patch applies to this vendor kernel

To enable the display:

  • Build the patched vendor kernel that has CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE=y enabled and the dependency on nonfree display binaries removed.
  • Once the device booted under Parabola, run the following program:
/*
 * Copyright (C) 2019 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stropts.h>
#include <stdint.h>
#include <asm/ioctls.h>

#define AUTO_UPDATE_MODE_AUTOMATIC_MODE		1
#define MXCFB_SET_AUTO_UPDATE_MODE		_IOW('F', 0x2D, uint32_t)

static int set_auto_update(int fd)
{
	int ret;
	int mode = AUTO_UPDATE_MODE_AUTOMATIC_MODE;

	ret = ioctl(fd, MXCFB_SET_AUTO_UPDATE_MODE, &mode);
	if (ret < 0) {
		int err = errno;
		printf("ioctl error: %s\n", strerror(err));
	}
}

int main()
{
	int fd = open("/dev/fb0", 0);
	if (fd < 0) {
		int err = errno;
		printf("open error: %s\n", strerror(err));
	}
	set_auto_update(fd);

	return 0;
}
  • Run Xorg -retro or startxfce4 as root
  • Touch the screen, the cursor will move (not at the location of the touch though)

By default the display orientation is in landscape mode.

Making the touchscreen work

The input orientation can be adjusted to match the display landscape mode with:

xinput set-prop "cyttsp5_mt" "Coordinate Transformation Matrix" -1 0 1   0 -1 1   0 0 1

See the following links for more information on how to compute the coordinate transformation matrix:

To come up with that number I computed a translation to the origin multiplicated by a half-circle rotation which was transleted again to 1/2 width, 1/2 height coordinates.

That didn't work however replacing the width and height by 1 in the final matrix worked (and gave the command above). I probably did a sign error somewhere in the calculation.

Linux upstream TODO

Driver or chip Devicetree Driver or comments
Base hardware Sent upstream: TODO:
  • Validate the basic PMIC support (power off, reboot, regulators) DONE
  • Send the DTS upstream DONE
GPIO button Understand how it's connected and how it interferes with the PMIC, and why it works in u-boot
cyttsp5 touchscreen+button+proximity driver
  • Find the exact chip used
  • Look if it's supported by drivers/input/touchscreen/cyttsp*
Ricoh RC5T619: Driver present for:
  • regulators
  • watchdog timer
  • RTC (since 5.7-rc1
  • ADC (since 5.7-rc1, can also read battery voltage)
Missing:
  • Battery charger / (gauge?)
  • power button
  • GPIOs
TPS 6518? It might be possible to integrate it in similar already existing drivers or make one line in:
  • drivers/mfd/tps*
TI lm3630 backlight driver
NXP/Freescale epdc (e-paper display controller) TODO TODO

Enabling people to easily install and backup a rootfs

Without serial we only have access to fastboot which only support booting an image, flashing an image or rebooting the device[1].

So with that we need to find a way to backup and/or install a distribution on the device that people can easily use.

We have several approaches for that:

  • Modify the u-boot environment from adb. This is the most simple way but it's dangerous.
  • Create a rootfs that has to fit in RAM, so it needs to be less than 512M

Distributions

Distribution Type Size Verdict
Parabola arm with openssh, ddrescue, vim initramfs 899M Cannot fit into the RAM even as an XZ compressed initramfs as the kernel would have to decompress it anyway.
Parabola arm with openssh, ddrescue, vim squashfs with -comp xz 408M May fit, needs testing
Parabola arm with openssh, ddrescue, vim squashfs with -comp lzo 465M May fit, needs testing
Parabola arm with openssh, ddrescue, vim xz compressed intramfs and Linux with CONFIG_ZSWAP (LZO compression) May work, need testing
LibreCMC Allwinner A1x/A20/A3x
LibreCMC Allwinner A1x/A20/A3x Needs an external kernel
LibreCMC QEMU ARM Virtual Machine
  • Needs an external kernel
  • Easier to test in a vm

References

  1. From the vendor u-boot in drivers/fastboot/fastboot.c we have: "fastboot main process, only support 'download', 'flash' 'reboot' command now"

Manufacturer informations

Other informations