1 /* 2 * QTest testcase for parallel flash with AMD command set 3 * 4 * Copyright (c) 2019 Stephen Checkoway 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 #include "libqtest.h" 12 13 /* 14 * To test the pflash_cfi02 device, we run QEMU with the musicpal machine with 15 * a pflash drive. This enables us to test some flash configurations, but not 16 * all. In particular, we're limited to a 16-bit wide flash device. 17 */ 18 19 #define MP_FLASH_SIZE_MAX (32 * 1024 * 1024) 20 #define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX) 21 22 #define UNIFORM_FLASH_SIZE (8 * 1024 * 1024) 23 #define UNIFORM_FLASH_SECTOR_SIZE (64 * 1024) 24 25 /* Use a newtype to keep flash addresses separate from byte addresses. */ 26 typedef struct { 27 uint64_t addr; 28 } faddr; 29 #define FLASH_ADDR(x) ((faddr) { .addr = (x) }) 30 31 #define CFI_ADDR FLASH_ADDR(0x55) 32 #define UNLOCK0_ADDR FLASH_ADDR(0x555) 33 #define UNLOCK1_ADDR FLASH_ADDR(0x2AA) 34 35 #define CFI_CMD 0x98 36 #define UNLOCK0_CMD 0xAA 37 #define UNLOCK1_CMD 0x55 38 #define SECOND_UNLOCK_CMD 0x80 39 #define AUTOSELECT_CMD 0x90 40 #define RESET_CMD 0xF0 41 #define PROGRAM_CMD 0xA0 42 #define SECTOR_ERASE_CMD 0x30 43 #define CHIP_ERASE_CMD 0x10 44 #define UNLOCK_BYPASS_CMD 0x20 45 #define UNLOCK_BYPASS_RESET_CMD 0x00 46 #define ERASE_SUSPEND_CMD 0xB0 47 #define ERASE_RESUME_CMD SECTOR_ERASE_CMD 48 49 typedef struct { 50 int bank_width; 51 52 /* Nonuniform block size. */ 53 int nb_blocs[4]; 54 int sector_len[4]; 55 56 QTestState *qtest; 57 } FlashConfig; 58 59 static char *image_path; 60 61 /* 62 * The pflash implementation allows some parameters to be unspecified. We want 63 * to test those configurations but we also need to know the real values in 64 * our testing code. So after we launch qemu, we'll need a new FlashConfig 65 * with the correct values filled in. 66 */ 67 static FlashConfig expand_config_defaults(const FlashConfig *c) 68 { 69 FlashConfig ret = *c; 70 71 if (ret.bank_width == 0) { 72 ret.bank_width = 2; 73 } 74 if (ret.nb_blocs[0] == 0 && ret.sector_len[0] == 0) { 75 ret.sector_len[0] = UNIFORM_FLASH_SECTOR_SIZE; 76 ret.nb_blocs[0] = UNIFORM_FLASH_SIZE / UNIFORM_FLASH_SECTOR_SIZE; 77 } 78 79 /* XXX: Limitations of test harness. */ 80 assert(ret.bank_width == 2); 81 return ret; 82 } 83 84 /* 85 * Return a bit mask suitable for extracting the least significant 86 * status/query response from an interleaved response. 87 */ 88 static inline uint64_t device_mask(const FlashConfig *c) 89 { 90 return (uint64_t)-1; 91 } 92 93 /* 94 * Return a bit mask exactly as long as the bank_width. 95 */ 96 static inline uint64_t bank_mask(const FlashConfig *c) 97 { 98 if (c->bank_width == 8) { 99 return (uint64_t)-1; 100 } 101 return (1ULL << (c->bank_width * 8)) - 1ULL; 102 } 103 104 static inline void flash_write(const FlashConfig *c, uint64_t byte_addr, 105 uint64_t data) 106 { 107 /* Sanity check our tests. */ 108 assert((data & ~bank_mask(c)) == 0); 109 uint64_t addr = BASE_ADDR + byte_addr; 110 switch (c->bank_width) { 111 case 1: 112 qtest_writeb(c->qtest, addr, data); 113 break; 114 case 2: 115 qtest_writew(c->qtest, addr, data); 116 break; 117 case 4: 118 qtest_writel(c->qtest, addr, data); 119 break; 120 case 8: 121 qtest_writeq(c->qtest, addr, data); 122 break; 123 default: 124 abort(); 125 } 126 } 127 128 static inline uint64_t flash_read(const FlashConfig *c, uint64_t byte_addr) 129 { 130 uint64_t addr = BASE_ADDR + byte_addr; 131 switch (c->bank_width) { 132 case 1: 133 return qtest_readb(c->qtest, addr); 134 case 2: 135 return qtest_readw(c->qtest, addr); 136 case 4: 137 return qtest_readl(c->qtest, addr); 138 case 8: 139 return qtest_readq(c->qtest, addr); 140 default: 141 abort(); 142 } 143 } 144 145 /* 146 * Convert a flash address expressed in the maximum width of the device as a 147 * byte address. 148 */ 149 static inline uint64_t as_byte_addr(const FlashConfig *c, faddr flash_addr) 150 { 151 /* 152 * Command addresses are always given as addresses in the maximum 153 * supported bus size for the flash chip. So an x8/x16 chip in x8 mode 154 * uses addresses 0xAAA and 0x555 to unlock because the least significant 155 * bit is ignored. (0x555 rather than 0x554 is traditional.) 156 * 157 * In general we need to multiply by the maximum device width. 158 */ 159 return flash_addr.addr * c->bank_width; 160 } 161 162 /* 163 * Return the command value or expected status replicated across all devices. 164 */ 165 static inline uint64_t replicate(const FlashConfig *c, uint64_t data) 166 { 167 /* Sanity check our tests. */ 168 assert((data & ~device_mask(c)) == 0); 169 return data; 170 } 171 172 static inline void flash_cmd(const FlashConfig *c, faddr cmd_addr, 173 uint8_t cmd) 174 { 175 flash_write(c, as_byte_addr(c, cmd_addr), replicate(c, cmd)); 176 } 177 178 static inline uint64_t flash_query(const FlashConfig *c, faddr query_addr) 179 { 180 return flash_read(c, as_byte_addr(c, query_addr)); 181 } 182 183 static inline uint64_t flash_query_1(const FlashConfig *c, faddr query_addr) 184 { 185 return flash_query(c, query_addr) & device_mask(c); 186 } 187 188 static void unlock(const FlashConfig *c) 189 { 190 flash_cmd(c, UNLOCK0_ADDR, UNLOCK0_CMD); 191 flash_cmd(c, UNLOCK1_ADDR, UNLOCK1_CMD); 192 } 193 194 static void reset(const FlashConfig *c) 195 { 196 flash_cmd(c, FLASH_ADDR(0), RESET_CMD); 197 } 198 199 static void sector_erase(const FlashConfig *c, uint64_t byte_addr) 200 { 201 unlock(c); 202 flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD); 203 unlock(c); 204 flash_write(c, byte_addr, replicate(c, SECTOR_ERASE_CMD)); 205 } 206 207 static void wait_for_completion(const FlashConfig *c, uint64_t byte_addr) 208 { 209 /* If DQ6 is toggling, step the clock and ensure the toggle stops. */ 210 const uint64_t dq6 = replicate(c, 0x40); 211 if ((flash_read(c, byte_addr) & dq6) ^ (flash_read(c, byte_addr) & dq6)) { 212 /* Wait for erase or program to finish. */ 213 qtest_clock_step_next(c->qtest); 214 /* Ensure that DQ6 has stopped toggling. */ 215 g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr)); 216 } 217 } 218 219 static void bypass_program(const FlashConfig *c, uint64_t byte_addr, 220 uint16_t data) 221 { 222 flash_cmd(c, UNLOCK0_ADDR, PROGRAM_CMD); 223 flash_write(c, byte_addr, data); 224 /* 225 * Data isn't valid until DQ6 stops toggling. We don't model this as 226 * writes are immediate, but if this changes in the future, we can wait 227 * until the program is complete. 228 */ 229 wait_for_completion(c, byte_addr); 230 } 231 232 static void program(const FlashConfig *c, uint64_t byte_addr, uint16_t data) 233 { 234 unlock(c); 235 bypass_program(c, byte_addr, data); 236 } 237 238 static void chip_erase(const FlashConfig *c) 239 { 240 unlock(c); 241 flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD); 242 unlock(c); 243 flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD); 244 } 245 246 static void erase_suspend(const FlashConfig *c) 247 { 248 flash_cmd(c, FLASH_ADDR(0), ERASE_SUSPEND_CMD); 249 } 250 251 static void erase_resume(const FlashConfig *c) 252 { 253 flash_cmd(c, FLASH_ADDR(0), ERASE_RESUME_CMD); 254 } 255 256 /* 257 * Test flash commands with a variety of device geometry. 258 */ 259 static void test_geometry(const void *opaque) 260 { 261 const FlashConfig *config = opaque; 262 QTestState *qtest; 263 qtest = qtest_initf("-M musicpal" 264 " -drive if=pflash,file=%s,format=raw,copy-on-read=on" 265 /* Device geometry properties. */ 266 " -global driver=cfi.pflash02," 267 "property=num-blocks0,value=%d" 268 " -global driver=cfi.pflash02," 269 "property=sector-length0,value=%d" 270 " -global driver=cfi.pflash02," 271 "property=num-blocks1,value=%d" 272 " -global driver=cfi.pflash02," 273 "property=sector-length1,value=%d" 274 " -global driver=cfi.pflash02," 275 "property=num-blocks2,value=%d" 276 " -global driver=cfi.pflash02," 277 "property=sector-length2,value=%d" 278 " -global driver=cfi.pflash02," 279 "property=num-blocks3,value=%d" 280 " -global driver=cfi.pflash02," 281 "property=sector-length3,value=%d", 282 image_path, 283 config->nb_blocs[0], 284 config->sector_len[0], 285 config->nb_blocs[1], 286 config->sector_len[1], 287 config->nb_blocs[2], 288 config->sector_len[2], 289 config->nb_blocs[3], 290 config->sector_len[3]); 291 FlashConfig explicit_config = expand_config_defaults(config); 292 explicit_config.qtest = qtest; 293 const FlashConfig *c = &explicit_config; 294 295 /* Check the IDs. */ 296 unlock(c); 297 flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD); 298 g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF)); 299 if (c->bank_width >= 2) { 300 /* 301 * XXX: The ID returned by the musicpal flash chip is 16 bits which 302 * wouldn't happen with an 8-bit device. It would probably be best to 303 * prohibit addresses larger than the device width in pflash_cfi02.c, 304 * but then we couldn't test smaller device widths at all. 305 */ 306 g_assert_cmphex(flash_query(c, FLASH_ADDR(1)), ==, 307 replicate(c, 0x236D)); 308 } 309 reset(c); 310 311 /* Check the erase blocks. */ 312 flash_cmd(c, CFI_ADDR, CFI_CMD); 313 g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q')); 314 g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R')); 315 g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y')); 316 317 /* Num erase regions. */ 318 int nb_erase_regions = flash_query_1(c, FLASH_ADDR(0x2C)); 319 g_assert_cmphex(nb_erase_regions, ==, 320 !!c->nb_blocs[0] + !!c->nb_blocs[1] + !!c->nb_blocs[2] + 321 !!c->nb_blocs[3]); 322 323 /* Check device length. */ 324 uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27)); 325 g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE); 326 327 /* Check that erase suspend to read/write is supported. */ 328 uint16_t pri = flash_query_1(c, FLASH_ADDR(0x15)) + 329 (flash_query_1(c, FLASH_ADDR(0x16)) << 8); 330 g_assert_cmpint(pri, >=, 0x2D + 4 * nb_erase_regions); 331 g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 0)), ==, replicate(c, 'P')); 332 g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 1)), ==, replicate(c, 'R')); 333 g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 2)), ==, replicate(c, 'I')); 334 g_assert_cmpint(flash_query_1(c, FLASH_ADDR(pri + 6)), ==, 2); /* R/W */ 335 reset(c); 336 337 const uint64_t dq7 = replicate(c, 0x80); 338 const uint64_t dq6 = replicate(c, 0x40); 339 const uint64_t dq3 = replicate(c, 0x08); 340 const uint64_t dq2 = replicate(c, 0x04); 341 342 uint64_t byte_addr = 0; 343 for (int region = 0; region < nb_erase_regions; ++region) { 344 uint64_t base = 0x2D + 4 * region; 345 flash_cmd(c, CFI_ADDR, CFI_CMD); 346 uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(base + 0)) + 347 (flash_query_1(c, FLASH_ADDR(base + 1)) << 8) + 1; 348 uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(base + 2)) << 8) + 349 (flash_query_1(c, FLASH_ADDR(base + 3)) << 16); 350 g_assert_cmphex(nb_sectors, ==, c->nb_blocs[region]); 351 g_assert_cmphex(sector_len, ==, c->sector_len[region]); 352 reset(c); 353 354 /* Erase and program sector. */ 355 for (uint32_t i = 0; i < nb_sectors; ++i) { 356 sector_erase(c, byte_addr); 357 358 /* Check that DQ3 is 0. */ 359 g_assert_cmphex(flash_read(c, byte_addr) & dq3, ==, 0); 360 qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */ 361 362 /* Check that DQ3 is 1. */ 363 uint64_t status0 = flash_read(c, byte_addr); 364 g_assert_cmphex(status0 & dq3, ==, dq3); 365 366 /* DQ7 is 0 during an erase. */ 367 g_assert_cmphex(status0 & dq7, ==, 0); 368 uint64_t status1 = flash_read(c, byte_addr); 369 370 /* DQ6 toggles during an erase. */ 371 g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6); 372 373 /* Wait for erase to complete. */ 374 wait_for_completion(c, byte_addr); 375 376 /* Ensure DQ6 has stopped toggling. */ 377 g_assert_cmphex(flash_read(c, byte_addr), ==, 378 flash_read(c, byte_addr)); 379 380 /* Now the data should be valid. */ 381 g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c)); 382 383 /* Program a bit pattern. */ 384 program(c, byte_addr, 0x55); 385 g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55); 386 program(c, byte_addr, 0xA5); 387 g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05); 388 byte_addr += sector_len; 389 } 390 } 391 392 /* Erase the chip. */ 393 chip_erase(c); 394 /* Read toggle. */ 395 uint64_t status0 = flash_read(c, 0); 396 /* DQ7 is 0 during an erase. */ 397 g_assert_cmphex(status0 & dq7, ==, 0); 398 uint64_t status1 = flash_read(c, 0); 399 /* DQ6 toggles during an erase. */ 400 g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6); 401 /* Wait for erase to complete. */ 402 qtest_clock_step_next(c->qtest); 403 /* Ensure DQ6 has stopped toggling. */ 404 g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0)); 405 /* Now the data should be valid. */ 406 407 for (int region = 0; region < nb_erase_regions; ++region) { 408 for (uint32_t i = 0; i < c->nb_blocs[region]; ++i) { 409 uint64_t byte_addr = (uint64_t)i * c->sector_len[region]; 410 g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c)); 411 } 412 } 413 414 /* Unlock bypass */ 415 unlock(c); 416 flash_cmd(c, UNLOCK0_ADDR, UNLOCK_BYPASS_CMD); 417 bypass_program(c, 0 * c->bank_width, 0x01); 418 bypass_program(c, 1 * c->bank_width, 0x23); 419 bypass_program(c, 2 * c->bank_width, 0x45); 420 /* 421 * Test that bypass programming, unlike normal programming can use any 422 * address for the PROGRAM_CMD. 423 */ 424 flash_cmd(c, FLASH_ADDR(3 * c->bank_width), PROGRAM_CMD); 425 flash_write(c, 3 * c->bank_width, 0x67); 426 wait_for_completion(c, 3 * c->bank_width); 427 flash_cmd(c, FLASH_ADDR(0), UNLOCK_BYPASS_RESET_CMD); 428 bypass_program(c, 4 * c->bank_width, 0x89); /* Should fail. */ 429 g_assert_cmphex(flash_read(c, 0 * c->bank_width), ==, 0x01); 430 g_assert_cmphex(flash_read(c, 1 * c->bank_width), ==, 0x23); 431 g_assert_cmphex(flash_read(c, 2 * c->bank_width), ==, 0x45); 432 g_assert_cmphex(flash_read(c, 3 * c->bank_width), ==, 0x67); 433 g_assert_cmphex(flash_read(c, 4 * c->bank_width), ==, bank_mask(c)); 434 435 /* Test ignored high order bits of address. */ 436 flash_cmd(c, FLASH_ADDR(0x5555), UNLOCK0_CMD); 437 flash_cmd(c, FLASH_ADDR(0x2AAA), UNLOCK1_CMD); 438 flash_cmd(c, FLASH_ADDR(0x5555), AUTOSELECT_CMD); 439 g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF)); 440 reset(c); 441 442 /* 443 * Program a word on each sector, erase one or two sectors per region, and 444 * verify that all of those, and only those, are erased. 445 */ 446 byte_addr = 0; 447 for (int region = 0; region < nb_erase_regions; ++region) { 448 for (int i = 0; i < config->nb_blocs[region]; ++i) { 449 program(c, byte_addr, 0); 450 byte_addr += config->sector_len[region]; 451 } 452 } 453 unlock(c); 454 flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD); 455 unlock(c); 456 byte_addr = 0; 457 const uint64_t erase_cmd = replicate(c, SECTOR_ERASE_CMD); 458 for (int region = 0; region < nb_erase_regions; ++region) { 459 flash_write(c, byte_addr, erase_cmd); 460 if (c->nb_blocs[region] > 1) { 461 flash_write(c, byte_addr + c->sector_len[region], erase_cmd); 462 } 463 byte_addr += c->sector_len[region] * c->nb_blocs[region]; 464 } 465 466 qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */ 467 wait_for_completion(c, 0); 468 byte_addr = 0; 469 for (int region = 0; region < nb_erase_regions; ++region) { 470 for (int i = 0; i < config->nb_blocs[region]; ++i) { 471 if (i < 2) { 472 g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c)); 473 } else { 474 g_assert_cmphex(flash_read(c, byte_addr), ==, 0); 475 } 476 byte_addr += config->sector_len[region]; 477 } 478 } 479 480 /* Test erase suspend/resume during erase timeout. */ 481 sector_erase(c, 0); 482 /* 483 * Check that DQ 3 is 0 and DQ6 and DQ2 are toggling in the sector being 484 * erased as well as in a sector not being erased. 485 */ 486 byte_addr = c->sector_len[0]; 487 status0 = flash_read(c, 0); 488 status1 = flash_read(c, 0); 489 g_assert_cmpint(status0 & dq3, ==, 0); 490 g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 491 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 492 status0 = flash_read(c, byte_addr); 493 status1 = flash_read(c, byte_addr); 494 g_assert_cmpint(status0 & dq3, ==, 0); 495 g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 496 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 497 498 /* 499 * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in 500 * an erase suspended sector but that neither toggle (we should be 501 * getting data) in a sector not being erased. 502 */ 503 erase_suspend(c); 504 status0 = flash_read(c, 0); 505 status1 = flash_read(c, 0); 506 g_assert_cmpint(status0 & dq6, ==, status1 & dq6); 507 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 508 g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr)); 509 510 /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */ 511 erase_resume(c); 512 status0 = flash_read(c, 0); 513 status1 = flash_read(c, 0); 514 g_assert_cmpint(status0 & dq3, ==, dq3); 515 g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 516 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 517 status0 = flash_read(c, byte_addr); 518 status1 = flash_read(c, byte_addr); 519 g_assert_cmpint(status0 & dq3, ==, dq3); 520 g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 521 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 522 wait_for_completion(c, 0); 523 524 /* Repeat this process but this time suspend after the timeout. */ 525 sector_erase(c, 0); 526 qtest_clock_step_next(c->qtest); 527 /* 528 * Check that DQ 3 is 1 and DQ6 and DQ2 are toggling in the sector being 529 * erased as well as in a sector not being erased. 530 */ 531 byte_addr = c->sector_len[0]; 532 status0 = flash_read(c, 0); 533 status1 = flash_read(c, 0); 534 g_assert_cmpint(status0 & dq3, ==, dq3); 535 g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 536 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 537 status0 = flash_read(c, byte_addr); 538 status1 = flash_read(c, byte_addr); 539 g_assert_cmpint(status0 & dq3, ==, dq3); 540 g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 541 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 542 543 /* 544 * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in 545 * an erase suspended sector but that neither toggle (we should be 546 * getting data) in a sector not being erased. 547 */ 548 erase_suspend(c); 549 status0 = flash_read(c, 0); 550 status1 = flash_read(c, 0); 551 g_assert_cmpint(status0 & dq6, ==, status1 & dq6); 552 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 553 g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr)); 554 555 /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */ 556 erase_resume(c); 557 status0 = flash_read(c, 0); 558 status1 = flash_read(c, 0); 559 g_assert_cmpint(status0 & dq3, ==, dq3); 560 g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 561 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 562 status0 = flash_read(c, byte_addr); 563 status1 = flash_read(c, byte_addr); 564 g_assert_cmpint(status0 & dq3, ==, dq3); 565 g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 566 g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 567 wait_for_completion(c, 0); 568 569 qtest_quit(qtest); 570 } 571 572 /* 573 * Test that 574 * 1. enter autoselect mode; 575 * 2. enter CFI mode; and then 576 * 3. exit CFI mode 577 * leaves the flash device in autoselect mode. 578 */ 579 static void test_cfi_in_autoselect(const void *opaque) 580 { 581 const FlashConfig *config = opaque; 582 QTestState *qtest; 583 qtest = qtest_initf("-M musicpal" 584 " -drive if=pflash,file=%s,format=raw,copy-on-read=on", 585 image_path); 586 FlashConfig explicit_config = expand_config_defaults(config); 587 explicit_config.qtest = qtest; 588 const FlashConfig *c = &explicit_config; 589 590 /* 1. Enter autoselect. */ 591 unlock(c); 592 flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD); 593 g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF)); 594 595 /* 2. Enter CFI. */ 596 flash_cmd(c, CFI_ADDR, CFI_CMD); 597 g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q')); 598 g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R')); 599 g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y')); 600 601 /* 3. Exit CFI. */ 602 reset(c); 603 g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF)); 604 605 qtest_quit(qtest); 606 } 607 608 static void cleanup(void *opaque) 609 { 610 unlink(image_path); 611 g_free(image_path); 612 } 613 614 /* 615 * XXX: Tests are limited to bank_width = 2 for now because that's what 616 * hw/arm/musicpal.c has. 617 */ 618 static const FlashConfig configuration[] = { 619 /* One x16 device. */ 620 { 621 .bank_width = 2, 622 }, 623 /* Nonuniform sectors (top boot). */ 624 { 625 .bank_width = 2, 626 .nb_blocs = { 127, 1, 2, 1 }, 627 .sector_len = { 0x10000, 0x08000, 0x02000, 0x04000 }, 628 }, 629 /* Nonuniform sectors (bottom boot). */ 630 { 631 .bank_width = 2, 632 .nb_blocs = { 1, 2, 1, 127 }, 633 .sector_len = { 0x04000, 0x02000, 0x08000, 0x10000 }, 634 }, 635 }; 636 637 int main(int argc, char **argv) 638 { 639 GError *err = NULL; 640 int fd = g_file_open_tmp("qtest.XXXXXX", &image_path, &err); 641 g_assert_no_error(err); 642 643 if (ftruncate(fd, UNIFORM_FLASH_SIZE) < 0) { 644 int error_code = errno; 645 close(fd); 646 cleanup(NULL); 647 g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path, 648 UNIFORM_FLASH_SIZE, strerror(error_code)); 649 exit(EXIT_FAILURE); 650 } 651 close(fd); 652 653 qtest_add_abrt_handler(cleanup, NULL); 654 g_test_init(&argc, &argv, NULL); 655 656 size_t nb_configurations = sizeof configuration / sizeof configuration[0]; 657 for (size_t i = 0; i < nb_configurations; ++i) { 658 const FlashConfig *config = &configuration[i]; 659 char *path = g_strdup_printf("pflash-cfi02" 660 "/geometry/%dx%x-%dx%x-%dx%x-%dx%x" 661 "/%d", 662 config->nb_blocs[0], 663 config->sector_len[0], 664 config->nb_blocs[1], 665 config->sector_len[1], 666 config->nb_blocs[2], 667 config->sector_len[2], 668 config->nb_blocs[3], 669 config->sector_len[3], 670 config->bank_width); 671 qtest_add_data_func(path, config, test_geometry); 672 g_free(path); 673 } 674 675 qtest_add_data_func("pflash-cfi02/cfi-in-autoselect", &configuration[0], 676 test_cfi_in_autoselect); 677 int result = g_test_run(); 678 cleanup(NULL); 679 return result; 680 } 681