1da2f02b3SShengtan Mao /*
2da2f02b3SShengtan Mao * MMC Host Controller Commands
3da2f02b3SShengtan Mao *
4da2f02b3SShengtan Mao * Copyright (c) 2021 Google LLC
5da2f02b3SShengtan Mao *
6da2f02b3SShengtan Mao * This program is free software; you can redistribute it and/or modify it
7da2f02b3SShengtan Mao * under the terms of the GNU General Public License as published by the
8da2f02b3SShengtan Mao * Free Software Foundation; either version 2 of the License, or
9da2f02b3SShengtan Mao * (at your option) any later version.
10da2f02b3SShengtan Mao *
11da2f02b3SShengtan Mao * This program is distributed in the hope that it will be useful, but WITHOUT
12da2f02b3SShengtan Mao * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13da2f02b3SShengtan Mao * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14da2f02b3SShengtan Mao * for more details.
15da2f02b3SShengtan Mao */
16da2f02b3SShengtan Mao
17da2f02b3SShengtan Mao #include "qemu/osdep.h"
18da2f02b3SShengtan Mao #include "sdhci-cmd.h"
19*907b5105SMarc-André Lureau #include "../libqtest.h"
20da2f02b3SShengtan Mao
read_fifo(QTestState * qts,uint64_t reg,char * msg,size_t count)21da2f02b3SShengtan Mao static ssize_t read_fifo(QTestState *qts, uint64_t reg, char *msg, size_t count)
22da2f02b3SShengtan Mao {
23da2f02b3SShengtan Mao uint32_t mask = 0xff;
24da2f02b3SShengtan Mao size_t index = 0;
25da2f02b3SShengtan Mao uint32_t msg_frag;
26da2f02b3SShengtan Mao int size;
27da2f02b3SShengtan Mao while (index < count) {
28da2f02b3SShengtan Mao size = count - index;
29da2f02b3SShengtan Mao if (size > 4) {
30da2f02b3SShengtan Mao size = 4;
31da2f02b3SShengtan Mao }
32da2f02b3SShengtan Mao msg_frag = qtest_readl(qts, reg);
33da2f02b3SShengtan Mao while (size > 0) {
34da2f02b3SShengtan Mao msg[index] = msg_frag & mask;
35da2f02b3SShengtan Mao if (msg[index++] == 0) {
36da2f02b3SShengtan Mao return index;
37da2f02b3SShengtan Mao }
38da2f02b3SShengtan Mao msg_frag >>= 8;
39da2f02b3SShengtan Mao --size;
40da2f02b3SShengtan Mao }
41da2f02b3SShengtan Mao }
42da2f02b3SShengtan Mao return index;
43da2f02b3SShengtan Mao }
44da2f02b3SShengtan Mao
write_fifo(QTestState * qts,uint64_t reg,const char * msg,size_t count)45da2f02b3SShengtan Mao static void write_fifo(QTestState *qts, uint64_t reg, const char *msg,
46da2f02b3SShengtan Mao size_t count)
47da2f02b3SShengtan Mao {
48da2f02b3SShengtan Mao size_t index = 0;
49da2f02b3SShengtan Mao uint32_t msg_frag;
50da2f02b3SShengtan Mao int size;
51da2f02b3SShengtan Mao int frag_i;
52da2f02b3SShengtan Mao while (index < count) {
53da2f02b3SShengtan Mao size = count - index;
54da2f02b3SShengtan Mao if (size > 4) {
55da2f02b3SShengtan Mao size = 4;
56da2f02b3SShengtan Mao }
57da2f02b3SShengtan Mao msg_frag = 0;
58da2f02b3SShengtan Mao frag_i = 0;
59da2f02b3SShengtan Mao while (frag_i < size) {
60da2f02b3SShengtan Mao msg_frag |= ((uint32_t)msg[index++]) << (frag_i * 8);
61da2f02b3SShengtan Mao ++frag_i;
62da2f02b3SShengtan Mao }
63da2f02b3SShengtan Mao qtest_writel(qts, reg, msg_frag);
64da2f02b3SShengtan Mao }
65da2f02b3SShengtan Mao }
66da2f02b3SShengtan Mao
fill_block(QTestState * qts,uint64_t reg,int count)67da2f02b3SShengtan Mao static void fill_block(QTestState *qts, uint64_t reg, int count)
68da2f02b3SShengtan Mao {
69da2f02b3SShengtan Mao while (--count >= 0) {
70da2f02b3SShengtan Mao qtest_writel(qts, reg, 0);
71da2f02b3SShengtan Mao }
72da2f02b3SShengtan Mao }
73da2f02b3SShengtan Mao
sdhci_cmd_regs(QTestState * qts,uint64_t base_addr,uint16_t blksize,uint16_t blkcnt,uint32_t argument,uint16_t trnmod,uint16_t cmdreg)74da2f02b3SShengtan Mao void sdhci_cmd_regs(QTestState *qts, uint64_t base_addr, uint16_t blksize,
75da2f02b3SShengtan Mao uint16_t blkcnt, uint32_t argument, uint16_t trnmod,
76da2f02b3SShengtan Mao uint16_t cmdreg)
77da2f02b3SShengtan Mao {
78da2f02b3SShengtan Mao qtest_writew(qts, base_addr + SDHC_BLKSIZE, blksize);
79da2f02b3SShengtan Mao qtest_writew(qts, base_addr + SDHC_BLKCNT, blkcnt);
80da2f02b3SShengtan Mao qtest_writel(qts, base_addr + SDHC_ARGUMENT, argument);
81da2f02b3SShengtan Mao qtest_writew(qts, base_addr + SDHC_TRNMOD, trnmod);
82da2f02b3SShengtan Mao qtest_writew(qts, base_addr + SDHC_CMDREG, cmdreg);
83da2f02b3SShengtan Mao }
84da2f02b3SShengtan Mao
sdhci_read_cmd(QTestState * qts,uint64_t base_addr,char * msg,size_t count)85da2f02b3SShengtan Mao ssize_t sdhci_read_cmd(QTestState *qts, uint64_t base_addr, char *msg,
86da2f02b3SShengtan Mao size_t count)
87da2f02b3SShengtan Mao {
88da2f02b3SShengtan Mao sdhci_cmd_regs(qts, base_addr, count, 1, 0,
89da2f02b3SShengtan Mao SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN,
90da2f02b3SShengtan Mao SDHC_READ_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT);
91da2f02b3SShengtan Mao
92da2f02b3SShengtan Mao /* read sd fifo_buffer */
93da2f02b3SShengtan Mao ssize_t bytes_read = read_fifo(qts, base_addr + SDHC_BDATA, msg, count);
94da2f02b3SShengtan Mao
95da2f02b3SShengtan Mao sdhci_cmd_regs(qts, base_addr, 0, 0, 0,
96da2f02b3SShengtan Mao SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN,
97da2f02b3SShengtan Mao SDHC_STOP_TRANSMISSION);
98da2f02b3SShengtan Mao
99da2f02b3SShengtan Mao return bytes_read;
100da2f02b3SShengtan Mao }
101da2f02b3SShengtan Mao
sdhci_write_cmd(QTestState * qts,uint64_t base_addr,const char * msg,size_t count,size_t blksize)102da2f02b3SShengtan Mao void sdhci_write_cmd(QTestState *qts, uint64_t base_addr, const char *msg,
103da2f02b3SShengtan Mao size_t count, size_t blksize)
104da2f02b3SShengtan Mao {
105da2f02b3SShengtan Mao sdhci_cmd_regs(qts, base_addr, blksize, 1, 0,
106da2f02b3SShengtan Mao SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN,
107da2f02b3SShengtan Mao SDHC_WRITE_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT);
108da2f02b3SShengtan Mao
109da2f02b3SShengtan Mao /* write to sd fifo_buffer */
110da2f02b3SShengtan Mao write_fifo(qts, base_addr + SDHC_BDATA, msg, count);
111da2f02b3SShengtan Mao fill_block(qts, base_addr + SDHC_BDATA, (blksize - count) / 4);
112da2f02b3SShengtan Mao
113da2f02b3SShengtan Mao sdhci_cmd_regs(qts, base_addr, 0, 0, 0,
114da2f02b3SShengtan Mao SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN,
115da2f02b3SShengtan Mao SDHC_STOP_TRANSMISSION);
116da2f02b3SShengtan Mao }
117