Porting Linux to a new board

Info

This post is work in process.

I haven’t done this before so I’m a bit nervous whether I get everything working but lets try it.

It’s gorgeous to have a device that will become a consumer device and a goal to do some real development instead of just doing generic experiments with the OLinuXino boards. Now I’m forced to dig through the code to solve all the problems. It makes a lot of fun and I’m also learning a lot.

About the iMX233 Audio Development Board

You can think of the iMX233 Audio Development Board like of a iMX233 based development board to build yourself a MP3 player with the ability to record audio. If I’m correct then it uses the same audio codec like the Apple 8GB iPod nano [1] [2]. The contour of the later handheld device is already printed on the board. I don’t know what the future brings, but it might get released as open source hardware. For more information please visit: http://blog.bones-embedded.ch/imx233-audio-development-board/.

About Bones

Bones is a company from Switzerland that focusses on the development and production of products for people with visual impairment and deaf-blindness as well as Speech & Sound Modules (BSM) for text-to-speech applications and audio playback. Their Milestone line of audio players for the blind and visually impaired play audio books and music, record lectures and messages, read text files and eBooks, enable you to label objects and much more.

Useful information to port Linux to it

  • The board uses nearly the same processor (other package, BGA, more pins) as the OLinuXino

  • SJTAG is working

  • Boots from micro SD card

  • Audio via Wolfson codec connected to SAIF (Serial Audio Interface)

  • 2 SAIF ports, one for playback and one for recording

  • Important errata: “5838 SAIF2 DMA completion IRQ in the APBX DMA module is not connected to the interrupt collector”. ‘SAIF2 DMA completion IRQ’ must be triggered manually by polling

  • Files: sound/soc/mxs/mxs-saif.c, sound/soc/codecs/wm8750.c could be of interest

  • RAM: Mobile DDR mt46_h_32m16lf instead of the DDR mt46_v_32m16 which is used on the Olimex boards

    In imx-bootlets: #define MEM_MDDR

  • This board has also a 800 mAh LiPo Battery, so that I can experiment a bit with power saving under Linux like it was asked here.

GitHub Repository

Step 2: Blinking LED

I modified the blinking example from Debugging the iMX233-OLinuXino via SJTAG with OpenOCD so that it blinks the LED on this board.

[chris@thinkpad blink_led_bones]$ cat src/main.c
#include "regspinctrl.h"
#include "regsdigctl.h"

#define led_off()   (HW_PINCTRL_DOUT1_SET(0x00200000))
#define led_on()    (HW_PINCTRL_DOUT1_CLR(0x00200000))

void delay_us (int us)
{
  volatile int start = HW_DIGCTL_MICROSECONDS_RD();

  while (HW_DIGCTL_MICROSECONDS_RD() - start < us)
      ;
}

int main(void)
{

    // Make LED a GPIO
    HW_PINCTRL_MUXSEL3_SET(0x00000C00); // For LED at LCD_CS

    // Set output power to 4mA
    HW_PINCTRL_DRIVE6_CLR(0x00200000);

    // Enable output
    HW_PINCTRL_DOE1_SET(0x00200000);

    while(1)
    {
        led_off();
        delay_us(900000);
        led_on();
        delay_us(900000);
    }

    return 0;
}
[chris@thinkpad blink_led_bones]$ make all
mkdir -p ./output
arm-none-eabi-gcc -c -O0 -g -Wall -I./include -I/include -nostdinc -fno-builtin -o src/main.o src/main.c
arm-none-eabi-ld -o output/blink_led.elf ./src/entry.o ./src/main.o -static -nostdlib -T ./output/blink_led.ld -L/home/chris/local/gcc-arm-none-eabi-4_7-2013q1/bin/../lib/gcc/arm-none-eabi/4.7.3/ -lgcc
arm-none-eabi-objcopy -R -S -O binary -R .note -R .note.gnu.build-id -R .comment output/blink_led.elf output/blink_led.bin
[chris@thinkpad blink_led_bones]$ arm-none-eabi-gdb output/blink_led.elf
GNU gdb (GNU Tools for ARM Embedded Processors) 7.4.1.20130312-cvs
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-linux-gnu --target=arm-none-eabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/chris/local/OLinuXino/Debugging/SJTAG-Example/blink_led_bones/output/blink_led.elf...done.
(gdb) target remote :3333
Remote debugging using :3333
0x00002070 in delay_us (us=900000) at src/main.c:11
11         while (HW_DIGCTL_MICROSECONDS_RD() - start < us)
(gdb) monitor halt
(gdb) load output/blink_led.elf
Loading section .start, size 0x34 lma 0x2000
Loading section .text, size 0xc8 lma 0x2040
Start address 0x2000, load size 252
Transfer rate: 41 KB/sec, 126 bytes/write.
(gdb) monitor resume 0x2000
(gdb)

Now I know that I can at least create a bootable SD card and use the debugger.

Step 3: imx-bootlets

Follow the kernel building tutorial and edit imx-bootlets-src-10.05.02/boot_prep/init-mx23.c and add #define MEM_MDDR at the top, rebuilt it and write it to the SD card:

[chris@thinkpad imx-bootlets-src-10.05.02]$ make CROSS_COMPILE=arm-none-eabi- clean
[chris@thinkpad imx-bootlets-src-10.05.02]$ make CROSS_COMPILE=arm-none-eabi-
[chris@thinkpad imx-bootlets-src-10.05.02]$ sudo dd if=sd_mmc_bootstream.raw of=/dev/mmcblk0p1

Lets try to boot. I’m seeing nothing on the AUART, only on the DUART. But I cannot login because the RX pin from the DUART is not available. If I change the order of console=ttyAMA0,115200 console=ttyAPP0,115200 to console=ttyAPP0,115200 console=ttyAMA0,115200 I can see a bit more boot output because always the last console gets assigned to /dev/console.

First boot

First boot with debug UART connected on my desk at night

First boot with debug UART connected on my desk at night

[chris@thinkpad ~]$ minicom oli
Welcome to minicom 2.6.2

OPTIONS: I18n
Compiled on Jun 25 2013, 10:33:22.
Port /dev/ttyUSB0, 16:51:07

Press CTRL-A Z for help on special keys

HTLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLFC
PowerPrep start initialize power...
Battery Voltage = 0.98V
No battery or bad battery                                       detected!!!.Disabling battery                                   voltage measurements./2
EMI_CTRL 0x1C084040
FRAC 0x92926192
init_mddr_mt46h32m16lf_133Mhz
power 0x00820710
Frac 0x92926192
start change cpu freq
hbus 0x00000003
cpu 0x00010001
LLLLLLLFCLJUncompressing Linux... done, booting the kernel.
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 3.9.4-dirty (chris@thinkpad) (gcc version 4.7.3 20130312 (release) [ARM/embedded-4_7-branch revision 196615] (GNU Tools f3
[    0.000000] CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177
[    0.000000] CPU: VIVT data cache, VIVT instruction cache
[    0.000000] Machine: Freescale i.MX23 (Device Tree), model: i.MX23 Olinuxino Low Cost Board
[    0.000000] Memory policy: ECC disabled, Data cache writeback
[    0.000000] On node 0 totalpages: 16384
[    0.000000] free_area_init_node: node 0, pgdat c087e938, node_mem_map c0ddc000
[    0.000000]   Normal zone: 128 pages used for memmap
[    0.000000]   Normal zone: 0 pages reserved
[    0.000000]   Normal zone: 16384 pages, LIFO batch:3
[    0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
[    0.000000] pcpu-alloc: [0] 0
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
[    0.000000] Kernel command line: noinitrd console=ttyAPP0,115200 console=ttyAMA0,115200 root=/dev/mmcblk0p2 rw rootwait ssp1=mmc verbose debug
[    0.000000] PID hash table entries: 256 (order: -2, 1024 bytes)
[    0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] __ex_table already sorted, skipping sort
[    0.000000] Memory: 64MB = 64MB total
[    0.000000] Memory: 50720k/50720k available, 14816k reserved, 0K highmem
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.000000]     vmalloc : 0xc4800000 - 0xff000000   ( 936 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
[    0.000000]     modules : 0xbf000000 - 0xc0000000   (  16 MB)
[    0.000000]       .text : 0xc0008000 - 0xc07ff26c   (8157 kB)
[    0.000000]       .init : 0xc0800000 - 0xc082813c   ( 161 kB)
[    0.000000]       .data : 0xc082a000 - 0xc0882120   ( 353 kB)
[    0.000000]        .bss : 0xc0882120 - 0xc0dd8f20   (5468 kB)
[    0.000000] SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[    0.000000] NR_IRQS:16 nr_irqs:16 16
[    0.000000] of_irq_init: children remain, but no parents
[    0.000000] sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps every 4294967286ms
[    0.000000] Console: colour dummy device 80x30
[    0.000000] Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar
[    0.000000] ... MAX_LOCKDEP_SUBCLASSES:  8
[    0.000000] ... MAX_LOCK_DEPTH:          48
[    0.000000] ... MAX_LOCKDEP_KEYS:        8191
[    0.000000] ... CLASSHASH_SIZE:          4096
[    0.000000] ... MAX_LOCKDEP_ENTRIES:     16384
[    0.000000] ... MAX_LOCKDEP_CHAINS:      32768
[    0.000000] ... CHAINHASH_SIZE:          16384
[    0.000000]  memory used by lock dependency info: 3695 kB
[    0.000000]  per task-struct memory footprint: 1152 bytes
[    0.070000] Calibrating delay loop... 226.09 BogoMIPS (lpj=1130496)
[    0.070000] pid_max: default: 32768 minimum: 301
[    0.070000] Mount-cache hash table entries: 512
[    0.080000] CPU: Testing write buffer coherency: ok
[    0.080000] Setting up static identity map for 0xc05a76b0 - 0xc05a7708
[    0.090000] devtmpfs: initialized
[    0.110000] pinctrl core: initialized pinctrl subsystem
[    0.110000] regulator-dummy: no parameters
[    0.120000] NET: Registered protocol family 16
[    0.120000] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.130000] i2c-core: driver [dummy] registered
[    0.140000] gpiochip_add: registered GPIOs 0 to 31 on device: gpio.0
[    0.150000] gpiochip_add: registered GPIOs 32 to 63 on device: gpio.1
[    0.150000] gpiochip_add: registered GPIOs 64 to 95 on device: gpio.2
[    0.170000] Serial: AMBA PL011 UART driver
[    0.170000] 80070000.serial: ttyAMA0 at MMIO 0x80070000 (irq = 129) is a PL011 rev2
[    0.420000] console [ttyAMA0] enabled
[    0.470000] bio: create slab <bio-0> at 0
[    0.480000] mxs-dma 80004000.dma-apbh: initialized
[    0.490000] mxs-dma 80024000.dma-apbx: initialized
[    0.500000] of_get_named_gpio_flags exited with status 17
[    0.500000] usb0_vbus: 5000 mV
[    0.510000] SCSI subsystem initialized
[    0.510000] usbcore: registered new interface driver usbfs
[    0.520000] usbcore: registered new interface driver hub
[    0.520000] usbcore: registered new device driver usb
[    0.530000] i2c i2c-0: adapter [MXS I2C adapter] registered
[    0.540000] Linux video capture interface: v2.00
[    0.540000] pps_core: LinuxPPS API ver. 1 registered
[    0.550000] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.550000] PTP clock support registered
[    0.560000] Advanced Linux Sound Architecture Driver Initialized.
[    0.580000] cfg80211: Calling CRDA to update world regulatory domain
[    0.590000] Switching to clocksource mxs_timer
[    0.890000] FS-Cache: Loaded
[    0.890000] CacheFiles: Loaded
[    0.970000] NET: Registered protocol family 2
[    0.980000] TCP established hash table entries: 512 (order: 0, 4096 bytes)
[    0.990000] TCP bind hash table entries: 512 (order: 2, 18432 bytes)
[    1.000000] TCP: Hash tables configured (established 512 bind 512)
[    1.010000] TCP: reno registered
[    1.010000] UDP hash table entries: 256 (order: 2, 20480 bytes)
[    1.020000] UDP-Lite hash table entries: 256 (order: 2, 20480 bytes)
[    1.020000] NET: Registered protocol family 1
[    1.030000] RPC: Registered named UNIX socket transport module.
[    1.040000] RPC: Registered udp transport module.
[    1.040000] RPC: Registered tcp transport module.
[    1.050000] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    1.060000] NetWinder Floating Point Emulator V0.97 (double precision)
[    1.150000] FS-Cache: Netfs 'nfs' registered for caching
[    1.160000] NFS: Registering the id_resolver key type
[    1.170000] Key type id_resolver registered
[    1.180000] Key type id_legacy registered
[    1.180000] jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
[    1.190000] msgmni has been set to 99
[    1.220000] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 249)
[    1.230000] io scheduler noop registered (default)
[    1.240000] uart-pl011 80070000.serial: no DMA platform data
[    1.250000] 8006c000.serial: ttyAPP0 at MMIO 0x8006c000 (irq = 126) is a 8006c000.serial
[    1.840000] console [ttyAPP0] enabled
[    1.850000] mxs-auart 8006c000.serial: Found APPUART 3.0.0
[    1.860000] i2c-core: driver [at24] registered
[    1.880000] mxs-spi 80034000.ssp: registered master spi32766 (dynamic)
[    1.900000] CAN device driver interface
[    1.910000] PPP generic driver version 2.4.2
[    1.920000] PPP BSD Compression module registered
[    1.930000] PPP Deflate Compression module registered
[    1.940000] usbcore: registered new interface driver rtl8192cu
[    1.960000] usbcore: registered new interface driver rt2500usb
[    1.970000] usbcore: registered new interface driver rt73usb
[    1.980000] usbcore: registered new interface driver rt2800usb
[    1.990000] usbcore: registered new interface driver ath9k_htc
[    2.010000] usbcore: registered new interface driver ar5523
[    2.020000] usbcore: registered new interface driver asix
[    2.030000] usbcore: registered new interface driver ax88179_178a
[    2.040000] usbcore: registered new interface driver cdc_ether
[    2.050000] usbcore: registered new interface driver smsc95xx
[    2.070000] usbcore: registered new interface driver net1080
[    2.080000] usbcore: registered new interface driver cdc_subset
[    2.090000] usbcore: registered new interface driver zaurus
[    2.100000] usbcore: registered new interface driver cdc_ncm
[    2.110000] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    2.130000] usbcore: registered new interface driver cdc_acm
[    2.140000] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[    2.160000] Initializing USB Mass Storage driver...
[    2.170000] usbcore: registered new interface driver usb-storage
[    2.180000] USB Mass Storage support registered.
[    2.190000] usbcore: registered new interface driver usbserial
[    2.200000] usbcore: registered new interface driver usbserial_generic
[    2.220000] usbserial: USB Serial support registered for generic
[    2.230000] usbcore: registered new interface driver ipw
[    2.240000] usbserial: USB Serial support registered for IPWireless converter
[    2.250000] usbcore: registered new interface driver option
[    2.270000] usbserial: USB Serial support registered for GSM modem (1-port)
[    2.280000] imx_usb 80080000.usb: pinctrl get/select failed, err=-19
[    2.300000] ci_hdrc ci_hdrc.0: doesn't support gadget
[    2.310000] ci_hdrc ci_hdrc.0: EHCI Host Controller
[    2.320000] ci_hdrc ci_hdrc.0: new USB bus registered, assigned bus number 1
[    2.360000] ci_hdrc ci_hdrc.0: USB 2.0 started, EHCI 1.00
[    2.380000] hub 1-0:1.0: USB hub found
[    2.390000] hub 1-0:1.0: 1 port detected
[    2.400000] mousedev: PS/2 mouse device common for all mice
[    2.410000] i2c-core: driver [tsc2007] registered
[    2.420000] i2c-core: driver [rtc-ds1307] registered
[    2.440000] stmp3xxx-rtc 8005c000.rtc: rtc core: registered 8005c000.rtc as rtc0
[    2.460000] i2c /dev entries driver
[    2.470000] i2c-dev: adapter [MXS I2C adapter] registered as minor 0
[    2.480000] usbcore: registered new interface driver uvcvideo
[    2.490000] USB Video Class driver (1.1.1)
[    2.500000] gspca_main: v2.14.0 registered
[    2.510000] usbcore: registered new interface driver gspca_zc3xx
[    2.530000] stmp3xxx_rtc_wdt stmp3xxx_rtc_wdt: initialized watchdog with heartbeat 19s
[    2.550000] softdog: Software Watchdog Timer: 0.08 initialized. soft_noboot=0 soft_margin=60 sec soft_panic=0 (nowayout=0)
[    2.570000] of_get_named_gpio_flags: can't parse gpios property
[    2.620000] mxs-mmc 80010000.ssp: initialized
[    2.630000] of_get_named_gpio_flags exited with status 65
[    2.640000] of_get_named_gpio_flags exited with status 65
[    2.660000] ledtrig-cpu: registered to indicate activity on CPUs
[    2.680000] usbcore: registered new interface driver usbhid
[    2.690000] usbhid: USB HID core driver
[    2.710000] i2c-core: driver [sgtl5000] registered
[    2.730000] TCP: cubic registered
[    2.730000] NET: Registered protocol family 17
[    2.740000] can: controller area network core (rev 20120528 abi 9)
[    2.760000] NET: Registered protocol family 29
[    2.760000] can: raw protocol (rev 20120528)
[    2.770000] mmc0: host does not support reading read-only switch. assuming write-enable.
[    2.790000] can: broadcast manager protocol (rev 20120528 t)
[    2.800000] can: netlink gateway (rev 20130117) max_hops=1
[    2.810000] Key type dns_resolver registered
[    2.820000] mmc0: new high speed SDHC card at address 1234
[    2.840000] registered taskstats version 1
[    2.860000] mmcblk0: mmc0:1234 SA04G 3.63 GiB
[    2.880000] stmp3xxx-rtc 8005c000.rtc: setting system clock to 1970-01-01 00:00:06 UTC (6)
[    2.900000]  mmcblk0: p1 p2 p3
[    2.940000] ALSA device list:
[    2.950000]   No soundcards found.
[   13.820000] kjournald starting.  Commit interval 5 seconds
[   14.540000] EXT3-fs (mmcblk0p2): using internal journal
[   14.560000] EXT3-fs (mmcblk0p2): recovery complete
[   14.570000] EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode
[   14.580000] VFS: Mounted root (ext3 filesystem) on device 179:2.
[   14.600000] devtmpfs: mounted
[   14.610000] Freeing init memory: 160K
[   15.200000] systemd[1]: systemd 204 running in system mode. (+PAM -LIBWRAP -AUDIT -SELINUX -IMA -SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ)

