|
|
1.1 root 1: /*
2: * CFI parallel flash with AMD command set emulation
1.1.1.3 root 3: *
1.1 root 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
1.1.1.4 ! root 18: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
1.1 root 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:
1.1.1.3 root 39: #include "hw.h"
40: #include "flash.h"
41: #include "qemu-timer.h"
42: #include "block.h"
1.1 root 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;
1.1.1.3 root 56: target_phys_addr_t base;
57: uint32_t sector_len;
1.1.1.4 ! root 58: uint32_t chip_len;
! 59: int mappings;
1.1 root 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];
1.1.1.4 ! root 67: uint16_t unlock_addr[2];
1.1 root 68: uint8_t cfi_len;
69: uint8_t cfi_table[0x52];
70: QEMUTimer *timer;
71: ram_addr_t off;
72: int fl_mem;
1.1.1.4 ! root 73: int rom_mode;
1.1 root 74: void *storage;
75: };
76:
1.1.1.4 ! root 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:
1.1 root 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 {
1.1.1.4 ! root 101: pflash_register_memory(pfl, 1);
1.1 root 102: pfl->wcycle = 0;
103: }
104: pfl->cmd = 0;
105: }
106:
1.1.1.3 root 107: static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width)
1.1 root 108: {
1.1.1.3 root 109: uint32_t boff;
1.1 root 110: uint32_t ret;
111: uint8_t *p;
112:
1.1.1.3 root 113: DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset);
1.1 root 114: ret = -1;
1.1.1.4 ! root 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;
1.1 root 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: }
1.1.1.3 root 188: DPRINTF("%s: ID " TARGET_FMT_ld " %x\n", __func__, boff, ret);
1.1 root 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 */
1.1.1.3 root 212: static void pflash_update(pflash_t *pfl, int offset,
1.1 root 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;
1.1.1.3 root 221: bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
1.1 root 222: offset_end - offset);
223: }
224: }
225:
1.1.1.3 root 226: static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value,
1.1 root 227: int width)
228: {
1.1.1.3 root 229: uint32_t boff;
1.1 root 230: uint8_t *p;
231: uint8_t cmd;
232:
233: cmd = value;
234: if (pfl->cmd != 0xA0 && cmd == 0xF0) {
1.1.1.3 root 235: #if 0
1.1 root 236: DPRINTF("%s: flash reset asked (%02x %02x)\n",
237: __func__, pfl->cmd, cmd);
1.1.1.3 root 238: #endif
1.1 root 239: goto reset_flash;
240: }
1.1.1.3 root 241: DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__,
242: offset, value, width, pfl->wcycle);
1.1.1.4 ! root 243: offset &= pfl->chip_len - 1;
1.1.1.3 root 244:
245: DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__,
246: offset, value, width);
1.1 root 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:
1.1.1.4 ! root 254: /* Set the device in I/O access mode if required */
! 255: if (pfl->rom_mode)
! 256: pflash_register_memory(pfl, 0);
1.1 root 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: }
1.1.1.4 ! root 266: if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
1.1.1.3 root 267: DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n",
1.1.1.4 ! root 268: __func__, boff, cmd, pfl->unlock_addr[0]);
1.1 root 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:
1.1.1.4 ! root 276: if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
1.1.1.3 root 277: DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__,
278: boff, cmd);
1.1 root 279: goto reset_flash;
280: }
281: DPRINTF("%s: unlock sequence done\n", __func__);
282: break;
283: case 2:
284: /* We finished an unlock sequence */
1.1.1.4 ! root 285: if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
1.1.1.3 root 286: DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__,
287: boff, cmd);
1.1 root 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:
1.1.1.3 root 311: DPRINTF("%s: write data offset " TARGET_FMT_lx " %08x %d\n",
1.1 root 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:
1.1.1.4 ! root 381: if (boff != pfl->unlock_addr[0]) {
1.1.1.3 root 382: DPRINTF("%s: chip erase: invalid address " TARGET_FMT_lx "\n",
1.1 root 383: __func__, offset);
384: goto reset_flash;
385: }
386: /* Chip erase */
387: DPRINTF("%s: start chip erase\n", __func__);
1.1.1.4 ! root 388: memset(pfl->storage, 0xFF, pfl->chip_len);
1.1 root 389: pfl->status = 0x00;
1.1.1.4 ! root 390: pflash_update(pfl, 0, pfl->chip_len);
1.1 root 391: /* Let's wait 5 seconds before chip erase is done */
1.1.1.3 root 392: qemu_mod_timer(pfl->timer,
1.1 root 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);
1.1.1.3 root 399: DPRINTF("%s: start sector erase at " TARGET_FMT_lx "\n", __func__,
400: offset);
1.1 root 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 */
1.1.1.3 root 405: qemu_mod_timer(pfl->timer,
1.1 root 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:
1.1.1.3 root 542: pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
543: BlockDriverState *bs, uint32_t sector_len,
1.1.1.4 ! root 544: int nb_blocs, int nb_mappings, int width,
1.1.1.3 root 545: uint16_t id0, uint16_t id1,
1.1.1.4 ! root 546: uint16_t id2, uint16_t id3,
! 547: uint16_t unlock_addr0, uint16_t unlock_addr1)
1.1 root 548: {
549: pflash_t *pfl;
1.1.1.4 ! root 550: int32_t chip_len;
1.1 root 551:
1.1.1.4 ! root 552: chip_len = sector_len * nb_blocs;
1.1 root 553: /* XXX: to be fixed */
1.1.1.3 root 554: #if 0
1.1 root 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;
1.1.1.3 root 558: #endif
1.1 root 559: pfl = qemu_mallocz(sizeof(pflash_t));
560: pfl->storage = phys_ram_base + off;
1.1.1.3 root 561: pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops,
562: pfl);
1.1 root 563: pfl->off = off;
1.1.1.4 ! root 564: pfl->base = base;
! 565: pfl->chip_len = chip_len;
! 566: pfl->mappings = nb_mappings;
! 567: pflash_register_memory(pfl, 1);
1.1 root 568: pfl->bs = bs;
569: if (pfl->bs) {
570: /* read the initial flash content */
1.1.1.4 ! root 571: bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
1.1 root 572: }
573: #if 0 /* XXX: there should be a bit to set up read-only,
574: * the same way the hardware does (with WP pin).
575: */
576: pfl->ro = 1;
577: #else
578: pfl->ro = 0;
579: #endif
580: pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
581: pfl->sector_len = sector_len;
582: pfl->width = width;
583: pfl->wcycle = 0;
584: pfl->cmd = 0;
585: pfl->status = 0;
586: pfl->ident[0] = id0;
587: pfl->ident[1] = id1;
588: pfl->ident[2] = id2;
589: pfl->ident[3] = id3;
1.1.1.4 ! root 590: pfl->unlock_addr[0] = unlock_addr0;
! 591: pfl->unlock_addr[1] = unlock_addr1;
1.1 root 592: /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
593: pfl->cfi_len = 0x52;
594: /* Standard "QRY" string */
595: pfl->cfi_table[0x10] = 'Q';
596: pfl->cfi_table[0x11] = 'R';
597: pfl->cfi_table[0x12] = 'Y';
598: /* Command set (AMD/Fujitsu) */
599: pfl->cfi_table[0x13] = 0x02;
600: pfl->cfi_table[0x14] = 0x00;
1.1.1.4 ! root 601: /* Primary extended table address */
! 602: pfl->cfi_table[0x15] = 0x31;
1.1 root 603: pfl->cfi_table[0x16] = 0x00;
604: /* Alternate command set (none) */
605: pfl->cfi_table[0x17] = 0x00;
606: pfl->cfi_table[0x18] = 0x00;
607: /* Alternate extended table (none) */
608: pfl->cfi_table[0x19] = 0x00;
609: pfl->cfi_table[0x1A] = 0x00;
610: /* Vcc min */
611: pfl->cfi_table[0x1B] = 0x27;
612: /* Vcc max */
613: pfl->cfi_table[0x1C] = 0x36;
614: /* Vpp min (no Vpp pin) */
615: pfl->cfi_table[0x1D] = 0x00;
616: /* Vpp max (no Vpp pin) */
617: pfl->cfi_table[0x1E] = 0x00;
618: /* Reserved */
619: pfl->cfi_table[0x1F] = 0x07;
1.1.1.4 ! root 620: /* Timeout for min size buffer write (NA) */
! 621: pfl->cfi_table[0x20] = 0x00;
1.1 root 622: /* Typical timeout for block erase (512 ms) */
623: pfl->cfi_table[0x21] = 0x09;
624: /* Typical timeout for full chip erase (4096 ms) */
625: pfl->cfi_table[0x22] = 0x0C;
626: /* Reserved */
627: pfl->cfi_table[0x23] = 0x01;
1.1.1.4 ! root 628: /* Max timeout for buffer write (NA) */
! 629: pfl->cfi_table[0x24] = 0x00;
1.1 root 630: /* Max timeout for block erase */
631: pfl->cfi_table[0x25] = 0x0A;
632: /* Max timeout for chip erase */
633: pfl->cfi_table[0x26] = 0x0D;
634: /* Device size */
1.1.1.4 ! root 635: pfl->cfi_table[0x27] = ctz32(chip_len);
1.1 root 636: /* Flash device interface (8 & 16 bits) */
637: pfl->cfi_table[0x28] = 0x02;
638: pfl->cfi_table[0x29] = 0x00;
639: /* Max number of bytes in multi-bytes write */
1.1.1.3 root 640: /* XXX: disable buffered write as it's not supported */
641: // pfl->cfi_table[0x2A] = 0x05;
642: pfl->cfi_table[0x2A] = 0x00;
1.1 root 643: pfl->cfi_table[0x2B] = 0x00;
644: /* Number of erase block regions (uniform) */
645: pfl->cfi_table[0x2C] = 0x01;
646: /* Erase block region 1 */
647: pfl->cfi_table[0x2D] = nb_blocs - 1;
648: pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
649: pfl->cfi_table[0x2F] = sector_len >> 8;
650: pfl->cfi_table[0x30] = sector_len >> 16;
651:
1.1.1.4 ! root 652: /* Extended */
! 653: pfl->cfi_table[0x31] = 'P';
! 654: pfl->cfi_table[0x32] = 'R';
! 655: pfl->cfi_table[0x33] = 'I';
! 656:
! 657: pfl->cfi_table[0x34] = '1';
! 658: pfl->cfi_table[0x35] = '0';
! 659:
! 660: pfl->cfi_table[0x36] = 0x00;
! 661: pfl->cfi_table[0x37] = 0x00;
! 662: pfl->cfi_table[0x38] = 0x00;
! 663: pfl->cfi_table[0x39] = 0x00;
! 664:
! 665: pfl->cfi_table[0x3a] = 0x00;
! 666:
! 667: pfl->cfi_table[0x3b] = 0x00;
! 668: pfl->cfi_table[0x3c] = 0x00;
! 669:
1.1 root 670: return pfl;
671: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.