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

File kamikaze-809-brcm24-sflash.patch, 51.8 KB (added by Tony Butler <spudz76@…>, 8 years ago)

repaired version of previous 809 patch

  • 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 * 
    1212 * $Id$ 
    1313 */ 
    1414 
     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 
    1527#include <typedefs.h> 
    1628#include <osl.h> 
     29// #include <bcmutils.h> 
     30#include <bcmdevs.h> 
     31#include <bcmnvram.h> 
    1732#include <sbutils.h> 
    1833#include <sbconfig.h> 
    1934#include <sbchipc.h> 
    20 #include <bcmdevs.h> 
    2135#include <sflash.h> 
    2236 
     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 
    2349/* Private global state */ 
    24 static struct sflash sflash; 
     50static struct sflash_mtd sflash; 
    2551 
    26 /* Issue a serial flash command */ 
    27 static INLINE void 
    28 sflash_cmd (osl_t * osh, chipcregs_t * cc, uint opcode) 
     52static int 
     53sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout) 
    2954{ 
    30   W_REG (osh, &cc->flashcontrol, SFLASH_START | opcode); 
    31   while (R_REG (osh, &cc->flashcontrol) & SFLASH_BUSY); 
    32 } 
     55        int now = jiffies; 
     56        int ret = 0; 
    3357 
    34 /* Initialize serial flash access */ 
    35 struct sflash * 
    36 sflash_init (sb_t * sbh, chipcregs_t * cc) 
    37 { 
    38   uint32 id, id2; 
    39   osl_t *osh; 
    40  
    41   ASSERT (sbh); 
    42  
    43   osh = sb_osh (sbh); 
    44  
    45   bzero (&sflash, sizeof (sflash)); 
    46  
    47   sflash.type = sbh->cccaps & CC_CAP_FLASH_MASK; 
    48  
    49   switch (sflash.type) 
    50     { 
    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         { 
    58         case 0x11: 
    59           /* ST M25P20 2 Mbit Serial Flash */ 
    60           sflash.blocksize = 64 * 1024; 
    61           sflash.numblocks = 4; 
    62           break; 
    63         case 0x12: 
    64           /* ST M25P40 4 Mbit Serial Flash */ 
    65           sflash.blocksize = 64 * 1024; 
    66           sflash.numblocks = 8; 
    67           break; 
    68         case 0x13: 
    69           /* ST M25P80 8 Mbit Serial Flash */ 
    70           sflash.blocksize = 64 * 1024; 
    71           sflash.numblocks = 16; 
    72           break; 
    73         case 0x14: 
    74           /* ST M25P16 16 Mbit Serial Flash */ 
    75           sflash.blocksize = 64 * 1024; 
    76           sflash.numblocks = 32; 
    77           break; 
    78         case 0x15: 
    79           /* ST M25P32 32 Mbit Serial Flash */ 
    80           sflash.blocksize = 64 * 1024; 
    81           sflash.numblocks = 64; 
    82           break; 
    83         case 0x16: 
    84           /* ST M25P64 64 Mbit Serial Flash */ 
    85           sflash.blocksize = 64 * 1024; 
    86           sflash.numblocks = 128; 
    87           break; 
    88         case 0xbf: 
    89           W_REG (osh, &cc->flashaddress, 1); 
    90           sflash_cmd (osh, cc, SFLASH_ST_RES); 
    91           id2 = R_REG (osh, &cc->flashdata); 
    92           if (id2 == 0x44) 
    93             { 
    94               /* SST M25VF80 4 Mbit Serial Flash */ 
    95               sflash.blocksize = 64 * 1024; 
    96               sflash.numblocks = 8; 
    97             } 
    98           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); 
    9973        } 
    100       break; 
    10174 
    102     case SFLASH_AT: 
    103       /* Probe for Atmel chips */ 
    104       sflash_cmd (osh, cc, SFLASH_AT_STATUS); 
    105       id = R_REG (osh, &cc->flashdata) & 0x3c; 
    106       switch (id) 
    107         { 
    108         case 0xc: 
    109           /* Atmel AT45DB011 1Mbit Serial Flash */ 
    110           sflash.blocksize = 256; 
    111           sflash.numblocks = 512; 
    112           break; 
    113         case 0x14: 
    114           /* Atmel AT45DB021 2Mbit Serial Flash */ 
    115           sflash.blocksize = 256; 
    116           sflash.numblocks = 1024; 
    117           break; 
    118         case 0x1c: 
    119           /* Atmel AT45DB041 4Mbit Serial Flash */ 
    120           sflash.blocksize = 256; 
    121           sflash.numblocks = 2048; 
    122           break; 
    123         case 0x24: 
    124           /* Atmel AT45DB081 8Mbit Serial Flash */ 
    125           sflash.blocksize = 256; 
    126           sflash.numblocks = 4096; 
    127           break; 
    128         case 0x2c: 
    129           /* Atmel AT45DB161 16Mbit Serial Flash */ 
    130           sflash.blocksize = 512; 
    131           sflash.numblocks = 4096; 
    132           break; 
    133         case 0x34: 
    134           /* Atmel AT45DB321 32Mbit Serial Flash */ 
    135           sflash.blocksize = 512; 
    136           sflash.numblocks = 8192; 
    137           break; 
    138         case 0x3c: 
    139           /* Atmel AT45DB642 64Mbit Serial Flash */ 
    140           sflash.blocksize = 1024; 
    141           sflash.numblocks = 8192; 
    142           break; 
    143         } 
    144       break; 
    145     } 
    146  
    147   sflash.size = sflash.blocksize * sflash.numblocks; 
    148   return sflash.size ? &sflash : NULL; 
     75        return ret; 
    14976} 
    15077 
    151 /* Read len bytes starting at offset into buf. Returns number of bytes read. */ 
    152 int 
    153 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) 
    15480{ 
    155   uint8 *from, *to; 
    156   int cnt, i; 
    157   osl_t *osh; 
     81        struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; 
     82        int bytes, ret = 0; 
    15883 
    159   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); 
    16095 
    161   if (!len) 
    162     return 0; 
    163  
    164   if ((offset + len) > sflash.size) 
    165     return -22; 
    166  
    167   if ((len >= 4) && (offset & 3)) 
    168     cnt = 4 - (offset & 3); 
    169   else if ((len >= 4) && ((uintptr) buf & 3)) 
    170     cnt = 4 - ((uintptr) buf & 3); 
    171   else 
    172     cnt = len; 
    173  
    174   osh = sb_osh (sbh); 
    175  
    176   from = (uint8 *) (uintptr) OSL_UNCACHED (SB_FLASH2 + offset); 
    177   to = (uint8 *) buf; 
    178  
    179   if (cnt < 4) 
    180     { 
    181       for (i = 0; i < cnt; i++) 
    182         { 
    183           *to = R_REG (osh, from); 
    184           from++; 
    185           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; 
    186106        } 
    187       return cnt; 
    188     } 
    189107 
    190   while (cnt >= 4) 
    191     { 
    192       *(uint32 *) to = R_REG (osh, (uint32 *) from); 
    193       from += 4; 
    194       to += 4; 
    195       cnt -= 4; 
    196     } 
     108        up(&sflash->lock); 
    197109 
    198   return (len - cnt); 
     110        return ret; 
    199111} 
    200112 
    201 /* Poll for command completion. Returns zero when complete. */ 
    202 int 
    203 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) 
    204115{ 
    205   osl_t *osh; 
     116        struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; 
     117        int bytes, ret = 0; 
    206118 
    207   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; 
    208128 
    209   osh = sb_osh (sbh); 
     129        down(&sflash->lock); 
    210130 
    211   if (offset >= sflash.size) 
    212     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        } 
    213144 
    214   switch (sflash.type) 
    215     { 
    216     case SFLASH_ST: 
    217       /* Check for ST Write In Progress bit */ 
    218       sflash_cmd (osh, cc, SFLASH_ST_RDSR); 
    219       return R_REG (osh, &cc->flashdata) & SFLASH_ST_WIP; 
    220     case SFLASH_AT: 
    221       /* Check for Atmel Ready bit */ 
    222       sflash_cmd (osh, cc, SFLASH_AT_STATUS); 
    223       return !(R_REG (osh, &cc->flashdata) & SFLASH_AT_READY); 
    224     } 
     145        up(&sflash->lock); 
    225146 
    226   return 0; 
     147        return ret; 
    227148} 
    228149 
    229 /* Write len bytes starting at offset into buf. Returns number of bytes 
    230  * written. Caller should poll for completion. 
    231  */ 
    232 int 
    233 sflash_write (sb_t * sbh, chipcregs_t * cc, uint offset, uint len, 
    234               const uchar * buf) 
     150static int 
     151sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) 
    235152{ 
    236   struct sflash *sfl; 
    237   int ret = 0; 
    238   bool is4712b0; 
    239   uint32 page, byte, mask; 
    240   osl_t *osh; 
     153        struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; 
     154        int i, j, ret = 0; 
     155        unsigned int addr, len; 
    241156 
    242   ASSERT (sbh); 
     157        /* Check address range */ 
     158        if (!erase->len) 
     159                return 0; 
     160        if ((erase->addr + erase->len) > mtd->size) 
     161                return -EINVAL; 
    243162 
    244   osh = sb_osh (sbh); 
     163        addr = erase->addr; 
     164        len = erase->len; 
    245165 
    246   if (!len) 
    247     return 0; 
     166        down(&sflash->lock); 
    248167 
    249   if ((offset + len) > sflash.size) 
    250     return -22; 
    251  
    252   sfl = &sflash; 
    253   switch (sfl->type) 
    254     { 
    255     case SFLASH_ST: 
    256       is4712b0 = (sbh->chip == BCM4712_CHIP_ID) && (sbh->chiprev == 3); 
    257       /* Enable writes */ 
    258       sflash_cmd (osh, cc, SFLASH_ST_WREN); 
    259       if (is4712b0) 
    260         { 
    261           mask = 1 << 14; 
    262           W_REG (osh, &cc->flashaddress, offset); 
    263           W_REG (osh, &cc->flashdata, *buf++); 
    264           /* Set chip select */ 
    265           OR_REG (osh, &cc->gpioout, mask); 
    266           /* Issue a page program with the first byte */ 
    267           sflash_cmd (osh, cc, SFLASH_ST_PP); 
    268           ret = 1; 
    269           offset++; 
    270           len--; 
    271           while (len > 0) 
    272             { 
    273               if ((offset & 255) == 0) 
    274                 { 
    275                   /* Page boundary, drop cs and return */ 
    276                   AND_REG (osh, &cc->gpioout, ~mask); 
    277                   if (!sflash_poll (sbh, cc, offset)) 
    278                     { 
    279                       /* Flash rejected command */ 
    280                       return -11; 
    281                     } 
    282                   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                        } 
    283180                } 
    284               else 
    285                 { 
    286                   /* Write single byte */ 
    287                   sflash_cmd (osh, cc, *buf++); 
    288                 } 
    289               ret++; 
    290               offset++; 
    291               len--; 
    292             } 
    293           /* All done, drop cs if needed */ 
    294           if ((offset & 255) != 1) 
    295             { 
    296               /* Drop cs */ 
    297               AND_REG (osh, &cc->gpioout, ~mask); 
    298               if (!sflash_poll (sbh, cc, offset)) 
    299                 { 
    300                   /* Flash rejected command */ 
    301                   return -12; 
    302                 } 
    303             } 
     181                if (ret) 
     182                        break; 
    304183        } 
    305       else if (sbh->ccrev >= 20) 
    306         { 
    307           W_REG (NULL, &cc->flashaddress, offset); 
    308           W_REG (NULL, &cc->flashdata, *buf++); 
    309           /* Issue a page program with CSA bit set */ 
    310           sflash_cmd (osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP); 
    311           ret = 1; 
    312           offset++; 
    313           len--; 
    314           while (len > 0) 
    315             { 
    316               if ((offset & 255) == 0) 
    317                 { 
    318                   /* Page boundary, poll droping cs and return */ 
    319                   W_REG (NULL, &cc->flashcontrol, 0); 
    320                   if (!sflash_poll (sbh, cc, offset)) 
    321                     { 
    322                       /* Flash rejected command */ 
    323                       return -11; 
    324                     } 
    325                   return ret; 
    326                 } 
    327               else 
    328                 { 
    329                   /* Write single byte */ 
    330                   sflash_cmd (osh, cc, SFLASH_ST_CSA | *buf++); 
    331                 } 
    332               ret++; 
    333               offset++; 
    334               len--; 
    335             } 
    336           /* All done, drop cs if needed */ 
    337           if ((offset & 255) != 1) 
    338             { 
    339               /* Drop cs, poll */ 
    340               W_REG (NULL, &cc->flashcontrol, 0); 
    341               if (!sflash_poll (sbh, cc, offset)) 
    342                 { 
    343                   /* Flash rejected command */ 
    344                   return -12; 
    345                 } 
    346             } 
    347         } 
    348       else 
    349         { 
    350           ret = 1; 
    351           W_REG (osh, &cc->flashaddress, offset); 
    352           W_REG (osh, &cc->flashdata, *buf); 
    353           /* Page program */ 
    354           sflash_cmd (osh, cc, SFLASH_ST_PP); 
    355         } 
    356       break; 
    357     case SFLASH_AT: 
    358       mask = sfl->blocksize - 1; 
    359       page = (offset & ~mask) << 1; 
    360       byte = offset & mask; 
    361       /* Read main memory page into buffer 1 */ 
    362       if (byte || (len < sfl->blocksize)) 
    363         { 
    364           W_REG (osh, &cc->flashaddress, page); 
    365           sflash_cmd (osh, cc, SFLASH_AT_BUF1_LOAD); 
    366           /* 250 us for AT45DB321B */ 
    367           SPINWAIT (sflash_poll (sbh, cc, offset), 1000); 
    368           ASSERT (!sflash_poll (sbh, cc, offset)); 
    369         } 
    370       /* Write into buffer 1 */ 
    371       for (ret = 0; (ret < (int) len) && (byte < sfl->blocksize); ret++) 
    372         { 
    373           W_REG (osh, &cc->flashaddress, byte++); 
    374           W_REG (osh, &cc->flashdata, *buf++); 
    375           sflash_cmd (osh, cc, SFLASH_AT_BUF1_WRITE); 
    376         } 
    377       /* Write buffer 1 into main memory page */ 
    378       W_REG (osh, &cc->flashaddress, page); 
    379       sflash_cmd (osh, cc, SFLASH_AT_BUF1_PROGRAM); 
    380       break; 
    381     } 
    382184 
    383   return ret; 
    384 } 
     185        up(&sflash->lock); 
    385186 
    386 /* Erase a region. Returns number of bytes scheduled for erasure. 
    387  * Caller should poll for completion. 
    388  */ 
    389 int 
    390 sflash_erase (sb_t * sbh, chipcregs_t * cc, uint offset) 
    391 { 
    392   struct sflash *sfl; 
    393   osl_t *osh; 
     187        /* Set erase status */ 
     188        if (ret) 
     189                erase->state = MTD_ERASE_FAILED; 
     190        else  
     191                erase->state = MTD_ERASE_DONE; 
    394192 
    395   ASSERT (sbh); 
     193        /* Call erase callback */ 
     194        if (erase->callback) 
     195                erase->callback(erase); 
    396196 
    397   osh = sb_osh (sbh); 
    398  
    399   if (offset >= sflash.size) 
    400     return -22; 
    401  
    402   sfl = &sflash; 
    403   switch (sfl->type) 
    404     { 
    405     case SFLASH_ST: 
    406       sflash_cmd (osh, cc, SFLASH_ST_WREN); 
    407       W_REG (osh, &cc->flashaddress, offset); 
    408       sflash_cmd (osh, cc, SFLASH_ST_SE); 
    409       return sfl->blocksize; 
    410     case SFLASH_AT: 
    411       W_REG (osh, &cc->flashaddress, offset << 1); 
    412       sflash_cmd (osh, cc, SFLASH_AT_PAGE_ERASE); 
    413       return sfl->blocksize; 
    414     } 
    415  
    416   return 0; 
     197        return ret; 
    417198} 
    418199 
    419 /* 
    420  * writes the appropriate range of flash, a NULL buf simply erases 
    421  * the region of flash 
    422  */ 
    423 int 
    424 sflash_commit (sb_t * sbh, chipcregs_t * cc, uint offset, uint len, 
    425                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) 
    426207{ 
    427   struct sflash *sfl; 
    428   uchar *block = NULL, *cur_ptr, *blk_ptr; 
    429   uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder; 
    430   uint blk_offset, blk_len, copied; 
    431   int bytes, ret = 0; 
    432   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 
    433215 
    434   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        } 
    435220 
    436   osh = sb_osh (sbh); 
     221        memset(&sflash, 0, sizeof(struct sflash_mtd)); 
     222        init_MUTEX(&sflash.lock); 
    437223 
    438   /* Check address range */ 
    439   if (len <= 0) 
    440     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        } 
    441230 
    442   sfl = &sflash; 
    443   if ((offset + len) > sfl->size) 
    444     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        } 
    445238 
    446   blocksize = sfl->blocksize; 
    447   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        } 
    448245 
    449   /* Allocate a block of mem */ 
    450   if (!(block = MALLOC (osh, blocksize))) 
    451     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); 
    452247 
    453   while (len) 
    454     { 
    455       /* Align offset */ 
    456       cur_offset = offset & ~mask; 
    457       cur_length = blocksize; 
    458       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; 
    459256 
    460       remainder = blocksize - (offset & mask); 
    461       if (len < remainder) 
    462         cur_retlen = len; 
    463       else 
    464         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; 
    465267 
    466       /* buf == NULL means erase only */ 
    467       if (buf) 
    468         { 
    469           /* Copy existing data into holding block if necessary */ 
    470           if ((offset & mask) || (len < blocksize)) 
    471             { 
    472               blk_offset = cur_offset; 
    473               blk_len = cur_length; 
    474               blk_ptr = cur_ptr; 
    475  
    476               /* Copy entire block */ 
    477               while (blk_len) 
    478                 { 
    479                   copied = 
    480                     sflash_read (sbh, cc, blk_offset, blk_len, blk_ptr); 
    481                   blk_offset += copied; 
    482                   blk_len -= copied; 
    483                   blk_ptr += copied; 
    484                 } 
    485             } 
    486  
    487           /* Copy input data into holding block */ 
    488           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; 
    489278        } 
    490279 
    491       /* Erase block */ 
    492       if ((ret = sflash_erase (sbh, cc, (uint) cur_offset)) < 0) 
    493         goto done; 
    494       while (sflash_poll (sbh, cc, (uint) cur_offset)); 
     280        return 0; 
    495281 
    496       /* buf == NULL means erase only */ 
    497       if (!buf) 
    498         { 
    499           offset += cur_retlen; 
    500           len -= cur_retlen; 
    501           continue; 
    502         } 
     282 fail: 
     283        if (sflash.cc) 
     284                iounmap((void *) sflash.cc); 
     285        if (sflash.sbh) 
     286                sb_detach(sflash.sbh); 
     287        return ret; 
     288} 
    503289 
    504       /* Write holding block */ 
    505       while (cur_length > 0) 
    506         { 
    507           if ((bytes = sflash_write (sbh, cc, 
    508                                      (uint) cur_offset, 
    509                                      (uint) cur_length, 
    510                                      (uchar *) cur_ptr)) < 0) 
    511             { 
    512               ret = bytes; 
    513               goto done; 
    514             } 
    515           while (sflash_poll (sbh, cc, (uint) cur_offset)); 
    516           cur_offset += bytes; 
    517           cur_length -= bytes; 
    518           cur_ptr += bytes; 
    519         } 
    520  
    521       offset += cur_retlen; 
    522       len -= cur_retlen; 
    523       buf += cur_retlen; 
    524     } 
    525  
    526   ret = len; 
    527 done: 
    528   if (block) 
    529     MFREE (osh, block, blocksize); 
    530   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); 
    531300} 
     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 @@