Welcome to Arch Linux ARM!

[   15.290000] systemd[1]: Failed to insert module 'ipv6'
[   15.310000] systemd[1]: Set hostname to <olinuxino>.
[   16.170000] systemd[1]: Cannot add dependency job for unit netcfg.service, ignoring: Unit netcfg.service failed to load: No such file or directory..
[   16.210000] systemd[1]: Cannot add dependency job for unit display-manager.service, ignoring: Unit display-manager.service failed to load: No such .
[   16.260000] systemd[1]: Starting Forward Password Requests to Wall Directory Watch.
[   16.290000] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
[   16.300000] systemd[1]: Expecting device dev-ttyAMA0.device...
        Expecting device dev-ttyAMA0.device...
[   16.340000] systemd[1]: Expecting device dev-ttyAPP0.device...
        Expecting device dev-ttyAPP0.device...
[   16.370000] systemd[1]: Starting Remote File Systems.
[  OK  ] Reached target Remote File Systems.
[   16.400000] systemd[1]: Reached target Remote File Systems.
[   16.410000] systemd[1]: Starting Syslog Socket.
[  OK  ] Listening on Syslog Socket.
[   16.440000] systemd[1]: Listening on Syslog Socket.
[   16.450000] systemd[1]: Starting LVM2 metadata daemon socket.
[  OK  ] Listening on LVM2 metadata daemon socket.
[   16.490000] systemd[1]: Listening on LVM2 metadata daemon socket.
[   16.500000] systemd[1]: Starting Delayed Shutdown Socket.
[  OK  ] Listening on Delayed Shutdown Socket.
[   16.540000] systemd[1]: Listening on Delayed Shutdown Socket.
[   16.550000] systemd[1]: Starting Device-mapper event daemon FIFOs.
[  OK  ] Listening on Device-mapper event daemon FIFOs.
[   16.590000] systemd[1]: Listening on Device-mapper event daemon FIFOs.
[   16.600000] systemd[1]: Starting /dev/initctl Compatibility Named Pipe.
[  OK  ] Listening on /dev/initctl Compatibility Named Pipe.
[   16.640000] systemd[1]: Listening on /dev/initctl Compatibility Named Pipe.
[   16.650000] systemd[1]: Starting udev Kernel Socket.
[  OK  ] Listening on udev Kernel Socket.
[   16.690000] systemd[1]: Listening on udev Kernel Socket.
[   16.700000] systemd[1]: Starting udev Control Socket.
^@[  OK  ] Listening on udev Control Socket.
[   16.740000] systemd[1]: Listening on udev Control Socket.
[   16.750000] systemd[1]: Starting Dispatch Password Requests to Console Directory Watch.
[   16.770000] systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
[   16.780000] systemd[1]: Starting Paths.
[  OK  ] Reached target Paths.
[   16.820000] systemd[1]: Reached target Paths.
[   16.830000] systemd[1]: Starting Journal Socket.
[  OK  ] Listening on Journal Socket.
[   16.860000] systemd[1]: Listening on Journal Socket.
[   16.870000] systemd[1]: Starting Create static device nodes in /dev...
        Starting Create static device nodes in /dev...
[   16.930000] systemd[1]: Starting udev Coldplug all Devices...
        Starting udev Coldplug all Devices...
[   17.000000] systemd[1]: Mounted POSIX Message Queue File System.
[   17.020000] systemd[1]: Starting Journal Service...
        Starting Journal Service...
[  OK  ] Started Journal Service.
[   17.130000] systemd[1]: Started Journal Service.
[   17.150000] systemd[1]: Starting Encrypted Volumes.
[  OK  ] Reached target Encrypted Volumes.
[   17.190000] systemd[1]: Reached target Encrypted Volumes.
[   17.280000] systemd[1]: Starting Apply Kernel Variables...
        Starting Apply Kernel Variables...
[   17.470000] systemd[1]: Started Load Kernel Modules.
[   17.500000] systemd[1]: Mounted FUSE Control File System.
[   17.580000] systemd[1]: Mounted Configuration File System.
[   17.620000] systemd[1]: Starting Setup Virtual Console...
        Starting Setup Virtual Console...
[   17.720000] systemd[1]: Mounted Huge Pages File System.
[   17.770000] systemd[1]: Set up automount Arbitrary Executable File Formats File System Automount Point.
[   17.860000] systemd[1]: Started Set Up Additional Binary Formats.
[   17.930000] systemd[1]: Mounting Debug File System...
        Mounting Debug File System...
[   18.030000] systemd[1]: Starting Swap.
[  OK  ] Reached target Swap.
[   18.090000] systemd[1]: Reached target Swap.
[   18.140000] systemd[1]: Started File System Check on Root Device.
[   18.200000] systemd[1]: Starting Remount Root and Kernel File Systems...
        Starting Remount Root and Kernel File Systems...
[   18.410000] systemd[1]: Mounting Temporary Directory...
        Mounting Temporary Directory...
[  OK  ] Started Create static device nodes in /dev.
[   18.900000] systemd[1]: Started Create static device nodes in /dev.
[  OK  ] Started Apply Kernel Variables.
[   19.020000] systemd[1]: Started Apply Kernel Variables.
[  OK  ] Mounted Debug File System.
[   19.230000] systemd[1]: Mounted Debug File System.
[  OK  ] Started Remount Root and Kernel File Systems.
[   19.320000] systemd[1]: Started Remount Root and Kernel File Systems.
[  OK  ] Mounted Temporary Directory.
[   19.380000] systemd[1]: Mounted Temporary Directory.
[   19.420000] systemd[1]: Starting Load Random Seed...
        Starting Load Random Seed...
[   19.520000] systemd[1]: Starting udev Kernel Device Manager...
        Starting udev Kernel Device Manager...
[  OK  ] Started Load Random Seed.
[   20.140000] systemd-udevd[71]: starting version 204
[  OK  ] Started udev Kernel Device Manager.
[  OK  ] Reached target Local File Systems (Pre).
[  OK  ] Reached target Local File Systems.
        Starting Recreate Volatile Files and Directories...
        Starting Trigger Flushing of Journal to Persistent Storage...
[  OK  ] Started Recreate Volatile Files and Directories.
[  OK  ] Started Setup Virtual Console.
        Starting Update UTMP about System Reboot/Shutdown...
[  OK  ] Started Trigger Flushing of Journal to Persistent Storage.
[  OK  ] Started udev Coldplug all Devices.
[  OK  ] Started Update UTMP about System Reboot/Shutdown.
[  OK  ] Reached target System Initialization.
[  OK  ] Reached target Timers.
[  OK  ] Listening on D-Bus System Message Bus Socket.
[  OK  ] Reached target Sockets.
[  OK  ] Reached target Basic System.
        Starting OpenNTP Daemon...
        Starting System Logger Daemon...
[  OK  ] Started System Logger Daemon.
        Starting /etc/rc.local Compatibility...
        Starting Periodic Command Scheduler...
[  OK  ] Started Periodic Command Scheduler.
^@         Starting OpenSSH Daemon...
[  OK  ] Started OpenSSH Daemon.
        Starting Permit User Sessions...
        Starting D-Bus System Message Bus...
[  OK  ] Started D-Bus System Message Bus.
        Starting Login Service...
[  OK  ] Started Permit User Sessions.
        Starting Getty on tty1...
[  OK  ] Started Getty on tty1.
[  OK  ] Started /etc/rc.local Compatibility.
[  OK  ] Started Login Service.
[  OK  ] Found device /dev/ttyAPP0.
        Starting Serial Getty on ttyAPP0...
[  OK  ] Started Serial Getty on ttyAPP0.
[  OK  ] Found device /dev/ttyAMA0.
        Starting Serial Getty on ttyAMA0...
[  OK  ] Started Serial Getty on ttyAMA0.
[  OK  ] Reached target Login Prompts.
[  OK  ] Started OpenNTP Daemon.
[  OK  ] Reached target Multi-User System.
[  OK  ] Reached target Graphical Interface.

Arch Linux 3.9.4-dirty (ttyAMA0)

olinuxino login:

Step 4: The Application UART

To use the application UART you have to enable the following when configuring the kernel:

System Type  --->
  ARM system type (Allow multiple platforms to be selected)  --->
    (X) Freescale MXS-based
Device Drivers  --->
  Character devices  --->
    Serial drivers  --->
      <*> MXS AUART support
      [*]   MXS AUART console support

Enable a console for it on the kernel command line: console=ttyAPP0,115200 console=ttyAMA0,115200 and also start a serial tty for it:

[chris@thinkpad ~]$ sudo mount /dev/mmcblk0p2 /mnt/olinuxino/
[chris@thinkpad ~]$ sudo ln -s /usr/lib/systemd/system/serial-getty@.service /mnt/olinuxino/etc/systemd/system/getty.target.wants/serial-getty@ttyAPP0.service
[chris@thinkpad ~]$ sudo umount /mnt/olinuxino
[chris@thinkpad ~]$

It is really helpful to have the OLinuXino, I’ve removed the SD card from the development board, used the same kernel with the memory initialization for the OLinuXino and booted it there and I can confirm that the AUART works correctly. Maybe the development board uses some alternative pin mapping for AUART pins.

In linux-stable/arch/arm/boot/dts/imx23.dtsi there are 2 different pin mappings defined:

auart0_pins_a: auart0@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x01c0 /* MX23_PAD_AUART1_RX__AUART1_RX */
    0x01d0 /* MX23_PAD_AUART1_TX__AUART1_TX */
    0x01a0 /* MX23_PAD_AUART1_CTS__AUART1_CTS */
    0x01b0 /* MX23_PAD_AUART1_RTS__AUART1_RTS */
  >;
  fsl,drive-strength = <0>;
  fsl,voltage = <1>;
  fsl,pull-up = <0>;
};

auart0_2pins_a: auart0-2pins@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x01e2 /* MX23_PAD_I2C_SCL__AUART1_TX */
    0x01f2 /* MX23_PAD_I2C_SDA__AUART1_RX */
  >;
  fsl,drive-strength = <0>;
  fsl,voltage = <1>;
  fsl,pull-up = <0>;
};

