xref: /qemu/tests/qtest/aspeed_smc-test.c (revision 08479f0ca01414aadf513717ba3e1258321e6513)
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