Ticket #6442: kamikaze-trunk-brcm24-sflash.patch

File kamikaze-trunk-brcm24-sflash.patch, 51.9 KB (added by Tony Butler <spudz76@…>, 7 years ago)

(same effect, for trunk)

  • target/linux/brcm-2.4/files/arch/mips/bcm947xx/include/bcmutils.h

     
     1/* 
     2 * Misc useful os-independent macros and functions. 
     3 * 
     4 * Copyright 2007, Broadcom Corporation 
     5 * All Rights Reserved. 
     6 *  
     7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 
     8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 
     9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 
     10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 
     11 * $Id$ 
     12 */ 
     13 
     14#ifndef _bcmutils_h_ 
     15#define _bcmutils_h_ 
     16 
     17/* ctype replacement */ 
     18#define _BCM_U  0x01    /* upper */ 
     19#define _BCM_L  0x02    /* lower */ 
     20#define _BCM_D  0x04    /* digit */ 
     21#define _BCM_C  0x08    /* cntrl */ 
     22#define _BCM_P  0x10    /* punct */ 
     23#define _BCM_S  0x20    /* white space (space/lf/tab) */ 
     24#define _BCM_X  0x40    /* hex digit */ 
     25#define _BCM_SP 0x80    /* hard space (0x20) */ 
     26 
     27extern const unsigned char bcm_ctype[]; 
     28#define bcm_ismask(x)   (bcm_ctype[(int)(unsigned char)(x)]) 
     29 
     30#define bcm_isalnum(c)  ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) 
     31#define bcm_isalpha(c)  ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) 
     32#define bcm_iscntrl(c)  ((bcm_ismask(c)&(_BCM_C)) != 0) 
     33#define bcm_isdigit(c)  ((bcm_ismask(c)&(_BCM_D)) != 0) 
     34#define bcm_isgraph(c)  ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) 
     35#define bcm_islower(c)  ((bcm_ismask(c)&(_BCM_L)) != 0) 
     36#define bcm_isprint(c)  ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) 
     37#define bcm_ispunct(c)  ((bcm_ismask(c)&(_BCM_P)) != 0) 
     38#define bcm_isspace(c)  ((bcm_ismask(c)&(_BCM_S)) != 0) 
     39#define bcm_isupper(c)  ((bcm_ismask(c)&(_BCM_U)) != 0) 
     40#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) 
     41#define bcm_tolower(c)  (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) 
     42#define bcm_toupper(c)  (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) 
     43 
     44/* Buffer structure for collecting string-formatted data  
     45* using bcm_bprintf() API. 
     46* Use bcm_binit() to initialize before use 
     47*/ 
     48 
     49struct bcmstrbuf { 
     50        char *buf;      /* pointer to current position in origbuf */ 
     51        unsigned int size;      /* current (residual) size in bytes */ 
     52        char *origbuf;  /* unmodified pointer to orignal buffer */ 
     53        unsigned int origsize;  /* unmodified orignal buffer size in bytes */ 
     54}; 
     55 
     56/* ** driver-only section ** */ 
     57#ifdef BCMDRIVER 
     58#include <osl.h> 
     59 
     60#define GPIO_PIN_NOTDEFINED     0x20    /* Pin not defined */ 
     61 
     62/* 
     63 * Spin at most 'us' microseconds while 'exp' is true. 
     64 * Caller should explicitly test 'exp' when this completes 
     65 * and take appropriate error action if 'exp' is still true. 
     66 */ 
     67#define SPINWAIT(exp, us) { \ 
     68        uint countdown = (us) + 9; \ 
     69        while ((exp) && (countdown >= 10)) {\ 
     70                OSL_DELAY(10); \ 
     71                countdown -= 10; \ 
     72        } \ 
     73} 
     74 
     75 
     76/* osl multi-precedence packet queue */ 
     77#ifndef PKTQ_LEN_DEFAULT 
     78#define PKTQ_LEN_DEFAULT        128     /* Max 128 packets */ 
     79#endif 
     80#ifndef PKTQ_MAX_PREC 
     81#define PKTQ_MAX_PREC           16      /* Maximum precedence levels */ 
     82#endif 
     83 
     84typedef struct pktq_prec { 
     85        void *head;     /* first packet to dequeue */ 
     86        void *tail;     /* last packet to dequeue */ 
     87        uint16 len;     /* number of queued packets */ 
     88        uint16 max;     /* maximum number of queued packets */ 
     89} pktq_prec_t; 
     90 
     91 
     92/* multi-priority pkt queue */ 
     93struct pktq { 
     94        uint16 num_prec;        /* number of precedences in use */ 
     95        uint16 hi_prec;         /* rapid dequeue hint (>= highest non-empty prec) */ 
     96        uint16 max;             /* total max packets */ 
     97        uint16 len;             /* total number of packets */ 
     98        /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ 
     99        struct pktq_prec q[PKTQ_MAX_PREC]; 
     100}; 
     101 
     102/* simple, non-priority pkt queue */ 
     103struct spktq { 
     104        uint16 num_prec;        /* number of precedences in use (always 1) */ 
     105        uint16 hi_prec;         /* rapid dequeue hint (>= highest non-empty prec) */ 
     106        uint16 max;             /* total max packets */ 
     107        uint16 len;             /* total number of packets */ 
     108        /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ 
     109        struct pktq_prec q[1]; 
     110}; 
     111 
     112#define PKTQ_PREC_ITER(pq, prec)        for (prec = (pq)->num_prec - 1; prec >= 0; prec--) 
     113 
     114/* forward definition of ether_addr structure used by some function prototypes */ 
     115 
     116struct ether_addr; 
     117 
     118/* operations on a specific precedence in packet queue */ 
     119 
     120#define pktq_psetmax(pq, prec, _max)    ((pq)->q[prec].max = (_max)) 
     121#define pktq_plen(pq, prec)             ((pq)->q[prec].len) 
     122#define pktq_pavail(pq, prec)           ((pq)->q[prec].max - (pq)->q[prec].len) 
     123#define pktq_pfull(pq, prec)            ((pq)->q[prec].len >= (pq)->q[prec].max) 
     124#define pktq_pempty(pq, prec)           ((pq)->q[prec].len == 0) 
     125 
     126#define pktq_ppeek(pq, prec)            ((pq)->q[prec].head) 
     127#define pktq_ppeek_tail(pq, prec)       ((pq)->q[prec].tail) 
     128 
     129extern void *pktq_penq(struct pktq *pq, int prec, void *p); 
     130extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); 
     131extern void *pktq_pdeq(struct pktq *pq, int prec); 
     132extern void *pktq_pdeq_tail(struct pktq *pq, int prec); 
     133/* Empty the queue at particular precedence level */ 
     134extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir); 
     135/* Remove a specified packet from its queue */ 
     136extern bool pktq_pdel(struct pktq *pq, void *p, int prec); 
     137 
     138/* operations on a set of precedences in packet queue */ 
     139 
     140extern int pktq_mlen(struct pktq *pq, uint prec_bmp); 
     141extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); 
     142 
     143/* operations on packet queue as a whole */ 
     144 
     145#define pktq_len(pq)                    ((int)(pq)->len) 
     146#define pktq_max(pq)                    ((int)(pq)->max) 
     147#define pktq_avail(pq)                  ((int)((pq)->max - (pq)->len)) 
     148#define pktq_full(pq)                   ((pq)->len >= (pq)->max) 
     149#define pktq_empty(pq)                  ((pq)->len == 0) 
     150 
     151/* operations for single precedence queues */ 
     152#define pktenq(pq, p)           pktq_penq(((struct pktq *)pq), 0, (p)) 
     153#define pktenq_head(pq, p)      pktq_penq_head(((struct pktq *)pq), 0, (p)) 
     154#define pktdeq(pq)              pktq_pdeq(((struct pktq *)pq), 0) 
     155#define pktdeq_tail(pq)         pktq_pdeq_tail(((struct pktq *)pq), 0) 
     156#define pktqinit(pq, len) pktq_init(((struct pktq *)pq), 1, len) 
     157 
     158extern void pktq_init(struct pktq *pq, int num_prec, int max_len); 
     159/* prec_out may be NULL if caller is not interested in return value */ 
     160extern void *pktq_deq(struct pktq *pq, int *prec_out); 
     161extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); 
     162extern void *pktq_peek(struct pktq *pq, int *prec_out); 
     163extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); 
     164extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); /* Empty the entire queue */ 
     165extern int pktq_setmax(struct pktq *pq, int max_len); 
     166 
     167/* externs */ 
     168/* packet */ 
     169extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); 
     170extern uint pkttotlen(osl_t *osh, void *p); 
     171extern void *pktlast(osl_t *osh, void *p); 
     172 
     173/* Get priority from a packet and pass it back in scb (or equiv) */ 
     174extern uint pktsetprio(void *pkt, bool update_vtag); 
     175#define PKTPRIO_VDSCP   0x100           /* DSCP prio found after VLAN tag */ 
     176#define PKTPRIO_VLAN    0x200           /* VLAN prio found */ 
     177#define PKTPRIO_UPD     0x400           /* DSCP used to update VLAN prio */ 
     178#define PKTPRIO_DSCP    0x800           /* DSCP prio found */ 
     179 
     180/* string */ 
     181extern int BCMROMFN(bcm_atoi)(char *s); 
     182extern ulong BCMROMFN(bcm_strtoul)(char *cp, char **endp, uint base); 
     183extern char *BCMROMFN(bcmstrstr)(char *haystack, char *needle); 
     184extern char *BCMROMFN(bcmstrcat)(char *dest, const char *src); 
     185extern char *BCMROMFN(bcmstrncat)(char *dest, const char *src, uint size); 
     186extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); 
     187/* ethernet address */ 
     188extern char *bcm_ether_ntoa(struct ether_addr *ea, char *buf); 
     189extern int BCMROMFN(bcm_ether_atoe)(char *p, struct ether_addr *ea); 
     190 
     191/* ip address */ 
     192struct ipv4_addr; 
     193extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); 
     194 
     195/* delay */ 
     196extern void bcm_mdelay(uint ms); 
     197/* variable access */ 
     198extern char *getvar(char *vars, const char *name); 
     199extern int getintvar(char *vars, const char *name); 
     200extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); 
     201#ifdef BCMPERFSTATS 
     202extern void bcm_perf_enable(void); 
     203extern void bcmstats(char *fmt); 
     204extern void bcmlog(char *fmt, uint a1, uint a2); 
     205extern void bcmdumplog(char *buf, int size); 
     206extern int bcmdumplogent(char *buf, uint idx); 
     207#else 
     208#define bcm_perf_enable() 
     209#define bcmstats(fmt) 
     210#define bcmlog(fmt, a1, a2) 
     211#define bcmdumplog(buf, size)   *buf = '\0' 
     212#define bcmdumplogent(buf, idx) -1 
     213#endif /* BCMPERFSTATS */ 
     214extern char *bcm_nvram_vars(uint *length); 
     215extern int bcm_nvram_cache(void *sbh); 
     216 
     217/* Support for sharing code across in-driver iovar implementations. 
     218 * The intent is that a driver use this structure to map iovar names 
     219 * to its (private) iovar identifiers, and the lookup function to 
     220 * find the entry.  Macros are provided to map ids and get/set actions 
     221 * into a single number space for a switch statement. 
     222 */ 
     223 
     224/* iovar structure */ 
     225typedef struct bcm_iovar { 
     226        const char *name;       /* name for lookup and display */ 
     227        uint16 varid;           /* id for switch */ 
     228        uint16 flags;           /* driver-specific flag bits */ 
     229        uint16 type;            /* base type of argument */ 
     230        uint16 minlen;          /* min length for buffer vars */ 
     231} bcm_iovar_t; 
     232 
     233/* varid definitions are per-driver, may use these get/set bits */ 
     234 
     235/* IOVar action bits for id mapping */ 
     236#define IOV_GET 0 /* Get an iovar */ 
     237#define IOV_SET 1 /* Set an iovar */ 
     238 
     239/* Varid to actionid mapping */ 
     240#define IOV_GVAL(id)            ((id)*2) 
     241#define IOV_SVAL(id)            (((id)*2)+IOV_SET) 
     242#define IOV_ISSET(actionid)     ((actionid & IOV_SET) == IOV_SET) 
     243 
     244/* flags are per-driver based on driver attributes */ 
     245 
     246extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); 
     247extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); 
     248 
     249#endif  /* BCMDRIVER */ 
     250 
     251/* Base type definitions */ 
     252#define IOVT_VOID       0       /* no value (implictly set only) */ 
     253#define IOVT_BOOL       1       /* any value ok (zero/nonzero) */ 
     254#define IOVT_INT8       2       /* integer values are range-checked */ 
     255#define IOVT_UINT8      3       /* unsigned int 8 bits */ 
     256#define IOVT_INT16      4       /* int 16 bits */ 
     257#define IOVT_UINT16     5       /* unsigned int 16 bits */ 
     258#define IOVT_INT32      6       /* int 32 bits */ 
     259#define IOVT_UINT32     7       /* unsigned int 32 bits */ 
     260#define IOVT_BUFFER     8       /* buffer is size-checked as per minlen */ 
     261#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) 
     262 
     263/* Initializer for IOV type strings */ 
     264#define BCM_IOV_TYPE_INIT { \ 
     265        "void", \ 
     266        "bool", \ 
     267        "int8", \ 
     268        "uint8", \ 
     269        "int16", \ 
     270        "uint16", \ 
     271        "int32", \ 
     272        "uint32", \ 
     273        "buffer", \ 
     274        "" } 
     275 
     276#define BCM_IOVT_IS_INT(type) (\ 
     277        (type == IOVT_BOOL) || \ 
     278        (type == IOVT_INT8) || \ 
     279        (type == IOVT_UINT8) || \ 
     280        (type == IOVT_INT16) || \ 
     281        (type == IOVT_UINT16) || \ 
     282        (type == IOVT_INT32) || \ 
     283        (type == IOVT_UINT32)) 
     284 
     285/* ** driver/apps-shared section ** */ 
     286 
     287#define BCME_STRLEN             64      /* Max string length for BCM errors */ 
     288#define VALID_BCMERROR(e)  ((e <= 0) && (e >= BCME_LAST)) 
     289 
     290 
     291/* 
     292 * error codes could be added but the defined ones shouldn't be changed/deleted 
     293 * these error codes are exposed to the user code 
     294 * when ever a new error code is added to this list 
     295 * please update errorstring table with the related error string and 
     296 * update osl files with os specific errorcode map 
     297*/ 
     298 
     299#define BCME_OK                         0       /* Success */ 
     300#define BCME_ERROR                      -1      /* Error generic */ 
     301#define BCME_BADARG                     -2      /* Bad Argument */ 
     302#define BCME_BADOPTION                  -3      /* Bad option */ 
     303#define BCME_NOTUP                      -4      /* Not up */ 
     304#define BCME_NOTDOWN                    -5      /* Not down */ 
     305#define BCME_NOTAP                      -6      /* Not AP */ 
     306#define BCME_NOTSTA                     -7      /* Not STA  */ 
     307#define BCME_BADKEYIDX                  -8      /* BAD Key Index */ 
     308#define BCME_RADIOOFF                   -9      /* Radio Off */ 
     309#define BCME_NOTBANDLOCKED              -10     /* Not  band locked */ 
     310#define BCME_NOCLK                      -11     /* No Clock */ 
     311#define BCME_BADRATESET                 -12     /* BAD Rate valueset */ 
     312#define BCME_BADBAND                    -13     /* BAD Band */ 
     313#define BCME_BUFTOOSHORT                -14     /* Buffer too short */ 
     314#define BCME_BUFTOOLONG                 -15     /* Buffer too long */ 
     315#define BCME_BUSY                       -16     /* Busy */ 
     316#define BCME_NOTASSOCIATED              -17     /* Not Associated */ 
     317#define BCME_BADSSIDLEN                 -18     /* Bad SSID len */ 
     318#define BCME_OUTOFRANGECHAN             -19     /* Out of Range Channel */ 
     319#define BCME_BADCHAN                    -20     /* Bad Channel */ 
     320#define BCME_BADADDR                    -21     /* Bad Address */ 
     321#define BCME_NORESOURCE                 -22     /* Not Enough Resources */ 
     322#define BCME_UNSUPPORTED                -23     /* Unsupported */ 
     323#define BCME_BADLEN                     -24     /* Bad length */ 
     324#define BCME_NOTREADY                   -25     /* Not Ready */ 
     325#define BCME_EPERM                      -26     /* Not Permitted */ 
     326#define BCME_NOMEM                      -27     /* No Memory */ 
     327#define BCME_ASSOCIATED                 -28     /* Associated */ 
     328#define BCME_RANGE                      -29     /* Not In Range */ 
     329#define BCME_NOTFOUND                   -30     /* Not Found */ 
     330#define BCME_WME_NOT_ENABLED            -31     /* WME Not Enabled */ 
     331#define BCME_TSPEC_NOTFOUND             -32     /* TSPEC Not Found */ 
     332#define BCME_ACM_NOTSUPPORTED           -33     /* ACM Not Supported */ 
     333#define BCME_NOT_WME_ASSOCIATION        -34     /* Not WME Association */ 
     334#define BCME_SDIO_ERROR                 -35     /* SDIO Bus Error */ 
     335#define BCME_DONGLE_DOWN                -36     /* Dongle Not Accessible */ 
     336#define BCME_VERSION                    -37 /* Incorrect version */ 
     337#define BCME_LAST                       BCME_VERSION 
     338 
     339/* These are collection of BCME Error strings */ 
     340#define BCMERRSTRINGTABLE {             \ 
     341        "OK",                           \ 
     342        "Undefined error",              \ 
     343        "Bad Argument",                 \ 
     344        "Bad Option",                   \ 
     345        "Not up",                       \ 
     346        "Not down",                     \ 
     347        "Not AP",                       \ 
     348        "Not STA",                      \ 
     349        "Bad Key Index",                \ 
     350        "Radio Off",                    \ 
     351        "Not band locked",              \ 
     352        "No clock",                     \ 
     353        "Bad Rate valueset",            \ 
     354        "Bad Band",                     \ 
     355        "Buffer too short",             \ 
     356        "Buffer too long",              \ 
     357        "Busy",                         \ 
     358        "Not Associated",               \ 
     359        "Bad SSID len",                 \ 
     360        "Out of Range Channel",         \ 
     361        "Bad Channel",                  \ 
     362        "Bad Address",                  \ 
     363        "Not Enough Resources",         \ 
     364        "Unsupported",                  \ 
     365        "Bad length",                   \ 
     366        "Not Ready",                    \ 
     367        "Not Permitted",                \ 
     368        "No Memory",                    \ 
     369        "Associated",                   \ 
     370        "Not In Range",                 \ 
     371        "Not Found",                    \ 
     372        "WME Not Enabled",              \ 
     373        "TSPEC Not Found",              \ 
     374        "ACM Not Supported",            \ 
     375        "Not WME Association",          \ 
     376        "SDIO Bus Error",               \ 
     377        "Dongle Not Accessible",        \ 
     378        "Incorrect version"     \ 
     379} 
     380 
     381#ifndef ABS 
     382#define ABS(a)                  (((a) < 0)?-(a):(a)) 
     383#endif /* ABS */ 
     384 
     385#ifndef MIN 
     386#define MIN(a, b)               (((a) < (b))?(a):(b)) 
     387#endif /* MIN */ 
     388 
     389#ifndef MAX 
     390#define MAX(a, b)               (((a) > (b))?(a):(b)) 
     391#endif /* MAX */ 
     392 
     393#define CEIL(x, y)              (((x) + ((y)-1)) / (y)) 
     394#define ROUNDUP(x, y)           ((((x)+((y)-1))/(y))*(y)) 
     395#define ISALIGNED(a, x)         (((a) & ((x)-1)) == 0) 
     396#define ISPOWEROF2(x)           ((((x)-1)&(x)) == 0) 
     397#define VALID_MASK(mask)        !((mask) & ((mask) + 1)) 
     398#ifndef OFFSETOF 
     399#define OFFSETOF(type, member)  ((uint)(uintptr)&((type *)0)->member) 
     400#endif /* OFFSETOF */ 
     401#ifndef ARRAYSIZE 
     402#define ARRAYSIZE(a)            (sizeof(a)/sizeof(a[0])) 
     403#endif 
     404 
     405/* bit map related macros */ 
     406#ifndef setbit 
     407#ifndef NBBY                /* the BSD family defines NBBY */ 
     408#define NBBY    8       /* 8 bits per byte */ 
     409#endif /* #ifndef NBBY */ 
     410#define setbit(a, i)    (((uint8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY)) 
     411#define clrbit(a, i)    (((uint8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) 
     412#define isset(a, i)     (((const uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) 
     413#define isclr(a, i)     ((((const uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) 
     414#endif /* setbit */ 
     415 
     416#define NBITS(type)     (sizeof(type) * 8) 
     417#define NBITVAL(nbits)  (1 << (nbits)) 
     418#define MAXBITVAL(nbits)        ((1 << (nbits)) - 1) 
     419#define NBITMASK(nbits) MAXBITVAL(nbits) 
     420#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) 
     421 
     422/* basic mux operation - can be optimized on several architectures */ 
     423#define MUX(pred, true, false) ((pred) ? (true) : (false)) 
     424 
     425/* modulo inc/dec - assumes x E [0, bound - 1] */ 
     426#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1) 
     427#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) 
     428 
     429/* modulo inc/dec, bound = 2^k */ 
     430#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) 
     431#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) 
     432 
     433/* modulo add/sub - assumes x, y E [0, bound - 1] */ 
     434#define MODADD(x, y, bound) \ 
     435    MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) 
     436#define MODSUB(x, y, bound) \ 
     437    MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) 
     438 
     439/* module add/sub, bound = 2^k */ 
     440#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1)) 
     441#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1)) 
     442 
     443/* crc defines */ 
     444#define CRC8_INIT_VALUE  0xff           /* Initial CRC8 checksum value */ 
     445#define CRC8_GOOD_VALUE  0x9f           /* Good final CRC8 checksum value */ 
     446#define CRC16_INIT_VALUE 0xffff         /* Initial CRC16 checksum value */ 
     447#define CRC16_GOOD_VALUE 0xf0b8         /* Good final CRC16 checksum value */ 
     448#define CRC32_INIT_VALUE 0xffffffff     /* Initial CRC32 checksum value */ 
     449#define CRC32_GOOD_VALUE 0xdebb20e3     /* Good final CRC32 checksum value */ 
     450 
     451/* bcm_format_flags() bit description structure */ 
     452typedef struct bcm_bit_desc { 
     453        uint32  bit; 
     454        const char* name; 
     455} bcm_bit_desc_t; 
     456 
     457/* tag_ID/length/value_buffer tuple */ 
     458typedef struct bcm_tlv { 
     459        uint8   id; 
     460        uint8   len; 
     461        uint8   data[1]; 
     462} bcm_tlv_t; 
     463 
     464/* Check that bcm_tlv_t fits into the given buflen */ 
     465#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len)) 
     466 
     467/* buffer length for ethernet address from bcm_ether_ntoa() */ 
     468#define ETHER_ADDR_STR_LEN      18      /* 18-bytes of Ethernet address buffer length */ 
     469 
     470/* unaligned load and store macros */ 
     471#ifdef IL_BIGENDIAN 
     472static INLINE uint32 
     473load32_ua(uint8 *a) 
     474{ 
     475        return ((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]); 
     476} 
     477 
     478static INLINE void 
     479store32_ua(uint8 *a, uint32 v) 
     480{ 
     481        a[0] = (v >> 24) & 0xff; 
     482        a[1] = (v >> 16) & 0xff; 
     483        a[2] = (v >> 8) & 0xff; 
     484        a[3] = v & 0xff; 
     485} 
     486 
     487static INLINE uint16 
     488load16_ua(uint8 *a) 
     489{ 
     490        return ((a[0] << 8) | a[1]); 
     491} 
     492 
     493static INLINE void 
     494store16_ua(uint8 *a, uint16 v) 
     495{ 
     496        a[0] = (v >> 8) & 0xff; 
     497        a[1] = v & 0xff; 
     498} 
     499 
     500#else /* IL_BIGENDIAN */ 
     501 
     502static INLINE uint32 
     503load32_ua(uint8 *a) 
     504{ 
     505        return ((a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]); 
     506} 
     507 
     508static INLINE void 
     509store32_ua(uint8 *a, uint32 v) 
     510{ 
     511        a[3] = (v >> 24) & 0xff; 
     512        a[2] = (v >> 16) & 0xff; 
     513        a[1] = (v >> 8) & 0xff; 
     514        a[0] = v & 0xff; 
     515} 
     516 
     517static INLINE uint16 
     518load16_ua(uint8 *a) 
     519{ 
     520        return ((a[1] << 8) | a[0]); 
     521} 
     522 
     523static INLINE void 
     524store16_ua(uint8 *a, uint16 v) 
     525{ 
     526        a[1] = (v >> 8) & 0xff; 
     527        a[0] = v & 0xff; 
     528} 
     529 
     530#endif /* IL_BIGENDIAN */ 
     531 
     532/* externs */ 
     533/* crc */ 
     534extern uint8 BCMROMFN(hndcrc8)(uint8 *p, uint nbytes, uint8 crc); 
     535extern uint16 BCMROMFN(hndcrc16)(uint8 *p, uint nbytes, uint16 crc); 
     536extern uint32 BCMROMFN(hndcrc32)(uint8 *p, uint nbytes, uint32 crc); 
     537/* format/print */ 
     538extern char *bcm_brev_str(uint16 brev, char *buf); 
     539extern void printfbig(char *buf); 
     540 
     541/* IE parsing */ 
     542extern bcm_tlv_t *BCMROMFN(bcm_next_tlv)(bcm_tlv_t *elt, int *buflen); 
     543extern bcm_tlv_t *BCMROMFN(bcm_parse_tlvs)(void *buf, int buflen, uint key); 
     544extern bcm_tlv_t *BCMROMFN(bcm_parse_ordered_tlvs)(void *buf, int buflen, uint key); 
     545 
     546/* bcmerror */ 
     547extern const char *bcmerrorstr(int bcmerror); 
     548 
     549/* multi-bool data type: set of bools, mbool is true if any is set */ 
     550typedef uint32 mbool; 
     551#define mboolset(mb, bit)               ((mb) |= (bit))         /* set one bool */ 
     552#define mboolclr(mb, bit)               ((mb) &= ~(bit))        /* clear one bool */ 
     553#define mboolisset(mb, bit)             (((mb) & (bit)) != 0)   /* TRUE if one bool is set */ 
     554#define mboolmaskset(mb, mask, val)     ((mb) = (((mb) & ~(mask)) | (val))) 
     555 
     556/* power conversion */ 
     557extern uint16 BCMROMFN(bcm_qdbm_to_mw)(uint8 qdbm); 
     558extern uint8 BCMROMFN(bcm_mw_to_qdbm)(uint16 mw); 
     559 
     560/* generic datastruct to help dump routines */ 
     561struct fielddesc { 
     562        const char *nameandfmt; 
     563        uint32  offset; 
     564        uint32  len; 
     565}; 
     566 
     567extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); 
     568extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); 
     569 
     570typedef  uint32 (*readreg_rtn)(void *arg0, void *arg1, uint32 offset); 
     571extern uint bcmdumpfields(readreg_rtn func_ptr, void *arg0, void *arg1, struct fielddesc *str, 
     572                          char *buf, uint32 bufsize); 
     573 
     574extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); 
     575extern uint BCMROMFN(bcm_bitcount)(uint8 *bitmap, uint bytelength); 
     576 
     577#ifdef BCMDBG_PKT      /* pkt logging for debugging */ 
     578#define PKTLIST_SIZE 1000 
     579typedef struct { 
     580        void *list[PKTLIST_SIZE]; /* List of pointers to packets */ 
     581        uint count; /* Total count of the packets */ 
     582} pktlist_info_t; 
     583 
     584extern void pktlist_add(pktlist_info_t *pktlist, void *p); 
     585extern void pktlist_remove(pktlist_info_t *pktlist, void *p); 
     586extern char* pktlist_dump(pktlist_info_t *pktlist, char *buf); 
     587#endif  /* BCMDBG_PKT */ 
     588 
     589#endif  /* _bcmutils_h_ */ 
  • target/linux/brcm-2.4/files/arch/mips/bcm947xx/sflash.c

     
     1/* 
     2 * Broadcom SiliconBackplane chipcommon serial flash interface 
     3 * 
     4 * Copyright 2007, Broadcom Corporation 
     5 * All Rights Reserved. 
     6 *  
     7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 
     8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 
     9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 
     10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 
     11 * 
     12 * $Id$ 
     13 */ 
     14 
     15#include <typedefs.h> 
     16#include <osl.h> 
     17#include "include/bcmutils.h" 
     18#include <sbutils.h> 
     19#include <sbconfig.h> 
     20#include <sbchipc.h> 
     21#include <bcmdevs.h> 
     22#include <sflash.h> 
     23 
     24/* Private global state */ 
     25static struct sflash sflash; 
     26 
     27/* Issue a serial flash command */ 
     28static INLINE void 
     29sflash_cmd(osl_t *osh, chipcregs_t *cc, uint opcode) 
     30{ 
     31        W_REG(osh, &cc->flashcontrol, SFLASH_START | opcode); 
     32        while (R_REG(osh, &cc->flashcontrol) & SFLASH_BUSY); 
     33} 
     34 
     35/* Initialize serial flash access */ 
     36struct sflash * 
     37sflash_init(sb_t *sbh, chipcregs_t *cc) 
     38{ 
     39        uint32 id, id2; 
     40        osl_t *osh; 
     41 
     42        ASSERT(sbh); 
     43 
     44        osh = sb_osh(sbh); 
     45 
     46        bzero(&sflash, sizeof(sflash)); 
     47 
     48        sflash.type = sbh->cccaps & CC_CAP_FLASH_MASK; 
     49 
     50        switch (sflash.type) { 
     51        case SFLASH_ST: 
     52                /* Probe for ST chips */ 
     53                sflash_cmd(osh, cc, SFLASH_ST_DP); 
     54                sflash_cmd(osh, cc, SFLASH_ST_RES); 
     55                id = R_REG(osh, &cc->flashdata); 
     56                switch (id) { 
     57                case 0x11: 
     58                        /* ST M25P20 2 Mbit Serial Flash */ 
     59                        sflash.blocksize = 64 * 1024; 
     60                        sflash.numblocks = 4; 
     61                        break; 
     62                case 0x12: 
     63                        /* ST M25P40 4 Mbit Serial Flash */ 
     64                        sflash.blocksize = 64 * 1024; 
     65                        sflash.numblocks = 8; 
     66                        break; 
     67                case 0x13: 
     68                        /* ST M25P80 8 Mbit Serial Flash */ 
     69                        sflash.blocksize = 64 * 1024; 
     70                        sflash.numblocks = 16; 
     71                        break; 
     72                case 0x14: 
     73                        /* ST M25P16 16 Mbit Serial Flash */ 
     74                        sflash.blocksize = 64 * 1024; 
     75                        sflash.numblocks = 32; 
     76                        break; 
     77                case 0x15: 
     78                        /* ST M25P32 32 Mbit Serial Flash */ 
     79                        sflash.blocksize = 64 * 1024; 
     80                        sflash.numblocks = 64; 
     81                        break; 
     82                case 0x16: 
     83                        /* ST M25P64 64 Mbit Serial Flash */ 
     84                        sflash.blocksize = 64 * 1024; 
     85                        sflash.numblocks = 128; 
     86                        break; 
     87                case 0xbf: 
     88                        W_REG(osh, &cc->flashaddress, 1); 
     89                        sflash_cmd(osh, cc, SFLASH_ST_RES); 
     90                        id2 = R_REG(osh, &cc->flashdata); 
     91                        if (id2 == 0x44) { 
     92                                /* SST M25VF80 4 Mbit Serial Flash */ 
     93                                sflash.blocksize = 64 * 1024; 
     94                                sflash.numblocks = 8; 
     95                        } 
     96                        break; 
     97                } 
     98                break; 
     99 
     100        case SFLASH_AT: 
     101                /* Probe for Atmel chips */ 
     102                sflash_cmd(osh, cc, SFLASH_AT_STATUS); 
     103                id = R_REG(osh, &cc->flashdata) & 0x3c; 
     104                switch (id) { 
     105                case 0xc: 
     106                        /* Atmel AT45DB011 1Mbit Serial Flash */ 
     107                        sflash.blocksize = 256; 
     108                        sflash.numblocks = 512; 
     109                        break; 
     110                case 0x14: 
     111                        /* Atmel AT45DB021 2Mbit Serial Flash */ 
     112                        sflash.blocksize = 256; 
     113                        sflash.numblocks = 1024; 
     114                        break; 
     115                case 0x1c: 
     116                        /* Atmel AT45DB041 4Mbit Serial Flash */ 
     117                        sflash.blocksize = 256; 
     118                        sflash.numblocks = 2048; 
     119                        break; 
     120                case 0x24: 
     121                        /* Atmel AT45DB081 8Mbit Serial Flash */ 
     122                        sflash.blocksize = 256; 
     123                        sflash.numblocks = 4096; 
     124                        break; 
     125                case 0x2c: 
     126                        /* Atmel AT45DB161 16Mbit Serial Flash */ 
     127                        sflash.blocksize = 512; 
     128                        sflash.numblocks = 4096; 
     129                        break; 
     130                case 0x34: 
     131                        /* Atmel AT45DB321 32Mbit Serial Flash */ 
     132                        sflash.blocksize = 512; 
     133                        sflash.numblocks = 8192; 
     134                        break; 
     135                case 0x3c: 
     136                        /* Atmel AT45DB642 64Mbit Serial Flash */ 
     137                        sflash.blocksize = 1024; 
     138                        sflash.numblocks = 8192; 
     139                        break; 
     140                } 
     141                break; 
     142        } 
     143 
     144        sflash.size = sflash.blocksize * sflash.numblocks; 
     145        return sflash.size ? &sflash : NULL; 
     146} 
     147 
     148/* Read len bytes starting at offset into buf. Returns number of bytes read. */ 
     149int 
     150sflash_read(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, uchar *buf) 
     151{ 
     152        uint8 *from, *to; 
     153        int cnt, i; 
     154        osl_t *osh; 
     155 
     156        ASSERT(sbh); 
     157 
     158        if (!len) 
     159                return 0; 
     160 
     161        if ((offset + len) > sflash.size) 
     162                return -22; 
     163 
     164        if ((len >= 4) && (offset & 3)) 
     165                cnt = 4 - (offset & 3); 
     166        else if ((len >= 4) && ((uintptr)buf & 3)) 
     167                cnt = 4 - ((uintptr)buf & 3); 
     168        else 
     169                cnt = len; 
     170 
     171        osh = sb_osh(sbh); 
     172 
     173        from = (uint8 *)(uintptr)OSL_UNCACHED(SB_FLASH2 + offset); 
     174        to = (uint8 *)buf; 
     175 
     176        if (cnt < 4) { 
     177                for (i = 0; i < cnt; i ++) { 
     178                        *to = R_REG(osh, from); 
     179                        from ++; 
     180                        to ++; 
     181                } 
     182                return cnt; 
     183        } 
     184 
     185        while (cnt >= 4) { 
     186                *(uint32 *)to = R_REG(osh, (uint32 *)from); 
     187                from += 4; 
     188                to += 4; 
     189                cnt -= 4; 
     190        } 
     191 
     192        return (len - cnt); 
     193} 
     194 
     195/* Poll for command completion. Returns zero when complete. */ 
     196int 
     197sflash_poll(sb_t *sbh, chipcregs_t *cc, uint offset) 
     198{ 
     199        osl_t *osh; 
     200 
     201        ASSERT(sbh); 
     202 
     203        osh = sb_osh(sbh); 
     204 
     205        if (offset >= sflash.size) 
     206                return -22; 
     207 
     208        switch (sflash.type) { 
     209        case SFLASH_ST: 
     210                /* Check for ST Write In Progress bit */ 
     211                sflash_cmd(osh, cc, SFLASH_ST_RDSR); 
     212                return R_REG(osh, &cc->flashdata) & SFLASH_ST_WIP; 
     213        case SFLASH_AT: 
     214                /* Check for Atmel Ready bit */ 
     215                sflash_cmd(osh, cc, SFLASH_AT_STATUS); 
     216                return !(R_REG(osh, &cc->flashdata) & SFLASH_AT_READY); 
     217        } 
     218 
     219        return 0; 
     220} 
     221 
     222/* Write len bytes starting at offset into buf. Returns number of bytes 
     223 * written. Caller should poll for completion. 
     224 */ 
     225int 
     226sflash_write(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, const uchar *buf) 
     227{ 
     228        struct sflash *sfl; 
     229        int ret = 0; 
     230        bool is4712b0; 
     231        uint32 page, byte, mask; 
     232        osl_t *osh; 
     233 
     234        ASSERT(sbh); 
     235 
     236        osh = sb_osh(sbh); 
     237 
     238        if (!len) 
     239                return 0; 
     240 
     241        if ((offset + len) > sflash.size) 
     242                return -22; 
     243 
     244        sfl = &sflash; 
     245        switch (sfl->type) { 
     246        case SFLASH_ST: 
     247                is4712b0 = (sbh->chip == BCM4712_CHIP_ID) && (sbh->chiprev == 3); 
     248                /* Enable writes */ 
     249                sflash_cmd(osh, cc, SFLASH_ST_WREN); 
     250                if (is4712b0) { 
     251                        mask = 1 << 14; 
     252                        W_REG(osh, &cc->flashaddress, offset); 
     253                        W_REG(osh, &cc->flashdata, *buf++); 
     254                        /* Set chip select */ 
     255                        OR_REG(osh, &cc->gpioout, mask); 
     256                        /* Issue a page program with the first byte */ 
     257                        sflash_cmd(osh, cc, SFLASH_ST_PP); 
     258                        ret = 1; 
     259                        offset++; 
     260                        len--; 
     261                        while (len > 0) { 
     262                                if ((offset & 255) == 0) { 
     263                                        /* Page boundary, drop cs and return */ 
     264                                        AND_REG(osh, &cc->gpioout, ~mask); 
     265                                        if (!sflash_poll(sbh, cc, offset)) { 
     266                                                /* Flash rejected command */ 
     267                                                return -11; 
     268                                        } 
     269                                        return ret; 
     270                                } else { 
     271                                        /* Write single byte */ 
     272                                        sflash_cmd(osh, cc, *buf++); 
     273                                } 
     274                                ret++; 
     275                                offset++; 
     276                                len--; 
     277                        } 
     278                        /* All done, drop cs if needed */ 
     279                        if ((offset & 255) != 1) { 
     280                                /* Drop cs */ 
     281                                AND_REG(osh, &cc->gpioout, ~mask); 
     282                                if (!sflash_poll(sbh, cc, offset)) { 
     283                                        /* Flash rejected command */ 
     284                                        return -12; 
     285                                } 
     286                        } 
     287                } else if ( (sbh->ccrev >= 20) && (len != 1) ) { 
     288                //} else if ( sbh->ccrev >= 20 ) {              /* foxconn modified by EricHuang, 05/24/2007 */ 
     289                        W_REG(NULL, &cc->flashaddress, offset); 
     290                        W_REG(NULL, &cc->flashdata, *buf++); 
     291                        /* Issue a page program with CSA bit set */ 
     292                        sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP); 
     293                        ret = 1; 
     294                        offset++; 
     295                        len--; 
     296                        while (len > 0) { 
     297                                if ((offset & 255) == 0) { 
     298                                        /* Page boundary, poll droping cs and return */ 
     299                                        W_REG(NULL, &cc->flashcontrol, 0); 
     300                                        /* wklin added start, 06/08/2007 */ 
     301                                        W_REG(NULL, &cc->flashcontrol, 0); 
     302                                        OSL_DELAY(1); 
     303                                        /* wklin added end, 06/08/2007 */ 
     304                                        /* wklin rmeoved start, 06/08/2007 */ 
     305#if 0 
     306                                        if (!sflash_poll(sbh, cc, offset)) { 
     307                                                /* Flash rejected command */ 
     308                                                return -11; 
     309                                        } 
     310#endif                                   
     311                                        /* wklin removed end, 06/08/2007 */ 
     312                                        return ret; 
     313                                } else { 
     314                                        /* Write single byte */ 
     315                                        sflash_cmd(osh, cc, SFLASH_ST_CSA | *buf++); 
     316                                } 
     317                                ret++; 
     318                                offset++; 
     319                                len--; 
     320                        } 
     321                        /* All done, drop cs if needed */ 
     322                        if ((offset & 255) != 1) { 
     323                                /* Drop cs, poll */ 
     324                                W_REG(NULL, &cc->flashcontrol, 0); 
     325                                /* wklin added start, 06/08/2007 */ 
     326                                W_REG(NULL, &cc->flashcontrol, 0); 
     327                                OSL_DELAY(1); 
     328                                /* wklin added end, 06/08/2007 */ 
     329                                /* wklin removed start, 06/08/2007 */ 
     330#if 0                            
     331                                if (!sflash_poll(sbh, cc, offset)) { 
     332                                        /* Flash rejected command */ 
     333                                        return -12; 
     334                                } 
     335#endif 
     336                                /* wklin removed end, 06/08/2007 */ 
     337                        } 
     338                } else { 
     339                        ret = 1; 
     340                        W_REG(osh, &cc->flashaddress, offset); 
     341                        W_REG(osh, &cc->flashdata, *buf); 
     342                        /* Page program */ 
     343                        sflash_cmd(osh, cc, SFLASH_ST_PP); 
     344                } 
     345                break; 
     346        case SFLASH_AT: 
     347                mask = sfl->blocksize - 1; 
     348                page = (offset & ~mask) << 1; 
     349                byte = offset & mask; 
     350                /* Read main memory page into buffer 1 */ 
     351                if (byte || (len < sfl->blocksize)) { 
     352                        W_REG(osh, &cc->flashaddress, page); 
     353                        sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD); 
     354                        /* 250 us for AT45DB321B */ 
     355                        SPINWAIT(sflash_poll(sbh, cc, offset), 1000); 
     356                        ASSERT(!sflash_poll(sbh, cc, offset)); 
     357                } 
     358                /* Write into buffer 1 */ 
     359                for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) { 
     360                        W_REG(osh, &cc->flashaddress, byte++); 
     361                        W_REG(osh, &cc->flashdata, *buf++); 
     362                        sflash_cmd(osh, cc, SFLASH_AT_BUF1_WRITE); 
     363                } 
     364                /* Write buffer 1 into main memory page */ 
     365                W_REG(osh, &cc->flashaddress, page); 
     366                sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM); 
     367                break; 
     368        } 
     369 
     370        return ret; 
     371} 
     372 
     373/* Erase a region. Returns number of bytes scheduled for erasure. 
     374 * Caller should poll for completion. 
     375 */ 
     376int 
     377sflash_erase(sb_t *sbh, chipcregs_t *cc, uint offset) 
     378{ 
     379        struct sflash *sfl; 
     380        osl_t *osh; 
     381 
     382        ASSERT(sbh); 
     383 
     384        osh = sb_osh(sbh); 
     385 
     386        if (offset >= sflash.size) 
     387                return -22; 
     388 
     389        sfl = &sflash; 
     390        switch (sfl->type) { 
     391        case SFLASH_ST: 
     392                sflash_cmd(osh, cc, SFLASH_ST_WREN); 
     393                W_REG(osh, &cc->flashaddress, offset); 
     394                sflash_cmd(osh, cc, SFLASH_ST_SE); 
     395                return sfl->blocksize; 
     396        case SFLASH_AT: 
     397                W_REG(osh, &cc->flashaddress, offset << 1); 
     398                sflash_cmd(osh, cc, SFLASH_AT_PAGE_ERASE); 
     399                return sfl->blocksize; 
     400        } 
     401 
     402        return 0; 
     403} 
     404 
     405/* 
     406 * writes the appropriate range of flash, a NULL buf simply erases 
     407 * the region of flash 
     408 */ 
     409int 
     410sflash_commit(sb_t *sbh, chipcregs_t *cc, uint offset, uint len, const uchar *buf) 
     411{ 
     412        struct sflash *sfl; 
     413        uchar *block = NULL, *cur_ptr, *blk_ptr; 
     414        uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder; 
     415        uint blk_offset, blk_len, copied; 
     416        int bytes, ret = 0; 
     417        osl_t *osh; 
     418 
     419        ASSERT(sbh); 
     420 
     421        osh = sb_osh(sbh); 
     422 
     423        /* Check address range */ 
     424        if (len <= 0) 
     425                return 0; 
     426 
     427        sfl = &sflash; 
     428        if ((offset + len) > sfl->size) 
     429                return -1; 
     430 
     431        blocksize = sfl->blocksize; 
     432        mask = blocksize - 1; 
     433 
     434        /* Allocate a block of mem */ 
     435        if (!(block = MALLOC(osh, blocksize))) 
     436                return -1; 
     437 
     438        while (len) { 
     439                /* Align offset */ 
     440                cur_offset = offset & ~mask; 
     441                cur_length = blocksize; 
     442                cur_ptr = block; 
     443 
     444                remainder = blocksize - (offset & mask); 
     445                if (len < remainder) 
     446                        cur_retlen = len; 
     447                else 
     448                        cur_retlen = remainder; 
     449 
     450                /* buf == NULL means erase only */ 
     451                if (buf) { 
     452                        /* Copy existing data into holding block if necessary */ 
     453                        if ((offset & mask) || (len < blocksize)) { 
     454                                blk_offset = cur_offset; 
     455                                blk_len = cur_length; 
     456                                blk_ptr = cur_ptr; 
     457 
     458                                /* Copy entire block */ 
     459                                while (blk_len) { 
     460                                        copied = sflash_read(sbh, cc, blk_offset, blk_len, blk_ptr); 
     461                                        blk_offset += copied; 
     462                                        blk_len -= copied; 
     463                                        blk_ptr += copied; 
     464                                } 
     465                        } 
     466 
     467                        /* Copy input data into holding block */ 
     468                        memcpy(cur_ptr + (offset & mask), buf, cur_retlen); 
     469                } 
     470 
     471                /* Erase block */ 
     472                if ((ret = sflash_erase(sbh, cc, (uint) cur_offset)) < 0) 
     473                        goto done; 
     474                while (sflash_poll(sbh, cc, (uint) cur_offset)); 
     475 
     476                /* buf == NULL means erase only */ 
     477                if (!buf) { 
     478                        offset += cur_retlen; 
     479                        len -= cur_retlen; 
     480                        continue; 
     481                } 
     482 
     483                /* Write holding block */ 
     484                while (cur_length > 0) { 
     485                        if ((bytes = sflash_write(sbh, cc, 
     486                                                  (uint) cur_offset, 
     487                                                  (uint) cur_length, 
     488                                                  (uchar *) cur_ptr)) < 0) { 
     489                                ret = bytes; 
     490                                goto done; 
     491                        } 
     492                        while (sflash_poll(sbh, cc, (uint) cur_offset)); 
     493                        cur_offset += bytes; 
     494                        cur_length -= bytes; 
     495                        cur_ptr += bytes; 
     496                } 
     497 
     498                offset += cur_retlen; 
     499                len -= cur_retlen; 
     500                buf += cur_retlen; 
     501        } 
     502 
     503        ret = len; 
     504done: 
     505        if (block) 
     506                MFREE(osh, block, blocksize); 
     507        return ret; 
     508} 
  • target/linux/brcm-2.4/files/drivers/mtd/devices/sflash.c

     
    11/* 
    22 * Broadcom SiliconBackplane chipcommon serial flash interface 
    33 * 
    4  * Copyright 2007, Broadcom Corporation 
    5  * All Rights Reserved. 
    6  *  
    7  * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 
    8  * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 
    9  * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 
    10  * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 
     4 * Copyright 2006, Broadcom Corporation       
     5 * All Rights Reserved.       
     6 *        
     7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY       
     8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM       
     9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS       
     10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.       
    1111 * 
     12 * $Id$ 
    1213 */ 
    1314 
     15#include <linux/config.h> 
     16#include <linux/module.h> 
     17#include <linux/slab.h> 
     18#include <linux/ioport.h> 
     19#include <linux/mtd/compatmac.h> 
     20#include <linux/mtd/mtd.h> 
     21#include <linux/mtd/partitions.h> 
     22#include <linux/errno.h> 
     23#include <linux/pci.h> 
     24#include <linux/delay.h> 
     25#include <asm/io.h> 
     26 
    1427#include <typedefs.h> 
    1528#include <osl.h> 
     29// #include <bcmutils.h> 
     30#include <bcmdevs.h> 
     31#include <bcmnvram.h> 
    1632#include <sbutils.h> 
    1733#include <sbconfig.h> 
    1834#include <sbchipc.h> 
    19 #include <bcmdevs.h> 
    2035#include <sflash.h> 
    2136 
     37#ifdef CONFIG_MTD_PARTITIONS 
     38extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size); 
     39#endif 
     40 
     41struct sflash_mtd { 
     42        sb_t *sbh; 
     43        chipcregs_t *cc; 
     44        struct semaphore lock; 
     45        struct mtd_info mtd; 
     46        struct mtd_erase_region_info region; 
     47}; 
     48 
    2249/* Private global state */ 
    23 static struct sflash sflash; 
     50static struct sflash_mtd sflash; 
    2451 
    25 /* Issue a serial flash command */ 
    26 static INLINE void 
    27 sflash_cmd (osl_t * osh, chipcregs_t * cc, uint opcode) 
     52static int 
     53sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout) 
    2854{ 
    29   W_REG (osh, &cc->flashcontrol, SFLASH_START | opcode); 
    30   while (R_REG (osh, &cc->flashcontrol) & SFLASH_BUSY); 
    31 } 
     55        int now = jiffies; 
     56        int ret = 0; 
    3257 
    33 /* Initialize serial flash access */ 
    34 struct sflash * 
    35 sflash_init (sb_t * sbh, chipcregs_t * cc) 
    36 { 
    37   uint32 id, id2; 
    38   osl_t *osh; 
    39  
    40   ASSERT (sbh); 
    41  
    42   osh = sb_osh (sbh); 
    43  
    44   bzero (&sflash, sizeof (sflash)); 
    45  
    46   sflash.type = sbh->cccaps & CC_CAP_FLASH_MASK; 
    47  
    48   switch (sflash.type) 
    49     { 
    50     case SFLASH_ST: 
    51       /* Probe for ST chips */ 
    52       sflash_cmd (osh, cc, SFLASH_ST_DP); 
    53       sflash_cmd (osh, cc, SFLASH_ST_RES); 
    54       id = R_REG (osh, &cc->flashdata); 
    55       switch (id) 
    56         { 
    57         case 0x11: 
    58           /* ST M25P20 2 Mbit Serial Flash */ 
    59           sflash.blocksize = 64 * 1024; 
    60           sflash.numblocks = 4; 
    61           break; 
    62         case 0x12: 
    63           /* ST M25P40 4 Mbit Serial Flash */ 
    64           sflash.blocksize = 64 * 1024; 
    65           sflash.numblocks = 8; 
    66           break; 
    67         case 0x13: 
    68           /* ST M25P80 8 Mbit Serial Flash */ 
    69           sflash.blocksize = 64 * 1024; 
    70           sflash.numblocks = 16; 
    71           break; 
    72         case 0x14: 
    73           /* ST M25P16 16 Mbit Serial Flash */ 
    74           sflash.blocksize = 64 * 1024; 
    75           sflash.numblocks = 32; 
    76           break; 
    77         case 0x15: 
    78           /* ST M25P32 32 Mbit Serial Flash */ 
    79           sflash.blocksize = 64 * 1024; 
    80           sflash.numblocks = 64; 
    81           break; 
    82         case 0x16: 
    83           /* ST M25P64 64 Mbit Serial Flash */ 
    84           sflash.blocksize = 64 * 1024; 
    85           sflash.numblocks = 128; 
    86           break; 
    87         case 0xbf: 
    88           W_REG (osh, &cc->flashaddress, 1); 
    89           sflash_cmd (osh, cc, SFLASH_ST_RES); 
    90           id2 = R_REG (osh, &cc->flashdata); 
    91           if (id2 == 0x44) 
    92             { 
    93               /* SST M25VF80 4 Mbit Serial Flash */ 
    94               sflash.blocksize = 64 * 1024; 
    95               sflash.numblocks = 8; 
    96             } 
    97           break; 
     58        for (;;) { 
     59                if (!sflash_poll(sflash->sbh, sflash->cc, offset)) { 
     60                        ret = 0; 
     61                        break; 
     62                } 
     63                if (time_after(jiffies, now + timeout)) { 
     64                        printk(KERN_ERR "sflash: timeout\n"); 
     65                        ret = -ETIMEDOUT; 
     66                        break; 
     67                } 
     68                if (current->need_resched) { 
     69                        set_current_state(TASK_UNINTERRUPTIBLE); 
     70                        schedule_timeout(timeout / 10); 
     71                } else 
     72                        udelay(1); 
    9873        } 
    99       break; 
    10074 
    101     case SFLASH_AT: 
    102       /* Probe for Atmel chips */ 
    103       sflash_cmd (osh, cc, SFLASH_AT_STATUS); 
    104       id = R_REG (osh, &cc->flashdata) & 0x3c; 
    105       switch (id) 
    106         { 
    107         case 0xc: 
    108           /* Atmel AT45DB011 1Mbit Serial Flash */ 
    109           sflash.blocksize = 256; 
    110           sflash.numblocks = 512; 
    111           break; 
    112         case 0x14: 
    113           /* Atmel AT45DB021 2Mbit Serial Flash */ 
    114           sflash.blocksize = 256; 
    115           sflash.numblocks = 1024; 
    116           break; 
    117         case 0x1c: 
    118           /* Atmel AT45DB041 4Mbit Serial Flash */ 
    119           sflash.blocksize = 256; 
    120           sflash.numblocks = 2048; 
    121           break; 
    122         case 0x24: 
    123           /* Atmel AT45DB081 8Mbit Serial Flash */ 
    124           sflash.blocksize = 256; 
    125           sflash.numblocks = 4096; 
    126           break; 
    127         case 0x2c: 
    128           /* Atmel AT45DB161 16Mbit Serial Flash */ 
    129           sflash.blocksize = 512; 
    130           sflash.numblocks = 4096; 
    131           break; 
    132         case 0x34: 
    133           /* Atmel AT45DB321 32Mbit Serial Flash */ 
    134           sflash.blocksize = 512; 
    135           sflash.numblocks = 8192; 
    136           break; 
    137         case 0x3c: 
    138           /* Atmel AT45DB642 64Mbit Serial Flash */ 
    139           sflash.blocksize = 1024; 
    140           sflash.numblocks = 8192; 
    141           break; 
    142         } 
    143       break; 
    144     } 
    145  
    146   sflash.size = sflash.blocksize * sflash.numblocks; 
    147   return sflash.size ? &sflash : NULL; 
     75        return ret; 
    14876} 
    14977 
    150 /* Read len bytes starting at offset into buf. Returns number of bytes read. */ 
    151 int 
    152 sflash_read (sb_t * sbh, chipcregs_t * cc, uint offset, uint len, uchar * buf) 
     78static int 
     79sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 
    15380{ 
    154   uint8 *from, *to; 
    155   int cnt, i; 
    156   osl_t *osh; 
     81        struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; 
     82        int bytes, ret = 0; 
    15783 
    158   ASSERT (sbh); 
     84        /* Check address range */ 
     85        if (len == 0){ 
     86         *retlen = 0; 
     87                return 0; 
     88 } 
     89        if (!len) 
     90                return 0; 
     91        if ((from + len) > mtd->size) 
     92                return -EINVAL; 
     93         
     94        down(&sflash->lock); 
    15995 
    160   if (!len) 
    161     return 0; 
    162  
    163   if ((offset + len) > sflash.size) 
    164     return -22; 
    165  
    166   if ((len >= 4) && (offset & 3)) 
    167     cnt = 4 - (offset & 3); 
    168   else if ((len >= 4) && ((uintptr) buf & 3)) 
    169     cnt = 4 - ((uintptr) buf & 3); 
    170   else 
    171     cnt = len; 
    172  
    173   osh = sb_osh (sbh); 
    174  
    175   from = (uint8 *) (uintptr) OSL_UNCACHED (SB_FLASH2 + offset); 
    176   to = (uint8 *) buf; 
    177  
    178   if (cnt < 4) 
    179     { 
    180       for (i = 0; i < cnt; i++) 
    181         { 
    182           *to = R_REG (osh, from); 
    183           from++; 
    184           to++; 
     96        *retlen = 0; 
     97        while (len) { 
     98                if ((bytes = sflash_read(sflash->sbh, sflash->cc, (uint) from, len, buf)) < 0) { 
     99                        ret = bytes; 
     100                        break; 
     101                } 
     102                from += (loff_t) bytes; 
     103                len -= bytes; 
     104                buf += bytes; 
     105                *retlen += bytes; 
    185106        } 
    186       return cnt; 
    187     } 
    188107 
    189   while (cnt >= 4) 
    190     { 
    191       *(uint32 *) to = R_REG (osh, (uint32 *) from); 
    192       from += 4; 
    193       to += 4; 
    194       cnt -= 4; 
    195     } 
     108        up(&sflash->lock); 
    196109 
    197   return (len - cnt); 
     110        return ret; 
    198111} 
    199112 
    200 /* Poll for command completion. Returns zero when complete. */ 
    201 int 
    202 sflash_poll (sb_t * sbh, chipcregs_t * cc, uint offset) 
     113static int 
     114sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) 
    203115{ 
    204   osl_t *osh; 
     116        struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; 
     117        int bytes, ret = 0; 
    205118 
    206   ASSERT (sbh); 
     119        /* Check address range */ 
     120        if (len == 0){ 
     121         *retlen = 0; 
     122                return 0; 
     123 } 
     124        if (!len) 
     125                return 0; 
     126        if ((to + len) > mtd->size) 
     127                return -EINVAL; 
    207128 
    208   osh = sb_osh (sbh); 
     129        down(&sflash->lock); 
    209130 
    210   if (offset >= sflash.size) 
    211     return -22; 
     131        *retlen = 0; 
     132        while (len) { 
     133                if ((bytes = sflash_write(sflash->sbh, sflash->cc, (uint)to, (uint)len, buf)) < 0) { 
     134                        ret = bytes; 
     135                        break; 
     136                } 
     137                if ((ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10))) 
     138                        break; 
     139                to += (loff_t) bytes; 
     140                len -= bytes; 
     141                buf += bytes; 
     142                *retlen += bytes; 
     143        } 
    212144 
    213   switch (sflash.type) 
    214     { 
    215     case SFLASH_ST: 
    216       /* Check for ST Write In Progress bit */ 
    217       sflash_cmd (osh, cc, SFLASH_ST_RDSR); 
    218       return R_REG (osh, &cc->flashdata) & SFLASH_ST_WIP; 
    219     case SFLASH_AT: 
    220       /* Check for Atmel Ready bit */ 
    221       sflash_cmd (osh, cc, SFLASH_AT_STATUS); 
    222       return !(R_REG (osh, &cc->flashdata) & SFLASH_AT_READY); 
    223     } 
     145        up(&sflash->lock); 
    224146 
    225   return 0; 
     147        return ret; 
    226148} 
    227149 
    228 /* Write len bytes starting at offset into buf. Returns number of bytes 
    229  * written. Caller should poll for completion. 
    230  */ 
    231 int 
    232 sflash_write (sb_t * sbh, chipcregs_t * cc, uint offset, uint len, 
    233               const uchar * buf) 
     150static int 
     151sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) 
    234152{ 
    235   struct sflash *sfl; 
    236   int ret = 0; 
    237   bool is4712b0; 
    238   uint32 page, byte, mask; 
    239   osl_t *osh; 
     153        struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; 
     154        int i, j, ret = 0; 
     155        unsigned int addr, len; 
    240156 
    241   ASSERT (sbh); 
     157        /* Check address range */ 
     158        if (!erase->len) 
     159                return 0; 
     160        if ((erase->addr + erase->len) > mtd->size) 
     161                return -EINVAL; 
    242162 
    243   osh = sb_osh (sbh); 
     163        addr = erase->addr; 
     164        len = erase->len; 
    244165 
    245   if (!len) 
    246     return 0; 
     166        down(&sflash->lock); 
    247167 
    248   if ((offset + len) > sflash.size) 
    249     return -22; 
    250  
    251   sfl = &sflash; 
    252   switch (sfl->type) 
    253     { 
    254     case SFLASH_ST: 
    255       is4712b0 = (sbh->chip == BCM4712_CHIP_ID) && (sbh->chiprev == 3); 
    256       /* Enable writes */ 
    257       sflash_cmd (osh, cc, SFLASH_ST_WREN); 
    258       if (is4712b0) 
    259         { 
    260           mask = 1 << 14; 
    261           W_REG (osh, &cc->flashaddress, offset); 
    262           W_REG (osh, &cc->flashdata, *buf++); 
    263           /* Set chip select */ 
    264           OR_REG (osh, &cc->gpioout, mask); 
    265           /* Issue a page program with the first byte */ 
    266           sflash_cmd (osh, cc, SFLASH_ST_PP); 
    267           ret = 1; 
    268           offset++; 
    269           len--; 
    270           while (len > 0) 
    271             { 
    272               if ((offset & 255) == 0) 
    273                 { 
    274                   /* Page boundary, drop cs and return */ 
    275                   AND_REG (osh, &cc->gpioout, ~mask); 
    276                   if (!sflash_poll (sbh, cc, offset)) 
    277                     { 
    278                       /* Flash rejected command */ 
    279                       return -11; 
    280                     } 
    281                   return ret; 
     168        /* Ensure that requested region is aligned */ 
     169        for (i = 0; i < mtd->numeraseregions; i++) { 
     170                for (j = 0; j < mtd->eraseregions[i].numblocks; j++) { 
     171                        if (addr == mtd->eraseregions[i].offset + mtd->eraseregions[i].erasesize * j && 
     172                            len >= mtd->eraseregions[i].erasesize) { 
     173                                if ((ret = sflash_erase(sflash->sbh, sflash->cc, addr)) < 0) 
     174                                        break; 
     175                                if ((ret = sflash_mtd_poll(sflash, addr, 10 * HZ))) 
     176                                        break; 
     177                                addr += mtd->eraseregions[i].erasesize; 
     178                                len -= mtd->eraseregions[i].erasesize; 
     179                        } 
    282180                } 
    283               else 
    284                 { 
    285                   /* Write single byte */ 
    286                   sflash_cmd (osh, cc, *buf++); 
    287                 } 
    288               ret++; 
    289               offset++; 
    290               len--; 
    291             } 
    292           /* All done, drop cs if needed */ 
    293           if ((offset & 255) != 1) 
    294             { 
    295               /* Drop cs */ 
    296               AND_REG (osh, &cc->gpioout, ~mask); 
    297               if (!sflash_poll (sbh, cc, offset)) 
    298                 { 
    299                   /* Flash rejected command */ 
    300                   return -12; 
    301                 } 
    302             } 
     181                if (ret) 
     182                        break; 
    303183        } 
    304       else if (sbh->ccrev >= 20) 
    305         { 
    306           W_REG (NULL, &cc->flashaddress, offset); 
    307           W_REG (NULL, &cc->flashdata, *buf++); 
    308           /* Issue a page program with CSA bit set */ 
    309           sflash_cmd (osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP); 
    310           ret = 1; 
    311           offset++; 
    312           len--; 
    313           while (len > 0) 
    314             { 
    315               if ((offset & 255) == 0) 
    316                 { 
    317                   /* Page boundary, poll droping cs and return */ 
    318                   W_REG (NULL, &cc->flashcontrol, 0); 
    319                   if (!sflash_poll (sbh, cc, offset)) 
    320                     { 
    321                       /* Flash rejected command */ 
    322                       return -11; 
    323                     } 
    324                   return ret; 
    325                 } 
    326               else 
    327                 { 
    328                   /* Write single byte */ 
    329                   sflash_cmd (osh, cc, SFLASH_ST_CSA | *buf++); 
    330                 } 
    331               ret++; 
    332               offset++; 
    333               len--; 
    334             } 
    335           /* All done, drop cs if needed */ 
    336           if ((offset & 255) != 1) 
    337             { 
    338               /* Drop cs, poll */ 
    339               W_REG (NULL, &cc->flashcontrol, 0); 
    340               if (!sflash_poll (sbh, cc, offset)) 
    341                 { 
    342                   /* Flash rejected command */ 
    343                   return -12; 
    344                 } 
    345             } 
    346         } 
    347       else 
    348         { 
    349           ret = 1; 
    350           W_REG (osh, &cc->flashaddress, offset); 
    351           W_REG (osh, &cc->flashdata, *buf); 
    352           /* Page program */ 
    353           sflash_cmd (osh, cc, SFLASH_ST_PP); 
    354         } 
    355       break; 
    356     case SFLASH_AT: 
    357       mask = sfl->blocksize - 1; 
    358       page = (offset & ~mask) << 1; 
    359       byte = offset & mask; 
    360       /* Read main memory page into buffer 1 */ 
    361       if (byte || (len < sfl->blocksize)) 
    362         { 
    363           W_REG (osh, &cc->flashaddress, page); 
    364           sflash_cmd (osh, cc, SFLASH_AT_BUF1_LOAD); 
    365           /* 250 us for AT45DB321B */ 
    366           SPINWAIT (sflash_poll (sbh, cc, offset), 1000); 
    367           ASSERT (!sflash_poll (sbh, cc, offset)); 
    368         } 
    369       /* Write into buffer 1 */ 
    370       for (ret = 0; (ret < (int) len) && (byte < sfl->blocksize); ret++) 
    371         { 
    372           W_REG (osh, &cc->flashaddress, byte++); 
    373           W_REG (osh, &cc->flashdata, *buf++); 
    374           sflash_cmd (osh, cc, SFLASH_AT_BUF1_WRITE); 
    375         } 
    376       /* Write buffer 1 into main memory page */ 
    377       W_REG (osh, &cc->flashaddress, page); 
    378       sflash_cmd (osh, cc, SFLASH_AT_BUF1_PROGRAM); 
    379       break; 
    380     } 
    381184 
    382   return ret; 
    383 } 
     185        up(&sflash->lock); 
    384186 
    385 /* Erase a region. Returns number of bytes scheduled for erasure. 
    386  * Caller should poll for completion. 
    387  */ 
    388 int 
    389 sflash_erase (sb_t * sbh, chipcregs_t * cc, uint offset) 
    390 { 
    391   struct sflash *sfl; 
    392   osl_t *osh; 
     187        /* Set erase status */ 
     188        if (ret) 
     189                erase->state = MTD_ERASE_FAILED; 
     190        else  
     191                erase->state = MTD_ERASE_DONE; 
    393192 
    394   ASSERT (sbh); 
     193        /* Call erase callback */ 
     194        if (erase->callback) 
     195                erase->callback(erase); 
    395196 
    396   osh = sb_osh (sbh); 
    397  
    398   if (offset >= sflash.size) 
    399     return -22; 
    400  
    401   sfl = &sflash; 
    402   switch (sfl->type) 
    403     { 
    404     case SFLASH_ST: 
    405       sflash_cmd (osh, cc, SFLASH_ST_WREN); 
    406       W_REG (osh, &cc->flashaddress, offset); 
    407       sflash_cmd (osh, cc, SFLASH_ST_SE); 
    408       return sfl->blocksize; 
    409     case SFLASH_AT: 
    410       W_REG (osh, &cc->flashaddress, offset << 1); 
    411       sflash_cmd (osh, cc, SFLASH_AT_PAGE_ERASE); 
    412       return sfl->blocksize; 
    413     } 
    414  
    415   return 0; 
     197        return ret; 
    416198} 
    417199 
    418 /* 
    419  * writes the appropriate range of flash, a NULL buf simply erases 
    420  * the region of flash 
    421  */ 
    422 int 
    423 sflash_commit (sb_t * sbh, chipcregs_t * cc, uint offset, uint len, 
    424                const uchar * buf) 
     200#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE) 
     201#define sflash_mtd_init init_module 
     202#define sflash_mtd_exit cleanup_module 
     203#endif 
     204 
     205mod_init_t 
     206sflash_mtd_init(void) 
    425207{ 
    426   struct sflash *sfl; 
    427   uchar *block = NULL, *cur_ptr, *blk_ptr; 
    428   uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder; 
    429   uint blk_offset, blk_len, copied; 
    430   int bytes, ret = 0; 
    431   osl_t *osh; 
     208        struct pci_dev *pdev; 
     209        int ret = 0; 
     210        struct sflash *info; 
     211        uint i; 
     212#ifdef CONFIG_MTD_PARTITIONS 
     213        struct mtd_partition *parts; 
     214#endif 
    432215 
    433   ASSERT (sbh); 
     216        if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_CC, NULL))) { 
     217                printk(KERN_ERR "sflash: chipcommon not found\n"); 
     218                return -ENODEV; 
     219        } 
    434220 
    435   osh = sb_osh (sbh); 
     221        memset(&sflash, 0, sizeof(struct sflash_mtd)); 
     222        init_MUTEX(&sflash.lock); 
    436223 
    437   /* Check address range */ 
    438   if (len <= 0) 
    439     return 0; 
     224        /* attach to the backplane */ 
     225        if (!(sflash.sbh = sb_kattach(SB_OSH))) { 
     226                printk(KERN_ERR "sflash: error attaching to backplane\n"); 
     227                ret = -EIO; 
     228                goto fail; 
     229        } 
    440230 
    441   sfl = &sflash; 
    442   if ((offset + len) > sfl->size) 
    443     return -1; 
     231        /* Map registers and flash base */ 
     232        if (!(sflash.cc = ioremap_nocache(pci_resource_start(pdev, 0), 
     233                                          pci_resource_len(pdev, 0)))) { 
     234                printk(KERN_ERR "sflash: error mapping registers\n"); 
     235                ret = -EIO; 
     236                goto fail; 
     237        } 
    444238 
    445   blocksize = sfl->blocksize; 
    446   mask = blocksize - 1; 
     239        /* Initialize serial flash access */ 
     240        if (!(info = sflash_init(sflash.sbh, sflash.cc))) { 
     241                printk(KERN_ERR "sflash: found no supported devices\n"); 
     242                ret = -ENODEV; 
     243                goto fail; 
     244        } 
    447245 
    448   /* Allocate a block of mem */ 
    449   if (!(block = MALLOC (osh, blocksize))) 
    450     return -1; 
     246        printk(KERN_INFO "sflash: found serial flash; blocksize=%dKB, numblocks=%d, size=%dKB\n",info->blocksize/1024,info->numblocks,info->size/1024); 
    451247 
    452   while (len) 
    453     { 
    454       /* Align offset */ 
    455       cur_offset = offset & ~mask; 
    456       cur_length = blocksize; 
    457       cur_ptr = block; 
     248        /* Setup region info */ 
     249        sflash.region.offset = 0; 
     250        sflash.region.erasesize = info->blocksize; 
     251        sflash.region.numblocks = info->numblocks; 
     252        if (sflash.region.erasesize > sflash.mtd.erasesize) 
     253                sflash.mtd.erasesize = sflash.region.erasesize; 
     254        sflash.mtd.size = info->size; 
     255        sflash.mtd.numeraseregions = 1; 
    458256 
    459       remainder = blocksize - (offset & mask); 
    460       if (len < remainder) 
    461         cur_retlen = len; 
    462       else 
    463         cur_retlen = remainder; 
     257        /* Register with MTD */ 
     258        sflash.mtd.name = "sflash"; 
     259        sflash.mtd.type = MTD_NORFLASH; 
     260        sflash.mtd.flags = MTD_CAP_NORFLASH; 
     261        sflash.mtd.eraseregions = &sflash.region; 
     262        sflash.mtd.module = THIS_MODULE; 
     263        sflash.mtd.erase = sflash_mtd_erase; 
     264        sflash.mtd.read = sflash_mtd_read; 
     265        sflash.mtd.write = sflash_mtd_write; 
     266        sflash.mtd.priv = &sflash; 
    464267 
    465       /* buf == NULL means erase only */ 
    466       if (buf) 
    467         { 
    468           /* Copy existing data into holding block if necessary */ 
    469           if ((offset & mask) || (len < blocksize)) 
    470             { 
    471               blk_offset = cur_offset; 
    472               blk_len = cur_length; 
    473               blk_ptr = cur_ptr; 
    474  
    475               /* Copy entire block */ 
    476               while (blk_len) 
    477                 { 
    478                   copied = 
    479                     sflash_read (sbh, cc, blk_offset, blk_len, blk_ptr); 
    480                   blk_offset += copied; 
    481                   blk_len -= copied; 
    482                   blk_ptr += copied; 
    483                 } 
    484             } 
    485  
    486           /* Copy input data into holding block */ 
    487           memcpy (cur_ptr + (offset & mask), buf, cur_retlen); 
     268#ifdef CONFIG_MTD_PARTITIONS 
     269        parts = init_mtd_partitions(&sflash.mtd, sflash.mtd.size); 
     270        for (i = 0; parts[i].name; i++); 
     271        ret = add_mtd_partitions(&sflash.mtd, parts, i); 
     272#else 
     273        ret = add_mtd_device(&sflash.mtd); 
     274#endif 
     275        if (ret) { 
     276                printk(KERN_ERR "sflash: add_mtd failed\n"); 
     277                goto fail; 
    488278        } 
    489279 
    490       /* Erase block */ 
    491       if ((ret = sflash_erase (sbh, cc, (uint) cur_offset)) < 0) 
    492         goto done; 
    493       while (sflash_poll (sbh, cc, (uint) cur_offset)); 
     280        return 0; 
    494281 
    495       /* buf == NULL means erase only */ 
    496       if (!buf) 
    497         { 
    498           offset += cur_retlen; 
    499           len -= cur_retlen; 
    500           continue; 
    501         } 
     282 fail: 
     283        if (sflash.cc) 
     284                iounmap((void *) sflash.cc); 
     285        if (sflash.sbh) 
     286                sb_detach(sflash.sbh); 
     287        return ret; 
     288} 
    502289 
    503       /* Write holding block */ 
    504       while (cur_length > 0) 
    505         { 
    506           if ((bytes = sflash_write (sbh, cc, 
    507                                      (uint) cur_offset, 
    508                                      (uint) cur_length, 
    509                                      (uchar *) cur_ptr)) < 0) 
    510             { 
    511               ret = bytes; 
    512               goto done; 
    513             } 
    514           while (sflash_poll (sbh, cc, (uint) cur_offset)); 
    515           cur_offset += bytes; 
    516           cur_length -= bytes; 
    517           cur_ptr += bytes; 
    518         } 
    519  
    520       offset += cur_retlen; 
    521       len -= cur_retlen; 
    522       buf += cur_retlen; 
    523     } 
    524  
    525   ret = len; 
    526 done: 
    527   if (block) 
    528     MFREE (osh, block, blocksize); 
    529   return ret; 
     290mod_exit_t 
     291sflash_mtd_exit(void) 
     292{ 
     293#ifdef CONFIG_MTD_PARTITIONS 
     294        del_mtd_partitions(&sflash.mtd); 
     295#else 
     296        del_mtd_device(&sflash.mtd); 
     297#endif 
     298        iounmap((void *) sflash.cc); 
     299        sb_detach(sflash.sbh); 
    530300} 
     301 
     302module_init(sflash_mtd_init); 
     303module_exit(sflash_mtd_exit); 
  • target/linux/brcm-2.4/patches/004-flash.patch

     
     1--- a/arch/mips/bcm947xx/Makefile        
     2+++ b/arch/mips/bcm947xx/Makefile        
     3@@ -11,6 +11,7 @@ 
     4 obj-y          := prom.o setup.o time.o sbmips.o gpio.o 
     5 obj-y          += nvram.o nvram_linux.o cfe_env.o hndpmu.o 
     6 obj-y          += sbutils.o utils.o bcmsrom.o hndchipc.o 
     7+obj-y          += sflash.o 
     8 obj-$(CONFIG_PCI) += sbpci.o pcibios.o 
     9 obj-y          += export.o 
     10  
    111--- a/drivers/mtd/devices/Config.in 
    212+++ b/drivers/mtd/devices/Config.in 
    313@@ -5,6 +5,7 @@