All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Woodhouse <dwmw2@infradead.org>
To: mtd@infradead.org
Subject: Common Flash Interface probe code.
Date: Mon, 12 Jun 2000 13:04:50 +0100	[thread overview]
Message-ID: <30028.960811490@cygnus.co.uk> (raw)

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

             reply	other threads:[~2000-06-12 12:05 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2000-06-12 12:04 David Woodhouse [this message]
2000-06-13  5:53 ` Common Flash Interface probe code 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=30028.960811490@cygnus.co.uk \
    --to=dwmw2@infradead.org \
    --cc=mtd@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.