xref: /qemu/tests/qtest/aspeed_smc-test.c (revision 92a45bde8cf4257f755ce718fbf7db5f2d607a15)
17a2334f7SCédric Le Goater /*
27a2334f7SCédric Le Goater  * QTest testcase for the M25P80 Flash (Using the Aspeed SPI
37a2334f7SCédric Le Goater  * Controller)
47a2334f7SCédric Le Goater  *
57a2334f7SCédric Le Goater  * Copyright (C) 2016 IBM Corp.
67a2334f7SCédric Le Goater  *
77a2334f7SCédric Le Goater  * Permission is hereby granted, free of charge, to any person obtaining a copy
87a2334f7SCédric Le Goater  * of this software and associated documentation files (the "Software"), to deal
97a2334f7SCédric Le Goater  * in the Software without restriction, including without limitation the rights
107a2334f7SCédric Le Goater  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
117a2334f7SCédric Le Goater  * copies of the Software, and to permit persons to whom the Software is
127a2334f7SCédric Le Goater  * furnished to do so, subject to the following conditions:
137a2334f7SCédric Le Goater  *
147a2334f7SCédric Le Goater  * The above copyright notice and this permission notice shall be included in
157a2334f7SCédric Le Goater  * all copies or substantial portions of the Software.
167a2334f7SCédric Le Goater  *
177a2334f7SCédric Le Goater  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187a2334f7SCédric Le Goater  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197a2334f7SCédric Le Goater  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
207a2334f7SCédric Le Goater  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
217a2334f7SCédric Le Goater  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
227a2334f7SCédric Le Goater  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
237a2334f7SCédric Le Goater  * THE SOFTWARE.
247a2334f7SCédric Le Goater  */
257a2334f7SCédric Le Goater 
267a2334f7SCédric Le Goater #include "qemu/osdep.h"
277a2334f7SCédric Le Goater #include "qemu/bswap.h"
28dd210749SThomas Huth #include "libqtest-single.h"
29188052a1SIris Chen #include "qemu/bitops.h"
307a2334f7SCédric Le Goater 
317a2334f7SCédric Le Goater /*
327a2334f7SCédric Le Goater  * ASPEED SPI Controller registers
337a2334f7SCédric Le Goater  */
347a2334f7SCédric Le Goater #define R_CONF              0x00
357a2334f7SCédric Le Goater #define   CONF_ENABLE_W0       (1 << 16)
367a2334f7SCédric Le Goater #define R_CE_CTRL           0x04
377a2334f7SCédric Le Goater #define   CRTL_EXTENDED0       0  /* 32 bit addressing for SPI */
387a2334f7SCédric Le Goater #define R_CTRL0             0x10
397a2334f7SCédric Le Goater #define   CTRL_CE_STOP_ACTIVE  (1 << 2)
40371a3dd2SCédric Le Goater #define   CTRL_READMODE        0x0
41371a3dd2SCédric Le Goater #define   CTRL_FREADMODE       0x1
42371a3dd2SCédric Le Goater #define   CTRL_WRITEMODE       0x2
437a2334f7SCédric Le Goater #define   CTRL_USERMODE        0x3
44188052a1SIris Chen #define SR_WEL BIT(1)
457a2334f7SCédric Le Goater 
467a2334f7SCédric Le Goater #define ASPEED_FMC_BASE    0x1E620000
477a2334f7SCédric Le Goater #define ASPEED_FLASH_BASE  0x20000000
487a2334f7SCédric Le Goater 
497a2334f7SCédric Le Goater /*
507a2334f7SCédric Le Goater  * Flash commands
517a2334f7SCédric Le Goater  */
527a2334f7SCédric Le Goater enum {
537a2334f7SCédric Le Goater     JEDEC_READ = 0x9f,
54188052a1SIris Chen     RDSR = 0x5,
55188052a1SIris Chen     WRDI = 0x4,
567a2334f7SCédric Le Goater     BULK_ERASE = 0xc7,
577a2334f7SCédric Le Goater     READ = 0x03,
587a2334f7SCédric Le Goater     PP = 0x02,
597a2334f7SCédric Le Goater     WREN = 0x6,
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 
667a2334f7SCédric Le Goater #define FLASH_JEDEC         0x20ba19  /* n25q256a */
677a2334f7SCédric Le Goater #define FLASH_SIZE          (32 * 1024 * 1024)
687a2334f7SCédric Le Goater 
69d2c4f384SJiaxun Yang #define FLASH_PAGE_SIZE           256
707a2334f7SCédric Le Goater 
717a2334f7SCédric Le Goater /*
727a2334f7SCédric Le Goater  * Use an explicit bswap for the values read/wrote to the flash region
737a2334f7SCédric Le Goater  * as they are BE and the Aspeed CPU is LE.
747a2334f7SCédric Le Goater  */
757a2334f7SCédric Le Goater static inline uint32_t make_be32(uint32_t data)
767a2334f7SCédric Le Goater {
777a2334f7SCédric Le Goater     return bswap32(data);
787a2334f7SCédric Le Goater }
797a2334f7SCédric Le Goater 
807a2334f7SCédric Le Goater static void spi_conf(uint32_t value)
817a2334f7SCédric Le Goater {
827a2334f7SCédric Le Goater     uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
837a2334f7SCédric Le Goater 
847a2334f7SCédric Le Goater     conf |= value;
857a2334f7SCédric Le Goater     writel(ASPEED_FMC_BASE + R_CONF, conf);
867a2334f7SCédric Le Goater }
877a2334f7SCédric Le Goater 
88bd9f5052SCédric Le Goater static void spi_conf_remove(uint32_t value)
89bd9f5052SCédric Le Goater {
90bd9f5052SCédric Le Goater     uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
91bd9f5052SCédric Le Goater 
92bd9f5052SCédric Le Goater     conf &= ~value;
93bd9f5052SCédric Le Goater     writel(ASPEED_FMC_BASE + R_CONF, conf);
94bd9f5052SCédric Le Goater }
95bd9f5052SCédric Le Goater 
96371a3dd2SCédric Le Goater static void spi_ce_ctrl(uint32_t value)
97371a3dd2SCédric Le Goater {
98371a3dd2SCédric Le Goater     uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL);
99371a3dd2SCédric Le Goater 
100371a3dd2SCédric Le Goater     conf |= value;
101371a3dd2SCédric Le Goater     writel(ASPEED_FMC_BASE + R_CE_CTRL, conf);
102371a3dd2SCédric Le Goater }
103371a3dd2SCédric Le Goater 
104371a3dd2SCédric Le Goater static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd)
105371a3dd2SCédric Le Goater {
106371a3dd2SCédric Le Goater     uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
107371a3dd2SCédric Le Goater     ctrl &= ~(CTRL_USERMODE | 0xff << 16);
108371a3dd2SCédric Le Goater     ctrl |= mode | (cmd << 16);
109371a3dd2SCédric Le Goater     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
110371a3dd2SCédric Le Goater }
111371a3dd2SCédric Le Goater 
1127a2334f7SCédric Le Goater static void spi_ctrl_start_user(void)
1137a2334f7SCédric Le Goater {
1147a2334f7SCédric Le Goater     uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
1157a2334f7SCédric Le Goater 
1167a2334f7SCédric Le Goater     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
1177a2334f7SCédric Le Goater     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
1187a2334f7SCédric Le Goater 
1197a2334f7SCédric Le Goater     ctrl &= ~CTRL_CE_STOP_ACTIVE;
1207a2334f7SCédric Le Goater     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
1217a2334f7SCédric Le Goater }
1227a2334f7SCédric Le Goater 
1237a2334f7SCédric Le Goater static void spi_ctrl_stop_user(void)
1247a2334f7SCédric Le Goater {
1257a2334f7SCédric Le Goater     uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
1267a2334f7SCédric Le Goater 
1277a2334f7SCédric Le Goater     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
1287a2334f7SCédric Le Goater     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
1297a2334f7SCédric Le Goater }
1307a2334f7SCédric Le Goater 
131bd9f5052SCédric Le Goater static void flash_reset(void)
132bd9f5052SCédric Le Goater {
133bd9f5052SCédric Le Goater     spi_conf(CONF_ENABLE_W0);
134bd9f5052SCédric Le Goater 
135bd9f5052SCédric Le Goater     spi_ctrl_start_user();
136bd9f5052SCédric Le Goater     writeb(ASPEED_FLASH_BASE, RESET_ENABLE);
137bd9f5052SCédric Le Goater     writeb(ASPEED_FLASH_BASE, RESET_MEMORY);
138*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, WREN);
139*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, BULK_ERASE);
140*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, WRDI);
141bd9f5052SCédric Le Goater     spi_ctrl_stop_user();
142bd9f5052SCédric Le Goater 
143bd9f5052SCédric Le Goater     spi_conf_remove(CONF_ENABLE_W0);
144bd9f5052SCédric Le Goater }
145bd9f5052SCédric Le Goater 
1467a2334f7SCédric Le Goater static void test_read_jedec(void)
1477a2334f7SCédric Le Goater {
1487a2334f7SCédric Le Goater     uint32_t jedec = 0x0;
1497a2334f7SCédric Le Goater 
1507a2334f7SCédric Le Goater     spi_conf(CONF_ENABLE_W0);
1517a2334f7SCédric Le Goater 
1527a2334f7SCédric Le Goater     spi_ctrl_start_user();
1537a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, JEDEC_READ);
1547a2334f7SCédric Le Goater     jedec |= readb(ASPEED_FLASH_BASE) << 16;
1557a2334f7SCédric Le Goater     jedec |= readb(ASPEED_FLASH_BASE) << 8;
1567a2334f7SCédric Le Goater     jedec |= readb(ASPEED_FLASH_BASE);
1577a2334f7SCédric Le Goater     spi_ctrl_stop_user();
1587a2334f7SCédric Le Goater 
159bd9f5052SCédric Le Goater     flash_reset();
160bd9f5052SCédric Le Goater 
1617a2334f7SCédric Le Goater     g_assert_cmphex(jedec, ==, FLASH_JEDEC);
1627a2334f7SCédric Le Goater }
1637a2334f7SCédric Le Goater 
1647a2334f7SCédric Le Goater static void read_page(uint32_t addr, uint32_t *page)
1657a2334f7SCédric Le Goater {
1667a2334f7SCédric Le Goater     int i;
1677a2334f7SCédric Le Goater 
1687a2334f7SCédric Le Goater     spi_ctrl_start_user();
1697a2334f7SCédric Le Goater 
1707a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
1717a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, READ);
1727a2334f7SCédric Le Goater     writel(ASPEED_FLASH_BASE, make_be32(addr));
1737a2334f7SCédric Le Goater 
1747a2334f7SCédric Le Goater     /* Continuous read are supported */
175d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
1767a2334f7SCédric Le Goater         page[i] = make_be32(readl(ASPEED_FLASH_BASE));
1777a2334f7SCédric Le Goater     }
1787a2334f7SCédric Le Goater     spi_ctrl_stop_user();
1797a2334f7SCédric Le Goater }
1807a2334f7SCédric Le Goater 
181371a3dd2SCédric Le Goater static void read_page_mem(uint32_t addr, uint32_t *page)
182371a3dd2SCédric Le Goater {
183371a3dd2SCédric Le Goater     int i;
184371a3dd2SCédric Le Goater 
185371a3dd2SCédric Le Goater     /* move out USER mode to use direct reads from the AHB bus */
186371a3dd2SCédric Le Goater     spi_ctrl_setmode(CTRL_READMODE, READ);
187371a3dd2SCédric Le Goater 
188d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
189371a3dd2SCédric Le Goater         page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
190371a3dd2SCédric Le Goater     }
191371a3dd2SCédric Le Goater }
192371a3dd2SCédric Le Goater 
1937a2334f7SCédric Le Goater static void test_erase_sector(void)
1947a2334f7SCédric Le Goater {
195d2c4f384SJiaxun Yang     uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
196d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
1977a2334f7SCédric Le Goater     int i;
1987a2334f7SCédric Le Goater 
1997a2334f7SCédric Le Goater     spi_conf(CONF_ENABLE_W0);
2007a2334f7SCédric Le Goater 
201*92a45bdeSIris Chen     /*
202*92a45bdeSIris Chen      * Previous page should be full of 0xffs after backend is
203*92a45bdeSIris Chen      * initialized
204*92a45bdeSIris Chen      */
205*92a45bdeSIris Chen     read_page(some_page_addr - FLASH_PAGE_SIZE, page);
206*92a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
207*92a45bdeSIris Chen         g_assert_cmphex(page[i], ==, 0xffffffff);
208*92a45bdeSIris Chen     }
209*92a45bdeSIris Chen 
210*92a45bdeSIris Chen     spi_ctrl_start_user();
211*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
212*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, WREN);
213*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, PP);
214*92a45bdeSIris Chen     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
215*92a45bdeSIris Chen 
216*92a45bdeSIris Chen     /* Fill the page with its own addresses */
217*92a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
218*92a45bdeSIris Chen         writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
219*92a45bdeSIris Chen     }
220*92a45bdeSIris Chen     spi_ctrl_stop_user();
221*92a45bdeSIris Chen 
222*92a45bdeSIris Chen     /* Check the page is correctly written */
223*92a45bdeSIris Chen     read_page(some_page_addr, page);
224*92a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
225*92a45bdeSIris Chen         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
226*92a45bdeSIris Chen     }
227*92a45bdeSIris Chen 
2287a2334f7SCédric Le Goater     spi_ctrl_start_user();
2297a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, WREN);
2307a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
2317a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, ERASE_SECTOR);
2327a2334f7SCédric Le Goater     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
2337a2334f7SCédric Le Goater     spi_ctrl_stop_user();
2347a2334f7SCédric Le Goater 
235*92a45bdeSIris Chen     /* Check the page is erased */
2367a2334f7SCédric Le Goater     read_page(some_page_addr, page);
237d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
2387a2334f7SCédric Le Goater         g_assert_cmphex(page[i], ==, 0xffffffff);
2397a2334f7SCédric Le Goater     }
240bd9f5052SCédric Le Goater 
241bd9f5052SCédric Le Goater     flash_reset();
2427a2334f7SCédric Le Goater }
2437a2334f7SCédric Le Goater 
2447a2334f7SCédric Le Goater static void test_erase_all(void)
2457a2334f7SCédric Le Goater {
246d2c4f384SJiaxun Yang     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
247d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
2487a2334f7SCédric Le Goater     int i;
2497a2334f7SCédric Le Goater 
2507a2334f7SCédric Le Goater     spi_conf(CONF_ENABLE_W0);
2517a2334f7SCédric Le Goater 
252*92a45bdeSIris Chen     /*
253*92a45bdeSIris Chen      * Previous page should be full of 0xffs after backend is
254*92a45bdeSIris Chen      * initialized
255*92a45bdeSIris Chen      */
256*92a45bdeSIris Chen     read_page(some_page_addr - FLASH_PAGE_SIZE, page);
257*92a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
258*92a45bdeSIris Chen         g_assert_cmphex(page[i], ==, 0xffffffff);
259*92a45bdeSIris Chen     }
260*92a45bdeSIris Chen 
261*92a45bdeSIris Chen     spi_ctrl_start_user();
262*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
263*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, WREN);
264*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, PP);
265*92a45bdeSIris Chen     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
266*92a45bdeSIris Chen 
267*92a45bdeSIris Chen     /* Fill the page with its own addresses */
268*92a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
269*92a45bdeSIris Chen         writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
270*92a45bdeSIris Chen     }
271*92a45bdeSIris Chen     spi_ctrl_stop_user();
272*92a45bdeSIris Chen 
273*92a45bdeSIris Chen     /* Check the page is correctly written */
2747a2334f7SCédric Le Goater     read_page(some_page_addr, page);
275d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
276*92a45bdeSIris Chen         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
2777a2334f7SCédric Le Goater     }
2787a2334f7SCédric Le Goater 
2797a2334f7SCédric Le Goater     spi_ctrl_start_user();
2807a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, WREN);
2817a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, BULK_ERASE);
2827a2334f7SCédric Le Goater     spi_ctrl_stop_user();
2837a2334f7SCédric Le Goater 
284*92a45bdeSIris Chen     /* Check the page is erased */
2857a2334f7SCédric Le Goater     read_page(some_page_addr, page);
286d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
2877a2334f7SCédric Le Goater         g_assert_cmphex(page[i], ==, 0xffffffff);
2887a2334f7SCédric Le Goater     }
289bd9f5052SCédric Le Goater 
290bd9f5052SCédric Le Goater     flash_reset();
2917a2334f7SCédric Le Goater }
2927a2334f7SCédric Le Goater 
2937a2334f7SCédric Le Goater static void test_write_page(void)
2947a2334f7SCédric Le Goater {
295d2c4f384SJiaxun Yang     uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
296d2c4f384SJiaxun Yang     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
297d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
2987a2334f7SCédric Le Goater     int i;
2997a2334f7SCédric Le Goater 
3007a2334f7SCédric Le Goater     spi_conf(CONF_ENABLE_W0);
3017a2334f7SCédric Le Goater 
3027a2334f7SCédric Le Goater     spi_ctrl_start_user();
3037a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
304bd9f5052SCédric Le Goater     writeb(ASPEED_FLASH_BASE, WREN);
3057a2334f7SCédric Le Goater     writeb(ASPEED_FLASH_BASE, PP);
3067a2334f7SCédric Le Goater     writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
3077a2334f7SCédric Le Goater 
3087a2334f7SCédric Le Goater     /* Fill the page with its own addresses */
309d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
3107a2334f7SCédric Le Goater         writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
3117a2334f7SCédric Le Goater     }
3127a2334f7SCédric Le Goater     spi_ctrl_stop_user();
3137a2334f7SCédric Le Goater 
3147a2334f7SCédric Le Goater     /* Check what was written */
3157a2334f7SCédric Le Goater     read_page(my_page_addr, page);
316d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
3177a2334f7SCédric Le Goater         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
3187a2334f7SCédric Le Goater     }
3197a2334f7SCédric Le Goater 
3207a2334f7SCédric Le Goater     /* Check some other page. It should be full of 0xff */
3217a2334f7SCédric Le Goater     read_page(some_page_addr, page);
322d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
3237a2334f7SCédric Le Goater         g_assert_cmphex(page[i], ==, 0xffffffff);
3247a2334f7SCédric Le Goater     }
325bd9f5052SCédric Le Goater 
326bd9f5052SCédric Le Goater     flash_reset();
3277a2334f7SCédric Le Goater }
3287a2334f7SCédric Le Goater 
329371a3dd2SCédric Le Goater static void test_read_page_mem(void)
330371a3dd2SCédric Le Goater {
331d2c4f384SJiaxun Yang     uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
332d2c4f384SJiaxun Yang     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
333d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
334371a3dd2SCédric Le Goater     int i;
335371a3dd2SCédric Le Goater 
336371a3dd2SCédric Le Goater     /* Enable 4BYTE mode for controller. This is should be strapped by
337371a3dd2SCédric Le Goater      * HW for CE0 anyhow.
338371a3dd2SCédric Le Goater      */
339371a3dd2SCédric Le Goater     spi_ce_ctrl(1 << CRTL_EXTENDED0);
340371a3dd2SCédric Le Goater 
341371a3dd2SCédric Le Goater     /* Enable 4BYTE mode for flash. */
342371a3dd2SCédric Le Goater     spi_conf(CONF_ENABLE_W0);
343371a3dd2SCédric Le Goater     spi_ctrl_start_user();
344371a3dd2SCédric Le Goater     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
345*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, WREN);
346*92a45bdeSIris Chen     writeb(ASPEED_FLASH_BASE, PP);
347*92a45bdeSIris Chen     writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
348*92a45bdeSIris Chen 
349*92a45bdeSIris Chen     /* Fill the page with its own addresses */
350*92a45bdeSIris Chen     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
351*92a45bdeSIris Chen         writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
352*92a45bdeSIris Chen     }
353371a3dd2SCédric Le Goater     spi_ctrl_stop_user();
354371a3dd2SCédric Le Goater     spi_conf_remove(CONF_ENABLE_W0);
355371a3dd2SCédric Le Goater 
356371a3dd2SCédric Le Goater     /* Check what was written */
357371a3dd2SCédric Le Goater     read_page_mem(my_page_addr, page);
358d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
359371a3dd2SCédric Le Goater         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
360371a3dd2SCédric Le Goater     }
361371a3dd2SCédric Le Goater 
362371a3dd2SCédric Le Goater     /* Check some other page. It should be full of 0xff */
363371a3dd2SCédric Le Goater     read_page_mem(some_page_addr, page);
364d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
365371a3dd2SCédric Le Goater         g_assert_cmphex(page[i], ==, 0xffffffff);
366371a3dd2SCédric Le Goater     }
367371a3dd2SCédric Le Goater 
368371a3dd2SCédric Le Goater     flash_reset();
369371a3dd2SCédric Le Goater }
370371a3dd2SCédric Le Goater 
371371a3dd2SCédric Le Goater static void test_write_page_mem(void)
372371a3dd2SCédric Le Goater {
373d2c4f384SJiaxun Yang     uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
374d2c4f384SJiaxun Yang     uint32_t page[FLASH_PAGE_SIZE / 4];
375371a3dd2SCédric Le Goater     int i;
376371a3dd2SCédric Le Goater 
377371a3dd2SCédric Le Goater     /* Enable 4BYTE mode for controller. This is should be strapped by
378371a3dd2SCédric Le Goater      * HW for CE0 anyhow.
379371a3dd2SCédric Le Goater      */
380371a3dd2SCédric Le Goater     spi_ce_ctrl(1 << CRTL_EXTENDED0);
381371a3dd2SCédric Le Goater 
382371a3dd2SCédric Le Goater     /* Enable 4BYTE mode for flash. */
383371a3dd2SCédric Le Goater     spi_conf(CONF_ENABLE_W0);
384371a3dd2SCédric Le Goater     spi_ctrl_start_user();
385371a3dd2SCédric Le Goater     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
386371a3dd2SCédric Le Goater     writeb(ASPEED_FLASH_BASE, WREN);
387371a3dd2SCédric Le Goater     spi_ctrl_stop_user();
388371a3dd2SCédric Le Goater 
389371a3dd2SCédric Le Goater     /* move out USER mode to use direct writes to the AHB bus */
390371a3dd2SCédric Le Goater     spi_ctrl_setmode(CTRL_WRITEMODE, PP);
391371a3dd2SCédric Le Goater 
392d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
393371a3dd2SCédric Le Goater         writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
394371a3dd2SCédric Le Goater                make_be32(my_page_addr + i * 4));
395371a3dd2SCédric Le Goater     }
396371a3dd2SCédric Le Goater 
397371a3dd2SCédric Le Goater     /* Check what was written */
398371a3dd2SCédric Le Goater     read_page_mem(my_page_addr, page);
399d2c4f384SJiaxun Yang     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
400371a3dd2SCédric Le Goater         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
401371a3dd2SCédric Le Goater     }
402371a3dd2SCédric Le Goater 
403371a3dd2SCédric Le Goater     flash_reset();
404371a3dd2SCédric Le Goater }
405371a3dd2SCédric Le Goater 
406188052a1SIris Chen static void test_read_status_reg(void)
407188052a1SIris Chen {
408188052a1SIris Chen     uint8_t r;
409188052a1SIris Chen 
410188052a1SIris Chen     spi_conf(CONF_ENABLE_W0);
411188052a1SIris Chen 
412188052a1SIris Chen     spi_ctrl_start_user();
413188052a1SIris Chen     writeb(ASPEED_FLASH_BASE, RDSR);
414188052a1SIris Chen     r = readb(ASPEED_FLASH_BASE);
415188052a1SIris Chen     spi_ctrl_stop_user();
416188052a1SIris Chen 
417188052a1SIris Chen     g_assert_cmphex(r & SR_WEL, ==, 0);
418188052a1SIris Chen     g_assert(!qtest_qom_get_bool
419188052a1SIris Chen             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
420188052a1SIris Chen 
421188052a1SIris Chen     spi_ctrl_start_user();
422188052a1SIris Chen     writeb(ASPEED_FLASH_BASE, WREN);
423188052a1SIris Chen     writeb(ASPEED_FLASH_BASE, RDSR);
424188052a1SIris Chen     r = readb(ASPEED_FLASH_BASE);
425188052a1SIris Chen     spi_ctrl_stop_user();
426188052a1SIris Chen 
427188052a1SIris Chen     g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
428188052a1SIris Chen     g_assert(qtest_qom_get_bool
429188052a1SIris Chen             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
430188052a1SIris Chen 
431188052a1SIris Chen     spi_ctrl_start_user();
432188052a1SIris Chen     writeb(ASPEED_FLASH_BASE, WRDI);
433188052a1SIris Chen     writeb(ASPEED_FLASH_BASE, RDSR);
434188052a1SIris Chen     r = readb(ASPEED_FLASH_BASE);
435188052a1SIris Chen     spi_ctrl_stop_user();
436188052a1SIris Chen 
437188052a1SIris Chen     g_assert_cmphex(r & SR_WEL, ==, 0);
438188052a1SIris Chen     g_assert(!qtest_qom_get_bool
439188052a1SIris Chen             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
440188052a1SIris Chen 
441188052a1SIris Chen     flash_reset();
442188052a1SIris Chen }
443188052a1SIris Chen 
4447a2334f7SCédric Le Goater static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
4457a2334f7SCédric Le Goater 
4467a2334f7SCédric Le Goater int main(int argc, char **argv)
4477a2334f7SCédric Le Goater {
4487a2334f7SCédric Le Goater     int ret;
4497a2334f7SCédric Le Goater     int fd;
4507a2334f7SCédric Le Goater 
4517a2334f7SCédric Le Goater     g_test_init(&argc, &argv, NULL);
4527a2334f7SCédric Le Goater 
4537a2334f7SCédric Le Goater     fd = mkstemp(tmp_path);
4547a2334f7SCédric Le Goater     g_assert(fd >= 0);
4557a2334f7SCédric Le Goater     ret = ftruncate(fd, FLASH_SIZE);
4567a2334f7SCédric Le Goater     g_assert(ret == 0);
4577a2334f7SCédric Le Goater     close(fd);
4587a2334f7SCédric Le Goater 
45988b988c8SMarkus Armbruster     global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
4607a2334f7SCédric Le Goater                                "-drive file=%s,format=raw,if=mtd",
4617a2334f7SCédric Le Goater                                tmp_path);
4627a2334f7SCédric Le Goater 
4635fde7f10SCédric Le Goater     qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec);
4645fde7f10SCédric Le Goater     qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector);
4655fde7f10SCédric Le Goater     qtest_add_func("/ast2400/smc/erase_all",  test_erase_all);
4665fde7f10SCédric Le Goater     qtest_add_func("/ast2400/smc/write_page", test_write_page);
4675fde7f10SCédric Le Goater     qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
4685fde7f10SCédric Le Goater     qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
469188052a1SIris Chen     qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg);
4707a2334f7SCédric Le Goater 
471*92a45bdeSIris Chen     flash_reset();
4727a2334f7SCédric Le Goater     ret = g_test_run();
4737a2334f7SCédric Le Goater 
4747a2334f7SCédric Le Goater     qtest_quit(global_qtest);
4757a2334f7SCédric Le Goater     unlink(tmp_path);
4767a2334f7SCédric Le Goater     return ret;
4777a2334f7SCédric Le Goater }
478