Annotation of qemu/hw/pflash_cfi01.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.