symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/pflash_cfi02.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  *  CFI parallel flash with AMD command set emulation
       
     3  *
       
     4  *  Copyright (c) 2005 Jocelyn Mayer
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Lesser General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Lesser General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Lesser General Public
       
    17  * License along with this library; if not, write to the Free Software
       
    18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    19  */
       
    20 
       
    21 /*
       
    22  * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
       
    23  * Supported commands/modes are:
       
    24  * - flash read
       
    25  * - flash write
       
    26  * - flash ID read
       
    27  * - sector erase
       
    28  * - chip erase
       
    29  * - unlock bypass command
       
    30  * - CFI queries
       
    31  *
       
    32  * It does not support flash interleaving.
       
    33  * It does not implement boot blocs with reduced size
       
    34  * It does not implement software data protection as found in many real chips
       
    35  * It does not implement erase suspend/resume commands
       
    36  * It does not implement multiple sectors erase
       
    37  */
       
    38 
       
    39 #include "hw.h"
       
    40 #include "flash.h"
       
    41 #include "qemu-timer.h"
       
    42 #include "block.h"
       
    43 
       
    44 //#define PFLASH_DEBUG
       
    45 #ifdef PFLASH_DEBUG
       
    46 #define DPRINTF(fmt, args...)                      \
       
    47 do {                                               \
       
    48         printf("PFLASH: " fmt , ##args);           \
       
    49 } while (0)
       
    50 #else
       
    51 #define DPRINTF(fmt, args...) do { } while (0)
       
    52 #endif
       
    53 
       
    54 struct pflash_t {
       
    55     BlockDriverState *bs;
       
    56     target_phys_addr_t base;
       
    57     uint32_t sector_len;
       
    58     uint32_t chip_len;
       
    59     int mappings;
       
    60     int width;
       
    61     int wcycle; /* if 0, the flash is read normally */
       
    62     int bypass;
       
    63     int ro;
       
    64     uint8_t cmd;
       
    65     uint8_t status;
       
    66     uint16_t ident[4];
       
    67     uint16_t unlock_addr[2];
       
    68     uint8_t cfi_len;
       
    69     uint8_t cfi_table[0x52];
       
    70     QEMUTimer *timer;
       
    71     ram_addr_t off;
       
    72     int fl_mem;
       
    73     int rom_mode;
       
    74     void *storage;
       
    75 };
       
    76 
       
    77 static void pflash_register_memory(pflash_t *pfl, int rom_mode)
       
    78 {
       
    79     unsigned long phys_offset = pfl->fl_mem;
       
    80     int i;
       
    81 
       
    82     if (rom_mode)
       
    83         phys_offset |= pfl->off | IO_MEM_ROMD;
       
    84     pfl->rom_mode = rom_mode;
       
    85 
       
    86     for (i = 0; i < pfl->mappings; i++)
       
    87         cpu_register_physical_memory(pfl->base + i * pfl->chip_len,
       
    88                                      pfl->chip_len, phys_offset);
       
    89 }
       
    90 
       
    91 static void pflash_timer (void *opaque)
       
    92 {
       
    93     pflash_t *pfl = opaque;
       
    94 
       
    95     DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
       
    96     /* Reset flash */
       
    97     pfl->status ^= 0x80;
       
    98     if (pfl->bypass) {
       
    99         pfl->wcycle = 2;
       
   100     } else {
       
   101         pflash_register_memory(pfl, 1);
       
   102         pfl->wcycle = 0;
       
   103     }
       
   104     pfl->cmd = 0;
       
   105 }
       
   106 
       
   107 static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width)
       
   108 {
       
   109     uint32_t boff;
       
   110     uint32_t ret;
       
   111     uint8_t *p;
       
   112 
       
   113     DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset);
       
   114     ret = -1;
       
   115     if (pfl->rom_mode) {
       
   116         /* Lazy reset of to ROMD mode */
       
   117         if (pfl->wcycle == 0)
       
   118             pflash_register_memory(pfl, 1);
       
   119     }
       
   120     offset &= pfl->chip_len - 1;
       
   121     boff = offset & 0xFF;
       
   122     if (pfl->width == 2)
       
   123         boff = boff >> 1;
       
   124     else if (pfl->width == 4)
       
   125         boff = boff >> 2;
       
   126     switch (pfl->cmd) {
       
   127     default:
       
   128         /* This should never happen : reset state & treat it as a read*/
       
   129         DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
       
   130         pfl->wcycle = 0;
       
   131         pfl->cmd = 0;
       
   132     case 0x80:
       
   133         /* We accept reads during second unlock sequence... */
       
   134     case 0x00:
       
   135     flash_read:
       
   136         /* Flash area read */
       
   137         p = pfl->storage;
       
   138         switch (width) {
       
   139         case 1:
       
   140             ret = p[offset];
       
   141 //            DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
       
   142             break;
       
   143         case 2:
       
   144 #if defined(TARGET_WORDS_BIGENDIAN)
       
   145             ret = p[offset] << 8;
       
   146             ret |= p[offset + 1];
       
   147 #else
       
   148             ret = p[offset];
       
   149             ret |= p[offset + 1] << 8;
       
   150 #endif
       
   151 //            DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
       
   152             break;
       
   153         case 4:
       
   154 #if defined(TARGET_WORDS_BIGENDIAN)
       
   155             ret = p[offset] << 24;
       
   156             ret |= p[offset + 1] << 16;
       
   157             ret |= p[offset + 2] << 8;
       
   158             ret |= p[offset + 3];
       
   159 #else
       
   160             ret = p[offset];
       
   161             ret |= p[offset + 1] << 8;
       
   162             ret |= p[offset + 2] << 16;
       
   163             ret |= p[offset + 3] << 24;
       
   164 #endif
       
   165 //            DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
       
   166             break;
       
   167         }
       
   168         break;
       
   169     case 0x90:
       
   170         /* flash ID read */
       
   171         switch (boff) {
       
   172         case 0x00:
       
   173         case 0x01:
       
   174             ret = pfl->ident[boff & 0x01];
       
   175             break;
       
   176         case 0x02:
       
   177             ret = 0x00; /* Pretend all sectors are unprotected */
       
   178             break;
       
   179         case 0x0E:
       
   180         case 0x0F:
       
   181             if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
       
   182                 goto flash_read;
       
   183             ret = pfl->ident[2 + (boff & 0x01)];
       
   184             break;
       
   185         default:
       
   186             goto flash_read;
       
   187         }
       
   188         DPRINTF("%s: ID " TARGET_FMT_ld " %x\n", __func__, boff, ret);
       
   189         break;
       
   190     case 0xA0:
       
   191     case 0x10:
       
   192     case 0x30:
       
   193         /* Status register read */
       
   194         ret = pfl->status;
       
   195         DPRINTF("%s: status %x\n", __func__, ret);
       
   196         /* Toggle bit 6 */
       
   197         pfl->status ^= 0x40;
       
   198         break;
       
   199     case 0x98:
       
   200         /* CFI query mode */
       
   201         if (boff > pfl->cfi_len)
       
   202             ret = 0;
       
   203         else
       
   204             ret = pfl->cfi_table[boff];
       
   205         break;
       
   206     }
       
   207 
       
   208     return ret;
       
   209 }
       
   210 
       
   211 /* update flash content on disk */
       
   212 static void pflash_update(pflash_t *pfl, int offset,
       
   213                           int size)
       
   214 {
       
   215     int offset_end;
       
   216     if (pfl->bs) {
       
   217         offset_end = offset + size;
       
   218         /* round to sectors */
       
   219         offset = offset >> 9;
       
   220         offset_end = (offset_end + 511) >> 9;
       
   221         bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
       
   222                    offset_end - offset);
       
   223     }
       
   224 }
       
   225 
       
   226 static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value,
       
   227                           int width)
       
   228 {
       
   229     uint32_t boff;
       
   230     uint8_t *p;
       
   231     uint8_t cmd;
       
   232 
       
   233     cmd = value;
       
   234     if (pfl->cmd != 0xA0 && cmd == 0xF0) {
       
   235 #if 0
       
   236         DPRINTF("%s: flash reset asked (%02x %02x)\n",
       
   237                 __func__, pfl->cmd, cmd);
       
   238 #endif
       
   239         goto reset_flash;
       
   240     }
       
   241     DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__,
       
   242             offset, value, width, pfl->wcycle);
       
   243     offset &= pfl->chip_len - 1;
       
   244 
       
   245     DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__,
       
   246             offset, value, width);
       
   247     boff = offset & (pfl->sector_len - 1);
       
   248     if (pfl->width == 2)
       
   249         boff = boff >> 1;
       
   250     else if (pfl->width == 4)
       
   251         boff = boff >> 2;
       
   252     switch (pfl->wcycle) {
       
   253     case 0:
       
   254         /* Set the device in I/O access mode if required */
       
   255         if (pfl->rom_mode)
       
   256             pflash_register_memory(pfl, 0);
       
   257         /* We're in read mode */
       
   258     check_unlock0:
       
   259         if (boff == 0x55 && cmd == 0x98) {
       
   260         enter_CFI_mode:
       
   261             /* Enter CFI query mode */
       
   262             pfl->wcycle = 7;
       
   263             pfl->cmd = 0x98;
       
   264             return;
       
   265         }
       
   266         if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
       
   267             DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n",
       
   268                     __func__, boff, cmd, pfl->unlock_addr[0]);
       
   269             goto reset_flash;
       
   270         }
       
   271         DPRINTF("%s: unlock sequence started\n", __func__);
       
   272         break;
       
   273     case 1:
       
   274         /* We started an unlock sequence */
       
   275     check_unlock1:
       
   276         if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
       
   277             DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__,
       
   278                     boff, cmd);
       
   279             goto reset_flash;
       
   280         }
       
   281         DPRINTF("%s: unlock sequence done\n", __func__);
       
   282         break;
       
   283     case 2:
       
   284         /* We finished an unlock sequence */
       
   285         if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
       
   286             DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__,
       
   287                     boff, cmd);
       
   288             goto reset_flash;
       
   289         }
       
   290         switch (cmd) {
       
   291         case 0x20:
       
   292             pfl->bypass = 1;
       
   293             goto do_bypass;
       
   294         case 0x80:
       
   295         case 0x90:
       
   296         case 0xA0:
       
   297             pfl->cmd = cmd;
       
   298             DPRINTF("%s: starting command %02x\n", __func__, cmd);
       
   299             break;
       
   300         default:
       
   301             DPRINTF("%s: unknown command %02x\n", __func__, cmd);
       
   302             goto reset_flash;
       
   303         }
       
   304         break;
       
   305     case 3:
       
   306         switch (pfl->cmd) {
       
   307         case 0x80:
       
   308             /* We need another unlock sequence */
       
   309             goto check_unlock0;
       
   310         case 0xA0:
       
   311             DPRINTF("%s: write data offset " TARGET_FMT_lx " %08x %d\n",
       
   312                     __func__, offset, value, width);
       
   313             p = pfl->storage;
       
   314             switch (width) {
       
   315             case 1:
       
   316                 p[offset] &= value;
       
   317                 pflash_update(pfl, offset, 1);
       
   318                 break;
       
   319             case 2:
       
   320 #if defined(TARGET_WORDS_BIGENDIAN)
       
   321                 p[offset] &= value >> 8;
       
   322                 p[offset + 1] &= value;
       
   323 #else
       
   324                 p[offset] &= value;
       
   325                 p[offset + 1] &= value >> 8;
       
   326 #endif
       
   327                 pflash_update(pfl, offset, 2);
       
   328                 break;
       
   329             case 4:
       
   330 #if defined(TARGET_WORDS_BIGENDIAN)
       
   331                 p[offset] &= value >> 24;
       
   332                 p[offset + 1] &= value >> 16;
       
   333                 p[offset + 2] &= value >> 8;
       
   334                 p[offset + 3] &= value;
       
   335 #else
       
   336                 p[offset] &= value;
       
   337                 p[offset + 1] &= value >> 8;
       
   338                 p[offset + 2] &= value >> 16;
       
   339                 p[offset + 3] &= value >> 24;
       
   340 #endif
       
   341                 pflash_update(pfl, offset, 4);
       
   342                 break;
       
   343             }
       
   344             pfl->status = 0x00 | ~(value & 0x80);
       
   345             /* Let's pretend write is immediate */
       
   346             if (pfl->bypass)
       
   347                 goto do_bypass;
       
   348             goto reset_flash;
       
   349         case 0x90:
       
   350             if (pfl->bypass && cmd == 0x00) {
       
   351                 /* Unlock bypass reset */
       
   352                 goto reset_flash;
       
   353             }
       
   354             /* We can enter CFI query mode from autoselect mode */
       
   355             if (boff == 0x55 && cmd == 0x98)
       
   356                 goto enter_CFI_mode;
       
   357             /* No break here */
       
   358         default:
       
   359             DPRINTF("%s: invalid write for command %02x\n",
       
   360                     __func__, pfl->cmd);
       
   361             goto reset_flash;
       
   362         }
       
   363     case 4:
       
   364         switch (pfl->cmd) {
       
   365         case 0xA0:
       
   366             /* Ignore writes while flash data write is occuring */
       
   367             /* As we suppose write is immediate, this should never happen */
       
   368             return;
       
   369         case 0x80:
       
   370             goto check_unlock1;
       
   371         default:
       
   372             /* Should never happen */
       
   373             DPRINTF("%s: invalid command state %02x (wc 4)\n",
       
   374                     __func__, pfl->cmd);
       
   375             goto reset_flash;
       
   376         }
       
   377         break;
       
   378     case 5:
       
   379         switch (cmd) {
       
   380         case 0x10:
       
   381             if (boff != pfl->unlock_addr[0]) {
       
   382                 DPRINTF("%s: chip erase: invalid address " TARGET_FMT_lx "\n",
       
   383                         __func__, offset);
       
   384                 goto reset_flash;
       
   385             }
       
   386             /* Chip erase */
       
   387             DPRINTF("%s: start chip erase\n", __func__);
       
   388             memset(pfl->storage, 0xFF, pfl->chip_len);
       
   389             pfl->status = 0x00;
       
   390             pflash_update(pfl, 0, pfl->chip_len);
       
   391             /* Let's wait 5 seconds before chip erase is done */
       
   392             qemu_mod_timer(pfl->timer,
       
   393                            qemu_get_clock(vm_clock) + (ticks_per_sec * 5));
       
   394             break;
       
   395         case 0x30:
       
   396             /* Sector erase */
       
   397             p = pfl->storage;
       
   398             offset &= ~(pfl->sector_len - 1);
       
   399             DPRINTF("%s: start sector erase at " TARGET_FMT_lx "\n", __func__,
       
   400                     offset);
       
   401             memset(p + offset, 0xFF, pfl->sector_len);
       
   402             pflash_update(pfl, offset, pfl->sector_len);
       
   403             pfl->status = 0x00;
       
   404             /* Let's wait 1/2 second before sector erase is done */
       
   405             qemu_mod_timer(pfl->timer,
       
   406                            qemu_get_clock(vm_clock) + (ticks_per_sec / 2));
       
   407             break;
       
   408         default:
       
   409             DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
       
   410             goto reset_flash;
       
   411         }
       
   412         pfl->cmd = cmd;
       
   413         break;
       
   414     case 6:
       
   415         switch (pfl->cmd) {
       
   416         case 0x10:
       
   417             /* Ignore writes during chip erase */
       
   418             return;
       
   419         case 0x30:
       
   420             /* Ignore writes during sector erase */
       
   421             return;
       
   422         default:
       
   423             /* Should never happen */
       
   424             DPRINTF("%s: invalid command state %02x (wc 6)\n",
       
   425                     __func__, pfl->cmd);
       
   426             goto reset_flash;
       
   427         }
       
   428         break;
       
   429     case 7: /* Special value for CFI queries */
       
   430         DPRINTF("%s: invalid write in CFI query mode\n", __func__);
       
   431         goto reset_flash;
       
   432     default:
       
   433         /* Should never happen */
       
   434         DPRINTF("%s: invalid write state (wc 7)\n",  __func__);
       
   435         goto reset_flash;
       
   436     }
       
   437     pfl->wcycle++;
       
   438 
       
   439     return;
       
   440 
       
   441     /* Reset flash */
       
   442  reset_flash:
       
   443     pfl->bypass = 0;
       
   444     pfl->wcycle = 0;
       
   445     pfl->cmd = 0;
       
   446     return;
       
   447 
       
   448  do_bypass:
       
   449     pfl->wcycle = 2;
       
   450     pfl->cmd = 0;
       
   451     return;
       
   452 }
       
   453 
       
   454 
       
   455 static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr)
       
   456 {
       
   457     return pflash_read(opaque, addr, 1);
       
   458 }
       
   459 
       
   460 static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
       
   461 {
       
   462     pflash_t *pfl = opaque;
       
   463 
       
   464     return pflash_read(pfl, addr, 2);
       
   465 }
       
   466 
       
   467 static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
       
   468 {
       
   469     pflash_t *pfl = opaque;
       
   470 
       
   471     return pflash_read(pfl, addr, 4);
       
   472 }
       
   473 
       
   474 static void pflash_writeb (void *opaque, target_phys_addr_t addr,
       
   475                            uint32_t value)
       
   476 {
       
   477     pflash_write(opaque, addr, value, 1);
       
   478 }
       
   479 
       
   480 static void pflash_writew (void *opaque, target_phys_addr_t addr,
       
   481                            uint32_t value)
       
   482 {
       
   483     pflash_t *pfl = opaque;
       
   484 
       
   485     pflash_write(pfl, addr, value, 2);
       
   486 }
       
   487 
       
   488 static void pflash_writel (void *opaque, target_phys_addr_t addr,
       
   489                            uint32_t value)
       
   490 {
       
   491     pflash_t *pfl = opaque;
       
   492 
       
   493     pflash_write(pfl, addr, value, 4);
       
   494 }
       
   495 
       
   496 static CPUWriteMemoryFunc *pflash_write_ops[] = {
       
   497     &pflash_writeb,
       
   498     &pflash_writew,
       
   499     &pflash_writel,
       
   500 };
       
   501 
       
   502 static CPUReadMemoryFunc *pflash_read_ops[] = {
       
   503     &pflash_readb,
       
   504     &pflash_readw,
       
   505     &pflash_readl,
       
   506 };
       
   507 
       
   508 /* Count trailing zeroes of a 32 bits quantity */
       
   509 static int ctz32 (uint32_t n)
       
   510 {
       
   511     int ret;
       
   512 
       
   513     ret = 0;
       
   514     if (!(n & 0xFFFF)) {
       
   515         ret += 16;
       
   516         n = n >> 16;
       
   517     }
       
   518     if (!(n & 0xFF)) {
       
   519         ret += 8;
       
   520         n = n >> 8;
       
   521     }
       
   522     if (!(n & 0xF)) {
       
   523         ret += 4;
       
   524         n = n >> 4;
       
   525     }
       
   526     if (!(n & 0x3)) {
       
   527         ret += 2;
       
   528         n = n >> 2;
       
   529     }
       
   530     if (!(n & 0x1)) {
       
   531         ret++;
       
   532         n = n >> 1;
       
   533     }
       
   534 #if 0 /* This is not necessary as n is never 0 */
       
   535     if (!n)
       
   536         ret++;
       
   537 #endif
       
   538 
       
   539     return ret;
       
   540 }
       
   541 
       
   542 pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
       
   543                                 BlockDriverState *bs, uint32_t sector_len,
       
   544                                 int nb_blocs, int nb_mappings, int width,
       
   545                                 uint16_t id0, uint16_t id1,
       
   546                                 uint16_t id2, uint16_t id3,
       
   547                                 uint16_t unlock_addr0, uint16_t unlock_addr1)
       
   548 {
       
   549     pflash_t *pfl;
       
   550     int32_t chip_len;
       
   551 
       
   552     chip_len = sector_len * nb_blocs;
       
   553     /* XXX: to be fixed */
       
   554 #if 0
       
   555     if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
       
   556         total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
       
   557         return NULL;
       
   558 #endif
       
   559     pfl = qemu_mallocz(sizeof(pflash_t));
       
   560     if (pfl == NULL)
       
   561         return NULL;
       
   562     /* FIXME: This is broken if it spans multiple RAM regions.  */
       
   563     pfl->storage = host_ram_addr(off);
       
   564     pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops,
       
   565                                          pfl);
       
   566     pfl->off = off;
       
   567     pfl->base = base;
       
   568     pfl->chip_len = chip_len;
       
   569     pfl->mappings = nb_mappings;
       
   570     pflash_register_memory(pfl, 1);
       
   571     pfl->bs = bs;
       
   572     if (pfl->bs) {
       
   573         /* read the initial flash content */
       
   574         bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
       
   575     }
       
   576 #if 0 /* XXX: there should be a bit to set up read-only,
       
   577        *      the same way the hardware does (with WP pin).
       
   578        */
       
   579     pfl->ro = 1;
       
   580 #else
       
   581     pfl->ro = 0;
       
   582 #endif
       
   583     pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
       
   584     pfl->sector_len = sector_len;
       
   585     pfl->width = width;
       
   586     pfl->wcycle = 0;
       
   587     pfl->cmd = 0;
       
   588     pfl->status = 0;
       
   589     pfl->ident[0] = id0;
       
   590     pfl->ident[1] = id1;
       
   591     pfl->ident[2] = id2;
       
   592     pfl->ident[3] = id3;
       
   593     pfl->unlock_addr[0] = unlock_addr0;
       
   594     pfl->unlock_addr[1] = unlock_addr1;
       
   595     /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
       
   596     pfl->cfi_len = 0x52;
       
   597     /* Standard "QRY" string */
       
   598     pfl->cfi_table[0x10] = 'Q';
       
   599     pfl->cfi_table[0x11] = 'R';
       
   600     pfl->cfi_table[0x12] = 'Y';
       
   601     /* Command set (AMD/Fujitsu) */
       
   602     pfl->cfi_table[0x13] = 0x02;
       
   603     pfl->cfi_table[0x14] = 0x00;
       
   604     /* Primary extended table address */
       
   605     pfl->cfi_table[0x15] = 0x31;
       
   606     pfl->cfi_table[0x16] = 0x00;
       
   607     /* Alternate command set (none) */
       
   608     pfl->cfi_table[0x17] = 0x00;
       
   609     pfl->cfi_table[0x18] = 0x00;
       
   610     /* Alternate extended table (none) */
       
   611     pfl->cfi_table[0x19] = 0x00;
       
   612     pfl->cfi_table[0x1A] = 0x00;
       
   613     /* Vcc min */
       
   614     pfl->cfi_table[0x1B] = 0x27;
       
   615     /* Vcc max */
       
   616     pfl->cfi_table[0x1C] = 0x36;
       
   617     /* Vpp min (no Vpp pin) */
       
   618     pfl->cfi_table[0x1D] = 0x00;
       
   619     /* Vpp max (no Vpp pin) */
       
   620     pfl->cfi_table[0x1E] = 0x00;
       
   621     /* Reserved */
       
   622     pfl->cfi_table[0x1F] = 0x07;
       
   623     /* Timeout for min size buffer write (NA) */
       
   624     pfl->cfi_table[0x20] = 0x00;
       
   625     /* Typical timeout for block erase (512 ms) */
       
   626     pfl->cfi_table[0x21] = 0x09;
       
   627     /* Typical timeout for full chip erase (4096 ms) */
       
   628     pfl->cfi_table[0x22] = 0x0C;
       
   629     /* Reserved */
       
   630     pfl->cfi_table[0x23] = 0x01;
       
   631     /* Max timeout for buffer write (NA) */
       
   632     pfl->cfi_table[0x24] = 0x00;
       
   633     /* Max timeout for block erase */
       
   634     pfl->cfi_table[0x25] = 0x0A;
       
   635     /* Max timeout for chip erase */
       
   636     pfl->cfi_table[0x26] = 0x0D;
       
   637     /* Device size */
       
   638     pfl->cfi_table[0x27] = ctz32(chip_len);
       
   639     /* Flash device interface (8 & 16 bits) */
       
   640     pfl->cfi_table[0x28] = 0x02;
       
   641     pfl->cfi_table[0x29] = 0x00;
       
   642     /* Max number of bytes in multi-bytes write */
       
   643     /* XXX: disable buffered write as it's not supported */
       
   644     //    pfl->cfi_table[0x2A] = 0x05;
       
   645     pfl->cfi_table[0x2A] = 0x00;
       
   646     pfl->cfi_table[0x2B] = 0x00;
       
   647     /* Number of erase block regions (uniform) */
       
   648     pfl->cfi_table[0x2C] = 0x01;
       
   649     /* Erase block region 1 */
       
   650     pfl->cfi_table[0x2D] = nb_blocs - 1;
       
   651     pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
       
   652     pfl->cfi_table[0x2F] = sector_len >> 8;
       
   653     pfl->cfi_table[0x30] = sector_len >> 16;
       
   654 
       
   655     /* Extended */
       
   656     pfl->cfi_table[0x31] = 'P';
       
   657     pfl->cfi_table[0x32] = 'R';
       
   658     pfl->cfi_table[0x33] = 'I';
       
   659 
       
   660     pfl->cfi_table[0x34] = '1';
       
   661     pfl->cfi_table[0x35] = '0';
       
   662 
       
   663     pfl->cfi_table[0x36] = 0x00;
       
   664     pfl->cfi_table[0x37] = 0x00;
       
   665     pfl->cfi_table[0x38] = 0x00;
       
   666     pfl->cfi_table[0x39] = 0x00;
       
   667 
       
   668     pfl->cfi_table[0x3a] = 0x00;
       
   669 
       
   670     pfl->cfi_table[0x3b] = 0x00;
       
   671     pfl->cfi_table[0x3c] = 0x00;
       
   672 
       
   673     return pfl;
       
   674 }