Wednesday, 31 July 2013

Software Power-Off of the AM335X with the TPS65217 PMIC

The BeagleBone Black is powered by the AM335X ARM Cortex-A8 Processor. The board provides a push button near the Ethernet connector for powering off and powering on the board. The AM335X works in concert with the TPS65217C Power Management IC (PMIC) and the operating system to do a proper shutdown when the button is pressed. By proper shutdown, I mean the file systems are sync()'d and services are shutdown cleanly. As part of my Google Summer of Code project, I've been implementing this functionality in Minix. I've got the basics working (clean shutdown and power off when the power button is pressed), but a lot of clean-up, re-factoring, and testing remains before I can think about submitting it for inclusion in Minix. The dance between the PMIC and SoC is interesting, so I thought I'd share how it works while it's fresh in my head.

There's a bit of setup to get this to work. It requires drivers for the SoC's I2C controller and RTC. A driver for the PMIC (an i2c slave) is also needed. First, the push button interrupt in the TPS65217C needs to be unmasked, and the driver for the TPS65217C needs to handle interrupts from the NNMI pin (irq 7). That pin signals the AM335X to let it know that there is an interrupt pending on the TPS65217C. This gets notifications about the button press to the TPS65217C driver. With just that part functional, you can do safe shutdowns of the operating system when the user presses the button.

Powering off the board takes a few more steps. The TPS65217C driver also has to set the OFF bit in the STATUS register. This enables power-off when the AM335X signals a power off by toggling the PWR_EN pin. Toggling the pin is done by setting the POWER_EN bit in RTC_PMIC, setting the time to power off the chip in the RTC's ALARM2 registers, enabling the the ALARM2 interrupt in the RTC_INTERRUPTS_REG register, and waiting for the alarm to go off which will automatically toggle the pin to alert the PMIC to power down the board. Finally, the PMIC will sense the toggle and cut the power. The user can press the power button again to boot the system.

TDA19988 Driver merged into mainline Minix

Just a quick note to mention that the driver I developed for the TDA19988 HDMI Transmitter was merged into the main Minix repository earlier in the week. The commit is here. The driver enables EDID reading on the BeagleBone Black. When the frame buffer driver is ported to the BeagleBone Black, it will be able to use the EDID from the TDA19988 to configure the display properly.

While the TDA19988 driver is meant to be accessed directly by the frame buffer driver, it can be tested from the shell by creating a block device file with an unused major number and doing a read with the dd command. Below is the output from one of my test runs showing the exact commands:

# cd /dev
# mknod tda19988 b 32 0
# chmod 600 tda19988
# /bin/service down tda19988.1.3470
# /bin/service up /usr/sbin/tda19988 -label tda19988.1.3470 \
 -dev /dev/tda19988 \
 -args 'cec_bus=1 cec_address=0x34 hdmi_bus=1 hdmi_address=0x70'
# dd if=/dev/tda19988 of=/root/edid.dat count=1 bs=128
1+0 records in
1+0 records out
# hexdump -C /root/edid.dat
00000000  00 ff ff ff ff ff ff 00  05 e3 02 19 56 04 00 00  |............V...|
00000010  24 10 01 03 81 29 1a 78  2a d7 a5 a2 59 4a 96 24  |$....).x*...YJ.$|
00000020  14 50 54 bf ef 00 81 80  71 4f 81 40 95 0f 01 01  |.PT.....qO.@....|
00000030  01 01 01 01 95 00 30 2a  a0 d0 51 84 22 30 50 98  |......0*..Q."0P.|
00000040  36 00 9a 01 11 00 00 1e  00 00 00 ff 00 39 33 31  |6............931|
00000050  36 39 43 41 30 30 31 31  31 30 00 00 00 fd 00 32  |69CA001110.....2|
00000060  4c 1e 53 0e 00 0a 20 20  20 20 20 20 00 00 00 fc  |L.S...      ....|
00000070  00 47 31 39 4c 57 6b 0a  20 20 20 20 20 20 00 95  |.G19LWk.      ..|
# /bin/service down tda19988.1.3470
# rm tda19988

If you try this at home, you'll need a display connected to your BeagleBone Black for this to work. The hexdump should begin with the EDID magic number: 00 ff ff ff ff ff ff 00. The checksum algorithm is: sum the bytes, (sum & 0xff) should equal 0.

Monday, 29 July 2013

Looking for beta testers who have a BeagleBoard-xM

I've been working on enhancements to Minix's frame buffer driver that allow it to detect the supported resolutions of the connected display via EDID (extended display identification data) and automatically configure the frame buffer driver with a resolution that works well with the display and the board. I'm looking for some people to help test my code as I only have 1 physical monitor to test with in addition to the Linaro QEMU simulator. If you'd like to help, please read on.

Note, this only works with the BeagleBoard-xM. The BeagleBone isn't supported by the frame buffer driver yet.

Test Instructions

  1. Connect a display to your BeagleBoard-xM. It should work with most HDMI/DVI displays.
  2. Boot a BeagleBoard-xM with my patches. Steps to obtain, build, and boot my code are provided here:
  3. Log in as root and run the splash program
    1. # splash
  4. Observe the screen. If it worked, you should see some raccoons ( like this photo ). To stop the splash program, use Ctrl+C.

If it works

Please e-mail me at to let me know. If you can, also include a description of your display (make, model, etc).

If it doesn't work

Please e-mail me at with your display's EDID. Here are the steps to get the EDID:

  1. Read the EDID and store the contents in a file
    1. # dd if=/dev/eepromb3s50 of=/root/eeprom.dat count=1 bs=128
  2. E-mail me the data. You can either send me that file as an attachment (it should be on the 2nd partition of the SD card) or copy and paste the output of `hexdump -C /root/eeprom.dat` into the e-mail body.

Sunday, 28 July 2013

Report 6 (July 22 - July 28)

This is Report #6. I plan to post these every Sunday. They will give a rundown of what I've done during the week, list any problems I had, and what I plan to do the following week. I'll be posting the reports both to the beagle-gsoc Google Group and to my blog.

Completed this week:

  • Rebased against mainline Minix
  • EEPROM driver enhancements (merged):
    • 4x speed-up for reads of 128 bytes or more.
    • Support for the 1 byte addressing scheme used in smaller EEPROMs. Previously, just the 2 byte (page + address) scheme, used by the CAT24C256 EEPROM, was supported.
  • Imported EDID validation, parsing, and printing code from NetBSD and got it compiling on Minix.
  • Committed small EDID man page fixes to NetBSD.
  • Began enhancing the frame buffer driver:
    • Added code to request and retrieve the EDID. Tested on BeagleBoard-xM. (blog post).
    • Began working on code to apply the settings. Works on my monitor (photo) and in Linaro QEMU.
    • Wrote a function to choose a resolution supported by both the SoC and the display.
  • Made a small fix to the frame buffer demo program to dynamically get the screen resolution from the frame buffer driver.
  • Continued work on the TDA19988 driver. EDID reading is buggy. It only works intermittently, and when it does work, it is only reading the last 32 bytes.

Issues / Concerns / Challenges:

  • None this week :)

Plan for next week:

  • Finish the frame buffer driver enhancements.
    • Code clean-up and more testing.
    • Maybe try to recruit some people to help test it with different monitors.
    • Submit changes for merging into mainline Minix.
  • Debug the TDA19988 driver, clean up the code a bit, and submit to mainline.
  • Begin working on a driver for the power management chip (TPS65217C).

Friday, 26 July 2013

EDID Reading

I haven't posted in a while, so here's a little bit of a brain dump about EDID on Beagle hardware with some sample debugging output from the BeagleBoard-xM towards the end.

Lately, I've been working on implementing support in Minix for reading Extended Display Identification Data (EDID). EDID contains information about your monitor (resolution, etc). The data resides on a chip in your monitor. It's read using I2C (well, technically I think it's DDC, but it's on the I2C bus). The general idea is that the frame buffer driver will query the EDID and configure itself with the optimal resolution, sync rates, etc. On the BeagleBoard-xM, the EDID is at slave address 0x50 on the third I2C bus. For the original BeagleBone (White), the EDID is at slave address 0x50 on the second I2C bus, assuming you're using the DVI cape. The programming for doing the reading is rather simple, it's done the same way as reading from an EEPROM: write 0x00 with a STOP and then do a 128 byte read.

For the BeagleBone Black, it's a lot more complicated. EDID reading goes through the TDA19988. The TDA19988 has two slave addresses (0x34 for CEC and 0x70 for HDMI). When the chip powers up, the HDMI interface is disabled by default. You have to enable it through the CEC interface. Then you need to setup interrupts, send a read request, poll a status register waiting for the interrupt to fire, and then you can read the EDID. Last week I got the point where my TDA19988 driver can detect if a monitor is connected, enable the HDMI interface, and read the TDA19988 revision information through the HDMI interface. I've written the code for the rest, but I'm waiting on a cable to fully test it (my uHDMI to VGA adapter doesn't support EDID -- I double checked in Linux); I should have the cable this weekend.

I did manage to get the right HDMI to DVI cable to do some testing of my work in progress code on the BeagleBoard-xM. Below is a screen dump of the debug output. I start the EEPROM driver for slave address 0x50 on I2C bus 3, I start the frame buffer driver with arguments to point it at the EEPROM driver, and then I run a program which feeds the frame buffer driver some images to display. You'll see that when the frame buffer init code runs, it looks up the EEPROM driver and requests the data. Then the frame buffer driver validates, parses, and displays the EDID. I'm using the NetBSD EDID code for that last part. I committed some EDID documentation fixes back to NetBSD.

# cd /dev && MAKEDEV eepromb3s50
# service up /usr/sbin/cat24c256 -dev /dev/eepromb3s50 -label cat24c256.3.50 -args 'bus=3 address=0x50'
# service up /usr/sbin/fb -dev /dev/fb0 -args edid.0=cat24c256.3.50
edid(debug):/home/tcort/repos/i2c/src/drivers/fb/fb_edid.c+67(fb_edid_args_parse):Found key:edid.0 value:cat24c256.3.50
framebuffer fresh: pid 140
# splash
edid(debug):/home/tcort/repos/i2c/src/drivers/fb/fb_edid.c+154(fb_edid_read):Contacting cat24c256.3.50 to get EDID.
edid(debug):/home/tcort/repos/i2c/src/drivers/fb/fb_edid.c+178(fb_edid_read):EDID Retrieved and Parsed OK
fb(debug):/home/tcort/repos/i2c/src/drivers/fb/arch/earm/fb_arch.c+311(arch_fb_init):Configuring Settings based on EDID...
fb(debug):/home/tcort/repos/i2c/src/drivers/fb/arch/earm/fb_arch.c+142(configure_with_edid):--- EDID - START ---
Vendor: [AOC] AOC
Product: [1902] G19LWk
Serial number: 93169CA001110
Manufactured 2006 Week 36
EDID Version 1.3
EDID Comment: 
Video Input: 81
Digital (DFP 1.x compatible)
Gamma: 2.20
Max Size: 41 cm x 26 cm
Features: 2a
DPMS active-off
Preferred timing
Chroma Info:
Red X: 0.635
Red Y: 0.635
Grn X: 0.290
Grn Y: 0.588
Blu X: 0.142
Blu Y: 0.080
Wht X: 0.313
Wht Y: 0.329
Horizontal: 30 - 83 kHz
Vertical: 50 - 76 Hz
Max Dot Clock: 140 MHz
Video modes:
720x400 @ 70Hz (28320 738 846 900 412 414 449 -H +V)
640x480 @ 60Hz (25175 656 752 800 490 492 525 -H -V)
640x480 @ 73Hz (31500 664 704 832 489 492 520 -H -V)
640x480 @ 75Hz (31500 656 720 840 481 484 500 -H -V)
800x600 @ 56Hz (36000 824 896 1024 601 603 625 +H +V)
800x600 @ 60Hz (40000 840 968 1056 601 605 628 +H +V)
800x600 @ 72Hz (50000 856 976 1040 637 643 666 +H +V)
800x600 @ 75Hz (49500 816 896 1056 601 604 625 +H +V)
832x624 @ 75Hz (57284 864 928 1152 625 628 667 -H -V)
1024x768 @ 60Hz (65000 1048 1184 1344 771 777 806 -H -V)
1024x768 @ 70Hz (75000 1048 1184 1328 771 777 806 -H -V)
1024x768 @ 75Hz (78750 1040 1136 1312 769 772 800 +H +V)
1280x1024 @ 75Hz (135000 1296 1440 1688 1025 1028 1066 +H +V)
1280x1024 @ 60Hz (108000 1328 1440 1688 1025 1028 1066 +H +V)
1152x864 @ 75Hz (108000 1216 1344 1600 865 868 900 +H +V)
1280x960 @ 60Hz (108000 1376 1488 1800 961 964 1000 +H +V)
1440x900 @ 75Hz (136492 1536 1688 1936 901 904 940 +H +V)
1440x900 @ 60Hz (106470 1520 1672 1904 901 904 932 +H +V)
1440x900 @ 61Hz (108000 1520 1672 1904 903 909 934 +H +V)
Preferred mode: 1440x900 @ 61Hz
fb(debug):/home/tcort/repos/i2c/src/drivers/fb/arch/earm/fb_arch.c+144(configure_with_edid):--- EDID - END ---

