pflash_cfi02.c 19 KB

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