qemu/tests/qtest/libqos/sdhci-cmd.c
<<
>>
Prefs
   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
  21static 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
  45static 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
  67static void fill_block(QTestState *qts, uint64_t reg, int count)
  68{
  69    while (--count >= 0) {
  70        qtest_writel(qts, reg, 0);
  71    }
  72}
  73
  74void 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
  85ssize_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
 102void 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}
 117