Now that the frame buffer driver can get the EDID, the next step is to actually configure the frame buffer driver using the EDID information. This will be a bit of a learning, but I'm looking forward to learning the details of graphics drivers like what a "horizontal front porch" is. Another next step is testing the TDA19988 driver. I'll let you know how it goes in my report on Sunday.

Sunday, 21 July 2013

Report 5 (July 15 - July 21)

This is Report #5. I plan to post these every Sunday. They will give a rundown of what I've done during the week, list any problems I had, and what I plan to do the following week. I'll be posting the reports both to the beagle-gsoc Google Group and to my blog.

Completed this week:

Issues / Concerns / Challenges:

  • None this week :)

Plan for next week:

  • EDID reading in the TDA19988 driver. Subtasks: enabling DDC, enabling interrupts, setting up the read, and reading the data.
  • Begin frame buffer driver enhancements to use EDID to configure the driver properly.

Wednesday, 17 July 2013

Everything you ever wanted to know about Minix I2C (and more!)

I just finished posting the last of 3 new pages to the Minix wiki documenting the I2C subsystem on Minix, the I2C driver interface, and I2C device driver development. Without further adieu, here are the links:

  • I2C Subsystem Internals - this page explains how the I2C subsystem works, how device files are named/numbered, what interfaces are provided, userland tools, and much more.
  • I2C Driver Protocol - this page specifies the interface between I2C device drivers and the I2C bus drivers. It explains what Minix IPC message types are accepted by the I2C bus drivers, the fields in the messages, and the possible reply codes. Pretty technical stuff.
  •  I2C Device Driver Programming - this is a step by step guide walking you through creating a new Minix device driver from scratch for an I2C device. I'm hoping it compliments the general Device Driver Programming guide (not written by me) and inspires/helps future Minix developers. At the very least, it will act as a checklist and provide skeleton for future I2C drivers that I develop.
During the rest of this week I will be continuing work on the TDA19988 driver. The main focus of that project is to read the Extended Display Identification Data (EDID). EDID contains the information about the monitor that's connected to the BeagleBone (resolution, etc). I'll be using that data later on to configure the frame buffer driver properly. I've got a stub for that driver built. Now I just have to read the documentation and figure out how to access the EDID.

Sunday, 14 July 2013

Report 4 (July 8 - July 14)

This is Report #4. I plan to post these every Sunday. They will give a rundown of what I've done during the week, list any problems I had, and what I plan to do the following week. I'll be posting the reports both to the beagle-gsoc Google Group and to my blog.

Completed this week:

  • Contributed i2cscan enhancements back to NetBSD. Commits: i2cscan.c, i2cscan.8
  • Finished the CAT24C256 Driver (EEPROM).
  • Resolved the pinmux issue I had last week. See my blog post for details.
  • General code clean-up and testing.
  • Documented the Minix I2C device driver interface to the I2C bus driver. Text here. Will post to the wiki when code is merged.
  • Documented the Minix I2C internals. Text here. Will post to the wiki when code is merged.

Issues / Concerns / Challenges:

  • None this week :)

Plan for next week:

  • Minor fix needed to allow the i2c device drivers to survive the i2c bus driver restarting.
  • Submit what I've done so far into the code review / continuous integration pipeline for inclusion in mainline Minix. This includes the pinmux work around, i2c bus driver, i2cscan utility, libi2cdriver, cat24c256 driver, eepromread utility.
  • Start working on a driver for reading the extended display identification data (EDID) via the TDA19988.
  • As I work on the TDA19988 driver, I'll also document how to write a Minix I2C driver using the i2cdriver library I developed previously.
  • If things go really well, begin frame buffer driver enhancements to use EDID to configure the driver properly.

Friday, 12 July 2013

pinmux issue resolved

Just a quickie update to say that I have overcome an issue I had last week. In my last report, I wrote that I had an issue configuring the I2C pins for the third I2C bus on the BeagleBone Black (AM335X). The root cause was that writes to the control module registers on the Cortex-A8 must be done in privileged mode and my driver runs in user space. I moved the pin configuration into the kernel and it executes as part of the arm specific initialization now. Now that the pins are getting setup properly, my driver works for the third I2C bus. Here's the output of my eepromread utility reading an EEPROM I attached to the third I2C bus:

This change is just a temporary fix until another developer gets a chance to create a pinmux server. With Minix being a microkernel based operating system, we try to keep the amount of code in the kernel to a minimum.

Sunday, 7 July 2013

Report 3 (July 1 - July 7)

This is Report #3. I plan to post these every Sunday. They will give a rundown of what I've done during the week, list any problems I had, and what I plan to do the following week. I'll be posting the reports both to the beagle-gsoc Google Group and to my blog.

Completed this week:
  • Rebased against mainline Minix.
  • Finished a simple I2C EEPROM test program that uses the /dev interface to write to specific locations in the EEPROM and read back what it wrote.
  • Did some testing, but I ran into an issue with the third i2c bus on the BBB (see "Issues" section below for details).
  • Enhanced i2cscan to support scanning using only the 1 byte read method (i.e. make it work similar to i2cdetect -r). Submitted patches upstream to NetBSD.
  • Defined an interface for accessing the i2c bus from other drivers and implemented it.
  • Created libi2cdriver and wrote common routines that would have been repeated in most i2c device drivers.
  • Updated the rc script to start the i2c bus drivers at boot and start the the proper i2c device drivers for the board it's being run on (BBB, BB, xM).
  • Started work on a CAT24C256 Driver (EEPROM). Implemented reading from specific locations on the chip.
  • Wrote a couple of blog posts: Using i2c-tools with Angstrom Linux on the BeagleBone Black, BeagleBone debugging with OpenOCD
Issues / Concerns / Challenges:
  • I spent well over 15 hours trying to figure out why my i2c bus code worked great for the first two I2C buses but not for the 3rd I2C bus. I got some tips in #beagle-gsoc from the group and from my mentors. Eventually, one of my mentors, Kees, figured out that the pinmux settings were not being applied. It turns out that writes to the control module need to be done in privileged mode. Since my code runs in userspace, writes to the control registers weren't having an affect. It seems that the only reason the first two buses worked was because they were left over from u-boot's pinmuxing.
Plan for next week:
  • Follow up with upstream on the patches to NetBSD's i2cscan program.
  • Finish the CAT24C256 Driver (EEPROM) by implementing writing to specific locations on the chip and developing an interface.
  • See how I can help the Minix team get the pinmux library working.
  • Code clean-up / testing / review.
  • If all goes well and time permits, submit what I've done so far to mainline Minix and write some documentation.
  • Begin working on a driver for reading extended display identification data.

Thursday, 4 July 2013

BeagleBone debugging with OpenOCD

The original BeagleBone (White) comes with a built-in JTAG emulator which allows you to debug your code without needing to go out and buy an expensive JTAG debugger. There's a neat tool called OpenOCD which, among many other things, can be used to debug code on your BeagleBone. I found that the few guides and tutorials available didn't work for me when I was trying to get it going, so I'm posting what I did in hopes that it'll help someone else and save them some time.

I did this on Gentoo Linux using OpenOCD 0.6.1, but similar steps should apply elsewhere. The first step is to install OpenOCD as well as usbutils. You'll need OpenOCD built with usb and ftd2xx support. In Gentoo, there are USE flags for this (USE="usb ftd2xx"). Connect your BeagleBone to your computer via USB, and then run `lsusb` as root. You should find a "Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC" in the list (ID: 0403:6010). If you don't, then the driver isn't installed properly.

The next part is to configure OpenOCD. This is where I ran into problems. There is a default configuration script for the BeagleBone called ti_beaglebone.cfg. You specify it when you run OpenOCD like this `openocd -s /usr/share/openocd/scripts -f board/ti_beaglebone.cfg`. The '-s' is to specify the base of the scripts directory.

Unfortunately, as you can see above, the default script doesn't work out of the box. It prompts you to add a line for your device with this message: "Error: please add "ft2232_device_desc <string>" or "ft2232_serial <string>" to your .cfg file". It wasn't 100% clear how to find out the serial number or device description so I experimented. I found that if you put in a bogus serial number, it will list the available serial numbers. I added the following line to /usr/share/openocd/scripts/board/ti_beaglebone.cfg:
ft2232_serial "XXX"
Then I ran openocd...

From that list I found the serial number "TIWKAE5U A". I edited /usr/share/openocd/scripts/board/ti_beaglebone.cfg again with that serial number and executed `openocd -s /usr/share/openocd/scripts -f board/ti_beaglebone.cfg` again. This time it worked.

Once the OpenOCD server is up, you can connect to it via telnet on port 4444. From there you can issue commands. In the example below I display the value of the I2C revision of the first I2C controller.