qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

npcm7xx_sdhci-test.c (6000B)


      1 /*
      2  * QTests for NPCM7xx SD-3.0 / MMC-4.51 Host Controller
      3  *
      4  * Copyright (c) 2022 Google LLC
      5  *
      6  * This program is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License as published by the
      8  * Free Software Foundation; either version 2 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
     14  * for more details.
     15  */
     16 
     17 #include "qemu/osdep.h"
     18 #include "hw/sd/npcm7xx_sdhci.h"
     19 
     20 #include "libqtest.h"
     21 #include "libqtest-single.h"
     22 #include "libqos/sdhci-cmd.h"
     23 
     24 #define NPCM7XX_REG_SIZE 0x100
     25 #define NPCM7XX_MMC_BA 0xF0842000
     26 #define NPCM7XX_BLK_SIZE 512
     27 #define NPCM7XX_TEST_IMAGE_SIZE (1 << 20)
     28 
     29 char *sd_path;
     30 
     31 static QTestState *setup_sd_card(void)
     32 {
     33     QTestState *qts = qtest_initf(
     34         "-machine kudo-bmc "
     35         "-device sd-card,drive=drive0 "
     36         "-drive id=drive0,if=none,file=%s,format=raw,auto-read-only=off",
     37         sd_path);
     38 
     39     qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_SWRST, SDHC_RESET_ALL);
     40     qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_CLKCON,
     41                  SDHC_CLOCK_SDCLK_EN | SDHC_CLOCK_INT_STABLE |
     42                      SDHC_CLOCK_INT_EN);
     43     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_APP_CMD);
     44     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x41200000, 0, (41 << 8));
     45     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_ALL_SEND_CID);
     46     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_SEND_RELATIVE_ADDR);
     47     sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x45670000, 0,
     48                    SDHC_SELECT_DESELECT_CARD);
     49 
     50     return qts;
     51 }
     52 
     53 static void write_sdread(QTestState *qts, const char *msg)
     54 {
     55     int fd, ret;
     56     size_t len = strlen(msg);
     57     char *rmsg = g_malloc(len);
     58 
     59     /* write message to sd */
     60     fd = open(sd_path, O_WRONLY);
     61     g_assert(fd >= 0);
     62     ret = write(fd, msg, len);
     63     close(fd);
     64     g_assert(ret == len);
     65 
     66     /* read message using sdhci */
     67     ret = sdhci_read_cmd(qts, NPCM7XX_MMC_BA, rmsg, len);
     68     g_assert(ret == len);
     69     g_assert(!memcmp(rmsg, msg, len));
     70 
     71     g_free(rmsg);
     72 }
     73 
     74 /* Check MMC can read values from sd */
     75 static void test_read_sd(void)
     76 {
     77     QTestState *qts = setup_sd_card();
     78 
     79     write_sdread(qts, "hello world");
     80     write_sdread(qts, "goodbye");
     81 
     82     qtest_quit(qts);
     83 }
     84 
     85 static void sdwrite_read(QTestState *qts, const char *msg)
     86 {
     87     int fd, ret;
     88     size_t len = strlen(msg);
     89     char *rmsg = g_malloc(len);
     90 
     91     /* write message using sdhci */
     92     sdhci_write_cmd(qts, NPCM7XX_MMC_BA, msg, len, NPCM7XX_BLK_SIZE);
     93 
     94     /* read message from sd */
     95     fd = open(sd_path, O_RDONLY);
     96     g_assert(fd >= 0);
     97     ret = read(fd, rmsg, len);
     98     close(fd);
     99     g_assert(ret == len);
    100 
    101     g_assert(!memcmp(rmsg, msg, len));
    102 
    103     g_free(rmsg);
    104 }
    105 
    106 /* Check MMC can write values to sd */
    107 static void test_write_sd(void)
    108 {
    109     QTestState *qts = setup_sd_card();
    110 
    111     sdwrite_read(qts, "hello world");
    112     sdwrite_read(qts, "goodbye");
    113 
    114     qtest_quit(qts);
    115 }
    116 
    117 /* Check SDHCI has correct default values. */
    118 static void test_reset(void)
    119 {
    120     QTestState *qts = qtest_init("-machine kudo-bmc");
    121     uint64_t addr = NPCM7XX_MMC_BA;
    122     uint64_t end_addr = addr + NPCM7XX_REG_SIZE;
    123     uint16_t prstvals_resets[] = {NPCM7XX_PRSTVALS_0_RESET,
    124                                   NPCM7XX_PRSTVALS_1_RESET,
    125                                   0,
    126                                   NPCM7XX_PRSTVALS_3_RESET,
    127                                   0,
    128                                   0};
    129     int i;
    130     uint32_t mask;
    131 
    132     while (addr < end_addr) {
    133         switch (addr - NPCM7XX_MMC_BA) {
    134         case SDHC_PRNSTS:
    135             /*
    136              * ignores bits 20 to 24: they are changed when reading registers
    137              */
    138             mask = 0x1f00000;
    139             g_assert_cmphex(qtest_readl(qts, addr) | mask, ==,
    140                             NPCM7XX_PRSNTS_RESET | mask);
    141             addr += 4;
    142             break;
    143         case SDHC_BLKGAP:
    144             g_assert_cmphex(qtest_readb(qts, addr), ==, NPCM7XX_BLKGAP_RESET);
    145             addr += 1;
    146             break;
    147         case SDHC_CAPAB:
    148             g_assert_cmphex(qtest_readq(qts, addr), ==, NPCM7XX_CAPAB_RESET);
    149             addr += 8;
    150             break;
    151         case SDHC_MAXCURR:
    152             g_assert_cmphex(qtest_readq(qts, addr), ==, NPCM7XX_MAXCURR_RESET);
    153             addr += 8;
    154             break;
    155         case SDHC_HCVER:
    156             g_assert_cmphex(qtest_readw(qts, addr), ==, NPCM7XX_HCVER_RESET);
    157             addr += 2;
    158             break;
    159         case NPCM7XX_PRSTVALS:
    160             for (i = 0; i < NPCM7XX_PRSTVALS_SIZE; ++i) {
    161                 g_assert_cmphex(qtest_readw(qts, addr + 2 * i), ==,
    162                                 prstvals_resets[i]);
    163             }
    164             addr += NPCM7XX_PRSTVALS_SIZE * 2;
    165             break;
    166         default:
    167             g_assert_cmphex(qtest_readb(qts, addr), ==, 0);
    168             addr += 1;
    169         }
    170     }
    171 
    172     qtest_quit(qts);
    173 }
    174 
    175 static void drive_destroy(void)
    176 {
    177     unlink(sd_path);
    178     g_free(sd_path);
    179 }
    180 
    181 static void drive_create(void)
    182 {
    183     int fd, ret;
    184     GError *error = NULL;
    185 
    186     /* Create a temporary raw image */
    187     fd = g_file_open_tmp("sdhci_XXXXXX", &sd_path, &error);
    188     if (fd == -1) {
    189         fprintf(stderr, "unable to create sdhci file: %s\n", error->message);
    190         g_error_free(error);
    191     }
    192     g_assert(sd_path != NULL);
    193 
    194     ret = ftruncate(fd, NPCM7XX_TEST_IMAGE_SIZE);
    195     g_assert_cmpint(ret, ==, 0);
    196     g_message("%s", sd_path);
    197     close(fd);
    198 }
    199 
    200 int main(int argc, char **argv)
    201 {
    202     int ret;
    203 
    204     drive_create();
    205 
    206     g_test_init(&argc, &argv, NULL);
    207 
    208     qtest_add_func("npcm7xx_sdhci/reset", test_reset);
    209     qtest_add_func("npcm7xx_sdhci/write_sd", test_write_sd);
    210     qtest_add_func("npcm7xx_sdhci/read_sd", test_read_sd);
    211 
    212     ret = g_test_run();
    213     drive_destroy();
    214     return ret;
    215 }