public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* Common Flash Interface probe code.
@ 2000-06-12 12:04 David Woodhouse
  2000-06-13  5:53 ` Jason Gunthorpe
  0 siblings, 1 reply; 12+ messages in thread
From: David Woodhouse @ 2000-06-12 12:04 UTC (permalink / raw)
  To: mtd

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@infradead.org

^ permalink raw reply	[flat|nested] 12+ messages in thread
* Common Flash Interface probe code
@ 2004-07-06  7:45 Reynolds-Lear, Matthew
  0 siblings, 0 replies; 12+ messages in thread
From: Reynolds-Lear, Matthew @ 2004-07-06  7:45 UTC (permalink / raw)
  To: linux-mtd


Hi,
I've written a flash driver based on CFI.  It was going so well until I
needed to detect if a device was top or bottom boot.
 
Basically, from looking at different manufacturer datasheets, I am
totally lost as to the correct approach to determining if a device is
top or bottom boot, and if the CFI device's geometry data is presented
in a different order depending if the device is top or bottom boot. 
 
As I see it, here are my issues:
 
1) I could determine if a device is top or bottom boot by reading the
private vendor specific table in the CFI.  However, it seems that this
table is not standardised and each manufacturer has their own version of
it.  Because the CFI indicates what algorithm can be used to perform
operations on the device, you shouldn't have to check the device ID etc
to determine anything about it - thus the idea behind the CFI.  It seems
though that each manufacturer can put slightly different data in the
private table so to find out exactly you'd need to read it's
manufacturer ID.  When you've done this you might as well have done a
JEDEC probe!
 
2) Some manufacturers (e.g. AMD) don't even indicate in their private
table if the device is top or bottom boot so how are users of the CFI
supposed to find out apart from fetching the ID and looking it up in
some sort of table (again, the CFI was intended to remove having to do
this)?
 
3) From reading some datasheets, some devices present their device
geometry CFI data differently if the device is top or bottom boot.
Thing is, other datasheets indicate that some devices do not do this.  
 
Basically, I want to avoid having to read the device's ID to determine
if it is top or bottom boot and what its sector map is since this
involves keeping a flash driver look up table up to date and drop in
replacement of flash devices won't be possible without updating this
table.  It seems that some device's CFI data in the private table will
do this tell me if it is top or bottom boot but the format of the table
is completely specific to the manufacturer (so I'd have to check the
manufacturer ID anyway) but other device's CFI data doesn't provide this
information so how are we supposed to know?!
 
I've seen a few postings related to this problem and can't find anything
'solid' which will assist.
 
Can anyone help?  It's all a bit frustrating.
 
Many thanks.
  Matt
-- 

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2004-07-06 17:05 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2000-06-12 12:04 Common Flash Interface probe code David Woodhouse
2000-06-13  5:53 ` Jason Gunthorpe
2000-06-13  6:34   ` M-Systems Disk-On-Chip driver Adi Linden
2000-06-13  7:44     ` David Woodhouse
2000-06-13 13:48       ` Adi Linden
2000-06-13 14:28         ` David Woodhouse
2000-06-13  7:40   ` Common Flash Interface probe code David Woodhouse
2000-06-13 15:30     ` Jason Gunthorpe
2000-06-13 16:11       ` David Woodhouse
2000-06-13 17:16         ` Jason Gunthorpe
2000-06-13 17:54           ` David Woodhouse
  -- strict thread matches above, loose matches on Subject: below --
2004-07-06  7:45 Reynolds-Lear, Matthew

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox