xref: /openbmc/qemu/tests/qtest/aspeed_smc-test.c (revision 6d17020a)
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 test_erase_sector(void)
196 {
197     uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
198     uint32_t page[FLASH_PAGE_SIZE / 4];
199     int i;
200 
201     spi_conf(CONF_ENABLE_W0);
202 
203     /*
204      * Previous page should be full of 0xffs after backend is
205      * initialized
206      */
207     read_page(some_page_addr - FLASH_PAGE_SIZE, page);
208     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
209         g_assert_cmphex(page[i], ==, 0xffffffff);
210     }
211 
212     spi_ctrl_start_user();
213     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
214     writeb(ASPEED_FLASH_BASE, WREN);
215     writeb(ASPEED_FLASH_BASE, PP);
216     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
217 
218     /* Fill the page with its own addresses */
219     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
220         writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
221     }
222     spi_ctrl_stop_user();
223 
224     /* Check the page is correctly written */
225     read_page(some_page_addr, page);
226     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
227         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
228     }
229 
230     spi_ctrl_start_user();
231     writeb(ASPEED_FLASH_BASE, WREN);
232     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
233     writeb(ASPEED_FLASH_BASE, ERASE_SECTOR);
234     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
235     spi_ctrl_stop_user();
236 
237     /* Check the page is erased */
238     read_page(some_page_addr, page);
239     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
240         g_assert_cmphex(page[i], ==, 0xffffffff);
241     }
242 
243     flash_reset();
244 }
245 
246 static void test_erase_all(void)
247 {
248     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
249     uint32_t page[FLASH_PAGE_SIZE / 4];
250     int i;
251 
252     spi_conf(CONF_ENABLE_W0);
253 
254     /*
255      * Previous page should be full of 0xffs after backend is
256      * initialized
257      */
258     read_page(some_page_addr - FLASH_PAGE_SIZE, page);
259     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
260         g_assert_cmphex(page[i], ==, 0xffffffff);
261     }
262 
263     spi_ctrl_start_user();
264     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
265     writeb(ASPEED_FLASH_BASE, WREN);
266     writeb(ASPEED_FLASH_BASE, PP);
267     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
268 
269     /* Fill the page with its own addresses */
270     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
271         writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
272     }
273     spi_ctrl_stop_user();
274 
275     /* Check the page is correctly written */
276     read_page(some_page_addr, page);
277     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
278         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
279     }
280 
281     spi_ctrl_start_user();
282     writeb(ASPEED_FLASH_BASE, WREN);
283     writeb(ASPEED_FLASH_BASE, BULK_ERASE);
284     spi_ctrl_stop_user();
285 
286     /* Check the page is erased */
287     read_page(some_page_addr, page);
288     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
289         g_assert_cmphex(page[i], ==, 0xffffffff);
290     }
291 
292     flash_reset();
293 }
294 
295 static void test_write_page(void)
296 {
297     uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
298     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
299     uint32_t page[FLASH_PAGE_SIZE / 4];
300     int i;
301 
302     spi_conf(CONF_ENABLE_W0);
303 
304     spi_ctrl_start_user();
305     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
306     writeb(ASPEED_FLASH_BASE, WREN);
307     writeb(ASPEED_FLASH_BASE, PP);
308     writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
309 
310     /* Fill the page with its own addresses */
311     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
312         writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
313     }
314     spi_ctrl_stop_user();
315 
316     /* Check what was written */
317     read_page(my_page_addr, page);
318     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
319         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
320     }
321 
322     /* Check some other page. It should be full of 0xff */
323     read_page(some_page_addr, page);
324     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
325         g_assert_cmphex(page[i], ==, 0xffffffff);
326     }
327 
328     flash_reset();
329 }
330 
331 static void test_read_page_mem(void)
332 {
333     uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
334     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
335     uint32_t page[FLASH_PAGE_SIZE / 4];
336     int i;
337 
338     /* Enable 4BYTE mode for controller. This is should be strapped by
339      * HW for CE0 anyhow.
340      */
341     spi_ce_ctrl(1 << CRTL_EXTENDED0);
342 
343     /* Enable 4BYTE mode for flash. */
344     spi_conf(CONF_ENABLE_W0);
345     spi_ctrl_start_user();
346     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
347     writeb(ASPEED_FLASH_BASE, WREN);
348     writeb(ASPEED_FLASH_BASE, PP);
349     writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
350 
351     /* Fill the page with its own addresses */
352     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
353         writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
354     }
355     spi_ctrl_stop_user();
356     spi_conf_remove(CONF_ENABLE_W0);
357 
358     /* Check what was written */
359     read_page_mem(my_page_addr, page);
360     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
361         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
362     }
363 
364     /* Check some other page. It should be full of 0xff */
365     read_page_mem(some_page_addr, page);
366     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
367         g_assert_cmphex(page[i], ==, 0xffffffff);
368     }
369 
370     flash_reset();
371 }
372 
373 static void test_write_page_mem(void)
374 {
375     uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
376     uint32_t page[FLASH_PAGE_SIZE / 4];
377     int i;
378 
379     /* Enable 4BYTE mode for controller. This is should be strapped by
380      * HW for CE0 anyhow.
381      */
382     spi_ce_ctrl(1 << CRTL_EXTENDED0);
383 
384     /* Enable 4BYTE mode for flash. */
385     spi_conf(CONF_ENABLE_W0);
386     spi_ctrl_start_user();
387     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
388     writeb(ASPEED_FLASH_BASE, WREN);
389     spi_ctrl_stop_user();
390 
391     /* move out USER mode to use direct writes to the AHB bus */
392     spi_ctrl_setmode(CTRL_WRITEMODE, PP);
393 
394     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
395         writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
396                make_be32(my_page_addr + i * 4));
397     }
398 
399     /* Check what was written */
400     read_page_mem(my_page_addr, page);
401     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
402         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
403     }
404 
405     flash_reset();
406 }
407 
408 static void test_read_status_reg(void)
409 {
410     uint8_t r;
411 
412     spi_conf(CONF_ENABLE_W0);
413 
414     spi_ctrl_start_user();
415     writeb(ASPEED_FLASH_BASE, RDSR);
416     r = readb(ASPEED_FLASH_BASE);
417     spi_ctrl_stop_user();
418 
419     g_assert_cmphex(r & SR_WEL, ==, 0);
420     g_assert(!qtest_qom_get_bool
421             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
422 
423     spi_ctrl_start_user();
424     writeb(ASPEED_FLASH_BASE, WREN);
425     writeb(ASPEED_FLASH_BASE, RDSR);
426     r = readb(ASPEED_FLASH_BASE);
427     spi_ctrl_stop_user();
428 
429     g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
430     g_assert(qtest_qom_get_bool
431             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
432 
433     spi_ctrl_start_user();
434     writeb(ASPEED_FLASH_BASE, WRDI);
435     writeb(ASPEED_FLASH_BASE, RDSR);
436     r = readb(ASPEED_FLASH_BASE);
437     spi_ctrl_stop_user();
438 
439     g_assert_cmphex(r & SR_WEL, ==, 0);
440     g_assert(!qtest_qom_get_bool
441             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
442 
443     flash_reset();
444 }
445 
446 static void test_status_reg_write_protection(void)
447 {
448     uint8_t r;
449 
450     spi_conf(CONF_ENABLE_W0);
451 
452     /* default case: WP# is high and SRWD is low -> status register writable */
453     spi_ctrl_start_user();
454     writeb(ASPEED_FLASH_BASE, WREN);
455     /* test ability to write SRWD */
456     writeb(ASPEED_FLASH_BASE, WRSR);
457     writeb(ASPEED_FLASH_BASE, SRWD);
458     writeb(ASPEED_FLASH_BASE, RDSR);
459     r = readb(ASPEED_FLASH_BASE);
460     spi_ctrl_stop_user();
461     g_assert_cmphex(r & SRWD, ==, SRWD);
462 
463     /* WP# high and SRWD high -> status register writable */
464     spi_ctrl_start_user();
465     writeb(ASPEED_FLASH_BASE, WREN);
466     /* test ability to write SRWD */
467     writeb(ASPEED_FLASH_BASE, WRSR);
468     writeb(ASPEED_FLASH_BASE, 0);
469     writeb(ASPEED_FLASH_BASE, RDSR);
470     r = readb(ASPEED_FLASH_BASE);
471     spi_ctrl_stop_user();
472     g_assert_cmphex(r & SRWD, ==, 0);
473 
474     /* WP# low and SRWD low -> status register writable */
475     qtest_set_irq_in(global_qtest,
476                      "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 0);
477     spi_ctrl_start_user();
478     writeb(ASPEED_FLASH_BASE, WREN);
479     /* test ability to write SRWD */
480     writeb(ASPEED_FLASH_BASE, WRSR);
481     writeb(ASPEED_FLASH_BASE, SRWD);
482     writeb(ASPEED_FLASH_BASE, RDSR);
483     r = readb(ASPEED_FLASH_BASE);
484     spi_ctrl_stop_user();
485     g_assert_cmphex(r & SRWD, ==, SRWD);
486 
487     /* WP# low and SRWD high -> status register NOT writable */
488     spi_ctrl_start_user();
489     writeb(ASPEED_FLASH_BASE, WREN);
490     /* test ability to write SRWD */
491     writeb(ASPEED_FLASH_BASE, WRSR);
492     writeb(ASPEED_FLASH_BASE, 0);
493     writeb(ASPEED_FLASH_BASE, RDSR);
494     r = readb(ASPEED_FLASH_BASE);
495     spi_ctrl_stop_user();
496     /* write is not successful */
497     g_assert_cmphex(r & SRWD, ==, SRWD);
498 
499     qtest_set_irq_in(global_qtest,
500                      "/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 1);
501     flash_reset();
502 }
503 
504 static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
505 
506 int main(int argc, char **argv)
507 {
508     int ret;
509     int fd;
510 
511     g_test_init(&argc, &argv, NULL);
512 
513     fd = mkstemp(tmp_path);
514     g_assert(fd >= 0);
515     ret = ftruncate(fd, FLASH_SIZE);
516     g_assert(ret == 0);
517     close(fd);
518 
519     global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
520                                "-drive file=%s,format=raw,if=mtd",
521                                tmp_path);
522 
523     qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec);
524     qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector);
525     qtest_add_func("/ast2400/smc/erase_all",  test_erase_all);
526     qtest_add_func("/ast2400/smc/write_page", test_write_page);
527     qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
528     qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
529     qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg);
530     qtest_add_func("/ast2400/smc/status_reg_write_protection",
531                    test_status_reg_write_protection);
532 
533     flash_reset();
534     ret = g_test_run();
535 
536     qtest_quit(global_qtest);
537     unlink(tmp_path);
538     return ret;
539 }
540