The aim of this project is to develop a solution for a solar laptop feedable with a photovoltaic (PV) module, hence low power available. The choice of the cubieboard as a development platform led us to look for very lighweight distributions considering the low-end hardware. Moreover another requirement is the availability of a convenient tool-set to help the source build and packaging processes.

What distro to choose? Mumble...

Our choice fell on Arch Linux, a corner distro that has recently become more popular for all the users bored from the difficulties involved in slimming down the major distros to fit their needs. With Arch Linux the process is flipped over: instead of removing stuff you can build brick after brick all your system, and since the aim is to obtain a full desktop environment (DE in short, not common for an embedded device, usually maintained headless), lightness is a critical feature. Despite the learning curve being far steeper than for regular distros, we succeeded in obtaining an OS cut out for ours needs, aided from one of the components of our team that is already fluent with it.

The setup process is quite straightforward following the installation steps, where the only change is we need to download the right hwpack to enable the whole 1GB RAM owned by our Cubieboard model.  This rootfs is the software base of the OS. Arch Linux follows a rolling release cycle and this is good because the development of the OSs on this ARM devices is still very dynamic and being able to catch the daily news is a plus for the prototyping stage.


The image we started working on was shipped with a 3.0 kernel tree, when a far better 3.4 was  still in a development stage. Since Allwinner, the (fabless) design house of the Cubieboard's CPU, releases the kernel source on GitHub, we had to configure, build, package and install the newer branch, since we were facing some incompatibilities with DVI output, i.e. we needed to setup the Desktop Environment waiting the hardware for the LVDS. Here we exploited the main Arch Linux benefits: PKGBUILDs. There's a sneak peek in the image above the title of this subsection. The main benefit of the "Arch way" is the easiness in maintaining and upgrading a package: we need only to change a couple of variables at the beginning of the file to point to the right version and the appropriate github branch, fine-tune the config with all the needed stuff for the sunxi hardware (not so easy as it seems) and finally type makepkg. Well done.

To build a kernel on a CPU like the A10 is a pain, so, to speed up the whole process, we designed a bash set of scripts to create an archlinux chroot inside an x86 guest system, to place in the right location the cross-buildchain and to configure distcc for a distributed build. With the native support of the archlinux package manager for distcc, setting up the cubieboard to send the sources to the network was straightforward, and this allowed to test several configurations until everything worked fine. You can find a simplified way to our approach in the archlinuxarm developer section.

At the moment we are typing, the 3.4 branch is being shipped upstream in the archlinuxarm repositories so there isn't the need to build yourself the new branch anymore to enjoy all the goodies, but it remains a good starting point to develop embedded software. This is what we tried to underline when talking about the rolling release profits.

Video stack

Cubieboard is equipped with a Mali 400 GPU. We needed a full working video stack to run a complete DE, actually there is an open source driver called lima, still under development and thus lacking a lot of features we were looking for. The other option is to use the proprietary driver dealing with all the problems that a binary blob brings, whose build system is hosted in github. Starting from the wiki page, digging out all the informations from every forum, we managed to get a proper working driver coupled with a proper framebuffer configuration (the kernel was already properly configured). Thanks to this, we managed to have first a DVI output through HDMI port, and eventually also one through LVDS. Below, we provide the framebuffer configuration and a tarball with all the packages used:

# This is a minimal sample config file, which can be copied to
# /etc/X11/xorg.conf.d/99-fbturbo.conf in order to make the Xorg server
# pick up and load xf86-video-fbturbo driver installed in the system.
# When troubleshooting, check /var/log/Xorg.0.log for the debugging
# output and error messages.
# Run "man fbturbo" to get additional information about the extra
# configuration options for tuning the driver.

Section "Device"
        Identifier      "Allwinner A10/A13 FBDEV"
        Driver          "fbturbo"
        Option          "fbdev" "/dev/fb0"
        Option          "SwapbuffersWait" "true"
        # `man fbturbo` to know more options
        Option          "AccelMethod" "G2D"

The packages needed to get the video stack working are:

sunxi-mali-git (provides: sunxi-mali-libmali-git, sunxi-mali-libump-git)

LVDS Configuration

