xref: /openbmc/qemu/tests/qtest/aspeed-smc-utils.c (revision 11d94251)
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 #include "aspeed-smc-utils.h"
31 
32 /*
33  * Use an explicit bswap for the values read/wrote to the flash region
34  * as they are BE and the Aspeed CPU is LE.
35  */
make_be32(uint32_t data)36 static inline uint32_t make_be32(uint32_t data)
37 {
38     return bswap32(data);
39 }
40 
spi_writel(const AspeedSMCTestData * data,uint64_t offset,uint32_t value)41 static inline void spi_writel(const AspeedSMCTestData *data, uint64_t offset,
42                               uint32_t value)
43 {
44     qtest_writel(data->s, data->spi_base + offset, value);
45 }
46 
spi_readl(const AspeedSMCTestData * data,uint64_t offset)47 static inline uint32_t spi_readl(const AspeedSMCTestData *data, uint64_t offset)
48 {
49     return qtest_readl(data->s, data->spi_base + offset);
50 }
51 
flash_writeb(const AspeedSMCTestData * data,uint64_t offset,uint8_t value)52 static inline void flash_writeb(const AspeedSMCTestData *data, uint64_t offset,
53                                 uint8_t value)
54 {
55     qtest_writeb(data->s, data->flash_base + offset, value);
56 }
57 
flash_writel(const AspeedSMCTestData * data,uint64_t offset,uint32_t value)58 static inline void flash_writel(const AspeedSMCTestData *data, uint64_t offset,
59                                 uint32_t value)
60 {
61     qtest_writel(data->s, data->flash_base + offset, value);
62 }
63 
flash_readb(const AspeedSMCTestData * data,uint64_t offset)64 static inline uint8_t flash_readb(const AspeedSMCTestData *data,
65                                   uint64_t offset)
66 {
67     return qtest_readb(data->s, data->flash_base + offset);
68 }
69 
flash_readl(const AspeedSMCTestData * data,uint64_t offset)70 static inline uint32_t flash_readl(const AspeedSMCTestData *data,
71                                    uint64_t offset)
72 {
73     return qtest_readl(data->s, data->flash_base + offset);
74 }
75 
spi_conf(const AspeedSMCTestData * data,uint32_t value)76 static void spi_conf(const AspeedSMCTestData *data, uint32_t value)
77 {
78     uint32_t conf = spi_readl(data, R_CONF);
79 
80     conf |= value;
81     spi_writel(data, R_CONF, conf);
82 }
83 
spi_conf_remove(const AspeedSMCTestData * data,uint32_t value)84 static void spi_conf_remove(const AspeedSMCTestData *data, uint32_t value)
85 {
86     uint32_t conf = spi_readl(data, R_CONF);
87 
88     conf &= ~value;
89     spi_writel(data, R_CONF, conf);
90 }
91 
spi_ce_ctrl(const AspeedSMCTestData * data,uint32_t value)92 static void spi_ce_ctrl(const AspeedSMCTestData *data, uint32_t value)
93 {
94     uint32_t conf = spi_readl(data, R_CE_CTRL);
95 
96     conf |= value;
97     spi_writel(data, R_CE_CTRL, conf);
98 }
99 
spi_ctrl_setmode(const AspeedSMCTestData * data,uint8_t mode,uint8_t cmd)100 static void spi_ctrl_setmode(const AspeedSMCTestData *data, uint8_t mode,
101                              uint8_t cmd)
102 {
103     uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
104     uint32_t ctrl = spi_readl(data, ctrl_reg);
105     ctrl &= ~(CTRL_USERMODE | 0xff << 16);
106     ctrl |= mode | (cmd << 16);
107     spi_writel(data, ctrl_reg, ctrl);
108 }
109 
spi_ctrl_start_user(const AspeedSMCTestData * data)110 static void spi_ctrl_start_user(const AspeedSMCTestData *data)
111 {
112     uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
113     uint32_t ctrl = spi_readl(data, ctrl_reg);
114 
115     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
116     spi_writel(data, ctrl_reg, ctrl);
117 
118     ctrl &= ~CTRL_CE_STOP_ACTIVE;
119     spi_writel(data, ctrl_reg, ctrl);
120 }
121 
spi_ctrl_stop_user(const AspeedSMCTestData * data)122 static void spi_ctrl_stop_user(const AspeedSMCTestData *data)
123 {
124     uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
125     uint32_t ctrl = spi_readl(data, ctrl_reg);
126 
127     ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
128     spi_writel(data, ctrl_reg, ctrl);
129 }
130 
spi_ctrl_set_io_mode(const AspeedSMCTestData * data,uint32_t value)131 static void spi_ctrl_set_io_mode(const AspeedSMCTestData *data, uint32_t value)
132 {
133     uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
134     uint32_t ctrl = spi_readl(data, ctrl_reg);
135     uint32_t mode;
136 
137     mode = value & CTRL_IO_MODE_MASK;
138     ctrl &= ~CTRL_IO_MODE_MASK;
139     ctrl |= mode;
140     spi_writel(data, ctrl_reg, ctrl);
141 }
142 
flash_reset(const AspeedSMCTestData * data)143 static void flash_reset(const AspeedSMCTestData *data)
144 {
145     spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
146 
147     spi_ctrl_start_user(data);
148     flash_writeb(data, 0, RESET_ENABLE);
149     flash_writeb(data, 0, RESET_MEMORY);
150     flash_writeb(data, 0, WREN);
151     flash_writeb(data, 0, BULK_ERASE);
152     flash_writeb(data, 0, WRDI);
153     spi_ctrl_stop_user(data);
154 
155     spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
156 }
157 
read_page(const AspeedSMCTestData * data,uint32_t addr,uint32_t * page)158 static void read_page(const AspeedSMCTestData *data, uint32_t addr,
159                       uint32_t *page)
160 {
161     int i;
162 
163     spi_ctrl_start_user(data);
164 
165     flash_writeb(data, 0, EN_4BYTE_ADDR);
166     flash_writeb(data, 0, READ);
167     flash_writel(data, 0, make_be32(addr));
168 
169     /* Continuous read are supported */
170     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
171         page[i] = make_be32(flash_readl(data, 0));
172     }
173     spi_ctrl_stop_user(data);
174 }
175 
read_page_mem(const AspeedSMCTestData * data,uint32_t addr,uint32_t * page)176 static void read_page_mem(const AspeedSMCTestData *data, uint32_t addr,
177                           uint32_t *page)
178 {
179     int i;
180 
181     /* move out USER mode to use direct reads from the AHB bus */
182     spi_ctrl_setmode(data, CTRL_READMODE, READ);
183 
184     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
185         page[i] = make_be32(flash_readl(data, addr + i * 4));
186     }
187 }
188 
write_page_mem(const AspeedSMCTestData * data,uint32_t addr,uint32_t write_value)189 static void write_page_mem(const AspeedSMCTestData *data, uint32_t addr,
190                            uint32_t write_value)
191 {
192     spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
193 
194     for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
195         flash_writel(data, addr + i * 4, write_value);
196     }
197 }
198 
assert_page_mem(const AspeedSMCTestData * data,uint32_t addr,uint32_t expected_value)199 static void assert_page_mem(const AspeedSMCTestData *data, uint32_t addr,
200                             uint32_t expected_value)
201 {
202     uint32_t page[FLASH_PAGE_SIZE / 4];
203     read_page_mem(data, addr, page);
204     for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
205         g_assert_cmphex(page[i], ==, expected_value);
206     }
207 }
208 
aspeed_smc_test_read_jedec(const void * data)209 void aspeed_smc_test_read_jedec(const void *data)
210 {
211     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
212     uint32_t jedec = 0x0;
213 
214     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
215 
216     spi_ctrl_start_user(test_data);
217     flash_writeb(test_data, 0, JEDEC_READ);
218     jedec |= flash_readb(test_data, 0) << 16;
219     jedec |= flash_readb(test_data, 0) << 8;
220     jedec |= flash_readb(test_data, 0);
221     spi_ctrl_stop_user(test_data);
222 
223     flash_reset(test_data);
224 
225     g_assert_cmphex(jedec, ==, test_data->jedec_id);
226 }
227 
aspeed_smc_test_erase_sector(const void * data)228 void aspeed_smc_test_erase_sector(const void *data)
229 {
230     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
231     uint32_t some_page_addr = test_data->page_addr;
232     uint32_t page[FLASH_PAGE_SIZE / 4];
233     int i;
234 
235     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
236 
237     /*
238      * Previous page should be full of 0xffs after backend is
239      * initialized
240      */
241     read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
242     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
243         g_assert_cmphex(page[i], ==, 0xffffffff);
244     }
245 
246     spi_ctrl_start_user(test_data);
247     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
248     flash_writeb(test_data, 0, WREN);
249     flash_writeb(test_data, 0, PP);
250     flash_writel(test_data, 0, make_be32(some_page_addr));
251 
252     /* Fill the page with its own addresses */
253     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
254         flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
255     }
256     spi_ctrl_stop_user(test_data);
257 
258     /* Check the page is correctly written */
259     read_page(test_data, some_page_addr, page);
260     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
261         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
262     }
263 
264     spi_ctrl_start_user(test_data);
265     flash_writeb(test_data, 0, WREN);
266     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
267     flash_writeb(test_data, 0, ERASE_SECTOR);
268     flash_writel(test_data, 0, make_be32(some_page_addr));
269     spi_ctrl_stop_user(test_data);
270 
271     /* Check the page is erased */
272     read_page(test_data, some_page_addr, page);
273     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
274         g_assert_cmphex(page[i], ==, 0xffffffff);
275     }
276 
277     flash_reset(test_data);
278 }
279 
aspeed_smc_test_erase_all(const void * data)280 void aspeed_smc_test_erase_all(const void *data)
281 {
282     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
283     uint32_t some_page_addr = test_data->page_addr;
284     uint32_t page[FLASH_PAGE_SIZE / 4];
285     int i;
286 
287     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
288 
289     /*
290      * Previous page should be full of 0xffs after backend is
291      * initialized
292      */
293     read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
294     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
295         g_assert_cmphex(page[i], ==, 0xffffffff);
296     }
297 
298     spi_ctrl_start_user(test_data);
299     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
300     flash_writeb(test_data, 0, WREN);
301     flash_writeb(test_data, 0, PP);
302     flash_writel(test_data, 0, make_be32(some_page_addr));
303 
304     /* Fill the page with its own addresses */
305     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
306         flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
307     }
308     spi_ctrl_stop_user(test_data);
309 
310     /* Check the page is correctly written */
311     read_page(test_data, some_page_addr, page);
312     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
313         g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
314     }
315 
316     spi_ctrl_start_user(test_data);
317     flash_writeb(test_data, 0, WREN);
318     flash_writeb(test_data, 0, BULK_ERASE);
319     spi_ctrl_stop_user(test_data);
320 
321     /* Check the page is erased */
322     read_page(test_data, some_page_addr, page);
323     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
324         g_assert_cmphex(page[i], ==, 0xffffffff);
325     }
326 
327     flash_reset(test_data);
328 }
329 
aspeed_smc_test_write_page(const void * data)330 void aspeed_smc_test_write_page(const void *data)
331 {
332     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
333     uint32_t my_page_addr = test_data->page_addr;
334     uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
335     uint32_t page[FLASH_PAGE_SIZE / 4];
336     int i;
337 
338     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
339 
340     spi_ctrl_start_user(test_data);
341     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
342     flash_writeb(test_data, 0, WREN);
343     flash_writeb(test_data, 0, PP);
344     flash_writel(test_data, 0, make_be32(my_page_addr));
345 
346     /* Fill the page with its own addresses */
347     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
348         flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
349     }
350     spi_ctrl_stop_user(test_data);
351 
352     /* Check what was written */
353     read_page(test_data, my_page_addr, page);
354     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
355         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
356     }
357 
358     /* Check some other page. It should be full of 0xff */
359     read_page(test_data, some_page_addr, page);
360     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
361         g_assert_cmphex(page[i], ==, 0xffffffff);
362     }
363 
364     flash_reset(test_data);
365 }
366 
aspeed_smc_test_read_page_mem(const void * data)367 void aspeed_smc_test_read_page_mem(const void *data)
368 {
369     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
370     uint32_t my_page_addr = test_data->page_addr;
371     uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
372     uint32_t page[FLASH_PAGE_SIZE / 4];
373     int i;
374 
375     /*
376      * Enable 4BYTE mode for controller.
377      */
378     spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
379 
380     /* Enable 4BYTE mode for flash. */
381     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
382     spi_ctrl_start_user(test_data);
383     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
384     flash_writeb(test_data, 0, WREN);
385     flash_writeb(test_data, 0, PP);
386     flash_writel(test_data, 0, make_be32(my_page_addr));
387 
388     /* Fill the page with its own addresses */
389     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
390         flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
391     }
392     spi_ctrl_stop_user(test_data);
393     spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
394 
395     /* Check what was written */
396     read_page_mem(test_data, my_page_addr, page);
397     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
398         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
399     }
400 
401     /* Check some other page. It should be full of 0xff */
402     read_page_mem(test_data, some_page_addr, page);
403     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
404         g_assert_cmphex(page[i], ==, 0xffffffff);
405     }
406 
407     flash_reset(test_data);
408 }
409 
aspeed_smc_test_write_page_mem(const void * data)410 void aspeed_smc_test_write_page_mem(const void *data)
411 {
412     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
413     uint32_t my_page_addr = test_data->page_addr;
414     uint32_t page[FLASH_PAGE_SIZE / 4];
415     int i;
416 
417     /*
418      * Enable 4BYTE mode for controller.
419      */
420     spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
421 
422     /* Enable 4BYTE mode for flash. */
423     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
424     spi_ctrl_start_user(test_data);
425     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
426     flash_writeb(test_data, 0, WREN);
427     spi_ctrl_stop_user(test_data);
428 
429     /* move out USER mode to use direct writes to the AHB bus */
430     spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
431 
432     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
433         flash_writel(test_data, my_page_addr + i * 4,
434                make_be32(my_page_addr + i * 4));
435     }
436 
437     /* Check what was written */
438     read_page_mem(test_data, my_page_addr, page);
439     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
440         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
441     }
442 
443     flash_reset(test_data);
444 }
445 
aspeed_smc_test_read_status_reg(const void * data)446 void aspeed_smc_test_read_status_reg(const void *data)
447 {
448     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
449     uint8_t r;
450 
451     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
452 
453     spi_ctrl_start_user(test_data);
454     flash_writeb(test_data, 0, RDSR);
455     r = flash_readb(test_data, 0);
456     spi_ctrl_stop_user(test_data);
457 
458     g_assert_cmphex(r & SR_WEL, ==, 0);
459     g_assert(!qtest_qom_get_bool
460             (test_data->s, test_data->node, "write-enable"));
461 
462     spi_ctrl_start_user(test_data);
463     flash_writeb(test_data, 0, WREN);
464     flash_writeb(test_data, 0, RDSR);
465     r = flash_readb(test_data, 0);
466     spi_ctrl_stop_user(test_data);
467 
468     g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
469     g_assert(qtest_qom_get_bool
470             (test_data->s, test_data->node, "write-enable"));
471 
472     spi_ctrl_start_user(test_data);
473     flash_writeb(test_data, 0, WRDI);
474     flash_writeb(test_data, 0, RDSR);
475     r = flash_readb(test_data, 0);
476     spi_ctrl_stop_user(test_data);
477 
478     g_assert_cmphex(r & SR_WEL, ==, 0);
479     g_assert(!qtest_qom_get_bool
480             (test_data->s, test_data->node, "write-enable"));
481 
482     flash_reset(test_data);
483 }
484 
aspeed_smc_test_status_reg_write_protection(const void * data)485 void aspeed_smc_test_status_reg_write_protection(const void *data)
486 {
487     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
488     uint8_t r;
489 
490     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
491 
492     /* default case: WP# is high and SRWD is low -> status register writable */
493     spi_ctrl_start_user(test_data);
494     flash_writeb(test_data, 0, WREN);
495     /* test ability to write SRWD */
496     flash_writeb(test_data, 0, WRSR);
497     flash_writeb(test_data, 0, SRWD);
498     flash_writeb(test_data, 0, RDSR);
499     r = flash_readb(test_data, 0);
500     spi_ctrl_stop_user(test_data);
501     g_assert_cmphex(r & SRWD, ==, SRWD);
502 
503     /* WP# high and SRWD high -> status register writable */
504     spi_ctrl_start_user(test_data);
505     flash_writeb(test_data, 0, WREN);
506     /* test ability to write SRWD */
507     flash_writeb(test_data, 0, WRSR);
508     flash_writeb(test_data, 0, 0);
509     flash_writeb(test_data, 0, RDSR);
510     r = flash_readb(test_data, 0);
511     spi_ctrl_stop_user(test_data);
512     g_assert_cmphex(r & SRWD, ==, 0);
513 
514     /* WP# low and SRWD low -> status register writable */
515     qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
516     spi_ctrl_start_user(test_data);
517     flash_writeb(test_data, 0, WREN);
518     /* test ability to write SRWD */
519     flash_writeb(test_data, 0, WRSR);
520     flash_writeb(test_data, 0, SRWD);
521     flash_writeb(test_data, 0, RDSR);
522     r = flash_readb(test_data, 0);
523     spi_ctrl_stop_user(test_data);
524     g_assert_cmphex(r & SRWD, ==, SRWD);
525 
526     /* WP# low and SRWD high -> status register NOT writable */
527     spi_ctrl_start_user(test_data);
528     flash_writeb(test_data, 0 , WREN);
529     /* test ability to write SRWD */
530     flash_writeb(test_data, 0, WRSR);
531     flash_writeb(test_data, 0, 0);
532     flash_writeb(test_data, 0, RDSR);
533     r = flash_readb(test_data, 0);
534     spi_ctrl_stop_user(test_data);
535     /* write is not successful */
536     g_assert_cmphex(r & SRWD, ==, SRWD);
537 
538     qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
539     flash_reset(test_data);
540 }
541 
aspeed_smc_test_write_block_protect(const void * data)542 void aspeed_smc_test_write_block_protect(const void *data)
543 {
544     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
545     uint32_t sector_size = 65536;
546     uint32_t n_sectors = 512;
547 
548     spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
549     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
550 
551     uint32_t bp_bits = 0b0;
552 
553     for (int i = 0; i < 16; i++) {
554         bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
555 
556         spi_ctrl_start_user(test_data);
557         flash_writeb(test_data, 0, WREN);
558         flash_writeb(test_data, 0, BULK_ERASE);
559         flash_writeb(test_data, 0, WREN);
560         flash_writeb(test_data, 0, WRSR);
561         flash_writeb(test_data, 0, bp_bits);
562         flash_writeb(test_data, 0, EN_4BYTE_ADDR);
563         flash_writeb(test_data, 0, WREN);
564         spi_ctrl_stop_user(test_data);
565 
566         uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
567         uint32_t protection_start = n_sectors - num_protected_sectors;
568         uint32_t protection_end = n_sectors;
569 
570         for (int sector = 0; sector < n_sectors; sector++) {
571             uint32_t addr = sector * sector_size;
572 
573             assert_page_mem(test_data, addr, 0xffffffff);
574             write_page_mem(test_data, addr, make_be32(0xabcdef12));
575 
576             uint32_t expected_value = protection_start <= sector
577                                       && sector < protection_end
578                                       ? 0xffffffff : 0xabcdef12;
579 
580             assert_page_mem(test_data, addr, expected_value);
581         }
582     }
583 
584     flash_reset(test_data);
585 }
586 
aspeed_smc_test_write_block_protect_bottom_bit(const void * data)587 void aspeed_smc_test_write_block_protect_bottom_bit(const void *data)
588 {
589     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
590     uint32_t sector_size = 65536;
591     uint32_t n_sectors = 512;
592 
593     spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
594     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
595 
596     /* top bottom bit is enabled */
597     uint32_t bp_bits = 0b00100 << 3;
598 
599     for (int i = 0; i < 16; i++) {
600         bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2);
601 
602         spi_ctrl_start_user(test_data);
603         flash_writeb(test_data, 0, WREN);
604         flash_writeb(test_data, 0, BULK_ERASE);
605         flash_writeb(test_data, 0, WREN);
606         flash_writeb(test_data, 0, WRSR);
607         flash_writeb(test_data, 0, bp_bits);
608         flash_writeb(test_data, 0, EN_4BYTE_ADDR);
609         flash_writeb(test_data, 0, WREN);
610         spi_ctrl_stop_user(test_data);
611 
612         uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
613         uint32_t protection_start = 0;
614         uint32_t protection_end = num_protected_sectors;
615 
616         for (int sector = 0; sector < n_sectors; sector++) {
617             uint32_t addr = sector * sector_size;
618 
619             assert_page_mem(test_data, addr, 0xffffffff);
620             write_page_mem(test_data, addr, make_be32(0xabcdef12));
621 
622             uint32_t expected_value = protection_start <= sector
623                                       && sector < protection_end
624                                       ? 0xffffffff : 0xabcdef12;
625 
626             assert_page_mem(test_data, addr, expected_value);
627         }
628     }
629 
630     flash_reset(test_data);
631 }
632 
aspeed_smc_test_write_page_qpi(const void * data)633 void aspeed_smc_test_write_page_qpi(const void *data)
634 {
635     const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
636     uint32_t my_page_addr = test_data->page_addr;
637     uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
638     uint32_t page[FLASH_PAGE_SIZE / 4];
639     uint32_t page_pattern[] = {
640         0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf
641     };
642     int i;
643 
644     spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
645 
646     spi_ctrl_start_user(test_data);
647     flash_writeb(test_data, 0, EN_4BYTE_ADDR);
648     flash_writeb(test_data, 0, WREN);
649     flash_writeb(test_data, 0, PP);
650     flash_writel(test_data, 0, make_be32(my_page_addr));
651 
652     /* Set QPI mode */
653     spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO);
654 
655     /* Fill the page pattern */
656     for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
657         flash_writel(test_data, 0, make_be32(page_pattern[i]));
658     }
659 
660     /* Fill the page with its own addresses */
661     for (; i < FLASH_PAGE_SIZE / 4; i++) {
662         flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
663     }
664 
665     /* Restore io mode */
666     spi_ctrl_set_io_mode(test_data, 0);
667     spi_ctrl_stop_user(test_data);
668 
669     /* Check what was written */
670     read_page(test_data, my_page_addr, page);
671     for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
672         g_assert_cmphex(page[i], ==, page_pattern[i]);
673     }
674     for (; i < FLASH_PAGE_SIZE / 4; i++) {
675         g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
676     }
677 
678     /* Check some other page. It should be full of 0xff */
679     read_page(test_data, some_page_addr, page);
680     for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
681         g_assert_cmphex(page[i], ==, 0xffffffff);
682     }
683 
684     flash_reset(test_data);
685 }
686 
687