xref: /qemu/tests/qtest/aspeed_smc-test.c (revision 84f7ea6db7709c8378362c4a1af30a3e3e3932b1)
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
39dc32f5baSJamin Lin #define   CTRL_CE_STOP_ACTIVE  BIT(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 
67975d4bafSJamin Lin typedef struct TestData {
68975d4bafSJamin Lin     QTestState *s;
69975d4bafSJamin Lin     uint64_t spi_base;
70975d4bafSJamin Lin     uint64_t flash_base;
71975d4bafSJamin Lin     uint32_t jedec_id;
72975d4bafSJamin Lin     char *tmp_path;
73dc32f5baSJamin Lin     uint8_t cs;
74dc32f5baSJamin Lin     const char *node;
75369a47aeSJamin Lin     uint32_t page_addr;
76975d4bafSJamin Lin } TestData;
77975d4bafSJamin Lin 
787a2334f7SCédric Le Goater /*
797a2334f7SCédric Le Goater  * Use an explicit bswap for the values read/wrote to the flash region
807a2334f7SCédric Le Goater  * as they are BE and the Aspeed CPU is LE.
817a2334f7SCédric Le Goater  */
827a2334f7SCédric Le Goater static inline uint32_t make_be32(uint32_t data)
837a2334f7SCédric Le Goater {
847a2334f7SCédric Le Goater     return bswap32(data);
857a2334f7SCédric Le Goater }
867a2334f7SCédric Le Goater 
87975d4bafSJamin Lin static inline void spi_writel(const TestData *data, uint64_t offset,
88975d4bafSJamin Lin                               uint32_t value)
897a2334f7SCédric Le Goater {
90975d4bafSJamin Lin     qtest_writel(data->s, data->spi_base + offset, value);
917a2334f7SCédric Le Goater }
927a2334f7SCédric Le Goater 
93975d4bafSJamin Lin static inline uint32_t spi_readl(const TestData *data, uint64_t offset)
94bd9f5052SCédric Le Goater {
95975d4bafSJamin Lin     return qtest_readl(data->s, data->spi_base + offset);
96975d4bafSJamin Lin }
97975d4bafSJamin Lin 
98975d4bafSJamin Lin static inline void flash_writeb(const TestData *data, uint64_t offset,
99975d4bafSJamin Lin                                 uint8_t value)
100975d4bafSJamin Lin {
101975d4bafSJamin Lin     qtest_writeb(data->s, data->flash_base + offset, value);
102975d4bafSJamin Lin }
103975d4bafSJamin Lin 
104975d4bafSJamin Lin static inline void flash_writel(const TestData *data, uint64_t offset,
105975d4bafSJamin Lin                                 uint32_t value)
106975d4bafSJamin Lin {
107975d4bafSJamin Lin     qtest_writel(data->s, data->flash_base + offset, value);
108975d4bafSJamin Lin }
109975d4bafSJamin Lin 
110975d4bafSJamin Lin static inline uint8_t flash_readb(const TestData *data, uint64_t offset)
111975d4bafSJamin Lin {
112975d4bafSJamin Lin     return qtest_readb(data->s, data->flash_base + offset);
113975d4bafSJamin Lin }
114975d4bafSJamin Lin 
115975d4bafSJamin Lin static inline uint32_t flash_readl(const TestData *data, uint64_t offset)
116975d4bafSJamin Lin {
117975d4bafSJamin Lin     return qtest_readl(data->s, data->flash_base + offset);
118975d4bafSJamin Lin }
119975d4bafSJamin Lin 
120975d4bafSJamin Lin static void spi_conf(const TestData *data, uint32_t value)
121975d4bafSJamin Lin {
122975d4bafSJamin Lin     uint32_t conf = spi_readl(data, R_CONF);
123975d4bafSJamin Lin 
124975d4bafSJamin Lin     conf |= value;
125975d4bafSJamin Lin     spi_writel(data, R_CONF, conf);
126975d4bafSJamin Lin }
127975d4bafSJamin Lin 
128975d4bafSJamin Lin static void spi_conf_remove(const TestData *data, uint32_t value)
129975d4bafSJamin Lin {
130975d4bafSJamin Lin     uint32_t conf = spi_readl(data, R_CONF);
131bd9f5052SCédric Le Goater 
132bd9f5052SCédric Le Goater     conf &= ~value;
133975d4bafSJamin Lin     spi_writel(data, R_CONF, conf);
134bd9f5052SCédric Le Goater }
135bd9f5052SCédric Le Goater 
136975d4bafSJamin Lin static void spi_ce_ctrl(const TestData *data, uint32_t value)
137371a3dd2SCédric Le Goater {
138975d4bafSJamin Lin     uint32_t conf = spi_readl(data, R_CE_CTRL);
139371a3dd2SCédric Le Goater 
140371a3dd2SCédric Le Goater     conf |= value;
141975d4bafSJamin Lin     spi_writel(data, R_CE_CTRL, conf);
142371a3dd2SCédric Le Goater }
143371a3dd2SCédric Le Goater 
144975d4bafSJamin Lin static void spi_ctrl_setmode(const TestData *data, uint8_t mode, uint8_t cmd)
145371a3dd2SCédric Le Goater {
146dc32f5baSJamin Lin     uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
147dc32f5baSJamin Lin     uint32_t ctrl = spi_readl(data, ctrl_reg);
148371a3dd2SCédric Le Goater     ctrl &= ~(CTRL_USERMODE | 0xff << 16);
149371a3dd2SCédric Le Goater     ctrl |= mode | (cmd << 16);
150dc32f5baSJamin Lin     spi_writel(data, ctrl_reg, ctrl);
151371a3dd2SCédric Le Goater }
152371a3dd2SCédric Le Goater 
153975d4bafSJamin Lin static void spi_ctrl_start_user(const TestData *data)
1547a2334f7SCédric Le Goater {
155dc32f5baSJamin Lin     uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
156dc32f5baSJamin Lin     uint32_t ctrl = spi_readl(data, ctrl_reg);
1577a2334f7SCédric Le Goater 
1587a2334f7SCédric Le Goater     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
159dc32f5baSJamin Lin     spi_writel(data, ctrl_reg, ctrl);
1607a2334f7SCédric Le Goater 
1617a2334f7SCédric Le Goater     ctrl &= ~CTRL_CE_STOP_ACTIVE;
162dc32f5baSJamin Lin     spi_writel(data, ctrl_reg, ctrl);
1637a2334f7SCédric Le Goater }
1647a2334f7SCédric Le Goater 
165975d4bafSJamin Lin static void spi_ctrl_stop_user(const TestData *data)
1667a2334f7SCédric Le Goater {
167dc32f5baSJamin Lin     uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
168dc32f5baSJamin Lin     uint32_t ctrl = spi_readl(data, ctrl_reg);
1697a2334f7SCédric Le Goater 
1707a2334f7SCédric Le Goater     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
171dc32f5baSJamin Lin     spi_writel(data, ctrl_reg, ctrl);
1727a2334f7SCédric Le Goater }
1737a2334f7SCédric Le Goater 
174975d4bafSJamin Lin static void flash_reset(const TestData *data)
175bd9f5052SCédric Le Goater {
176dc32f5baSJamin Lin     spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
177bd9f5052SCédric Le Goater 
178975d4bafSJamin Lin     spi_ctrl_start_user(data);
179975d4bafSJamin Lin     flash_writeb(data, 0, RESET_ENABLE);
180975d4bafSJamin Lin     flash_writeb(data, 0, RESET_MEMORY);
181975d4bafSJamin Lin     flash_writeb(data, 0, WREN);
182975d4bafSJamin Lin     flash_writeb(data, 0, BULK_ERASE);
183975d4bafSJamin Lin     flash_writeb(data, 0, WRDI);
184975d4bafSJamin Lin     spi_ctrl_stop_user(data);
185bd9f5052SCédric Le Goater 
186dc32f5baSJamin Lin     spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
187bd9f5052SCédric Le Goater }
188bd9f5052SCédric Le Goater 
189975d4bafSJamin Lin static void test_read_jedec(const void *data)
1907a2334f7SCédric Le Goater {
191975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
1927a2334f7SCédric Le Goater     uint32_t jedec = 0x0;
1937a2334f7SCédric Le Goater 
194dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
1957a2334f7SCédric Le Goater 
196975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
197975d4bafSJamin Lin     flash_writeb(test_data, 0, JEDEC_READ);
198975d4bafSJamin Lin     jedec |= flash_readb(test_data, 0) << 16;
199975d4bafSJamin Lin     jedec |= flash_readb(test_data, 0) << 8;
200975d4bafSJamin Lin     jedec |= flash_readb(test_data, 0);
201975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
2027a2334f7SCédric Le Goater 
203975d4bafSJamin Lin     flash_reset(test_data);
204bd9f5052SCédric Le Goater 
205975d4bafSJamin Lin     g_assert_cmphex(jedec, ==, test_data->jedec_id);
2067a2334f7SCédric Le Goater }
2077a2334f7SCédric Le Goater 
208975d4bafSJamin Lin static void read_page(const TestData *data, uint32_t addr, uint32_t *page)
2097a2334f7SCédric Le Goater {
2107a2334f7SCédric Le Goater     int i;
2117a2334f7SCédric Le Goater 
212975d4bafSJamin Lin     spi_ctrl_start_user(data);
2137a2334f7SCédric Le Goater 
214975d4bafSJamin Lin     flash_writeb(data, 0, EN_4BYTE_ADDR);
215975d4bafSJamin Lin     flash_writeb(data, 0, READ);
216975d4bafSJamin Lin     flash_writel(data, 0, make_be32(addr));
2177a2334f7SCédric Le Goater 
2187a2334f7SCédric Le Goater     /* Continuous read are supported */
219d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
220975d4bafSJamin Lin         page[i] = make_be32(flash_readl(data, 0));
2217a2334f7SCédric Le Goater     }
222975d4bafSJamin Lin     spi_ctrl_stop_user(data);
2237a2334f7SCédric Le Goater }
2247a2334f7SCédric Le Goater 
225975d4bafSJamin Lin static void read_page_mem(const TestData *data, uint32_t addr, uint32_t *page)
226371a3dd2SCédric Le Goater {
227371a3dd2SCédric Le Goater     int i;
228371a3dd2SCédric Le Goater 
229371a3dd2SCédric Le Goater     /* move out USER mode to use direct reads from the AHB bus */
230975d4bafSJamin Lin     spi_ctrl_setmode(data, CTRL_READMODE, READ);
231371a3dd2SCédric Le Goater 
232d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
233975d4bafSJamin Lin         page[i] = make_be32(flash_readl(data, addr + i * 4));
234371a3dd2SCédric Le Goater     }
235371a3dd2SCédric Le Goater }
236371a3dd2SCédric Le Goater 
237975d4bafSJamin Lin static void write_page_mem(const TestData *data, uint32_t addr,
238975d4bafSJamin Lin                            uint32_t write_value)
2398abf9ba4SIris Chen {
240975d4bafSJamin Lin     spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
2418abf9ba4SIris Chen 
2428abf9ba4SIris Chen     for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
243975d4bafSJamin Lin         flash_writel(data, addr + i * 4, write_value);
2448abf9ba4SIris Chen     }
2458abf9ba4SIris Chen }
2468abf9ba4SIris Chen 
247975d4bafSJamin Lin static void assert_page_mem(const TestData *data, uint32_t addr,
248975d4bafSJamin Lin                             uint32_t expected_value)
2498abf9ba4SIris Chen {
2508abf9ba4SIris Chen     uint32_t page[FLASH_PAGE_SIZE / 4];
251975d4bafSJamin Lin     read_page_mem(data, addr, page);
2528abf9ba4SIris Chen     for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
2538abf9ba4SIris Chen         g_assert_cmphex(page[i], ==, expected_value);
2548abf9ba4SIris Chen     }
2558abf9ba4SIris Chen }
2568abf9ba4SIris Chen 
257975d4bafSJamin Lin static void test_erase_sector(const void *data)
2587a2334f7SCédric Le Goater {
259975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
260369a47aeSJamin Lin     uint32_t some_page_addr = test_data->page_addr;
261d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
2627a2334f7SCédric Le Goater     int i;
2637a2334f7SCédric Le Goater 
264dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
2657a2334f7SCédric Le Goater 
26692a45bdeSIris Chen     /*
26792a45bdeSIris Chen      * Previous page should be full of 0xffs after backend is
26892a45bdeSIris Chen      * initialized
26992a45bdeSIris Chen      */
270975d4bafSJamin Lin     read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
27192a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
27292a45bdeSIris Chen         g_assert_cmphex(page[i], ==, 0xffffffff);
27392a45bdeSIris Chen     }
27492a45bdeSIris Chen 
275975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
276975d4bafSJamin Lin     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
277975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
278975d4bafSJamin Lin     flash_writeb(test_data, 0, PP);
279975d4bafSJamin Lin     flash_writel(test_data, 0, make_be32(some_page_addr));
28092a45bdeSIris Chen 
28192a45bdeSIris Chen     /* Fill the page with its own addresses */
28292a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
283975d4bafSJamin Lin         flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
28492a45bdeSIris Chen     }
285975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
28692a45bdeSIris Chen 
28792a45bdeSIris Chen     /* Check the page is correctly written */
288975d4bafSJamin Lin     read_page(test_data, some_page_addr, page);
28992a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
29092a45bdeSIris Chen         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
29192a45bdeSIris Chen     }
29292a45bdeSIris Chen 
293975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
294975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
295975d4bafSJamin Lin     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
296975d4bafSJamin Lin     flash_writeb(test_data, 0, ERASE_SECTOR);
297975d4bafSJamin Lin     flash_writel(test_data, 0, make_be32(some_page_addr));
298975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
2997a2334f7SCédric Le Goater 
30092a45bdeSIris Chen     /* Check the page is erased */
301975d4bafSJamin Lin     read_page(test_data, some_page_addr, page);
302d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
3037a2334f7SCédric Le Goater         g_assert_cmphex(page[i], ==, 0xffffffff);
3047a2334f7SCédric Le Goater     }
305bd9f5052SCédric Le Goater 
306975d4bafSJamin Lin     flash_reset(test_data);
3077a2334f7SCédric Le Goater }
3087a2334f7SCédric Le Goater 
309975d4bafSJamin Lin static void test_erase_all(const void *data)
3107a2334f7SCédric Le Goater {
311975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
312369a47aeSJamin Lin     uint32_t some_page_addr = test_data->page_addr;
313d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
3147a2334f7SCédric Le Goater     int i;
3157a2334f7SCédric Le Goater 
316dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
3177a2334f7SCédric Le Goater 
31892a45bdeSIris Chen     /*
31992a45bdeSIris Chen      * Previous page should be full of 0xffs after backend is
32092a45bdeSIris Chen      * initialized
32192a45bdeSIris Chen      */
322975d4bafSJamin Lin     read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
32392a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
32492a45bdeSIris Chen         g_assert_cmphex(page[i], ==, 0xffffffff);
32592a45bdeSIris Chen     }
32692a45bdeSIris Chen 
327975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
328975d4bafSJamin Lin     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
329975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
330975d4bafSJamin Lin     flash_writeb(test_data, 0, PP);
331975d4bafSJamin Lin     flash_writel(test_data, 0, make_be32(some_page_addr));
33292a45bdeSIris Chen 
33392a45bdeSIris Chen     /* Fill the page with its own addresses */
33492a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
335975d4bafSJamin Lin         flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
33692a45bdeSIris Chen     }
337975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
33892a45bdeSIris Chen 
33992a45bdeSIris Chen     /* Check the page is correctly written */
340975d4bafSJamin Lin     read_page(test_data, some_page_addr, page);
341d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
34292a45bdeSIris Chen         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
3437a2334f7SCédric Le Goater     }
3447a2334f7SCédric Le Goater 
345975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
346975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
347975d4bafSJamin Lin     flash_writeb(test_data, 0, BULK_ERASE);
348975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
3497a2334f7SCédric Le Goater 
35092a45bdeSIris Chen     /* Check the page is erased */
351975d4bafSJamin Lin     read_page(test_data, some_page_addr, page);
352d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
3537a2334f7SCédric Le Goater         g_assert_cmphex(page[i], ==, 0xffffffff);
3547a2334f7SCédric Le Goater     }
355bd9f5052SCédric Le Goater 
356975d4bafSJamin Lin     flash_reset(test_data);
3577a2334f7SCédric Le Goater }
3587a2334f7SCédric Le Goater 
359975d4bafSJamin Lin static void test_write_page(const void *data)
3607a2334f7SCédric Le Goater {
361975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
362369a47aeSJamin Lin     uint32_t my_page_addr = test_data->page_addr;
363369a47aeSJamin Lin     uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
364d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
3657a2334f7SCédric Le Goater     int i;
3667a2334f7SCédric Le Goater 
367dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
3687a2334f7SCédric Le Goater 
369975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
370975d4bafSJamin Lin     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
371975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
372975d4bafSJamin Lin     flash_writeb(test_data, 0, PP);
373975d4bafSJamin Lin     flash_writel(test_data, 0, make_be32(my_page_addr));
3747a2334f7SCédric Le Goater 
3757a2334f7SCédric Le Goater     /* Fill the page with its own addresses */
376d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
377975d4bafSJamin Lin         flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
3787a2334f7SCédric Le Goater     }
379975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
3807a2334f7SCédric Le Goater 
3817a2334f7SCédric Le Goater     /* Check what was written */
382975d4bafSJamin Lin     read_page(test_data, my_page_addr, page);
383d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
3847a2334f7SCédric Le Goater         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
3857a2334f7SCédric Le Goater     }
3867a2334f7SCédric Le Goater 
3877a2334f7SCédric Le Goater     /* Check some other page. It should be full of 0xff */
388975d4bafSJamin Lin     read_page(test_data, some_page_addr, page);
389d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
3907a2334f7SCédric Le Goater         g_assert_cmphex(page[i], ==, 0xffffffff);
3917a2334f7SCédric Le Goater     }
392bd9f5052SCédric Le Goater 
393975d4bafSJamin Lin     flash_reset(test_data);
3947a2334f7SCédric Le Goater }
3957a2334f7SCédric Le Goater 
396975d4bafSJamin Lin static void test_read_page_mem(const void *data)
397371a3dd2SCédric Le Goater {
398975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
399369a47aeSJamin Lin     uint32_t my_page_addr = test_data->page_addr;
400369a47aeSJamin Lin     uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
401d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
402371a3dd2SCédric Le Goater     int i;
403371a3dd2SCédric Le Goater 
4041df52a9aSJamin Lin     /*
405dc32f5baSJamin Lin      * Enable 4BYTE mode for controller.
406371a3dd2SCédric Le Goater      */
407dc32f5baSJamin Lin     spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
408371a3dd2SCédric Le Goater 
409371a3dd2SCédric Le Goater     /* Enable 4BYTE mode for flash. */
410dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
411975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
412975d4bafSJamin Lin     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
413975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
414975d4bafSJamin Lin     flash_writeb(test_data, 0, PP);
415975d4bafSJamin Lin     flash_writel(test_data, 0, make_be32(my_page_addr));
41692a45bdeSIris Chen 
41792a45bdeSIris Chen     /* Fill the page with its own addresses */
41892a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
419975d4bafSJamin Lin         flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
42092a45bdeSIris Chen     }
421975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
422dc32f5baSJamin Lin     spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
423371a3dd2SCédric Le Goater 
424371a3dd2SCédric Le Goater     /* Check what was written */
425975d4bafSJamin Lin     read_page_mem(test_data, my_page_addr, page);
426d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
427371a3dd2SCédric Le Goater         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
428371a3dd2SCédric Le Goater     }
429371a3dd2SCédric Le Goater 
430371a3dd2SCédric Le Goater     /* Check some other page. It should be full of 0xff */
431975d4bafSJamin Lin     read_page_mem(test_data, some_page_addr, page);
432d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
433371a3dd2SCédric Le Goater         g_assert_cmphex(page[i], ==, 0xffffffff);
434371a3dd2SCédric Le Goater     }
435371a3dd2SCédric Le Goater 
436975d4bafSJamin Lin     flash_reset(test_data);
437371a3dd2SCédric Le Goater }
438371a3dd2SCédric Le Goater 
439975d4bafSJamin Lin static void test_write_page_mem(const void *data)
440371a3dd2SCédric Le Goater {
441975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
442369a47aeSJamin Lin     uint32_t my_page_addr = test_data->page_addr;
443d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
444371a3dd2SCédric Le Goater     int i;
445371a3dd2SCédric Le Goater 
4461df52a9aSJamin Lin     /*
447dc32f5baSJamin Lin      * Enable 4BYTE mode for controller.
448371a3dd2SCédric Le Goater      */
449dc32f5baSJamin Lin     spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
450371a3dd2SCédric Le Goater 
451371a3dd2SCédric Le Goater     /* Enable 4BYTE mode for flash. */
452dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
453975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
454975d4bafSJamin Lin     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
455975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
456975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
457371a3dd2SCédric Le Goater 
458371a3dd2SCédric Le Goater     /* move out USER mode to use direct writes to the AHB bus */
459975d4bafSJamin Lin     spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
460371a3dd2SCédric Le Goater 
461d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
462975d4bafSJamin Lin         flash_writel(test_data, my_page_addr + i * 4,
463371a3dd2SCédric Le Goater                make_be32(my_page_addr + i * 4));
464371a3dd2SCédric Le Goater     }
465371a3dd2SCédric Le Goater 
466371a3dd2SCédric Le Goater     /* Check what was written */
467975d4bafSJamin Lin     read_page_mem(test_data, my_page_addr, page);
468d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
469371a3dd2SCédric Le Goater         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
470371a3dd2SCédric Le Goater     }
471371a3dd2SCédric Le Goater 
472975d4bafSJamin Lin     flash_reset(test_data);
473371a3dd2SCédric Le Goater }
474371a3dd2SCédric Le Goater 
475975d4bafSJamin Lin static void test_read_status_reg(const void *data)
476188052a1SIris Chen {
477975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
478188052a1SIris Chen     uint8_t r;
479188052a1SIris Chen 
480dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
481188052a1SIris Chen 
482975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
483975d4bafSJamin Lin     flash_writeb(test_data, 0, RDSR);
484975d4bafSJamin Lin     r = flash_readb(test_data, 0);
485975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
486188052a1SIris Chen 
487188052a1SIris Chen     g_assert_cmphex(r & SR_WEL, ==, 0);
488188052a1SIris Chen     g_assert(!qtest_qom_get_bool
489dc32f5baSJamin Lin             (test_data->s, test_data->node, "write-enable"));
490188052a1SIris Chen 
491975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
492975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
493975d4bafSJamin Lin     flash_writeb(test_data, 0, RDSR);
494975d4bafSJamin Lin     r = flash_readb(test_data, 0);
495975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
496188052a1SIris Chen 
497188052a1SIris Chen     g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
498188052a1SIris Chen     g_assert(qtest_qom_get_bool
499dc32f5baSJamin Lin             (test_data->s, test_data->node, "write-enable"));
500188052a1SIris Chen 
501975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
502975d4bafSJamin Lin     flash_writeb(test_data, 0, WRDI);
503975d4bafSJamin Lin     flash_writeb(test_data, 0, RDSR);
504975d4bafSJamin Lin     r = flash_readb(test_data, 0);
505975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
506188052a1SIris Chen 
507188052a1SIris Chen     g_assert_cmphex(r & SR_WEL, ==, 0);
508188052a1SIris Chen     g_assert(!qtest_qom_get_bool
509dc32f5baSJamin Lin             (test_data->s, test_data->node, "write-enable"));
510188052a1SIris Chen 
511975d4bafSJamin Lin     flash_reset(test_data);
512188052a1SIris Chen }
513188052a1SIris Chen 
514975d4bafSJamin Lin static void test_status_reg_write_protection(const void *data)
5151de51272SIris Chen {
516975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
5171de51272SIris Chen     uint8_t r;
5181de51272SIris Chen 
519dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
5201de51272SIris Chen 
5211de51272SIris Chen     /* default case: WP# is high and SRWD is low -> status register writable */
522975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
523975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
5241de51272SIris Chen     /* test ability to write SRWD */
525975d4bafSJamin Lin     flash_writeb(test_data, 0, WRSR);
526975d4bafSJamin Lin     flash_writeb(test_data, 0, SRWD);
527975d4bafSJamin Lin     flash_writeb(test_data, 0, RDSR);
528975d4bafSJamin Lin     r = flash_readb(test_data, 0);
529975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
5301de51272SIris Chen     g_assert_cmphex(r & SRWD, ==, SRWD);
5311de51272SIris Chen 
5321de51272SIris Chen     /* WP# high and SRWD high -> status register writable */
533975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
534975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
5351de51272SIris Chen     /* test ability to write SRWD */
536975d4bafSJamin Lin     flash_writeb(test_data, 0, WRSR);
537975d4bafSJamin Lin     flash_writeb(test_data, 0, 0);
538975d4bafSJamin Lin     flash_writeb(test_data, 0, RDSR);
539975d4bafSJamin Lin     r = flash_readb(test_data, 0);
540975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
5411de51272SIris Chen     g_assert_cmphex(r & SRWD, ==, 0);
5421de51272SIris Chen 
5431de51272SIris Chen     /* WP# low and SRWD low -> status register writable */
544dc32f5baSJamin Lin     qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
545975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
546975d4bafSJamin Lin     flash_writeb(test_data, 0, WREN);
5471de51272SIris Chen     /* test ability to write SRWD */
548975d4bafSJamin Lin     flash_writeb(test_data, 0, WRSR);
549975d4bafSJamin Lin     flash_writeb(test_data, 0, SRWD);
550975d4bafSJamin Lin     flash_writeb(test_data, 0, RDSR);
551975d4bafSJamin Lin     r = flash_readb(test_data, 0);
552975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
5531de51272SIris Chen     g_assert_cmphex(r & SRWD, ==, SRWD);
5541de51272SIris Chen 
5551de51272SIris Chen     /* WP# low and SRWD high -> status register NOT writable */
556975d4bafSJamin Lin     spi_ctrl_start_user(test_data);
557975d4bafSJamin Lin     flash_writeb(test_data, 0 , WREN);
5581de51272SIris Chen     /* test ability to write SRWD */
559975d4bafSJamin Lin     flash_writeb(test_data, 0, WRSR);
560975d4bafSJamin Lin     flash_writeb(test_data, 0, 0);
561975d4bafSJamin Lin     flash_writeb(test_data, 0, RDSR);
562975d4bafSJamin Lin     r = flash_readb(test_data, 0);
563975d4bafSJamin Lin     spi_ctrl_stop_user(test_data);
5641de51272SIris Chen     /* write is not successful */
5651de51272SIris Chen     g_assert_cmphex(r & SRWD, ==, SRWD);
5661de51272SIris Chen 
567dc32f5baSJamin Lin     qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
568975d4bafSJamin Lin     flash_reset(test_data);
5691de51272SIris Chen }
5701de51272SIris Chen 
571975d4bafSJamin Lin static void test_write_block_protect(const void *data)
5728abf9ba4SIris Chen {
573975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
5748abf9ba4SIris Chen     uint32_t sector_size = 65536;
5758abf9ba4SIris Chen     uint32_t n_sectors = 512;
5768abf9ba4SIris Chen 
577dc32f5baSJamin Lin     spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
578dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
5798abf9ba4SIris Chen 
5808abf9ba4SIris Chen     uint32_t bp_bits = 0b0;
5818abf9ba4SIris Chen 
5828abf9ba4SIris Chen     for (int i = 0; i < 16; i++) {
5838abf9ba4SIris Chen         bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
5848abf9ba4SIris Chen 
585975d4bafSJamin Lin         spi_ctrl_start_user(test_data);
586975d4bafSJamin Lin         flash_writeb(test_data, 0, WREN);
587975d4bafSJamin Lin         flash_writeb(test_data, 0, BULK_ERASE);
588975d4bafSJamin Lin         flash_writeb(test_data, 0, WREN);
589975d4bafSJamin Lin         flash_writeb(test_data, 0, WRSR);
590975d4bafSJamin Lin         flash_writeb(test_data, 0, bp_bits);
591975d4bafSJamin Lin         flash_writeb(test_data, 0, EN_4BYTE_ADDR);
592975d4bafSJamin Lin         flash_writeb(test_data, 0, WREN);
593975d4bafSJamin Lin         spi_ctrl_stop_user(test_data);
5948abf9ba4SIris Chen 
5958abf9ba4SIris Chen         uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
5968abf9ba4SIris Chen         uint32_t protection_start = n_sectors - num_protected_sectors;
5978abf9ba4SIris Chen         uint32_t protection_end = n_sectors;
5988abf9ba4SIris Chen 
5998abf9ba4SIris Chen         for (int sector = 0; sector < n_sectors; sector++) {
6008abf9ba4SIris Chen             uint32_t addr = sector * sector_size;
6018abf9ba4SIris Chen 
602975d4bafSJamin Lin             assert_page_mem(test_data, addr, 0xffffffff);
603975d4bafSJamin Lin             write_page_mem(test_data, addr, make_be32(0xabcdef12));
6048abf9ba4SIris Chen 
6058abf9ba4SIris Chen             uint32_t expected_value = protection_start <= sector
6068abf9ba4SIris Chen                                       && sector < protection_end
6078abf9ba4SIris Chen                                       ? 0xffffffff : 0xabcdef12;
6088abf9ba4SIris Chen 
609975d4bafSJamin Lin             assert_page_mem(test_data, addr, expected_value);
6108abf9ba4SIris Chen         }
6118abf9ba4SIris Chen     }
6128abf9ba4SIris Chen 
613975d4bafSJamin Lin     flash_reset(test_data);
6148abf9ba4SIris Chen }
6158abf9ba4SIris Chen 
616975d4bafSJamin Lin static void test_write_block_protect_bottom_bit(const void *data)
6178abf9ba4SIris Chen {
618975d4bafSJamin Lin     const TestData *test_data = (const TestData *)data;
6198abf9ba4SIris Chen     uint32_t sector_size = 65536;
6208abf9ba4SIris Chen     uint32_t n_sectors = 512;
6218abf9ba4SIris Chen 
622dc32f5baSJamin Lin     spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
623dc32f5baSJamin Lin     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
6248abf9ba4SIris Chen 
6258abf9ba4SIris Chen     /* top bottom bit is enabled */
6268abf9ba4SIris Chen     uint32_t bp_bits = 0b00100 << 3;
6278abf9ba4SIris Chen 
6288abf9ba4SIris Chen     for (int i = 0; i < 16; i++) {
6298abf9ba4SIris Chen         bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2);
6308abf9ba4SIris Chen 
631975d4bafSJamin Lin         spi_ctrl_start_user(test_data);
632975d4bafSJamin Lin         flash_writeb(test_data, 0, WREN);
633975d4bafSJamin Lin         flash_writeb(test_data, 0, BULK_ERASE);
634975d4bafSJamin Lin         flash_writeb(test_data, 0, WREN);
635975d4bafSJamin Lin         flash_writeb(test_data, 0, WRSR);
636975d4bafSJamin Lin         flash_writeb(test_data, 0, bp_bits);
637975d4bafSJamin Lin         flash_writeb(test_data, 0, EN_4BYTE_ADDR);
638975d4bafSJamin Lin         flash_writeb(test_data, 0, WREN);
639975d4bafSJamin Lin         spi_ctrl_stop_user(test_data);
6408abf9ba4SIris Chen 
6418abf9ba4SIris Chen         uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
6428abf9ba4SIris Chen         uint32_t protection_start = 0;
6438abf9ba4SIris Chen         uint32_t protection_end = num_protected_sectors;
6448abf9ba4SIris Chen 
6458abf9ba4SIris Chen         for (int sector = 0; sector < n_sectors; sector++) {
6468abf9ba4SIris Chen             uint32_t addr = sector * sector_size;
6478abf9ba4SIris Chen 
648975d4bafSJamin Lin             assert_page_mem(test_data, addr, 0xffffffff);
649975d4bafSJamin Lin             write_page_mem(test_data, addr, make_be32(0xabcdef12));
6508abf9ba4SIris Chen 
6518abf9ba4SIris Chen             uint32_t expected_value = protection_start <= sector
6528abf9ba4SIris Chen                                       && sector < protection_end
6538abf9ba4SIris Chen                                       ? 0xffffffff : 0xabcdef12;
6548abf9ba4SIris Chen 
655975d4bafSJamin Lin             assert_page_mem(test_data, addr, expected_value);
6568abf9ba4SIris Chen         }
6578abf9ba4SIris Chen     }
6588abf9ba4SIris Chen 
659975d4bafSJamin Lin     flash_reset(test_data);
6608abf9ba4SIris Chen }
6618abf9ba4SIris Chen 
662975d4bafSJamin Lin static void test_palmetto_bmc(TestData *data)
6637a2334f7SCédric Le Goater {
6647a2334f7SCédric Le Goater     int ret;
6657a2334f7SCédric Le Goater     int fd;
6667a2334f7SCédric Le Goater 
667975d4bafSJamin Lin     fd = g_file_open_tmp("qtest.m25p80.n25q256a.XXXXXX", &data->tmp_path, NULL);
6687a2334f7SCédric Le Goater     g_assert(fd >= 0);
669975d4bafSJamin Lin     ret = ftruncate(fd, 32 * 1024 * 1024);
6707a2334f7SCédric Le Goater     g_assert(ret == 0);
6717a2334f7SCédric Le Goater     close(fd);
6727a2334f7SCédric Le Goater 
673975d4bafSJamin Lin     data->s = qtest_initf("-m 256 -machine palmetto-bmc "
6747a2334f7SCédric Le Goater                           "-drive file=%s,format=raw,if=mtd",
675975d4bafSJamin Lin                           data->tmp_path);
6767a2334f7SCédric Le Goater 
677975d4bafSJamin Lin     /* fmc cs0 with n25q256a flash */
678975d4bafSJamin Lin     data->flash_base = 0x20000000;
679975d4bafSJamin Lin     data->spi_base = 0x1E620000;
680975d4bafSJamin Lin     data->jedec_id = 0x20ba19;
681dc32f5baSJamin Lin     data->cs = 0;
682dc32f5baSJamin Lin     data->node = "/machine/soc/fmc/ssi.0/child[0]";
683369a47aeSJamin Lin     /* beyond 16MB */
684369a47aeSJamin Lin     data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
6857a2334f7SCédric Le Goater 
686975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/read_jedec", data, test_read_jedec);
687975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/erase_sector", data, test_erase_sector);
688975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/erase_all",  data, test_erase_all);
689975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/write_page", data, test_write_page);
690975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/read_page_mem",
691975d4bafSJamin Lin                         data, test_read_page_mem);
692975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/write_page_mem",
693975d4bafSJamin Lin                         data, test_write_page_mem);
694975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/read_status_reg",
695975d4bafSJamin Lin                         data, test_read_status_reg);
696975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/status_reg_write_protection",
697975d4bafSJamin Lin                         data, test_status_reg_write_protection);
698975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/write_block_protect",
699975d4bafSJamin Lin                         data, test_write_block_protect);
700975d4bafSJamin Lin     qtest_add_data_func("/ast2400/smc/write_block_protect_bottom_bit",
701975d4bafSJamin Lin                         data, test_write_block_protect_bottom_bit);
702755e984aSJamin Lin }
703755e984aSJamin Lin 
704658ebe13SJamin Lin static void test_ast2500_evb(TestData *data)
705658ebe13SJamin Lin {
706658ebe13SJamin Lin     int ret;
707658ebe13SJamin Lin     int fd;
708658ebe13SJamin Lin 
709658ebe13SJamin Lin     fd = g_file_open_tmp("qtest.m25p80.mx25l25635e.XXXXXX",
710658ebe13SJamin Lin                          &data->tmp_path, NULL);
711658ebe13SJamin Lin     g_assert(fd >= 0);
712658ebe13SJamin Lin     ret = ftruncate(fd, 32 * 1024 * 1024);
713658ebe13SJamin Lin     g_assert(ret == 0);
714658ebe13SJamin Lin     close(fd);
715658ebe13SJamin Lin 
716658ebe13SJamin Lin     data->s = qtest_initf("-machine ast2500-evb "
717658ebe13SJamin Lin                           "-drive file=%s,format=raw,if=mtd",
718658ebe13SJamin Lin                           data->tmp_path);
719658ebe13SJamin Lin 
720658ebe13SJamin Lin     /* fmc cs0 with mx25l25635e flash */
721658ebe13SJamin Lin     data->flash_base = 0x20000000;
722658ebe13SJamin Lin     data->spi_base = 0x1E620000;
723658ebe13SJamin Lin     data->jedec_id = 0xc22019;
724658ebe13SJamin Lin     data->cs = 0;
725658ebe13SJamin Lin     data->node = "/machine/soc/fmc/ssi.0/child[0]";
726658ebe13SJamin Lin     /* beyond 16MB */
727658ebe13SJamin Lin     data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
728658ebe13SJamin Lin 
729658ebe13SJamin Lin     qtest_add_data_func("/ast2500/smc/read_jedec", data, test_read_jedec);
730658ebe13SJamin Lin     qtest_add_data_func("/ast2500/smc/erase_sector", data, test_erase_sector);
731658ebe13SJamin Lin     qtest_add_data_func("/ast2500/smc/erase_all",  data, test_erase_all);
732658ebe13SJamin Lin     qtest_add_data_func("/ast2500/smc/write_page", data, test_write_page);
733658ebe13SJamin Lin     qtest_add_data_func("/ast2500/smc/read_page_mem",
734658ebe13SJamin Lin                         data, test_read_page_mem);
735658ebe13SJamin Lin     qtest_add_data_func("/ast2500/smc/write_page_mem",
736658ebe13SJamin Lin                         data, test_write_page_mem);
737658ebe13SJamin Lin     qtest_add_data_func("/ast2500/smc/read_status_reg",
738658ebe13SJamin Lin                         data, test_read_status_reg);
739658ebe13SJamin Lin }
740*84f7ea6dSJamin Lin 
741*84f7ea6dSJamin Lin static void test_ast2600_evb(TestData *data)
742*84f7ea6dSJamin Lin {
743*84f7ea6dSJamin Lin     int ret;
744*84f7ea6dSJamin Lin     int fd;
745*84f7ea6dSJamin Lin 
746*84f7ea6dSJamin Lin     fd = g_file_open_tmp("qtest.m25p80.mx66u51235f.XXXXXX",
747*84f7ea6dSJamin Lin                          &data->tmp_path, NULL);
748*84f7ea6dSJamin Lin     g_assert(fd >= 0);
749*84f7ea6dSJamin Lin     ret = ftruncate(fd, 64 * 1024 * 1024);
750*84f7ea6dSJamin Lin     g_assert(ret == 0);
751*84f7ea6dSJamin Lin     close(fd);
752*84f7ea6dSJamin Lin 
753*84f7ea6dSJamin Lin     data->s = qtest_initf("-machine ast2600-evb "
754*84f7ea6dSJamin Lin                           "-drive file=%s,format=raw,if=mtd",
755*84f7ea6dSJamin Lin                           data->tmp_path);
756*84f7ea6dSJamin Lin 
757*84f7ea6dSJamin Lin     /* fmc cs0 with mx66u51235f flash */
758*84f7ea6dSJamin Lin     data->flash_base = 0x20000000;
759*84f7ea6dSJamin Lin     data->spi_base = 0x1E620000;
760*84f7ea6dSJamin Lin     data->jedec_id = 0xc2253a;
761*84f7ea6dSJamin Lin     data->cs = 0;
762*84f7ea6dSJamin Lin     data->node = "/machine/soc/fmc/ssi.0/child[0]";
763*84f7ea6dSJamin Lin     /* beyond 16MB */
764*84f7ea6dSJamin Lin     data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
765*84f7ea6dSJamin Lin 
766*84f7ea6dSJamin Lin     qtest_add_data_func("/ast2600/smc/read_jedec", data, test_read_jedec);
767*84f7ea6dSJamin Lin     qtest_add_data_func("/ast2600/smc/erase_sector", data, test_erase_sector);
768*84f7ea6dSJamin Lin     qtest_add_data_func("/ast2600/smc/erase_all",  data, test_erase_all);
769*84f7ea6dSJamin Lin     qtest_add_data_func("/ast2600/smc/write_page", data, test_write_page);
770*84f7ea6dSJamin Lin     qtest_add_data_func("/ast2600/smc/read_page_mem",
771*84f7ea6dSJamin Lin                         data, test_read_page_mem);
772*84f7ea6dSJamin Lin     qtest_add_data_func("/ast2600/smc/write_page_mem",
773*84f7ea6dSJamin Lin                         data, test_write_page_mem);
774*84f7ea6dSJamin Lin     qtest_add_data_func("/ast2600/smc/read_status_reg",
775*84f7ea6dSJamin Lin                         data, test_read_status_reg);
776*84f7ea6dSJamin Lin }
777755e984aSJamin Lin int main(int argc, char **argv)
778755e984aSJamin Lin {
779975d4bafSJamin Lin     TestData palmetto_data;
780658ebe13SJamin Lin     TestData ast2500_evb_data;
781*84f7ea6dSJamin Lin     TestData ast2600_evb_data;
782755e984aSJamin Lin     int ret;
783755e984aSJamin Lin 
784755e984aSJamin Lin     g_test_init(&argc, &argv, NULL);
785755e984aSJamin Lin 
786975d4bafSJamin Lin     test_palmetto_bmc(&palmetto_data);
787658ebe13SJamin Lin     test_ast2500_evb(&ast2500_evb_data);
788*84f7ea6dSJamin Lin     test_ast2600_evb(&ast2600_evb_data);
789975d4bafSJamin Lin     ret = g_test_run();
790975d4bafSJamin Lin 
791975d4bafSJamin Lin     qtest_quit(palmetto_data.s);
792658ebe13SJamin Lin     qtest_quit(ast2500_evb_data.s);
793*84f7ea6dSJamin Lin     qtest_quit(ast2600_evb_data.s);
794975d4bafSJamin Lin     unlink(palmetto_data.tmp_path);
795658ebe13SJamin Lin     unlink(ast2500_evb_data.tmp_path);
796*84f7ea6dSJamin Lin     unlink(ast2600_evb_data.tmp_path);
7977a2334f7SCédric Le Goater     return ret;
7987a2334f7SCédric Le Goater }
799