tests/qtest/libqos: add SDHCI commands
Signed-off-by: Shengtan Mao <stmao@google.com> Signed-off-by: Hao Wu <wuhaotsh@google.com> Reviewed-by: Hao Wu <wuhaotsh@google.com> Reviewed-by: Chris Rauer <crauer@google.com> Reviewed-by: Tyrone Ting <kfting@nuvoton.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-Id: <20211008002628.1958285-5-wuhaotsh@google.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
2cb06d492d
commit
da2f02b360
@ -5,6 +5,7 @@ libqos_srcs = files('../libqtest.c',
|
||||
'fw_cfg.c',
|
||||
'malloc.c',
|
||||
'libqos.c',
|
||||
'sdhci-cmd.c',
|
||||
|
||||
# spapr
|
||||
'malloc-spapr.c',
|
||||
|
116
tests/qtest/libqos/sdhci-cmd.c
Normal file
116
tests/qtest/libqos/sdhci-cmd.c
Normal file
@ -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);
|
||||
}
|
70
tests/qtest/libqos/sdhci-cmd.h
Normal file
70
tests/qtest/libqos/sdhci-cmd.h
Normal file
@ -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);
|
Loading…
Reference in New Issue
Block a user