diff options
Diffstat (limited to 'hw/sd')
-rw-r--r-- | hw/sd/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/sd/sd.c | 55 | ||||
-rw-r--r-- | hw/sd/sdhci.c | 4 | ||||
-rw-r--r-- | hw/sd/sdmmc-internal.c | 72 | ||||
-rw-r--r-- | hw/sd/sdmmc-internal.h | 24 | ||||
-rw-r--r-- | hw/sd/trace-events | 8 |
6 files changed, 152 insertions, 13 deletions
diff --git a/hw/sd/Makefile.objs b/hw/sd/Makefile.objs index c2b7664264..a99d9fbb04 100644 --- a/hw/sd/Makefile.objs +++ b/hw/sd/Makefile.objs @@ -1,6 +1,6 @@ common-obj-$(CONFIG_PL181) += pl181.o common-obj-$(CONFIG_SSI_SD) += ssi-sd.o -common-obj-$(CONFIG_SD) += sd.o core.o +common-obj-$(CONFIG_SD) += sd.o core.o sdmmc-internal.o common-obj-$(CONFIG_SDHCI) += sdhci.o obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 933890e86f..235e0518d6 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -120,6 +120,7 @@ struct SDState { qemu_irq readonly_cb; qemu_irq inserted_cb; QEMUTimer *ocr_power_timer; + const char *proto_name; bool enable; uint8_t dat_lines; bool cmd_line; @@ -866,13 +867,19 @@ static void sd_lock_command(SDState *sd) sd->card_status &= ~CARD_IS_LOCKED; } -static sd_rsp_type_t sd_normal_command(SDState *sd, - SDRequest req) +static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint32_t rca = 0x0000; uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : req.arg; - trace_sdcard_normal_command(req.cmd, req.arg, sd_state_name(sd->state)); + /* CMD55 precedes an ACMD, so we are not interested in tracing it. + * However there is no ACMD55, so we want to trace this particular case. + */ + if (req.cmd != 55 || sd->expecting_acmd) { + trace_sdcard_normal_command(sd->proto_name, + sd_cmd_name(req.cmd), req.cmd, + req.arg, sd_state_name(sd->state)); + } /* Not interpreting this as an app command */ sd->card_status &= ~APP_CMD; @@ -1162,6 +1169,14 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, } break; + case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ + if (sd->state == sd_transfer_state) { + sd->state = sd_sendingdata_state; + sd->data_offset = 0; + return sd_r1; + } + break; + case 23: /* CMD23: SET_BLOCK_COUNT */ switch (sd->state) { case sd_transfer_state: @@ -1450,7 +1465,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, static sd_rsp_type_t sd_app_command(SDState *sd, SDRequest req) { - trace_sdcard_app_command(req.cmd, req.arg); + trace_sdcard_app_command(sd->proto_name, sd_acmd_name(req.cmd), + req.cmd, req.arg, sd_state_name(sd->state)); sd->card_status |= APP_CMD; switch (req.cmd) { case 6: /* ACMD6: SET_BUS_WIDTH */ @@ -1765,7 +1781,9 @@ void sd_write_data(SDState *sd, uint8_t value) if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) return; - trace_sdcard_write_data(sd->current_cmd, value); + trace_sdcard_write_data(sd->proto_name, + sd_acmd_name(sd->current_cmd), + sd->current_cmd, value); switch (sd->current_cmd) { case 24: /* CMD24: WRITE_SINGLE_BLOCK */ sd->data[sd->data_offset ++] = value; @@ -1883,6 +1901,20 @@ void sd_write_data(SDState *sd, uint8_t value) } } +#define SD_TUNING_BLOCK_SIZE 64 + +static const uint8_t sd_tuning_block_pattern[SD_TUNING_BLOCK_SIZE] = { + /* See: Physical Layer Simplified Specification Version 3.01, Table 4-2 */ + 0xff, 0x0f, 0xff, 0x00, 0x0f, 0xfc, 0xc3, 0xcc, + 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, + 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, + 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, + 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, + 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, + 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, + 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, +}; + uint8_t sd_read_data(SDState *sd) { /* TODO: Append CRCs */ @@ -1903,7 +1935,9 @@ uint8_t sd_read_data(SDState *sd) io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len; - trace_sdcard_read_data(sd->current_cmd, io_len); + trace_sdcard_read_data(sd->proto_name, + sd_acmd_name(sd->current_cmd), + sd->current_cmd, io_len); switch (sd->current_cmd) { case 6: /* CMD6: SWITCH_FUNCTION */ ret = sd->data[sd->data_offset ++]; @@ -1960,6 +1994,13 @@ uint8_t sd_read_data(SDState *sd) } break; + case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ + if (sd->data_offset >= SD_TUNING_BLOCK_SIZE - 1) { + sd->state = sd_transfer_state; + } + ret = sd_tuning_block_pattern[sd->data_offset++]; + break; + case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ ret = sd->data[sd->data_offset ++]; @@ -2029,6 +2070,8 @@ static void sd_realize(DeviceState *dev, Error **errp) SDState *sd = SD_CARD(dev); int ret; + sd->proto_name = sd->spi ? "SPI" : "SD"; + if (sd->blk && blk_is_read_only(sd->blk)) { error_setg(errp, "Cannot use read-only drive as SD card"); return; diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 97b4a473c8..1b828b104d 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -433,13 +433,13 @@ static void sdhci_read_block_from_card(SDHCIState *s) for (index = 0; index < blk_size; index++) { data = sdbus_read_data(&s->sdbus); if (!FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, EXECUTE_TUNING)) { - /* Device is not in tunning */ + /* Device is not in tuning */ s->fifo_buffer[index] = data; } } if (FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, EXECUTE_TUNING)) { - /* Device is in tunning */ + /* Device is in tuning */ s->hostctl2 &= ~R_SDHC_HOSTCTL2_EXECUTE_TUNING_MASK; s->hostctl2 |= R_SDHC_HOSTCTL2_SAMPLING_CLKSEL_MASK; s->prnsts &= ~(SDHC_DAT_LINE_ACTIVE | SDHC_DOING_READ | diff --git a/hw/sd/sdmmc-internal.c b/hw/sd/sdmmc-internal.c new file mode 100644 index 0000000000..2053def3f1 --- /dev/null +++ b/hw/sd/sdmmc-internal.c @@ -0,0 +1,72 @@ +/* + * SD/MMC cards common helpers + * + * Copyright (c) 2018 Philippe Mathieu-Daudé <f4bug@amsat.org> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "sdmmc-internal.h" + +const char *sd_cmd_name(uint8_t cmd) +{ + static const char *cmd_abbrev[SDMMC_CMD_MAX] = { + [0] = "GO_IDLE_STATE", + [2] = "ALL_SEND_CID", [3] = "SEND_RELATIVE_ADDR", + [4] = "SET_DSR", [5] = "IO_SEND_OP_COND", + [6] = "SWITCH_FUNC", [7] = "SELECT/DESELECT_CARD", + [8] = "SEND_IF_COND", [9] = "SEND_CSD", + [10] = "SEND_CID", [11] = "VOLTAGE_SWITCH", + [12] = "STOP_TRANSMISSION", [13] = "SEND_STATUS", + [15] = "GO_INACTIVE_STATE", + [16] = "SET_BLOCKLEN", [17] = "READ_SINGLE_BLOCK", + [18] = "READ_MULTIPLE_BLOCK", [19] = "SEND_TUNING_BLOCK", + [20] = "SPEED_CLASS_CONTROL", [21] = "DPS_spec", + [23] = "SET_BLOCK_COUNT", + [24] = "WRITE_BLOCK", [25] = "WRITE_MULTIPLE_BLOCK", + [26] = "MANUF_RSVD", [27] = "PROGRAM_CSD", + [28] = "SET_WRITE_PROT", [29] = "CLR_WRITE_PROT", + [30] = "SEND_WRITE_PROT", + [32] = "ERASE_WR_BLK_START", [33] = "ERASE_WR_BLK_END", + [34] = "SW_FUNC_RSVD", [35] = "SW_FUNC_RSVD", + [36] = "SW_FUNC_RSVD", [37] = "SW_FUNC_RSVD", + [38] = "ERASE", + [40] = "DPS_spec", + [42] = "LOCK_UNLOCK", [43] = "Q_MANAGEMENT", + [44] = "Q_TASK_INFO_A", [45] = "Q_TASK_INFO_B", + [46] = "Q_RD_TASK", [47] = "Q_WR_TASK", + [48] = "READ_EXTR_SINGLE", [49] = "WRITE_EXTR_SINGLE", + [50] = "SW_FUNC_RSVD", + [52] = "IO_RW_DIRECT", [53] = "IO_RW_EXTENDED", + [54] = "SDIO_RSVD", [55] = "APP_CMD", + [56] = "GEN_CMD", [57] = "SW_FUNC_RSVD", + [58] = "READ_EXTR_MULTI", [59] = "WRITE_EXTR_MULTI", + [60] = "MANUF_RSVD", [61] = "MANUF_RSVD", + [62] = "MANUF_RSVD", [63] = "MANUF_RSVD", + }; + return cmd_abbrev[cmd] ? cmd_abbrev[cmd] : "UNKNOWN_CMD"; +} + +const char *sd_acmd_name(uint8_t cmd) +{ + static const char *acmd_abbrev[SDMMC_CMD_MAX] = { + [6] = "SET_BUS_WIDTH", + [13] = "SD_STATUS", + [14] = "DPS_spec", [15] = "DPS_spec", + [16] = "DPS_spec", + [18] = "SECU_spec", + [22] = "SEND_NUM_WR_BLOCKS", [23] = "SET_WR_BLK_ERASE_COUNT", + [41] = "SD_SEND_OP_COND", + [42] = "SET_CLR_CARD_DETECT", + [51] = "SEND_SCR", + [52] = "SECU_spec", [53] = "SECU_spec", + [54] = "SECU_spec", + [56] = "SECU_spec", [57] = "SECU_spec", + [58] = "SECU_spec", [59] = "SECU_spec", + }; + + return acmd_abbrev[cmd] ? acmd_abbrev[cmd] : "UNKNOWN_ACMD"; +} diff --git a/hw/sd/sdmmc-internal.h b/hw/sd/sdmmc-internal.h index 0e96cb0081..9aa04766fc 100644 --- a/hw/sd/sdmmc-internal.h +++ b/hw/sd/sdmmc-internal.h @@ -12,4 +12,28 @@ #define SDMMC_CMD_MAX 64 +/** + * sd_cmd_name: + * @cmd: A SD "normal" command, up to SDMMC_CMD_MAX. + * + * Returns a human-readable name describing the command. + * The return value is always a static string which does not need + * to be freed after use. + * + * Returns: The command name of @cmd or "UNKNOWN_CMD". + */ +const char *sd_cmd_name(uint8_t cmd); + +/** + * sd_acmd_name: + * @cmd: A SD "Application-Specific" command, up to SDMMC_CMD_MAX. + * + * Returns a human-readable name describing the application command. + * The return value is always a static string which does not need + * to be freed after use. + * + * Returns: The application command name of @cmd or "UNKNOWN_ACMD". + */ +const char *sd_acmd_name(uint8_t cmd); + #endif diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 3040d32560..2059ace61f 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -24,8 +24,8 @@ sdhci_write_dataport(uint16_t data_count) "write buffer filled with %u bytes of sdhci_capareg(const char *desc, uint16_t val) "%s: %u" # hw/sd/sd.c -sdcard_normal_command(uint8_t cmd, uint32_t arg, const char *state) "CMD%d arg 0x%08x (state %s)" -sdcard_app_command(uint8_t acmd, uint32_t arg) "ACMD%d arg 0x%08x" +sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *state) "%s %20s/ CMD%02d arg 0x%08x (state %s)" +sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *state) "%s %23s/ACMD%02d arg 0x%08x (state %s)" sdcard_response(const char *rspdesc, int rsplen) "%s (sz:%d)" sdcard_powerup(void) "" sdcard_inquiry_cmd41(void) "" @@ -39,8 +39,8 @@ sdcard_lock(void) "" sdcard_unlock(void) "" sdcard_read_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x%x" sdcard_write_block(uint64_t addr, uint32_t len) "addr 0x%" PRIx64 " size 0x%x" -sdcard_write_data(uint8_t cmd, uint8_t value) "CMD%02d value 0x%02x" -sdcard_read_data(uint8_t cmd, int length) "CMD%02d len %d" +sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint8_t value) "%s %20s/ CMD%02d value 0x%02x" +sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, int length) "%s %20s/ CMD%02d len %d" sdcard_set_voltage(uint16_t millivolts) "%u mV" # hw/sd/milkymist-memcard.c |