qemu

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

sdhci-cmd.c (3605B)


      1 /*
      2  * MMC Host Controller Commands
      3  *
      4  * Copyright (c) 2021 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 "sdhci-cmd.h"
     19 #include "../libqtest.h"
     20 
     21 static ssize_t read_fifo(QTestState *qts, uint64_t reg, char *msg, size_t count)
     22 {
     23     uint32_t mask = 0xff;
     24     size_t index = 0;
     25     uint32_t msg_frag;
     26     int size;
     27     while (index < count) {
     28         size = count - index;
     29         if (size > 4) {
     30             size = 4;
     31         }
     32         msg_frag = qtest_readl(qts, reg);
     33         while (size > 0) {
     34             msg[index] = msg_frag & mask;
     35             if (msg[index++] == 0) {
     36                 return index;
     37             }
     38             msg_frag >>= 8;
     39             --size;
     40         }
     41     }
     42     return index;
     43 }
     44 
     45 static void write_fifo(QTestState *qts, uint64_t reg, const char *msg,
     46                        size_t count)
     47 {
     48     size_t index = 0;
     49     uint32_t msg_frag;
     50     int size;
     51     int frag_i;
     52     while (index < count) {
     53         size = count - index;
     54         if (size > 4) {
     55             size = 4;
     56         }
     57         msg_frag = 0;
     58         frag_i = 0;
     59         while (frag_i < size) {
     60             msg_frag |= ((uint32_t)msg[index++]) << (frag_i * 8);
     61             ++frag_i;
     62         }
     63         qtest_writel(qts, reg, msg_frag);
     64     }
     65 }
     66 
     67 static void fill_block(QTestState *qts, uint64_t reg, int count)
     68 {
     69     while (--count >= 0) {
     70         qtest_writel(qts, reg, 0);
     71     }
     72 }
     73 
     74 void sdhci_cmd_regs(QTestState *qts, uint64_t base_addr, uint16_t blksize,
     75                     uint16_t blkcnt, uint32_t argument, uint16_t trnmod,
     76                     uint16_t cmdreg)
     77 {
     78     qtest_writew(qts, base_addr + SDHC_BLKSIZE, blksize);
     79     qtest_writew(qts, base_addr + SDHC_BLKCNT, blkcnt);
     80     qtest_writel(qts, base_addr + SDHC_ARGUMENT, argument);
     81     qtest_writew(qts, base_addr + SDHC_TRNMOD, trnmod);
     82     qtest_writew(qts, base_addr + SDHC_CMDREG, cmdreg);
     83 }
     84 
     85 ssize_t sdhci_read_cmd(QTestState *qts, uint64_t base_addr, char *msg,
     86                        size_t count)
     87 {
     88     sdhci_cmd_regs(qts, base_addr, count, 1, 0,
     89                    SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN,
     90                    SDHC_READ_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT);
     91 
     92     /* read sd fifo_buffer */
     93     ssize_t bytes_read = read_fifo(qts, base_addr + SDHC_BDATA, msg, count);
     94 
     95     sdhci_cmd_regs(qts, base_addr, 0, 0, 0,
     96                    SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN,
     97                    SDHC_STOP_TRANSMISSION);
     98 
     99     return bytes_read;
    100 }
    101 
    102 void sdhci_write_cmd(QTestState *qts, uint64_t base_addr, const char *msg,
    103                      size_t count, size_t blksize)
    104 {
    105     sdhci_cmd_regs(qts, base_addr, blksize, 1, 0,
    106                    SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN,
    107                    SDHC_WRITE_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT);
    108 
    109     /* write to sd fifo_buffer */
    110     write_fifo(qts, base_addr + SDHC_BDATA, msg, count);
    111     fill_block(qts, base_addr + SDHC_BDATA, (blksize - count) / 4);
    112 
    113     sdhci_cmd_regs(qts, base_addr, 0, 0, 0,
    114                    SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN,
    115                    SDHC_STOP_TRANSMISSION);
    116 }