2 * QTest testcase for parallel flash with AMD command set
4 * Copyright (c) 2019 Stephen Checkoway
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
14 * To test the pflash_cfi02 device, we run QEMU with the musicpal machine with
15 * a pflash drive. This enables us to test some flash configurations, but not
16 * all. In particular, we're limited to a 16-bit wide flash device.
19 #define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
20 #define FLASH_SIZE (8 * 1024 * 1024)
21 #define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
23 /* Use a newtype to keep flash addresses separate from byte addresses. */
27 #define FLASH_ADDR(x) ((faddr) { .addr = (x) })
29 #define CFI_ADDR FLASH_ADDR(0x55)
30 #define UNLOCK0_ADDR FLASH_ADDR(0x555)
31 #define UNLOCK1_ADDR FLASH_ADDR(0x2AA)
34 #define UNLOCK0_CMD 0xAA
35 #define UNLOCK1_CMD 0x55
36 #define AUTOSELECT_CMD 0x90
37 #define RESET_CMD 0xF0
38 #define PROGRAM_CMD 0xA0
39 #define SECTOR_ERASE_CMD 0x30
40 #define CHIP_ERASE_CMD 0x10
41 #define UNLOCK_BYPASS_CMD 0x20
42 #define UNLOCK_BYPASS_RESET_CMD 0x00
50 static char image_path
[] = "/tmp/qtest.XXXXXX";
53 * The pflash implementation allows some parameters to be unspecified. We want
54 * to test those configurations but we also need to know the real values in
55 * our testing code. So after we launch qemu, we'll need a new FlashConfig
56 * with the correct values filled in.
58 static FlashConfig
expand_config_defaults(const FlashConfig
*c
)
62 if (ret
.bank_width
== 0) {
66 /* XXX: Limitations of test harness. */
67 assert(ret
.bank_width
== 2);
72 * Return a bit mask suitable for extracting the least significant
73 * status/query response from an interleaved response.
75 static inline uint64_t device_mask(const FlashConfig
*c
)
81 * Return a bit mask exactly as long as the bank_width.
83 static inline uint64_t bank_mask(const FlashConfig
*c
)
85 if (c
->bank_width
== 8) {
88 return (1ULL << (c
->bank_width
* 8)) - 1ULL;
91 static inline void flash_write(const FlashConfig
*c
, uint64_t byte_addr
,
94 /* Sanity check our tests. */
95 assert((data
& ~bank_mask(c
)) == 0);
96 uint64_t addr
= BASE_ADDR
+ byte_addr
;
97 switch (c
->bank_width
) {
99 qtest_writeb(c
->qtest
, addr
, data
);
102 qtest_writew(c
->qtest
, addr
, data
);
105 qtest_writel(c
->qtest
, addr
, data
);
108 qtest_writeq(c
->qtest
, addr
, data
);
115 static inline uint64_t flash_read(const FlashConfig
*c
, uint64_t byte_addr
)
117 uint64_t addr
= BASE_ADDR
+ byte_addr
;
118 switch (c
->bank_width
) {
120 return qtest_readb(c
->qtest
, addr
);
122 return qtest_readw(c
->qtest
, addr
);
124 return qtest_readl(c
->qtest
, addr
);
126 return qtest_readq(c
->qtest
, addr
);
133 * Convert a flash address expressed in the maximum width of the device as a
136 static inline uint64_t as_byte_addr(const FlashConfig
*c
, faddr flash_addr
)
139 * Command addresses are always given as addresses in the maximum
140 * supported bus size for the flash chip. So an x8/x16 chip in x8 mode
141 * uses addresses 0xAAA and 0x555 to unlock because the least significant
142 * bit is ignored. (0x555 rather than 0x554 is traditional.)
144 * In general we need to multiply by the maximum device width.
146 return flash_addr
.addr
* c
->bank_width
;
150 * Return the command value or expected status replicated across all devices.
152 static inline uint64_t replicate(const FlashConfig
*c
, uint64_t data
)
154 /* Sanity check our tests. */
155 assert((data
& ~device_mask(c
)) == 0);
159 static inline void flash_cmd(const FlashConfig
*c
, faddr cmd_addr
,
162 flash_write(c
, as_byte_addr(c
, cmd_addr
), replicate(c
, cmd
));
165 static inline uint64_t flash_query(const FlashConfig
*c
, faddr query_addr
)
167 return flash_read(c
, as_byte_addr(c
, query_addr
));
170 static inline uint64_t flash_query_1(const FlashConfig
*c
, faddr query_addr
)
172 return flash_query(c
, query_addr
) & device_mask(c
);
175 static void unlock(const FlashConfig
*c
)
177 flash_cmd(c
, UNLOCK0_ADDR
, UNLOCK0_CMD
);
178 flash_cmd(c
, UNLOCK1_ADDR
, UNLOCK1_CMD
);
181 static void reset(const FlashConfig
*c
)
183 flash_cmd(c
, FLASH_ADDR(0), RESET_CMD
);
186 static void sector_erase(const FlashConfig
*c
, uint64_t byte_addr
)
189 flash_cmd(c
, UNLOCK0_ADDR
, 0x80);
191 flash_write(c
, byte_addr
, replicate(c
, SECTOR_ERASE_CMD
));
194 static void wait_for_completion(const FlashConfig
*c
, uint64_t byte_addr
)
196 /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
197 const uint64_t dq6
= replicate(c
, 0x40);
198 if ((flash_read(c
, byte_addr
) & dq6
) ^ (flash_read(c
, byte_addr
) & dq6
)) {
199 /* Wait for erase or program to finish. */
200 qtest_clock_step_next(c
->qtest
);
201 /* Ensure that DQ6 has stopped toggling. */
202 g_assert_cmphex(flash_read(c
, byte_addr
), ==, flash_read(c
, byte_addr
));
206 static void bypass_program(const FlashConfig
*c
, uint64_t byte_addr
,
209 flash_cmd(c
, UNLOCK0_ADDR
, PROGRAM_CMD
);
210 flash_write(c
, byte_addr
, data
);
212 * Data isn't valid until DQ6 stops toggling. We don't model this as
213 * writes are immediate, but if this changes in the future, we can wait
214 * until the program is complete.
216 wait_for_completion(c
, byte_addr
);
219 static void program(const FlashConfig
*c
, uint64_t byte_addr
, uint16_t data
)
222 bypass_program(c
, byte_addr
, data
);
225 static void chip_erase(const FlashConfig
*c
)
228 flash_cmd(c
, UNLOCK0_ADDR
, 0x80);
230 flash_cmd(c
, UNLOCK0_ADDR
, CHIP_ERASE_CMD
);
233 static void test_flash(const void *opaque
)
235 const FlashConfig
*config
= opaque
;
237 qtest
= qtest_initf("-M musicpal,accel=qtest"
238 " -drive if=pflash,file=%s,format=raw,copy-on-read",
240 FlashConfig explicit_config
= expand_config_defaults(config
);
241 explicit_config
.qtest
= qtest
;
242 const FlashConfig
*c
= &explicit_config
;
246 flash_cmd(c
, UNLOCK0_ADDR
, AUTOSELECT_CMD
);
247 g_assert_cmphex(flash_query(c
, FLASH_ADDR(0)), ==, replicate(c
, 0xBF));
248 if (c
->bank_width
>= 2) {
250 * XXX: The ID returned by the musicpal flash chip is 16 bits which
251 * wouldn't happen with an 8-bit device. It would probably be best to
252 * prohibit addresses larger than the device width in pflash_cfi02.c,
253 * but then we couldn't test smaller device widths at all.
255 g_assert_cmphex(flash_query(c
, FLASH_ADDR(1)), ==,
256 replicate(c
, 0x236D));
260 /* Check the erase blocks. */
261 flash_cmd(c
, CFI_ADDR
, CFI_CMD
);
262 g_assert_cmphex(flash_query(c
, FLASH_ADDR(0x10)), ==, replicate(c
, 'Q'));
263 g_assert_cmphex(flash_query(c
, FLASH_ADDR(0x11)), ==, replicate(c
, 'R'));
264 g_assert_cmphex(flash_query(c
, FLASH_ADDR(0x12)), ==, replicate(c
, 'Y'));
266 /* Num erase regions. */
267 g_assert_cmphex(flash_query_1(c
, FLASH_ADDR(0x2C)), >=, 1);
269 uint32_t nb_sectors
= flash_query_1(c
, FLASH_ADDR(0x2D)) +
270 (flash_query_1(c
, FLASH_ADDR(0x2E)) << 8) + 1;
271 uint32_t sector_len
= (flash_query_1(c
, FLASH_ADDR(0x2F)) << 8) +
272 (flash_query_1(c
, FLASH_ADDR(0x30)) << 16);
275 const uint64_t dq7
= replicate(c
, 0x80);
276 const uint64_t dq6
= replicate(c
, 0x40);
277 /* Erase and program sector. */
278 for (uint32_t i
= 0; i
< nb_sectors
; ++i
) {
279 uint64_t byte_addr
= i
* sector_len
;
280 sector_erase(c
, byte_addr
);
282 uint64_t status0
= flash_read(c
, byte_addr
);
283 /* DQ7 is 0 during an erase. */
284 g_assert_cmphex(status0
& dq7
, ==, 0);
285 uint64_t status1
= flash_read(c
, byte_addr
);
286 /* DQ6 toggles during an erase. */
287 g_assert_cmphex(status0
& dq6
, ==, ~status1
& dq6
);
288 /* Wait for erase to complete. */
289 qtest_clock_step_next(c
->qtest
);
290 /* Ensure DQ6 has stopped toggling. */
291 g_assert_cmphex(flash_read(c
, byte_addr
), ==, flash_read(c
, byte_addr
));
292 /* Now the data should be valid. */
293 g_assert_cmphex(flash_read(c
, byte_addr
), ==, bank_mask(c
));
295 /* Program a bit pattern. */
296 program(c
, byte_addr
, 0x55);
297 g_assert_cmphex(flash_read(c
, byte_addr
) & 0xFF, ==, 0x55);
298 program(c
, byte_addr
, 0xA5);
299 g_assert_cmphex(flash_read(c
, byte_addr
) & 0xFF, ==, 0x05);
302 /* Erase the chip. */
305 uint64_t status0
= flash_read(c
, 0);
306 /* DQ7 is 0 during an erase. */
307 g_assert_cmphex(status0
& dq7
, ==, 0);
308 uint64_t status1
= flash_read(c
, 0);
309 /* DQ6 toggles during an erase. */
310 g_assert_cmphex(status0
& dq6
, ==, ~status1
& dq6
);
311 /* Wait for erase to complete. */
312 qtest_clock_step_next(c
->qtest
);
313 /* Ensure DQ6 has stopped toggling. */
314 g_assert_cmphex(flash_read(c
, 0), ==, flash_read(c
, 0));
315 /* Now the data should be valid. */
317 for (uint32_t i
= 0; i
< nb_sectors
; ++i
) {
318 uint64_t byte_addr
= i
* sector_len
;
319 g_assert_cmphex(flash_read(c
, byte_addr
), ==, bank_mask(c
));
324 flash_cmd(c
, UNLOCK0_ADDR
, UNLOCK_BYPASS_CMD
);
325 bypass_program(c
, 0 * c
->bank_width
, 0x01);
326 bypass_program(c
, 1 * c
->bank_width
, 0x23);
327 bypass_program(c
, 2 * c
->bank_width
, 0x45);
329 * Test that bypass programming, unlike normal programming can use any
330 * address for the PROGRAM_CMD.
332 flash_cmd(c
, FLASH_ADDR(3 * c
->bank_width
), PROGRAM_CMD
);
333 flash_write(c
, 3 * c
->bank_width
, 0x67);
334 wait_for_completion(c
, 3 * c
->bank_width
);
335 flash_cmd(c
, FLASH_ADDR(0), UNLOCK_BYPASS_RESET_CMD
);
336 bypass_program(c
, 4 * c
->bank_width
, 0x89); /* Should fail. */
337 g_assert_cmphex(flash_read(c
, 0 * c
->bank_width
), ==, 0x01);
338 g_assert_cmphex(flash_read(c
, 1 * c
->bank_width
), ==, 0x23);
339 g_assert_cmphex(flash_read(c
, 2 * c
->bank_width
), ==, 0x45);
340 g_assert_cmphex(flash_read(c
, 3 * c
->bank_width
), ==, 0x67);
341 g_assert_cmphex(flash_read(c
, 4 * c
->bank_width
), ==, bank_mask(c
));
343 /* Test ignored high order bits of address. */
344 flash_cmd(c
, FLASH_ADDR(0x5555), UNLOCK0_CMD
);
345 flash_cmd(c
, FLASH_ADDR(0x2AAA), UNLOCK1_CMD
);
346 flash_cmd(c
, FLASH_ADDR(0x5555), AUTOSELECT_CMD
);
347 g_assert_cmphex(flash_query(c
, FLASH_ADDR(0)), ==, replicate(c
, 0xBF));
353 static void cleanup(void *opaque
)
359 * XXX: Tests are limited to bank_width = 2 for now because that's what
360 * hw/arm/musicpal.c has.
362 static const FlashConfig configuration
[] = {
363 /* One x16 device. */
369 int main(int argc
, char **argv
)
371 int fd
= mkstemp(image_path
);
373 g_printerr("Failed to create temporary file %s: %s\n", image_path
,
377 if (ftruncate(fd
, FLASH_SIZE
) < 0) {
378 int error_code
= errno
;
381 g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path
,
382 FLASH_SIZE
, strerror(error_code
));
387 qtest_add_abrt_handler(cleanup
, NULL
);
388 g_test_init(&argc
, &argv
, NULL
);
390 size_t nb_configurations
= sizeof configuration
/ sizeof configuration
[0];
391 for (size_t i
= 0; i
< nb_configurations
; ++i
) {
392 const FlashConfig
*config
= &configuration
[i
];
393 char *path
= g_strdup_printf("pflash-cfi02/%d",
395 qtest_add_data_func(path
, config
, test_flash
);
398 int result
= g_test_run();