160b725b6SStephen Checkoway /* 260b725b6SStephen Checkoway * QTest testcase for parallel flash with AMD command set 360b725b6SStephen Checkoway * 460b725b6SStephen Checkoway * Copyright (c) 2019 Stephen Checkoway 560b725b6SStephen Checkoway * 660b725b6SStephen Checkoway * This work is licensed under the terms of the GNU GPL, version 2 or later. 760b725b6SStephen Checkoway * See the COPYING file in the top-level directory. 860b725b6SStephen Checkoway */ 960b725b6SStephen Checkoway 1060b725b6SStephen Checkoway #include "qemu/osdep.h" 1160b725b6SStephen Checkoway #include "libqtest.h" 1260b725b6SStephen Checkoway 1360b725b6SStephen Checkoway /* 1460b725b6SStephen Checkoway * To test the pflash_cfi02 device, we run QEMU with the musicpal machine with 1560b725b6SStephen Checkoway * a pflash drive. This enables us to test some flash configurations, but not 1660b725b6SStephen Checkoway * all. In particular, we're limited to a 16-bit wide flash device. 1760b725b6SStephen Checkoway */ 1860b725b6SStephen Checkoway 1960b725b6SStephen Checkoway #define MP_FLASH_SIZE_MAX (32 * 1024 * 1024) 2060b725b6SStephen Checkoway #define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX) 2160b725b6SStephen Checkoway 2264659053SStephen Checkoway #define UNIFORM_FLASH_SIZE (8 * 1024 * 1024) 2364659053SStephen Checkoway #define UNIFORM_FLASH_SECTOR_SIZE (64 * 1024) 2464659053SStephen Checkoway 2591d02312SPhilippe Mathieu-Daudé /* Use a newtype to keep flash addresses separate from byte addresses. */ 2691d02312SPhilippe Mathieu-Daudé typedef struct { 2791d02312SPhilippe Mathieu-Daudé uint64_t addr; 2891d02312SPhilippe Mathieu-Daudé } faddr; 2991d02312SPhilippe Mathieu-Daudé #define FLASH_ADDR(x) ((faddr) { .addr = (x) }) 3091d02312SPhilippe Mathieu-Daudé 3191d02312SPhilippe Mathieu-Daudé #define CFI_ADDR FLASH_ADDR(0x55) 3291d02312SPhilippe Mathieu-Daudé #define UNLOCK0_ADDR FLASH_ADDR(0x555) 3391d02312SPhilippe Mathieu-Daudé #define UNLOCK1_ADDR FLASH_ADDR(0x2AA) 3460b725b6SStephen Checkoway 3560b725b6SStephen Checkoway #define CFI_CMD 0x98 3660b725b6SStephen Checkoway #define UNLOCK0_CMD 0xAA 3760b725b6SStephen Checkoway #define UNLOCK1_CMD 0x55 38a50547acSStephen Checkoway #define SECOND_UNLOCK_CMD 0x80 3960b725b6SStephen Checkoway #define AUTOSELECT_CMD 0x90 4060b725b6SStephen Checkoway #define RESET_CMD 0xF0 4160b725b6SStephen Checkoway #define PROGRAM_CMD 0xA0 4260b725b6SStephen Checkoway #define SECTOR_ERASE_CMD 0x30 4360b725b6SStephen Checkoway #define CHIP_ERASE_CMD 0x10 4460b725b6SStephen Checkoway #define UNLOCK_BYPASS_CMD 0x20 4560b725b6SStephen Checkoway #define UNLOCK_BYPASS_RESET_CMD 0x00 46ddb6f225SStephen Checkoway #define ERASE_SUSPEND_CMD 0xB0 47ddb6f225SStephen Checkoway #define ERASE_RESUME_CMD SECTOR_ERASE_CMD 4860b725b6SStephen Checkoway 4991d02312SPhilippe Mathieu-Daudé typedef struct { 5091d02312SPhilippe Mathieu-Daudé int bank_width; 5191d02312SPhilippe Mathieu-Daudé 5264659053SStephen Checkoway /* Nonuniform block size. */ 5364659053SStephen Checkoway int nb_blocs[4]; 5464659053SStephen Checkoway int sector_len[4]; 5564659053SStephen Checkoway 5691d02312SPhilippe Mathieu-Daudé QTestState *qtest; 5791d02312SPhilippe Mathieu-Daudé } FlashConfig; 5891d02312SPhilippe Mathieu-Daudé 5960b725b6SStephen Checkoway static char image_path[] = "/tmp/qtest.XXXXXX"; 6060b725b6SStephen Checkoway 6191d02312SPhilippe Mathieu-Daudé /* 6291d02312SPhilippe Mathieu-Daudé * The pflash implementation allows some parameters to be unspecified. We want 6391d02312SPhilippe Mathieu-Daudé * to test those configurations but we also need to know the real values in 6491d02312SPhilippe Mathieu-Daudé * our testing code. So after we launch qemu, we'll need a new FlashConfig 6591d02312SPhilippe Mathieu-Daudé * with the correct values filled in. 6691d02312SPhilippe Mathieu-Daudé */ 6791d02312SPhilippe Mathieu-Daudé static FlashConfig expand_config_defaults(const FlashConfig *c) 6860b725b6SStephen Checkoway { 6991d02312SPhilippe Mathieu-Daudé FlashConfig ret = *c; 7091d02312SPhilippe Mathieu-Daudé 7191d02312SPhilippe Mathieu-Daudé if (ret.bank_width == 0) { 7291d02312SPhilippe Mathieu-Daudé ret.bank_width = 2; 7360b725b6SStephen Checkoway } 7464659053SStephen Checkoway if (ret.nb_blocs[0] == 0 && ret.sector_len[0] == 0) { 7564659053SStephen Checkoway ret.sector_len[0] = UNIFORM_FLASH_SECTOR_SIZE; 7664659053SStephen Checkoway ret.nb_blocs[0] = UNIFORM_FLASH_SIZE / UNIFORM_FLASH_SECTOR_SIZE; 7764659053SStephen Checkoway } 7860b725b6SStephen Checkoway 7991d02312SPhilippe Mathieu-Daudé /* XXX: Limitations of test harness. */ 8091d02312SPhilippe Mathieu-Daudé assert(ret.bank_width == 2); 8191d02312SPhilippe Mathieu-Daudé return ret; 8260b725b6SStephen Checkoway } 8360b725b6SStephen Checkoway 8491d02312SPhilippe Mathieu-Daudé /* 8591d02312SPhilippe Mathieu-Daudé * Return a bit mask suitable for extracting the least significant 8691d02312SPhilippe Mathieu-Daudé * status/query response from an interleaved response. 8791d02312SPhilippe Mathieu-Daudé */ 8891d02312SPhilippe Mathieu-Daudé static inline uint64_t device_mask(const FlashConfig *c) 8960b725b6SStephen Checkoway { 9091d02312SPhilippe Mathieu-Daudé return (uint64_t)-1; 9160b725b6SStephen Checkoway } 9260b725b6SStephen Checkoway 9391d02312SPhilippe Mathieu-Daudé /* 9491d02312SPhilippe Mathieu-Daudé * Return a bit mask exactly as long as the bank_width. 9591d02312SPhilippe Mathieu-Daudé */ 9691d02312SPhilippe Mathieu-Daudé static inline uint64_t bank_mask(const FlashConfig *c) 9760b725b6SStephen Checkoway { 9891d02312SPhilippe Mathieu-Daudé if (c->bank_width == 8) { 9991d02312SPhilippe Mathieu-Daudé return (uint64_t)-1; 10091d02312SPhilippe Mathieu-Daudé } 10191d02312SPhilippe Mathieu-Daudé return (1ULL << (c->bank_width * 8)) - 1ULL; 10260b725b6SStephen Checkoway } 10360b725b6SStephen Checkoway 10491d02312SPhilippe Mathieu-Daudé static inline void flash_write(const FlashConfig *c, uint64_t byte_addr, 10591d02312SPhilippe Mathieu-Daudé uint64_t data) 10660b725b6SStephen Checkoway { 10791d02312SPhilippe Mathieu-Daudé /* Sanity check our tests. */ 10891d02312SPhilippe Mathieu-Daudé assert((data & ~bank_mask(c)) == 0); 10991d02312SPhilippe Mathieu-Daudé uint64_t addr = BASE_ADDR + byte_addr; 11091d02312SPhilippe Mathieu-Daudé switch (c->bank_width) { 11191d02312SPhilippe Mathieu-Daudé case 1: 11291d02312SPhilippe Mathieu-Daudé qtest_writeb(c->qtest, addr, data); 11391d02312SPhilippe Mathieu-Daudé break; 11491d02312SPhilippe Mathieu-Daudé case 2: 11591d02312SPhilippe Mathieu-Daudé qtest_writew(c->qtest, addr, data); 11691d02312SPhilippe Mathieu-Daudé break; 11791d02312SPhilippe Mathieu-Daudé case 4: 11891d02312SPhilippe Mathieu-Daudé qtest_writel(c->qtest, addr, data); 11991d02312SPhilippe Mathieu-Daudé break; 12091d02312SPhilippe Mathieu-Daudé case 8: 12191d02312SPhilippe Mathieu-Daudé qtest_writeq(c->qtest, addr, data); 12291d02312SPhilippe Mathieu-Daudé break; 12391d02312SPhilippe Mathieu-Daudé default: 12491d02312SPhilippe Mathieu-Daudé abort(); 12591d02312SPhilippe Mathieu-Daudé } 12660b725b6SStephen Checkoway } 12760b725b6SStephen Checkoway 12891d02312SPhilippe Mathieu-Daudé static inline uint64_t flash_read(const FlashConfig *c, uint64_t byte_addr) 12991d02312SPhilippe Mathieu-Daudé { 13091d02312SPhilippe Mathieu-Daudé uint64_t addr = BASE_ADDR + byte_addr; 13191d02312SPhilippe Mathieu-Daudé switch (c->bank_width) { 13291d02312SPhilippe Mathieu-Daudé case 1: 13391d02312SPhilippe Mathieu-Daudé return qtest_readb(c->qtest, addr); 13491d02312SPhilippe Mathieu-Daudé case 2: 13591d02312SPhilippe Mathieu-Daudé return qtest_readw(c->qtest, addr); 13691d02312SPhilippe Mathieu-Daudé case 4: 13791d02312SPhilippe Mathieu-Daudé return qtest_readl(c->qtest, addr); 13891d02312SPhilippe Mathieu-Daudé case 8: 13991d02312SPhilippe Mathieu-Daudé return qtest_readq(c->qtest, addr); 14091d02312SPhilippe Mathieu-Daudé default: 14191d02312SPhilippe Mathieu-Daudé abort(); 14291d02312SPhilippe Mathieu-Daudé } 14391d02312SPhilippe Mathieu-Daudé } 14491d02312SPhilippe Mathieu-Daudé 14591d02312SPhilippe Mathieu-Daudé /* 14691d02312SPhilippe Mathieu-Daudé * Convert a flash address expressed in the maximum width of the device as a 14791d02312SPhilippe Mathieu-Daudé * byte address. 14891d02312SPhilippe Mathieu-Daudé */ 14991d02312SPhilippe Mathieu-Daudé static inline uint64_t as_byte_addr(const FlashConfig *c, faddr flash_addr) 15091d02312SPhilippe Mathieu-Daudé { 15191d02312SPhilippe Mathieu-Daudé /* 15291d02312SPhilippe Mathieu-Daudé * Command addresses are always given as addresses in the maximum 15391d02312SPhilippe Mathieu-Daudé * supported bus size for the flash chip. So an x8/x16 chip in x8 mode 15491d02312SPhilippe Mathieu-Daudé * uses addresses 0xAAA and 0x555 to unlock because the least significant 15591d02312SPhilippe Mathieu-Daudé * bit is ignored. (0x555 rather than 0x554 is traditional.) 15691d02312SPhilippe Mathieu-Daudé * 15791d02312SPhilippe Mathieu-Daudé * In general we need to multiply by the maximum device width. 15891d02312SPhilippe Mathieu-Daudé */ 15991d02312SPhilippe Mathieu-Daudé return flash_addr.addr * c->bank_width; 16091d02312SPhilippe Mathieu-Daudé } 16191d02312SPhilippe Mathieu-Daudé 16291d02312SPhilippe Mathieu-Daudé /* 16391d02312SPhilippe Mathieu-Daudé * Return the command value or expected status replicated across all devices. 16491d02312SPhilippe Mathieu-Daudé */ 16591d02312SPhilippe Mathieu-Daudé static inline uint64_t replicate(const FlashConfig *c, uint64_t data) 16691d02312SPhilippe Mathieu-Daudé { 16791d02312SPhilippe Mathieu-Daudé /* Sanity check our tests. */ 16891d02312SPhilippe Mathieu-Daudé assert((data & ~device_mask(c)) == 0); 16991d02312SPhilippe Mathieu-Daudé return data; 17091d02312SPhilippe Mathieu-Daudé } 17191d02312SPhilippe Mathieu-Daudé 17291d02312SPhilippe Mathieu-Daudé static inline void flash_cmd(const FlashConfig *c, faddr cmd_addr, 17391d02312SPhilippe Mathieu-Daudé uint8_t cmd) 17491d02312SPhilippe Mathieu-Daudé { 17591d02312SPhilippe Mathieu-Daudé flash_write(c, as_byte_addr(c, cmd_addr), replicate(c, cmd)); 17691d02312SPhilippe Mathieu-Daudé } 17791d02312SPhilippe Mathieu-Daudé 17891d02312SPhilippe Mathieu-Daudé static inline uint64_t flash_query(const FlashConfig *c, faddr query_addr) 17991d02312SPhilippe Mathieu-Daudé { 18091d02312SPhilippe Mathieu-Daudé return flash_read(c, as_byte_addr(c, query_addr)); 18191d02312SPhilippe Mathieu-Daudé } 18291d02312SPhilippe Mathieu-Daudé 18391d02312SPhilippe Mathieu-Daudé static inline uint64_t flash_query_1(const FlashConfig *c, faddr query_addr) 18491d02312SPhilippe Mathieu-Daudé { 18591d02312SPhilippe Mathieu-Daudé return flash_query(c, query_addr) & device_mask(c); 18691d02312SPhilippe Mathieu-Daudé } 18791d02312SPhilippe Mathieu-Daudé 18891d02312SPhilippe Mathieu-Daudé static void unlock(const FlashConfig *c) 18991d02312SPhilippe Mathieu-Daudé { 19091d02312SPhilippe Mathieu-Daudé flash_cmd(c, UNLOCK0_ADDR, UNLOCK0_CMD); 19191d02312SPhilippe Mathieu-Daudé flash_cmd(c, UNLOCK1_ADDR, UNLOCK1_CMD); 19291d02312SPhilippe Mathieu-Daudé } 19391d02312SPhilippe Mathieu-Daudé 19491d02312SPhilippe Mathieu-Daudé static void reset(const FlashConfig *c) 19591d02312SPhilippe Mathieu-Daudé { 19691d02312SPhilippe Mathieu-Daudé flash_cmd(c, FLASH_ADDR(0), RESET_CMD); 19791d02312SPhilippe Mathieu-Daudé } 19891d02312SPhilippe Mathieu-Daudé 19991d02312SPhilippe Mathieu-Daudé static void sector_erase(const FlashConfig *c, uint64_t byte_addr) 20091d02312SPhilippe Mathieu-Daudé { 20191d02312SPhilippe Mathieu-Daudé unlock(c); 202a50547acSStephen Checkoway flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD); 20391d02312SPhilippe Mathieu-Daudé unlock(c); 20491d02312SPhilippe Mathieu-Daudé flash_write(c, byte_addr, replicate(c, SECTOR_ERASE_CMD)); 20591d02312SPhilippe Mathieu-Daudé } 20691d02312SPhilippe Mathieu-Daudé 20791d02312SPhilippe Mathieu-Daudé static void wait_for_completion(const FlashConfig *c, uint64_t byte_addr) 20860b725b6SStephen Checkoway { 20960b725b6SStephen Checkoway /* If DQ6 is toggling, step the clock and ensure the toggle stops. */ 21091d02312SPhilippe Mathieu-Daudé const uint64_t dq6 = replicate(c, 0x40); 21191d02312SPhilippe Mathieu-Daudé if ((flash_read(c, byte_addr) & dq6) ^ (flash_read(c, byte_addr) & dq6)) { 21260b725b6SStephen Checkoway /* Wait for erase or program to finish. */ 21391d02312SPhilippe Mathieu-Daudé qtest_clock_step_next(c->qtest); 21460b725b6SStephen Checkoway /* Ensure that DQ6 has stopped toggling. */ 21591d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr)); 21660b725b6SStephen Checkoway } 21760b725b6SStephen Checkoway } 21860b725b6SStephen Checkoway 21991d02312SPhilippe Mathieu-Daudé static void bypass_program(const FlashConfig *c, uint64_t byte_addr, 22091d02312SPhilippe Mathieu-Daudé uint16_t data) 22160b725b6SStephen Checkoway { 22291d02312SPhilippe Mathieu-Daudé flash_cmd(c, UNLOCK0_ADDR, PROGRAM_CMD); 22391d02312SPhilippe Mathieu-Daudé flash_write(c, byte_addr, data); 22460b725b6SStephen Checkoway /* 22560b725b6SStephen Checkoway * Data isn't valid until DQ6 stops toggling. We don't model this as 22660b725b6SStephen Checkoway * writes are immediate, but if this changes in the future, we can wait 22760b725b6SStephen Checkoway * until the program is complete. 22860b725b6SStephen Checkoway */ 22991d02312SPhilippe Mathieu-Daudé wait_for_completion(c, byte_addr); 23060b725b6SStephen Checkoway } 23160b725b6SStephen Checkoway 23291d02312SPhilippe Mathieu-Daudé static void program(const FlashConfig *c, uint64_t byte_addr, uint16_t data) 23360b725b6SStephen Checkoway { 23491d02312SPhilippe Mathieu-Daudé unlock(c); 23591d02312SPhilippe Mathieu-Daudé bypass_program(c, byte_addr, data); 23660b725b6SStephen Checkoway } 23760b725b6SStephen Checkoway 23891d02312SPhilippe Mathieu-Daudé static void chip_erase(const FlashConfig *c) 23960b725b6SStephen Checkoway { 24091d02312SPhilippe Mathieu-Daudé unlock(c); 241a50547acSStephen Checkoway flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD); 24291d02312SPhilippe Mathieu-Daudé unlock(c); 24391d02312SPhilippe Mathieu-Daudé flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD); 24460b725b6SStephen Checkoway } 24560b725b6SStephen Checkoway 246ddb6f225SStephen Checkoway static void erase_suspend(const FlashConfig *c) 247ddb6f225SStephen Checkoway { 248ddb6f225SStephen Checkoway flash_cmd(c, FLASH_ADDR(0), ERASE_SUSPEND_CMD); 249ddb6f225SStephen Checkoway } 250ddb6f225SStephen Checkoway 251ddb6f225SStephen Checkoway static void erase_resume(const FlashConfig *c) 252ddb6f225SStephen Checkoway { 253ddb6f225SStephen Checkoway flash_cmd(c, FLASH_ADDR(0), ERASE_RESUME_CMD); 254ddb6f225SStephen Checkoway } 255ddb6f225SStephen Checkoway 25664659053SStephen Checkoway /* 25764659053SStephen Checkoway * Test flash commands with a variety of device geometry. 25864659053SStephen Checkoway */ 25964659053SStephen Checkoway static void test_geometry(const void *opaque) 26060b725b6SStephen Checkoway { 26191d02312SPhilippe Mathieu-Daudé const FlashConfig *config = opaque; 26291d02312SPhilippe Mathieu-Daudé QTestState *qtest; 263*6f6e1698SPaolo Bonzini qtest = qtest_initf("-M musicpal" 26464659053SStephen Checkoway " -drive if=pflash,file=%s,format=raw,copy-on-read" 26564659053SStephen Checkoway /* Device geometry properties. */ 26664659053SStephen Checkoway " -global driver=cfi.pflash02," 26764659053SStephen Checkoway "property=num-blocks0,value=%d" 26864659053SStephen Checkoway " -global driver=cfi.pflash02," 26964659053SStephen Checkoway "property=sector-length0,value=%d" 27064659053SStephen Checkoway " -global driver=cfi.pflash02," 27164659053SStephen Checkoway "property=num-blocks1,value=%d" 27264659053SStephen Checkoway " -global driver=cfi.pflash02," 27364659053SStephen Checkoway "property=sector-length1,value=%d" 27464659053SStephen Checkoway " -global driver=cfi.pflash02," 27564659053SStephen Checkoway "property=num-blocks2,value=%d" 27664659053SStephen Checkoway " -global driver=cfi.pflash02," 27764659053SStephen Checkoway "property=sector-length2,value=%d" 27864659053SStephen Checkoway " -global driver=cfi.pflash02," 27964659053SStephen Checkoway "property=num-blocks3,value=%d" 28064659053SStephen Checkoway " -global driver=cfi.pflash02," 28164659053SStephen Checkoway "property=sector-length3,value=%d", 28264659053SStephen Checkoway image_path, 28364659053SStephen Checkoway config->nb_blocs[0], 28464659053SStephen Checkoway config->sector_len[0], 28564659053SStephen Checkoway config->nb_blocs[1], 28664659053SStephen Checkoway config->sector_len[1], 28764659053SStephen Checkoway config->nb_blocs[2], 28864659053SStephen Checkoway config->sector_len[2], 28964659053SStephen Checkoway config->nb_blocs[3], 29064659053SStephen Checkoway config->sector_len[3]); 29191d02312SPhilippe Mathieu-Daudé FlashConfig explicit_config = expand_config_defaults(config); 29291d02312SPhilippe Mathieu-Daudé explicit_config.qtest = qtest; 29391d02312SPhilippe Mathieu-Daudé const FlashConfig *c = &explicit_config; 29491d02312SPhilippe Mathieu-Daudé 29560b725b6SStephen Checkoway /* Check the IDs. */ 29691d02312SPhilippe Mathieu-Daudé unlock(c); 29791d02312SPhilippe Mathieu-Daudé flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD); 29891d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF)); 29991d02312SPhilippe Mathieu-Daudé if (c->bank_width >= 2) { 30091d02312SPhilippe Mathieu-Daudé /* 30191d02312SPhilippe Mathieu-Daudé * XXX: The ID returned by the musicpal flash chip is 16 bits which 30291d02312SPhilippe Mathieu-Daudé * wouldn't happen with an 8-bit device. It would probably be best to 30391d02312SPhilippe Mathieu-Daudé * prohibit addresses larger than the device width in pflash_cfi02.c, 30491d02312SPhilippe Mathieu-Daudé * but then we couldn't test smaller device widths at all. 30591d02312SPhilippe Mathieu-Daudé */ 30691d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_query(c, FLASH_ADDR(1)), ==, 30791d02312SPhilippe Mathieu-Daudé replicate(c, 0x236D)); 30891d02312SPhilippe Mathieu-Daudé } 30991d02312SPhilippe Mathieu-Daudé reset(c); 31060b725b6SStephen Checkoway 31160b725b6SStephen Checkoway /* Check the erase blocks. */ 31291d02312SPhilippe Mathieu-Daudé flash_cmd(c, CFI_ADDR, CFI_CMD); 31391d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q')); 31491d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R')); 31591d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y')); 31660b725b6SStephen Checkoway 31791d02312SPhilippe Mathieu-Daudé /* Num erase regions. */ 31864659053SStephen Checkoway int nb_erase_regions = flash_query_1(c, FLASH_ADDR(0x2C)); 31964659053SStephen Checkoway g_assert_cmphex(nb_erase_regions, ==, 32064659053SStephen Checkoway !!c->nb_blocs[0] + !!c->nb_blocs[1] + !!c->nb_blocs[2] + 32164659053SStephen Checkoway !!c->nb_blocs[3]); 32291d02312SPhilippe Mathieu-Daudé 32364659053SStephen Checkoway /* Check device length. */ 32464659053SStephen Checkoway uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27)); 32564659053SStephen Checkoway g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE); 32664659053SStephen Checkoway 327ddb6f225SStephen Checkoway /* Check that erase suspend to read/write is supported. */ 328ddb6f225SStephen Checkoway uint16_t pri = flash_query_1(c, FLASH_ADDR(0x15)) + 329ddb6f225SStephen Checkoway (flash_query_1(c, FLASH_ADDR(0x16)) << 8); 330ddb6f225SStephen Checkoway g_assert_cmpint(pri, >=, 0x2D + 4 * nb_erase_regions); 331ddb6f225SStephen Checkoway g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 0)), ==, replicate(c, 'P')); 332ddb6f225SStephen Checkoway g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 1)), ==, replicate(c, 'R')); 333ddb6f225SStephen Checkoway g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 2)), ==, replicate(c, 'I')); 334ddb6f225SStephen Checkoway g_assert_cmpint(flash_query_1(c, FLASH_ADDR(pri + 6)), ==, 2); /* R/W */ 33591d02312SPhilippe Mathieu-Daudé reset(c); 33691d02312SPhilippe Mathieu-Daudé 33791d02312SPhilippe Mathieu-Daudé const uint64_t dq7 = replicate(c, 0x80); 33891d02312SPhilippe Mathieu-Daudé const uint64_t dq6 = replicate(c, 0x40); 339a50547acSStephen Checkoway const uint64_t dq3 = replicate(c, 0x08); 340ddb6f225SStephen Checkoway const uint64_t dq2 = replicate(c, 0x04); 341a50547acSStephen Checkoway 34264659053SStephen Checkoway uint64_t byte_addr = 0; 34364659053SStephen Checkoway for (int region = 0; region < nb_erase_regions; ++region) { 34464659053SStephen Checkoway uint64_t base = 0x2D + 4 * region; 34564659053SStephen Checkoway flash_cmd(c, CFI_ADDR, CFI_CMD); 34664659053SStephen Checkoway uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(base + 0)) + 34764659053SStephen Checkoway (flash_query_1(c, FLASH_ADDR(base + 1)) << 8) + 1; 34864659053SStephen Checkoway uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(base + 2)) << 8) + 34964659053SStephen Checkoway (flash_query_1(c, FLASH_ADDR(base + 3)) << 16); 35064659053SStephen Checkoway g_assert_cmphex(nb_sectors, ==, c->nb_blocs[region]); 35164659053SStephen Checkoway g_assert_cmphex(sector_len, ==, c->sector_len[region]); 35264659053SStephen Checkoway reset(c); 35364659053SStephen Checkoway 35460b725b6SStephen Checkoway /* Erase and program sector. */ 35560b725b6SStephen Checkoway for (uint32_t i = 0; i < nb_sectors; ++i) { 35691d02312SPhilippe Mathieu-Daudé sector_erase(c, byte_addr); 357a50547acSStephen Checkoway 358a50547acSStephen Checkoway /* Check that DQ3 is 0. */ 359a50547acSStephen Checkoway g_assert_cmphex(flash_read(c, byte_addr) & dq3, ==, 0); 360a50547acSStephen Checkoway qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */ 361a50547acSStephen Checkoway 362a50547acSStephen Checkoway /* Check that DQ3 is 1. */ 36391d02312SPhilippe Mathieu-Daudé uint64_t status0 = flash_read(c, byte_addr); 364a50547acSStephen Checkoway g_assert_cmphex(status0 & dq3, ==, dq3); 365a50547acSStephen Checkoway 36660b725b6SStephen Checkoway /* DQ7 is 0 during an erase. */ 36791d02312SPhilippe Mathieu-Daudé g_assert_cmphex(status0 & dq7, ==, 0); 36891d02312SPhilippe Mathieu-Daudé uint64_t status1 = flash_read(c, byte_addr); 369a50547acSStephen Checkoway 37060b725b6SStephen Checkoway /* DQ6 toggles during an erase. */ 37191d02312SPhilippe Mathieu-Daudé g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6); 372a50547acSStephen Checkoway 37360b725b6SStephen Checkoway /* Wait for erase to complete. */ 374a50547acSStephen Checkoway wait_for_completion(c, byte_addr); 375a50547acSStephen Checkoway 37660b725b6SStephen Checkoway /* Ensure DQ6 has stopped toggling. */ 37764659053SStephen Checkoway g_assert_cmphex(flash_read(c, byte_addr), ==, 37864659053SStephen Checkoway flash_read(c, byte_addr)); 379a50547acSStephen Checkoway 38060b725b6SStephen Checkoway /* Now the data should be valid. */ 38191d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c)); 38260b725b6SStephen Checkoway 38360b725b6SStephen Checkoway /* Program a bit pattern. */ 38491d02312SPhilippe Mathieu-Daudé program(c, byte_addr, 0x55); 38591d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55); 38691d02312SPhilippe Mathieu-Daudé program(c, byte_addr, 0xA5); 38791d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05); 38864659053SStephen Checkoway byte_addr += sector_len; 38964659053SStephen Checkoway } 39060b725b6SStephen Checkoway } 39160b725b6SStephen Checkoway 39260b725b6SStephen Checkoway /* Erase the chip. */ 39391d02312SPhilippe Mathieu-Daudé chip_erase(c); 39460b725b6SStephen Checkoway /* Read toggle. */ 39591d02312SPhilippe Mathieu-Daudé uint64_t status0 = flash_read(c, 0); 39660b725b6SStephen Checkoway /* DQ7 is 0 during an erase. */ 39791d02312SPhilippe Mathieu-Daudé g_assert_cmphex(status0 & dq7, ==, 0); 39891d02312SPhilippe Mathieu-Daudé uint64_t status1 = flash_read(c, 0); 39960b725b6SStephen Checkoway /* DQ6 toggles during an erase. */ 40091d02312SPhilippe Mathieu-Daudé g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6); 40160b725b6SStephen Checkoway /* Wait for erase to complete. */ 40291d02312SPhilippe Mathieu-Daudé qtest_clock_step_next(c->qtest); 40360b725b6SStephen Checkoway /* Ensure DQ6 has stopped toggling. */ 40491d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0)); 40560b725b6SStephen Checkoway /* Now the data should be valid. */ 40691d02312SPhilippe Mathieu-Daudé 40764659053SStephen Checkoway for (int region = 0; region < nb_erase_regions; ++region) { 40864659053SStephen Checkoway for (uint32_t i = 0; i < c->nb_blocs[region]; ++i) { 40964659053SStephen Checkoway uint64_t byte_addr = i * c->sector_len[region]; 41091d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c)); 41191d02312SPhilippe Mathieu-Daudé } 41264659053SStephen Checkoway } 41360b725b6SStephen Checkoway 41460b725b6SStephen Checkoway /* Unlock bypass */ 41591d02312SPhilippe Mathieu-Daudé unlock(c); 41691d02312SPhilippe Mathieu-Daudé flash_cmd(c, UNLOCK0_ADDR, UNLOCK_BYPASS_CMD); 41791d02312SPhilippe Mathieu-Daudé bypass_program(c, 0 * c->bank_width, 0x01); 41891d02312SPhilippe Mathieu-Daudé bypass_program(c, 1 * c->bank_width, 0x23); 41991d02312SPhilippe Mathieu-Daudé bypass_program(c, 2 * c->bank_width, 0x45); 42060b725b6SStephen Checkoway /* 42160b725b6SStephen Checkoway * Test that bypass programming, unlike normal programming can use any 42260b725b6SStephen Checkoway * address for the PROGRAM_CMD. 42360b725b6SStephen Checkoway */ 42491d02312SPhilippe Mathieu-Daudé flash_cmd(c, FLASH_ADDR(3 * c->bank_width), PROGRAM_CMD); 42591d02312SPhilippe Mathieu-Daudé flash_write(c, 3 * c->bank_width, 0x67); 42691d02312SPhilippe Mathieu-Daudé wait_for_completion(c, 3 * c->bank_width); 42791d02312SPhilippe Mathieu-Daudé flash_cmd(c, FLASH_ADDR(0), UNLOCK_BYPASS_RESET_CMD); 42891d02312SPhilippe Mathieu-Daudé bypass_program(c, 4 * c->bank_width, 0x89); /* Should fail. */ 42991d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, 0 * c->bank_width), ==, 0x01); 43091d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, 1 * c->bank_width), ==, 0x23); 43191d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, 2 * c->bank_width), ==, 0x45); 43291d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, 3 * c->bank_width), ==, 0x67); 43391d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_read(c, 4 * c->bank_width), ==, bank_mask(c)); 43460b725b6SStephen Checkoway 4356682bc1eSStephen Checkoway /* Test ignored high order bits of address. */ 43691d02312SPhilippe Mathieu-Daudé flash_cmd(c, FLASH_ADDR(0x5555), UNLOCK0_CMD); 43791d02312SPhilippe Mathieu-Daudé flash_cmd(c, FLASH_ADDR(0x2AAA), UNLOCK1_CMD); 43891d02312SPhilippe Mathieu-Daudé flash_cmd(c, FLASH_ADDR(0x5555), AUTOSELECT_CMD); 43991d02312SPhilippe Mathieu-Daudé g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF)); 44091d02312SPhilippe Mathieu-Daudé reset(c); 4416682bc1eSStephen Checkoway 442a50547acSStephen Checkoway /* 443a50547acSStephen Checkoway * Program a word on each sector, erase one or two sectors per region, and 444a50547acSStephen Checkoway * verify that all of those, and only those, are erased. 445a50547acSStephen Checkoway */ 446a50547acSStephen Checkoway byte_addr = 0; 447a50547acSStephen Checkoway for (int region = 0; region < nb_erase_regions; ++region) { 448a50547acSStephen Checkoway for (int i = 0; i < config->nb_blocs[region]; ++i) { 449a50547acSStephen Checkoway program(c, byte_addr, 0); 450a50547acSStephen Checkoway byte_addr += config->sector_len[region]; 451a50547acSStephen Checkoway } 452a50547acSStephen Checkoway } 453a50547acSStephen Checkoway unlock(c); 454a50547acSStephen Checkoway flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD); 455a50547acSStephen Checkoway unlock(c); 456a50547acSStephen Checkoway byte_addr = 0; 457a50547acSStephen Checkoway const uint64_t erase_cmd = replicate(c, SECTOR_ERASE_CMD); 458a50547acSStephen Checkoway for (int region = 0; region < nb_erase_regions; ++region) { 459a50547acSStephen Checkoway flash_write(c, byte_addr, erase_cmd); 460a50547acSStephen Checkoway if (c->nb_blocs[region] > 1) { 461a50547acSStephen Checkoway flash_write(c, byte_addr + c->sector_len[region], erase_cmd); 462a50547acSStephen Checkoway } 463a50547acSStephen Checkoway byte_addr += c->sector_len[region] * c->nb_blocs[region]; 464a50547acSStephen Checkoway } 465a50547acSStephen Checkoway 466a50547acSStephen Checkoway qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */ 467a50547acSStephen Checkoway wait_for_completion(c, 0); 468a50547acSStephen Checkoway byte_addr = 0; 469a50547acSStephen Checkoway for (int region = 0; region < nb_erase_regions; ++region) { 470a50547acSStephen Checkoway for (int i = 0; i < config->nb_blocs[region]; ++i) { 471a50547acSStephen Checkoway if (i < 2) { 472a50547acSStephen Checkoway g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c)); 473a50547acSStephen Checkoway } else { 474a50547acSStephen Checkoway g_assert_cmphex(flash_read(c, byte_addr), ==, 0); 475a50547acSStephen Checkoway } 476a50547acSStephen Checkoway byte_addr += config->sector_len[region]; 477a50547acSStephen Checkoway } 478a50547acSStephen Checkoway } 479a50547acSStephen Checkoway 480ddb6f225SStephen Checkoway /* Test erase suspend/resume during erase timeout. */ 481ddb6f225SStephen Checkoway sector_erase(c, 0); 482ddb6f225SStephen Checkoway /* 483ddb6f225SStephen Checkoway * Check that DQ 3 is 0 and DQ6 and DQ2 are toggling in the sector being 484ddb6f225SStephen Checkoway * erased as well as in a sector not being erased. 485ddb6f225SStephen Checkoway */ 486ddb6f225SStephen Checkoway byte_addr = c->sector_len[0]; 487ddb6f225SStephen Checkoway status0 = flash_read(c, 0); 488ddb6f225SStephen Checkoway status1 = flash_read(c, 0); 489ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq3, ==, 0); 490ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 491ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 492ddb6f225SStephen Checkoway status0 = flash_read(c, byte_addr); 493ddb6f225SStephen Checkoway status1 = flash_read(c, byte_addr); 494ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq3, ==, 0); 495ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 496ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 497ddb6f225SStephen Checkoway 498ddb6f225SStephen Checkoway /* 499ddb6f225SStephen Checkoway * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in 500ddb6f225SStephen Checkoway * an erase suspended sector but that neither toggle (we should be 501ddb6f225SStephen Checkoway * getting data) in a sector not being erased. 502ddb6f225SStephen Checkoway */ 503ddb6f225SStephen Checkoway erase_suspend(c); 504ddb6f225SStephen Checkoway status0 = flash_read(c, 0); 505ddb6f225SStephen Checkoway status1 = flash_read(c, 0); 506ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, status1 & dq6); 507ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 508ddb6f225SStephen Checkoway g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr)); 509ddb6f225SStephen Checkoway 510ddb6f225SStephen Checkoway /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */ 511ddb6f225SStephen Checkoway erase_resume(c); 512ddb6f225SStephen Checkoway status0 = flash_read(c, 0); 513ddb6f225SStephen Checkoway status1 = flash_read(c, 0); 514ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq3, ==, dq3); 515ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 516ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 517ddb6f225SStephen Checkoway status0 = flash_read(c, byte_addr); 518ddb6f225SStephen Checkoway status1 = flash_read(c, byte_addr); 519ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq3, ==, dq3); 520ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 521ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 522ddb6f225SStephen Checkoway wait_for_completion(c, 0); 523ddb6f225SStephen Checkoway 524ddb6f225SStephen Checkoway /* Repeat this process but this time suspend after the timeout. */ 525ddb6f225SStephen Checkoway sector_erase(c, 0); 526ddb6f225SStephen Checkoway qtest_clock_step_next(c->qtest); 527ddb6f225SStephen Checkoway /* 528ddb6f225SStephen Checkoway * Check that DQ 3 is 1 and DQ6 and DQ2 are toggling in the sector being 529ddb6f225SStephen Checkoway * erased as well as in a sector not being erased. 530ddb6f225SStephen Checkoway */ 531ddb6f225SStephen Checkoway byte_addr = c->sector_len[0]; 532ddb6f225SStephen Checkoway status0 = flash_read(c, 0); 533ddb6f225SStephen Checkoway status1 = flash_read(c, 0); 534ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq3, ==, dq3); 535ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 536ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 537ddb6f225SStephen Checkoway status0 = flash_read(c, byte_addr); 538ddb6f225SStephen Checkoway status1 = flash_read(c, byte_addr); 539ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq3, ==, dq3); 540ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 541ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 542ddb6f225SStephen Checkoway 543ddb6f225SStephen Checkoway /* 544ddb6f225SStephen Checkoway * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in 545ddb6f225SStephen Checkoway * an erase suspended sector but that neither toggle (we should be 546ddb6f225SStephen Checkoway * getting data) in a sector not being erased. 547ddb6f225SStephen Checkoway */ 548ddb6f225SStephen Checkoway erase_suspend(c); 549ddb6f225SStephen Checkoway status0 = flash_read(c, 0); 550ddb6f225SStephen Checkoway status1 = flash_read(c, 0); 551ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, status1 & dq6); 552ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 553ddb6f225SStephen Checkoway g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr)); 554ddb6f225SStephen Checkoway 555ddb6f225SStephen Checkoway /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */ 556ddb6f225SStephen Checkoway erase_resume(c); 557ddb6f225SStephen Checkoway status0 = flash_read(c, 0); 558ddb6f225SStephen Checkoway status1 = flash_read(c, 0); 559ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq3, ==, dq3); 560ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 561ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 562ddb6f225SStephen Checkoway status0 = flash_read(c, byte_addr); 563ddb6f225SStephen Checkoway status1 = flash_read(c, byte_addr); 564ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq3, ==, dq3); 565ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); 566ddb6f225SStephen Checkoway g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); 567ddb6f225SStephen Checkoway wait_for_completion(c, 0); 568ddb6f225SStephen Checkoway 56991d02312SPhilippe Mathieu-Daudé qtest_quit(qtest); 57060b725b6SStephen Checkoway } 57160b725b6SStephen Checkoway 57246fb7809SStephen Checkoway /* 57346fb7809SStephen Checkoway * Test that 57446fb7809SStephen Checkoway * 1. enter autoselect mode; 57546fb7809SStephen Checkoway * 2. enter CFI mode; and then 57646fb7809SStephen Checkoway * 3. exit CFI mode 57746fb7809SStephen Checkoway * leaves the flash device in autoselect mode. 57846fb7809SStephen Checkoway */ 57946fb7809SStephen Checkoway static void test_cfi_in_autoselect(const void *opaque) 58046fb7809SStephen Checkoway { 58146fb7809SStephen Checkoway const FlashConfig *config = opaque; 58246fb7809SStephen Checkoway QTestState *qtest; 583*6f6e1698SPaolo Bonzini qtest = qtest_initf("-M musicpal" 58446fb7809SStephen Checkoway " -drive if=pflash,file=%s,format=raw,copy-on-read", 58546fb7809SStephen Checkoway image_path); 58646fb7809SStephen Checkoway FlashConfig explicit_config = expand_config_defaults(config); 58746fb7809SStephen Checkoway explicit_config.qtest = qtest; 58846fb7809SStephen Checkoway const FlashConfig *c = &explicit_config; 58946fb7809SStephen Checkoway 59046fb7809SStephen Checkoway /* 1. Enter autoselect. */ 59146fb7809SStephen Checkoway unlock(c); 59246fb7809SStephen Checkoway flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD); 593a50547acSStephen Checkoway g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF)); 59446fb7809SStephen Checkoway 59546fb7809SStephen Checkoway /* 2. Enter CFI. */ 59646fb7809SStephen Checkoway flash_cmd(c, CFI_ADDR, CFI_CMD); 597a50547acSStephen Checkoway g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q')); 598a50547acSStephen Checkoway g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R')); 599a50547acSStephen Checkoway g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y')); 60046fb7809SStephen Checkoway 60146fb7809SStephen Checkoway /* 3. Exit CFI. */ 60246fb7809SStephen Checkoway reset(c); 603a50547acSStephen Checkoway g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF)); 60446fb7809SStephen Checkoway 60546fb7809SStephen Checkoway qtest_quit(qtest); 60646fb7809SStephen Checkoway } 60746fb7809SStephen Checkoway 60860b725b6SStephen Checkoway static void cleanup(void *opaque) 60960b725b6SStephen Checkoway { 61060b725b6SStephen Checkoway unlink(image_path); 61160b725b6SStephen Checkoway } 61260b725b6SStephen Checkoway 61391d02312SPhilippe Mathieu-Daudé /* 61491d02312SPhilippe Mathieu-Daudé * XXX: Tests are limited to bank_width = 2 for now because that's what 61591d02312SPhilippe Mathieu-Daudé * hw/arm/musicpal.c has. 61691d02312SPhilippe Mathieu-Daudé */ 61791d02312SPhilippe Mathieu-Daudé static const FlashConfig configuration[] = { 61891d02312SPhilippe Mathieu-Daudé /* One x16 device. */ 61991d02312SPhilippe Mathieu-Daudé { 62091d02312SPhilippe Mathieu-Daudé .bank_width = 2, 62191d02312SPhilippe Mathieu-Daudé }, 62264659053SStephen Checkoway /* Nonuniform sectors (top boot). */ 62364659053SStephen Checkoway { 62464659053SStephen Checkoway .bank_width = 2, 62564659053SStephen Checkoway .nb_blocs = { 127, 1, 2, 1 }, 62664659053SStephen Checkoway .sector_len = { 0x10000, 0x08000, 0x02000, 0x04000 }, 62764659053SStephen Checkoway }, 62864659053SStephen Checkoway /* Nonuniform sectors (bottom boot). */ 62964659053SStephen Checkoway { 63064659053SStephen Checkoway .bank_width = 2, 63164659053SStephen Checkoway .nb_blocs = { 1, 2, 1, 127 }, 63264659053SStephen Checkoway .sector_len = { 0x04000, 0x02000, 0x08000, 0x10000 }, 63364659053SStephen Checkoway }, 63491d02312SPhilippe Mathieu-Daudé }; 63591d02312SPhilippe Mathieu-Daudé 63660b725b6SStephen Checkoway int main(int argc, char **argv) 63760b725b6SStephen Checkoway { 63860b725b6SStephen Checkoway int fd = mkstemp(image_path); 63960b725b6SStephen Checkoway if (fd == -1) { 64060b725b6SStephen Checkoway g_printerr("Failed to create temporary file %s: %s\n", image_path, 64160b725b6SStephen Checkoway strerror(errno)); 64260b725b6SStephen Checkoway exit(EXIT_FAILURE); 64360b725b6SStephen Checkoway } 64464659053SStephen Checkoway if (ftruncate(fd, UNIFORM_FLASH_SIZE) < 0) { 64560b725b6SStephen Checkoway int error_code = errno; 64660b725b6SStephen Checkoway close(fd); 64760b725b6SStephen Checkoway unlink(image_path); 64891d02312SPhilippe Mathieu-Daudé g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path, 64964659053SStephen Checkoway UNIFORM_FLASH_SIZE, strerror(error_code)); 65060b725b6SStephen Checkoway exit(EXIT_FAILURE); 65160b725b6SStephen Checkoway } 65260b725b6SStephen Checkoway close(fd); 65360b725b6SStephen Checkoway 65460b725b6SStephen Checkoway qtest_add_abrt_handler(cleanup, NULL); 65560b725b6SStephen Checkoway g_test_init(&argc, &argv, NULL); 65691d02312SPhilippe Mathieu-Daudé 65791d02312SPhilippe Mathieu-Daudé size_t nb_configurations = sizeof configuration / sizeof configuration[0]; 65891d02312SPhilippe Mathieu-Daudé for (size_t i = 0; i < nb_configurations; ++i) { 65991d02312SPhilippe Mathieu-Daudé const FlashConfig *config = &configuration[i]; 66064659053SStephen Checkoway char *path = g_strdup_printf("pflash-cfi02" 66164659053SStephen Checkoway "/geometry/%dx%x-%dx%x-%dx%x-%dx%x" 66264659053SStephen Checkoway "/%d", 66364659053SStephen Checkoway config->nb_blocs[0], 66464659053SStephen Checkoway config->sector_len[0], 66564659053SStephen Checkoway config->nb_blocs[1], 66664659053SStephen Checkoway config->sector_len[1], 66764659053SStephen Checkoway config->nb_blocs[2], 66864659053SStephen Checkoway config->sector_len[2], 66964659053SStephen Checkoway config->nb_blocs[3], 67064659053SStephen Checkoway config->sector_len[3], 67191d02312SPhilippe Mathieu-Daudé config->bank_width); 67264659053SStephen Checkoway qtest_add_data_func(path, config, test_geometry); 67391d02312SPhilippe Mathieu-Daudé g_free(path); 67491d02312SPhilippe Mathieu-Daudé } 67546fb7809SStephen Checkoway 67646fb7809SStephen Checkoway qtest_add_data_func("pflash-cfi02/cfi-in-autoselect", &configuration[0], 67746fb7809SStephen Checkoway test_cfi_in_autoselect); 67860b725b6SStephen Checkoway int result = g_test_run(); 67960b725b6SStephen Checkoway cleanup(NULL); 68060b725b6SStephen Checkoway return result; 68160b725b6SStephen Checkoway } 682