From which auart0_2pins_a gets selected by default in linux-stable/arch/arm/boot/dts/imx23-olinuxino.dts:

auart0: serial@8006c000 {
  pinctrl-names = "default";
  pinctrl-0 = <&auart0_2pins_a>;
  status = "okay";
};

But using auart0_pins_a does not fix my problem.

OK, now I have the schematic. The BGA169 version of the i.MX23 has three Universal Asynchronous Receiver-Transmitters (UARTs), two high-speed application UARTs (AUART0, AUART1) operating up to 3.25 Mb/s with hardware flow control and dual DMA and one Debug UART that operates at up to 115Kb/s using programmed I/O. On this board the AUART1 is used by default.

Now we will need the i.MX23 reference manual (http://www.freescale.com/files/dsp/doc/ref_manual/IMX23RM.pdf) to add AUART1 to the device tree. We need to add the pinmux for AUART1 to linux-stable/arch/arm/boot/dts/imx23.dtsi and auart1 to linux-stable/arch/arm/boot/dts/imx23-olinuxino.dts.

If we search for 8006c000 within the i.MX23 reference manual we will find out that this is the address for auart0 and that the address for auart1 should be 8006e000. So we can already add auart1:

auart1: serial@8006e000 {
  pinctrl-names = "default";
  pinctrl-0 = <&auart1_2pins_a>;
  status = "okay";
};

Now the pinmux, adapted for auart1 but still the old pinmux-ids from auart0:

auart1_2pins_a: auart1-2pins@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x01e2 /* MX23_PAD_I2C_SCL__AUART1_TX */
    0x01f2 /* MX23_PAD_I2C_SDA__AUART1_RX */
  >;
  fsl,drive-strength = <0>;
  fsl,voltage = <1>;
  fsl,pull-up = <0>;
};

I grepped through the kernel source and searched for MX23_PAD_I2C_SCL__AUART1_TX and found it inside linux-stable/Documentation/devicetree/bindings/pinctrl/fsl,mxs-pinctrl.txt:

...
MX23_PAD_GPMI_D14__GPMI_D14     0x00e0
MX23_PAD_GPMI_D15__GPMI_D15     0x00f0
...
MX23_PAD_I2C_SCL__AUART1_TX     0x01e2
MX23_PAD_I2C_SDA__AUART1_RX     0x01f2
MX23_PAD_LCD_D08__SAIF2_SDATA0      0x1082
MX23_PAD_LCD_D09__SAIF1_SDATA0      0x1092
MX23_PAD_LCD_D10__SAIF_MCLK_BITCLK    0x10a2
MX23_PAD_LCD_D11__SAIF_LRCLK      0x10b2
...

Now I know how to get the pinmux-ids and after looking into the schematic to see what pins are used for auart1 I found GPMI_D14 / UART2_RX and GPMI_D15 / UART2_TX / GPMI_CE3n which results in MX23_PAD_GPMI_D14__GPMI_D14 and MX23_PAD_GPMI_D15__GPMI_D15 for the pinmux-ids:

auart1_2pins_a: auart1-2pins@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x00e0 /* MX23_PAD_GPMI_D14__GPMI_D14 */
    0x00f0 /* MX23_PAD_GPMI_D15__GPMI_D15 */
  >;
  fsl,drive-strength = <0>;
  fsl,voltage = <1>;
  fsl,pull-up = <0>;
};

You have to be a bit careful with the numbers, because Freescale starts to count from 1 to name the UARTs and the kernel developers start from 0.

Now I can recreate the device tree blob .dtb file, join the zImage and imx23-olinuxino.dtb into the zImage_dtb file and recreate the bootlets:

[chris@thinkpad linux-stable]$ make ARCH=arm CROSS_COMPILE=arm-none-eabi- imx23-olinuxino.dtb
  CC      scripts/mod/devicetable-offsets.s
  GEN     scripts/mod/devicetable-offsets.h
  HOSTCC  scripts/mod/file2alias.o
  HOSTLD  scripts/mod/modpost
  DTC     arch/arm/boot/dts/imx23-olinuxino.dtb
[chris@thinkpad linux-stable]$ cat arch/arm/boot/zImage arch/arm/boot/dts/imx23-olinuxino.dtb > arch/arm/boot/zImage_dtb
[chris@thinkpad linux-stable]$ cd ../../boot/imx-bootlets-src-10.05.02/
[chris@thinkpad imx-bootlets-src-10.05.02]$ vim linux_prep/cmdlines/imx23_olinuxino_dev.txt
[chris@thinkpad imx-bootlets-src-10.05.02]$ cat linux_prep/cmdlines/imx23_olinuxino_dev.txt
noinitrd console=ttyAPP1,115200 console=ttyAMA0,115200 root=/dev/mmcblk0p2 rw rootwait ssp1=mmc verbose debug
noinitrd console=ttyAPP1,115200 console=ttyAMA0,115200 root=/dev/mmcblk0p2 rw rootwait ssp1=mmc verbose debug
noinitrd console=ttyAPP1,115200 console=ttyAMA0,115200 root=/dev/mmcblk0p2 rw rootwait ssp1=mmc verbose debug
[chris@thinkpad imx-bootlets-src-10.05.02]$ make CROSS_COMPILE=arm-none-eabi- clean
[chris@thinkpad imx-bootlets-src-10.05.02]$ make CROSS_COMPILE=arm-none-eabi-
[chris@thinkpad imx-bootlets-src-10.05.02]$ sudo dd if=sd_mmc_bootstream.raw of=/dev/mmcblk0p1
8434+0 records in
8434+0 records out
4318208 bytes (4.3 MB) copied, 1.67169 s, 2.6 MB/s
[chris@thinkpad imx-bootlets-src-10.05.02]$

Enable a serial tty for it:

[chris@thinkpad ~]$ sudo mount /dev/mmcblk0p2 /mnt/olinuxino/
[chris@thinkpad ~]$ sudo ln -s /usr/lib/systemd/system/serial-getty@.service /mnt/olinuxino/etc/systemd/system/getty.target.wants/serial-getty@ttyAPP1.service
[chris@thinkpad ~]$ ls -l /mnt/olinuxino/etc/systemd/system/getty.target.wants/serial-getty@ttyAPP1.service
lrwxrwxrwx. 1 root root 45 Sep  4 17:36 /mnt/olinuxino/etc/systemd/system/getty.target.wants/serial-getty@ttyAPP1.service -> /usr/lib/systemd/system/serial-getty@.service
[chris@thinkpad ~]$ sudo umount /mnt/olinuxino
[chris@thinkpad ~]$

And change the kernel command line to console=ttyAMA0,115200 console=ttyAPP1,115200.

Now boot the new kernel:

...
[    1.240000] uart-pl011 80070000.serial: no DMA platform data
[    1.250000] 8006c000.serial: ttyAPP0 at MMIO 0x8006c000 (irq = 126) is a 8006c000.serial
[    1.260000] mxs-auart 8006c000.serial: Found APPUART 3.0.0
[    1.260000] 8006e000.serial: ttyAPP1 at MMIO 0x8006e000 (irq = 129) is a 8006e000.serial
[    1.870000] console [ttyAPP1] enabled
[    1.880000] mxs-auart 8006e000.serial: Found APPUART 3.0.0
...
[  OK  ] Started /etc/rc.local Compatibility.
[  OK  ] Started Login Service.
[  OK  ] Found device /dev/ttyAMA0.
         Starting Serial Getty on ttyAMA0...
[  OK  ] Started Serial Getty on ttyAMA0.
[  OK  ] Found device /dev/ttyAPP1.
         Starting Serial Getty on ttyAPP1...
[  OK  ] Started Serial Getty on ttyAPP1.
[  OK  ] Found device /dev/ttyAPP0.
         Starting Serial Getty on ttyAPP0...
[  OK  ] Started Serial Getty on ttyAPP0.
[  OK  ] Reached target Login Prompts.

Arch Linux 3.9.4-dirty (ttyAMA0)

olinuxino login:

