Common Flash Interface probe code.
David Woodhouse
dwmw2 at infradead.org
Mon Jun 12 08:04:50 EDT 2000
Anyone with memory-mapped CFI-compliant NOR flash, especially if it's not
in 16-bit mode like the one I'm testing on - could you test this probe code
for me?
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
$Id$
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <linux/errno.h>
#ifdef __arm__
/* Shoot me. Better still, shoot rmk. dwmw2 */
#undef writeb
#undef writew
#undef readb
#undef readw
#define readb(l) (*(unsigned char *)(l))
#define writeb(c,l) do {*((unsigned char *)(l)) = (c);} while (0)
#define readw(l) (*(unsigned short *)(l))
#define writew(c,l) do {*((unsigned short *)(l)) = (c);} while (0)
/* It's OK. You can look back now. */
#endif /* __arm__ */
struct cfi_ident {
__u8 qry[3];
__u16 P_ID;
__u16 P;
__u16 A_ID;
__u16 A;
__u8 VccMin;
__u8 VccMax;
__u8 VppMin;
__u8 VppMax;
__u8 WordWriteTimeoutTyp;
__u8 BufWriteTimeoutTyp;
__u8 BlockEraseTimeoutTyp;
__u8 ChipEraseTimeoutTyp;
__u8 WordWriteTimeoutMax;
__u8 BufWriteTimeoutMax;
__u8 BlockEraseTimeoutMax;
__u8 ChipEraseTimeoutMax;
__u8 DevSize;
__u16 InterfaceDesc;
__u16 MaxBufWriteSize;
__u8 NumEraseRegions;
__u32 EraseRegionInfo[1];
} __attribute__((packed));
void print_cfi_ident(struct cfi_ident *cfip);
int init_module(void)
{
unsigned char tmpzero;
unsigned long base = 0xd0000000;
int devwidth=0, numdevs=0;
int i;
struct cfi_ident cfip;
tmpzero=readb(base);
writeb(0x98, base+0x55);
if (*(unsigned char*) (base + 0x10) == 'Q' &&
*(unsigned char*) (base + 0x11) == 'R' &&
*(unsigned char*) (base + 0x12) == 'Y') {
printk("Found a CFI device at location %lx in 8 bit mode\n", base);
devwidth=1;
numdevs=1;
}
if (!devwidth) {
writew(0x9898, base+0xAA);
if (*(__u16*) (base + 0x20) == cpu_to_le16(0x0051) &&
*(__u16*) (base + 0x22) == cpu_to_le16(0x0052) &&
*(__u16*) (base + 0x24) == cpu_to_le16(0x0059)) {
printk("Found a CFI device at location %lx in 16 bit mode\n", base);
devwidth=2;
numdevs=1;
}
else if (*(__u16*) (base + 0x20) == 0x5151 &&
*(__u16*) (base + 0x22) == 0x5252 &&
*(__u16*) (base + 0x24) == 0x5959) {
printk("Found a coupled pair of CFI devices at location %lx in 8 bit mode\n", base);
devwidth=2;
numdevs=2;
}
}
if (!devwidth) {
writel(0x98989898, base+0x154);
if (*(__u32*) (base + 0x40) == cpu_to_le32(0x00000051) &&
*(__u32*) (base + 0x44) == cpu_to_le32(0x00000052) &&
*(__u32*) (base + 0x48) == cpu_to_le32(0x00000059)) {
/* This isn't actually in the CFI spec - only x8 and x16 are. */
printk("Found a CFI-like device at location %lx which appears to be in 32 bit mode(!)\n", base);
devwidth=4;
numdevs=1;
}
else if (*(__u32*) (base + 0x40) == cpu_to_le32(0x00510051) &&
*(__u32*) (base + 0x44) == cpu_to_le32(0x00520052) &&
*(__u32*) (base + 0x48) == cpu_to_le32(0x00590059)) {
printk("Found a coupled pair of CFI devices at location %lx in 16 bit mode\n", base);
devwidth=4;
numdevs=2;
}
else if (*(__u32*) (base + 0x40) == 0x51515151 &&
*(__u32*) (base + 0x44) == 0x52525252 &&
*(__u32*) (base + 0x48) == 0x59595959) {
printk("Found four side-by-side CFI devices at location %lx in 8 bit mode\n", base);
devwidth=4;
numdevs=4;
}
}
/* We won't bother with 64-bit wide detection at the moment */
if (!devwidth) {
printk("Found no CFI device at location %lx\n", base);
return -ENXIO;
}
for (i=0; i<sizeof(struct cfi_ident); i++) {
((unsigned char *)&cfip)[i] = *(unsigned char *) (base + ((0x10 + i)*devwidth));
}
#if 0
for (i=0; i<8; i++) {
printk ("CFI[%2.2X]: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
i*8,
((unsigned char *)&cfip)[(i*8)+0],
((unsigned char *)&cfip)[(i*8)+1],
((unsigned char *)&cfip)[(i*8)+2],
((unsigned char *)&cfip)[(i*8)+3],
((unsigned char *)&cfip)[(i*8)+4],
((unsigned char *)&cfip)[(i*8)+5],
((unsigned char *)&cfip)[(i*8)+6],
((unsigned char *)&cfip)[(i*8)+7]
);
}
#endif
print_cfi_ident(&cfip);
for (i=0; i<cfip.NumEraseRegions; i++) {
__u16 EraseRegionInfoNum = (*(unsigned char *) (base + ((0x2d + (4*i))*devwidth))) +
((*(unsigned char *) (base + ((0x2e + (4*i))*devwidth)) << 8));
__u16 EraseRegionInfoSize = (*(unsigned char *) (base + ((0x2f + (4*i))*devwidth))) +
((*(unsigned char *) (base + ((0x30 + (4*i))*devwidth)) << 8));
printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n",
i, EraseRegionInfoSize * 256, EraseRegionInfoNum+1);
}
return -ENXIO;
}
void print_cfi_ident(struct cfi_ident *cfip)
{
if (cfip->qry[0] == 'Q' && cfip->qry[1] == 'R' && cfip->qry[2] == 'Y') {
printk("Primary vendor: %4.4X\n", le16_to_cpu(cfip->P_ID));
printk("Alternatve vendor: %4.4X\n", le16_to_cpu(cfip->A_ID));
if (cfip->P)
printk("Primary Algorithm Table at %4.4X\n", le16_to_cpu(cfip->P));
else
printk("No Primary Algorithm Table\n");
if (cfip->A)
printk("Alternate Algorithm Table at %4.4X\n", le16_to_cpu(cfip->A));
else
printk("No Alternate Algorithm Table\n");
printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
if (cfip->VppMin) {
printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
}
else
printk("No Vpp line\n");
printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp);
printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) {
printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp);
printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
}
else
printk("Full buffer write not supported\n");
printk("Typical block erase timeout: %d µs\n", 1<<cfip->BlockEraseTimeoutTyp);
printk("Maximum block erase timeout: %d µs\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) {
printk("Typical chip erase timeout: %d µs\n", 1<<cfip->ChipEraseTimeoutTyp);
printk("Maximum chip erase timeout: %d µs\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
}
else
printk("Chip erase not supported\n");
printk("Device size: 0x%X bytes (%d Mb)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20));
printk("Flash Device Interface description: 0x%4.4X\n", le16_to_cpu(cfip->InterfaceDesc));
printk("Max. bytes in buffer write: 0x%x\n", 1<< le16_to_cpu(cfip->MaxBufWriteSize));
printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions);
}
else printk("Invalid CFI ident structure.\n");
}
--
dwmw2
To unsubscribe, send "unsubscribe mtd" to majordomo at infradead.org
More information about the linux-mtd
mailing list