sdhci-cmd.c 3.5 KB

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