17a2334f7SCédric Le Goater /* 27a2334f7SCédric Le Goater * QTest testcase for the M25P80 Flash (Using the Aspeed SPI 37a2334f7SCédric Le Goater * Controller) 47a2334f7SCédric Le Goater * 57a2334f7SCédric Le Goater * Copyright (C) 2016 IBM Corp. 67a2334f7SCédric Le Goater * 77a2334f7SCédric Le Goater * Permission is hereby granted, free of charge, to any person obtaining a copy 87a2334f7SCédric Le Goater * of this software and associated documentation files (the "Software"), to deal 97a2334f7SCédric Le Goater * in the Software without restriction, including without limitation the rights 107a2334f7SCédric Le Goater * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 117a2334f7SCédric Le Goater * copies of the Software, and to permit persons to whom the Software is 127a2334f7SCédric Le Goater * furnished to do so, subject to the following conditions: 137a2334f7SCédric Le Goater * 147a2334f7SCédric Le Goater * The above copyright notice and this permission notice shall be included in 157a2334f7SCédric Le Goater * all copies or substantial portions of the Software. 167a2334f7SCédric Le Goater * 177a2334f7SCédric Le Goater * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 187a2334f7SCédric Le Goater * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197a2334f7SCédric Le Goater * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 207a2334f7SCédric Le Goater * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 217a2334f7SCédric Le Goater * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 227a2334f7SCédric Le Goater * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 237a2334f7SCédric Le Goater * THE SOFTWARE. 247a2334f7SCédric Le Goater */ 257a2334f7SCédric Le Goater 267a2334f7SCédric Le Goater #include "qemu/osdep.h" 277a2334f7SCédric Le Goater #include "qemu/bswap.h" 28dd210749SThomas Huth #include "libqtest-single.h" 29188052a1SIris Chen #include "qemu/bitops.h" 307a2334f7SCédric Le Goater 317a2334f7SCédric Le Goater /* 327a2334f7SCédric Le Goater * ASPEED SPI Controller registers 337a2334f7SCédric Le Goater */ 347a2334f7SCédric Le Goater #define R_CONF 0x00 357a2334f7SCédric Le Goater #define CONF_ENABLE_W0 (1 << 16) 367a2334f7SCédric Le Goater #define R_CE_CTRL 0x04 377a2334f7SCédric Le Goater #define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */ 387a2334f7SCédric Le Goater #define R_CTRL0 0x10 397a2334f7SCédric Le Goater #define CTRL_CE_STOP_ACTIVE (1 << 2) 40371a3dd2SCédric Le Goater #define CTRL_READMODE 0x0 41371a3dd2SCédric Le Goater #define CTRL_FREADMODE 0x1 42371a3dd2SCédric Le Goater #define CTRL_WRITEMODE 0x2 437a2334f7SCédric Le Goater #define CTRL_USERMODE 0x3 44188052a1SIris Chen #define SR_WEL BIT(1) 457a2334f7SCédric Le Goater 467a2334f7SCédric Le Goater /* 477a2334f7SCédric Le Goater * Flash commands 487a2334f7SCédric Le Goater */ 497a2334f7SCédric Le Goater enum { 507a2334f7SCédric Le Goater JEDEC_READ = 0x9f, 51188052a1SIris Chen RDSR = 0x5, 52188052a1SIris Chen WRDI = 0x4, 537a2334f7SCédric Le Goater BULK_ERASE = 0xc7, 547a2334f7SCédric Le Goater READ = 0x03, 557a2334f7SCédric Le Goater PP = 0x02, 561de51272SIris Chen WRSR = 0x1, 577a2334f7SCédric Le Goater WREN = 0x6, 581de51272SIris Chen SRWD = 0x80, 59bd9f5052SCédric Le Goater RESET_ENABLE = 0x66, 60bd9f5052SCédric Le Goater RESET_MEMORY = 0x99, 617a2334f7SCédric Le Goater EN_4BYTE_ADDR = 0xB7, 627a2334f7SCédric Le Goater ERASE_SECTOR = 0xd8, 637a2334f7SCédric Le Goater }; 647a2334f7SCédric Le Goater 65d2c4f384SJiaxun Yang #define FLASH_PAGE_SIZE 256 667a2334f7SCédric Le Goater 67*975d4bafSJamin Lin typedef struct TestData { 68*975d4bafSJamin Lin QTestState *s; 69*975d4bafSJamin Lin uint64_t spi_base; 70*975d4bafSJamin Lin uint64_t flash_base; 71*975d4bafSJamin Lin uint32_t jedec_id; 72*975d4bafSJamin Lin char *tmp_path; 73*975d4bafSJamin Lin } TestData; 74*975d4bafSJamin Lin 757a2334f7SCédric Le Goater /* 767a2334f7SCédric Le Goater * Use an explicit bswap for the values read/wrote to the flash region 777a2334f7SCédric Le Goater * as they are BE and the Aspeed CPU is LE. 787a2334f7SCédric Le Goater */ 797a2334f7SCédric Le Goater static inline uint32_t make_be32(uint32_t data) 807a2334f7SCédric Le Goater { 817a2334f7SCédric Le Goater return bswap32(data); 827a2334f7SCédric Le Goater } 837a2334f7SCédric Le Goater 84*975d4bafSJamin Lin static inline void spi_writel(const TestData *data, uint64_t offset, 85*975d4bafSJamin Lin uint32_t value) 867a2334f7SCédric Le Goater { 87*975d4bafSJamin Lin qtest_writel(data->s, data->spi_base + offset, value); 887a2334f7SCédric Le Goater } 897a2334f7SCédric Le Goater 90*975d4bafSJamin Lin static inline uint32_t spi_readl(const TestData *data, uint64_t offset) 91bd9f5052SCédric Le Goater { 92*975d4bafSJamin Lin return qtest_readl(data->s, data->spi_base + offset); 93*975d4bafSJamin Lin } 94*975d4bafSJamin Lin 95*975d4bafSJamin Lin static inline void flash_writeb(const TestData *data, uint64_t offset, 96*975d4bafSJamin Lin uint8_t value) 97*975d4bafSJamin Lin { 98*975d4bafSJamin Lin qtest_writeb(data->s, data->flash_base + offset, value); 99*975d4bafSJamin Lin } 100*975d4bafSJamin Lin 101*975d4bafSJamin Lin static inline void flash_writel(const TestData *data, uint64_t offset, 102*975d4bafSJamin Lin uint32_t value) 103*975d4bafSJamin Lin { 104*975d4bafSJamin Lin qtest_writel(data->s, data->flash_base + offset, value); 105*975d4bafSJamin Lin } 106*975d4bafSJamin Lin 107*975d4bafSJamin Lin static inline uint8_t flash_readb(const TestData *data, uint64_t offset) 108*975d4bafSJamin Lin { 109*975d4bafSJamin Lin return qtest_readb(data->s, data->flash_base + offset); 110*975d4bafSJamin Lin } 111*975d4bafSJamin Lin 112*975d4bafSJamin Lin static inline uint32_t flash_readl(const TestData *data, uint64_t offset) 113*975d4bafSJamin Lin { 114*975d4bafSJamin Lin return qtest_readl(data->s, data->flash_base + offset); 115*975d4bafSJamin Lin } 116*975d4bafSJamin Lin 117*975d4bafSJamin Lin static void spi_conf(const TestData *data, uint32_t value) 118*975d4bafSJamin Lin { 119*975d4bafSJamin Lin uint32_t conf = spi_readl(data, R_CONF); 120*975d4bafSJamin Lin 121*975d4bafSJamin Lin conf |= value; 122*975d4bafSJamin Lin spi_writel(data, R_CONF, conf); 123*975d4bafSJamin Lin } 124*975d4bafSJamin Lin 125*975d4bafSJamin Lin static void spi_conf_remove(const TestData *data, uint32_t value) 126*975d4bafSJamin Lin { 127*975d4bafSJamin Lin uint32_t conf = spi_readl(data, R_CONF); 128bd9f5052SCédric Le Goater 129bd9f5052SCédric Le Goater conf &= ~value; 130*975d4bafSJamin Lin spi_writel(data, R_CONF, conf); 131bd9f5052SCédric Le Goater } 132bd9f5052SCédric Le Goater 133*975d4bafSJamin Lin static void spi_ce_ctrl(const TestData *data, uint32_t value) 134371a3dd2SCédric Le Goater { 135*975d4bafSJamin Lin uint32_t conf = spi_readl(data, R_CE_CTRL); 136371a3dd2SCédric Le Goater 137371a3dd2SCédric Le Goater conf |= value; 138*975d4bafSJamin Lin spi_writel(data, R_CE_CTRL, conf); 139371a3dd2SCédric Le Goater } 140371a3dd2SCédric Le Goater 141*975d4bafSJamin Lin static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t cmd) 142371a3dd2SCédric Le Goater { 143*975d4bafSJamin Lin uint32_t ctrl = spi_readl(data, R_CTRL0); 144371a3dd2SCédric Le Goater ctrl &= ~(CTRL_USERMODE | 0xff << 16); 145371a3dd2SCédric Le Goater ctrl |= mode | (cmd << 16); 146*975d4bafSJamin Lin spi_writel(data, R_CTRL0, ctrl); 147371a3dd2SCédric Le Goater } 148371a3dd2SCédric Le Goater 149*975d4bafSJamin Lin static void spi_ctrl_start_user(const TestData *data) 1507a2334f7SCédric Le Goater { 151*975d4bafSJamin Lin uint32_t ctrl = spi_readl(data, R_CTRL0); 1527a2334f7SCédric Le Goater 1537a2334f7SCédric Le Goater ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; 154*975d4bafSJamin Lin spi_writel(data, R_CTRL0, ctrl); 1557a2334f7SCédric Le Goater 1567a2334f7SCédric Le Goater ctrl &= ~CTRL_CE_STOP_ACTIVE; 157*975d4bafSJamin Lin spi_writel(data, R_CTRL0, ctrl); 1587a2334f7SCédric Le Goater } 1597a2334f7SCédric Le Goater 160*975d4bafSJamin Lin static void spi_ctrl_stop_user(const TestData *data) 1617a2334f7SCédric Le Goater { 162*975d4bafSJamin Lin uint32_t ctrl = spi_readl(data, R_CTRL0); 1637a2334f7SCédric Le Goater 1647a2334f7SCédric Le Goater ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; 165*975d4bafSJamin Lin spi_writel(data, R_CTRL0, ctrl); 1667a2334f7SCédric Le Goater } 1677a2334f7SCédric Le Goater 168*975d4bafSJamin Lin static void flash_reset(const TestData *data) 169bd9f5052SCédric Le Goater { 170*975d4bafSJamin Lin spi_conf(data, CONF_ENABLE_W0); 171bd9f5052SCédric Le Goater 172*975d4bafSJamin Lin spi_ctrl_start_user(data); 173*975d4bafSJamin Lin flash_writeb(data, 0, RESET_ENABLE); 174*975d4bafSJamin Lin flash_writeb(data, 0, RESET_MEMORY); 175*975d4bafSJamin Lin flash_writeb(data, 0, WREN); 176*975d4bafSJamin Lin flash_writeb(data, 0, BULK_ERASE); 177*975d4bafSJamin Lin flash_writeb(data, 0, WRDI); 178*975d4bafSJamin Lin spi_ctrl_stop_user(data); 179bd9f5052SCédric Le Goater 180*975d4bafSJamin Lin spi_conf_remove(data, CONF_ENABLE_W0); 181bd9f5052SCédric Le Goater } 182bd9f5052SCédric Le Goater 183*975d4bafSJamin Lin static void test_read_jedec(const void *data) 1847a2334f7SCédric Le Goater { 185*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 1867a2334f7SCédric Le Goater uint32_t jedec = 0x0; 1877a2334f7SCédric Le Goater 188*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 1897a2334f7SCédric Le Goater 190*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 191*975d4bafSJamin Lin flash_writeb(test_data, 0, JEDEC_READ); 192*975d4bafSJamin Lin jedec |= flash_readb(test_data, 0) << 16; 193*975d4bafSJamin Lin jedec |= flash_readb(test_data, 0) << 8; 194*975d4bafSJamin Lin jedec |= flash_readb(test_data, 0); 195*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 1967a2334f7SCédric Le Goater 197*975d4bafSJamin Lin flash_reset(test_data); 198bd9f5052SCédric Le Goater 199*975d4bafSJamin Lin g_assert_cmphex(jedec, ==, test_data->jedec_id); 2007a2334f7SCédric Le Goater } 2017a2334f7SCédric Le Goater 202*975d4bafSJamin Lin static void read_page(const TestData *data, uint32_t addr, uint32_t *page) 2037a2334f7SCédric Le Goater { 2047a2334f7SCédric Le Goater int i; 2057a2334f7SCédric Le Goater 206*975d4bafSJamin Lin spi_ctrl_start_user(data); 2077a2334f7SCédric Le Goater 208*975d4bafSJamin Lin flash_writeb(data, 0, EN_4BYTE_ADDR); 209*975d4bafSJamin Lin flash_writeb(data, 0, READ); 210*975d4bafSJamin Lin flash_writel(data, 0, make_be32(addr)); 2117a2334f7SCédric Le Goater 2127a2334f7SCédric Le Goater /* Continuous read are supported */ 213d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 214*975d4bafSJamin Lin page[i] = make_be32(flash_readl(data, 0)); 2157a2334f7SCédric Le Goater } 216*975d4bafSJamin Lin spi_ctrl_stop_user(data); 2177a2334f7SCédric Le Goater } 2187a2334f7SCédric Le Goater 219*975d4bafSJamin Lin static void read_page_mem(const TestData *data, uint32_t addr, uint32_t *page) 220371a3dd2SCédric Le Goater { 221371a3dd2SCédric Le Goater int i; 222371a3dd2SCédric Le Goater 223371a3dd2SCédric Le Goater /* move out USER mode to use direct reads from the AHB bus */ 224*975d4bafSJamin Lin spi_ctrl_setmode(data, CTRL_READMODE, READ); 225371a3dd2SCédric Le Goater 226d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 227*975d4bafSJamin Lin page[i] = make_be32(flash_readl(data, addr + i * 4)); 228371a3dd2SCédric Le Goater } 229371a3dd2SCédric Le Goater } 230371a3dd2SCédric Le Goater 231*975d4bafSJamin Lin static void write_page_mem(const TestData *data, uint32_t addr, 232*975d4bafSJamin Lin uint32_t write_value) 2338abf9ba4SIris Chen { 234*975d4bafSJamin Lin spi_ctrl_setmode(data, CTRL_WRITEMODE, PP); 2358abf9ba4SIris Chen 2368abf9ba4SIris Chen for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 237*975d4bafSJamin Lin flash_writel(data, addr + i * 4, write_value); 2388abf9ba4SIris Chen } 2398abf9ba4SIris Chen } 2408abf9ba4SIris Chen 241*975d4bafSJamin Lin static void assert_page_mem(const TestData *data, uint32_t addr, 242*975d4bafSJamin Lin uint32_t expected_value) 2438abf9ba4SIris Chen { 2448abf9ba4SIris Chen uint32_t page[FLASH_PAGE_SIZE / 4]; 245*975d4bafSJamin Lin read_page_mem(data, addr, page); 2468abf9ba4SIris Chen for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 2478abf9ba4SIris Chen g_assert_cmphex(page[i], ==, expected_value); 2488abf9ba4SIris Chen } 2498abf9ba4SIris Chen } 2508abf9ba4SIris Chen 251*975d4bafSJamin Lin static void test_erase_sector(const void *data) 2527a2334f7SCédric Le Goater { 253*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 254d2c4f384SJiaxun Yang uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE; 255d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 2567a2334f7SCédric Le Goater int i; 2577a2334f7SCédric Le Goater 258*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 2597a2334f7SCédric Le Goater 26092a45bdeSIris Chen /* 26192a45bdeSIris Chen * Previous page should be full of 0xffs after backend is 26292a45bdeSIris Chen * initialized 26392a45bdeSIris Chen */ 264*975d4bafSJamin Lin read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page); 26592a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 26692a45bdeSIris Chen g_assert_cmphex(page[i], ==, 0xffffffff); 26792a45bdeSIris Chen } 26892a45bdeSIris Chen 269*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 270*975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 271*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 272*975d4bafSJamin Lin flash_writeb(test_data, 0, PP); 273*975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr)); 27492a45bdeSIris Chen 27592a45bdeSIris Chen /* Fill the page with its own addresses */ 27692a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 277*975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr + i * 4)); 27892a45bdeSIris Chen } 279*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 28092a45bdeSIris Chen 28192a45bdeSIris Chen /* Check the page is correctly written */ 282*975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 28392a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 28492a45bdeSIris Chen g_assert_cmphex(page[i], ==, some_page_addr + i * 4); 28592a45bdeSIris Chen } 28692a45bdeSIris Chen 287*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 288*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 289*975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 290*975d4bafSJamin Lin flash_writeb(test_data, 0, ERASE_SECTOR); 291*975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr)); 292*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 2937a2334f7SCédric Le Goater 29492a45bdeSIris Chen /* Check the page is erased */ 295*975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 296d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 2977a2334f7SCédric Le Goater g_assert_cmphex(page[i], ==, 0xffffffff); 2987a2334f7SCédric Le Goater } 299bd9f5052SCédric Le Goater 300*975d4bafSJamin Lin flash_reset(test_data); 3017a2334f7SCédric Le Goater } 3027a2334f7SCédric Le Goater 303*975d4bafSJamin Lin static void test_erase_all(const void *data) 3047a2334f7SCédric Le Goater { 305*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 306d2c4f384SJiaxun Yang uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE; 307d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 3087a2334f7SCédric Le Goater int i; 3097a2334f7SCédric Le Goater 310*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 3117a2334f7SCédric Le Goater 31292a45bdeSIris Chen /* 31392a45bdeSIris Chen * Previous page should be full of 0xffs after backend is 31492a45bdeSIris Chen * initialized 31592a45bdeSIris Chen */ 316*975d4bafSJamin Lin read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page); 31792a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 31892a45bdeSIris Chen g_assert_cmphex(page[i], ==, 0xffffffff); 31992a45bdeSIris Chen } 32092a45bdeSIris Chen 321*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 322*975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 323*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 324*975d4bafSJamin Lin flash_writeb(test_data, 0, PP); 325*975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr)); 32692a45bdeSIris Chen 32792a45bdeSIris Chen /* Fill the page with its own addresses */ 32892a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 329*975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr + i * 4)); 33092a45bdeSIris Chen } 331*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 33292a45bdeSIris Chen 33392a45bdeSIris Chen /* Check the page is correctly written */ 334*975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 335d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 33692a45bdeSIris Chen g_assert_cmphex(page[i], ==, some_page_addr + i * 4); 3377a2334f7SCédric Le Goater } 3387a2334f7SCédric Le Goater 339*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 340*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 341*975d4bafSJamin Lin flash_writeb(test_data, 0, BULK_ERASE); 342*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 3437a2334f7SCédric Le Goater 34492a45bdeSIris Chen /* Check the page is erased */ 345*975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 346d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 3477a2334f7SCédric Le Goater g_assert_cmphex(page[i], ==, 0xffffffff); 3487a2334f7SCédric Le Goater } 349bd9f5052SCédric Le Goater 350*975d4bafSJamin Lin flash_reset(test_data); 3517a2334f7SCédric Le Goater } 3527a2334f7SCédric Le Goater 353*975d4bafSJamin Lin static void test_write_page(const void *data) 3547a2334f7SCédric Le Goater { 355*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 356d2c4f384SJiaxun Yang uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */ 357d2c4f384SJiaxun Yang uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE; 358d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 3597a2334f7SCédric Le Goater int i; 3607a2334f7SCédric Le Goater 361*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 3627a2334f7SCédric Le Goater 363*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 364*975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 365*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 366*975d4bafSJamin Lin flash_writeb(test_data, 0, PP); 367*975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr)); 3687a2334f7SCédric Le Goater 3697a2334f7SCédric Le Goater /* Fill the page with its own addresses */ 370d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 371*975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr + i * 4)); 3727a2334f7SCédric Le Goater } 373*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 3747a2334f7SCédric Le Goater 3757a2334f7SCédric Le Goater /* Check what was written */ 376*975d4bafSJamin Lin read_page(test_data, my_page_addr, page); 377d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 3787a2334f7SCédric Le Goater g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 3797a2334f7SCédric Le Goater } 3807a2334f7SCédric Le Goater 3817a2334f7SCédric Le Goater /* Check some other page. It should be full of 0xff */ 382*975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 383d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 3847a2334f7SCédric Le Goater g_assert_cmphex(page[i], ==, 0xffffffff); 3857a2334f7SCédric Le Goater } 386bd9f5052SCédric Le Goater 387*975d4bafSJamin Lin flash_reset(test_data); 3887a2334f7SCédric Le Goater } 3897a2334f7SCédric Le Goater 390*975d4bafSJamin Lin static void test_read_page_mem(const void *data) 391371a3dd2SCédric Le Goater { 392*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 393d2c4f384SJiaxun Yang uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */ 394d2c4f384SJiaxun Yang uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE; 395d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 396371a3dd2SCédric Le Goater int i; 397371a3dd2SCédric Le Goater 3981df52a9aSJamin Lin /* 3991df52a9aSJamin Lin * Enable 4BYTE mode for controller. This is should be strapped by 400371a3dd2SCédric Le Goater * HW for CE0 anyhow. 401371a3dd2SCédric Le Goater */ 402*975d4bafSJamin Lin spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0); 403371a3dd2SCédric Le Goater 404371a3dd2SCédric Le Goater /* Enable 4BYTE mode for flash. */ 405*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 406*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 407*975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 408*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 409*975d4bafSJamin Lin flash_writeb(test_data, 0, PP); 410*975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr)); 41192a45bdeSIris Chen 41292a45bdeSIris Chen /* Fill the page with its own addresses */ 41392a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 414*975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr + i * 4)); 41592a45bdeSIris Chen } 416*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 417*975d4bafSJamin Lin spi_conf_remove(test_data, CONF_ENABLE_W0); 418371a3dd2SCédric Le Goater 419371a3dd2SCédric Le Goater /* Check what was written */ 420*975d4bafSJamin Lin read_page_mem(test_data, my_page_addr, page); 421d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 422371a3dd2SCédric Le Goater g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 423371a3dd2SCédric Le Goater } 424371a3dd2SCédric Le Goater 425371a3dd2SCédric Le Goater /* Check some other page. It should be full of 0xff */ 426*975d4bafSJamin Lin read_page_mem(test_data, some_page_addr, page); 427d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 428371a3dd2SCédric Le Goater g_assert_cmphex(page[i], ==, 0xffffffff); 429371a3dd2SCédric Le Goater } 430371a3dd2SCédric Le Goater 431*975d4bafSJamin Lin flash_reset(test_data); 432371a3dd2SCédric Le Goater } 433371a3dd2SCédric Le Goater 434*975d4bafSJamin Lin static void test_write_page_mem(const void *data) 435371a3dd2SCédric Le Goater { 436*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 437d2c4f384SJiaxun Yang uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE; 438d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 439371a3dd2SCédric Le Goater int i; 440371a3dd2SCédric Le Goater 4411df52a9aSJamin Lin /* 4421df52a9aSJamin Lin * Enable 4BYTE mode for controller. This is should be strapped by 443371a3dd2SCédric Le Goater * HW for CE0 anyhow. 444371a3dd2SCédric Le Goater */ 445*975d4bafSJamin Lin spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0); 446371a3dd2SCédric Le Goater 447371a3dd2SCédric Le Goater /* Enable 4BYTE mode for flash. */ 448*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 449*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 450*975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 451*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 452*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 453371a3dd2SCédric Le Goater 454371a3dd2SCédric Le Goater /* move out USER mode to use direct writes to the AHB bus */ 455*975d4bafSJamin Lin spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP); 456371a3dd2SCédric Le Goater 457d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 458*975d4bafSJamin Lin flash_writel(test_data, my_page_addr + i * 4, 459371a3dd2SCédric Le Goater make_be32(my_page_addr + i * 4)); 460371a3dd2SCédric Le Goater } 461371a3dd2SCédric Le Goater 462371a3dd2SCédric Le Goater /* Check what was written */ 463*975d4bafSJamin Lin read_page_mem(test_data, my_page_addr, page); 464d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 465371a3dd2SCédric Le Goater g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 466371a3dd2SCédric Le Goater } 467371a3dd2SCédric Le Goater 468*975d4bafSJamin Lin flash_reset(test_data); 469371a3dd2SCédric Le Goater } 470371a3dd2SCédric Le Goater 471*975d4bafSJamin Lin static void test_read_status_reg(const void *data) 472188052a1SIris Chen { 473*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 474188052a1SIris Chen uint8_t r; 475188052a1SIris Chen 476*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 477188052a1SIris Chen 478*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 479*975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 480*975d4bafSJamin Lin r = flash_readb(test_data, 0); 481*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 482188052a1SIris Chen 483188052a1SIris Chen g_assert_cmphex(r & SR_WEL, ==, 0); 484188052a1SIris Chen g_assert(!qtest_qom_get_bool 485*975d4bafSJamin Lin (test_data->s, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); 486188052a1SIris Chen 487*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 488*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 489*975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 490*975d4bafSJamin Lin r = flash_readb(test_data, 0); 491*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 492188052a1SIris Chen 493188052a1SIris Chen g_assert_cmphex(r & SR_WEL, ==, SR_WEL); 494188052a1SIris Chen g_assert(qtest_qom_get_bool 495*975d4bafSJamin Lin (test_data->s, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); 496188052a1SIris Chen 497*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 498*975d4bafSJamin Lin flash_writeb(test_data, 0, WRDI); 499*975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 500*975d4bafSJamin Lin r = flash_readb(test_data, 0); 501*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 502188052a1SIris Chen 503188052a1SIris Chen g_assert_cmphex(r & SR_WEL, ==, 0); 504188052a1SIris Chen g_assert(!qtest_qom_get_bool 505*975d4bafSJamin Lin (test_data->s, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); 506188052a1SIris Chen 507*975d4bafSJamin Lin flash_reset(test_data); 508188052a1SIris Chen } 509188052a1SIris Chen 510*975d4bafSJamin Lin static void test_status_reg_write_protection(const void *data) 5111de51272SIris Chen { 512*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 5131de51272SIris Chen uint8_t r; 5141de51272SIris Chen 515*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 5161de51272SIris Chen 5171de51272SIris Chen /* default case: WP# is high and SRWD is low -> status register writable */ 518*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 519*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 5201de51272SIris Chen /* test ability to write SRWD */ 521*975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 522*975d4bafSJamin Lin flash_writeb(test_data, 0, SRWD); 523*975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 524*975d4bafSJamin Lin r = flash_readb(test_data, 0); 525*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 5261de51272SIris Chen g_assert_cmphex(r & SRWD, ==, SRWD); 5271de51272SIris Chen 5281de51272SIris Chen /* WP# high and SRWD high -> status register writable */ 529*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 530*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 5311de51272SIris Chen /* test ability to write SRWD */ 532*975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 533*975d4bafSJamin Lin flash_writeb(test_data, 0, 0); 534*975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 535*975d4bafSJamin Lin r = flash_readb(test_data, 0); 536*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 5371de51272SIris Chen g_assert_cmphex(r & SRWD, ==, 0); 5381de51272SIris Chen 5391de51272SIris Chen /* WP# low and SRWD low -> status register writable */ 540*975d4bafSJamin Lin qtest_set_irq_in(test_data->s, 5411de51272SIris Chen "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 0); 542*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 543*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 5441de51272SIris Chen /* test ability to write SRWD */ 545*975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 546*975d4bafSJamin Lin flash_writeb(test_data, 0, SRWD); 547*975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 548*975d4bafSJamin Lin r = flash_readb(test_data, 0); 549*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 5501de51272SIris Chen g_assert_cmphex(r & SRWD, ==, SRWD); 5511de51272SIris Chen 5521de51272SIris Chen /* WP# low and SRWD high -> status register NOT writable */ 553*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 554*975d4bafSJamin Lin flash_writeb(test_data, 0 , WREN); 5551de51272SIris Chen /* test ability to write SRWD */ 556*975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 557*975d4bafSJamin Lin flash_writeb(test_data, 0, 0); 558*975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 559*975d4bafSJamin Lin r = flash_readb(test_data, 0); 560*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 5611de51272SIris Chen /* write is not successful */ 5621de51272SIris Chen g_assert_cmphex(r & SRWD, ==, SRWD); 5631de51272SIris Chen 564*975d4bafSJamin Lin qtest_set_irq_in(test_data->s, 5651de51272SIris Chen "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 1); 566*975d4bafSJamin Lin flash_reset(test_data); 5671de51272SIris Chen } 5681de51272SIris Chen 569*975d4bafSJamin Lin static void test_write_block_protect(const void *data) 5708abf9ba4SIris Chen { 571*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 5728abf9ba4SIris Chen uint32_t sector_size = 65536; 5738abf9ba4SIris Chen uint32_t n_sectors = 512; 5748abf9ba4SIris Chen 575*975d4bafSJamin Lin spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0); 576*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 5778abf9ba4SIris Chen 5788abf9ba4SIris Chen uint32_t bp_bits = 0b0; 5798abf9ba4SIris Chen 5808abf9ba4SIris Chen for (int i = 0; i < 16; i++) { 5818abf9ba4SIris Chen bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2); 5828abf9ba4SIris Chen 583*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 584*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 585*975d4bafSJamin Lin flash_writeb(test_data, 0, BULK_ERASE); 586*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 587*975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 588*975d4bafSJamin Lin flash_writeb(test_data, 0, bp_bits); 589*975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 590*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 591*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 5928abf9ba4SIris Chen 5938abf9ba4SIris Chen uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0; 5948abf9ba4SIris Chen uint32_t protection_start = n_sectors - num_protected_sectors; 5958abf9ba4SIris Chen uint32_t protection_end = n_sectors; 5968abf9ba4SIris Chen 5978abf9ba4SIris Chen for (int sector = 0; sector < n_sectors; sector++) { 5988abf9ba4SIris Chen uint32_t addr = sector * sector_size; 5998abf9ba4SIris Chen 600*975d4bafSJamin Lin assert_page_mem(test_data, addr, 0xffffffff); 601*975d4bafSJamin Lin write_page_mem(test_data, addr, make_be32(0xabcdef12)); 6028abf9ba4SIris Chen 6038abf9ba4SIris Chen uint32_t expected_value = protection_start <= sector 6048abf9ba4SIris Chen && sector < protection_end 6058abf9ba4SIris Chen ? 0xffffffff : 0xabcdef12; 6068abf9ba4SIris Chen 607*975d4bafSJamin Lin assert_page_mem(test_data, addr, expected_value); 6088abf9ba4SIris Chen } 6098abf9ba4SIris Chen } 6108abf9ba4SIris Chen 611*975d4bafSJamin Lin flash_reset(test_data); 6128abf9ba4SIris Chen } 6138abf9ba4SIris Chen 614*975d4bafSJamin Lin static void test_write_block_protect_bottom_bit(const void *data) 6158abf9ba4SIris Chen { 616*975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 6178abf9ba4SIris Chen uint32_t sector_size = 65536; 6188abf9ba4SIris Chen uint32_t n_sectors = 512; 6198abf9ba4SIris Chen 620*975d4bafSJamin Lin spi_ce_ctrl(test_data, 1 << CRTL_EXTENDED0); 621*975d4bafSJamin Lin spi_conf(test_data, CONF_ENABLE_W0); 6228abf9ba4SIris Chen 6238abf9ba4SIris Chen /* top bottom bit is enabled */ 6248abf9ba4SIris Chen uint32_t bp_bits = 0b00100 << 3; 6258abf9ba4SIris Chen 6268abf9ba4SIris Chen for (int i = 0; i < 16; i++) { 6278abf9ba4SIris Chen bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2); 6288abf9ba4SIris Chen 629*975d4bafSJamin Lin spi_ctrl_start_user(test_data); 630*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 631*975d4bafSJamin Lin flash_writeb(test_data, 0, BULK_ERASE); 632*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 633*975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 634*975d4bafSJamin Lin flash_writeb(test_data, 0, bp_bits); 635*975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 636*975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 637*975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 6388abf9ba4SIris Chen 6398abf9ba4SIris Chen uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0; 6408abf9ba4SIris Chen uint32_t protection_start = 0; 6418abf9ba4SIris Chen uint32_t protection_end = num_protected_sectors; 6428abf9ba4SIris Chen 6438abf9ba4SIris Chen for (int sector = 0; sector < n_sectors; sector++) { 6448abf9ba4SIris Chen uint32_t addr = sector * sector_size; 6458abf9ba4SIris Chen 646*975d4bafSJamin Lin assert_page_mem(test_data, addr, 0xffffffff); 647*975d4bafSJamin Lin write_page_mem(test_data, addr, make_be32(0xabcdef12)); 6488abf9ba4SIris Chen 6498abf9ba4SIris Chen uint32_t expected_value = protection_start <= sector 6508abf9ba4SIris Chen && sector < protection_end 6518abf9ba4SIris Chen ? 0xffffffff : 0xabcdef12; 6528abf9ba4SIris Chen 653*975d4bafSJamin Lin assert_page_mem(test_data, addr, expected_value); 6548abf9ba4SIris Chen } 6558abf9ba4SIris Chen } 6568abf9ba4SIris Chen 657*975d4bafSJamin Lin flash_reset(test_data); 6588abf9ba4SIris Chen } 6598abf9ba4SIris Chen 660*975d4bafSJamin Lin static void test_palmetto_bmc(TestData *data) 6617a2334f7SCédric Le Goater { 6627a2334f7SCédric Le Goater int ret; 6637a2334f7SCédric Le Goater int fd; 6647a2334f7SCédric Le Goater 665*975d4bafSJamin Lin fd = g_file_open_tmp("qtest.m25p80.n25q256a.XXXXXX", &data->tmp_path, NULL); 6667a2334f7SCédric Le Goater g_assert(fd >= 0); 667*975d4bafSJamin Lin ret = ftruncate(fd, 32 * 1024 * 1024); 6687a2334f7SCédric Le Goater g_assert(ret == 0); 6697a2334f7SCédric Le Goater close(fd); 6707a2334f7SCédric Le Goater 671*975d4bafSJamin Lin data->s = qtest_initf("-m 256 -machine palmetto-bmc " 6727a2334f7SCédric Le Goater "-drive file=%s,format=raw,if=mtd", 673*975d4bafSJamin Lin data->tmp_path); 6747a2334f7SCédric Le Goater 675*975d4bafSJamin Lin /* fmc cs0 with n25q256a flash */ 676*975d4bafSJamin Lin data->flash_base = 0x20000000; 677*975d4bafSJamin Lin data->spi_base = 0x1E620000; 678*975d4bafSJamin Lin data->jedec_id = 0x20ba19; 6797a2334f7SCédric Le Goater 680*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/read_jedec", data, test_read_jedec); 681*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/erase_sector", data, test_erase_sector); 682*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/erase_all", data, test_erase_all); 683*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/write_page", data, test_write_page); 684*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/read_page_mem", 685*975d4bafSJamin Lin data, test_read_page_mem); 686*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/write_page_mem", 687*975d4bafSJamin Lin data, test_write_page_mem); 688*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/read_status_reg", 689*975d4bafSJamin Lin data, test_read_status_reg); 690*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/status_reg_write_protection", 691*975d4bafSJamin Lin data, test_status_reg_write_protection); 692*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/write_block_protect", 693*975d4bafSJamin Lin data, test_write_block_protect); 694*975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/write_block_protect_bottom_bit", 695*975d4bafSJamin Lin data, test_write_block_protect_bottom_bit); 696755e984aSJamin Lin } 697755e984aSJamin Lin 698755e984aSJamin Lin int main(int argc, char **argv) 699755e984aSJamin Lin { 700*975d4bafSJamin Lin TestData palmetto_data; 701755e984aSJamin Lin int ret; 702755e984aSJamin Lin 703755e984aSJamin Lin g_test_init(&argc, &argv, NULL); 704755e984aSJamin Lin 705*975d4bafSJamin Lin test_palmetto_bmc(&palmetto_data); 706*975d4bafSJamin Lin ret = g_test_run(); 707*975d4bafSJamin Lin 708*975d4bafSJamin Lin qtest_quit(palmetto_data.s); 709*975d4bafSJamin Lin unlink(palmetto_data.tmp_path); 7107a2334f7SCédric Le Goater return ret; 7117a2334f7SCédric Le Goater } 712