diff mbox series

[PULL,v2,04/12] tests/qtest/libqos: add SDHCI commands

Message ID 20211102182519.320319-5-richard.henderson@linaro.org
State New
Headers show
Series target/arm patch queue | expand

Commit Message

Richard Henderson Nov. 2, 2021, 6:25 p.m. UTC
From: Shengtan Mao <stmao@google.com>


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>

---
 tests/qtest/libqos/sdhci-cmd.h |  70 ++++++++++++++++++++
 tests/qtest/libqos/sdhci-cmd.c | 116 +++++++++++++++++++++++++++++++++
 tests/qtest/libqos/meson.build |   1 +
 3 files changed, 187 insertions(+)
 create mode 100644 tests/qtest/libqos/sdhci-cmd.h
 create mode 100644 tests/qtest/libqos/sdhci-cmd.c

-- 
2.25.1

Comments

Hao Wu Nov. 2, 2021, 10:49 p.m. UTC | #1
Hi,

I've sent a new patch set which uses memcpy here. Thank you!


On Tue, Nov 2, 2021 at 11:25 AM Richard Henderson <
richard.henderson@linaro.org> wrote:

> From: Shengtan Mao <stmao@google.com>

>

> 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>

> ---

>  tests/qtest/libqos/sdhci-cmd.h |  70 ++++++++++++++++++++

>  tests/qtest/libqos/sdhci-cmd.c | 116 +++++++++++++++++++++++++++++++++

>  tests/qtest/libqos/meson.build |   1 +

>  3 files changed, 187 insertions(+)

>  create mode 100644 tests/qtest/libqos/sdhci-cmd.h

>  create mode 100644 tests/qtest/libqos/sdhci-cmd.c

>

> 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);

> 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/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',

> --

> 2.25.1

>

>
<div dir="ltr">Hi,<div><br></div><div>I&#39;ve sent a new patch set which uses memcpy here. Thank you!</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Nov 2, 2021 at 11:25 AM Richard Henderson &lt;<a href="mailto:richard.henderson@linaro.org">richard.henderson@linaro.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">From: Shengtan Mao &lt;<a href="mailto:stmao@google.com" target="_blank">stmao@google.com</a>&gt;<br>
<br>
Signed-off-by: Shengtan Mao &lt;<a href="mailto:stmao@google.com" target="_blank">stmao@google.com</a>&gt;<br>

Signed-off-by: Hao Wu &lt;<a href="mailto:wuhaotsh@google.com" target="_blank">wuhaotsh@google.com</a>&gt;<br>

Reviewed-by: Hao Wu &lt;<a href="mailto:wuhaotsh@google.com" target="_blank">wuhaotsh@google.com</a>&gt;<br>

Reviewed-by: Chris Rauer &lt;<a href="mailto:crauer@google.com" target="_blank">crauer@google.com</a>&gt;<br>

Reviewed-by: Tyrone Ting &lt;<a href="mailto:kfting@nuvoton.com" target="_blank">kfting@nuvoton.com</a>&gt;<br>

Reviewed-by: Peter Maydell &lt;<a href="mailto:peter.maydell@linaro.org" target="_blank">peter.maydell@linaro.org</a>&gt;<br>

Message-Id: &lt;<a href="mailto:20211008002628.1958285-5-wuhaotsh@google.com" target="_blank">20211008002628.1958285-5-wuhaotsh@google.com</a>&gt;<br>
Signed-off-by: Richard Henderson &lt;<a href="mailto:richard.henderson@linaro.org" target="_blank">richard.henderson@linaro.org</a>&gt;<br>

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

Patch

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);
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/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',