But still no output on the application UART? Why? :-(

To define the problem a bit better:

  • The first application UART is working on the OLinuXino but not on this board, so the rootfs should be working correctly.
  • I have a SD card image that outputs something on the second AUART on this board, so the hardware is also working.
  • Is there something wrong with my device tree?

I get no errors or crashs, so it is not so easy to debug. Maybe I could search for a serial receive interrupt, set a breakpoint there an see whether it gets triggered? Or a UART send register empty flag and if it is not empty search the reason for it.

OK, I’ve modified the minimal example to output something on the AUART, now I can compare it with the initialisation within the kernel:

int main(void)
{

    // Make LED a GPIO
    HW_PINCTRL_MUXSEL3_SET(0x00000C00); // For LED at LCD_CS

    // Set output power to 4mA
    HW_PINCTRL_DRIVE6_CLR(0x00200000);

    // Enable output
    HW_PINCTRL_DOE1_SET(0x00200000);

    uart_init();

    uart_send("Hello World!\r\n", 14);

    while(1)
    {
        led_off();
        delay_us(900000);
        led_on();
        delay_us(900000);
        uart_send("ping!\r\n", 7);
    }

    return 0;
}

The output on the terminal:

Hello World!
ping!
ping!
ping!
ping!
...

And a part of the UART initialisation:

// These pins for UART2 (default):
HW_PINCTRL_MUXSEL0_CLR((unsigned)3<<30);
HW_PINCTRL_MUXSEL0_SET((unsigned)1<<30);  // GPMI_D15 pin select auart2_tx
HW_PINCTRL_MUXSEL0_CLR((unsigned)3<<28);
HW_PINCTRL_MUXSEL0_SET((unsigned)1<<28);  // GPMI_D14 pin select auart2_rx

So these are the same pins like specified by in the devicetree, why does it not work?

Now what does HW_PINCTRL_MUXSEL0_CLR and HW_PINCTRL_MUXSEL0_SET do and how does it map to the kernel initialisation and the device tree?

If we have a look inside regspinctrl.h and platform.h from Freescale we will find the following macros:

#define REGS_BASE 0x80000000

#ifndef REGS_PINCTRL_BASE
#define REGS_PINCTRL_BASE (REGS_BASE + 0x00018000)
#endif

#define HW_PINCTRL_MUXSEL0_SET_ADDR  (REGS_PINCTRL_BASE + 0x00000104)
#define HW_PINCTRL_MUXSEL0_SET(v)    ((*(volatile reg32_t *) HW_PINCTRL_MUXSEL0_SET_ADDR) = (v))

So if I’m correct then HW_PINCTRL_MUXSEL0_SET((unsigned)1<<30); writes 0x40000000 to 0x80018104, but still how does this fit with the “fsl,pinmux-ids” like 0x00f0 /* MX23_PAD_GPMI_D15__GPMI_D15 */?

Now have a look into:

  • linux-stable/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
  • linux-stable/Documentation/devicetree/bindings/pinctrl/fsl,mxs-pinctrl.txt
  • linux-stable/drivers/tty/serial/mxs-auart.c
  • linux-stable/Documentation/devicetree/bindings/tty/serial/fsl-mxs-auart.txt

Now I will try it again with the latest kernel. To show the differences for some important files:

[chris@thinkpad linux-stable]$ git diff v3.9.4 v3.10.11 arch/arm/boot/dts/imx23.dtsi
...
[chris@thinkpad linux-stable]$ git diff v3.9.4 v3.10.11 arch/arm/boot/dts/imx23-olinuxino.dts
...
[chris@thinkpad linux-stable]$ git diff v3.9.4 v3.10.11 drivers/tty/serial/mxs-auart.c
...
[chris@thinkpad linux-stable]$

Git is really a useful tool.

There where some changes to the application UARTs maybe it solves my problems.

OK. Same problems with 3.11: imx23.dtsi, imx23-olinuxino.dts, 3.11.diff

Lets try linux-next:

[chris@thinkpad linux-stable]$ git diff > 3.11.diff
[chris@thinkpad linux-stable]$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
        arch/arm/boot/dts/imx23-olinuxino.dts
        arch/arm/boot/dts/imx23.dtsi
Please, commit your changes or stash them before you can switch branches.
Aborting
[chris@thinkpad linux-stable]$ git clean -fd
Removing arch/arm/boot/zImage_dtb
Removing dotconfig
[chris@thinkpad linux-stable]$ git reset --hard HEAD
HEAD is now at 85cdabb Linux 3.10.11
[chris@thinkpad linux-stable]$ git checkout master
Checking out files: 100% (12892/12892), done.
Previous HEAD position was 85cdabb... Linux 3.10.11
Switched to branch 'master'
[chris@thinkpad linux-stable]$ git pull
Already up-to-date.
[chris@thinkpad linux-stable]$ git remote add linux-next git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
[chris@thinkpad linux-stable]$ git fetch linux-next
remote: Counting objects: 18516, done.
remote: Compressing objects: 100% (4261/4261), done.
remote: Total 14740 (delta 12334), reused 12765 (delta 10417)
Receiving objects: 100% (14740/14740), 3.22 MiB | 763.00 KiB/s, done.
Resolving deltas: 100% (12334/12334), completed with 2294 local objects.
From git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next
* [new branch]      akpm       -> linux-next/akpm
* [new branch]      akpm-base  -> linux-next/akpm-base
* [new branch]      master     -> linux-next/master
* [new branch]      stable     -> linux-next/stable
* [new tag]         next-20130910 -> next-20130910
[chris@thinkpad linux-stable]$ git fetch --tags linux-next
remote: Counting objects: 150029, done.
remote: Compressing objects: 100% (23505/23505), done.
remote: Total 143122 (delta 127788), reused 133639 (delta 119332)
Receiving objects: 100% (143122/143122), 19.07 MiB | 840.00 KiB/s, done.
Resolving deltas: 100% (127788/127788), completed with 3348 local objects.
From git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next
* [new tag]         next-20130617 -> next-20130617
* [new tag]         next-20130618 -> next-20130618
* [new tag]         next-20130619 -> next-20130619
...
* [new tag]         next-20130904 -> next-20130904
* [new tag]         next-20130905 -> next-20130905
* [new tag]         next-20130906 -> next-20130906
* [new tag]         next-20130909 -> next-20130909
[chris@thinkpad linux-stable]$ git remote update
Fetching origin
Fetching linux-next
[chris@thinkpad linux-stable]$ git checkout -b my_working_branch next-20130910
Switched to a new branch 'my_working_branch'
[chris@thinkpad linux-stable]$ git-cola
[chris@thinkpad linux-stable]$ git diff v3.10.11 next-20130910 drivers/tty/serial/mxs-auart.c
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index f85b8e6..10e9d70 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -32,7 +32,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/of_device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
@@ -134,10 +133,10 @@ enum mxs_auart_type {
struct mxs_auart_port {
        struct uart_port port;

-#define MXS_AUART_DMA_CONFIG   0x1
#define MXS_AUART_DMA_ENABLED  0x2
#define MXS_AUART_DMA_TX_SYNC  2  /* bit 2 */
#define MXS_AUART_DMA_RX_READY 3  /* bit 3 */
+#define MXS_AUART_RTSCTS       4  /* bit 4 */
        unsigned long flags;
        unsigned int ctrl;
        enum mxs_auart_type devtype;
@@ -640,7 +639,8 @@ static void mxs_auart_settermios(struct uart_port *u,
                * we can only implement the DMA support for auart
                * in mx28.
                */
-               if (is_imx28_auart(s) && (s->flags & MXS_AUART_DMA_CONFIG)) {
+               if (is_imx28_auart(s)
+                               && test_bit(MXS_AUART_RTSCTS, &s->flags)) {
                        if (!mxs_auart_dma_init(s))
                                /* enable DMA tranfer */
                                ctrl2 |= AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE
@@ -1008,7 +1008,8 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
        }
        s->port.line = ret;

-       s->flags |= MXS_AUART_DMA_CONFIG;
+       if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
+               set_bit(MXS_AUART_RTSCTS, &s->flags);

        return 0;
}
@@ -1021,7 +1022,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
        u32 version;
        int ret = 0;
        struct resource *r;
-       struct pinctrl *pinctrl;

        s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
        if (!s) {
@@ -1035,12 +1035,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
        else if (ret < 0)
                goto out_free;

-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               ret = PTR_ERR(pinctrl);
-               goto out_free;
-       }
-
        if (of_id) {
                pdev->id_entry = of_id->data;
                s->devtype = pdev->id_entry->driver_data;
[chris@thinkpad linux-stable]$

Now apply the patches again, and rebuild the kernel.

OK. Same problems with next-20130910: imx23.dtsi, imx23-olinuxino.dts, next-20130910.diff

Maybe there is a bug: “The current mxs-auart driver is used for both mx23 and mx28. But in mx23, the DMA has a bug(see errata:2836). We can not add the DMA support in mx23, but we can add DMA support to auart in mx28.http://article.gmane.org/gmane.linux.serial/9184/

I’ve asked on linux-serial: http://thread.gmane.org/gmane.linux.serial/12556

Now attach the debugger to the kernel and set breakpoint on all functions in drivers/tty/serial/mxs-auart.c to see what happens:

[chris@thinkpad linux-stable]$ arm-none-eabi-gdb vmlinux
GNU gdb (GNU Tools for ARM Embedded Processors) 7.4.1.20130312-cvs
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-linux-gnu --target=arm-none-eabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/chris/local/OLinuXino/imx23-olinuxino/kernel/linux-stable/vmlinux...done.
(gdb) target remote :3333
Remote debugging using :3333
?? () at arch/arm/kernel/entry-armv.S:1132
1132            W(b)    vector_rst
(gdb) c
Continuing.
WARNING! The target is already running. All changes GDB did to registers will be discarded! Waiting for target to halt.
^C
Program received signal SIGINT, Interrupt.
0xc0814728 in start_kernel () at init/main.c:480
480       while(wait_for_debugger);
(gdb) rbreak ^mxs_auart_.*
Breakpoint 1 at 0xc02d6d04: file drivers/tty/serial/mxs-auart.c, line 800.
static void mxs_auart_break_ctl(struct uart_port *, int);
Breakpoint 2 at 0xc02d6c50: file drivers/tty/serial/mxs-auart.c, line 388.
static void mxs_auart_config_port(struct uart_port *, int);
Breakpoint 3 at 0xc02d6d28: file drivers/tty/serial/mxs-auart.c, line 836.
static void mxs_auart_console_putchar(struct uart_port *, int);
Breakpoint 4 at 0xc02d6f88: file drivers/tty/serial/mxs-auart.c, line 515.
static void mxs_auart_dma_exit(struct mxs_auart_port *);
Breakpoint 5 at 0xc02d6f30: file drivers/tty/serial/mxs-auart.c, line 498.
static void mxs_auart_dma_exit_channel(struct mxs_auart_port *);
Breakpoint 6 at 0xc02d703c: file drivers/tty/serial/mxs-auart.c, line 462.
static int mxs_auart_dma_prep_rx(struct mxs_auart_port *);
Breakpoint 7 at 0xc02d6d24: file drivers/tty/serial/mxs-auart.c, line 809.
static void mxs_auart_enable_ms(struct uart_port *);
Breakpoint 8 at 0xc0851b18: file drivers/tty/serial/mxs-auart.c, line 1145.
static void mxs_auart_exit(void);
Breakpoint 9 at 0xc02d6ca4: file drivers/tty/serial/mxs-auart.c, line 423.
static u32 mxs_auart_get_mctrl(struct uart_port *);
Breakpoint 10 at 0xc0834af0: file drivers/tty/serial/mxs-auart.c, line 1126.
static int mxs_auart_init(void);
Breakpoint 11 at 0xc02d7b9c: file drivers/tty/serial/mxs-auart.c, line 680.
static irqreturn_t mxs_auart_irq_handle(int, void *);
Breakpoint 12 at 0xc02d78e8: file drivers/tty/serial/mxs-auart.c, line 1018.
static int mxs_auart_probe(struct platform_device *);
Breakpoint 13 at 0xc02d6c68: file drivers/tty/serial/mxs-auart.c, line 399.
static void mxs_auart_release_port(struct uart_port *);
Breakpoint 14 at 0xc02d6ed4: file drivers/tty/serial/mxs-auart.c, line 1101.
static int mxs_auart_remove(struct platform_device *);
Breakpoint 15 at 0xc02d6c30: file drivers/tty/serial/mxs-auart.c, line 377.
static int mxs_auart_request_port(struct uart_port *);
Breakpoint 16 at 0xc02d6c6c: file drivers/tty/serial/mxs-auart.c, line 406.
static void mxs_auart_set_mctrl(struct uart_port *, unsigned int);
Breakpoint 17 at 0xc02d7630: file drivers/tty/serial/mxs-auart.c, line 562.
static void mxs_auart_settermios(struct uart_port *, struct ktermios *, struct ktermios *);
Breakpoint 18 at 0xc02d6fe8: file drivers/tty/serial/mxs-auart.c, line 754.
static void mxs_auart_shutdown(struct uart_port *);
Breakpoint 19 at 0xc02d7578: file drivers/tty/serial/mxs-auart.c, line 783.
static void mxs_auart_start_tx(struct uart_port *);
Breakpoint 20 at 0xc02d6d88: file drivers/tty/serial/mxs-auart.c, line 732.
static int mxs_auart_startup(struct uart_port *);
Breakpoint 21 at 0xc02d6cf4: file drivers/tty/serial/mxs-auart.c, line 795.
static void mxs_auart_stop_rx(struct uart_port *);
Breakpoint 22 at 0xc02d6ce4: file drivers/tty/serial/mxs-auart.c, line 790.
static void mxs_auart_stop_tx(struct uart_port *);
---Type <return> to continue, or q <return> to quit---
Breakpoint 23 at 0xc02d7220: file drivers/tty/serial/mxs-auart.c, line 246.
static void mxs_auart_tx_chars(struct mxs_auart_port *);
Breakpoint 24 at 0xc02d6cd0: file drivers/tty/serial/mxs-auart.c, line 772.
static unsigned int mxs_auart_tx_empty(struct uart_port *);
Breakpoint 25 at 0xc02d6c54: file drivers/tty/serial/mxs-auart.c, line 395.
static const char *mxs_auart_type(struct uart_port *);
Breakpoint 26 at 0xc02d6c38: file drivers/tty/serial/mxs-auart.c, line 382.
static int mxs_auart_verify_port(struct uart_port *, struct serial_struct *);
(gdb) set var wait_for_debugger=0
(gdb) c
Continuing.

Breakpoint 10, mxs_auart_init () at drivers/tty/serial/mxs-auart.c:1126
1126    {
(gdb)

Now we’ve hit a breakpoint and booting has stopped:

[    1.160000] msgmni has been set to 98
[    1.190000] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 249)
[    1.200000] io scheduler noop registered (default)
[    1.210000] of_dma_request_slave_channel: dma-names property of node '/apb@80000000/apbx@80040000/serial@80070000' missing or empty
[    1.220000] uart-pl011 80070000.serial: no DMA platform data

That I’ve overseen the dma-names property of node '/apb@80000000/apbx@80040000/serial@80070000' missing or empty error before, shame on me. OK 80070000 is the address of the debug uart duart: serial@80070000 so this is probably not the problem.

Now see what happens next:

(gdb) list
1121                    .of_match_table = mxs_auart_dt_ids,
1122            },
1123    };
1124
1125    static int __init mxs_auart_init(void)
1126    {
1127            int r;
1128
1129            r = uart_register_driver(&auart_driver);
1130            if (r)
(gdb) n
1129            r = uart_register_driver(&auart_driver);
(gdb) n
1130            if (r)
(gdb) n
1133            r = platform_driver_register(&mxs_auart_driver);
(gdb) n

Breakpoint 12, mxs_auart_probe (pdev=0xc38c9c00) at drivers/tty/serial/mxs-auart.c:1018
1018    {
(gdb) n
1020                            of_match_device(mxs_auart_dt_ids, &pdev->dev);
(gdb) n
1018    {
(gdb) list
1013
1014            return 0;
1015    }
1016
1017    static int mxs_auart_probe(struct platform_device *pdev)
1018    {
1019            const struct of_device_id *of_id =
1020                            of_match_device(mxs_auart_dt_ids, &pdev->dev);
1021            struct mxs_auart_port *s;
1022            u32 version;
(gdb) c
Continuing.

Breakpoint 25, mxs_auart_type (u=0xc3a27600) at drivers/tty/serial/mxs-auart.c:395
395             return dev_name(s->dev);
(gdb) c
Continuing.

Breakpoint 16, mxs_auart_set_mctrl (u=0xc3a27600, mctrl=0) at drivers/tty/serial/mxs-auart.c:406
406             u32 ctrl = readl(u->membase + AUART_CTRL2);
(gdb) c
Continuing.

Breakpoint 12, mxs_auart_probe (pdev=0xc38c9e00) at drivers/tty/serial/mxs-auart.c:1018
1018    {
(gdb) c
Continuing.

Breakpoint 25, mxs_auart_type (u=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:395
395             return dev_name(s->dev);
(gdb) c
Continuing.

Breakpoint 16, mxs_auart_set_mctrl (u=0xc3a27a00, mctrl=0) at drivers/tty/serial/mxs-auart.c:406
406             u32 ctrl = readl(u->membase + AUART_CTRL2);
(gdb) c
Continuing.

Breakpoint 17, mxs_auart_settermios (u=0xc3a27a00, termios=0xc3841d1c, old=0xc0e055e0) at drivers/tty/serial/mxs-auart.c:562
562     {
(gdb) c
Continuing.

Breakpoint 3, mxs_auart_console_putchar (port=0xc3a27a00, ch=91) at drivers/tty/serial/mxs-auart.c:836
836     {
(gdb) c
Continuing.

Breakpoint 3, mxs_auart_console_putchar (port=0xc3a27a00, ch=32) at drivers/tty/serial/mxs-auart.c:836
836     {
(gdb) c
Continuing.

Breakpoint 3, mxs_auart_console_putchar (port=0xc3a27a00, ch=32) at drivers/tty/serial/mxs-auart.c:836
836     {
(gdb) delete breakpoints 3
(gdb) c
Continuing.

Breakpoint 20, mxs_auart_startup (u=0xc3a27600) at drivers/tty/serial/mxs-auart.c:732
732     {
(gdb) c
Continuing.

Breakpoint 17, mxs_auart_settermios (u=0xc3a27600, termios=0xc3bc0de0, old=0x0) at drivers/tty/serial/mxs-auart.c:562
562     {
(gdb) c
Continuing.

Breakpoint 16, mxs_auart_set_mctrl (u=0xc3a27600, mctrl=6) at drivers/tty/serial/mxs-auart.c:406
406             u32 ctrl = readl(u->membase + AUART_CTRL2);
(gdb) c
Continuing.

Breakpoint 20, mxs_auart_startup (u=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:732
732     {
(gdb) c
Continuing.

Breakpoint 11, mxs_auart_irq_handle (irq=146, context=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:680
680     {
(gdb) c
Continuing.

Breakpoint 11, mxs_auart_irq_handle (irq=146, context=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:680
680     {
(gdb) c
Continuing.

Breakpoint 11, mxs_auart_irq_handle (irq=146, context=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:680
680     {
(gdb) c
Continuing.

Breakpoint 11, mxs_auart_irq_handle (irq=146, context=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:680
680     {
(gdb) c
Continuing.

Breakpoint 11, mxs_auart_irq_handle (irq=146, context=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:680
680     {
(gdb) c
Continuing.

Breakpoint 11, mxs_auart_irq_handle (irq=146, context=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:680
680     {
(gdb) delete breakpoints 11
(gdb) c
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
mxs_auart_irq_handle (irq=146, context=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:680
680     {
(gdb) c
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
mxs_auart_irq_handle (irq=146, context=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:680
680     {
(gdb)
[    5.770000] 8006c000.serial: ttyAPP0 at MMIO 0x8006c000 (irq = 145, base_baud = 1500000) is a 8006c000.serial
[    7.690000] mxs-auart 8006c000.serial: Found APPUART 3.0.0
[    9.530000] 8006e000.serial: ttyAPP1 at MMIO 0x8006e000 (irq = 146, base_baud = 1500000) is a 8006e000.serial
[   12.020000] console [ttyAPP1] enabled
[   12.020000] mxs-auart 8006e000.serial: Found APPUART 3.0.0
...

Maybe something gets received, the function mxs_auart_rx_chars should only be executed if data is available:

[chris@thinkpad linux-stable]$ arm-none-eabi-gdb vmlinux
GNU gdb (GNU Tools for ARM Embedded Processors) 7.4.1.20130312-cvs
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-linux-gnu --target=arm-none-eabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/chris/local/OLinuXino/imx23-olinuxino/kernel/linux-stable/vmlinux...done.
(gdb) c
The program is not being run.
(gdb) target remote :3333
Remote debugging using :3333
?? () at arch/arm/kernel/entry-armv.S:1132
1132            W(b)    vector_rst
(gdb) c
Continuing.
WARNING! The target is already running. All changes GDB did to registers will be discarded! Waiting for target to halt.
^C
Program received signal SIGINT, Interrupt.
0xc0814728 in start_kernel () at init/main.c:480
480       while(wait_for_debugger);
(gdb) break mxs_auart_rx_char
Function "mxs_auart_rx_char" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) break drivers/tty/serial/mxs-auart.c:mxs_auart_rx_char
Function "mxs_auart_rx_char" not defined in "drivers/tty/serial/mxs-auart.c".
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) break drivers/tty/serial/mxs-auart.c:703
Breakpoint 1 at 0xc02d7be0: file drivers/tty/serial/mxs-auart.c, line 703.
(gdb) set var wait_for_debugger=0
(gdb) c
Continuing.

Breakpoint 1, mxs_auart_irq_handle (irq=<optimized out>, context=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:704
704                     istat &= ~(AUART_INTR_RTIS | AUART_INTR_RXIS);
(gdb) s
707             if (istat & AUART_INTR_TXIS) {
(gdb) s
708                     mxs_auart_tx_chars(s);
(gdb) s
mxs_auart_tx_chars (s=s@entry=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:249
249             if (auart_dma_enabled(s)) {
(gdb) s
auart_dma_enabled (s=<optimized out>) at drivers/tty/serial/mxs-auart.c:184
184             return s->flags & MXS_AUART_DMA_ENABLED;
(gdb) s
mxs_auart_tx_chars (s=s@entry=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:246
246     {
(gdb) delete breakpoints 1
(gdb) break drivers/tty/serial/mxs-auart.c:320
Breakpoint 2 at 0xc02d7c4c: file drivers/tty/serial/mxs-auart.c, line 320.
(gdb) c
Continuing.

Breakpoint 2, mxs_auart_rx_chars (s=<optimized out>) at drivers/tty/serial/mxs-auart.c:367
367                     mxs_auart_rx_char(s);
(gdb) delete breakpoints
Delete all breakpoints? (y or n) y
(gdb) break drivers/tty/serial/mxs-auart.c:321
Breakpoint 3 at 0xc02d7c54: file drivers/tty/serial/mxs-auart.c, line 321.
(gdb) c
Continuing.

Breakpoint 3, mxs_auart_rx_char (s=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:321
321             stat = readl(s->port.membase + AUART_STAT);
(gdb) list
316             int flag;
317             u32 stat;
318             u8 c;
319
320             c = readl(s->port.membase + AUART_DATA);
321             stat = readl(s->port.membase + AUART_STAT);
322
323             flag = TTY_NORMAL;
324             s->port.icount.rx++;
325
(gdb) p c
$3 = 72 'H'
(gdb) c
Continuing.

Breakpoint 3, mxs_auart_rx_char (s=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:321
321             stat = readl(s->port.membase + AUART_STAT);
(gdb) p c
$4 = 101 'e'
(gdb) c
Continuing.

Breakpoint 3, mxs_auart_rx_char (s=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:321
321             stat = readl(s->port.membase + AUART_STAT);
(gdb) p c
$5 = 108 'l'
(gdb) c
Continuing.

Breakpoint 3, mxs_auart_rx_char (s=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:321
321             stat = readl(s->port.membase + AUART_STAT);
(gdb) p c
$6 = 108 'l'
(gdb) c
Continuing.

Breakpoint 3, mxs_auart_rx_char (s=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:321
321             stat = readl(s->port.membase + AUART_STAT);
(gdb) p c
$7 = 111 'o'
(gdb)

OK, receiving works, above you can see that I’ve received “Hello” one char at a time.

But on the serial terminal nothing gets printed, so sending must be broken.

All my sent characters and the Arch Linux login prompt (\r\r\nArch Linux 3.11.0-next-20130910-dirty (ttyAPP1)\r\n\r\nolinuxino login: ddHHe[AHelloWW) are in the tx buffer:

(gdb) delete breakpoints
Delete all breakpoints? (y or n) y
(gdb) break drivers/tty/serial/mxs-auart.c:285
Breakpoint 5 at 0xc02d7308: file drivers/tty/serial/mxs-auart.c, line 285.
(gdb) c
Continuing.

Breakpoint 5, mxs_auart_tx_chars (s=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:285
285                     if (s->port.x_char) {
(gdb) p s->port.x_char
$8 = 0 '\000'
(gdb) list
280             }
281
282
283             while (!(readl(s->port.membase + AUART_STAT) &
284                      AUART_STAT_TXFF)) {
285                     if (s->port.x_char) {
286                             s->port.icount.tx++;
287                             writel(s->port.x_char,
288                                          s->port.membase + AUART_DATA);
289                             s->port.x_char = 0;
(gdb) break drivers/tty/serial/mxs-auart.c:294
Breakpoint 6 at 0xc02d72c8: file drivers/tty/serial/mxs-auart.c, line 294.
(gdb) n
292                     if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
(gdb) n
293                             s->port.icount.tx++;
(gdb) n

Breakpoint 6, mxs_auart_tx_chars (s=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:294
294                             writel(xmit->buf[xmit->tail],
(gdb) p xmit->buf[xmit->tail]
$10 = 87 'W'
(gdb) p xmit->buf
$9 = 0xc29cb000 "\r\r\nArch Linux 3.11.0-next-20130910-dirty (ttyAPP1)\r\n\r\nolinuxino login: ddHHe[AHelloWW"
(gdb)

But I don’t receive them:

(gdb) list
289                             s->port.x_char = 0;
290                             continue;
291                     }
292                     if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
293                             s->port.icount.tx++;
294                             writel(xmit->buf[xmit->tail],
295                                          s->port.membase + AUART_DATA);
296                             xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
297                     } else
298                             break;
(gdb) n
293                             s->port.icount.tx++;
(gdb) n
294                             writel(xmit->buf[xmit->tail],
(gdb) n
296                             xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
(gdb) n
283             while (!(readl(s->port.membase + AUART_STAT) &
(gdb) n

Breakpoint 5, mxs_auart_tx_chars (s=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:285
285                     if (s->port.x_char) {
(gdb) n
292                     if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
(gdb) n
301                     uart_write_wakeup(&s->port);
(gdb) n
303             if (uart_circ_empty(&(s->port.state->xmit)))
(gdb) n
304                     writel(AUART_INTR_TXIEN,
(gdb) n
303             if (uart_circ_empty(&(s->port.state->xmit)))
(gdb) n
304                     writel(AUART_INTR_TXIEN,
(gdb) n
310             if (uart_tx_stopped(&s->port))
(gdb) n
312     }
(gdb) n
uart_start (tty=tty@entry=0xc3b90000) at drivers/tty/serial/serial_core.c:105
105             spin_unlock_irqrestore(&port->lock, flags);
(gdb) c
Continuing.
arm-none-eabi-gdbtui --eval-command="target remote localhost:3333" vmlinux

arm-none-eabi-gdbtui --eval-command="target remote localhost:3333" vmlinux

ddd --eval-command="target remote localhost:3333" --debugger arm-none-eabi-gdb  vmlinux

ddd --eval-command="target remote localhost:3333" --debugger arm-none-eabi-gdb  vmlinux

nemiver --remote=localhost:3333 --gdb-binary="$(which arm-none-eabi-gdb)" vmlinux

nemiver --remote=localhost:3333 --gdb-binary="$(which arm-none-eabi-gdb)" vmlinux

The most interesting function in drivers/tty/serial/mxs-auart.c is mxs_auart_tx_chars():

static void mxs_auart_tx_chars(struct mxs_auart_port *s)
{
  struct circ_buf *xmit = &s->port.state->xmit;

  if (auart_dma_enabled(s)) {
    u32 i = 0;
    int size;
    void *buffer = s->tx_dma_buf;

    if (test_and_set_bit(MXS_AUART_DMA_TX_SYNC, &s->flags))
      return;

    while (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
      size = min_t(u32, UART_XMIT_SIZE - i,
            CIRC_CNT_TO_END(xmit->head,
                xmit->tail,
                UART_XMIT_SIZE));
      memcpy(buffer + i, xmit->buf + xmit->tail, size);
      xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1);

      i += size;
      if (i >= UART_XMIT_SIZE)
        break;
    }

    if (uart_tx_stopped(&s->port))
      mxs_auart_stop_tx(&s->port);

    if (i) {
      mxs_auart_dma_tx(s, i);
    } else {
      clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags);
      smp_mb__after_clear_bit();
    }
    return;
  }


  while (!(readl(s->port.membase + AUART_STAT) &
    AUART_STAT_TXFF)) {
    if (s->port.x_char) {
      s->port.icount.tx++;
      writel(s->port.x_char,
            s->port.membase + AUART_DATA);
      s->port.x_char = 0;
      continue;
    }
    if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
      s->port.icount.tx++;
      writel(xmit->buf[xmit->tail],
            s->port.membase + AUART_DATA);
      xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
    } else
      break;
  }
  if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
    uart_write_wakeup(&s->port);

  if (uart_circ_empty(&(s->port.state->xmit)))
    writel(AUART_INTR_TXIEN,
          s->port.membase + AUART_INTR_CLR);
  else
    writel(AUART_INTR_TXIEN,
          s->port.membase + AUART_INTR_SET);

  if (uart_tx_stopped(&s->port))
    mxs_auart_stop_tx(&s->port);
}

Normally a new character becomes visible on the terminal after writel(xmit->buf[xmit->tail], s->port.membase + AUART_DATA); has been executed, I’ve tested this on my OLinuXino with auart0. On the Audio Development Board when using auart1 this function gets executed too, but there is no output on the terminal, so the problem must be somewhere inside writel(xmit->buf[xmit->tail], s->port.membase + AUART_DATA);. Maybe the address where it gets written to is wrong.

Working function call on OLinuXino and auart0 (printing “L”):

(gdb) print xmit->buf[xmit->tail]
$4 = 76 'L'
(gdb) print s->port.membase
$5 = (unsigned char *) 0xc48d0000 ""
(gdb) print s->port
$6 = {lock = {{rlock = {raw_lock = {slock = 0}, magic = 3735899821, owner_cpu = 0, owner = 0xc3bb2b20, dep_map = {key = 0xc0e055d8, class_cache = {0xc098bc84, 0x0}, name = 0xc076a0e4 "&port_lock_key"}}, {__padding = "\000\000\000\000\255N\255\336\000\000\000\000 +\273", <incomplete sequence \303>, dep_map = {key = 0xc0e055d8, class_cache = {0xc098bc84, 0x0}, name = 0xc076a0e4 "&port_lock_key"}}}}, iobase = 0, membase = 0xc48d0000 "", serial_in = 0, serial_out = 0, set_termios = 0, handle_irq = 0, pm = 0, handle_break = 0, irq = 145, irqflags = 0, uartclk = 24000000, fifosize = 16, x_char = 0 '\000', regshift = 0 '\000',
iotype = 2 '\002', unused1 = 0 '\000', read_status_mask = 0, ignore_status_mask = 0, state = 0xc381c000, icount = {cts = 0, dsr = 0, rng = 0, dcd = 0, rx = 0, tx = 8, frame = 0, overrun = 0, parity = 0, brk = 0, buf_overrun = 0}, cons = 0xc0888bdc, sysrq = 0, flags = 0, mctrl = 6, timeout = 2, type = 62, ops = 0xc0888b70, custom_divisor = 0, line = 0, mapbase = 2147926016, dev = 0xc38c9c10, hub6 = 0 '\000', suspended = 0 '\000', irq_wake = 0 '\000', unused = "\000", private_data = 0x0}
(gdb)

Not working function call on the Audio Development Board:

(gdb) c

Breakpoint 1, mxs_auart_tx_chars (s=0xc3a27a00) at drivers/tty/serial/mxs-auart.c:294
(gdb) list
289       s->port.x_char = 0;
290       continue;
291     }
292     if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
293       s->port.icount.tx++;
294       writel(xmit->buf[xmit->tail],
295              s->port.membase + AUART_DATA);
296       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
297     } else
298       break;
(gdb)
(gdb) print xmit->buf[xmit->tail]
$2 = 76 'L'
(gdb) print s->port.membase
$3 = (unsigned char *) 0xc48d4000 ""
(gdb) print s->port
$4 = {lock = {{rlock = {raw_lock = {slock = 0}, magic = 3735899821, owner_cpu = 0, owner = 0xc3ad4500, dep_map = {key = 0xc0e055d8, class_cache = {0xc098bc84, 0x0}, name = 0xc076a0e4 "&port_lock_key"}}, {__padding = "\000\000\000\000\255N\255\336\000\000\000\000\000E\255", <incomplete sequence \303>, dep_map = {key = 0xc0e055d8, class_cache = {0xc098bc84, 0x0}, name = 0xc076a0e4 "&port_lock_key"}}}}, iobase = 0, membase = 0xc48d4000 "", serial_in = 0, serial_out = 0, set_termios = 0, handle_irq = 0, pm = 0, handle_break = 0, irq = 146, irqflags = 0, uartclk = 24000000, fifosize = 16, x_char = 0 '\000', regshift = 0 '\000',
iotype = 2 '\002', unused1 = 0 '\000', read_status_mask = 0, ignore_status_mask = 0, state = 0xc381c1fc, icount = {cts = 0, dsr = 0, rng = 0, dcd = 0, rx = 0, tx = 8, frame = 0, overrun = 0, parity = 0, brk = 0, buf_overrun = 0}, cons = 0xc0888bdc, sysrq = 0, flags = 0, mctrl = 6, timeout = 2, type = 62, ops = 0xc0888b70, custom_divisor = 0, line = 1, mapbase = 2147934208, dev = 0xc38c9e10, hub6 = 0 '\000', suspended = 0 '\000', irq_wake = 0 '\000', unused = "\000", private_data = 0x0}
(gdb)

OK, s->port.membase has changed, I’m not sure whether this means anything, I can’t find this address anywhere else.

Next attempt:

(gdb) set wait_for_debugger=0
(gdb) set var wait_for_debugger=0
(gdb) ser $r0=0
Undefined command: "ser".  Try "help".
(gdb) set $r0=0
(gdb) s
(gdb) break drivers/tty/serial/mxs-auart.c:294
Breakpoint 1 at 0xc02d72c8: file drivers/tty/serial/mxs-auart.c, line 294.
(gdb) break drivers/tty/serial/mxs-auart.c:772
Breakpoint 2 at 0xc02d6cd0: drivers/tty/serial/mxs-auart.c:772. (2 locations)
(gdb) break drivers/tty/serial/mxs-auart.c:778
Breakpoint 3 at 0xc02d7578: file drivers/tty/serial/mxs-auart.c, line 778.
(gdb) break drivers/tty/serial/mxs-auart.c:788
Breakpoint 4 at 0xc02d6ce4: file drivers/tty/serial/mxs-auart.c, line 788.
(gdb) c

Breakpoint 2, mxs_auart_tx_empty (u=0xc3a27600) at drivers/tty/serial/mxs-auart.c:772
(gdb)
static unsigned int mxs_auart_tx_empty(struct uart_port *u)
{
  if (readl(u->membase + AUART_STAT) & AUART_STAT_TXFE)
    return TIOCSER_TEMT;
  else
    return 0;
}

static void mxs_auart_start_tx(struct uart_port *u)
{
  struct mxs_auart_port *s = to_auart_port(u);

  /* enable transmitter */
  writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_SET);

  mxs_auart_tx_chars(s);
}

static void mxs_auart_stop_tx(struct uart_port *u)
{
  writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_CLR);
}

writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_SET); /* enable transmitter */ gets actually executed, so what is the problem?

Some notes:

AUART_CTRL2_TXE:
  #define AUART_CTRL2_TXE (1 << 8)
u->membase:
  (gdb) print u->membase
  $2 = (unsigned char *) 0xc48d4000 ""
AUART_CTRL2_SET:
  #define AUART_CTRL2_SET 0x00000024

So I’ve finally solved the issue after reading Documentation/devicetree/bindings/pinctrl/fsl,mxs-pinctrl.txt again, the pinmux-ids were wrong.

Required subnode-properties:
- fsl,pinmux-ids: An integer array.  Each integer in the array specify a pin
  with given mux function, with bank, pin and mux packed as below.

    [15..12] : bank number
    [11..4]  : pin number
    [3..0]   : mux selection

0000000000000000
[  ][      ][  ]
bank  pin    mux

0000000011100000 0x00e0 /* MX23_PAD_GPMI_D14__GPMI_D14 */
0000000011110000 0x00f0 /* MX23_PAD_GPMI_D15__GPMI_D15 */
  0b00001110 = 14
  0b00001111 = 15

Looking at the datasheet, mux for auart should be 01:

0000000011100001 0x00e1 /* MX23_PAD_GPMI_D14__AUART2_TX */
0000000011110001 0x00f1 /* MX23_PAD_GPMI_D15__AUART2_RX */
IMX23RM: pin multiplexing for AUART2

IMX23RM: pin multiplexing for AUART2

Before I haven’t understood the exact functioning of fsl,pinmux-ids but now I’ve corrected arch/arm/boot/dts/imx23.dtsi:

auart1_2pins_a: auart1-2pins@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x00e1 /* MX23_PAD_GPMI_D14__AUART2_TX */
    0x00f1 /* MX23_PAD_GPMI_D15__AUART2_RX */
  >;
  fsl,drive-strength = <0>;
  fsl,voltage = <1>;
  fsl,pull-up = <0>;
};

Woo-hoo! Finally! Its working! I have a serial terminal @ ttyAPP1 :-)

Arch Linux 3.11.0-next-20130910-dirty (ttyAPP1)

olinuxino login: root
Password:
Last login: Wed Dec 31 18:05:40 on ttyAPP1
[root@olinuxino ~]# cat /proc/version
Linux version 3.11.0-next-20130910-dirty (chris@thinkpad) (gcc version 4.7.3 20130312 (release) [ARM/embedded-4_7-branch revision 196615] (GNU Tools f3
[root@olinuxino ~]#

It took a bit long to find the error but I’ve found it myself and now I’m mush better at debugging.

Step 5: The status led

The green status LED is connected to LCD_CS:

IMX23RM: pin multiplexing for LCD_CS

IMX23RM: pin multiplexing for LCD_CS

Required subnode-properties:
- fsl,pinmux-ids: An integer array.  Each integer in the array specify a pin
  with given mux function, with bank, pin and mux packed as below.

    [15..12] : bank number
    [11..4]  : pin number
    [3..0]   : mux selection

0000000000000000
[  ][      ][  ]
bank  pin    mux

0001000101010011 0x1153 /* MX23_PAD_LCD_CS__GPIO_1_21 */
  0b00010101 = 21

linux-stable/arch/arm/boot/dts/imx23-olinuxino.dts:

led_pin_gpio1_21: led_gpio1_21@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x1153 /* MX23_PAD_LCD_CS__GPIO_1_21 */
  >;
  fsl,drive-strength = <0>;
  fsl,voltage = <1>;
  fsl,pull-up = <0>;
};
leds {
  compatible = "gpio-leds";
  pinctrl-names = "default";
  pinctrl-0 = <&led_pin_gpio1_21>;

  user {
    label = "green";
    gpios = <&gpio1 21 1>;
  };
};

Now make the led blink:

[root@alarm ~]# vim led_blink
[root@alarm ~]# cat led_blink
while [ 1 -eq 1 ]
do
  echo 1 > /sys/class/leds/green/brightness
  sleep 1
  echo 0 > /sys/class/leds/green/brightness
  sleep 1
done
[root@alarm ~]# chmod +x led_blink
[root@alarm ~]# ./led_blink

Or enable the heartbeat trigger:

[root@alarm ~]# echo heartbeat >  /sys/class/leds/green/trigger
[root@alarm ~]#

Add it to an startup script:

[root@alarm ~]# vim /etc/rc.local
[root@alarm ~]# cat /etc/rc.local
#!/bin/sh
echo heartbeat >  /sys/class/leds/green/trigger

[root@alarm ~]# chmod +x /etc/rc.local
[root@alarm ~]# vim /etc/systemd/system/rc-local.service
[root@alarm ~]# cat /etc/systemd/system/rc-local.service
[Unit]
Description=/etc/rc.local Compatibility
ConditionPathExists=/etc/rc.local

[Service]
Type=oneshot
ExecStart=/etc/rc.local start
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99

[Install]
WantedBy=multi-user.target

[root@alarm ~]# systemctl enable rc-local.service
ln -s '/etc/systemd/system/rc-local.service' '/etc/systemd/system/multi-user.target.wants/rc-local.service'
[root@alarm ~]# reboot

Step 6: The second SD card

The second SD card on the board can be used to store recorded audio files or MP3 files for playback.

Enabling the SD card:

Have a look into linux-stable/Documentation/devicetree/bindings/mmc/mmc.txt and in linux-stable/arch/arm/boot/dts/imx23.dtsi add this:

mmc1_4bit_pins_a: mmc1-4bit@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x2020 /* MX23_PAD_SSP2_DATA0__SSP1_DATA0 */
    0x2030 /* MX23_PAD_SSP2_DATA1__SSP1_DATA1 */
    0x2040 /* MX23_PAD_SSP2_DATA2__SSP1_DATA2 */
    0x2050 /* MX23_PAD_SSP2_DATA3__SSP1_DATA3 */
    0x2000 /* MX23_PAD_SSP2_CMD__SSP1_CMD */
    0x2060 /* MX23_PAD_SSP2_SCK__SSP1_SCK */
    0x2010 /* MX23_PAD_SSP2_DETECT__SSP1_DETECT */
  >;
  fsl,drive-strength = <1>;
  fsl,voltage = <1>;
  fsl,pull-up = <1>;
};

And in linux-stable/arch/arm/boot/dts/imx23-olinuxino.dts add the following:

ssp1: ssp@80034000 {
  compatible = "fsl,imx23-mmc";
  pinctrl-names = "default";
  pinctrl-0 = <&mmc1_4bit_pins_a>;
  bus-width = <4>;
  status = "okay";
};

This was just copied from the first SD card, now get the correct pinmux-ids from the schematic and the data sheet:

Required subnode-properties:
- fsl,pinmux-ids: An integer array.  Each integer in the array specify a pin
  with given mux function, with bank, pin and mux packed as below.

    [15..12] : bank number
    [11..4]  : pin number
    [3..0]   : mux selection

0000000000000000
[  ][      ][  ]
bank  pin    mux

0000000000000010 0x0002 /* MX23_PAD_SSP2_DATA0__SSP2_DATA0 */
  0b00000000 = 0
0000000000010010 0x0012 /* MX23_PAD_SSP2_DATA1__SSP2_DATA1 */
  0b00000001 = 1
0000000000100010 0x0022 /* MX23_PAD_SSP2_DATA2__SSP2_DATA2 */
  0b00000010 = 2
0000000000110010 0x0032 /* MX23_PAD_SSP2_DATA3__SSP2_DATA3 */
  0b00000011 = 3
0000000101000010 0x0142 /* MX23_PAD_SSP2_CMD__SSP2_CMD */
  0b00010100 = 20
0000000110000010 0x0182 /* MX23_PAD_SSP2_SCK__SSP2_SCK */
  0b00011000 = 24
0000000100110010 0x0132 /* MX23_PAD_SSP2_DETECT__SSP2_DETECT */
  0b00010011 = 19

The updated linux-stable/arch/arm/boot/dts/imx23.dtsi looks like this:

mmc1_4bit_pins_a: mmc1-4bit@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x0002 /* MX23_PAD_SSP2_DATA0__SSP2_DATA0 */
    0x0012 /* MX23_PAD_SSP2_DATA1__SSP2_DATA1 */
    0x0022 /* MX23_PAD_SSP2_DATA2__SSP2_DATA2 */
    0x0032 /* MX23_PAD_SSP2_DATA3__SSP2_DATA3 */
    0x0142 /* MX23_PAD_SSP2_CMD__SSP2_CMD */
    0x0182 /* MX23_PAD_SSP2_SCK__SSP2_SCK */
    0x0132 /* MX23_PAD_SSP2_DETECT__SSP2_DETECT */
  >;
  fsl,drive-strength = <1>;
  fsl,voltage = <1>;
  fsl,pull-up = <1>;
};

But after booting the second SD card is still missing:

[root@alarm ~]# ls /dev/mmcblk*
/dev/mmcblk0  /dev/mmcblk0p1  /dev/mmcblk0p2  /dev/mmcblk0p3
[root@alarm ~]#

With Systemd we don’t have /var/log/messages any more, but we can just use dmesg or the Systemd Journal (journalctl --this-boot | grep -i mmc) instead to look for some debug messages:

[root@alarm ~]# cat /var/log/mess*
cat: /var/log/mess*: No such file or directory
[root@alarm ~]# dmesg |grep mmc
[    0.000000] Kernel command line: noinitrd console=ttyAMA0,115200 console=ttyAPP1,115200 root=/dev/mmcblk0p2 rw rootwait ssp1=mmc
[    2.410000] mxs-mmc 80010000.ssp: initialized
[    2.520000] mmc0: host does not support reading read-only switch. assuming write-enable.
[    2.570000] mmc0: new high speed SD card at address 0260
[    2.610000] mmcblk0: mmc0:0260 SD    1.87 GiB
[    2.660000]  mmcblk0: p1 p2 p3
[    8.140000] EXT3-fs (mmcblk0p2): using internal journal
[    8.160000] EXT3-fs (mmcblk0p2): recovery complete
[    8.170000] EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode
[root@alarm ~]# dmesg |grep ssp
[    0.000000] Kernel command line: noinitrd console=ttyAMA0,115200 console=ttyAPP1,115200 root=/dev/mmcblk0p2 rw rootwait ssp1=mmc
[    1.850000] mxs-spi 80034000.ssp: registered master spi1
[    2.370000] of_get_named_gpio_flags: can't parse gpios property of node '/apb@80000000/apbh@80000000/ssp@80010000[0]'
[    2.410000] mxs-mmc 80010000.ssp: initialized
[root@alarm ~]# journalctl -b --no-pager | grep -i mmc
Dec 31 17:04:12 alarm kernel: Kernel command line: noinitrd console=ttyAMA0,115200 console=ttyAPP1,115200 root=/dev/mmcblk0p2 rw rootwait ssp1=mmc
Dec 31 17:04:12 alarm kernel: mxs-mmc 80010000.ssp: initialized
Dec 31 17:04:12 alarm kernel: mmc0: host does not support reading read-only switch. assuming write-enable.
Dec 31 17:04:12 alarm kernel: mmc0: new high speed SD card at address 0260
Dec 31 17:04:12 alarm kernel: mmcblk0: mmc0:0260 SD    1.87 GiB
Dec 31 17:04:12 alarm kernel:  mmcblk0: p1 p2 p3
Dec 31 17:04:13 alarm kernel: EXT3-fs (mmcblk0p2): using internal journal
Dec 31 17:04:13 alarm kernel: EXT3-fs (mmcblk0p2): recovery complete
Dec 31 17:04:13 alarm kernel: EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode
[root@alarm ~]# dmesg |grep ssp
[    0.000000] Kernel command line: noinitrd console=ttyAMA0,115200 console=ttyAPP1,115200 root=/dev/mmcblk0p2 rw rootwait ssp1=mmc
[    1.850000] mxs-spi 80034000.ssp: registered master spi1
[    2.370000] of_get_named_gpio_flags: can't parse gpios property of node '/apb@80000000/apbh@80000000/ssp@80010000[0]'
[    2.410000] mxs-mmc 80010000.ssp: initialized
[root@alarm ~]#

OK, I’ve found the error, there was a duplicated ssp1 section in imx23-olinuxino.dts, now it works:

[    2.400000] mxs-mmc 80010000.ssp: initialized
[    2.450000] mxs-mmc 80034000.ssp: initialized
[    2.460000] mmc0: host does not support reading read-only switch. assuming write-enable.
[    2.480000] ledtrig-cpu: registered to indicate activity on CPUs
[    2.490000] mmc0: new high speed SD card at address 0260
[    2.500000] usbcore: registered new interface driver usbhid
[    2.520000] usbhid: USB HID core driver
[    2.530000] mmcblk0: mmc0:0260 SD    1.87 GiB
[    2.540000] mxs-lradc 80050000.lradc: Touchscreen not enabled.
[    2.580000]  mmcblk0: p1 p2 p3
[    2.610000] TCP: cubic registered
[    2.620000] NET: Registered protocol family 17
[    2.630000] can: controller area network core (rev 20120528 abi 9)
[    2.640000] NET: Registered protocol family 29
[    2.650000] can: raw protocol (rev 20120528)
[    2.660000] can: broadcast manager protocol (rev 20120528 t)
[    2.670000] can: netlink gateway (rev 20130117) max_hops=1
[    2.680000] Key type dns_resolver registered
[    2.700000] registered taskstats version 1
[    2.710000] stmp3xxx-rtc 8005c000.rtc: setting system clock to 1970-01-01 00:00:07 UTC (7)
[    2.740000] mmc1: host does not support reading read-only switch. assuming write-enable.
[    2.780000] ALSA device list:
[    2.780000]   No soundcards found.
[    2.790000] mmc1: new high speed SDHC card at address 1234
[    2.800000] mmcblk1: mmc1:1234 SA04G 3.63 GiB
[    2.820000]  mmcblk1: p1 p2 p3
[root@alarm ~]# ls /dev/mmcblk*
/dev/mmcblk0    /dev/mmcblk0p2  /dev/mmcblk1    /dev/mmcblk1p2
/dev/mmcblk0p1  /dev/mmcblk0p3  /dev/mmcblk1p1  /dev/mmcblk1p3
[root@alarm ~]# mkdir /mnt/main
[root@alarm ~]# mount /dev/mmcblk1p
mmcblk1p1  mmcblk1p2  mmcblk1p3
[root@alarm ~]# mount /dev/mmcblk1p2 /mnt/main/
[  360.810000] kjournald starting.  Commit interval 5 seconds
[  361.530000] EXT3-fs (mmcblk1p2): using internal journal
[  361.550000] EXT3-fs (mmcblk1p2): recovery complete
[  361.560000] EXT3-fs (mmcblk1p2): mounted filesystem with ordered data mode
[root@alarm ~]# ls /mnt/main/
bin   core  etc   lib         ls_output  opt   root  sbin  sys  usr
boot  dev   home  lost+found  mnt        proc  run   srv   tmp  var
[root@alarm ~]#

/dev/mmcblk0 is the boot card and /dev/mmcblk1 is the main card.

I can also remove the card and plug it in again:

[root@alarm ~]# umount /mnt/main/ # umount it first to avoid data loss
[root@alarm ~]#
[ 1652.820000] mmc1: card 1234 removed
[ 1663.460000] mmc1: host does not support reading read-only switch. assuming write-enable.
[ 1663.490000] mmc1: new high speed SDHC card at address 1234
[ 1663.510000] mmcblk1: mmc1:1234 SA04G 3.63 GiB
[ 1663.550000]  mmcblk1: p1 p2 p3

[root@alarm ~]#

Later we may also add write protect and chip detect pins:

  • wp-gpios: Specify GPIOs for write protection, see gpio binding
  • cd-gpios: Specify GPIOs for card detection, see gpio binding

Example:

sdhci@ab000000 {
  ...
  wp-gpios = <&gpio 70 0>;
  cd-gpios = <&gpio 69 0>;
  ...
}

Step 7: Audio Support

The mx28evk uses a sgtl5000 connected to the saif port which could serve as a reference. Have a look at linux-stable/arch/arm/boot/dts/imx28-evk.dts:

apbx@80040000 {
saif0: saif@80042000 {
  pinctrl-names = "default";
  pinctrl-0 = <&saif0_pins_a>;
  status = "okay";
};

saif1: saif@80046000 {
  pinctrl-names = "default";
  pinctrl-0 = <&saif1_pins_a>;
  fsl,saif-master = <&saif0>;
  status = "okay";
};

sound {
compatible = "fsl,imx28-evk-sgtl5000",
        "fsl,mxs-audio-sgtl5000";
model = "imx28-evk-sgtl5000";
saif-controllers = <&saif0 &saif1>;
audio-codec = <&sgtl5000>;
};

And the following files:

SAIF pins from linux-stable/Documentation/devicetree/bindings/pinctrl/fsl,mxs-pinctrl.txt:

MX23_PAD_LCD_D08__SAIF2_SDATA0      0x1082
MX23_PAD_LCD_D09__SAIF1_SDATA0      0x1092
MX23_PAD_LCD_D10__SAIF_MCLK_BITCLK    0x10a2
MX23_PAD_LCD_D11__SAIF_LRCLK      0x10b2
MX23_PAD_LCD_D12__SAIF2_SDATA1      0x10c2
MX23_PAD_LCD_D13__SAIF2_SDATA2      0x10d2
MX23_PAD_LCD_D14__SAIF1_SDATA2      0x10e2
MX23_PAD_LCD_D15__SAIF1_SDATA1      0x10f2
MX23_PAD_LCD_D16__SAIF_ALT_BITCLK   0x1102

Hardware information and wiring

WM8750L (Datasheet):

I2C Address = 0011'010_ (0x34)

MCLK: Master Clock of Chip
BCLK: Audio Interface Bit Clock
ADCLRC: Audio Interface Left/Right Clock
ADCDAT: ADC Digital Data
DACDAT: DAC Digital Data

Pinning at iMX233:
MCLK  H1: SAIF_BITCLK (configure as MCLK in iMX233)
BLCK  F4: SAIF2_D2
ADCLRC G4: SAIF_LRCLK (same as LRCK)
ADCDAT H2: SAIF2_D0
DACDAT H3: SAIF1_D0

Device tree

Then linux-stable/arch/arm/boot/dts/imx23.dtsi should look something like:

...

saif0_pins_a: saif0@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x10a2 /* MX23_PAD_LCD_D10__SAIF_MCLK_BITCLK */
    0x10b2 /* MX23_PAD_LCD_D11__SAIF_LRCLK */
    0x1092 /* MX23_PAD_LCD_D09__SAIF1_SDATA0 */
  >;
  fsl,drive-strength = <2>;
  fsl,voltage = <1>;
  fsl,pull-up = <1>;
};

saif1_pins_a: saif1@0 {
  reg = <0>;
  fsl,pinmux-ids = <
    0x10d2 /* MX23_PAD_LCD_D13__SAIF2_SDATA2 */
    0x1082 /* MX23_PAD_LCD_D08__SAIF2_SDATA0 */
  >;
  fsl,drive-strength = <2>;
  fsl,voltage = <1>;
  fsl,pull-up = <1>;
};

...

saif0: saif@80042000 {
  reg = <0x80042000 0x2000>;
  status = "disabled";
};

saif1: saif@80046000 {
  reg = <0x80046000 0x2000>;
  status = "disabled";
};

...

i2c0: i2c@80058000 {
  #address-cells = <1>;
  #size-cells = <0>;
  compatible = "fsl,imx23-i2c";
  reg = <0x80058000 0x2000>;
  interrupts = <27 26>;
  clock-frequency = <100000>;
  fsl,i2c-dma-channel = <3>;
  status = "disabled";

  wm8750: wm8750@1a {
    compatible = "wlf,wm8750";
    reg = <0x34>;
  };
};

...

And in linux-stable/arch/arm/boot/dts/imx23-olinuxino.dts add:

...

saif0: saif@80042000 {
  pinctrl-names = "default";
  pinctrl-0 = <&saif0_pins_a>;
  status = "okay";
};

saif1: saif@80046000 {
  pinctrl-names = "default";
  pinctrl-0 = <&saif1_pins_a>;
  fsl,saif-master = <&saif0>;
  status = "okay";
};

...

sound {
  compatible = "wlf,wm8750";
  model = "wm8750";
  saif-controllers = <&saif0 &saif1>;
  audio-codec = <&wm8750>;
};

When compiling the kernel select also the following:

Device Drivers  --->
  <*> Sound card support  --->
    <*>   Advanced Linux Sound Architecture  --->
      <*>   ALSA for SoC audio support  --->
        <*>   SoC Audio for Freescale MXS CPUs  --->
        <*>   Build all ASoC CODEC drivers
        <*>   ASoC Simple sound card support

Probably you don’t need everything but I’m too lazy to rebuilt the kernel and flash it again if something is missing. If I diff the old configuration and the new one the driver for the Wolfson WM8750 chip should be selected:

[chris@thinkpad linux-stable]$ diff dotconfig dotconfig.old  |grep -i wm8750
< CONFIG_SND_SOC_WM8750=y
[chris@thinkpad linux-stable]$

It compiles but I doubt that it will work as it is.

The bootlog contains now the following:

...
[    0.130000] i2c-core: driver [dummy] registered
[    0.140000] gpiochip_add: registered GPIOs 0 to 31 on device: gpio.0
[    0.150000] gpiochip_add: registered GPIOs 32 to 63 on device: gpio.1
[    0.150000] gpiochip_add: registered GPIOs 64 to 95 on device: gpio.2
[    0.170000] Serial: AMBA PL011 UART driver
[    0.180000] 80070000.serial: ttyAMA0 at MMIO 0x80070000 (irq = 132) is a PL011 rev2
[    0.420000] console [ttyAMA0] enabled
[    0.470000] bio: create slab <bio-0> at 0
[    0.480000] mxs-dma 80004000.dma-apbh: initialized
[    0.490000] mxs-dma 80024000.dma-apbx: initialized
[    0.500000] of_get_named_gpio_flags exited with status 17
[    0.500000] usb0_vbus: 5000 mV
[    0.510000] SCSI subsystem initialized
[    0.510000] usbcore: registered new interface driver usbfs
[    0.520000] usbcore: registered new interface driver hub
[    0.520000] usbcore: registered new device driver usb
[    0.530000] i2c i2c-0: adapter [MXS I2C adapter] registered
[    0.540000] i2c 0-0034: uevent
[    0.550000] i2c i2c-0: client [wm8750] registered with bus id 0-0034
[    0.550000] Linux video capture interface: v2.00
...
[    1.230000] uart-pl011 80070000.serial: no DMA platform data
[    1.240000] 8006c000.serial: ttyAPP0 at MMIO 0x8006c000 (irq = 126) is a 8006c000.serial
[    1.250000] mxs-auart 8006c000.serial: Found APPUART 3.0.0
[    1.260000] 8006e000.serial: ttyAPP1 at MMIO 0x8006e000 (irq = 129) is a 8006e000.serial
[    1.870000] console [ttyAPP1] enabled
[    1.880000] mxs-auart 8006e000.serial: Found APPUART 3.0.0
[    1.900000] i2c-core: driver [at24] registered
[    1.920000] mxs-spi 80034000.ssp: registered master spi32766 (dynamic)
...
[    2.440000] i2c-core: driver [tsc2007] registered
[    2.450000] i2c-core: driver [rtc-ds1307] registered
[    2.470000] stmp3xxx-rtc 8005c000.rtc: rtc core: registered 8005c000.rtc as rtc0
[    2.490000] i2c /dev entries driver
[    2.500000] i2c-dev: adapter [MXS I2C adapter] registered as minor 0
[    2.510000] usbcore: registered new interface driver uvcvideo
[    2.520000] USB Video Class driver (1.1.1)
...
[    2.750000] mmc0: host does not support reading read-only switch. assuming write-enable.
[    2.770000] i2c-core: driver [ad193x] registered
[    2.780000] i2c-core: driver [adau1373] registered
[    2.790000] i2c-core: driver [adav803] registered
[    2.800000] mmc0: new high speed SDHC card at address 1234
[    2.810000] i2c-core: driver [ak4535] registered
[    2.830000] i2c-core: driver [ak4641] registered
[    2.840000] mmcblk0: mmc0:1234 SA04G 3.63 GiB
[    2.850000] i2c-core: driver [ak4642-codec] registered
[    2.870000] i2c-core: driver [ak4671-codec] registered
[    2.880000]  mmcblk0: p1 p2 p3
[    2.890000] i2c-core: driver [alc562x-codec] registered
[    2.910000] i2c-core: driver [alc5632] registered
[    2.920000] i2c-core: driver [cs42l51-codec] registered
[    2.930000] i2c-core: driver [cs42l52] registered
[    2.940000] i2c-core: driver [cs42l73] registered
[    2.950000] i2c-core: driver [cs4270] registered
[    2.960000] i2c-core: driver [cs4271] registered
[    2.970000] i2c-core: driver [da7210] registered
[    2.980000] i2c-core: driver [da7213] registered
[    2.990000] i2c-core: driver [da7320] registered
[    3.000000] i2c-core: driver [da9055] registered
[    3.010000] i2c-core: driver [isabelle] registered
[    3.020000] i2c-core: driver [lm4857] registered
[    3.030000] i2c-core: driver [lm49453] registered
[    3.040000] i2c-core: driver [max9768] registered
[    3.050000] i2c-core: driver [max98088] registered
[    3.060000] i2c-core: driver [max98090] registered
[    3.070000] i2c-core: driver [max98095] registered
[    3.080000] i2c-core: driver [max9850] registered
[    3.090000] i2c-core: driver [ml26124] registered
[    3.100000] i2c-core: driver [rt5631] registered
[    3.110000] i2c-core: driver [sgtl5000] registered
[    3.120000] i2c-core: driver [ssm2602] registered
[    3.130000] i2c-core: driver [sta32x] registered
[    3.140000] i2c-core: driver [sta529] registered
[    3.150000] i2c-core: driver [tlv320aic23-codec] registered
[    3.160000] i2c-core: driver [tlv320aic3x-codec] registered
[    3.180000] i2c-core: driver [tlv320aic32x4] registered
[    3.190000] i2c-core: driver [tlv320dac33-codec] registered
[    3.200000] i2c-core: driver [uda1380-codec] registered
[    3.210000] i2c-core: driver [wm1250-ev1] registered
[    3.220000] i2c-core: driver [wm2000] registered
[    3.230000] i2c-core: driver [wm2200] registered
[    3.240000] i2c-core: driver [wm5100] registered
[    3.250000] i2c-core: driver [wm8510] registered
[    3.260000] i2c-core: driver [wm8523] registered
[    3.270000] i2c-core: driver [wm8580] registered
[    3.280000] i2c-core: driver [wm8711] registered
[    3.290000] i2c-core: driver [wm8728] registered
[    3.300000] i2c-core: driver [wm8731] registered
[    3.310000] i2c-core: driver [wm8737] registered
[    3.320000] i2c-core: driver [wm8741] registered
[    3.330000] wm8750 0-0034: probe
[    3.340000] i2c-core: driver [wm8750] registered
[    3.350000] i2c-core: driver [wm8753] registered
[    3.360000] i2c-core: driver [wm8776] registered
[    3.370000] i2c-core: driver [wm8804] registered
[    3.380000] i2c-core: driver [wm8900] registered
[    3.390000] i2c-core: driver [wm8903] registered
[    3.400000] i2c-core: driver [wm8904] registered
[    3.410000] i2c-core: driver [wm8996] registered
[    3.420000] i2c-core: driver [wm8940] registered
[    3.430000] i2c-core: driver [wm8955] registered
[    3.440000] i2c-core: driver [wm8960] registered
[    3.450000] i2c-core: driver [wm8961] registered
[    3.460000] i2c-core: driver [wm8962] registered
[    3.470000] i2c-core: driver [wm8971] registered
[    3.480000] i2c-core: driver [wm8974] registered
[    3.490000] i2c-core: driver [wm8978] registered
[    3.500000] i2c-core: driver [wm8983] registered
[    3.510000] i2c-core: driver [wm8985] registered
[    3.520000] i2c-core: driver [wm8988] registered
[    3.530000] i2c-core: driver [wm8990] registered
[    3.540000] i2c-core: driver [wm8991] registered
[    3.550000] i2c-core: driver [wm8993] registered
[    3.560000] i2c-core: driver [wm8995] registered
[    3.570000] i2c-core: driver [wm9081] registered
[    3.580000] i2c-core: driver [wm9090] registered
[    3.590000] i2c-core: driver [max9877] registered
[    3.600000] i2c-core: driver [tpa6130a2] registered
[    3.610000] TCP: cubic registered
[    3.620000] NET: Registered protocol family 17
[    3.630000] can: controller area network core (rev 20120528 abi 9)
[    3.640000] NET: Registered protocol family 29
[    3.650000] can: raw protocol (rev 20120528)
[    3.660000] can: broadcast manager protocol (rev 20120528 t)
[    3.670000] can: netlink gateway (rev 20130117) max_hops=1
[    3.680000] Key type dns_resolver registered
[    3.690000] registered taskstats version 1
[    3.710000] stmp3xxx-rtc 8005c000.rtc: setting system clock to 1970-01-01 00:00:07 UTC (7)
[    3.750000] ALSA device list:
[    3.760000]   No soundcards found.
[   14.630000] kjournald starting.  Commit interval 5 seconds
[   15.340000] EXT3-fs (mmcblk0p2): using internal journal
[   15.360000] EXT3-fs (mmcblk0p2): recovery complete
[   15.370000] EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode
[   15.380000] VFS: Mounted root (ext3 filesystem) on device 179:2.
[   15.400000] devtmpfs: mounted
[   15.410000] Freeing init memory: 164K
[   16.000000] systemd[1]: systemd 204 running in system mode. (+PAM -LIBWRAP -AUDIT -SELINUX -IMA -SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ)

Welcome to Arch Linux ARM!

[   16.090000] systemd[1]: Failed to insert module 'ipv6'
[   16.110000] systemd[1]: Set hostname to <olinuxino>.
...
[   18.710000] systemd[1]: Mounting Debug File System...
        Mounting Debug File System...
[   18.810000] systemd[1]: Starting Swap.
[   18.830000] wm8750 0-0034: uevent
[  OK  ] Reached target Swap.
...
[  OK  ] Reached target Local File Systems.
        Starting Recreate Volatile Files and Directories...
        Starting Trigger Flushing of Journal to Persistent Storage...
[   21.510000] wm8750 0-0034: uevent
[   21.610000] wm8750 0-0034: uevent
[   21.650000] wm8750 0-0034: uevent
[   21.730000] wm8750 0-0034: uevent
[   21.750000] wm8750 0-0034: uevent
[   21.780000] wm8750 0-0034: uevent
[   21.820000] wm8750 0-0034: uevent
[   21.860000] wm8750 0-0034: uevent
[   21.920000] wm8750 0-0034: uevent
[  OK  ] Started Recreate Volatile Files and Directories.
        Starting Update UTMP about System Reboot/Shutdown...
[   22.070000] wm8750 0-0034: uevent
[  OK  ] Started Setup Virtual Console.
[   22.150000] wm8750 0-0034: uevent
[   22.280000] wm8750 0-0034: uevent
[   22.340000] wm8750 0-0034: uevent
[   22.410000] wm8750 0-0034: uevent
[  OK  ] Started Trigger Flushing of Journal to Persistent Storage.
[   22.460000] wm8750 0-0034: uevent
[   22.510000] wm8750 0-0034: uevent
[   22.570000] wm8750 0-0034: uevent
[  OK  ] Started Update UTMP about System Reboot/Shutdown.
[   22.620000] wm8750 0-0034: uevent
[   22.700000] wm8750 0-0034: uevent
[   22.760000] wm8750 0-0034: uevent
[   22.810000] wm8750 0-0034: uevent
[   22.850000] wm8750 0-0034: uevent
[   22.880000] wm8750 0-0034: uevent
[   22.910000] wm8750 0-0034: uevent
[   22.940000] wm8750 0-0034: uevent
[   22.980000] wm8750 0-0034: uevent
[   23.020000] wm8750 0-0034: uevent
[   23.060000] wm8750 0-0034: uevent
[   23.130000] wm8750 0-0034: uevent
[   23.250000] wm8750 0-0034: uevent
[   23.310000] wm8750 0-0034: uevent
[   23.420000] wm8750 0-0034: uevent
[   23.480000] wm8750 0-0034: uevent
[   23.530000] wm8750 0-0034: uevent
[   23.580000] wm8750 0-0034: uevent
[   23.600000] wm8750 0-0034: uevent
[   23.730000] wm8750 0-0034: uevent
[   23.860000] wm8750 0-0034: uevent
[   23.940000] wm8750 0-0034: uevent
[   24.180000] wm8750 0-0034: uevent
[   24.310000] wm8750 0-0034: uevent
[   24.400000] wm8750 0-0034: uevent
[   24.570000] wm8750 0-0034: uevent
[   24.640000] wm8750 0-0034: uevent
[   24.700000] wm8750 0-0034: uevent
[   24.830000] wm8750 0-0034: uevent
[   24.900000] wm8750 0-0034: uevent
[   24.940000] wm8750 0-0034: uevent
[   25.070000] wm8750 0-0034: uevent
[   25.140000] wm8750 0-0034: uevent
[   25.210000] wm8750 0-0034: uevent
[   25.260000] wm8750 0-0034: uevent
[   25.310000] wm8750 0-0034: uevent
[   25.350000] wm8750 0-0034: uevent
[   25.370000] wm8750 0-0034: uevent
[  OK  ] Started udev Coldplug all Devices.
[  OK  ] Reached target System Initialization.
[  OK  ] Reached target Timers.
[   25.470000] wm8750 0-0034: uevent
[  OK  ] Listening on D-Bus System Message Bus Socket.
[  OK  ] Reached target Sockets.
[  OK  ] Reached target Basic System.
        Starting OpenNTP Daemon...
[   25.610000] wm8750 0-0034: uevent
        Starting System Logger Daemon...
[   25.670000] wm8750 0-0034: uevent
[  OK  ] Started System Logger Daemon.
[   25.840000] wm8750 0-0034: uevent
        Starting /etc/rc.local Compatibility...
[   25.920000] wm8750 0-0034: uevent
        Starting Periodic Command Scheduler...
[   25.990000] wm8750 0-0034: uevent
[   26.100000] wm8750 0-0034: uevent
[   26.210000] wm8750 0-0034: uevent
[  OK  ] Started Periodic Command Scheduler.
        Starting OpenSSH Daemon...
[   26.280000] wm8750 0-0034: uevent
[   26.340000] wm8750 0-0034: uevent
[  OK  ] Started OpenSSH Daemon.
        Starting Permit User Sessions...
[   26.380000] wm8750 0-0034: uevent
[   26.430000] wm8750 0-0034: uevent
        Starting D-Bus System Message Bus...
[   26.510000] wm8750 0-0034: uevent
[  OK  ] Started D-Bus System Message Bus.
[   26.550000] wm8750 0-0034: uevent
        Starting Login Service...
[   26.600000] wm8750 0-0034: uevent
[   26.660000] wm8750 0-0034: uevent
[   26.710000] wm8750 0-0034: uevent
[   26.760000] wm8750 0-0034: uevent
[   26.850000] wm8750 0-0034: uevent
[   26.940000] wm8750 0-0034: uevent
[   27.120000] wm8750 0-0034: uevent
[  OK  ] Started Permit User Sessions.
        Starting Getty on tty1...
[   27.390000] wm8750 0-0034: uevent
[  OK  ] Started Getty on tty1.
[   27.710000] wm8750 0-0034: uevent
[   27.810000] wm8750 0-0034: uevent
[   27.890000] wm8750 0-0034: uevent
[   28.000000] wm8750 0-0034: uevent
[   28.090000] wm8750 0-0034: uevent
[   28.110000] wm8750 0-0034: uevent
[   28.350000] wm8750 0-0034: uevent
[  OK  ] Started /etc/rc.local Compatibility.
[   28.460000] wm8750 0-0034: uevent
[   28.540000] wm8750 0-0034: uevent
[   28.610000] wm8750 0-0034: uevent
[   28.740000] wm8750 0-0034: uevent
[   28.820000] wm8750 0-0034: uevent
[  OK  ] Started Login Service.
[   28.970000] wm8750 0-0034: uevent
[   29.040000] wm8750 0-0034: uevent
[   29.110000] wm8750 0-0034: uevent
[   29.110000] wm8750 0-0034: uevent
[   29.170000] wm8750 0-0034: uevent
[   29.250000] wm8750 0-0034: uevent
[   29.320000] wm8750 0-0034: uevent
[   29.450000] wm8750 0-0034: uevent
[   29.570000] wm8750 0-0034: uevent
[   29.640000] wm8750 0-0034: uevent
[   29.660000] wm8750 0-0034: uevent
[   29.710000] wm8750 0-0034: uevent
[   29.790000] wm8750 0-0034: uevent
[   29.940000] wm8750 0-0034: uevent
[  OK  ] Found device /dev/ttyAPP0.
[   30.100000] wm8750 0-0034: uevent
        Starting Serial Getty on ttyAPP0...
[   30.210000] wm8750 0-0034: uevent
[  OK  ] Started Serial Getty on ttyAPP0.
[   30.330000] wm8750 0-0034: uevent
[   30.350000] wm8750 0-0034: uevent
[   30.450000] wm8750 0-0034: uevent
[  OK  ] Found device /dev/ttyAMA0.
        Starting Serial Getty on ttyAMA0...
[   30.530000] wm8750 0-0034: uevent
[[   30.600000] wm8750 0-0034: uevent
  OK  ] Started Serial Getty on ttyAMA0.
[   30.680000] wm8750 0-0034: uevent
[   30.760000] wm8750 0-0034: uevent
[  OK  ] Found device /dev/ttyAPP1.
        Starting Serial Getty on ttyAPP1...
[   30.840000] wm8750 0-0034: uevent
[   30.910000] wm8750 0-0034: uevent
[   31.060000] wm8750 0-0034: uevent
[   31.270000] wm8750 0-0034: uevent
[   31.280000] wm8750 0-0034: uevent
[  OK  ] [   31.380000] wm8750 0-0034: uevent
Started Serial Getty on ttyAPP1.
[  OK  ] Reached target Login Prompts.
[   31.460000] wm8750 0-0034: uevent
[   31.560000] wm8750 0-0034: uevent
[   31.710000] wm8750 0-0034: uevent
[   31.810000] wm8750 0-0034: uevent
[   31.870000] wm8750 0-0034: uevent
[   31.940000] wm8750 0-0034: uevent
[   32.090000] wm8750 0-0034: uevent
...
[   36.610000] wm8750 0-0034: uevent
[   36.630000] wm8750 0-0034: uevent
[   36.650000] wm8750 0-0034: uevent
[   36.680000] wm8750 0-0034: uevent
[   36.700000] wm8750 0-0034: uevent
[   36.720000] wm8750 0-0034: uevent
[   36.740000] wm8750 0-0034: uevent
[   36.760000] wm8750 0-0034: uevent

Arch Linux 3.9.4-dirty (ttyAMA0)

[   36.780000] wm8750 0-0034: uevent
olinuxino login:
[   36.800000] wm8750 0-0034: uevent
[   36.820000] wm8750 0-0034: uevent
...
[   43.270000] wm8750 0-0034: uevent
[  OK  ] Started OpenNTP Daemon.
[   43.300000] wm8750 0-0034: uevent
[  OK  ] Reached target Multi-User System.
[  OK  ] Reached target Graphical Interface.
[   43.330000] wm8750 0-0034: uevent
...
[   67.310000] wm8750 0-0034: uevent
[   67.320000] wm8750 0-0034: uevent
[   67.340000] wm8750 0-0034: uevent
...

To be continued...

Audio playback and recording

amixer / alsamixer

arecord -d 5 -t wav -f cd a.wav

aplay -d 5 -t wav -f cd a.wav

Text To Speech, TTS

espeak -vde “zu sprechender Text”

echo “This is a test.” | festival –tts

http://wiki.ubuntuusers.de/Sprachausgabe

http://wiki.ubuntuusers.de/Festival/Kompilieren

HOWTO: Make festival TTS use better voices (MBROLA CMU HTS): http://ubuntuforums.org/showthread.php?t=751169

Step 11: U-Boot

Fix U-Boot memory init:

  • imx-bootlets-src-10.05.02/boot_prep/init-mx23.c
  • u-boot.git/arch/arm/cpu/arm926ejs/mxs/spl_mem_init.c

To be continued...

Step 12: QEMU

Instead of debugging our program on the real hardware we can also use QEMU, which is a generic and open source machine emulator and virtualizer.

This may speedup the compilation and development.

Further tasks

  • Try to push everything upstream
  • I’m not sure if Linux drivers for the following modules exist but it could be an interesting task to write some simple kernel drivers or to interface them from userspace.
    • FM Tuner (connected via SAIF)
    • Vibration Module
    • Accelerometer
  • Using Qt Creator for fast application development on the OLinuXino

Change list

2013-09-13: The second application UART is finally working.
2013-10-06: I2C works good enough now: https://www.olimex.com/forum/index.php?topic=1919.msg8858#msg8858, patches are ready for linux-next, so that it should work out-of-the-box in the next kernel http://www.spinics.net/lists/linux-i2c/msg13482.html
2013-11-20: Added repository on GitHub + Arch Linux ARM SD card image
2013-12-13: First steps to get the second SD card working. Currently the kernel reboots if I insert the second SD card. Why?
2013-12-14: Added the status led. The second SD card works now.