################################# Notes on the Pogoplug Mobile / V4 ################################# Hardware ######## The CPU family functional manual is wonderfully detailed and available at http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf The processor itself is documented at http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6281_OpenSource.pdf Table 26, on page 53, details the pin multiplexing arrangement and is very useful! Serial console is available on vias. With the power plug component-side-up and top-left, the block of four pins to the left of the power plug are, top-to-bottom, 3.3V, uart0 txd (GPIO 10), uart0 rxd (GPIO 11), and gnd. I2C is available on pads. With the CPU component-side-up and the RAM chip top-left, the pad to the right of R259 (in the region marked Q12) is SCK (GPIO 9); the pad to the right of R261 (in Q13) is SDA (GPIO 8). JTAG is available on test-pads. (Not tested; taken from http://wiki.openwrt.org/toh/cloudengines/pogo-v4 .) : TDI on TP19; TDO on TP20; TCK on TP18; TMS_CPU on TP21; RSTn on TP17; TMS_CORE on TP22. To the right of the SD card socket is J17, which looks to be (not tested; taken from http://wiki.openwrt.org/toh/cloudengines/pogo-v4 and visual inspection), in left-to-right order: 3.3V, GND, GPIO 3 (miso), GPIO 7 (cs), GPIO 1 (mosi), GPIO 2 (sck); this appears to be an SPI breakout! On the board's back side, by the processor, LED7 is GPIO 23 and LED8 is GPIO 21, both through resistors. Note that GPIO 21 is by default assigned to SATA0_ACT, which indicates either presence or activity on the SATA link. It could be repurposed. There is an un-populated button? near the power connector; I do not know what GPIO(s) are there, if any. There appears to be a GPIO pin, but I am unsure which, on the top right pin of U11 (next to R219, and in fact connected to one of its pads, too). Processor pin multiplexing configuration values (MPPs) can be investigated from within uboot, by something like ``md.l f1010000 4``. UART Booting ############ The kirkwood chips are very friendly and can be fed their initial boot image over a UART. The requisite ``kwboot`` tool is even packaged in Debian (in ``u-boot-tools``). Use, for example:: kwboot -b /path/to/uboot.kwb -B 115200 -t /dev/ttyACM0 -p Building UBoot ############## With an ``arm-none-eabi`` cross-compiler (say, Debian's ``gcc-arm-none-eabi``), run:: make pogo_v4_defconfig echo CONFIG_ENV_OFFSET=0x1C0000 >> .config make oldconfig CROSS_COMPILE=arm-none-eabi- make KCFLAGS=-fshort-enums ./tools/mkimage -T kwbimage \ -n ./board/cloudengines/pogo_v4/kwbimage.cfg \ -a 0x00600000 -e 0x00600000 -d u-boot.bin u-boot.kwb Or you could grab my binary, if you trust me, at :download:`pogo4-uboot.kwb`. Landing uBoot without serial console #################################### Taking over a from-factory device time! Do the pogoplug activation dance, but you can stop just after it finds and updates the device. Then run, on a host :: curl -k "https://root:ceadmin@PogoplugMobile/sqdiag/HBPlug?action=command&command=dropbear%20start"; Then you want to run all of this, as taken wholesale from http://blog.qnology.com/2014/07/hacking-pogoplug-v4-series-4-and-mobile.html :: #stop my.pogoplug.com service killall hbwd #download firmware utilities cd /tmp wget http://download.doozan.com/uboot/nanddump wget http://download.doozan.com/uboot/nandwrite wget http://download.doozan.com/uboot/flash_erase wget http://download.doozan.com/uboot/fw_printenv #make execuable chmod +x flash_erase fw_printenv nanddump nandwrite #printenv and setenv are normally symbolic links cp fw_printenv fw_setenv #remount '/' as read/write #by default the Pogoplug OS (internal flash) is read only #skip if running from Debian/ALARM mount -o remount,rw / #setup fw_env.config echo "/dev/mtd0 0xc0000 0x20000 0x20000">/etc/fw_env.config scp over your own uBoot image, and then write it:: /tmp/flash_erase /dev/mtd0 0 4 /tmp/nandwrite --pad /dev/mtd0 /tmp/uboot.kwb Then run whatever commands to adjust the uboot environment. Loading New Firmware from UBoot ############################### Flash bootloader without nuking environment (at ``0x1C0000``) :: mw 0x800000 0xffff 0x1C0000 tftpboot 0x800000 u-boot.kwb nand erase 0x0 0x1C0000 nand write.e 0x800000 0x0 0x1C0000 To nuke the environment, too, change the ``nand erase`` above to ``nand erase 0x0 0x200000``. You can also substitute ``loadb 0x800000`` (kermit) or ``loady 0x800000`` (ymodem) to use the serial port. In ckermit on the host, then, use, for example :: set prefixing all send /binary /protocol:kermit u-boot.kwb Flash UBI-nized image :: nand erase 0x200000 0x7e00000 tftpboot 0x800000 ... nand write 0x800000 0x200000 ${filesize} The Greatest UBoot Environment Settings ####################################### Here are what I consider to be the best uboot environment configuration settings. If you're pasting along, it may be useful to run ``:%s!^setenv!/tmp/fw_setenv!g`` for pasting into a root shell! Basics. You'll probably want to keep your ``ethaddr`` as it was :: setenv ethaddr 00:11:22:33:44:55 setenv baudrate 115200 setenv bootdelay 30 setenv arcNumber 3960 setenv machid f78 Netconsole ala http://forum.doozan.com/read.php?3,14,14 . To use this run ``nc -u -p 6666 -s 192.168.77.1 192.168.77.100 6666`` or ``socat STDIO UDP4-DATAGRAM:192.168.77.100:6666,sourceport=6666`` on your host:: setenv serverip 192.168.77.1 setenv ipaddr 192.168.77.100 setenv if_netconsole 'ping ${serverip}' setenv start_netconsole 'setenv ncip ${serverip}; setenv stdin nc; setenv stdout nc; setenv stderr nc; version;' setenv preboot 'run if_netconsole start_netconsole' Kernel command-line arguments :: setenv mtdids nand0=orion_nand setenv mtdparts 'mtdparts=orion_nand:0x1c0000(uboot),0x40000(uboot_env),0x7e00000(ubi)' setenv bootargs_console 'console=ttyS0,115200n8 panic=10' .. note:: The choice of partition layout is consistent with OpenWRT as of commit c19f811c4d732f634ac18f33ae95e954ac9e8c81 (on 2 Jan 2018, "kirkwood: add pogoplug v4" by Alberto Bursi); earlier editions of this page had smaller uboot partitions and placed the environment elsewhere. Boot commands and conditional operations. This wad of complexity attempts... * to boot the following file-system-based options: * A boot script ``/boot.scr`` of the 1st partition, formatted FAT, of any USB2 storage. * A kernel in the root of the 1st partition, formatted ext4, of the sdcard. * Like above, but on a FAT partition * The above two options, but on any USB2 storage. * The above three options, but searching ``/boot`` instead of ``/`` * OpenWRT compatibility: a file "initramfs.bin" in the root of a FAT fs via USB. In all file-system-based attempts, the kernel is expected to be named ``uImage``. If that is found, the loader additionally searches for ``uInitrd`` and ``pogo4.dtb`` and installs them correctly. For FAT partition options, it is assumed that the 2nd partition is ext4 and contains the root filesystem. .. note:: The MMC is apparently insufficiently reliable to be a good source of boot scripts (or, rather, of large file reads? in any case, my attempt at making UBI-paving update devices doesn't go well), so while the machinery could load scripts from MMC, it's less of a headache to use USB. * Having exhausted file-system options, the loader attempts a "raw" UBI boot, using a UBI partition ``root`` and *UBI volumes* named ``kernel`` (mandatory), ``initrd`` (optional), ``dtb`` (optional), and ``rootfs`` (mandatory). If these are found, the system will boot with ``rootfs`` as ``/``. The centerpieces of this mess are the ``bootcmd_load_*`` macros, which are pointed to by ``loadercmd`` (set in ``boot_try_*``). These expect to find five variables set in the environment: * ``loadermedia`` : source media (set in ``boot_if_*``) * ``loaderpart`` : partition on media (set in ``boot_common_pre``) * ``loaderwhere`` : memory address for resulting load (set in ``boot_cond*``) * ``loaderlimit`` : a size limit on the thing to load (set in ``boot_cond*``) * ``loaderwhence`` : source file or volume (set in ``boot_cond*`` from other vars) The ``boot_cond*`` wrappers around this know to build ``loaderwhence`` from: * ``loaderprefix`` : the filesystem path prefix (``/`` or ``/boot``; set in ``bootcmd``) * ``loaderkernel``, ``loaderinitramfs``, ``loaderdtb`` : the names of components of the boot process (set in ``boot_common_fs`` and ``boot_try_ubi``) * (if a DTB is loaded, the ``machid`` environment variable is cleared) :: setenv nc_disable 'setenv stdin serial; setenv stdout serial; setenv stderr serial' setenv bootcmd_do_bootm 'setenv bootargs ${bootargs_console} ${mtdids} ${mtdparts} ${loaderbootargs} ${xtrabootargs}; run nc_disable; bootm ${bootmargs}' setenv bootcmd_load_fat 'fatload $loadermedia $loaderpart $loaderwhere $loaderwhence' setenv bootcmd_load_ext 'ext4load $loadermedia $loaderpart $loaderwhere $loaderwhence' setenv bootcmd_load_ubi 'ubi read $loaderwhere $loaderwhence $loaderlimit' setenv boot_condload_fdt 'if loaderwhere=0x00700000; loaderwhence=${loaderprefix}${loaderdtb}; loaderlimit=0x100000; run ${loadercmd}; then fdt addr 0x00700000; fdt resize; fdt chosen; setenv machid; bootmargs="${bootmargs} 0x00700000"; fi;' setenv boot_condload_ird 'if loaderwhere=0x01100000; loaderwhence=${loaderprefix}${loaderinitramfs}; loaderlimit=0x300000; run ${loadercmd}; then bootmargs="${bootmargs} 0x01100000"; else bootmargs="${bootmargs} -"; fi;' setenv boot_condload 'if loaderwhere=0x00800000; loaderwhence=${loaderprefix}${loaderkernel}; loaderlimit=0x300000; run ${loadercmd}; then bootmargs="0x00800000"; run boot_condload_ird; run boot_condload_fdt; run bootcmd_do_bootm; fi' setenv boot_condscript 'if loaderwhere=0x00700000; loaderwhence=${loaderprefix}boot.scr; loaderlimit=0x100000; run ${loadercmd}; then source 0x700000; fi' setenv boot_common_pre 'loaderpart="0:1";' setenv boot_common_fs 'loaderkernel="uImage"; loaderinitramfs="uInitrd"; loaderdtb="pogo4.dtb"; loadercondcmd="boot_condload";' setenv boot_if_mmc 'if mmc rescan; mmc info; then loadermedia="mmc"; run ${loadercondcmd}; fi' setenv boot_if_usb 'if usb start; then loadermedia="usb"; run ${loadercondcmd}; fi' setenv boot_try_mmcE 'loadercmd="bootcmd_load_ext"; loaderbootargs="root=/dev/mmcblk0p1 rootfstype=ext4 rootwait"; run boot_if_mmc' setenv boot_try_mmcF 'loadercmd="bootcmd_load_fat"; loaderbootargs="root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"; run boot_if_mmc' setenv boot_try_usbE 'loadercmd="bootcmd_load_ext"; loaderbootargs="root=/dev/sda1 rootfstype=ext4 rootwait"; run boot_if_usb' setenv boot_try_usbF 'loadercmd="bootcmd_load_fat"; loaderbootargs="root=/dev/sda2 rootfstype=ext4 rootwait"; run boot_if_usb' setenv boot_try_ubi 'if ubi part ubi && ubi check rootfs; then loadercmd="bootcmd_load_ubi"; loaderbootargs="ubi.mtd=ubi rootfstype=ubifs"; run ${loadercondcmd}; fi' setenv bootcmd_fs 'echo "trying ${loaderprefix} kernels"; run boot_try_mmcE; run boot_try_mmcF; run boot_try_usbE; run boot_try_usbF;' setenv bootcmd_owt 'echo "trying OpenWRT recovery..."; loaderkernel="initramfs.bin"; loaderinitramfs="initrd"; loaderdtb="dtb"; run boot_try_usbF;' setenv bootcmd_ubi 'echo "trying UBI kernels"; loaderkernel="kernel"; loaderinitramfs="initrd"; loaderdtb="dtb"; run boot_try_ubi;' setenv bootcmd 'run boot_common_pre; loadercondcmd=boot_condscript; echo "trying script"; loaderprefix=/; run boot_try_usbF; run boot_common_fs; run bootcmd_fs; loaderprefix=/boot/; run bootcmd_fs; loaderprefix=""; run bootcmd_owt; run bootcmd_ubi; echo "Boot search failed"' .. note:: If you're wanting to extend the kernel's command line, the ``xtrabootargs`` environment variable is for you. .. note:: Boot scripts are useful for making media that pave over the internal flash on boot, offering a kind of less-manual upgrade path. .. note:: As of the latest attempt (U-Boot 174ac987), there are two deficiencies: * one has to drop netconsole before ``bootm`` (see ``nc_disable``, above) or the system will fail to load * the `standard boot `_ machinery lacks a prober for UBI(fs), which is kind of sad. It would be neat to teach OpenWRT to land a U-Boot script in ``/`` or something of that ilk and remove much of the above environmental complexity. .. _sysadmin_embcomp_pogo4-hardware_debian: How to Install Debian ##################### .. note:: Unless you have particularly good reason, you probably want to run a system that's more designed for... shall we say, politely, low-end devices. May I recommend `OpenWRT `_. .. note:: You will want a custom bootloader on the device for booting either USB or MMC, as Debian (or ALARM) will not fit on the onboard flash. I have one in my branch of OpenWRT that I use (https://github.com/nwf/openwrt), but there are others floating around that may be more convenient. These instructions have been updated as of 2023 Jan to work with ``bullseye``. Sadly, things are now a little *more* involved than they used to be, since the installation seemingly can no longer take place in an emulator. Fetch Debian Marvell arm installer images and the ``dtb`` we'll need: - ``vmlinuz-...`` from https://d-i.debian.org/daily-images/armel/daily/kirkwood/netboot/ - https://d-i.debian.org/daily-images/armel/daily/kirkwood/netboot/initrd.gz - https://d-i.debian.org/daily-images/armel/daily/kirkwood/device-tree/kirkwood-pogoplug-series-4.dtb Get these files onto your Pogoplug somehow; possibly the simplest is to land them in a FAT filesystem on a SD card or USB stick (which can be repurposed as your installation target, if desired). Concretely, using a USB stick, I was able to boot the kernel with :: usb start setenv bootargs console=ttyS0,115200n8 panic=10 fatload usb 0:1 0x00800000 vmlinuz-... fatload usb 0:1 0x01100000 initrd.gz fatload usb 0:1 0x00700000 kirkwood-pogoplug-series-4.dtb fdt addr 0x00700000; fdt resize; fdt chosen bootm 0x00800000 0x01100000 0x00700000 - Proceed to install as a usual Debian box. When making partitions, note that uBoot can understand only ext4 usefully, tho', so either make ``/``, if no ``/boot``, or ``/boot`` ext4. If you do separate ``/boot``, be sure to adjust your uBoot environment's kernel command line accordingly, as it likely defaults to the first partition as root and as the place to grab the kernel and so on. - The Debian installer will not install a kernel for you. After it declares the installation finished, instead launch a shell (or just switch to one of the two ``screen`` panes it has open to shells). - You'll want to run, in the target (so, under ``chroot /target /bin/dash`` :: cat >> /etc/kernel-img.conf < /etc/fw_env.config - Fetch the ``dtb`` again into ``/boot`` as ``/boot/pogo4.dtb``. - Into ``/boot/update_uimages.sh`` place the following (and ``chmod +x`` it) :: #!/bin/bash set -e -x -u cp /boot/uImage{,.old} || true cp /boot/uInitrd{,.old} || true mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e 0x00008000 \ -n Linux -d /boot/vmlinuz /boot/uImage mkimage -A arm -O linux -T ramdisk -C gzip -a 0x00000000 -e 0x00000000 \ -n initramfs -d /boot/initrd.img /boot/uInitrd Symlink this program so that it gets run whenever a new kernel is added or deleted:: ln -s /boot/update_uimages.sh /etc/kernel/postinst.d ln -s /boot/update_uimages.sh /etc/kernel/postrm.d - Add ``mvsdio`` and ``mmc_block`` to ``/etc/initramfs-tools/modules`` if you're installing to a SD card; the installer won't grab it because it won't see the need. - Run ``update-initramfs -k all -u`` and ``/boot/update_uimages.sh``. - ``systemd`` wants to see 16M free in ``/run``, so we need to raise its default size (as 10% of 128M is, notably, less than 16M to begin with):: echo RUN_SIZE=20M > /etc/default/tmpfs - Now exit the chroot and finish the installer. Assuming you've got ``u-boot`` set up correctly (itself a longer discussion), you should now have a Debian box.