xref: /qemu/tests/qtest/npcm7xx_sdhci-test.c (revision b9ee1387e0cf0fba5a73a610d31cb9cead457dc0)
14c579e15SShengtan Mao /*
24c579e15SShengtan Mao  * QTests for NPCM7xx SD-3.0 / MMC-4.51 Host Controller
34c579e15SShengtan Mao  *
44c579e15SShengtan Mao  * Copyright (c) 2022 Google LLC
54c579e15SShengtan Mao  *
64c579e15SShengtan Mao  * This program is free software; you can redistribute it and/or modify it
74c579e15SShengtan Mao  * under the terms of the GNU General Public License as published by the
84c579e15SShengtan Mao  * Free Software Foundation; either version 2 of the License, or
94c579e15SShengtan Mao  * (at your option) any later version.
104c579e15SShengtan Mao  *
114c579e15SShengtan Mao  * This program is distributed in the hope that it will be useful, but WITHOUT
124c579e15SShengtan Mao  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
134c579e15SShengtan Mao  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
144c579e15SShengtan Mao  * for more details.
154c579e15SShengtan Mao  */
164c579e15SShengtan Mao 
174c579e15SShengtan Mao #include "qemu/osdep.h"
184c579e15SShengtan Mao #include "hw/sd/npcm7xx_sdhci.h"
194c579e15SShengtan Mao 
20907b5105SMarc-André Lureau #include "libqtest.h"
214c579e15SShengtan Mao #include "libqtest-single.h"
224c579e15SShengtan Mao #include "libqos/sdhci-cmd.h"
234c579e15SShengtan Mao 
244c579e15SShengtan Mao #define NPCM7XX_REG_SIZE 0x100
254c579e15SShengtan Mao #define NPCM7XX_MMC_BA 0xF0842000
264c579e15SShengtan Mao #define NPCM7XX_BLK_SIZE 512
27284ad5e7SHao Wu #define NPCM7XX_TEST_IMAGE_SIZE (1 << 20)
284c579e15SShengtan Mao 
294c579e15SShengtan Mao char *sd_path;
304c579e15SShengtan Mao 
setup_sd_card(void)314c579e15SShengtan Mao static QTestState *setup_sd_card(void)
324c579e15SShengtan Mao {
33*3baae281SPhilippe Mathieu-Daudé     uint16_t rca;
34*3baae281SPhilippe Mathieu-Daudé 
354c579e15SShengtan Mao     QTestState *qts = qtest_initf(
364c579e15SShengtan Mao         "-machine kudo-bmc "
374c579e15SShengtan Mao         "-device sd-card,drive=drive0 "
384c579e15SShengtan Mao         "-drive id=drive0,if=none,file=%s,format=raw,auto-read-only=off",
394c579e15SShengtan Mao         sd_path);
404c579e15SShengtan Mao 
414c579e15SShengtan Mao     qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_SWRST, SDHC_RESET_ALL);
424c579e15SShengtan Mao     qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_CLKCON,
434c579e15SShengtan Mao                  SDHC_CLOCK_SDCLK_EN | SDHC_CLOCK_INT_STABLE |
444c579e15SShengtan Mao                      SDHC_CLOCK_INT_EN);
454c579e15SShengtan Mao     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_APP_CMD);
464c579e15SShengtan Mao     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x41200000, 0, (41 << 8));
474c579e15SShengtan Mao     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_ALL_SEND_CID);
48*3baae281SPhilippe Mathieu-Daudé     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_SEND_RELATIVE_ADDR
49*3baae281SPhilippe Mathieu-Daudé                                                     | SDHC_CMD_RESPONSE);
50*3baae281SPhilippe Mathieu-Daudé     rca = qtest_readl(qts, NPCM7XX_MMC_BA + SDHC_RSPREG0) >> 16;
51*3baae281SPhilippe Mathieu-Daudé     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, rca << 16, 0,
524c579e15SShengtan Mao                    SDHC_SELECT_DESELECT_CARD);
534c579e15SShengtan Mao 
544c579e15SShengtan Mao     return qts;
554c579e15SShengtan Mao }
564c579e15SShengtan Mao 
write_sdread(QTestState * qts,const char * msg)574c579e15SShengtan Mao static void write_sdread(QTestState *qts, const char *msg)
584c579e15SShengtan Mao {
594c579e15SShengtan Mao     int fd, ret;
604c579e15SShengtan Mao     size_t len = strlen(msg);
614c579e15SShengtan Mao     char *rmsg = g_malloc(len);
624c579e15SShengtan Mao 
634c579e15SShengtan Mao     /* write message to sd */
644c579e15SShengtan Mao     fd = open(sd_path, O_WRONLY);
654c579e15SShengtan Mao     g_assert(fd >= 0);
664c579e15SShengtan Mao     ret = write(fd, msg, len);
674c579e15SShengtan Mao     close(fd);
684c579e15SShengtan Mao     g_assert(ret == len);
694c579e15SShengtan Mao 
704c579e15SShengtan Mao     /* read message using sdhci */
714c579e15SShengtan Mao     ret = sdhci_read_cmd(qts, NPCM7XX_MMC_BA, rmsg, len);
724c579e15SShengtan Mao     g_assert(ret == len);
734c579e15SShengtan Mao     g_assert(!memcmp(rmsg, msg, len));
744c579e15SShengtan Mao 
754c579e15SShengtan Mao     g_free(rmsg);
764c579e15SShengtan Mao }
774c579e15SShengtan Mao 
784c579e15SShengtan Mao /* Check MMC can read values from sd */
test_read_sd(void)794c579e15SShengtan Mao static void test_read_sd(void)
804c579e15SShengtan Mao {
814c579e15SShengtan Mao     QTestState *qts = setup_sd_card();
824c579e15SShengtan Mao 
834c579e15SShengtan Mao     write_sdread(qts, "hello world");
844c579e15SShengtan Mao     write_sdread(qts, "goodbye");
854c579e15SShengtan Mao 
864c579e15SShengtan Mao     qtest_quit(qts);
874c579e15SShengtan Mao }
884c579e15SShengtan Mao 
sdwrite_read(QTestState * qts,const char * msg)894c579e15SShengtan Mao static void sdwrite_read(QTestState *qts, const char *msg)
904c579e15SShengtan Mao {
914c579e15SShengtan Mao     int fd, ret;
924c579e15SShengtan Mao     size_t len = strlen(msg);
934c579e15SShengtan Mao     char *rmsg = g_malloc(len);
944c579e15SShengtan Mao 
954c579e15SShengtan Mao     /* write message using sdhci */
964c579e15SShengtan Mao     sdhci_write_cmd(qts, NPCM7XX_MMC_BA, msg, len, NPCM7XX_BLK_SIZE);
974c579e15SShengtan Mao 
984c579e15SShengtan Mao     /* read message from sd */
994c579e15SShengtan Mao     fd = open(sd_path, O_RDONLY);
1004c579e15SShengtan Mao     g_assert(fd >= 0);
1014c579e15SShengtan Mao     ret = read(fd, rmsg, len);
1024c579e15SShengtan Mao     close(fd);
1034c579e15SShengtan Mao     g_assert(ret == len);
1044c579e15SShengtan Mao 
1054c579e15SShengtan Mao     g_assert(!memcmp(rmsg, msg, len));
1064c579e15SShengtan Mao 
1074c579e15SShengtan Mao     g_free(rmsg);
1084c579e15SShengtan Mao }
1094c579e15SShengtan Mao 
1104c579e15SShengtan Mao /* Check MMC can write values to sd */
test_write_sd(void)1114c579e15SShengtan Mao static void test_write_sd(void)
1124c579e15SShengtan Mao {
1134c579e15SShengtan Mao     QTestState *qts = setup_sd_card();
1144c579e15SShengtan Mao 
1154c579e15SShengtan Mao     sdwrite_read(qts, "hello world");
1164c579e15SShengtan Mao     sdwrite_read(qts, "goodbye");
1174c579e15SShengtan Mao 
1184c579e15SShengtan Mao     qtest_quit(qts);
1194c579e15SShengtan Mao }
1204c579e15SShengtan Mao 
1214c579e15SShengtan Mao /* Check SDHCI has correct default values. */
test_reset(void)1224c579e15SShengtan Mao static void test_reset(void)
1234c579e15SShengtan Mao {
1244c579e15SShengtan Mao     QTestState *qts = qtest_init("-machine kudo-bmc");
1254c579e15SShengtan Mao     uint64_t addr = NPCM7XX_MMC_BA;
1264c579e15SShengtan Mao     uint64_t end_addr = addr + NPCM7XX_REG_SIZE;
1274c579e15SShengtan Mao     uint16_t prstvals_resets[] = {NPCM7XX_PRSTVALS_0_RESET,
1284c579e15SShengtan Mao                                   NPCM7XX_PRSTVALS_1_RESET,
1294c579e15SShengtan Mao                                   0,
1304c579e15SShengtan Mao                                   NPCM7XX_PRSTVALS_3_RESET,
1314c579e15SShengtan Mao                                   0,
1324c579e15SShengtan Mao                                   0};
1334c579e15SShengtan Mao     int i;
1344c579e15SShengtan Mao     uint32_t mask;
1354c579e15SShengtan Mao 
1364c579e15SShengtan Mao     while (addr < end_addr) {
1374c579e15SShengtan Mao         switch (addr - NPCM7XX_MMC_BA) {
1384c579e15SShengtan Mao         case SDHC_PRNSTS:
1394c579e15SShengtan Mao             /*
1404c579e15SShengtan Mao              * ignores bits 20 to 24: they are changed when reading registers
1414c579e15SShengtan Mao              */
1424c579e15SShengtan Mao             mask = 0x1f00000;
1434c579e15SShengtan Mao             g_assert_cmphex(qtest_readl(qts, addr) | mask, ==,
1444c579e15SShengtan Mao                             NPCM7XX_PRSNTS_RESET | mask);
1454c579e15SShengtan Mao             addr += 4;
1464c579e15SShengtan Mao             break;
1474c579e15SShengtan Mao         case SDHC_BLKGAP:
1484c579e15SShengtan Mao             g_assert_cmphex(qtest_readb(qts, addr), ==, NPCM7XX_BLKGAP_RESET);
1494c579e15SShengtan Mao             addr += 1;
1504c579e15SShengtan Mao             break;
1514c579e15SShengtan Mao         case SDHC_CAPAB:
1524c579e15SShengtan Mao             g_assert_cmphex(qtest_readq(qts, addr), ==, NPCM7XX_CAPAB_RESET);
1534c579e15SShengtan Mao             addr += 8;
1544c579e15SShengtan Mao             break;
1554c579e15SShengtan Mao         case SDHC_MAXCURR:
1564c579e15SShengtan Mao             g_assert_cmphex(qtest_readq(qts, addr), ==, NPCM7XX_MAXCURR_RESET);
1574c579e15SShengtan Mao             addr += 8;
1584c579e15SShengtan Mao             break;
1594c579e15SShengtan Mao         case SDHC_HCVER:
1604c579e15SShengtan Mao             g_assert_cmphex(qtest_readw(qts, addr), ==, NPCM7XX_HCVER_RESET);
1614c579e15SShengtan Mao             addr += 2;
1624c579e15SShengtan Mao             break;
1634c579e15SShengtan Mao         case NPCM7XX_PRSTVALS:
1644c579e15SShengtan Mao             for (i = 0; i < NPCM7XX_PRSTVALS_SIZE; ++i) {
1654c579e15SShengtan Mao                 g_assert_cmphex(qtest_readw(qts, addr + 2 * i), ==,
1664c579e15SShengtan Mao                                 prstvals_resets[i]);
1674c579e15SShengtan Mao             }
1684c579e15SShengtan Mao             addr += NPCM7XX_PRSTVALS_SIZE * 2;
1694c579e15SShengtan Mao             break;
1704c579e15SShengtan Mao         default:
1714c579e15SShengtan Mao             g_assert_cmphex(qtest_readb(qts, addr), ==, 0);
1724c579e15SShengtan Mao             addr += 1;
1734c579e15SShengtan Mao         }
1744c579e15SShengtan Mao     }
1754c579e15SShengtan Mao 
1764c579e15SShengtan Mao     qtest_quit(qts);
1774c579e15SShengtan Mao }
1784c579e15SShengtan Mao 
drive_destroy(void)1794c579e15SShengtan Mao static void drive_destroy(void)
1804c579e15SShengtan Mao {
1814c579e15SShengtan Mao     unlink(sd_path);
1824c579e15SShengtan Mao     g_free(sd_path);
1834c579e15SShengtan Mao }
1844c579e15SShengtan Mao 
drive_create(void)1854c579e15SShengtan Mao static void drive_create(void)
1864c579e15SShengtan Mao {
1874c579e15SShengtan Mao     int fd, ret;
1884c579e15SShengtan Mao     GError *error = NULL;
1894c579e15SShengtan Mao 
1904c579e15SShengtan Mao     /* Create a temporary raw image */
1914c579e15SShengtan Mao     fd = g_file_open_tmp("sdhci_XXXXXX", &sd_path, &error);
1924c579e15SShengtan Mao     if (fd == -1) {
1934c579e15SShengtan Mao         fprintf(stderr, "unable to create sdhci file: %s\n", error->message);
1944c579e15SShengtan Mao         g_error_free(error);
1954c579e15SShengtan Mao     }
1964c579e15SShengtan Mao     g_assert(sd_path != NULL);
1974c579e15SShengtan Mao 
1984c579e15SShengtan Mao     ret = ftruncate(fd, NPCM7XX_TEST_IMAGE_SIZE);
1994c579e15SShengtan Mao     g_assert_cmpint(ret, ==, 0);
2004c579e15SShengtan Mao     g_message("%s", sd_path);
2014c579e15SShengtan Mao     close(fd);
2024c579e15SShengtan Mao }
2034c579e15SShengtan Mao 
main(int argc,char ** argv)2044c579e15SShengtan Mao int main(int argc, char **argv)
2054c579e15SShengtan Mao {
2064c579e15SShengtan Mao     int ret;
2074c579e15SShengtan Mao 
2084c579e15SShengtan Mao     drive_create();
2094c579e15SShengtan Mao 
2104c579e15SShengtan Mao     g_test_init(&argc, &argv, NULL);
2114c579e15SShengtan Mao 
2124c579e15SShengtan Mao     qtest_add_func("npcm7xx_sdhci/reset", test_reset);
2134c579e15SShengtan Mao     qtest_add_func("npcm7xx_sdhci/write_sd", test_write_sd);
2144c579e15SShengtan Mao     qtest_add_func("npcm7xx_sdhci/read_sd", test_read_sd);
2154c579e15SShengtan Mao 
2164c579e15SShengtan Mao     ret = g_test_run();
2174c579e15SShengtan Mao     drive_destroy();
2184c579e15SShengtan Mao     return ret;
2194c579e15SShengtan Mao }
220