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 35dc32f5baSJamin Lin #define CONF_ENABLE_W0 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 39*08479f0cSJamin Lin #define CTRL_IO_QUAD_IO BIT(31) 40dc32f5baSJamin Lin #define CTRL_CE_STOP_ACTIVE BIT(2) 41371a3dd2SCédric Le Goater #define CTRL_READMODE 0x0 42371a3dd2SCédric Le Goater #define CTRL_FREADMODE 0x1 43371a3dd2SCédric Le Goater #define CTRL_WRITEMODE 0x2 447a2334f7SCédric Le Goater #define CTRL_USERMODE 0x3 45188052a1SIris Chen #define SR_WEL BIT(1) 467a2334f7SCédric Le Goater 477a2334f7SCédric Le Goater /* 487a2334f7SCédric Le Goater * Flash commands 497a2334f7SCédric Le Goater */ 507a2334f7SCédric Le Goater enum { 517a2334f7SCédric Le Goater JEDEC_READ = 0x9f, 52188052a1SIris Chen RDSR = 0x5, 53188052a1SIris Chen WRDI = 0x4, 547a2334f7SCédric Le Goater BULK_ERASE = 0xc7, 557a2334f7SCédric Le Goater READ = 0x03, 567a2334f7SCédric Le Goater PP = 0x02, 571de51272SIris Chen WRSR = 0x1, 587a2334f7SCédric Le Goater WREN = 0x6, 591de51272SIris Chen SRWD = 0x80, 60bd9f5052SCédric Le Goater RESET_ENABLE = 0x66, 61bd9f5052SCédric Le Goater RESET_MEMORY = 0x99, 627a2334f7SCédric Le Goater EN_4BYTE_ADDR = 0xB7, 637a2334f7SCédric Le Goater ERASE_SECTOR = 0xd8, 647a2334f7SCédric Le Goater }; 657a2334f7SCédric Le Goater 66*08479f0cSJamin Lin #define CTRL_IO_MODE_MASK (BIT(31) | BIT(30) | BIT(29) | BIT(28)) 67d2c4f384SJiaxun Yang #define FLASH_PAGE_SIZE 256 687a2334f7SCédric Le Goater 69975d4bafSJamin Lin typedef struct TestData { 70975d4bafSJamin Lin QTestState *s; 71975d4bafSJamin Lin uint64_t spi_base; 72975d4bafSJamin Lin uint64_t flash_base; 73975d4bafSJamin Lin uint32_t jedec_id; 74975d4bafSJamin Lin char *tmp_path; 75dc32f5baSJamin Lin uint8_t cs; 76dc32f5baSJamin Lin const char *node; 77369a47aeSJamin Lin uint32_t page_addr; 78975d4bafSJamin Lin } TestData; 79975d4bafSJamin Lin 807a2334f7SCédric Le Goater /* 817a2334f7SCédric Le Goater * Use an explicit bswap for the values read/wrote to the flash region 827a2334f7SCédric Le Goater * as they are BE and the Aspeed CPU is LE. 837a2334f7SCédric Le Goater */ 847a2334f7SCédric Le Goater static inline uint32_t make_be32(uint32_t data) 857a2334f7SCédric Le Goater { 867a2334f7SCédric Le Goater return bswap32(data); 877a2334f7SCédric Le Goater } 887a2334f7SCédric Le Goater 89975d4bafSJamin Lin static inline void spi_writel(const TestData *data, uint64_t offset, 90975d4bafSJamin Lin uint32_t value) 917a2334f7SCédric Le Goater { 92975d4bafSJamin Lin qtest_writel(data->s, data->spi_base + offset, value); 937a2334f7SCédric Le Goater } 947a2334f7SCédric Le Goater 95975d4bafSJamin Lin static inline uint32_t spi_readl(const TestData *data, uint64_t offset) 96bd9f5052SCédric Le Goater { 97975d4bafSJamin Lin return qtest_readl(data->s, data->spi_base + offset); 98975d4bafSJamin Lin } 99975d4bafSJamin Lin 100975d4bafSJamin Lin static inline void flash_writeb(const TestData *data, uint64_t offset, 101975d4bafSJamin Lin uint8_t value) 102975d4bafSJamin Lin { 103975d4bafSJamin Lin qtest_writeb(data->s, data->flash_base + offset, value); 104975d4bafSJamin Lin } 105975d4bafSJamin Lin 106975d4bafSJamin Lin static inline void flash_writel(const TestData *data, uint64_t offset, 107975d4bafSJamin Lin uint32_t value) 108975d4bafSJamin Lin { 109975d4bafSJamin Lin qtest_writel(data->s, data->flash_base + offset, value); 110975d4bafSJamin Lin } 111975d4bafSJamin Lin 112975d4bafSJamin Lin static inline uint8_t flash_readb(const TestData *data, uint64_t offset) 113975d4bafSJamin Lin { 114975d4bafSJamin Lin return qtest_readb(data->s, data->flash_base + offset); 115975d4bafSJamin Lin } 116975d4bafSJamin Lin 117975d4bafSJamin Lin static inline uint32_t flash_readl(const TestData *data, uint64_t offset) 118975d4bafSJamin Lin { 119975d4bafSJamin Lin return qtest_readl(data->s, data->flash_base + offset); 120975d4bafSJamin Lin } 121975d4bafSJamin Lin 122975d4bafSJamin Lin static void spi_conf(const TestData *data, uint32_t value) 123975d4bafSJamin Lin { 124975d4bafSJamin Lin uint32_t conf = spi_readl(data, R_CONF); 125975d4bafSJamin Lin 126975d4bafSJamin Lin conf |= value; 127975d4bafSJamin Lin spi_writel(data, R_CONF, conf); 128975d4bafSJamin Lin } 129975d4bafSJamin Lin 130975d4bafSJamin Lin static void spi_conf_remove(const TestData *data, uint32_t value) 131975d4bafSJamin Lin { 132975d4bafSJamin Lin uint32_t conf = spi_readl(data, R_CONF); 133bd9f5052SCédric Le Goater 134bd9f5052SCédric Le Goater conf &= ~value; 135975d4bafSJamin Lin spi_writel(data, R_CONF, conf); 136bd9f5052SCédric Le Goater } 137bd9f5052SCédric Le Goater 138975d4bafSJamin Lin static void spi_ce_ctrl(const TestData *data, uint32_t value) 139371a3dd2SCédric Le Goater { 140975d4bafSJamin Lin uint32_t conf = spi_readl(data, R_CE_CTRL); 141371a3dd2SCédric Le Goater 142371a3dd2SCédric Le Goater conf |= value; 143975d4bafSJamin Lin spi_writel(data, R_CE_CTRL, conf); 144371a3dd2SCédric Le Goater } 145371a3dd2SCédric Le Goater 146975d4bafSJamin Lin static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t cmd) 147371a3dd2SCédric Le Goater { 148dc32f5baSJamin Lin uint32_t ctrl_reg = R_CTRL0 + data->cs * 4; 149dc32f5baSJamin Lin uint32_t ctrl = spi_readl(data, ctrl_reg); 150371a3dd2SCédric Le Goater ctrl &= ~(CTRL_USERMODE | 0xff << 16); 151371a3dd2SCédric Le Goater ctrl |= mode | (cmd << 16); 152dc32f5baSJamin Lin spi_writel(data, ctrl_reg, ctrl); 153371a3dd2SCédric Le Goater } 154371a3dd2SCédric Le Goater 155975d4bafSJamin Lin static void spi_ctrl_start_user(const TestData *data) 1567a2334f7SCédric Le Goater { 157dc32f5baSJamin Lin uint32_t ctrl_reg = R_CTRL0 + data->cs * 4; 158dc32f5baSJamin Lin uint32_t ctrl = spi_readl(data, ctrl_reg); 1597a2334f7SCédric Le Goater 1607a2334f7SCédric Le Goater ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; 161dc32f5baSJamin Lin spi_writel(data, ctrl_reg, ctrl); 1627a2334f7SCédric Le Goater 1637a2334f7SCédric Le Goater ctrl &= ~CTRL_CE_STOP_ACTIVE; 164dc32f5baSJamin Lin spi_writel(data, ctrl_reg, ctrl); 1657a2334f7SCédric Le Goater } 1667a2334f7SCédric Le Goater 167975d4bafSJamin Lin static void spi_ctrl_stop_user(const TestData *data) 1687a2334f7SCédric Le Goater { 169dc32f5baSJamin Lin uint32_t ctrl_reg = R_CTRL0 + data->cs * 4; 170dc32f5baSJamin Lin uint32_t ctrl = spi_readl(data, ctrl_reg); 1717a2334f7SCédric Le Goater 1727a2334f7SCédric Le Goater ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; 173dc32f5baSJamin Lin spi_writel(data, ctrl_reg, ctrl); 1747a2334f7SCédric Le Goater } 1757a2334f7SCédric Le Goater 176*08479f0cSJamin Lin static void spi_ctrl_set_io_mode(const TestData *data, uint32_t value) 177*08479f0cSJamin Lin { 178*08479f0cSJamin Lin uint32_t ctrl_reg = R_CTRL0 + data->cs * 4; 179*08479f0cSJamin Lin uint32_t ctrl = spi_readl(data, ctrl_reg); 180*08479f0cSJamin Lin uint32_t mode; 181*08479f0cSJamin Lin 182*08479f0cSJamin Lin mode = value & CTRL_IO_MODE_MASK; 183*08479f0cSJamin Lin ctrl &= ~CTRL_IO_MODE_MASK; 184*08479f0cSJamin Lin ctrl |= mode; 185*08479f0cSJamin Lin spi_writel(data, ctrl_reg, ctrl); 186*08479f0cSJamin Lin } 187*08479f0cSJamin Lin 188975d4bafSJamin Lin static void flash_reset(const TestData *data) 189bd9f5052SCédric Le Goater { 190dc32f5baSJamin Lin spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs)); 191bd9f5052SCédric Le Goater 192975d4bafSJamin Lin spi_ctrl_start_user(data); 193975d4bafSJamin Lin flash_writeb(data, 0, RESET_ENABLE); 194975d4bafSJamin Lin flash_writeb(data, 0, RESET_MEMORY); 195975d4bafSJamin Lin flash_writeb(data, 0, WREN); 196975d4bafSJamin Lin flash_writeb(data, 0, BULK_ERASE); 197975d4bafSJamin Lin flash_writeb(data, 0, WRDI); 198975d4bafSJamin Lin spi_ctrl_stop_user(data); 199bd9f5052SCédric Le Goater 200dc32f5baSJamin Lin spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs)); 201bd9f5052SCédric Le Goater } 202bd9f5052SCédric Le Goater 203975d4bafSJamin Lin static void test_read_jedec(const void *data) 2047a2334f7SCédric Le Goater { 205975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 2067a2334f7SCédric Le Goater uint32_t jedec = 0x0; 2077a2334f7SCédric Le Goater 208dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 2097a2334f7SCédric Le Goater 210975d4bafSJamin Lin spi_ctrl_start_user(test_data); 211975d4bafSJamin Lin flash_writeb(test_data, 0, JEDEC_READ); 212975d4bafSJamin Lin jedec |= flash_readb(test_data, 0) << 16; 213975d4bafSJamin Lin jedec |= flash_readb(test_data, 0) << 8; 214975d4bafSJamin Lin jedec |= flash_readb(test_data, 0); 215975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 2167a2334f7SCédric Le Goater 217975d4bafSJamin Lin flash_reset(test_data); 218bd9f5052SCédric Le Goater 219975d4bafSJamin Lin g_assert_cmphex(jedec, ==, test_data->jedec_id); 2207a2334f7SCédric Le Goater } 2217a2334f7SCédric Le Goater 222975d4bafSJamin Lin static void read_page(const TestData *data, uint32_t addr, uint32_t *page) 2237a2334f7SCédric Le Goater { 2247a2334f7SCédric Le Goater int i; 2257a2334f7SCédric Le Goater 226975d4bafSJamin Lin spi_ctrl_start_user(data); 2277a2334f7SCédric Le Goater 228975d4bafSJamin Lin flash_writeb(data, 0, EN_4BYTE_ADDR); 229975d4bafSJamin Lin flash_writeb(data, 0, READ); 230975d4bafSJamin Lin flash_writel(data, 0, make_be32(addr)); 2317a2334f7SCédric Le Goater 2327a2334f7SCédric Le Goater /* Continuous read are supported */ 233d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 234975d4bafSJamin Lin page[i] = make_be32(flash_readl(data, 0)); 2357a2334f7SCédric Le Goater } 236975d4bafSJamin Lin spi_ctrl_stop_user(data); 2377a2334f7SCédric Le Goater } 2387a2334f7SCédric Le Goater 239975d4bafSJamin Lin static void read_page_mem(const TestData *data, uint32_t addr, uint32_t *page) 240371a3dd2SCédric Le Goater { 241371a3dd2SCédric Le Goater int i; 242371a3dd2SCédric Le Goater 243371a3dd2SCédric Le Goater /* move out USER mode to use direct reads from the AHB bus */ 244975d4bafSJamin Lin spi_ctrl_setmode(data, CTRL_READMODE, READ); 245371a3dd2SCédric Le Goater 246d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 247975d4bafSJamin Lin page[i] = make_be32(flash_readl(data, addr + i * 4)); 248371a3dd2SCédric Le Goater } 249371a3dd2SCédric Le Goater } 250371a3dd2SCédric Le Goater 251975d4bafSJamin Lin static void write_page_mem(const TestData *data, uint32_t addr, 252975d4bafSJamin Lin uint32_t write_value) 2538abf9ba4SIris Chen { 254975d4bafSJamin Lin spi_ctrl_setmode(data, CTRL_WRITEMODE, PP); 2558abf9ba4SIris Chen 2568abf9ba4SIris Chen for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 257975d4bafSJamin Lin flash_writel(data, addr + i * 4, write_value); 2588abf9ba4SIris Chen } 2598abf9ba4SIris Chen } 2608abf9ba4SIris Chen 261975d4bafSJamin Lin static void assert_page_mem(const TestData *data, uint32_t addr, 262975d4bafSJamin Lin uint32_t expected_value) 2638abf9ba4SIris Chen { 2648abf9ba4SIris Chen uint32_t page[FLASH_PAGE_SIZE / 4]; 265975d4bafSJamin Lin read_page_mem(data, addr, page); 2668abf9ba4SIris Chen for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 2678abf9ba4SIris Chen g_assert_cmphex(page[i], ==, expected_value); 2688abf9ba4SIris Chen } 2698abf9ba4SIris Chen } 2708abf9ba4SIris Chen 271975d4bafSJamin Lin static void test_erase_sector(const void *data) 2727a2334f7SCédric Le Goater { 273975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 274369a47aeSJamin Lin uint32_t some_page_addr = test_data->page_addr; 275d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 2767a2334f7SCédric Le Goater int i; 2777a2334f7SCédric Le Goater 278dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 2797a2334f7SCédric Le Goater 28092a45bdeSIris Chen /* 28192a45bdeSIris Chen * Previous page should be full of 0xffs after backend is 28292a45bdeSIris Chen * initialized 28392a45bdeSIris Chen */ 284975d4bafSJamin Lin read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page); 28592a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 28692a45bdeSIris Chen g_assert_cmphex(page[i], ==, 0xffffffff); 28792a45bdeSIris Chen } 28892a45bdeSIris Chen 289975d4bafSJamin Lin spi_ctrl_start_user(test_data); 290975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 291975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 292975d4bafSJamin Lin flash_writeb(test_data, 0, PP); 293975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr)); 29492a45bdeSIris Chen 29592a45bdeSIris Chen /* Fill the page with its own addresses */ 29692a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 297975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr + i * 4)); 29892a45bdeSIris Chen } 299975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 30092a45bdeSIris Chen 30192a45bdeSIris Chen /* Check the page is correctly written */ 302975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 30392a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 30492a45bdeSIris Chen g_assert_cmphex(page[i], ==, some_page_addr + i * 4); 30592a45bdeSIris Chen } 30692a45bdeSIris Chen 307975d4bafSJamin Lin spi_ctrl_start_user(test_data); 308975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 309975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 310975d4bafSJamin Lin flash_writeb(test_data, 0, ERASE_SECTOR); 311975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr)); 312975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 3137a2334f7SCédric Le Goater 31492a45bdeSIris Chen /* Check the page is erased */ 315975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 316d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 3177a2334f7SCédric Le Goater g_assert_cmphex(page[i], ==, 0xffffffff); 3187a2334f7SCédric Le Goater } 319bd9f5052SCédric Le Goater 320975d4bafSJamin Lin flash_reset(test_data); 3217a2334f7SCédric Le Goater } 3227a2334f7SCédric Le Goater 323975d4bafSJamin Lin static void test_erase_all(const void *data) 3247a2334f7SCédric Le Goater { 325975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 326369a47aeSJamin Lin uint32_t some_page_addr = test_data->page_addr; 327d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 3287a2334f7SCédric Le Goater int i; 3297a2334f7SCédric Le Goater 330dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 3317a2334f7SCédric Le Goater 33292a45bdeSIris Chen /* 33392a45bdeSIris Chen * Previous page should be full of 0xffs after backend is 33492a45bdeSIris Chen * initialized 33592a45bdeSIris Chen */ 336975d4bafSJamin Lin read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page); 33792a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 33892a45bdeSIris Chen g_assert_cmphex(page[i], ==, 0xffffffff); 33992a45bdeSIris Chen } 34092a45bdeSIris Chen 341975d4bafSJamin Lin spi_ctrl_start_user(test_data); 342975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 343975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 344975d4bafSJamin Lin flash_writeb(test_data, 0, PP); 345975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr)); 34692a45bdeSIris Chen 34792a45bdeSIris Chen /* Fill the page with its own addresses */ 34892a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 349975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(some_page_addr + i * 4)); 35092a45bdeSIris Chen } 351975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 35292a45bdeSIris Chen 35392a45bdeSIris Chen /* Check the page is correctly written */ 354975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 355d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 35692a45bdeSIris Chen g_assert_cmphex(page[i], ==, some_page_addr + i * 4); 3577a2334f7SCédric Le Goater } 3587a2334f7SCédric Le Goater 359975d4bafSJamin Lin spi_ctrl_start_user(test_data); 360975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 361975d4bafSJamin Lin flash_writeb(test_data, 0, BULK_ERASE); 362975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 3637a2334f7SCédric Le Goater 36492a45bdeSIris Chen /* Check the page is erased */ 365975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 366d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 3677a2334f7SCédric Le Goater g_assert_cmphex(page[i], ==, 0xffffffff); 3687a2334f7SCédric Le Goater } 369bd9f5052SCédric Le Goater 370975d4bafSJamin Lin flash_reset(test_data); 3717a2334f7SCédric Le Goater } 3727a2334f7SCédric Le Goater 373975d4bafSJamin Lin static void test_write_page(const void *data) 3747a2334f7SCédric Le Goater { 375975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 376369a47aeSJamin Lin uint32_t my_page_addr = test_data->page_addr; 377369a47aeSJamin Lin uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE; 378d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 3797a2334f7SCédric Le Goater int i; 3807a2334f7SCédric Le Goater 381dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 3827a2334f7SCédric Le Goater 383975d4bafSJamin Lin spi_ctrl_start_user(test_data); 384975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 385975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 386975d4bafSJamin Lin flash_writeb(test_data, 0, PP); 387975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr)); 3887a2334f7SCédric Le Goater 3897a2334f7SCédric Le Goater /* Fill the page with its own addresses */ 390d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 391975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr + i * 4)); 3927a2334f7SCédric Le Goater } 393975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 3947a2334f7SCédric Le Goater 3957a2334f7SCédric Le Goater /* Check what was written */ 396975d4bafSJamin Lin read_page(test_data, my_page_addr, page); 397d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 3987a2334f7SCédric Le Goater g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 3997a2334f7SCédric Le Goater } 4007a2334f7SCédric Le Goater 4017a2334f7SCédric Le Goater /* Check some other page. It should be full of 0xff */ 402975d4bafSJamin Lin read_page(test_data, some_page_addr, page); 403d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 4047a2334f7SCédric Le Goater g_assert_cmphex(page[i], ==, 0xffffffff); 4057a2334f7SCédric Le Goater } 406bd9f5052SCédric Le Goater 407975d4bafSJamin Lin flash_reset(test_data); 4087a2334f7SCédric Le Goater } 4097a2334f7SCédric Le Goater 410975d4bafSJamin Lin static void test_read_page_mem(const void *data) 411371a3dd2SCédric Le Goater { 412975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 413369a47aeSJamin Lin uint32_t my_page_addr = test_data->page_addr; 414369a47aeSJamin Lin uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE; 415d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 416371a3dd2SCédric Le Goater int i; 417371a3dd2SCédric Le Goater 4181df52a9aSJamin Lin /* 419dc32f5baSJamin Lin * Enable 4BYTE mode for controller. 420371a3dd2SCédric Le Goater */ 421dc32f5baSJamin Lin spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs)); 422371a3dd2SCédric Le Goater 423371a3dd2SCédric Le Goater /* Enable 4BYTE mode for flash. */ 424dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 425975d4bafSJamin Lin spi_ctrl_start_user(test_data); 426975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 427975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 428975d4bafSJamin Lin flash_writeb(test_data, 0, PP); 429975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr)); 43092a45bdeSIris Chen 43192a45bdeSIris Chen /* Fill the page with its own addresses */ 43292a45bdeSIris Chen for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 433975d4bafSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr + i * 4)); 43492a45bdeSIris Chen } 435975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 436dc32f5baSJamin Lin spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 437371a3dd2SCédric Le Goater 438371a3dd2SCédric Le Goater /* Check what was written */ 439975d4bafSJamin Lin read_page_mem(test_data, my_page_addr, page); 440d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 441371a3dd2SCédric Le Goater g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 442371a3dd2SCédric Le Goater } 443371a3dd2SCédric Le Goater 444371a3dd2SCédric Le Goater /* Check some other page. It should be full of 0xff */ 445975d4bafSJamin Lin read_page_mem(test_data, some_page_addr, page); 446d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 447371a3dd2SCédric Le Goater g_assert_cmphex(page[i], ==, 0xffffffff); 448371a3dd2SCédric Le Goater } 449371a3dd2SCédric Le Goater 450975d4bafSJamin Lin flash_reset(test_data); 451371a3dd2SCédric Le Goater } 452371a3dd2SCédric Le Goater 453975d4bafSJamin Lin static void test_write_page_mem(const void *data) 454371a3dd2SCédric Le Goater { 455975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 456369a47aeSJamin Lin uint32_t my_page_addr = test_data->page_addr; 457d2c4f384SJiaxun Yang uint32_t page[FLASH_PAGE_SIZE / 4]; 458371a3dd2SCédric Le Goater int i; 459371a3dd2SCédric Le Goater 4601df52a9aSJamin Lin /* 461dc32f5baSJamin Lin * Enable 4BYTE mode for controller. 462371a3dd2SCédric Le Goater */ 463dc32f5baSJamin Lin spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs)); 464371a3dd2SCédric Le Goater 465371a3dd2SCédric Le Goater /* Enable 4BYTE mode for flash. */ 466dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 467975d4bafSJamin Lin spi_ctrl_start_user(test_data); 468975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 469975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 470975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 471371a3dd2SCédric Le Goater 472371a3dd2SCédric Le Goater /* move out USER mode to use direct writes to the AHB bus */ 473975d4bafSJamin Lin spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP); 474371a3dd2SCédric Le Goater 475d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 476975d4bafSJamin Lin flash_writel(test_data, my_page_addr + i * 4, 477371a3dd2SCédric Le Goater make_be32(my_page_addr + i * 4)); 478371a3dd2SCédric Le Goater } 479371a3dd2SCédric Le Goater 480371a3dd2SCédric Le Goater /* Check what was written */ 481975d4bafSJamin Lin read_page_mem(test_data, my_page_addr, page); 482d2c4f384SJiaxun Yang for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 483371a3dd2SCédric Le Goater g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 484371a3dd2SCédric Le Goater } 485371a3dd2SCédric Le Goater 486975d4bafSJamin Lin flash_reset(test_data); 487371a3dd2SCédric Le Goater } 488371a3dd2SCédric Le Goater 489975d4bafSJamin Lin static void test_read_status_reg(const void *data) 490188052a1SIris Chen { 491975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 492188052a1SIris Chen uint8_t r; 493188052a1SIris Chen 494dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 495188052a1SIris Chen 496975d4bafSJamin Lin spi_ctrl_start_user(test_data); 497975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 498975d4bafSJamin Lin r = flash_readb(test_data, 0); 499975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 500188052a1SIris Chen 501188052a1SIris Chen g_assert_cmphex(r & SR_WEL, ==, 0); 502188052a1SIris Chen g_assert(!qtest_qom_get_bool 503dc32f5baSJamin Lin (test_data->s, test_data->node, "write-enable")); 504188052a1SIris Chen 505975d4bafSJamin Lin spi_ctrl_start_user(test_data); 506975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 507975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 508975d4bafSJamin Lin r = flash_readb(test_data, 0); 509975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 510188052a1SIris Chen 511188052a1SIris Chen g_assert_cmphex(r & SR_WEL, ==, SR_WEL); 512188052a1SIris Chen g_assert(qtest_qom_get_bool 513dc32f5baSJamin Lin (test_data->s, test_data->node, "write-enable")); 514188052a1SIris Chen 515975d4bafSJamin Lin spi_ctrl_start_user(test_data); 516975d4bafSJamin Lin flash_writeb(test_data, 0, WRDI); 517975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 518975d4bafSJamin Lin r = flash_readb(test_data, 0); 519975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 520188052a1SIris Chen 521188052a1SIris Chen g_assert_cmphex(r & SR_WEL, ==, 0); 522188052a1SIris Chen g_assert(!qtest_qom_get_bool 523dc32f5baSJamin Lin (test_data->s, test_data->node, "write-enable")); 524188052a1SIris Chen 525975d4bafSJamin Lin flash_reset(test_data); 526188052a1SIris Chen } 527188052a1SIris Chen 528975d4bafSJamin Lin static void test_status_reg_write_protection(const void *data) 5291de51272SIris Chen { 530975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 5311de51272SIris Chen uint8_t r; 5321de51272SIris Chen 533dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 5341de51272SIris Chen 5351de51272SIris Chen /* default case: WP# is high and SRWD is low -> status register writable */ 536975d4bafSJamin Lin spi_ctrl_start_user(test_data); 537975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 5381de51272SIris Chen /* test ability to write SRWD */ 539975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 540975d4bafSJamin Lin flash_writeb(test_data, 0, SRWD); 541975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 542975d4bafSJamin Lin r = flash_readb(test_data, 0); 543975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 5441de51272SIris Chen g_assert_cmphex(r & SRWD, ==, SRWD); 5451de51272SIris Chen 5461de51272SIris Chen /* WP# high and SRWD high -> status register writable */ 547975d4bafSJamin Lin spi_ctrl_start_user(test_data); 548975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 5491de51272SIris Chen /* test ability to write SRWD */ 550975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 551975d4bafSJamin Lin flash_writeb(test_data, 0, 0); 552975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 553975d4bafSJamin Lin r = flash_readb(test_data, 0); 554975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 5551de51272SIris Chen g_assert_cmphex(r & SRWD, ==, 0); 5561de51272SIris Chen 5571de51272SIris Chen /* WP# low and SRWD low -> status register writable */ 558dc32f5baSJamin Lin qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0); 559975d4bafSJamin Lin spi_ctrl_start_user(test_data); 560975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 5611de51272SIris Chen /* test ability to write SRWD */ 562975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 563975d4bafSJamin Lin flash_writeb(test_data, 0, SRWD); 564975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 565975d4bafSJamin Lin r = flash_readb(test_data, 0); 566975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 5671de51272SIris Chen g_assert_cmphex(r & SRWD, ==, SRWD); 5681de51272SIris Chen 5691de51272SIris Chen /* WP# low and SRWD high -> status register NOT writable */ 570975d4bafSJamin Lin spi_ctrl_start_user(test_data); 571975d4bafSJamin Lin flash_writeb(test_data, 0 , WREN); 5721de51272SIris Chen /* test ability to write SRWD */ 573975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 574975d4bafSJamin Lin flash_writeb(test_data, 0, 0); 575975d4bafSJamin Lin flash_writeb(test_data, 0, RDSR); 576975d4bafSJamin Lin r = flash_readb(test_data, 0); 577975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 5781de51272SIris Chen /* write is not successful */ 5791de51272SIris Chen g_assert_cmphex(r & SRWD, ==, SRWD); 5801de51272SIris Chen 581dc32f5baSJamin Lin qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1); 582975d4bafSJamin Lin flash_reset(test_data); 5831de51272SIris Chen } 5841de51272SIris Chen 585975d4bafSJamin Lin static void test_write_block_protect(const void *data) 5868abf9ba4SIris Chen { 587975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 5888abf9ba4SIris Chen uint32_t sector_size = 65536; 5898abf9ba4SIris Chen uint32_t n_sectors = 512; 5908abf9ba4SIris Chen 591dc32f5baSJamin Lin spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs)); 592dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 5938abf9ba4SIris Chen 5948abf9ba4SIris Chen uint32_t bp_bits = 0b0; 5958abf9ba4SIris Chen 5968abf9ba4SIris Chen for (int i = 0; i < 16; i++) { 5978abf9ba4SIris Chen bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2); 5988abf9ba4SIris Chen 599975d4bafSJamin Lin spi_ctrl_start_user(test_data); 600975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 601975d4bafSJamin Lin flash_writeb(test_data, 0, BULK_ERASE); 602975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 603975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 604975d4bafSJamin Lin flash_writeb(test_data, 0, bp_bits); 605975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 606975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 607975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 6088abf9ba4SIris Chen 6098abf9ba4SIris Chen uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0; 6108abf9ba4SIris Chen uint32_t protection_start = n_sectors - num_protected_sectors; 6118abf9ba4SIris Chen uint32_t protection_end = n_sectors; 6128abf9ba4SIris Chen 6138abf9ba4SIris Chen for (int sector = 0; sector < n_sectors; sector++) { 6148abf9ba4SIris Chen uint32_t addr = sector * sector_size; 6158abf9ba4SIris Chen 616975d4bafSJamin Lin assert_page_mem(test_data, addr, 0xffffffff); 617975d4bafSJamin Lin write_page_mem(test_data, addr, make_be32(0xabcdef12)); 6188abf9ba4SIris Chen 6198abf9ba4SIris Chen uint32_t expected_value = protection_start <= sector 6208abf9ba4SIris Chen && sector < protection_end 6218abf9ba4SIris Chen ? 0xffffffff : 0xabcdef12; 6228abf9ba4SIris Chen 623975d4bafSJamin Lin assert_page_mem(test_data, addr, expected_value); 6248abf9ba4SIris Chen } 6258abf9ba4SIris Chen } 6268abf9ba4SIris Chen 627975d4bafSJamin Lin flash_reset(test_data); 6288abf9ba4SIris Chen } 6298abf9ba4SIris Chen 630975d4bafSJamin Lin static void test_write_block_protect_bottom_bit(const void *data) 6318abf9ba4SIris Chen { 632975d4bafSJamin Lin const TestData *test_data = (const TestData *)data; 6338abf9ba4SIris Chen uint32_t sector_size = 65536; 6348abf9ba4SIris Chen uint32_t n_sectors = 512; 6358abf9ba4SIris Chen 636dc32f5baSJamin Lin spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs)); 637dc32f5baSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 6388abf9ba4SIris Chen 6398abf9ba4SIris Chen /* top bottom bit is enabled */ 6408abf9ba4SIris Chen uint32_t bp_bits = 0b00100 << 3; 6418abf9ba4SIris Chen 6428abf9ba4SIris Chen for (int i = 0; i < 16; i++) { 6438abf9ba4SIris Chen bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2); 6448abf9ba4SIris Chen 645975d4bafSJamin Lin spi_ctrl_start_user(test_data); 646975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 647975d4bafSJamin Lin flash_writeb(test_data, 0, BULK_ERASE); 648975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 649975d4bafSJamin Lin flash_writeb(test_data, 0, WRSR); 650975d4bafSJamin Lin flash_writeb(test_data, 0, bp_bits); 651975d4bafSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 652975d4bafSJamin Lin flash_writeb(test_data, 0, WREN); 653975d4bafSJamin Lin spi_ctrl_stop_user(test_data); 6548abf9ba4SIris Chen 6558abf9ba4SIris Chen uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0; 6568abf9ba4SIris Chen uint32_t protection_start = 0; 6578abf9ba4SIris Chen uint32_t protection_end = num_protected_sectors; 6588abf9ba4SIris Chen 6598abf9ba4SIris Chen for (int sector = 0; sector < n_sectors; sector++) { 6608abf9ba4SIris Chen uint32_t addr = sector * sector_size; 6618abf9ba4SIris Chen 662975d4bafSJamin Lin assert_page_mem(test_data, addr, 0xffffffff); 663975d4bafSJamin Lin write_page_mem(test_data, addr, make_be32(0xabcdef12)); 6648abf9ba4SIris Chen 6658abf9ba4SIris Chen uint32_t expected_value = protection_start <= sector 6668abf9ba4SIris Chen && sector < protection_end 6678abf9ba4SIris Chen ? 0xffffffff : 0xabcdef12; 6688abf9ba4SIris Chen 669975d4bafSJamin Lin assert_page_mem(test_data, addr, expected_value); 6708abf9ba4SIris Chen } 6718abf9ba4SIris Chen } 6728abf9ba4SIris Chen 673975d4bafSJamin Lin flash_reset(test_data); 6748abf9ba4SIris Chen } 6758abf9ba4SIris Chen 676*08479f0cSJamin Lin static void test_write_page_qpi(const void *data) 677*08479f0cSJamin Lin { 678*08479f0cSJamin Lin const TestData *test_data = (const TestData *)data; 679*08479f0cSJamin Lin uint32_t my_page_addr = test_data->page_addr; 680*08479f0cSJamin Lin uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE; 681*08479f0cSJamin Lin uint32_t page[FLASH_PAGE_SIZE / 4]; 682*08479f0cSJamin Lin uint32_t page_pattern[] = { 683*08479f0cSJamin Lin 0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf 684*08479f0cSJamin Lin }; 685*08479f0cSJamin Lin int i; 686*08479f0cSJamin Lin 687*08479f0cSJamin Lin spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); 688*08479f0cSJamin Lin 689*08479f0cSJamin Lin spi_ctrl_start_user(test_data); 690*08479f0cSJamin Lin flash_writeb(test_data, 0, EN_4BYTE_ADDR); 691*08479f0cSJamin Lin flash_writeb(test_data, 0, WREN); 692*08479f0cSJamin Lin flash_writeb(test_data, 0, PP); 693*08479f0cSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr)); 694*08479f0cSJamin Lin 695*08479f0cSJamin Lin /* Set QPI mode */ 696*08479f0cSJamin Lin spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO); 697*08479f0cSJamin Lin 698*08479f0cSJamin Lin /* Fill the page pattern */ 699*08479f0cSJamin Lin for (i = 0; i < ARRAY_SIZE(page_pattern); i++) { 700*08479f0cSJamin Lin flash_writel(test_data, 0, make_be32(page_pattern[i])); 701*08479f0cSJamin Lin } 702*08479f0cSJamin Lin 703*08479f0cSJamin Lin /* Fill the page with its own addresses */ 704*08479f0cSJamin Lin for (; i < FLASH_PAGE_SIZE / 4; i++) { 705*08479f0cSJamin Lin flash_writel(test_data, 0, make_be32(my_page_addr + i * 4)); 706*08479f0cSJamin Lin } 707*08479f0cSJamin Lin 708*08479f0cSJamin Lin /* Restore io mode */ 709*08479f0cSJamin Lin spi_ctrl_set_io_mode(test_data, 0); 710*08479f0cSJamin Lin spi_ctrl_stop_user(test_data); 711*08479f0cSJamin Lin 712*08479f0cSJamin Lin /* Check what was written */ 713*08479f0cSJamin Lin read_page(test_data, my_page_addr, page); 714*08479f0cSJamin Lin for (i = 0; i < ARRAY_SIZE(page_pattern); i++) { 715*08479f0cSJamin Lin g_assert_cmphex(page[i], ==, page_pattern[i]); 716*08479f0cSJamin Lin } 717*08479f0cSJamin Lin for (; i < FLASH_PAGE_SIZE / 4; i++) { 718*08479f0cSJamin Lin g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 719*08479f0cSJamin Lin } 720*08479f0cSJamin Lin 721*08479f0cSJamin Lin /* Check some other page. It should be full of 0xff */ 722*08479f0cSJamin Lin read_page(test_data, some_page_addr, page); 723*08479f0cSJamin Lin for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 724*08479f0cSJamin Lin g_assert_cmphex(page[i], ==, 0xffffffff); 725*08479f0cSJamin Lin } 726*08479f0cSJamin Lin 727*08479f0cSJamin Lin flash_reset(test_data); 728*08479f0cSJamin Lin } 729*08479f0cSJamin Lin 730975d4bafSJamin Lin static void test_palmetto_bmc(TestData *data) 7317a2334f7SCédric Le Goater { 7327a2334f7SCédric Le Goater int ret; 7337a2334f7SCédric Le Goater int fd; 7347a2334f7SCédric Le Goater 735975d4bafSJamin Lin fd = g_file_open_tmp("qtest.m25p80.n25q256a.XXXXXX", &data->tmp_path, NULL); 7367a2334f7SCédric Le Goater g_assert(fd >= 0); 737975d4bafSJamin Lin ret = ftruncate(fd, 32 * 1024 * 1024); 7387a2334f7SCédric Le Goater g_assert(ret == 0); 7397a2334f7SCédric Le Goater close(fd); 7407a2334f7SCédric Le Goater 741975d4bafSJamin Lin data->s = qtest_initf("-m 256 -machine palmetto-bmc " 7427a2334f7SCédric Le Goater "-drive file=%s,format=raw,if=mtd", 743975d4bafSJamin Lin data->tmp_path); 7447a2334f7SCédric Le Goater 745975d4bafSJamin Lin /* fmc cs0 with n25q256a flash */ 746975d4bafSJamin Lin data->flash_base = 0x20000000; 747975d4bafSJamin Lin data->spi_base = 0x1E620000; 748975d4bafSJamin Lin data->jedec_id = 0x20ba19; 749dc32f5baSJamin Lin data->cs = 0; 750dc32f5baSJamin Lin data->node = "/machine/soc/fmc/ssi.0/child[0]"; 751369a47aeSJamin Lin /* beyond 16MB */ 752369a47aeSJamin Lin data->page_addr = 0x14000 * FLASH_PAGE_SIZE; 7537a2334f7SCédric Le Goater 754975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/read_jedec", data, test_read_jedec); 755975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/erase_sector", data, test_erase_sector); 756975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/erase_all", data, test_erase_all); 757975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/write_page", data, test_write_page); 758975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/read_page_mem", 759975d4bafSJamin Lin data, test_read_page_mem); 760975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/write_page_mem", 761975d4bafSJamin Lin data, test_write_page_mem); 762975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/read_status_reg", 763975d4bafSJamin Lin data, test_read_status_reg); 764975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/status_reg_write_protection", 765975d4bafSJamin Lin data, test_status_reg_write_protection); 766975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/write_block_protect", 767975d4bafSJamin Lin data, test_write_block_protect); 768975d4bafSJamin Lin qtest_add_data_func("/ast2400/smc/write_block_protect_bottom_bit", 769975d4bafSJamin Lin data, test_write_block_protect_bottom_bit); 770755e984aSJamin Lin } 771755e984aSJamin Lin 772658ebe13SJamin Lin static void test_ast2500_evb(TestData *data) 773658ebe13SJamin Lin { 774658ebe13SJamin Lin int ret; 775658ebe13SJamin Lin int fd; 776658ebe13SJamin Lin 777658ebe13SJamin Lin fd = g_file_open_tmp("qtest.m25p80.mx25l25635e.XXXXXX", 778658ebe13SJamin Lin &data->tmp_path, NULL); 779658ebe13SJamin Lin g_assert(fd >= 0); 780658ebe13SJamin Lin ret = ftruncate(fd, 32 * 1024 * 1024); 781658ebe13SJamin Lin g_assert(ret == 0); 782658ebe13SJamin Lin close(fd); 783658ebe13SJamin Lin 784658ebe13SJamin Lin data->s = qtest_initf("-machine ast2500-evb " 785658ebe13SJamin Lin "-drive file=%s,format=raw,if=mtd", 786658ebe13SJamin Lin data->tmp_path); 787658ebe13SJamin Lin 788658ebe13SJamin Lin /* fmc cs0 with mx25l25635e flash */ 789658ebe13SJamin Lin data->flash_base = 0x20000000; 790658ebe13SJamin Lin data->spi_base = 0x1E620000; 791658ebe13SJamin Lin data->jedec_id = 0xc22019; 792658ebe13SJamin Lin data->cs = 0; 793658ebe13SJamin Lin data->node = "/machine/soc/fmc/ssi.0/child[0]"; 794658ebe13SJamin Lin /* beyond 16MB */ 795658ebe13SJamin Lin data->page_addr = 0x14000 * FLASH_PAGE_SIZE; 796658ebe13SJamin Lin 797658ebe13SJamin Lin qtest_add_data_func("/ast2500/smc/read_jedec", data, test_read_jedec); 798658ebe13SJamin Lin qtest_add_data_func("/ast2500/smc/erase_sector", data, test_erase_sector); 799658ebe13SJamin Lin qtest_add_data_func("/ast2500/smc/erase_all", data, test_erase_all); 800658ebe13SJamin Lin qtest_add_data_func("/ast2500/smc/write_page", data, test_write_page); 801658ebe13SJamin Lin qtest_add_data_func("/ast2500/smc/read_page_mem", 802658ebe13SJamin Lin data, test_read_page_mem); 803658ebe13SJamin Lin qtest_add_data_func("/ast2500/smc/write_page_mem", 804658ebe13SJamin Lin data, test_write_page_mem); 805658ebe13SJamin Lin qtest_add_data_func("/ast2500/smc/read_status_reg", 806658ebe13SJamin Lin data, test_read_status_reg); 807*08479f0cSJamin Lin qtest_add_data_func("/ast2500/smc/write_page_qpi", 808*08479f0cSJamin Lin data, test_write_page_qpi); 809658ebe13SJamin Lin } 81084f7ea6dSJamin Lin 81184f7ea6dSJamin Lin static void test_ast2600_evb(TestData *data) 81284f7ea6dSJamin Lin { 81384f7ea6dSJamin Lin int ret; 81484f7ea6dSJamin Lin int fd; 81584f7ea6dSJamin Lin 81684f7ea6dSJamin Lin fd = g_file_open_tmp("qtest.m25p80.mx66u51235f.XXXXXX", 81784f7ea6dSJamin Lin &data->tmp_path, NULL); 81884f7ea6dSJamin Lin g_assert(fd >= 0); 81984f7ea6dSJamin Lin ret = ftruncate(fd, 64 * 1024 * 1024); 82084f7ea6dSJamin Lin g_assert(ret == 0); 82184f7ea6dSJamin Lin close(fd); 82284f7ea6dSJamin Lin 82384f7ea6dSJamin Lin data->s = qtest_initf("-machine ast2600-evb " 82484f7ea6dSJamin Lin "-drive file=%s,format=raw,if=mtd", 82584f7ea6dSJamin Lin data->tmp_path); 82684f7ea6dSJamin Lin 82784f7ea6dSJamin Lin /* fmc cs0 with mx66u51235f flash */ 82884f7ea6dSJamin Lin data->flash_base = 0x20000000; 82984f7ea6dSJamin Lin data->spi_base = 0x1E620000; 83084f7ea6dSJamin Lin data->jedec_id = 0xc2253a; 83184f7ea6dSJamin Lin data->cs = 0; 83284f7ea6dSJamin Lin data->node = "/machine/soc/fmc/ssi.0/child[0]"; 83384f7ea6dSJamin Lin /* beyond 16MB */ 83484f7ea6dSJamin Lin data->page_addr = 0x14000 * FLASH_PAGE_SIZE; 83584f7ea6dSJamin Lin 83684f7ea6dSJamin Lin qtest_add_data_func("/ast2600/smc/read_jedec", data, test_read_jedec); 83784f7ea6dSJamin Lin qtest_add_data_func("/ast2600/smc/erase_sector", data, test_erase_sector); 83884f7ea6dSJamin Lin qtest_add_data_func("/ast2600/smc/erase_all", data, test_erase_all); 83984f7ea6dSJamin Lin qtest_add_data_func("/ast2600/smc/write_page", data, test_write_page); 84084f7ea6dSJamin Lin qtest_add_data_func("/ast2600/smc/read_page_mem", 84184f7ea6dSJamin Lin data, test_read_page_mem); 84284f7ea6dSJamin Lin qtest_add_data_func("/ast2600/smc/write_page_mem", 84384f7ea6dSJamin Lin data, test_write_page_mem); 84484f7ea6dSJamin Lin qtest_add_data_func("/ast2600/smc/read_status_reg", 84584f7ea6dSJamin Lin data, test_read_status_reg); 846*08479f0cSJamin Lin qtest_add_data_func("/ast2600/smc/write_page_qpi", 847*08479f0cSJamin Lin data, test_write_page_qpi); 84884f7ea6dSJamin Lin } 8490f6e8aa4SJamin Lin 8500f6e8aa4SJamin Lin static void test_ast1030_evb(TestData *data) 8510f6e8aa4SJamin Lin { 8520f6e8aa4SJamin Lin int ret; 8530f6e8aa4SJamin Lin int fd; 8540f6e8aa4SJamin Lin 8550f6e8aa4SJamin Lin fd = g_file_open_tmp("qtest.m25p80.w25q80bl.XXXXXX", 8560f6e8aa4SJamin Lin &data->tmp_path, NULL); 8570f6e8aa4SJamin Lin g_assert(fd >= 0); 8580f6e8aa4SJamin Lin ret = ftruncate(fd, 1 * 1024 * 1024); 8590f6e8aa4SJamin Lin g_assert(ret == 0); 8600f6e8aa4SJamin Lin close(fd); 8610f6e8aa4SJamin Lin 8620f6e8aa4SJamin Lin data->s = qtest_initf("-machine ast1030-evb " 8630f6e8aa4SJamin Lin "-drive file=%s,format=raw,if=mtd", 8640f6e8aa4SJamin Lin data->tmp_path); 8650f6e8aa4SJamin Lin 8660f6e8aa4SJamin Lin /* fmc cs0 with w25q80bl flash */ 8670f6e8aa4SJamin Lin data->flash_base = 0x80000000; 8680f6e8aa4SJamin Lin data->spi_base = 0x7E620000; 8690f6e8aa4SJamin Lin data->jedec_id = 0xef4014; 8700f6e8aa4SJamin Lin data->cs = 0; 8710f6e8aa4SJamin Lin data->node = "/machine/soc/fmc/ssi.0/child[0]"; 8720f6e8aa4SJamin Lin /* beyond 512KB */ 8730f6e8aa4SJamin Lin data->page_addr = 0x800 * FLASH_PAGE_SIZE; 8740f6e8aa4SJamin Lin 8750f6e8aa4SJamin Lin qtest_add_data_func("/ast1030/smc/read_jedec", data, test_read_jedec); 8760f6e8aa4SJamin Lin qtest_add_data_func("/ast1030/smc/erase_sector", data, test_erase_sector); 8770f6e8aa4SJamin Lin qtest_add_data_func("/ast1030/smc/erase_all", data, test_erase_all); 8780f6e8aa4SJamin Lin qtest_add_data_func("/ast1030/smc/write_page", data, test_write_page); 8790f6e8aa4SJamin Lin qtest_add_data_func("/ast1030/smc/read_page_mem", 8800f6e8aa4SJamin Lin data, test_read_page_mem); 8810f6e8aa4SJamin Lin qtest_add_data_func("/ast1030/smc/write_page_mem", 8820f6e8aa4SJamin Lin data, test_write_page_mem); 8830f6e8aa4SJamin Lin qtest_add_data_func("/ast1030/smc/read_status_reg", 8840f6e8aa4SJamin Lin data, test_read_status_reg); 885*08479f0cSJamin Lin qtest_add_data_func("/ast1030/smc/write_page_qpi", 886*08479f0cSJamin Lin data, test_write_page_qpi); 8870f6e8aa4SJamin Lin } 8880f6e8aa4SJamin Lin 889755e984aSJamin Lin int main(int argc, char **argv) 890755e984aSJamin Lin { 891975d4bafSJamin Lin TestData palmetto_data; 892658ebe13SJamin Lin TestData ast2500_evb_data; 89384f7ea6dSJamin Lin TestData ast2600_evb_data; 8940f6e8aa4SJamin Lin TestData ast1030_evb_data; 895755e984aSJamin Lin int ret; 896755e984aSJamin Lin 897755e984aSJamin Lin g_test_init(&argc, &argv, NULL); 898755e984aSJamin Lin 899975d4bafSJamin Lin test_palmetto_bmc(&palmetto_data); 900658ebe13SJamin Lin test_ast2500_evb(&ast2500_evb_data); 90184f7ea6dSJamin Lin test_ast2600_evb(&ast2600_evb_data); 9020f6e8aa4SJamin Lin test_ast1030_evb(&ast1030_evb_data); 903975d4bafSJamin Lin ret = g_test_run(); 904975d4bafSJamin Lin 905975d4bafSJamin Lin qtest_quit(palmetto_data.s); 906658ebe13SJamin Lin qtest_quit(ast2500_evb_data.s); 90784f7ea6dSJamin Lin qtest_quit(ast2600_evb_data.s); 9080f6e8aa4SJamin Lin qtest_quit(ast1030_evb_data.s); 909975d4bafSJamin Lin unlink(palmetto_data.tmp_path); 910658ebe13SJamin Lin unlink(ast2500_evb_data.tmp_path); 91184f7ea6dSJamin Lin unlink(ast2600_evb_data.tmp_path); 9120f6e8aa4SJamin Lin unlink(ast1030_evb_data.tmp_path); 9137a2334f7SCédric Le Goater return ret; 9147a2334f7SCédric Le Goater } 915