NWR04B: Secret Knocks

So I came to the the realization that I've been including the driver for the wrong damn flash chip. This came straight from Codeman's tree, which in turn is based on (I think) the HRI tree. Codeman's .config file for uClinux included drivers for the SST39V flash chip, which just plain isn't right for this router. It's possible that he had a different revision of the board or some such, but I suspect that since he wrote to the flash using the JTAG interface, the issue just never came up.

I grabbed the datasheet for the Hynix chip, and it's not that different from what's in the SST driver...but it's just different enough that it's causes problems. First of all, you've got to give the secret knock before writing a byte to flash -- apparently to keep electrical noise (or some such) from accidentally erasing important data. In the SST driver, it looks like this:

map->write8(map, 0xaa, 0x5555)
map->write8(map, 0x55, 0x2aaa);
map->write8(map, 0xa0, 0x5555);

But according to the Hynix datasheet, it should look like this:

map->write8(map, 0xaa, 0xaaa);
map->write8(map, 0x55, 0x555);
map->write8(map, 0xa0, 0xaaa);

Okay, easy enough to change. Still didn't work, though, when I tried to copy the jffs2 image to /dev/mtd1; the writes just keep on failing. But then I remembered that only an erase can turn on a particular bit -- ordinary writes can only flip 'em off.

Just for fun, I tried copying an image where, compared to what was in flash already, bits would only have to be turned off -- and sure enough, that worked. Didn't survive a reboot, though...weird.

On, then, to the bit of the datasheet that deals with erasing. There's the secret knock for erasing, but that was easy enough to fix. The last part of the secret knock tells the chip which 0x1000-byte sector to erase. With the SST driver, it looks like you just use the beginning of the 0x1000 byte sector you want to erase, making sure that it's on an erase boundary (ie, some multiple of 0x1000).

The Hynix, though...I'm having trouble figuring it out. The sector I'm trying to erase starts at 0xf0000, so I'll use that as an example. The datasheet has a table listing what address to write the final command, and it says that the addres should be binary 01111??? -- the last three bits don't matter. But this table also seems to say these should be bits 19 through 12 (counting from zero). If that's the case, then we're just shifting the address over by one, which means writing the final command to 0x78000. But that doesn't seem to work.

In another part of the datasheet, it seems to imply that the sector address is just 8 bits long -- in which case, we're shifting the address right by 13 bits. That seems like a very strange number. It works out to a write to 0x78, and that doesn't work, either. The only thing that I can think of is that flash memory is supposed to be mapped to 0x20000000, so maybe it's 0x2f000000 that should be shifted as necessary. But that doesn't make any sense to me.

And the fact that the bits I managed to flip don't survive a reboot makes me suspicious -- am I trying to write to RAM or some such rather than flash? If anyone out there knows this sort of thing, I'd be grateful if you could take a look at the datasheet and see if you can figure out what I'm doing wrong.