For this project we have recovered a Samsung 15'' LTN156AT06 raw LCD panel from a dead laptop. To connect it to the Cubieboard's GPIO headers we used an exotic I-PEX 20455 40P to dupont connector and a own-designed PCB to power all components through the PV panel and the battery. The configuration of the headers' signal outputs is performed by a so called fex file, read by the bootloader in the early stages of the boot process. There isn't a lot of documentation around about the meaning of all the variables contained in the fex file, nevertheless you can find an example in the linux-sunxi wiki. Matching the values given by the datasheet of our panel, we configured the fex file as follows:

disp_init_enable = 1
disp_mode = 0
screen0_output_type = 1
screen0_output_mode = 4
screen1_output_type = 1
screen1_output_mode = 4
fb0_framebuffer_num = 2
fb0_format = 10
fb0_pixel_sequence = 0
fb0_scaler_mode_enable = 0
fb1_framebuffer_num = 2
fb1_format = 10
fb1_pixel_sequence = 0
fb1_scaler_mode_enable = 0
lcd0_bright = 197
lcd1_bright = 197
lcd0_screen_bright = 50
lcd0_screen_contrast = 50
lcd0_screen_saturation = 57
lcd0_screen_hue = 50
lcd1_screen_bright = 50
lcd1_screen_contrast = 50
lcd1_screen_saturation = 57
lcd1_screen_hue = 50

lcd_used = 1
lcd_x = 1366
lcd_y = 768
lcd_dclk_freq = 69
lcd_pwm_not_used = 0
lcd_pwm_pol = 0
lcd_if = 3
lcd_hbp = 114
lcd_ht = 1484
lcd_vbp = 12
lcd_vt = 1564
lcd_hv_if = 0
lcd_hv_smode = 0
lcd_hv_s888_if = 0
lcd_hv_syuv_if = 0
lcd_hv_vspw = 0
lcd_hv_hspw = 0
lcd_lvds_ch = 0
lcd_lvds_mode = 0
lcd_lvds_bitwidth = 1
lcd_lvds_io_cross = 0
lcd_cpu_if = 0
lcd_frm = 1
lcd_io_cfg0 = 268435456
lcd_gamma_correction_en = 0
lcd_gamma_tbl_0 = 0x0
lcd_gamma_tbl_1 = 0x10101
lcd_gamma_tbl_255 = 0xffffff
lcd_bl_en_used = 1
lcd_bl_en = port:PH07<1><0><default><1>
lcd_power_used = 1
lcd_power = port:PH08<1><0><default><1>
lcd_pwm_used = 1
lcd_pwm = port:PB02<2><0><default><default>
lcd_gpio_0 =
lcd_gpio_1 =
lcd_gpio_2 =
lcd_gpio_3 =
lcdd0 = port:PD00<2><0><default><default>
lcdd1 = port:PD01<2><0><default><default>
lcdd2 = port:PD02<2><0><default><default>
lcdd3 = port:PD03<2><0><default><default>
lcdd4 = port:PD04<2><0><default><default>
lcdd5 = port:PD05<2><0><default><default>
lcdd6 = port:PD06<2><0><default><default>
lcdd7 = port:PD07<2><0><default><default>
lcdd8 = port:PD08<2><0><default><default>
lcdd9 = port:PD09<2><0><default><default>
lcdd10 = port:PD10<2><0><default><default>
lcdd11 = port:PD11<2><0><default><default>
lcdd12 = port:PD12<2><0><default><default>
lcdd13 = port:PD13<2><0><default><default>
lcdd14 = port:PD14<2><0><default><default>
lcdd15 = port:PD15<2><0><default><default>
lcdd16 = port:PD16<2><0><default><default>
lcdd17 = port:PD17<2><0><default><default>
lcdd18 = port:PD18<2><0><default><default>
lcdd19 = port:PD19<2><0><default><default>
lcdd20 = port:PD20<2><0><default><default>
lcdd21 = port:PD21<2><0><default><default>
lcdd22 = port:PD22<2><0><default><default>
lcdd23 = port:PD23<2><0><default><default>
lcdclk = port:PD24<2><0><default><default>
lcdde = port:PD25<2><0><default><default>
lcdhsync = port:PD26<2><0><default><default>
lcdvsync = port:PD27<2><0><default><default>