Table of Contents

Blackfin One Time Programmable (OTP) Memory

Many Blackfins now have on-chip One Time Programmable (OTP) memory. This document will cover this OTP memory and is not a general document for any other OTP flash memory device. The exact size of the OTP region may vary according to your Blackfin processor variant, so consult the datasheet for exact specifications.

The OTP memory is backed by physical fuses which are “blown” in order to change bit states. Due to the destructive nature of this operation, you can only change bits once. Protection bits and ECC support is included to lock memory from further writing, and to allow for error corrections in case a bit goes bad.

The OTP memory is not directly accessible (in other words, it is not a memory mapped region). Control MMRs are used to communicate with the OTP peripheral (setting up timings, reading/writing values, etc…). Since programming of the MMRs can be error prone, helper functions have been included in the Boot ROM. This is the only supported method for accessing the OTP region.

The OTP memory is split up into 128 bit pages. Read/write accesses occur in increments of 64 bit half pages. Often times the pages have predefined meanings (such as the Factory Programmed Settings (FPS) pages), or the Customer Programmable Settings (CPS) pages. The memory is also split up into an “unsecure” region (which means it can be used at any time) and a “secure” region (which means it can only be used when the processor is in “secure” mode). Consult the HRM for further information on these topics.

Accessing secure regions of OTP is not handled specially for you. In order for it to work, you need to get the processor into secure mode first.

While reading the OTP memory allows for flexible operating conditions, writing the OTP memory is not as forgiving. Consult the datasheet to make sure you are operating within specified conditions before attempting to do any write.

Boot ROM

The Blackfin on-chip ROM contains helper functions for accessing the OTP memory. We will not discuss this interface further; please refer to the HRM for your processor variant for more information.

uint32_t bfrom_OtpCommand(uint32_t dCommand, uint32_t dValue);
uint32_t bfrom_OtpWrite(uint32_t dPage, uint32_t dFlags, uint64_t *pPageContent);
uint32_t bfrom_OtpRead(uint32_t dPage, uint32_t dFlags, uint64_t *pPageContent);

U-Boot

There is a simple otp command to read and write OTP memory. It follows the typical U-Boot command style and can be found at common/cmd_otp.c.

bfin> help otp
otp read <addr> <page> [count] [half]
otp write [--force] <addr> <page> [count] [half]
    - read/write 'count' half-pages starting at page 'page' (offset 'half')

Here is an example reading the first 10 half pages and storing the results at address 0x100.

bfin> otp read 0x100 0 10
OTP memory read: addr 0x00000100  page 0x000  count 16 ... W...........W... done

Linux

A simple character device driver has been created so you can read/write OTP memory from user space. The driver can be found at linux-2.6.x/drivers/char/bfin-otp.c.

First enable the driver in your kernel configuration menu. Obviously, you should only enable writing support if you intend on writing OTP.

Device Drivers  --->
  Character devices  --->
    <*> Blackfin On-Chip OTP Memory Support
    [ ]   Enable writing support of OTP pages

While booting, you should see something like:

bfin-otp: initialized

Then to access the OTP memory, just open /dev/bfin-otp and use it like a normal character device. Make sure you only do reads/writes in 64 bit increments (8 bytes or 1 half page), and you can use the standard seek functions to select the half page (in units of bytes) you want to start reading from.

A quick example is to use dd to read the OTP memory:

root:/> dd if=/dev/bfin-otp of=otp.bin bs=8 count=100
100+0 records in
100+0 records out
root:/> ls -l otp.bin
-rw-r--r--    1 root     root          800 Jan  1 00:41 otp.bin

Notice how the block size was set to 8 bytes (or 64 bits). Any other increment will result in an error since the ROM functions only support reading in chunks of half pages.

Writing

Before you can write to the device, you have to initiate a simple unlock ioctl. This is to prevent inadvertent writes and has no relation to the OTP_LOCK operation. Once you've opened the device and have a file descriptor, issue:

#include <sys/ioctl.h>
#include <mtd/mtd-abi.h>
...
    ioctl(fd, MEMUNLOCK);

Then use the normal write and lseek functions to write out data. The same limitation mentioned above with valid lengths applies here as well. You can only program half-pages at a time, so it is up to you to handle this. The kernel will not split up/overlay writes for you.

Conversely, once you've finished writing, you should inform the kernel by doing:

ioctl(fd, MEMLOCK);

Page Locking

If you wish to lock a page in OTP (the OTP_LOCK operation), then you can use the OTPLOCK ioctl:

#include <sys/ioctl.h>
#include <mtd/mtd-abi.h>
...
    ioctl(fd, OTPLOCK, 0x1C);

This will lock page 0x1C in OTP.