typedef struct Flash Flash;
typedef struct Flashchip Flashchip;
typedef struct Flashpart Flashpart;
typedef struct Flashregion Flashregion;

/*
* logical partitions
*/
enum {
       Maxflashpart = 8
};

struct Flashpart {
       char*   name;
       ulong   start;
       ulong   end;
};

enum {
       Maxflashregion = 4
};

/*
* physical erase block regions
*/
struct Flashregion {
       int     n;              /* number of blocks in region */
       ulong   start;          /* physical base address (allowing for banks) */
       ulong   end;
       ulong   erasesize;
       ulong   eraseshift;     /* log2(erasesize) */
       ulong   pagesize;       /* if non-0, size of pages within erase block */
       ulong   pageshift;      /* log2(pagesize) */
       ulong   spares;         /* spare bytes per page, for ecc, etc. */
};

/*
* one of a set of chips in a given region
*/
struct Flashchip {
       int     nr;
       Flashregion regions[Maxflashregion];

       uchar   id;             /* flash manufacturer ID */
       ushort  devid;          /* flash device ID */
       int     width;          /* bytes per flash line */
       int     maxwb;          /* max write buffer size */
       ulong   devsize;        /* physical device size */
       int     alg;            /* programming algorithm (if CFI) */
       int     protect;        /* software protection */
};

/*
* structure defining a contiguous region of flash memory
*/
struct Flash {
       QLock;                  /* interlock on flash operations */
       Flash*  next;

       /* following are filled in before calling Flash.reset */
       char*   type;
       void*   addr;
       ulong   size;
       int     xip;            /* executing in place: don't query */
       int     (*reset)(Flash*);

       /* following are filled in by the reset routine */
       int     (*eraseall)(Flash*);
       int     (*erasezone)(Flash*, Flashregion*, ulong);
       /* (optional) reads of correct width and alignment */
       int     (*read)(Flash*, ulong, void*, long);
       /* writes of correct width and alignment */
       int     (*write)(Flash*, ulong, void*, long);
       int     (*suspend)(Flash*);
       int     (*resume)(Flash*);
       int     (*attach)(Flash*);

       /* following might be filled in by either archflashreset or reset routine */
       int     nr;
       Flashregion regions[Maxflashregion];

       uchar   id;             /* flash manufacturer ID */
       ushort  devid;          /* flash device ID */
       int     width;          /* bytes per flash line */
       int     interleave;     /* addresses are interleaved across set of chips */
       int     bshift;         /* byte addresses are shifted */
       ulong   cmask;          /* command mask for interleaving */
       int     maxwb;          /* max write buffer size */
       ulong   devsize;        /* physical device size */
       int     alg;            /* programming algorithm (if CFI) */
       void*   data;           /* flash type routines' private storage, or nil */
       Flashpart part[Maxflashpart];   /* logical partitions */
       int     protect;        /* software protection */
       char*   sort;           /* "nand", "nor", "serial", nil (unspecified) */
};

/*
* called by link routine of driver for specific flash type: arguments are
* conventional name for card type/model, and card driver's reset routine.
*/
void    addflashcard(char*, int (*)(Flash*));

/*
* called by devflash.c:/^flashreset; if flash exists,
* sets type, address, and size in bytes of flash
* and returns 0; returns -1 if flash doesn't exist
*/
int     archflashreset(int, Flash*);

/*
* enable/disable write protect
*/
void    archflashwp(Flash*, int);

/*
* flash access taking width and interleave into account
*/
int     flashget(Flash*, ulong);
void    flashput(Flash*, ulong, int);

/*
* Architecture specific routines for managing nand devices
*/

/*
* do any device spcific initialisation
*/
void archnand_init(Flash*);

/*
* if claim is 1, claim device exclusively, and enable it (power it up)
* if claim is 0, release, and disable it (power it down)
* claiming may be as simple as a qlock per device
*/
void archnand_claim(Flash*, int claim);

/*
* set command latch enable (CLE) and address latch enable (ALE)
* appropriately
*/
void archnand_setCLEandALE(Flash*, int cle, int ale);

/*
* write a sequence of bytes to the device
*/
void archnand_write(Flash*, void *buf, int len);

/*
* read a sequence of bytes from the device
* if buf is 0, throw away the data
*/
void archnand_read(Flash*, void *buf, int len);