xref: /openbmc/qemu/tests/qtest/aspeed_smc-test.c (revision ed3a06b1)
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     WREN = 0x6,
60     RESET_ENABLE = 0x66,
61     RESET_MEMORY = 0x99,
62     EN_4BYTE_ADDR = 0xB7,
63     ERASE_SECTOR = 0xd8,
64 };
65 
66 #define FLASH_JEDEC         0x20ba19  /* n25q256a */
67 #define FLASH_SIZE          (32 * 1024 * 1024)
68 
69 #define FLASH_PAGE_SIZE           256
70 
71 /*
72  * Use an explicit bswap for the values read/wrote to the flash region
73  * as they are BE and the Aspeed CPU is LE.
74  */
75 static inline uint32_t make_be32(uint32_t data)
76 {
77     return bswap32(data);
78 }
79 
80 static void spi_conf(uint32_t value)
81 {
82     uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
83 
84     conf |= value;
85     writel(ASPEED_FMC_BASE + R_CONF, conf);
86 }
87 
88 static void spi_conf_remove(uint32_t value)
89 {
90     uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
91 
92     conf &= ~value;
93     writel(ASPEED_FMC_BASE + R_CONF, conf);
94 }
95 
96 static void spi_ce_ctrl(uint32_t value)
97 {
98     uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL);
99 
100     conf |= value;
101     writel(ASPEED_FMC_BASE + R_CE_CTRL, conf);
102 }
103 
104 static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd)
105 {
106     uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
107     ctrl &= ~(CTRL_USERMODE | 0xff << 16);
108     ctrl |= mode | (cmd << 16);
109     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
110 }
111 
112 static void spi_ctrl_start_user(void)
113 {
114     uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
115 
116     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
117     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
118 
119     ctrl &= ~CTRL_CE_STOP_ACTIVE;
120     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
121 }
122 
123 static void spi_ctrl_stop_user(void)
124 {
125     uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
126 
127     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
128     writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
129 }
130 
131 static void flash_reset(void)
132 {
133     spi_conf(CONF_ENABLE_W0);
134 
135     spi_ctrl_start_user();
136     writeb(ASPEED_FLASH_BASE, RESET_ENABLE);
137     writeb(ASPEED_FLASH_BASE, RESET_MEMORY);
138     writeb(ASPEED_FLASH_BASE, WREN);
139     writeb(ASPEED_FLASH_BASE, BULK_ERASE);
140     writeb(ASPEED_FLASH_BASE, WRDI);
141     spi_ctrl_stop_user();
142 
143     spi_conf_remove(CONF_ENABLE_W0);
144 }
145 
146 static void test_read_jedec(void)
147 {
148     uint32_t jedec = 0x0;
149 
150     spi_conf(CONF_ENABLE_W0);
151 
152     spi_ctrl_start_user();
153     writeb(ASPEED_FLASH_BASE, JEDEC_READ);
154     jedec |= readb(ASPEED_FLASH_BASE) << 16;
155     jedec |= readb(ASPEED_FLASH_BASE) << 8;
156     jedec |= readb(ASPEED_FLASH_BASE);
157     spi_ctrl_stop_user();
158 
159     flash_reset();
160 
161     g_assert_cmphex(jedec, ==, FLASH_JEDEC);
162 }
163 
164 static void read_page(uint32_t addr, uint32_t *page)
165 {
166     int i;
167 
168     spi_ctrl_start_user();
169 
170     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
171     writeb(ASPEED_FLASH_BASE, READ);
172     writel(ASPEED_FLASH_BASE, make_be32(addr));
173 
174     /* Continuous read are supported */
175     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
176         page[i] = make_be32(readl(ASPEED_FLASH_BASE));
177     }
178     spi_ctrl_stop_user();
179 }
180 
181 static void read_page_mem(uint32_t addr, uint32_t *page)
182 {
183     int i;
184 
185     /* move out USER mode to use direct reads from the AHB bus */
186     spi_ctrl_setmode(CTRL_READMODE, READ);
187 
188     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
189         page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
190     }
191 }
192 
193 static void test_erase_sector(void)
194 {
195     uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
196     uint32_t page[FLASH_PAGE_SIZE / 4];
197     int i;
198 
199     spi_conf(CONF_ENABLE_W0);
200 
201     /*
202      * Previous page should be full of 0xffs after backend is
203      * initialized
204      */
205     read_page(some_page_addr - FLASH_PAGE_SIZE, page);
206     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
207         g_assert_cmphex(page[i], ==, 0xffffffff);
208     }
209 
210     spi_ctrl_start_user();
211     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
212     writeb(ASPEED_FLASH_BASE, WREN);
213     writeb(ASPEED_FLASH_BASE, PP);
214     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
215 
216     /* Fill the page with its own addresses */
217     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
218         writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
219     }
220     spi_ctrl_stop_user();
221 
222     /* Check the page is correctly written */
223     read_page(some_page_addr, page);
224     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
225         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
226     }
227 
228     spi_ctrl_start_user();
229     writeb(ASPEED_FLASH_BASE, WREN);
230     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
231     writeb(ASPEED_FLASH_BASE, ERASE_SECTOR);
232     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
233     spi_ctrl_stop_user();
234 
235     /* Check the page is erased */
236     read_page(some_page_addr, page);
237     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
238         g_assert_cmphex(page[i], ==, 0xffffffff);
239     }
240 
241     flash_reset();
242 }
243 
244 static void test_erase_all(void)
245 {
246     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
247     uint32_t page[FLASH_PAGE_SIZE / 4];
248     int i;
249 
250     spi_conf(CONF_ENABLE_W0);
251 
252     /*
253      * Previous page should be full of 0xffs after backend is
254      * initialized
255      */
256     read_page(some_page_addr - FLASH_PAGE_SIZE, page);
257     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
258         g_assert_cmphex(page[i], ==, 0xffffffff);
259     }
260 
261     spi_ctrl_start_user();
262     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
263     writeb(ASPEED_FLASH_BASE, WREN);
264     writeb(ASPEED_FLASH_BASE, PP);
265     writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
266 
267     /* Fill the page with its own addresses */
268     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
269         writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
270     }
271     spi_ctrl_stop_user();
272 
273     /* Check the page is correctly written */
274     read_page(some_page_addr, page);
275     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
276         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
277     }
278 
279     spi_ctrl_start_user();
280     writeb(ASPEED_FLASH_BASE, WREN);
281     writeb(ASPEED_FLASH_BASE, BULK_ERASE);
282     spi_ctrl_stop_user();
283 
284     /* Check the page is erased */
285     read_page(some_page_addr, page);
286     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
287         g_assert_cmphex(page[i], ==, 0xffffffff);
288     }
289 
290     flash_reset();
291 }
292 
293 static void test_write_page(void)
294 {
295     uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
296     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
297     uint32_t page[FLASH_PAGE_SIZE / 4];
298     int i;
299 
300     spi_conf(CONF_ENABLE_W0);
301 
302     spi_ctrl_start_user();
303     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
304     writeb(ASPEED_FLASH_BASE, WREN);
305     writeb(ASPEED_FLASH_BASE, PP);
306     writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
307 
308     /* Fill the page with its own addresses */
309     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
310         writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
311     }
312     spi_ctrl_stop_user();
313 
314     /* Check what was written */
315     read_page(my_page_addr, page);
316     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
317         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
318     }
319 
320     /* Check some other page. It should be full of 0xff */
321     read_page(some_page_addr, page);
322     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
323         g_assert_cmphex(page[i], ==, 0xffffffff);
324     }
325 
326     flash_reset();
327 }
328 
329 static void test_read_page_mem(void)
330 {
331     uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
332     uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
333     uint32_t page[FLASH_PAGE_SIZE / 4];
334     int i;
335 
336     /* Enable 4BYTE mode for controller. This is should be strapped by
337      * HW for CE0 anyhow.
338      */
339     spi_ce_ctrl(1 << CRTL_EXTENDED0);
340 
341     /* Enable 4BYTE mode for flash. */
342     spi_conf(CONF_ENABLE_W0);
343     spi_ctrl_start_user();
344     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
345     writeb(ASPEED_FLASH_BASE, WREN);
346     writeb(ASPEED_FLASH_BASE, PP);
347     writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
348 
349     /* Fill the page with its own addresses */
350     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
351         writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
352     }
353     spi_ctrl_stop_user();
354     spi_conf_remove(CONF_ENABLE_W0);
355 
356     /* Check what was written */
357     read_page_mem(my_page_addr, page);
358     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
359         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
360     }
361 
362     /* Check some other page. It should be full of 0xff */
363     read_page_mem(some_page_addr, page);
364     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
365         g_assert_cmphex(page[i], ==, 0xffffffff);
366     }
367 
368     flash_reset();
369 }
370 
371 static void test_write_page_mem(void)
372 {
373     uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
374     uint32_t page[FLASH_PAGE_SIZE / 4];
375     int i;
376 
377     /* Enable 4BYTE mode for controller. This is should be strapped by
378      * HW for CE0 anyhow.
379      */
380     spi_ce_ctrl(1 << CRTL_EXTENDED0);
381 
382     /* Enable 4BYTE mode for flash. */
383     spi_conf(CONF_ENABLE_W0);
384     spi_ctrl_start_user();
385     writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
386     writeb(ASPEED_FLASH_BASE, WREN);
387     spi_ctrl_stop_user();
388 
389     /* move out USER mode to use direct writes to the AHB bus */
390     spi_ctrl_setmode(CTRL_WRITEMODE, PP);
391 
392     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
393         writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
394                make_be32(my_page_addr + i * 4));
395     }
396 
397     /* Check what was written */
398     read_page_mem(my_page_addr, page);
399     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
400         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
401     }
402 
403     flash_reset();
404 }
405 
406 static void test_read_status_reg(void)
407 {
408     uint8_t r;
409 
410     spi_conf(CONF_ENABLE_W0);
411 
412     spi_ctrl_start_user();
413     writeb(ASPEED_FLASH_BASE, RDSR);
414     r = readb(ASPEED_FLASH_BASE);
415     spi_ctrl_stop_user();
416 
417     g_assert_cmphex(r & SR_WEL, ==, 0);
418     g_assert(!qtest_qom_get_bool
419             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
420 
421     spi_ctrl_start_user();
422     writeb(ASPEED_FLASH_BASE, WREN);
423     writeb(ASPEED_FLASH_BASE, RDSR);
424     r = readb(ASPEED_FLASH_BASE);
425     spi_ctrl_stop_user();
426 
427     g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
428     g_assert(qtest_qom_get_bool
429             (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
430 
431     spi_ctrl_start_user();
432     writeb(ASPEED_FLASH_BASE, WRDI);
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     flash_reset();
442 }
443 
444 static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
445 
446 int main(int argc, char **argv)
447 {
448     int ret;
449     int fd;
450 
451     g_test_init(&argc, &argv, NULL);
452 
453     fd = mkstemp(tmp_path);
454     g_assert(fd >= 0);
455     ret = ftruncate(fd, FLASH_SIZE);
456     g_assert(ret == 0);
457     close(fd);
458 
459     global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
460                                "-drive file=%s,format=raw,if=mtd",
461                                tmp_path);
462 
463     qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec);
464     qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector);
465     qtest_add_func("/ast2400/smc/erase_all",  test_erase_all);
466     qtest_add_func("/ast2400/smc/write_page", test_write_page);
467     qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
468     qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
469     qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg);
470 
471     flash_reset();
472     ret = g_test_run();
473 
474     qtest_quit(global_qtest);
475     unlink(tmp_path);
476     return ret;
477 }
478