From da2f02b360f405d7badc4a3028276e07db58026c Mon Sep 17 00:00:00 2001 From: Shengtan Mao Date: Thu, 7 Oct 2021 17:26:27 -0700 Subject: [PATCH] tests/qtest/libqos: add SDHCI commands Signed-off-by: Shengtan Mao Signed-off-by: Hao Wu Reviewed-by: Hao Wu Reviewed-by: Chris Rauer Reviewed-by: Tyrone Ting Reviewed-by: Peter Maydell Message-Id: <20211008002628.1958285-5-wuhaotsh@google.com> Signed-off-by: Richard Henderson --- tests/qtest/libqos/meson.build | 1 + tests/qtest/libqos/sdhci-cmd.c | 116 +++++++++++++++++++++++++++++++++++++++++ tests/qtest/libqos/sdhci-cmd.h | 70 +++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 tests/qtest/libqos/sdhci-cmd.c create mode 100644 tests/qtest/libqos/sdhci-cmd.h diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build index 1f5c8f1053..4af1f04787 100644 --- a/tests/qtest/libqos/meson.build +++ b/tests/qtest/libqos/meson.build @@ -5,6 +5,7 @@ libqos_srcs = files('../libqtest.c', 'fw_cfg.c', 'malloc.c', 'libqos.c', + 'sdhci-cmd.c', # spapr 'malloc-spapr.c', diff --git a/tests/qtest/libqos/sdhci-cmd.c b/tests/qtest/libqos/sdhci-cmd.c new file mode 100644 index 0000000000..2d9e518341 --- /dev/null +++ b/tests/qtest/libqos/sdhci-cmd.c @@ -0,0 +1,116 @@ +/* + * MMC Host Controller Commands + * + * Copyright (c) 2021 Google LLC + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "qemu/osdep.h" +#include "sdhci-cmd.h" +#include "libqtest.h" + +static ssize_t read_fifo(QTestState *qts, uint64_t reg, char *msg, size_t count) +{ + uint32_t mask = 0xff; + size_t index = 0; + uint32_t msg_frag; + int size; + while (index < count) { + size = count - index; + if (size > 4) { + size = 4; + } + msg_frag = qtest_readl(qts, reg); + while (size > 0) { + msg[index] = msg_frag & mask; + if (msg[index++] == 0) { + return index; + } + msg_frag >>= 8; + --size; + } + } + return index; +} + +static void write_fifo(QTestState *qts, uint64_t reg, const char *msg, + size_t count) +{ + size_t index = 0; + uint32_t msg_frag; + int size; + int frag_i; + while (index < count) { + size = count - index; + if (size > 4) { + size = 4; + } + msg_frag = 0; + frag_i = 0; + while (frag_i < size) { + msg_frag |= ((uint32_t)msg[index++]) << (frag_i * 8); + ++frag_i; + } + qtest_writel(qts, reg, msg_frag); + } +} + +static void fill_block(QTestState *qts, uint64_t reg, int count) +{ + while (--count >= 0) { + qtest_writel(qts, reg, 0); + } +} + +void sdhci_cmd_regs(QTestState *qts, uint64_t base_addr, uint16_t blksize, + uint16_t blkcnt, uint32_t argument, uint16_t trnmod, + uint16_t cmdreg) +{ + qtest_writew(qts, base_addr + SDHC_BLKSIZE, blksize); + qtest_writew(qts, base_addr + SDHC_BLKCNT, blkcnt); + qtest_writel(qts, base_addr + SDHC_ARGUMENT, argument); + qtest_writew(qts, base_addr + SDHC_TRNMOD, trnmod); + qtest_writew(qts, base_addr + SDHC_CMDREG, cmdreg); +} + +ssize_t sdhci_read_cmd(QTestState *qts, uint64_t base_addr, char *msg, + size_t count) +{ + sdhci_cmd_regs(qts, base_addr, count, 1, 0, + SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN, + SDHC_READ_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT); + + /* read sd fifo_buffer */ + ssize_t bytes_read = read_fifo(qts, base_addr + SDHC_BDATA, msg, count); + + sdhci_cmd_regs(qts, base_addr, 0, 0, 0, + SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN, + SDHC_STOP_TRANSMISSION); + + return bytes_read; +} + +void sdhci_write_cmd(QTestState *qts, uint64_t base_addr, const char *msg, + size_t count, size_t blksize) +{ + sdhci_cmd_regs(qts, base_addr, blksize, 1, 0, + SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN, + SDHC_WRITE_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT); + + /* write to sd fifo_buffer */ + write_fifo(qts, base_addr + SDHC_BDATA, msg, count); + fill_block(qts, base_addr + SDHC_BDATA, (blksize - count) / 4); + + sdhci_cmd_regs(qts, base_addr, 0, 0, 0, + SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN, + SDHC_STOP_TRANSMISSION); +} diff --git a/tests/qtest/libqos/sdhci-cmd.h b/tests/qtest/libqos/sdhci-cmd.h new file mode 100644 index 0000000000..64763c5a2a --- /dev/null +++ b/tests/qtest/libqos/sdhci-cmd.h @@ -0,0 +1,70 @@ +/* + * MMC Host Controller Commands + * + * Copyright (c) 2021 Google LLC + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "libqtest.h" + +/* more details at hw/sd/sdhci-internal.h */ +#define SDHC_BLKSIZE 0x04 +#define SDHC_BLKCNT 0x06 +#define SDHC_ARGUMENT 0x08 +#define SDHC_TRNMOD 0x0C +#define SDHC_CMDREG 0x0E +#define SDHC_BDATA 0x20 +#define SDHC_PRNSTS 0x24 +#define SDHC_BLKGAP 0x2A +#define SDHC_CLKCON 0x2C +#define SDHC_SWRST 0x2F +#define SDHC_CAPAB 0x40 +#define SDHC_MAXCURR 0x48 +#define SDHC_HCVER 0xFE + +/* TRNSMOD Reg */ +#define SDHC_TRNS_BLK_CNT_EN 0x0002 +#define SDHC_TRNS_READ 0x0010 +#define SDHC_TRNS_WRITE 0x0000 +#define SDHC_TRNS_MULTI 0x0020 + +/* CMD Reg */ +#define SDHC_CMD_DATA_PRESENT (1 << 5) +#define SDHC_ALL_SEND_CID (2 << 8) +#define SDHC_SEND_RELATIVE_ADDR (3 << 8) +#define SDHC_SELECT_DESELECT_CARD (7 << 8) +#define SDHC_SEND_CSD (9 << 8) +#define SDHC_STOP_TRANSMISSION (12 << 8) +#define SDHC_READ_MULTIPLE_BLOCK (18 << 8) +#define SDHC_WRITE_MULTIPLE_BLOCK (25 << 8) +#define SDHC_APP_CMD (55 << 8) + +/* SWRST Reg */ +#define SDHC_RESET_ALL 0x01 + +/* CLKCTRL Reg */ +#define SDHC_CLOCK_INT_EN 0x0001 +#define SDHC_CLOCK_INT_STABLE 0x0002 +#define SDHC_CLOCK_SDCLK_EN (1 << 2) + +/* Set registers needed to send commands to SD */ +void sdhci_cmd_regs(QTestState *qts, uint64_t base_addr, uint16_t blksize, + uint16_t blkcnt, uint32_t argument, uint16_t trnmod, + uint16_t cmdreg); + +/* Read at most 1 block of SD using non-DMA */ +ssize_t sdhci_read_cmd(QTestState *qts, uint64_t base_addr, char *msg, + size_t count); + +/* Write at most 1 block of SD using non-DMA */ +void sdhci_write_cmd(QTestState *qts, uint64_t base_addr, const char *msg, + size_t count, size_t blksize); -- 2.11.0