Changeset 19171


Ignore:
Timestamp:
2010-01-16T16:11:52+01:00 (8 years ago)
Author:
jow
Message:

[brcm-2.4] fix serial flash support (#6442)

Location:
trunk/target/linux/brcm-2.4
Files:
2 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/brcm-2.4/files/drivers/mtd/devices/sflash.c

    r15242 r19171  
    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 */ 
     14 
     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> 
    1326 
    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; 
    24  
    25 /* Issue a serial flash command */ 
    26 static INLINE void 
    27 sflash_cmd (osl_t * osh, chipcregs_t * cc, uint opcode) 
    28 { 
    29   W_REG (osh, &cc->flashcontrol, SFLASH_START | opcode); 
    30   while (R_REG (osh, &cc->flashcontrol) & SFLASH_BUSY); 
    31 } 
    32  
    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; 
    98         } 
    99       break; 
    100  
    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; 
    148 } 
    149  
    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) 
    153 { 
    154   uint8 *from, *to; 
    155   int cnt, i; 
    156   osl_t *osh; 
    157  
    158   ASSERT (sbh); 
    159  
    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++; 
    185         } 
    186       return cnt; 
    187     } 
    188  
    189   while (cnt >= 4) 
    190     { 
    191       *(uint32 *) to = R_REG (osh, (uint32 *) from); 
    192       from += 4; 
    193       to += 4; 
    194       cnt -= 4; 
    195     } 
    196  
    197   return (len - cnt); 
    198 } 
    199  
    200 /* Poll for command completion. Returns zero when complete. */ 
    201 int 
    202 sflash_poll (sb_t * sbh, chipcregs_t * cc, uint offset) 
    203 { 
    204   osl_t *osh; 
    205  
    206   ASSERT (sbh); 
    207  
    208   osh = sb_osh (sbh); 
    209  
    210   if (offset >= sflash.size) 
    211     return -22; 
    212  
    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     } 
    224  
    225   return 0; 
    226 } 
    227  
    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) 
    234 { 
    235   struct sflash *sfl; 
    236   int ret = 0; 
    237   bool is4712b0; 
    238   uint32 page, byte, mask; 
    239   osl_t *osh; 
    240  
    241   ASSERT (sbh); 
    242  
    243   osh = sb_osh (sbh); 
    244  
    245   if (!len) 
    246     return 0; 
    247  
    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; 
    282                 } 
    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             } 
    303         } 
    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     } 
    381  
    382   return ret; 
    383 } 
    384  
    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; 
    393  
    394   ASSERT (sbh); 
    395  
    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; 
    416 } 
    417  
    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) 
    425 { 
    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; 
    432  
    433   ASSERT (sbh); 
    434  
    435   osh = sb_osh (sbh); 
    436  
    437   /* Check address range */ 
    438   if (len <= 0) 
    439     return 0; 
    440  
    441   sfl = &sflash; 
    442   if ((offset + len) > sfl->size) 
    443     return -1; 
    444  
    445   blocksize = sfl->blocksize; 
    446   mask = blocksize - 1; 
    447  
    448   /* Allocate a block of mem */ 
    449   if (!(block = MALLOC (osh, blocksize))) 
    450     return -1; 
    451  
    452   while (len) 
    453     { 
    454       /* Align offset */ 
    455       cur_offset = offset & ~mask; 
    456       cur_length = blocksize; 
    457       cur_ptr = block; 
    458  
    459       remainder = blocksize - (offset & mask); 
    460       if (len < remainder) 
    461         cur_retlen = len; 
    462       else 
    463         cur_retlen = remainder; 
    464  
    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); 
    488         } 
    489  
    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)); 
    494  
    495       /* buf == NULL means erase only */ 
    496       if (!buf) 
    497         { 
    498           offset += cur_retlen; 
    499           len -= cur_retlen; 
    500           continue; 
    501         } 
    502  
    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; 
    530 } 
     50static struct sflash_mtd sflash; 
     51 
     52static int 
     53sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout) 
     54{ 
     55        int now = jiffies; 
     56        int ret = 0; 
     57 
     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); 
     73        } 
     74 
     75        return ret; 
     76} 
     77 
     78static int 
     79sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) 
     80{ 
     81        struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; 
     82        int bytes, ret = 0; 
     83 
     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); 
     95 
     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; 
     106        } 
     107 
     108        up(&sflash->lock); 
     109 
     110        return ret; 
     111} 
     112 
     113static int 
     114sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) 
     115{ 
     116        struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; 
     117        int bytes, ret = 0; 
     118 
     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; 
     128 
     129        down(&sflash->lock); 
     130 
     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        } 
     144 
     145        up(&sflash->lock); 
     146 
     147        return ret; 
     148} 
     149 
     150static int 
     151sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) 
     152{ 
     153        struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; 
     154        int i, j, ret = 0; 
     155        unsigned int addr, len; 
     156 
     157        /* Check address range */ 
     158        if (!erase->len) 
     159                return 0; 
     160        if ((erase->addr + erase->len) > mtd->size) 
     161                return -EINVAL; 
     162 
     163        addr = erase->addr; 
     164        len = erase->len; 
     165 
     166        down(&sflash->lock); 
     167 
     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                        } 
     180                } 
     181                if (ret) 
     182                        break; 
     183        } 
     184 
     185        up(&sflash->lock); 
     186 
     187        /* Set erase status */ 
     188        if (ret) 
     189                erase->state = MTD_ERASE_FAILED; 
     190        else  
     191                erase->state = MTD_ERASE_DONE; 
     192 
     193        /* Call erase callback */ 
     194        if (erase->callback) 
     195                erase->callback(erase); 
     196 
     197        return ret; 
     198} 
     199 
     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) 
     207{ 
     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 
     215 
     216        if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_CC, NULL))) { 
     217                printk(KERN_ERR "sflash: chipcommon not found\n"); 
     218                return -ENODEV; 
     219        } 
     220 
     221        memset(&sflash, 0, sizeof(struct sflash_mtd)); 
     222        init_MUTEX(&sflash.lock); 
     223 
     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        } 
     230 
     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        } 
     238 
     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        } 
     245 
     246        printk(KERN_INFO "sflash: found serial flash; blocksize=%dKB, numblocks=%d, size=%dKB\n",info->blocksize/1024,info->numblocks,info->size/1024); 
     247 
     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; 
     256 
     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; 
     267 
     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; 
     278        } 
     279 
     280        return 0; 
     281 
     282 fail: 
     283        if (sflash.cc) 
     284                iounmap((void *) sflash.cc); 
     285        if (sflash.sbh) 
     286                sb_detach(sflash.sbh); 
     287        return ret; 
     288} 
     289 
     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); 
     300} 
     301 
     302module_init(sflash_mtd_init); 
     303module_exit(sflash_mtd_exit); 
  • trunk/target/linux/brcm-2.4/patches/004-flash.patch

    r16144 r19171  
     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 
Note: See TracChangeset for help on using the changeset viewer.