xref: /openbmc/qemu/tests/qtest/aspeed_smc-test.c (revision 764a6ee9)
1 /*
2  * QTest testcase for the M25P80 Flash (Using the Aspeed SPI
3  * Controller)
4  *
5  * Copyright (C) 2016 IBM Corp.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 
26 #include "qemu/osdep.h"
27 #include "qemu/bswap.h"
28 #include "libqtest-single.h"
29 #include "qemu/bitops.h"
30 
31 /*
32  * ASPEED SPI Controller registers
33  */
34 #define R_CONF              0x00
35 #define   CONF_ENABLE_W0       (1 << 16)
36 #define R_CE_CTRL           0x04
37 #define   CRTL_EXTENDED0       0  /* 32 bit addressing for SPI */
38 #define R_CTRL0             0x10
39 #define   CTRL_CE_STOP_ACTIVE  (1 << 2)
40 #define   CTRL_READMODE        0x0
41 #define   CTRL_FREADMODE       0x1
42 #define   CTRL_WRITEMODE       0x2
43 #define   CTRL_USERMODE        0x3
44 #define SR_WEL BIT(1)
45 
46 #define ASPEED_FMC_BASE    0x1E620000
47 #define ASPEED_FLASH_BASE  0x20000000
48 
49 /*
50  * Flash commands
51  */
52 enum {
53     JEDEC_READ = 0x9f,
54     RDSR = 0x5,
55     WRDI = 0x4,
56     BULK_ERASE = 0xc7,
57     READ = 0x03,
58     PP = 0x02,
59     WRSR = 0x1,
60     WREN = 0x6,
61     SRWD = 0x80,
62     RESET_ENABLE = 0x66,
63     RESET_MEMORY = 0x99,
64     EN_4BYTE_ADDR = 0xB7,
65     ERASE_SECTOR = 0xd8,
66 };
67 
68 #define FLASH_JEDEC         0x20ba19  /* n25q256a */
69 #define FLASH_SIZE          (32 * 1024 * 1024)
70 
71 #define FLASH_PAGE_SIZE           256
72 
73 /*
74  * Use an explicit bswap for the values read/wrote to the flash region
75  * as they are BE and the Aspeed CPU is LE.
76  */
77 static inline uint32_t make_be32(uint32_t data)
78 {
79     return bswap32(data);
80 }
81 
82 static void spi_conf(uint32_t value)
83 {
84     uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
85 
86     conf |= value;
87     writel(ASPEED_FMC_BASE + R_CONF, conf);
88 }
89 
90 static void spi_conf_remove(uint32_t value)
91 {
92     uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
93 
94     conf &= ~value;
95     writel(ASPEED_FMC_BASE + R_CONF, conf);
96 }
97 
98 static void spi_ce_ctrl(uint32_t value)
99 {
100     uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL);
101 
102     conf |= value;
103     writel(ASPEED_FMC_BASE + R_CE_CTRL, conf);
104 }
105 
106 static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd)
107 {
108     uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
109     ctrl &= ~(CTRL_USERMODE | 0xff << 16);
110     ctrl |= mode | (cmd << 16);
111     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
112 }
113 
114 static void spi_ctrl_start_user(void)
115 {
116     uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
117 
118     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
119     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
120 
121     ctrl &= ~CTRL_CE_STOP_ACTIVE;
122     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
123 }
124 
125 static void spi_ctrl_stop_user(void)
126 {
127     uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
128 
129     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
130     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
131 }
132 
133 static void flash_reset(void)
134 {
135     spi_conf(CONF_ENABLE_W0);
136 
137     spi_ctrl_start_user();
138     writeb(ASPEED_FLASH_BASE, RESET_ENABLE);
139     writeb(ASPEED_FLASH_BASE, RESET_MEMORY);
140     writeb(ASPEED_FLASH_BASE, WREN);
141     writeb(ASPEED_FLASH_BASE, BULK_ERASE);
142     writeb(ASPEED_FLASH_BASE, WRDI);
143     spi_ctrl_stop_user();
144 
145     spi_conf_remove(CONF_ENABLE_W0);
146 }
147 
148 static void test_read_jedec(void)
149 {
150     uint32_t jedec = 0x0;
151 
152     spi_conf(CONF_ENABLE_W0);
153 
154     spi_ctrl_start_user();
155     writeb(ASPEED_FLASH_BASE, JEDEC_READ);
156     jedec |= readb(ASPEED_FLASH_BASE) << 16;
157     jedec |= readb(ASPEED_FLASH_BASE) << 8;
158     jedec |= readb(ASPEED_FLASH_BASE);
159     spi_ctrl_stop_user();
160 
161     flash_reset();
162 
163     g_assert_cmphex(jedec, ==, FLASH_JEDEC);
164 }
165 
166 static void read_page(uint32_t addr, uint32_t *page)
167 {
168     int i;
169 
170     spi_ctrl_start_user();
171 
172     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
173     writeb(ASPEED_FLASH_BASE, READ);
174     writel(ASPEED_FLASH_BASE, make_be32(addr));
175 
176     /* Continuous read are supported */
177     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
178         page[i] = make_be32(readl(ASPEED_FLASH_BASE));
179     }
180     spi_ctrl_stop_user();
181 }
182 
183 static void read_page_mem(uint32_t addr, uint32_t *page)
184 {
185     int i;
186 
187     /* move out USER mode to use direct reads from the AHB bus */
188     spi_ctrl_setmode(CTRL_READMODE, READ);
189 
190     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
191         page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
192     }
193 }
194 
195 static void write_page_mem(uint32_t addr, uint32_t write_value)
196 {
197     spi_ctrl_setmode(CTRL_WRITEMODE, PP);
198 
199     for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
200         writel(ASPEED_FLASH_BASE + addr + i * 4, write_value);
201     }
202 }
203 
204 static void assert_page_mem(uint32_t addr, uint32_t expected_value)
205 {
206     uint32_t page[FLASH_PAGE_SIZE / 4];
207     read_page_mem(addr, page);
208     for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
209         g_assert_cmphex(page[i], ==, expected_value);
210     }
211 }
212 
213 static void test_erase_sector(void)
214 {
215     uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
216     uint32_t page[FLASH_PAGE_SIZE / 4];
217     int i;
218 
219     spi_conf(CONF_ENABLE_W0);
220 
221     /*
222      * Previous page should be full of 0xffs after backend is
223      * initialized
224      */
225     read_page(some_page_addr - FLASH_PAGE_SIZE, page);
226     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
227         g_assert_cmphex(page[i], ==, 0xffffffff);
228     }
229 
230     spi_ctrl_start_user();
231     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
232     writeb(ASPEED_FLASH_BASE, WREN);
233     writeb(ASPEED_FLASH_BASE, PP);
234     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
235 
236     /* Fill the page with its own addresses */
237     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
238         writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
239     }
240     spi_ctrl_stop_user();
241 
242     /* Check the page is correctly written */
243     read_page(some_page_addr, page);
244     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
245         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
246     }
247 
248     spi_ctrl_start_user();
249     writeb(ASPEED_FLASH_BASE, WREN);
250     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
251     writeb(ASPEED_FLASH_BASE, ERASE_SECTOR);
252     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
253     spi_ctrl_stop_user();
254 
255     /* Check the page is erased */
256     read_page(some_page_addr, page);
257     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
258         g_assert_cmphex(page[i], ==, 0xffffffff);
259     }
260 
261     flash_reset();
262 }
263 
264 static void test_erase_all(void)
265 {
266     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
267     uint32_t page[FLASH_PAGE_SIZE / 4];
268     int i;
269 
270     spi_conf(CONF_ENABLE_W0);
271 
272     /*
273      * Previous page should be full of 0xffs after backend is
274      * initialized
275      */
276     read_page(some_page_addr - FLASH_PAGE_SIZE, page);
277     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
278         g_assert_cmphex(page[i], ==, 0xffffffff);
279     }
280 
281     spi_ctrl_start_user();
282     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
283     writeb(ASPEED_FLASH_BASE, WREN);
284     writeb(ASPEED_FLASH_BASE, PP);
285     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
286 
287     /* Fill the page with its own addresses */
288     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
289         writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
290     }
291     spi_ctrl_stop_user();
292 
293     /* Check the page is correctly written */
294     read_page(some_page_addr, page);
295     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
296         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
297     }
298 
299     spi_ctrl_start_user();
300     writeb(ASPEED_FLASH_BASE, WREN);
301     writeb(ASPEED_FLASH_BASE, BULK_ERASE);
302     spi_ctrl_stop_user();
303 
304     /* Check the page is erased */
305     read_page(some_page_addr, page);
306     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
307         g_assert_cmphex(page[i], ==, 0xffffffff);
308     }
309 
310     flash_reset();
311 }
312 
313 static void test_write_page(void)
314 {
315     uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
316     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
317     uint32_t page[FLASH_PAGE_SIZE / 4];
318     int i;
319 
320     spi_conf(CONF_ENABLE_W0);
321 
322     spi_ctrl_start_user();
323     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
324     writeb(ASPEED_FLASH_BASE, WREN);
325     writeb(ASPEED_FLASH_BASE, PP);
326     writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
327 
328     /* Fill the page with its own addresses */
329     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
330         writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
331     }
332     spi_ctrl_stop_user();
333 
334     /* Check what was written */
335     read_page(my_page_addr, page);
336     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
337         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
338     }
339 
340     /* Check some other page. It should be full of 0xff */
341     read_page(some_page_addr, page);
342     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
343         g_assert_cmphex(page[i], ==, 0xffffffff);
344     }
345 
346     flash_reset();
347 }
348 
349 static void test_read_page_mem(void)
350 {
351     uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
352     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
353     uint32_t page[FLASH_PAGE_SIZE / 4];
354     int i;
355 
356     /* Enable 4BYTE mode for controller. This is should be strapped by
357      * HW for CE0 anyhow.
358      */
359     spi_ce_ctrl(1 << CRTL_EXTENDED0);
360 
361     /* Enable 4BYTE mode for flash. */
362     spi_conf(CONF_ENABLE_W0);
363     spi_ctrl_start_user();
364     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
365     writeb(ASPEED_FLASH_BASE, WREN);
366     writeb(ASPEED_FLASH_BASE, PP);
367     writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
368 
369     /* Fill the page with its own addresses */
370     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
371         writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
372     }
373     spi_ctrl_stop_user();
374     spi_conf_remove(CONF_ENABLE_W0);
375 
376     /* Check what was written */
377     read_page_mem(my_page_addr, page);
378     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
379         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
380     }
381 
382     /* Check some other page. It should be full of 0xff */
383     read_page_mem(some_page_addr, page);
384     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
385         g_assert_cmphex(page[i], ==, 0xffffffff);
386     }
387 
388     flash_reset();
389 }
390 
391 static void test_write_page_mem(void)
392 {
393     uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
394     uint32_t page[FLASH_PAGE_SIZE / 4];
395     int i;
396 
397     /* Enable 4BYTE mode for controller. This is should be strapped by
398      * HW for CE0 anyhow.
399      */
400     spi_ce_ctrl(1 << CRTL_EXTENDED0);
401 
402     /* Enable 4BYTE mode for flash. */
403     spi_conf(CONF_ENABLE_W0);
404     spi_ctrl_start_user();
405     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
406     writeb(ASPEED_FLASH_BASE, WREN);
407     spi_ctrl_stop_user();
408 
409     /* move out USER mode to use direct writes to the AHB bus */
410     spi_ctrl_setmode(CTRL_WRITEMODE, PP);
411 
412     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
413         writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
414                make_be32(my_page_addr + i * 4));
415     }
416 
417     /* Check what was written */
418     read_page_mem(my_page_addr, page);
419     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
420         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
421     }
422 
423     flash_reset();
424 }
425 
426 static void test_read_status_reg(void)
427 {
428     uint8_t r;
429 
430     spi_conf(CONF_ENABLE_W0);
431 
432     spi_ctrl_start_user();
433     writeb(ASPEED_FLASH_BASE, RDSR);
434     r = readb(ASPEED_FLASH_BASE);
435     spi_ctrl_stop_user();
436 
437     g_assert_cmphex(r & SR_WEL, ==, 0);
438     g_assert(!qtest_qom_get_bool
439             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
440 
441     spi_ctrl_start_user();
442     writeb(ASPEED_FLASH_BASE, WREN);
443     writeb(ASPEED_FLASH_BASE, RDSR);
444     r = readb(ASPEED_FLASH_BASE);
445     spi_ctrl_stop_user();
446 
447     g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
448     g_assert(qtest_qom_get_bool
449             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
450 
451     spi_ctrl_start_user();
452     writeb(ASPEED_FLASH_BASE, WRDI);
453     writeb(ASPEED_FLASH_BASE, RDSR);
454     r = readb(ASPEED_FLASH_BASE);
455     spi_ctrl_stop_user();
456 
457     g_assert_cmphex(r & SR_WEL, ==, 0);
458     g_assert(!qtest_qom_get_bool
459             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
460 
461     flash_reset();
462 }
463 
464 static void test_status_reg_write_protection(void)
465 {
466     uint8_t r;
467 
468     spi_conf(CONF_ENABLE_W0);
469 
470     /* default case: WP# is high and SRWD is low -> status register writable */
471     spi_ctrl_start_user();
472     writeb(ASPEED_FLASH_BASE, WREN);
473     /* test ability to write SRWD */
474     writeb(ASPEED_FLASH_BASE, WRSR);
475     writeb(ASPEED_FLASH_BASE, SRWD);
476     writeb(ASPEED_FLASH_BASE, RDSR);
477     r = readb(ASPEED_FLASH_BASE);
478     spi_ctrl_stop_user();
479     g_assert_cmphex(r & SRWD, ==, SRWD);
480 
481     /* WP# high and SRWD high -> status register writable */
482     spi_ctrl_start_user();
483     writeb(ASPEED_FLASH_BASE, WREN);
484     /* test ability to write SRWD */
485     writeb(ASPEED_FLASH_BASE, WRSR);
486     writeb(ASPEED_FLASH_BASE, 0);
487     writeb(ASPEED_FLASH_BASE, RDSR);
488     r = readb(ASPEED_FLASH_BASE);
489     spi_ctrl_stop_user();
490     g_assert_cmphex(r & SRWD, ==, 0);
491 
492     /* WP# low and SRWD low -> status register writable */
493     qtest_set_irq_in(global_qtest,
494                      "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 0);
495     spi_ctrl_start_user();
496     writeb(ASPEED_FLASH_BASE, WREN);
497     /* test ability to write SRWD */
498     writeb(ASPEED_FLASH_BASE, WRSR);
499     writeb(ASPEED_FLASH_BASE, SRWD);
500     writeb(ASPEED_FLASH_BASE, RDSR);
501     r = readb(ASPEED_FLASH_BASE);
502     spi_ctrl_stop_user();
503     g_assert_cmphex(r & SRWD, ==, SRWD);
504 
505     /* WP# low and SRWD high -> status register NOT writable */
506     spi_ctrl_start_user();
507     writeb(ASPEED_FLASH_BASE, WREN);
508     /* test ability to write SRWD */
509     writeb(ASPEED_FLASH_BASE, WRSR);
510     writeb(ASPEED_FLASH_BASE, 0);
511     writeb(ASPEED_FLASH_BASE, RDSR);
512     r = readb(ASPEED_FLASH_BASE);
513     spi_ctrl_stop_user();
514     /* write is not successful */
515     g_assert_cmphex(r & SRWD, ==, SRWD);
516 
517     qtest_set_irq_in(global_qtest,
518                      "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 1);
519     flash_reset();
520 }
521 
522 static void test_write_block_protect(void)
523 {
524     uint32_t sector_size = 65536;
525     uint32_t n_sectors = 512;
526 
527     spi_ce_ctrl(1 << CRTL_EXTENDED0);
528     spi_conf(CONF_ENABLE_W0);
529 
530     uint32_t bp_bits = 0b0;
531 
532     for (int i = 0; i < 16; i++) {
533         bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
534 
535         spi_ctrl_start_user();
536         writeb(ASPEED_FLASH_BASE, WREN);
537         writeb(ASPEED_FLASH_BASE, BULK_ERASE);
538         writeb(ASPEED_FLASH_BASE, WREN);
539         writeb(ASPEED_FLASH_BASE, WRSR);
540         writeb(ASPEED_FLASH_BASE, bp_bits);
541         writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
542         writeb(ASPEED_FLASH_BASE, WREN);
543         spi_ctrl_stop_user();
544 
545         uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
546         uint32_t protection_start = n_sectors - num_protected_sectors;
547         uint32_t protection_end = n_sectors;
548 
549         for (int sector = 0; sector < n_sectors; sector++) {
550             uint32_t addr = sector * sector_size;
551 
552             assert_page_mem(addr, 0xffffffff);
553             write_page_mem(addr, make_be32(0xabcdef12));
554 
555             uint32_t expected_value = protection_start <= sector
556                                       && sector < protection_end
557                                       ? 0xffffffff : 0xabcdef12;
558 
559             assert_page_mem(addr, expected_value);
560         }
561     }
562 
563     flash_reset();
564 }
565 
566 static void test_write_block_protect_bottom_bit(void)
567 {
568     uint32_t sector_size = 65536;
569     uint32_t n_sectors = 512;
570 
571     spi_ce_ctrl(1 << CRTL_EXTENDED0);
572     spi_conf(CONF_ENABLE_W0);
573 
574     /* top bottom bit is enabled */
575     uint32_t bp_bits = 0b00100 << 3;
576 
577     for (int i = 0; i < 16; i++) {
578         bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2);
579 
580         spi_ctrl_start_user();
581         writeb(ASPEED_FLASH_BASE, WREN);
582         writeb(ASPEED_FLASH_BASE, BULK_ERASE);
583         writeb(ASPEED_FLASH_BASE, WREN);
584         writeb(ASPEED_FLASH_BASE, WRSR);
585         writeb(ASPEED_FLASH_BASE, bp_bits);
586         writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
587         writeb(ASPEED_FLASH_BASE, WREN);
588         spi_ctrl_stop_user();
589 
590         uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
591         uint32_t protection_start = 0;
592         uint32_t protection_end = num_protected_sectors;
593 
594         for (int sector = 0; sector < n_sectors; sector++) {
595             uint32_t addr = sector * sector_size;
596 
597             assert_page_mem(addr, 0xffffffff);
598             write_page_mem(addr, make_be32(0xabcdef12));
599 
600             uint32_t expected_value = protection_start <= sector
601                                       && sector < protection_end
602                                       ? 0xffffffff : 0xabcdef12;
603 
604             assert_page_mem(addr, expected_value);
605         }
606     }
607 
608     flash_reset();
609 }
610 
611 int main(int argc, char **argv)
612 {
613     g_autofree char *tmp_path = NULL;
614     int ret;
615     int fd;
616 
617     g_test_init(&argc, &argv, NULL);
618 
619     fd = g_file_open_tmp("qtest.m25p80.XXXXXX", &tmp_path, NULL);
620     g_assert(fd >= 0);
621     ret = ftruncate(fd, FLASH_SIZE);
622     g_assert(ret == 0);
623     close(fd);
624 
625     global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
626                                "-drive file=%s,format=raw,if=mtd",
627                                tmp_path);
628 
629     qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec);
630     qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector);
631     qtest_add_func("/ast2400/smc/erase_all",  test_erase_all);
632     qtest_add_func("/ast2400/smc/write_page", test_write_page);
633     qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
634     qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
635     qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg);
636     qtest_add_func("/ast2400/smc/status_reg_write_protection",
637                    test_status_reg_write_protection);
638     qtest_add_func("/ast2400/smc/write_block_protect",
639                    test_write_block_protect);
640     qtest_add_func("/ast2400/smc/write_block_protect_bottom_bit",
641                    test_write_block_protect_bottom_bit);
642 
643     flash_reset();
644     ret = g_test_run();
645 
646     qtest_quit(global_qtest);
647     unlink(tmp_path);
648     return ret;
649 }
650