diff options
Diffstat (limited to 'qemu/hw/sd')
-rw-r--r-- | qemu/hw/sd/Makefile.objs | 8 | ||||
-rw-r--r-- | qemu/hw/sd/core.c | 146 | ||||
-rw-r--r-- | qemu/hw/sd/milkymist-memcard.c | 317 | ||||
-rw-r--r-- | qemu/hw/sd/omap_mmc.c | 647 | ||||
-rw-r--r-- | qemu/hw/sd/pl181.c | 528 | ||||
-rw-r--r-- | qemu/hw/sd/pxa2xx_mmci.c | 598 | ||||
-rw-r--r-- | qemu/hw/sd/sd.c | 1979 | ||||
-rw-r--r-- | qemu/hw/sd/sdhci-internal.h | 232 | ||||
-rw-r--r-- | qemu/hw/sd/sdhci.c | 1394 | ||||
-rw-r--r-- | qemu/hw/sd/ssi-sd.c | 290 |
10 files changed, 0 insertions, 6139 deletions
diff --git a/qemu/hw/sd/Makefile.objs b/qemu/hw/sd/Makefile.objs deleted file mode 100644 index 31c83308f..000000000 --- a/qemu/hw/sd/Makefile.objs +++ /dev/null @@ -1,8 +0,0 @@ -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_SDHCI) += sdhci.o - -obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o -obj-$(CONFIG_OMAP) += omap_mmc.o -obj-$(CONFIG_PXA2XX) += pxa2xx_mmci.o diff --git a/qemu/hw/sd/core.c b/qemu/hw/sd/core.c deleted file mode 100644 index 14c2bdf27..000000000 --- a/qemu/hw/sd/core.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * SD card bus interface code. - * - * Copyright (c) 2015 Linaro Limited - * - * Author: - * Peter Maydell <peter.maydell@linaro.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/qdev-core.h" -#include "sysemu/block-backend.h" -#include "hw/sd/sd.h" - -static SDState *get_card(SDBus *sdbus) -{ - /* We only ever have one child on the bus so just return it */ - BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children); - - if (!kid) { - return NULL; - } - return SD_CARD(kid->child); -} - -int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response) -{ - SDState *card = get_card(sdbus); - - if (card) { - SDCardClass *sc = SD_CARD_GET_CLASS(card); - - return sc->do_command(card, req, response); - } - - return 0; -} - -void sdbus_write_data(SDBus *sdbus, uint8_t value) -{ - SDState *card = get_card(sdbus); - - if (card) { - SDCardClass *sc = SD_CARD_GET_CLASS(card); - - sc->write_data(card, value); - } -} - -uint8_t sdbus_read_data(SDBus *sdbus) -{ - SDState *card = get_card(sdbus); - - if (card) { - SDCardClass *sc = SD_CARD_GET_CLASS(card); - - return sc->read_data(card); - } - - return 0; -} - -bool sdbus_data_ready(SDBus *sdbus) -{ - SDState *card = get_card(sdbus); - - if (card) { - SDCardClass *sc = SD_CARD_GET_CLASS(card); - - return sc->data_ready(card); - } - - return false; -} - -bool sdbus_get_inserted(SDBus *sdbus) -{ - SDState *card = get_card(sdbus); - - if (card) { - SDCardClass *sc = SD_CARD_GET_CLASS(card); - - return sc->get_inserted(card); - } - - return false; -} - -bool sdbus_get_readonly(SDBus *sdbus) -{ - SDState *card = get_card(sdbus); - - if (card) { - SDCardClass *sc = SD_CARD_GET_CLASS(card); - - return sc->get_readonly(card); - } - - return false; -} - -void sdbus_set_inserted(SDBus *sdbus, bool inserted) -{ - SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus); - BusState *qbus = BUS(sdbus); - - if (sbc->set_inserted) { - sbc->set_inserted(qbus->parent, inserted); - } -} - -void sdbus_set_readonly(SDBus *sdbus, bool readonly) -{ - SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus); - BusState *qbus = BUS(sdbus); - - if (sbc->set_readonly) { - sbc->set_readonly(qbus->parent, readonly); - } -} - -static const TypeInfo sd_bus_info = { - .name = TYPE_SD_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(SDBus), - .class_size = sizeof(SDBusClass), -}; - -static void sd_bus_register_types(void) -{ - type_register_static(&sd_bus_info); -} - -type_init(sd_bus_register_types) diff --git a/qemu/hw/sd/milkymist-memcard.c b/qemu/hw/sd/milkymist-memcard.c deleted file mode 100644 index c04ff02fa..000000000 --- a/qemu/hw/sd/milkymist-memcard.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * QEMU model of the Milkymist SD Card Controller. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://www.milkymist.org/socdoc/memcard.pdf - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "sysemu/sysemu.h" -#include "trace.h" -#include "qemu/error-report.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "hw/sd/sd.h" - -enum { - ENABLE_CMD_TX = (1<<0), - ENABLE_CMD_RX = (1<<1), - ENABLE_DAT_TX = (1<<2), - ENABLE_DAT_RX = (1<<3), -}; - -enum { - PENDING_CMD_TX = (1<<0), - PENDING_CMD_RX = (1<<1), - PENDING_DAT_TX = (1<<2), - PENDING_DAT_RX = (1<<3), -}; - -enum { - START_CMD_TX = (1<<0), - START_DAT_RX = (1<<1), -}; - -enum { - R_CLK2XDIV = 0, - R_ENABLE, - R_PENDING, - R_START, - R_CMD, - R_DAT, - R_MAX -}; - -#define TYPE_MILKYMIST_MEMCARD "milkymist-memcard" -#define MILKYMIST_MEMCARD(obj) \ - OBJECT_CHECK(MilkymistMemcardState, (obj), TYPE_MILKYMIST_MEMCARD) - -struct MilkymistMemcardState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - SDState *card; - - int command_write_ptr; - int response_read_ptr; - int response_len; - int ignore_next_cmd; - int enabled; - uint8_t command[6]; - uint8_t response[17]; - uint32_t regs[R_MAX]; -}; -typedef struct MilkymistMemcardState MilkymistMemcardState; - -static void update_pending_bits(MilkymistMemcardState *s) -{ - /* transmits are instantaneous, thus tx pending bits are never set */ - s->regs[R_PENDING] = 0; - /* if rx is enabled the corresponding pending bits are always set */ - if (s->regs[R_ENABLE] & ENABLE_CMD_RX) { - s->regs[R_PENDING] |= PENDING_CMD_RX; - } - if (s->regs[R_ENABLE] & ENABLE_DAT_RX) { - s->regs[R_PENDING] |= PENDING_DAT_RX; - } -} - -static void memcard_sd_command(MilkymistMemcardState *s) -{ - SDRequest req; - - req.cmd = s->command[0] & 0x3f; - req.arg = (s->command[1] << 24) | (s->command[2] << 16) - | (s->command[3] << 8) | s->command[4]; - req.crc = s->command[5]; - - s->response[0] = req.cmd; - s->response_len = sd_do_command(s->card, &req, s->response+1); - s->response_read_ptr = 0; - - if (s->response_len == 16) { - /* R2 response */ - s->response[0] = 0x3f; - s->response_len += 1; - } else if (s->response_len == 4) { - /* no crc calculation, insert dummy byte */ - s->response[5] = 0; - s->response_len += 2; - } - - if (req.cmd == 0) { - /* next write is a dummy byte to clock the initialization of the sd - * card */ - s->ignore_next_cmd = 1; - } -} - -static uint64_t memcard_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistMemcardState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CMD: - if (!s->enabled) { - r = 0xff; - } else { - r = s->response[s->response_read_ptr++]; - if (s->response_read_ptr > s->response_len) { - error_report("milkymist_memcard: " - "read more cmd bytes than available. Clipping."); - s->response_read_ptr = 0; - } - } - break; - case R_DAT: - if (!s->enabled) { - r = 0xffffffff; - } else { - r = 0; - r |= sd_read_data(s->card) << 24; - r |= sd_read_data(s->card) << 16; - r |= sd_read_data(s->card) << 8; - r |= sd_read_data(s->card); - } - break; - case R_CLK2XDIV: - case R_ENABLE: - case R_PENDING: - case R_START: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_memcard: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_memcard_memory_read(addr << 2, r); - - return r; -} - -static void memcard_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistMemcardState *s = opaque; - - trace_milkymist_memcard_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_PENDING: - /* clear rx pending bits */ - s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX)); - update_pending_bits(s); - break; - case R_CMD: - if (!s->enabled) { - break; - } - if (s->ignore_next_cmd) { - s->ignore_next_cmd = 0; - break; - } - s->command[s->command_write_ptr] = value & 0xff; - s->command_write_ptr = (s->command_write_ptr + 1) % 6; - if (s->command_write_ptr == 0) { - memcard_sd_command(s); - } - break; - case R_DAT: - if (!s->enabled) { - break; - } - sd_write_data(s->card, (value >> 24) & 0xff); - sd_write_data(s->card, (value >> 16) & 0xff); - sd_write_data(s->card, (value >> 8) & 0xff); - sd_write_data(s->card, value & 0xff); - break; - case R_ENABLE: - s->regs[addr] = value; - update_pending_bits(s); - break; - case R_CLK2XDIV: - case R_START: - s->regs[addr] = value; - break; - - default: - error_report("milkymist_memcard: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps memcard_mmio_ops = { - .read = memcard_read, - .write = memcard_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_memcard_reset(DeviceState *d) -{ - MilkymistMemcardState *s = MILKYMIST_MEMCARD(d); - int i; - - s->command_write_ptr = 0; - s->response_read_ptr = 0; - s->response_len = 0; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } -} - -static int milkymist_memcard_init(SysBusDevice *dev) -{ - MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev); - DriveInfo *dinfo; - BlockBackend *blk; - - /* FIXME use a qdev drive property instead of drive_get_next() */ - dinfo = drive_get_next(IF_SD); - blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; - s->card = sd_init(blk, false); - if (s->card == NULL) { - return -1; - } - - s->enabled = blk && blk_is_inserted(blk); - - memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s, - "milkymist-memcard", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); - - return 0; -} - -static const VMStateDescription vmstate_milkymist_memcard = { - .name = "milkymist-memcard", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(command_write_ptr, MilkymistMemcardState), - VMSTATE_INT32(response_read_ptr, MilkymistMemcardState), - VMSTATE_INT32(response_len, MilkymistMemcardState), - VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState), - VMSTATE_INT32(enabled, MilkymistMemcardState), - VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6), - VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17), - VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_memcard_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = milkymist_memcard_init; - dc->reset = milkymist_memcard_reset; - dc->vmsd = &vmstate_milkymist_memcard; - /* Reason: init() method uses drive_get_next() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo milkymist_memcard_info = { - .name = TYPE_MILKYMIST_MEMCARD, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistMemcardState), - .class_init = milkymist_memcard_class_init, -}; - -static void milkymist_memcard_register_types(void) -{ - type_register_static(&milkymist_memcard_info); -} - -type_init(milkymist_memcard_register_types) diff --git a/qemu/hw/sd/omap_mmc.c b/qemu/hw/sd/omap_mmc.c deleted file mode 100644 index e934cd365..000000000 --- a/qemu/hw/sd/omap_mmc.c +++ /dev/null @@ -1,647 +0,0 @@ -/* - * OMAP on-chip MMC/SD host emulation. - * - * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/arm/omap.h" -#include "hw/sd/sd.h" - -struct omap_mmc_s { - qemu_irq irq; - qemu_irq *dma; - qemu_irq coverswitch; - MemoryRegion iomem; - omap_clk clk; - SDState *card; - uint16_t last_cmd; - uint16_t sdio; - uint16_t rsp[8]; - uint32_t arg; - int lines; - int dw; - int mode; - int enable; - int be; - int rev; - uint16_t status; - uint16_t mask; - uint8_t cto; - uint16_t dto; - int clkdiv; - uint16_t fifo[32]; - int fifo_start; - int fifo_len; - uint16_t blen; - uint16_t blen_counter; - uint16_t nblk; - uint16_t nblk_counter; - int tx_dma; - int rx_dma; - int af_level; - int ae_level; - - int ddir; - int transfer; - - int cdet_wakeup; - int cdet_enable; - int cdet_state; - qemu_irq cdet; -}; - -static void omap_mmc_interrupts_update(struct omap_mmc_s *s) -{ - qemu_set_irq(s->irq, !!(s->status & s->mask)); -} - -static void omap_mmc_fifolevel_update(struct omap_mmc_s *host) -{ - if (!host->transfer && !host->fifo_len) { - host->status &= 0xf3ff; - return; - } - - if (host->fifo_len > host->af_level && host->ddir) { - if (host->rx_dma) { - host->status &= 0xfbff; - qemu_irq_raise(host->dma[1]); - } else - host->status |= 0x0400; - } else { - host->status &= 0xfbff; - qemu_irq_lower(host->dma[1]); - } - - if (host->fifo_len < host->ae_level && !host->ddir) { - if (host->tx_dma) { - host->status &= 0xf7ff; - qemu_irq_raise(host->dma[0]); - } else - host->status |= 0x0800; - } else { - qemu_irq_lower(host->dma[0]); - host->status &= 0xf7ff; - } -} - -typedef enum { - sd_nore = 0, /* no response */ - sd_r1, /* normal response command */ - sd_r2, /* CID, CSD registers */ - sd_r3, /* OCR register */ - sd_r6 = 6, /* Published RCA response */ - sd_r1b = -1, -} sd_rsp_type_t; - -static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir, - sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init) -{ - uint32_t rspstatus, mask; - int rsplen, timeout; - SDRequest request; - uint8_t response[16]; - - if (init && cmd == 0) { - host->status |= 0x0001; - return; - } - - if (resptype == sd_r1 && busy) - resptype = sd_r1b; - - if (type == sd_adtc) { - host->fifo_start = 0; - host->fifo_len = 0; - host->transfer = 1; - host->ddir = dir; - } else - host->transfer = 0; - timeout = 0; - mask = 0; - rspstatus = 0; - - request.cmd = cmd; - request.arg = host->arg; - request.crc = 0; /* FIXME */ - - rsplen = sd_do_command(host->card, &request, response); - - /* TODO: validate CRCs */ - switch (resptype) { - case sd_nore: - rsplen = 0; - break; - - case sd_r1: - case sd_r1b: - if (rsplen < 4) { - timeout = 1; - break; - } - rsplen = 4; - - mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR | - ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION | - LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND | - CARD_ECC_FAILED | CC_ERROR | SD_ERROR | - CID_CSD_OVERWRITE; - if (host->sdio & (1 << 13)) - mask |= AKE_SEQ_ERROR; - rspstatus = (response[0] << 24) | (response[1] << 16) | - (response[2] << 8) | (response[3] << 0); - break; - - case sd_r2: - if (rsplen < 16) { - timeout = 1; - break; - } - rsplen = 16; - break; - - case sd_r3: - if (rsplen < 4) { - timeout = 1; - break; - } - rsplen = 4; - - rspstatus = (response[0] << 24) | (response[1] << 16) | - (response[2] << 8) | (response[3] << 0); - if (rspstatus & 0x80000000) - host->status &= 0xe000; - else - host->status |= 0x1000; - break; - - case sd_r6: - if (rsplen < 4) { - timeout = 1; - break; - } - rsplen = 4; - - mask = 0xe000 | AKE_SEQ_ERROR; - rspstatus = (response[2] << 8) | (response[3] << 0); - } - - if (rspstatus & mask) - host->status |= 0x4000; - else - host->status &= 0xb000; - - if (rsplen) - for (rsplen = 0; rsplen < 8; rsplen ++) - host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] | - (response[(rsplen << 1) | 0] << 8); - - if (timeout) - host->status |= 0x0080; - else if (cmd == 12) - host->status |= 0x0005; /* Makes it more real */ - else - host->status |= 0x0001; -} - -static void omap_mmc_transfer(struct omap_mmc_s *host) -{ - uint8_t value; - - if (!host->transfer) - return; - - while (1) { - if (host->ddir) { - if (host->fifo_len > host->af_level) - break; - - value = sd_read_data(host->card); - host->fifo[(host->fifo_start + host->fifo_len) & 31] = value; - if (-- host->blen_counter) { - value = sd_read_data(host->card); - host->fifo[(host->fifo_start + host->fifo_len) & 31] |= - value << 8; - host->blen_counter --; - } - - host->fifo_len ++; - } else { - if (!host->fifo_len) - break; - - value = host->fifo[host->fifo_start] & 0xff; - sd_write_data(host->card, value); - if (-- host->blen_counter) { - value = host->fifo[host->fifo_start] >> 8; - sd_write_data(host->card, value); - host->blen_counter --; - } - - host->fifo_start ++; - host->fifo_len --; - host->fifo_start &= 31; - } - - if (host->blen_counter == 0) { - host->nblk_counter --; - host->blen_counter = host->blen; - - if (host->nblk_counter == 0) { - host->nblk_counter = host->nblk; - host->transfer = 0; - host->status |= 0x0008; - break; - } - } - } -} - -static void omap_mmc_update(void *opaque) -{ - struct omap_mmc_s *s = opaque; - omap_mmc_transfer(s); - omap_mmc_fifolevel_update(s); - omap_mmc_interrupts_update(s); -} - -void omap_mmc_reset(struct omap_mmc_s *host) -{ - host->last_cmd = 0; - memset(host->rsp, 0, sizeof(host->rsp)); - host->arg = 0; - host->dw = 0; - host->mode = 0; - host->enable = 0; - host->status = 0; - host->mask = 0; - host->cto = 0; - host->dto = 0; - host->fifo_len = 0; - host->blen = 0; - host->blen_counter = 0; - host->nblk = 0; - host->nblk_counter = 0; - host->tx_dma = 0; - host->rx_dma = 0; - host->ae_level = 0x00; - host->af_level = 0x1f; - host->transfer = 0; - host->cdet_wakeup = 0; - host->cdet_enable = 0; - qemu_set_irq(host->coverswitch, host->cdet_state); - host->clkdiv = 0; -} - -static uint64_t omap_mmc_read(void *opaque, hwaddr offset, - unsigned size) -{ - uint16_t i; - struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; - - if (size != 2) { - return omap_badwidth_read16(opaque, offset); - } - - switch (offset) { - case 0x00: /* MMC_CMD */ - return s->last_cmd; - - case 0x04: /* MMC_ARGL */ - return s->arg & 0x0000ffff; - - case 0x08: /* MMC_ARGH */ - return s->arg >> 16; - - case 0x0c: /* MMC_CON */ - return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) | - (s->be << 10) | s->clkdiv; - - case 0x10: /* MMC_STAT */ - return s->status; - - case 0x14: /* MMC_IE */ - return s->mask; - - case 0x18: /* MMC_CTO */ - return s->cto; - - case 0x1c: /* MMC_DTO */ - return s->dto; - - case 0x20: /* MMC_DATA */ - /* TODO: support 8-bit access */ - i = s->fifo[s->fifo_start]; - if (s->fifo_len == 0) { - printf("MMC: FIFO underrun\n"); - return i; - } - s->fifo_start ++; - s->fifo_len --; - s->fifo_start &= 31; - omap_mmc_transfer(s); - omap_mmc_fifolevel_update(s); - omap_mmc_interrupts_update(s); - return i; - - case 0x24: /* MMC_BLEN */ - return s->blen_counter; - - case 0x28: /* MMC_NBLK */ - return s->nblk_counter; - - case 0x2c: /* MMC_BUF */ - return (s->rx_dma << 15) | (s->af_level << 8) | - (s->tx_dma << 7) | s->ae_level; - - case 0x30: /* MMC_SPI */ - return 0x0000; - case 0x34: /* MMC_SDIO */ - return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio; - case 0x38: /* MMC_SYST */ - return 0x0000; - - case 0x3c: /* MMC_REV */ - return s->rev; - - case 0x40: /* MMC_RSP0 */ - case 0x44: /* MMC_RSP1 */ - case 0x48: /* MMC_RSP2 */ - case 0x4c: /* MMC_RSP3 */ - case 0x50: /* MMC_RSP4 */ - case 0x54: /* MMC_RSP5 */ - case 0x58: /* MMC_RSP6 */ - case 0x5c: /* MMC_RSP7 */ - return s->rsp[(offset - 0x40) >> 2]; - - /* OMAP2-specific */ - case 0x60: /* MMC_IOSR */ - case 0x64: /* MMC_SYSC */ - return 0; - case 0x68: /* MMC_SYSS */ - return 1; /* RSTD */ - } - - OMAP_BAD_REG(offset); - return 0; -} - -static void omap_mmc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - int i; - struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; - - if (size != 2) { - omap_badwidth_write16(opaque, offset, value); - return; - } - - switch (offset) { - case 0x00: /* MMC_CMD */ - if (!s->enable) - break; - - s->last_cmd = value; - for (i = 0; i < 8; i ++) - s->rsp[i] = 0x0000; - omap_mmc_command(s, value & 63, (value >> 15) & 1, - (sd_cmd_type_t) ((value >> 12) & 3), - (value >> 11) & 1, - (sd_rsp_type_t) ((value >> 8) & 7), - (value >> 7) & 1); - omap_mmc_update(s); - break; - - case 0x04: /* MMC_ARGL */ - s->arg &= 0xffff0000; - s->arg |= 0x0000ffff & value; - break; - - case 0x08: /* MMC_ARGH */ - s->arg &= 0x0000ffff; - s->arg |= value << 16; - break; - - case 0x0c: /* MMC_CON */ - s->dw = (value >> 15) & 1; - s->mode = (value >> 12) & 3; - s->enable = (value >> 11) & 1; - s->be = (value >> 10) & 1; - s->clkdiv = (value >> 0) & (s->rev >= 2 ? 0x3ff : 0xff); - if (s->mode != 0) - printf("SD mode %i unimplemented!\n", s->mode); - if (s->be != 0) - printf("SD FIFO byte sex unimplemented!\n"); - if (s->dw != 0 && s->lines < 4) - printf("4-bit SD bus enabled\n"); - if (!s->enable) - omap_mmc_reset(s); - break; - - case 0x10: /* MMC_STAT */ - s->status &= ~value; - omap_mmc_interrupts_update(s); - break; - - case 0x14: /* MMC_IE */ - s->mask = value & 0x7fff; - omap_mmc_interrupts_update(s); - break; - - case 0x18: /* MMC_CTO */ - s->cto = value & 0xff; - if (s->cto > 0xfd && s->rev <= 1) - printf("MMC: CTO of 0xff and 0xfe cannot be used!\n"); - break; - - case 0x1c: /* MMC_DTO */ - s->dto = value & 0xffff; - break; - - case 0x20: /* MMC_DATA */ - /* TODO: support 8-bit access */ - if (s->fifo_len == 32) - break; - s->fifo[(s->fifo_start + s->fifo_len) & 31] = value; - s->fifo_len ++; - omap_mmc_transfer(s); - omap_mmc_fifolevel_update(s); - omap_mmc_interrupts_update(s); - break; - - case 0x24: /* MMC_BLEN */ - s->blen = (value & 0x07ff) + 1; - s->blen_counter = s->blen; - break; - - case 0x28: /* MMC_NBLK */ - s->nblk = (value & 0x07ff) + 1; - s->nblk_counter = s->nblk; - s->blen_counter = s->blen; - break; - - case 0x2c: /* MMC_BUF */ - s->rx_dma = (value >> 15) & 1; - s->af_level = (value >> 8) & 0x1f; - s->tx_dma = (value >> 7) & 1; - s->ae_level = value & 0x1f; - - if (s->rx_dma) - s->status &= 0xfbff; - if (s->tx_dma) - s->status &= 0xf7ff; - omap_mmc_fifolevel_update(s); - omap_mmc_interrupts_update(s); - break; - - /* SPI, SDIO and TEST modes unimplemented */ - case 0x30: /* MMC_SPI (OMAP1 only) */ - break; - case 0x34: /* MMC_SDIO */ - s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020); - s->cdet_wakeup = (value >> 9) & 1; - s->cdet_enable = (value >> 2) & 1; - break; - case 0x38: /* MMC_SYST */ - break; - - case 0x3c: /* MMC_REV */ - case 0x40: /* MMC_RSP0 */ - case 0x44: /* MMC_RSP1 */ - case 0x48: /* MMC_RSP2 */ - case 0x4c: /* MMC_RSP3 */ - case 0x50: /* MMC_RSP4 */ - case 0x54: /* MMC_RSP5 */ - case 0x58: /* MMC_RSP6 */ - case 0x5c: /* MMC_RSP7 */ - OMAP_RO_REG(offset); - break; - - /* OMAP2-specific */ - case 0x60: /* MMC_IOSR */ - if (value & 0xf) - printf("MMC: SDIO bits used!\n"); - break; - case 0x64: /* MMC_SYSC */ - if (value & (1 << 2)) /* SRTS */ - omap_mmc_reset(s); - break; - case 0x68: /* MMC_SYSS */ - OMAP_RO_REG(offset); - break; - - default: - OMAP_BAD_REG(offset); - } -} - -static const MemoryRegionOps omap_mmc_ops = { - .read = omap_mmc_read, - .write = omap_mmc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void omap_mmc_cover_cb(void *opaque, int line, int level) -{ - struct omap_mmc_s *host = (struct omap_mmc_s *) opaque; - - if (!host->cdet_state && level) { - host->status |= 0x0002; - omap_mmc_interrupts_update(host); - if (host->cdet_wakeup) { - /* TODO: Assert wake-up */ - } - } - - if (host->cdet_state != level) { - qemu_set_irq(host->coverswitch, level); - host->cdet_state = level; - } -} - -struct omap_mmc_s *omap_mmc_init(hwaddr base, - MemoryRegion *sysmem, - BlockBackend *blk, - qemu_irq irq, qemu_irq dma[], omap_clk clk) -{ - struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1); - - s->irq = irq; - s->dma = dma; - s->clk = clk; - s->lines = 1; /* TODO: needs to be settable per-board */ - s->rev = 1; - - omap_mmc_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", 0x800); - memory_region_add_subregion(sysmem, base, &s->iomem); - - /* Instantiate the storage */ - s->card = sd_init(blk, false); - if (s->card == NULL) { - exit(1); - } - - return s; -} - -struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, - BlockBackend *blk, qemu_irq irq, qemu_irq dma[], - omap_clk fclk, omap_clk iclk) -{ - struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1); - - s->irq = irq; - s->dma = dma; - s->clk = fclk; - s->lines = 4; - s->rev = 2; - - omap_mmc_reset(s); - - memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - /* Instantiate the storage */ - s->card = sd_init(blk, false); - if (s->card == NULL) { - exit(1); - } - - s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0); - sd_set_cb(s->card, NULL, s->cdet); - - return s; -} - -void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover) -{ - if (s->cdet) { - sd_set_cb(s->card, ro, s->cdet); - s->coverswitch = cover; - qemu_set_irq(cover, s->cdet_state); - } else - sd_set_cb(s->card, ro, cover); -} - -void omap_mmc_enable(struct omap_mmc_s *s, int enable) -{ - sd_enable(s->card, enable); -} diff --git a/qemu/hw/sd/pl181.c b/qemu/hw/sd/pl181.c deleted file mode 100644 index e87abb205..000000000 --- a/qemu/hw/sd/pl181.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Arm PrimeCell PL181 MultiMedia Card Interface - * - * Copyright (c) 2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "hw/sysbus.h" -#include "hw/sd/sd.h" - -//#define DEBUG_PL181 1 - -#ifdef DEBUG_PL181 -#define DPRINTF(fmt, ...) \ -do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#endif - -#define PL181_FIFO_LEN 16 - -#define TYPE_PL181 "pl181" -#define PL181(obj) OBJECT_CHECK(PL181State, (obj), TYPE_PL181) - -typedef struct PL181State { - SysBusDevice parent_obj; - - MemoryRegion iomem; - SDState *card; - uint32_t clock; - uint32_t power; - uint32_t cmdarg; - uint32_t cmd; - uint32_t datatimer; - uint32_t datalength; - uint32_t respcmd; - uint32_t response[4]; - uint32_t datactrl; - uint32_t datacnt; - uint32_t status; - uint32_t mask[2]; - int32_t fifo_pos; - int32_t fifo_len; - /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives - while it is reading the FIFO. We hack around this by deferring - subsequent transfers until after the driver polls the status word. - http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1 - */ - int32_t linux_hack; - uint32_t fifo[PL181_FIFO_LEN]; - qemu_irq irq[2]; - /* GPIO outputs for 'card is readonly' and 'card inserted' */ - qemu_irq cardstatus[2]; -} PL181State; - -static const VMStateDescription vmstate_pl181 = { - .name = "pl181", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(clock, PL181State), - VMSTATE_UINT32(power, PL181State), - VMSTATE_UINT32(cmdarg, PL181State), - VMSTATE_UINT32(cmd, PL181State), - VMSTATE_UINT32(datatimer, PL181State), - VMSTATE_UINT32(datalength, PL181State), - VMSTATE_UINT32(respcmd, PL181State), - VMSTATE_UINT32_ARRAY(response, PL181State, 4), - VMSTATE_UINT32(datactrl, PL181State), - VMSTATE_UINT32(datacnt, PL181State), - VMSTATE_UINT32(status, PL181State), - VMSTATE_UINT32_ARRAY(mask, PL181State, 2), - VMSTATE_INT32(fifo_pos, PL181State), - VMSTATE_INT32(fifo_len, PL181State), - VMSTATE_INT32(linux_hack, PL181State), - VMSTATE_UINT32_ARRAY(fifo, PL181State, PL181_FIFO_LEN), - VMSTATE_END_OF_LIST() - } -}; - -#define PL181_CMD_INDEX 0x3f -#define PL181_CMD_RESPONSE (1 << 6) -#define PL181_CMD_LONGRESP (1 << 7) -#define PL181_CMD_INTERRUPT (1 << 8) -#define PL181_CMD_PENDING (1 << 9) -#define PL181_CMD_ENABLE (1 << 10) - -#define PL181_DATA_ENABLE (1 << 0) -#define PL181_DATA_DIRECTION (1 << 1) -#define PL181_DATA_MODE (1 << 2) -#define PL181_DATA_DMAENABLE (1 << 3) - -#define PL181_STATUS_CMDCRCFAIL (1 << 0) -#define PL181_STATUS_DATACRCFAIL (1 << 1) -#define PL181_STATUS_CMDTIMEOUT (1 << 2) -#define PL181_STATUS_DATATIMEOUT (1 << 3) -#define PL181_STATUS_TXUNDERRUN (1 << 4) -#define PL181_STATUS_RXOVERRUN (1 << 5) -#define PL181_STATUS_CMDRESPEND (1 << 6) -#define PL181_STATUS_CMDSENT (1 << 7) -#define PL181_STATUS_DATAEND (1 << 8) -#define PL181_STATUS_DATABLOCKEND (1 << 10) -#define PL181_STATUS_CMDACTIVE (1 << 11) -#define PL181_STATUS_TXACTIVE (1 << 12) -#define PL181_STATUS_RXACTIVE (1 << 13) -#define PL181_STATUS_TXFIFOHALFEMPTY (1 << 14) -#define PL181_STATUS_RXFIFOHALFFULL (1 << 15) -#define PL181_STATUS_TXFIFOFULL (1 << 16) -#define PL181_STATUS_RXFIFOFULL (1 << 17) -#define PL181_STATUS_TXFIFOEMPTY (1 << 18) -#define PL181_STATUS_RXFIFOEMPTY (1 << 19) -#define PL181_STATUS_TXDATAAVLBL (1 << 20) -#define PL181_STATUS_RXDATAAVLBL (1 << 21) - -#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \ - |PL181_STATUS_TXFIFOHALFEMPTY \ - |PL181_STATUS_TXFIFOFULL \ - |PL181_STATUS_TXFIFOEMPTY \ - |PL181_STATUS_TXDATAAVLBL) -#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \ - |PL181_STATUS_RXFIFOHALFFULL \ - |PL181_STATUS_RXFIFOFULL \ - |PL181_STATUS_RXFIFOEMPTY \ - |PL181_STATUS_RXDATAAVLBL) - -static const unsigned char pl181_id[] = -{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; - -static void pl181_update(PL181State *s) -{ - int i; - for (i = 0; i < 2; i++) { - qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0); - } -} - -static void pl181_fifo_push(PL181State *s, uint32_t value) -{ - int n; - - if (s->fifo_len == PL181_FIFO_LEN) { - fprintf(stderr, "pl181: FIFO overflow\n"); - return; - } - n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1); - s->fifo_len++; - s->fifo[n] = value; - DPRINTF("FIFO push %08x\n", (int)value); -} - -static uint32_t pl181_fifo_pop(PL181State *s) -{ - uint32_t value; - - if (s->fifo_len == 0) { - fprintf(stderr, "pl181: FIFO underflow\n"); - return 0; - } - value = s->fifo[s->fifo_pos]; - s->fifo_len--; - s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1); - DPRINTF("FIFO pop %08x\n", (int)value); - return value; -} - -static void pl181_send_command(PL181State *s) -{ - SDRequest request; - uint8_t response[16]; - int rlen; - - request.cmd = s->cmd & PL181_CMD_INDEX; - request.arg = s->cmdarg; - DPRINTF("Command %d %08x\n", request.cmd, request.arg); - rlen = sd_do_command(s->card, &request, response); - if (rlen < 0) - goto error; - if (s->cmd & PL181_CMD_RESPONSE) { -#define RWORD(n) (((uint32_t)response[n] << 24) | (response[n + 1] << 16) \ - | (response[n + 2] << 8) | response[n + 3]) - if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP))) - goto error; - if (rlen != 4 && rlen != 16) - goto error; - s->response[0] = RWORD(0); - if (rlen == 4) { - s->response[1] = s->response[2] = s->response[3] = 0; - } else { - s->response[1] = RWORD(4); - s->response[2] = RWORD(8); - s->response[3] = RWORD(12) & ~1; - } - DPRINTF("Response received\n"); - s->status |= PL181_STATUS_CMDRESPEND; -#undef RWORD - } else { - DPRINTF("Command sent\n"); - s->status |= PL181_STATUS_CMDSENT; - } - return; - -error: - DPRINTF("Timeout\n"); - s->status |= PL181_STATUS_CMDTIMEOUT; -} - -/* Transfer data between the card and the FIFO. This is complicated by - the FIFO holding 32-bit words and the card taking data in single byte - chunks. FIFO bytes are transferred in little-endian order. */ - -static void pl181_fifo_run(PL181State *s) -{ - uint32_t bits; - uint32_t value = 0; - int n; - int is_read; - - is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0; - if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card)) - && !s->linux_hack) { - if (is_read) { - n = 0; - while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) { - value |= (uint32_t)sd_read_data(s->card) << (n * 8); - s->datacnt--; - n++; - if (n == 4) { - pl181_fifo_push(s, value); - n = 0; - value = 0; - } - } - if (n != 0) { - pl181_fifo_push(s, value); - } - } else { /* write */ - n = 0; - while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) { - if (n == 0) { - value = pl181_fifo_pop(s); - n = 4; - } - n--; - s->datacnt--; - sd_write_data(s->card, value & 0xff); - value >>= 8; - } - } - } - s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO); - if (s->datacnt == 0) { - s->status |= PL181_STATUS_DATAEND; - /* HACK: */ - s->status |= PL181_STATUS_DATABLOCKEND; - DPRINTF("Transfer Complete\n"); - } - if (s->datacnt == 0 && s->fifo_len == 0) { - s->datactrl &= ~PL181_DATA_ENABLE; - DPRINTF("Data engine idle\n"); - } else { - /* Update FIFO bits. */ - bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE; - if (s->fifo_len == 0) { - bits |= PL181_STATUS_TXFIFOEMPTY; - bits |= PL181_STATUS_RXFIFOEMPTY; - } else { - bits |= PL181_STATUS_TXDATAAVLBL; - bits |= PL181_STATUS_RXDATAAVLBL; - } - if (s->fifo_len == 16) { - bits |= PL181_STATUS_TXFIFOFULL; - bits |= PL181_STATUS_RXFIFOFULL; - } - if (s->fifo_len <= 8) { - bits |= PL181_STATUS_TXFIFOHALFEMPTY; - } - if (s->fifo_len >= 8) { - bits |= PL181_STATUS_RXFIFOHALFFULL; - } - if (s->datactrl & PL181_DATA_DIRECTION) { - bits &= PL181_STATUS_RX_FIFO; - } else { - bits &= PL181_STATUS_TX_FIFO; - } - s->status |= bits; - } -} - -static uint64_t pl181_read(void *opaque, hwaddr offset, - unsigned size) -{ - PL181State *s = (PL181State *)opaque; - uint32_t tmp; - - if (offset >= 0xfe0 && offset < 0x1000) { - return pl181_id[(offset - 0xfe0) >> 2]; - } - switch (offset) { - case 0x00: /* Power */ - return s->power; - case 0x04: /* Clock */ - return s->clock; - case 0x08: /* Argument */ - return s->cmdarg; - case 0x0c: /* Command */ - return s->cmd; - case 0x10: /* RespCmd */ - return s->respcmd; - case 0x14: /* Response0 */ - return s->response[0]; - case 0x18: /* Response1 */ - return s->response[1]; - case 0x1c: /* Response2 */ - return s->response[2]; - case 0x20: /* Response3 */ - return s->response[3]; - case 0x24: /* DataTimer */ - return s->datatimer; - case 0x28: /* DataLength */ - return s->datalength; - case 0x2c: /* DataCtrl */ - return s->datactrl; - case 0x30: /* DataCnt */ - return s->datacnt; - case 0x34: /* Status */ - tmp = s->status; - if (s->linux_hack) { - s->linux_hack = 0; - pl181_fifo_run(s); - pl181_update(s); - } - return tmp; - case 0x3c: /* Mask0 */ - return s->mask[0]; - case 0x40: /* Mask1 */ - return s->mask[1]; - case 0x48: /* FifoCnt */ - /* The documentation is somewhat vague about exactly what FifoCnt - does. On real hardware it appears to be when decrememnted - when a word is transferred between the FIFO and the serial - data engine. DataCnt is decremented after each byte is - transferred between the serial engine and the card. - We don't emulate this level of detail, so both can be the same. */ - tmp = (s->datacnt + 3) >> 2; - if (s->linux_hack) { - s->linux_hack = 0; - pl181_fifo_run(s); - pl181_update(s); - } - return tmp; - case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */ - case 0x90: case 0x94: case 0x98: case 0x9c: - case 0xa0: case 0xa4: case 0xa8: case 0xac: - case 0xb0: case 0xb4: case 0xb8: case 0xbc: - if (s->fifo_len == 0) { - qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n"); - return 0; - } else { - uint32_t value; - value = pl181_fifo_pop(s); - s->linux_hack = 1; - pl181_fifo_run(s); - pl181_update(s); - return value; - } - default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl181_read: Bad offset %x\n", (int)offset); - return 0; - } -} - -static void pl181_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PL181State *s = (PL181State *)opaque; - - switch (offset) { - case 0x00: /* Power */ - s->power = value & 0xff; - break; - case 0x04: /* Clock */ - s->clock = value & 0xff; - break; - case 0x08: /* Argument */ - s->cmdarg = value; - break; - case 0x0c: /* Command */ - s->cmd = value; - if (s->cmd & PL181_CMD_ENABLE) { - if (s->cmd & PL181_CMD_INTERRUPT) { - qemu_log_mask(LOG_UNIMP, - "pl181: Interrupt mode not implemented\n"); - } if (s->cmd & PL181_CMD_PENDING) { - qemu_log_mask(LOG_UNIMP, - "pl181: Pending commands not implemented\n"); - } else { - pl181_send_command(s); - pl181_fifo_run(s); - } - /* The command has completed one way or the other. */ - s->cmd &= ~PL181_CMD_ENABLE; - } - break; - case 0x24: /* DataTimer */ - s->datatimer = value; - break; - case 0x28: /* DataLength */ - s->datalength = value & 0xffff; - break; - case 0x2c: /* DataCtrl */ - s->datactrl = value & 0xff; - if (value & PL181_DATA_ENABLE) { - s->datacnt = s->datalength; - pl181_fifo_run(s); - } - break; - case 0x38: /* Clear */ - s->status &= ~(value & 0x7ff); - break; - case 0x3c: /* Mask0 */ - s->mask[0] = value; - break; - case 0x40: /* Mask1 */ - s->mask[1] = value; - break; - case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */ - case 0x90: case 0x94: case 0x98: case 0x9c: - case 0xa0: case 0xa4: case 0xa8: case 0xac: - case 0xb0: case 0xb4: case 0xb8: case 0xbc: - if (s->datacnt == 0) { - qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n"); - } else { - pl181_fifo_push(s, value); - pl181_fifo_run(s); - } - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl181_write: Bad offset %x\n", (int)offset); - } - pl181_update(s); -} - -static const MemoryRegionOps pl181_ops = { - .read = pl181_read, - .write = pl181_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void pl181_reset(DeviceState *d) -{ - PL181State *s = PL181(d); - - s->power = 0; - s->cmdarg = 0; - s->cmd = 0; - s->datatimer = 0; - s->datalength = 0; - s->respcmd = 0; - s->response[0] = 0; - s->response[1] = 0; - s->response[2] = 0; - s->response[3] = 0; - s->datatimer = 0; - s->datalength = 0; - s->datactrl = 0; - s->datacnt = 0; - s->status = 0; - s->linux_hack = 0; - s->mask[0] = 0; - s->mask[1] = 0; - - /* We can assume our GPIO outputs have been wired up now */ - sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]); -} - -static int pl181_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - PL181State *s = PL181(dev); - DriveInfo *dinfo; - - memory_region_init_io(&s->iomem, OBJECT(s), &pl181_ops, s, "pl181", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq[0]); - sysbus_init_irq(sbd, &s->irq[1]); - qdev_init_gpio_out(dev, s->cardstatus, 2); - /* FIXME use a qdev drive property instead of drive_get_next() */ - dinfo = drive_get_next(IF_SD); - s->card = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, false); - if (s->card == NULL) { - return -1; - } - - return 0; -} - -static void pl181_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - DeviceClass *k = DEVICE_CLASS(klass); - - sdc->init = pl181_init; - k->vmsd = &vmstate_pl181; - k->reset = pl181_reset; - /* Reason: init() method uses drive_get_next() */ - k->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo pl181_info = { - .name = TYPE_PL181, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PL181State), - .class_init = pl181_class_init, -}; - -static void pl181_register_types(void) -{ - type_register_static(&pl181_info); -} - -type_init(pl181_register_types) diff --git a/qemu/hw/sd/pxa2xx_mmci.c b/qemu/hw/sd/pxa2xx_mmci.c deleted file mode 100644 index 3deccf02c..000000000 --- a/qemu/hw/sd/pxa2xx_mmci.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski <balrog@zabor.org> - * - * This code is licensed under the GPLv2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "hw/arm/pxa.h" -#include "hw/sd/sd.h" -#include "hw/qdev.h" -#include "hw/qdev-properties.h" -#include "qemu/error-report.h" - -#define TYPE_PXA2XX_MMCI "pxa2xx-mmci" -#define PXA2XX_MMCI(obj) OBJECT_CHECK(PXA2xxMMCIState, (obj), TYPE_PXA2XX_MMCI) - -#define TYPE_PXA2XX_MMCI_BUS "pxa2xx-mmci-bus" -#define PXA2XX_MMCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_PXA2XX_MMCI_BUS) - -struct PXA2xxMMCIState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - qemu_irq rx_dma; - qemu_irq tx_dma; - qemu_irq inserted; - qemu_irq readonly; - - BlockBackend *blk; - SDBus sdbus; - - uint32_t status; - uint32_t clkrt; - uint32_t spi; - uint32_t cmdat; - uint32_t resp_tout; - uint32_t read_tout; - int32_t blklen; - int32_t numblk; - uint32_t intmask; - uint32_t intreq; - int32_t cmd; - uint32_t arg; - - int32_t active; - int32_t bytesleft; - uint8_t tx_fifo[64]; - uint32_t tx_start; - uint32_t tx_len; - uint8_t rx_fifo[32]; - uint32_t rx_start; - uint32_t rx_len; - uint16_t resp_fifo[9]; - uint32_t resp_len; - - int32_t cmdreq; -}; - -static bool pxa2xx_mmci_vmstate_validate(void *opaque, int version_id) -{ - PXA2xxMMCIState *s = opaque; - - return s->tx_start < ARRAY_SIZE(s->tx_fifo) - && s->rx_start < ARRAY_SIZE(s->rx_fifo) - && s->tx_len <= ARRAY_SIZE(s->tx_fifo) - && s->rx_len <= ARRAY_SIZE(s->rx_fifo) - && s->resp_len <= ARRAY_SIZE(s->resp_fifo); -} - - -static const VMStateDescription vmstate_pxa2xx_mmci = { - .name = "pxa2xx-mmci", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32(status, PXA2xxMMCIState), - VMSTATE_UINT32(clkrt, PXA2xxMMCIState), - VMSTATE_UINT32(spi, PXA2xxMMCIState), - VMSTATE_UINT32(cmdat, PXA2xxMMCIState), - VMSTATE_UINT32(resp_tout, PXA2xxMMCIState), - VMSTATE_UINT32(read_tout, PXA2xxMMCIState), - VMSTATE_INT32(blklen, PXA2xxMMCIState), - VMSTATE_INT32(numblk, PXA2xxMMCIState), - VMSTATE_UINT32(intmask, PXA2xxMMCIState), - VMSTATE_UINT32(intreq, PXA2xxMMCIState), - VMSTATE_INT32(cmd, PXA2xxMMCIState), - VMSTATE_UINT32(arg, PXA2xxMMCIState), - VMSTATE_INT32(cmdreq, PXA2xxMMCIState), - VMSTATE_INT32(active, PXA2xxMMCIState), - VMSTATE_INT32(bytesleft, PXA2xxMMCIState), - VMSTATE_UINT32(tx_start, PXA2xxMMCIState), - VMSTATE_UINT32(tx_len, PXA2xxMMCIState), - VMSTATE_UINT32(rx_start, PXA2xxMMCIState), - VMSTATE_UINT32(rx_len, PXA2xxMMCIState), - VMSTATE_UINT32(resp_len, PXA2xxMMCIState), - VMSTATE_VALIDATE("fifo size incorrect", pxa2xx_mmci_vmstate_validate), - VMSTATE_UINT8_ARRAY(tx_fifo, PXA2xxMMCIState, 64), - VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxMMCIState, 32), - VMSTATE_UINT16_ARRAY(resp_fifo, PXA2xxMMCIState, 9), - VMSTATE_END_OF_LIST() - } -}; - -#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */ -#define MMC_STAT 0x04 /* MMC Status register */ -#define MMC_CLKRT 0x08 /* MMC Clock Rate register */ -#define MMC_SPI 0x0c /* MMC SPI Mode register */ -#define MMC_CMDAT 0x10 /* MMC Command/Data register */ -#define MMC_RESTO 0x14 /* MMC Response Time-Out register */ -#define MMC_RDTO 0x18 /* MMC Read Time-Out register */ -#define MMC_BLKLEN 0x1c /* MMC Block Length register */ -#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */ -#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */ -#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */ -#define MMC_I_REG 0x2c /* MMC Interrupt Request register */ -#define MMC_CMD 0x30 /* MMC Command register */ -#define MMC_ARGH 0x34 /* MMC Argument High register */ -#define MMC_ARGL 0x38 /* MMC Argument Low register */ -#define MMC_RES 0x3c /* MMC Response FIFO */ -#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */ -#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */ -#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */ -#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */ - -/* Bitfield masks */ -#define STRPCL_STOP_CLK (1 << 0) -#define STRPCL_STRT_CLK (1 << 1) -#define STAT_TOUT_RES (1 << 1) -#define STAT_CLK_EN (1 << 8) -#define STAT_DATA_DONE (1 << 11) -#define STAT_PRG_DONE (1 << 12) -#define STAT_END_CMDRES (1 << 13) -#define SPI_SPI_MODE (1 << 0) -#define CMDAT_RES_TYPE (3 << 0) -#define CMDAT_DATA_EN (1 << 2) -#define CMDAT_WR_RD (1 << 3) -#define CMDAT_DMA_EN (1 << 7) -#define CMDAT_STOP_TRAN (1 << 10) -#define INT_DATA_DONE (1 << 0) -#define INT_PRG_DONE (1 << 1) -#define INT_END_CMD (1 << 2) -#define INT_STOP_CMD (1 << 3) -#define INT_CLK_OFF (1 << 4) -#define INT_RXFIFO_REQ (1 << 5) -#define INT_TXFIFO_REQ (1 << 6) -#define INT_TINT (1 << 7) -#define INT_DAT_ERR (1 << 8) -#define INT_RES_ERR (1 << 9) -#define INT_RD_STALLED (1 << 10) -#define INT_SDIO_INT (1 << 11) -#define INT_SDIO_SACK (1 << 12) -#define PRTBUF_PRT_BUF (1 << 0) - -/* Route internal interrupt lines to the global IC and DMA */ -static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s) -{ - uint32_t mask = s->intmask; - if (s->cmdat & CMDAT_DMA_EN) { - mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ; - - qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ)); - qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ)); - } - - qemu_set_irq(s->irq, !!(s->intreq & ~mask)); -} - -static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s) -{ - if (!s->active) - return; - - if (s->cmdat & CMDAT_WR_RD) { - while (s->bytesleft && s->tx_len) { - sdbus_write_data(&s->sdbus, s->tx_fifo[s->tx_start++]); - s->tx_start &= 0x1f; - s->tx_len --; - s->bytesleft --; - } - if (s->bytesleft) - s->intreq |= INT_TXFIFO_REQ; - } else - while (s->bytesleft && s->rx_len < 32) { - s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] = - sdbus_read_data(&s->sdbus); - s->bytesleft --; - s->intreq |= INT_RXFIFO_REQ; - } - - if (!s->bytesleft) { - s->active = 0; - s->intreq |= INT_DATA_DONE; - s->status |= STAT_DATA_DONE; - - if (s->cmdat & CMDAT_WR_RD) { - s->intreq |= INT_PRG_DONE; - s->status |= STAT_PRG_DONE; - } - } - - pxa2xx_mmci_int_update(s); -} - -static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s) -{ - int rsplen, i; - SDRequest request; - uint8_t response[16]; - - s->active = 1; - s->rx_len = 0; - s->tx_len = 0; - s->cmdreq = 0; - - request.cmd = s->cmd; - request.arg = s->arg; - request.crc = 0; /* FIXME */ - - rsplen = sdbus_do_command(&s->sdbus, &request, response); - s->intreq |= INT_END_CMD; - - memset(s->resp_fifo, 0, sizeof(s->resp_fifo)); - switch (s->cmdat & CMDAT_RES_TYPE) { -#define PXAMMCI_RESP(wd, value0, value1) \ - s->resp_fifo[(wd) + 0] |= (value0); \ - s->resp_fifo[(wd) + 1] |= (value1) << 8; - case 0: /* No response */ - goto complete; - - case 1: /* R1, R4, R5 or R6 */ - if (rsplen < 4) - goto timeout; - goto complete; - - case 2: /* R2 */ - if (rsplen < 16) - goto timeout; - goto complete; - - case 3: /* R3 */ - if (rsplen < 4) - goto timeout; - goto complete; - - complete: - for (i = 0; rsplen > 0; i ++, rsplen -= 2) { - PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]); - } - s->status |= STAT_END_CMDRES; - - if (!(s->cmdat & CMDAT_DATA_EN)) - s->active = 0; - else - s->bytesleft = s->numblk * s->blklen; - - s->resp_len = 0; - break; - - timeout: - s->active = 0; - s->status |= STAT_TOUT_RES; - break; - } - - pxa2xx_mmci_fifo_update(s); -} - -static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - uint32_t ret; - - switch (offset) { - case MMC_STRPCL: - return 0; - case MMC_STAT: - return s->status; - case MMC_CLKRT: - return s->clkrt; - case MMC_SPI: - return s->spi; - case MMC_CMDAT: - return s->cmdat; - case MMC_RESTO: - return s->resp_tout; - case MMC_RDTO: - return s->read_tout; - case MMC_BLKLEN: - return s->blklen; - case MMC_NUMBLK: - return s->numblk; - case MMC_PRTBUF: - return 0; - case MMC_I_MASK: - return s->intmask; - case MMC_I_REG: - return s->intreq; - case MMC_CMD: - return s->cmd | 0x40; - case MMC_ARGH: - return s->arg >> 16; - case MMC_ARGL: - return s->arg & 0xffff; - case MMC_RES: - if (s->resp_len < 9) - return s->resp_fifo[s->resp_len ++]; - return 0; - case MMC_RXFIFO: - ret = 0; - while (size-- && s->rx_len) { - ret |= s->rx_fifo[s->rx_start++] << (size << 3); - s->rx_start &= 0x1f; - s->rx_len --; - } - s->intreq &= ~INT_RXFIFO_REQ; - pxa2xx_mmci_fifo_update(s); - return ret; - case MMC_RDWAIT: - return 0; - case MMC_BLKS_REM: - return s->numblk; - default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); - } - - return 0; -} - -static void pxa2xx_mmci_write(void *opaque, - hwaddr offset, uint64_t value, unsigned size) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - - switch (offset) { - case MMC_STRPCL: - if (value & STRPCL_STRT_CLK) { - s->status |= STAT_CLK_EN; - s->intreq &= ~INT_CLK_OFF; - - if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) { - s->status &= STAT_CLK_EN; - pxa2xx_mmci_wakequeues(s); - } - } - - if (value & STRPCL_STOP_CLK) { - s->status &= ~STAT_CLK_EN; - s->intreq |= INT_CLK_OFF; - s->active = 0; - } - - pxa2xx_mmci_int_update(s); - break; - - case MMC_CLKRT: - s->clkrt = value & 7; - break; - - case MMC_SPI: - s->spi = value & 0xf; - if (value & SPI_SPI_MODE) - printf("%s: attempted to use card in SPI mode\n", __FUNCTION__); - break; - - case MMC_CMDAT: - s->cmdat = value & 0x3dff; - s->active = 0; - s->cmdreq = 1; - if (!(value & CMDAT_STOP_TRAN)) { - s->status &= STAT_CLK_EN; - - if (s->status & STAT_CLK_EN) - pxa2xx_mmci_wakequeues(s); - } - - pxa2xx_mmci_int_update(s); - break; - - case MMC_RESTO: - s->resp_tout = value & 0x7f; - break; - - case MMC_RDTO: - s->read_tout = value & 0xffff; - break; - - case MMC_BLKLEN: - s->blklen = value & 0xfff; - break; - - case MMC_NUMBLK: - s->numblk = value & 0xffff; - break; - - case MMC_PRTBUF: - if (value & PRTBUF_PRT_BUF) { - s->tx_start ^= 32; - s->tx_len = 0; - } - pxa2xx_mmci_fifo_update(s); - break; - - case MMC_I_MASK: - s->intmask = value & 0x1fff; - pxa2xx_mmci_int_update(s); - break; - - case MMC_CMD: - s->cmd = value & 0x3f; - break; - - case MMC_ARGH: - s->arg &= 0x0000ffff; - s->arg |= value << 16; - break; - - case MMC_ARGL: - s->arg &= 0xffff0000; - s->arg |= value & 0x0000ffff; - break; - - case MMC_TXFIFO: - while (size-- && s->tx_len < 0x20) - s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] = - (value >> (size << 3)) & 0xff; - s->intreq &= ~INT_TXFIFO_REQ; - pxa2xx_mmci_fifo_update(s); - break; - - case MMC_RDWAIT: - case MMC_BLKS_REM: - break; - - default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); - } -} - -static const MemoryRegionOps pxa2xx_mmci_ops = { - .read = pxa2xx_mmci_read, - .write = pxa2xx_mmci_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, - hwaddr base, - BlockBackend *blk, qemu_irq irq, - qemu_irq rx_dma, qemu_irq tx_dma) -{ - DeviceState *dev, *carddev; - SysBusDevice *sbd; - PXA2xxMMCIState *s; - Error *err = NULL; - - dev = qdev_create(NULL, TYPE_PXA2XX_MMCI); - s = PXA2XX_MMCI(dev); - sbd = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(sbd, 0, base); - sysbus_connect_irq(sbd, 0, irq); - qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma); - qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma); - - /* Create and plug in the sd card */ - carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); - qdev_prop_set_drive(carddev, "drive", blk, &err); - if (err) { - error_report("failed to init SD card: %s", error_get_pretty(err)); - return NULL; - } - object_property_set_bool(OBJECT(carddev), true, "realized", &err); - if (err) { - error_report("failed to init SD card: %s", error_get_pretty(err)); - return NULL; - } - - return s; -} - -static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted) -{ - PXA2xxMMCIState *s = PXA2XX_MMCI(dev); - - qemu_set_irq(s->inserted, inserted); -} - -static void pxa2xx_mmci_set_readonly(DeviceState *dev, bool readonly) -{ - PXA2xxMMCIState *s = PXA2XX_MMCI(dev); - - qemu_set_irq(s->readonly, readonly); -} - -void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly, - qemu_irq coverswitch) -{ - DeviceState *dev = DEVICE(s); - - s->readonly = readonly; - s->inserted = coverswitch; - - pxa2xx_mmci_set_inserted(dev, sdbus_get_inserted(&s->sdbus)); - pxa2xx_mmci_set_readonly(dev, sdbus_get_readonly(&s->sdbus)); -} - -static void pxa2xx_mmci_reset(DeviceState *d) -{ - PXA2xxMMCIState *s = PXA2XX_MMCI(d); - - s->status = 0; - s->clkrt = 0; - s->spi = 0; - s->cmdat = 0; - s->resp_tout = 0; - s->read_tout = 0; - s->blklen = 0; - s->numblk = 0; - s->intmask = 0; - s->intreq = 0; - s->cmd = 0; - s->arg = 0; - s->active = 0; - s->bytesleft = 0; - s->tx_start = 0; - s->tx_len = 0; - s->rx_start = 0; - s->rx_len = 0; - s->resp_len = 0; - s->cmdreq = 0; - memset(s->tx_fifo, 0, sizeof(s->tx_fifo)); - memset(s->rx_fifo, 0, sizeof(s->rx_fifo)); - memset(s->resp_fifo, 0, sizeof(s->resp_fifo)); -} - -static void pxa2xx_mmci_instance_init(Object *obj) -{ - PXA2xxMMCIState *s = PXA2XX_MMCI(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - DeviceState *dev = DEVICE(obj); - - memory_region_init_io(&s->iomem, obj, &pxa2xx_mmci_ops, s, - "pxa2xx-mmci", 0x00100000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - qdev_init_gpio_out_named(dev, &s->rx_dma, "rx-dma", 1); - qdev_init_gpio_out_named(dev, &s->tx_dma, "tx-dma", 1); - - qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), - TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus"); -} - -static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &vmstate_pxa2xx_mmci; - dc->reset = pxa2xx_mmci_reset; -} - -static void pxa2xx_mmci_bus_class_init(ObjectClass *klass, void *data) -{ - SDBusClass *sbc = SD_BUS_CLASS(klass); - - sbc->set_inserted = pxa2xx_mmci_set_inserted; - sbc->set_readonly = pxa2xx_mmci_set_readonly; -} - -static const TypeInfo pxa2xx_mmci_info = { - .name = TYPE_PXA2XX_MMCI, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxMMCIState), - .instance_init = pxa2xx_mmci_instance_init, - .class_init = pxa2xx_mmci_class_init, -}; - -static const TypeInfo pxa2xx_mmci_bus_info = { - .name = TYPE_PXA2XX_MMCI_BUS, - .parent = TYPE_SD_BUS, - .instance_size = sizeof(SDBus), - .class_init = pxa2xx_mmci_bus_class_init, -}; - -static void pxa2xx_mmci_register_types(void) -{ - type_register_static(&pxa2xx_mmci_info); - type_register_static(&pxa2xx_mmci_bus_info); -} - -type_init(pxa2xx_mmci_register_types) diff --git a/qemu/hw/sd/sd.c b/qemu/hw/sd/sd.c deleted file mode 100644 index b66e5d2db..000000000 --- a/qemu/hw/sd/sd.c +++ /dev/null @@ -1,1979 +0,0 @@ -/* - * SD Memory Card emulation as defined in the "SD Memory Card Physical - * layer specification, Version 1.10." - * - * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> - * Copyright (c) 2007 CodeSourcery - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "qemu/osdep.h" -#include "hw/qdev.h" -#include "hw/hw.h" -#include "sysemu/block-backend.h" -#include "hw/sd/sd.h" -#include "qapi/error.h" -#include "qemu/bitmap.h" -#include "hw/qdev-properties.h" -#include "qemu/error-report.h" -#include "qemu/timer.h" - -//#define DEBUG_SD 1 - -#ifdef DEBUG_SD -#define DPRINTF(fmt, ...) \ -do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#endif - -#define ACMD41_ENQUIRY_MASK 0x00ffffff -#define OCR_POWER_UP 0x80000000 -#define OCR_POWER_DELAY_NS 500000 /* 0.5ms */ - -typedef enum { - sd_r0 = 0, /* no response */ - sd_r1, /* normal response command */ - sd_r2_i, /* CID register */ - sd_r2_s, /* CSD register */ - sd_r3, /* OCR register */ - sd_r6 = 6, /* Published RCA response */ - sd_r7, /* Operating voltage */ - sd_r1b = -1, - sd_illegal = -2, -} sd_rsp_type_t; - -enum SDCardModes { - sd_inactive, - sd_card_identification_mode, - sd_data_transfer_mode, -}; - -enum SDCardStates { - sd_inactive_state = -1, - sd_idle_state = 0, - sd_ready_state, - sd_identification_state, - sd_standby_state, - sd_transfer_state, - sd_sendingdata_state, - sd_receivingdata_state, - sd_programming_state, - sd_disconnect_state, -}; - -struct SDState { - DeviceState parent_obj; - - uint32_t mode; /* current card mode, one of SDCardModes */ - int32_t state; /* current card state, one of SDCardStates */ - uint32_t ocr; - QEMUTimer *ocr_power_timer; - uint8_t scr[8]; - uint8_t cid[16]; - uint8_t csd[16]; - uint16_t rca; - uint32_t card_status; - uint8_t sd_status[64]; - uint32_t vhs; - bool wp_switch; - unsigned long *wp_groups; - int32_t wpgrps_size; - uint64_t size; - uint32_t blk_len; - uint32_t multi_blk_cnt; - uint32_t erase_start; - uint32_t erase_end; - uint8_t pwd[16]; - uint32_t pwd_len; - uint8_t function_group[6]; - - bool spi; - uint8_t current_cmd; - /* True if we will handle the next command as an ACMD. Note that this does - * *not* track the APP_CMD status bit! - */ - bool expecting_acmd; - uint32_t blk_written; - uint64_t data_start; - uint32_t data_offset; - uint8_t data[512]; - qemu_irq readonly_cb; - qemu_irq inserted_cb; - BlockBackend *blk; - uint8_t *buf; - - bool enable; -}; - -static void sd_set_mode(SDState *sd) -{ - switch (sd->state) { - case sd_inactive_state: - sd->mode = sd_inactive; - break; - - case sd_idle_state: - case sd_ready_state: - case sd_identification_state: - sd->mode = sd_card_identification_mode; - break; - - case sd_standby_state: - case sd_transfer_state: - case sd_sendingdata_state: - case sd_receivingdata_state: - case sd_programming_state: - case sd_disconnect_state: - sd->mode = sd_data_transfer_mode; - break; - } -} - -static const sd_cmd_type_t sd_cmd_type[64] = { - sd_bc, sd_none, sd_bcr, sd_bcr, sd_none, sd_none, sd_none, sd_ac, - sd_bcr, sd_ac, sd_ac, sd_adtc, sd_ac, sd_ac, sd_none, sd_ac, - sd_ac, sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, - sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac, sd_ac, sd_adtc, sd_none, - sd_ac, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none, - sd_none, sd_none, sd_bc, sd_none, sd_none, sd_none, sd_none, sd_none, - sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac, - sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, -}; - -static const int sd_cmd_class[64] = { - 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, - 5, 5, 10, 10, 10, 10, 5, 9, 9, 9, 7, 7, 7, 7, 7, 7, - 7, 7, 10, 7, 9, 9, 9, 8, 8, 10, 8, 8, 8, 8, 8, 8, -}; - -static uint8_t sd_crc7(void *message, size_t width) -{ - int i, bit; - uint8_t shift_reg = 0x00; - uint8_t *msg = (uint8_t *) message; - - for (i = 0; i < width; i ++, msg ++) - for (bit = 7; bit >= 0; bit --) { - shift_reg <<= 1; - if ((shift_reg >> 7) ^ ((*msg >> bit) & 1)) - shift_reg ^= 0x89; - } - - return shift_reg; -} - -static uint16_t sd_crc16(void *message, size_t width) -{ - int i, bit; - uint16_t shift_reg = 0x0000; - uint16_t *msg = (uint16_t *) message; - width <<= 1; - - for (i = 0; i < width; i ++, msg ++) - for (bit = 15; bit >= 0; bit --) { - shift_reg <<= 1; - if ((shift_reg >> 15) ^ ((*msg >> bit) & 1)) - shift_reg ^= 0x1011; - } - - return shift_reg; -} - -static void sd_set_ocr(SDState *sd) -{ - /* All voltages OK, Standard Capacity SD Memory Card, not yet powered up */ - sd->ocr = 0x00ffff00; -} - -static void sd_ocr_powerup(void *opaque) -{ - SDState *sd = opaque; - - /* Set powered up bit in OCR */ - assert(!(sd->ocr & OCR_POWER_UP)); - sd->ocr |= OCR_POWER_UP; -} - -static void sd_set_scr(SDState *sd) -{ - sd->scr[0] = 0x00; /* SCR Structure */ - sd->scr[1] = 0x2f; /* SD Security Support */ - sd->scr[2] = 0x00; - sd->scr[3] = 0x00; - sd->scr[4] = 0x00; - sd->scr[5] = 0x00; - sd->scr[6] = 0x00; - sd->scr[7] = 0x00; -} - -#define MID 0xaa -#define OID "XY" -#define PNM "QEMU!" -#define PRV 0x01 -#define MDT_YR 2006 -#define MDT_MON 2 - -static void sd_set_cid(SDState *sd) -{ - sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ - sd->cid[1] = OID[0]; /* OEM/Application ID (OID) */ - sd->cid[2] = OID[1]; - sd->cid[3] = PNM[0]; /* Fake product name (PNM) */ - sd->cid[4] = PNM[1]; - sd->cid[5] = PNM[2]; - sd->cid[6] = PNM[3]; - sd->cid[7] = PNM[4]; - sd->cid[8] = PRV; /* Fake product revision (PRV) */ - sd->cid[9] = 0xde; /* Fake serial number (PSN) */ - sd->cid[10] = 0xad; - sd->cid[11] = 0xbe; - sd->cid[12] = 0xef; - sd->cid[13] = 0x00 | /* Manufacture date (MDT) */ - ((MDT_YR - 2000) / 10); - sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; - sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; -} - -#define HWBLOCK_SHIFT 9 /* 512 bytes */ -#define SECTOR_SHIFT 5 /* 16 kilobytes */ -#define WPGROUP_SHIFT 7 /* 2 megs */ -#define CMULT_SHIFT 9 /* 512 times HWBLOCK_SIZE */ -#define WPGROUP_SIZE (1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) - -static const uint8_t sd_csd_rw_mask[16] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, -}; - -static void sd_set_csd(SDState *sd, uint64_t size) -{ - uint32_t csize = (size >> (CMULT_SHIFT + HWBLOCK_SHIFT)) - 1; - uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1; - uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1; - - if (size <= 0x40000000) { /* Standard Capacity SD */ - sd->csd[0] = 0x00; /* CSD structure */ - sd->csd[1] = 0x26; /* Data read access-time-1 */ - sd->csd[2] = 0x00; /* Data read access-time-2 */ - sd->csd[3] = 0x5a; /* Max. data transfer rate */ - sd->csd[4] = 0x5f; /* Card Command Classes */ - sd->csd[5] = 0x50 | /* Max. read data block length */ - HWBLOCK_SHIFT; - sd->csd[6] = 0xe0 | /* Partial block for read allowed */ - ((csize >> 10) & 0x03); - sd->csd[7] = 0x00 | /* Device size */ - ((csize >> 2) & 0xff); - sd->csd[8] = 0x3f | /* Max. read current */ - ((csize << 6) & 0xc0); - sd->csd[9] = 0xfc | /* Max. write current */ - ((CMULT_SHIFT - 2) >> 1); - sd->csd[10] = 0x40 | /* Erase sector size */ - (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1); - sd->csd[11] = 0x00 | /* Write protect group size */ - ((sectsize << 7) & 0x80) | wpsize; - sd->csd[12] = 0x90 | /* Write speed factor */ - (HWBLOCK_SHIFT >> 2); - sd->csd[13] = 0x20 | /* Max. write data block length */ - ((HWBLOCK_SHIFT << 6) & 0xc0); - sd->csd[14] = 0x00; /* File format group */ - sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1; - } else { /* SDHC */ - size /= 512 * 1024; - size -= 1; - sd->csd[0] = 0x40; - sd->csd[1] = 0x0e; - sd->csd[2] = 0x00; - sd->csd[3] = 0x32; - sd->csd[4] = 0x5b; - sd->csd[5] = 0x59; - sd->csd[6] = 0x00; - sd->csd[7] = (size >> 16) & 0xff; - sd->csd[8] = (size >> 8) & 0xff; - sd->csd[9] = (size & 0xff); - sd->csd[10] = 0x7f; - sd->csd[11] = 0x80; - sd->csd[12] = 0x0a; - sd->csd[13] = 0x40; - sd->csd[14] = 0x00; - sd->csd[15] = 0x00; - sd->ocr |= 1 << 30; /* High Capacity SD Memory Card */ - } -} - -static void sd_set_rca(SDState *sd) -{ - sd->rca += 0x4567; -} - -/* Card status bits, split by clear condition: - * A : According to the card current state - * B : Always related to the previous command - * C : Cleared by read - */ -#define CARD_STATUS_A 0x02004100 -#define CARD_STATUS_B 0x00c01e00 -#define CARD_STATUS_C 0xfd39a028 - -static void sd_set_cardstatus(SDState *sd) -{ - sd->card_status = 0x00000100; -} - -static void sd_set_sdstatus(SDState *sd) -{ - memset(sd->sd_status, 0, 64); -} - -static int sd_req_crc_validate(SDRequest *req) -{ - uint8_t buffer[5]; - buffer[0] = 0x40 | req->cmd; - buffer[1] = (req->arg >> 24) & 0xff; - buffer[2] = (req->arg >> 16) & 0xff; - buffer[3] = (req->arg >> 8) & 0xff; - buffer[4] = (req->arg >> 0) & 0xff; - return 0; - return sd_crc7(buffer, 5) != req->crc; /* TODO */ -} - -static void sd_response_r1_make(SDState *sd, uint8_t *response) -{ - uint32_t status = sd->card_status; - /* Clear the "clear on read" status bits */ - sd->card_status &= ~CARD_STATUS_C; - - response[0] = (status >> 24) & 0xff; - response[1] = (status >> 16) & 0xff; - response[2] = (status >> 8) & 0xff; - response[3] = (status >> 0) & 0xff; -} - -static void sd_response_r3_make(SDState *sd, uint8_t *response) -{ - response[0] = (sd->ocr >> 24) & 0xff; - response[1] = (sd->ocr >> 16) & 0xff; - response[2] = (sd->ocr >> 8) & 0xff; - response[3] = (sd->ocr >> 0) & 0xff; -} - -static void sd_response_r6_make(SDState *sd, uint8_t *response) -{ - uint16_t arg; - uint16_t status; - - arg = sd->rca; - status = ((sd->card_status >> 8) & 0xc000) | - ((sd->card_status >> 6) & 0x2000) | - (sd->card_status & 0x1fff); - sd->card_status &= ~(CARD_STATUS_C & 0xc81fff); - - response[0] = (arg >> 8) & 0xff; - response[1] = arg & 0xff; - response[2] = (status >> 8) & 0xff; - response[3] = status & 0xff; -} - -static void sd_response_r7_make(SDState *sd, uint8_t *response) -{ - response[0] = (sd->vhs >> 24) & 0xff; - response[1] = (sd->vhs >> 16) & 0xff; - response[2] = (sd->vhs >> 8) & 0xff; - response[3] = (sd->vhs >> 0) & 0xff; -} - -static inline uint64_t sd_addr_to_wpnum(uint64_t addr) -{ - return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT); -} - -static void sd_reset(DeviceState *dev) -{ - SDState *sd = SD_CARD(dev); - uint64_t size; - uint64_t sect; - - if (sd->blk) { - blk_get_geometry(sd->blk, §); - } else { - sect = 0; - } - size = sect << 9; - - sect = sd_addr_to_wpnum(size) + 1; - - sd->state = sd_idle_state; - sd->rca = 0x0000; - sd_set_ocr(sd); - sd_set_scr(sd); - sd_set_cid(sd); - sd_set_csd(sd, size); - sd_set_cardstatus(sd); - sd_set_sdstatus(sd); - - g_free(sd->wp_groups); - sd->wp_switch = sd->blk ? blk_is_read_only(sd->blk) : false; - sd->wpgrps_size = sect; - sd->wp_groups = bitmap_new(sd->wpgrps_size); - memset(sd->function_group, 0, sizeof(sd->function_group)); - sd->erase_start = 0; - sd->erase_end = 0; - sd->size = size; - sd->blk_len = 0x200; - sd->pwd_len = 0; - sd->expecting_acmd = false; - sd->multi_blk_cnt = 0; -} - -static bool sd_get_inserted(SDState *sd) -{ - return sd->blk && blk_is_inserted(sd->blk); -} - -static bool sd_get_readonly(SDState *sd) -{ - return sd->wp_switch; -} - -static void sd_cardchange(void *opaque, bool load) -{ - SDState *sd = opaque; - DeviceState *dev = DEVICE(sd); - SDBus *sdbus = SD_BUS(qdev_get_parent_bus(dev)); - bool inserted = sd_get_inserted(sd); - bool readonly = sd_get_readonly(sd); - - if (inserted) { - sd_reset(dev); - } - - /* The IRQ notification is for legacy non-QOM SD controller devices; - * QOMified controllers use the SDBus APIs. - */ - if (sdbus) { - sdbus_set_inserted(sdbus, inserted); - if (inserted) { - sdbus_set_readonly(sdbus, readonly); - } - } else { - qemu_set_irq(sd->inserted_cb, inserted); - if (inserted) { - qemu_set_irq(sd->readonly_cb, readonly); - } - } -} - -static const BlockDevOps sd_block_ops = { - .change_media_cb = sd_cardchange, -}; - -static bool sd_ocr_vmstate_needed(void *opaque) -{ - SDState *sd = opaque; - - /* Include the OCR state (and timer) if it is not yet powered up */ - return !(sd->ocr & OCR_POWER_UP); -} - -static const VMStateDescription sd_ocr_vmstate = { - .name = "sd-card/ocr-state", - .version_id = 1, - .minimum_version_id = 1, - .needed = sd_ocr_vmstate_needed, - .fields = (VMStateField[]) { - VMSTATE_UINT32(ocr, SDState), - VMSTATE_TIMER_PTR(ocr_power_timer, SDState), - VMSTATE_END_OF_LIST() - }, -}; - -static int sd_vmstate_pre_load(void *opaque) -{ - SDState *sd = opaque; - - /* If the OCR state is not included (prior versions, or not - * needed), then the OCR must be set as powered up. If the OCR state - * is included, this will be replaced by the state restore. - */ - sd_ocr_powerup(sd); - - return 0; -} - -static const VMStateDescription sd_vmstate = { - .name = "sd-card", - .version_id = 1, - .minimum_version_id = 1, - .pre_load = sd_vmstate_pre_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(mode, SDState), - VMSTATE_INT32(state, SDState), - VMSTATE_UINT8_ARRAY(cid, SDState, 16), - VMSTATE_UINT8_ARRAY(csd, SDState, 16), - VMSTATE_UINT16(rca, SDState), - VMSTATE_UINT32(card_status, SDState), - VMSTATE_PARTIAL_BUFFER(sd_status, SDState, 1), - VMSTATE_UINT32(vhs, SDState), - VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size), - VMSTATE_UINT32(blk_len, SDState), - VMSTATE_UINT32(multi_blk_cnt, SDState), - VMSTATE_UINT32(erase_start, SDState), - VMSTATE_UINT32(erase_end, SDState), - VMSTATE_UINT8_ARRAY(pwd, SDState, 16), - VMSTATE_UINT32(pwd_len, SDState), - VMSTATE_UINT8_ARRAY(function_group, SDState, 6), - VMSTATE_UINT8(current_cmd, SDState), - VMSTATE_BOOL(expecting_acmd, SDState), - VMSTATE_UINT32(blk_written, SDState), - VMSTATE_UINT64(data_start, SDState), - VMSTATE_UINT32(data_offset, SDState), - VMSTATE_UINT8_ARRAY(data, SDState, 512), - VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512), - VMSTATE_BOOL(enable, SDState), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &sd_ocr_vmstate, - NULL - }, -}; - -/* Legacy initialization function for use by non-qdevified callers */ -SDState *sd_init(BlockBackend *blk, bool is_spi) -{ - Object *obj; - DeviceState *dev; - Error *err = NULL; - - obj = object_new(TYPE_SD_CARD); - dev = DEVICE(obj); - qdev_prop_set_drive(dev, "drive", blk, &err); - if (err) { - error_report("sd_init failed: %s", error_get_pretty(err)); - return NULL; - } - qdev_prop_set_bit(dev, "spi", is_spi); - object_property_set_bool(obj, true, "realized", &err); - if (err) { - error_report("sd_init failed: %s", error_get_pretty(err)); - return NULL; - } - - return SD_CARD(dev); -} - -void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert) -{ - sd->readonly_cb = readonly; - sd->inserted_cb = insert; - qemu_set_irq(readonly, sd->blk ? blk_is_read_only(sd->blk) : 0); - qemu_set_irq(insert, sd->blk ? blk_is_inserted(sd->blk) : 0); -} - -static void sd_erase(SDState *sd) -{ - int i; - uint64_t erase_start = sd->erase_start; - uint64_t erase_end = sd->erase_end; - - if (!sd->erase_start || !sd->erase_end) { - sd->card_status |= ERASE_SEQ_ERROR; - return; - } - - if (extract32(sd->ocr, OCR_CCS_BITN, 1)) { - /* High capacity memory card: erase units are 512 byte blocks */ - erase_start *= 512; - erase_end *= 512; - } - - erase_start = sd_addr_to_wpnum(erase_start); - erase_end = sd_addr_to_wpnum(erase_end); - sd->erase_start = 0; - sd->erase_end = 0; - sd->csd[14] |= 0x40; - - for (i = erase_start; i <= erase_end; i++) { - if (test_bit(i, sd->wp_groups)) { - sd->card_status |= WP_ERASE_SKIP; - } - } -} - -static uint32_t sd_wpbits(SDState *sd, uint64_t addr) -{ - uint32_t i, wpnum; - uint32_t ret = 0; - - wpnum = sd_addr_to_wpnum(addr); - - for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) { - if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) { - ret |= (1 << i); - } - } - - return ret; -} - -static void sd_function_switch(SDState *sd, uint32_t arg) -{ - int i, mode, new_func, crc; - mode = !!(arg & 0x80000000); - - sd->data[0] = 0x00; /* Maximum current consumption */ - sd->data[1] = 0x01; - sd->data[2] = 0x80; /* Supported group 6 functions */ - sd->data[3] = 0x01; - sd->data[4] = 0x80; /* Supported group 5 functions */ - sd->data[5] = 0x01; - sd->data[6] = 0x80; /* Supported group 4 functions */ - sd->data[7] = 0x01; - sd->data[8] = 0x80; /* Supported group 3 functions */ - sd->data[9] = 0x01; - sd->data[10] = 0x80; /* Supported group 2 functions */ - sd->data[11] = 0x43; - sd->data[12] = 0x80; /* Supported group 1 functions */ - sd->data[13] = 0x03; - for (i = 0; i < 6; i ++) { - new_func = (arg >> (i * 4)) & 0x0f; - if (mode && new_func != 0x0f) - sd->function_group[i] = new_func; - sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4); - } - memset(&sd->data[17], 0, 47); - crc = sd_crc16(sd->data, 64); - sd->data[65] = crc >> 8; - sd->data[66] = crc & 0xff; -} - -static inline bool sd_wp_addr(SDState *sd, uint64_t addr) -{ - return test_bit(sd_addr_to_wpnum(addr), sd->wp_groups); -} - -static void sd_lock_command(SDState *sd) -{ - int erase, lock, clr_pwd, set_pwd, pwd_len; - erase = !!(sd->data[0] & 0x08); - lock = sd->data[0] & 0x04; - clr_pwd = sd->data[0] & 0x02; - set_pwd = sd->data[0] & 0x01; - - if (sd->blk_len > 1) - pwd_len = sd->data[1]; - else - pwd_len = 0; - - if (erase) { - if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 || - set_pwd || clr_pwd || lock || sd->wp_switch || - (sd->csd[14] & 0x20)) { - sd->card_status |= LOCK_UNLOCK_FAILED; - return; - } - bitmap_zero(sd->wp_groups, sd->wpgrps_size); - sd->csd[14] &= ~0x10; - sd->card_status &= ~CARD_IS_LOCKED; - sd->pwd_len = 0; - /* Erasing the entire card here! */ - fprintf(stderr, "SD: Card force-erased by CMD42\n"); - return; - } - - if (sd->blk_len < 2 + pwd_len || - pwd_len <= sd->pwd_len || - pwd_len > sd->pwd_len + 16) { - sd->card_status |= LOCK_UNLOCK_FAILED; - return; - } - - if (sd->pwd_len && memcmp(sd->pwd, sd->data + 2, sd->pwd_len)) { - sd->card_status |= LOCK_UNLOCK_FAILED; - return; - } - - pwd_len -= sd->pwd_len; - if ((pwd_len && !set_pwd) || - (clr_pwd && (set_pwd || lock)) || - (lock && !sd->pwd_len && !set_pwd) || - (!set_pwd && !clr_pwd && - (((sd->card_status & CARD_IS_LOCKED) && lock) || - (!(sd->card_status & CARD_IS_LOCKED) && !lock)))) { - sd->card_status |= LOCK_UNLOCK_FAILED; - return; - } - - if (set_pwd) { - memcpy(sd->pwd, sd->data + 2 + sd->pwd_len, pwd_len); - sd->pwd_len = pwd_len; - } - - if (clr_pwd) { - sd->pwd_len = 0; - } - - if (lock) - sd->card_status |= CARD_IS_LOCKED; - else - sd->card_status &= ~CARD_IS_LOCKED; -} - -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; - - /* Not interpreting this as an app command */ - sd->card_status &= ~APP_CMD; - - if (sd_cmd_type[req.cmd & 0x3F] == sd_ac - || sd_cmd_type[req.cmd & 0x3F] == sd_adtc) { - rca = req.arg >> 16; - } - - /* CMD23 (set block count) must be immediately followed by CMD18 or CMD25 - * if not, its effects are cancelled */ - if (sd->multi_blk_cnt != 0 && !(req.cmd == 18 || req.cmd == 25)) { - sd->multi_blk_cnt = 0; - } - - DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state); - switch (req.cmd) { - /* Basic commands (Class 0 and Class 1) */ - case 0: /* CMD0: GO_IDLE_STATE */ - switch (sd->state) { - case sd_inactive_state: - return sd->spi ? sd_r1 : sd_r0; - - default: - sd->state = sd_idle_state; - sd_reset(DEVICE(sd)); - return sd->spi ? sd_r1 : sd_r0; - } - break; - - case 1: /* CMD1: SEND_OP_CMD */ - if (!sd->spi) - goto bad_cmd; - - sd->state = sd_transfer_state; - return sd_r1; - - case 2: /* CMD2: ALL_SEND_CID */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_ready_state: - sd->state = sd_identification_state; - return sd_r2_i; - - default: - break; - } - break; - - case 3: /* CMD3: SEND_RELATIVE_ADDR */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_identification_state: - case sd_standby_state: - sd->state = sd_standby_state; - sd_set_rca(sd); - return sd_r6; - - default: - break; - } - break; - - case 4: /* CMD4: SEND_DSR */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_standby_state: - break; - - default: - break; - } - break; - - case 5: /* CMD5: reserved for SDIO cards */ - return sd_illegal; - - case 6: /* CMD6: SWITCH_FUNCTION */ - if (sd->spi) - goto bad_cmd; - switch (sd->mode) { - case sd_data_transfer_mode: - sd_function_switch(sd, req.arg); - sd->state = sd_sendingdata_state; - sd->data_start = 0; - sd->data_offset = 0; - return sd_r1; - - default: - break; - } - break; - - case 7: /* CMD7: SELECT/DESELECT_CARD */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_standby_state: - if (sd->rca != rca) - return sd_r0; - - sd->state = sd_transfer_state; - return sd_r1b; - - case sd_transfer_state: - case sd_sendingdata_state: - if (sd->rca == rca) - break; - - sd->state = sd_standby_state; - return sd_r1b; - - case sd_disconnect_state: - if (sd->rca != rca) - return sd_r0; - - sd->state = sd_programming_state; - return sd_r1b; - - case sd_programming_state: - if (sd->rca == rca) - break; - - sd->state = sd_disconnect_state; - return sd_r1b; - - default: - break; - } - break; - - case 8: /* CMD8: SEND_IF_COND */ - /* Physical Layer Specification Version 2.00 command */ - switch (sd->state) { - case sd_idle_state: - sd->vhs = 0; - - /* No response if not exactly one VHS bit is set. */ - if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) { - return sd->spi ? sd_r7 : sd_r0; - } - - /* Accept. */ - sd->vhs = req.arg; - return sd_r7; - - default: - break; - } - break; - - case 9: /* CMD9: SEND_CSD */ - switch (sd->state) { - case sd_standby_state: - if (sd->rca != rca) - return sd_r0; - - return sd_r2_s; - - case sd_transfer_state: - if (!sd->spi) - break; - sd->state = sd_sendingdata_state; - memcpy(sd->data, sd->csd, 16); - sd->data_start = addr; - sd->data_offset = 0; - return sd_r1; - - default: - break; - } - break; - - case 10: /* CMD10: SEND_CID */ - switch (sd->state) { - case sd_standby_state: - if (sd->rca != rca) - return sd_r0; - - return sd_r2_i; - - case sd_transfer_state: - if (!sd->spi) - break; - sd->state = sd_sendingdata_state; - memcpy(sd->data, sd->cid, 16); - sd->data_start = addr; - sd->data_offset = 0; - return sd_r1; - - default: - break; - } - break; - - case 11: /* CMD11: READ_DAT_UNTIL_STOP */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_transfer_state: - sd->state = sd_sendingdata_state; - sd->data_start = req.arg; - sd->data_offset = 0; - - if (sd->data_start + sd->blk_len > sd->size) - sd->card_status |= ADDRESS_ERROR; - return sd_r0; - - default: - break; - } - break; - - case 12: /* CMD12: STOP_TRANSMISSION */ - switch (sd->state) { - case sd_sendingdata_state: - sd->state = sd_transfer_state; - return sd_r1b; - - case sd_receivingdata_state: - sd->state = sd_programming_state; - /* Bzzzzzzztt .... Operation complete. */ - sd->state = sd_transfer_state; - return sd_r1b; - - default: - break; - } - break; - - case 13: /* CMD13: SEND_STATUS */ - switch (sd->mode) { - case sd_data_transfer_mode: - if (sd->rca != rca) - return sd_r0; - - return sd_r1; - - default: - break; - } - break; - - case 15: /* CMD15: GO_INACTIVE_STATE */ - if (sd->spi) - goto bad_cmd; - switch (sd->mode) { - case sd_data_transfer_mode: - if (sd->rca != rca) - return sd_r0; - - sd->state = sd_inactive_state; - return sd_r0; - - default: - break; - } - break; - - /* Block read commands (Classs 2) */ - case 16: /* CMD16: SET_BLOCKLEN */ - switch (sd->state) { - case sd_transfer_state: - if (req.arg > (1 << HWBLOCK_SHIFT)) - sd->card_status |= BLOCK_LEN_ERROR; - else - sd->blk_len = req.arg; - - return sd_r1; - - default: - break; - } - break; - - case 17: /* CMD17: READ_SINGLE_BLOCK */ - switch (sd->state) { - case sd_transfer_state: - sd->state = sd_sendingdata_state; - sd->data_start = addr; - sd->data_offset = 0; - - if (sd->data_start + sd->blk_len > sd->size) - sd->card_status |= ADDRESS_ERROR; - return sd_r1; - - default: - break; - } - break; - - case 18: /* CMD18: READ_MULTIPLE_BLOCK */ - switch (sd->state) { - case sd_transfer_state: - sd->state = sd_sendingdata_state; - sd->data_start = addr; - sd->data_offset = 0; - - if (sd->data_start + sd->blk_len > sd->size) - sd->card_status |= ADDRESS_ERROR; - return sd_r1; - - default: - break; - } - break; - - case 23: /* CMD23: SET_BLOCK_COUNT */ - switch (sd->state) { - case sd_transfer_state: - sd->multi_blk_cnt = req.arg; - return sd_r1; - - default: - break; - } - break; - - /* Block write commands (Class 4) */ - case 24: /* CMD24: WRITE_SINGLE_BLOCK */ - if (sd->spi) - goto unimplemented_cmd; - switch (sd->state) { - case sd_transfer_state: - /* Writing in SPI mode not implemented. */ - if (sd->spi) - break; - sd->state = sd_receivingdata_state; - sd->data_start = addr; - sd->data_offset = 0; - sd->blk_written = 0; - - if (sd->data_start + sd->blk_len > sd->size) - sd->card_status |= ADDRESS_ERROR; - if (sd_wp_addr(sd, sd->data_start)) - sd->card_status |= WP_VIOLATION; - if (sd->csd[14] & 0x30) - sd->card_status |= WP_VIOLATION; - return sd_r1; - - default: - break; - } - break; - - case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ - if (sd->spi) - goto unimplemented_cmd; - switch (sd->state) { - case sd_transfer_state: - /* Writing in SPI mode not implemented. */ - if (sd->spi) - break; - sd->state = sd_receivingdata_state; - sd->data_start = addr; - sd->data_offset = 0; - sd->blk_written = 0; - - if (sd->data_start + sd->blk_len > sd->size) - sd->card_status |= ADDRESS_ERROR; - if (sd_wp_addr(sd, sd->data_start)) - sd->card_status |= WP_VIOLATION; - if (sd->csd[14] & 0x30) - sd->card_status |= WP_VIOLATION; - return sd_r1; - - default: - break; - } - break; - - case 26: /* CMD26: PROGRAM_CID */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_transfer_state: - sd->state = sd_receivingdata_state; - sd->data_start = 0; - sd->data_offset = 0; - return sd_r1; - - default: - break; - } - break; - - case 27: /* CMD27: PROGRAM_CSD */ - if (sd->spi) - goto unimplemented_cmd; - switch (sd->state) { - case sd_transfer_state: - sd->state = sd_receivingdata_state; - sd->data_start = 0; - sd->data_offset = 0; - return sd_r1; - - default: - break; - } - break; - - /* Write protection (Class 6) */ - case 28: /* CMD28: SET_WRITE_PROT */ - switch (sd->state) { - case sd_transfer_state: - if (addr >= sd->size) { - sd->card_status |= ADDRESS_ERROR; - return sd_r1b; - } - - sd->state = sd_programming_state; - set_bit(sd_addr_to_wpnum(addr), sd->wp_groups); - /* Bzzzzzzztt .... Operation complete. */ - sd->state = sd_transfer_state; - return sd_r1b; - - default: - break; - } - break; - - case 29: /* CMD29: CLR_WRITE_PROT */ - switch (sd->state) { - case sd_transfer_state: - if (addr >= sd->size) { - sd->card_status |= ADDRESS_ERROR; - return sd_r1b; - } - - sd->state = sd_programming_state; - clear_bit(sd_addr_to_wpnum(addr), sd->wp_groups); - /* Bzzzzzzztt .... Operation complete. */ - sd->state = sd_transfer_state; - return sd_r1b; - - default: - break; - } - break; - - case 30: /* CMD30: SEND_WRITE_PROT */ - switch (sd->state) { - case sd_transfer_state: - sd->state = sd_sendingdata_state; - *(uint32_t *) sd->data = sd_wpbits(sd, req.arg); - sd->data_start = addr; - sd->data_offset = 0; - return sd_r1b; - - default: - break; - } - break; - - /* Erase commands (Class 5) */ - case 32: /* CMD32: ERASE_WR_BLK_START */ - switch (sd->state) { - case sd_transfer_state: - sd->erase_start = req.arg; - return sd_r1; - - default: - break; - } - break; - - case 33: /* CMD33: ERASE_WR_BLK_END */ - switch (sd->state) { - case sd_transfer_state: - sd->erase_end = req.arg; - return sd_r1; - - default: - break; - } - break; - - case 38: /* CMD38: ERASE */ - switch (sd->state) { - case sd_transfer_state: - if (sd->csd[14] & 0x30) { - sd->card_status |= WP_VIOLATION; - return sd_r1b; - } - - sd->state = sd_programming_state; - sd_erase(sd); - /* Bzzzzzzztt .... Operation complete. */ - sd->state = sd_transfer_state; - return sd_r1b; - - default: - break; - } - break; - - /* Lock card commands (Class 7) */ - case 42: /* CMD42: LOCK_UNLOCK */ - if (sd->spi) - goto unimplemented_cmd; - switch (sd->state) { - case sd_transfer_state: - sd->state = sd_receivingdata_state; - sd->data_start = 0; - sd->data_offset = 0; - return sd_r1; - - default: - break; - } - break; - - case 52: - case 53: - /* CMD52, CMD53: reserved for SDIO cards - * (see the SDIO Simplified Specification V2.0) - * Handle as illegal command but do not complain - * on stderr, as some OSes may use these in their - * probing for presence of an SDIO card. - */ - return sd_illegal; - - /* Application specific commands (Class 8) */ - case 55: /* CMD55: APP_CMD */ - if (sd->rca != rca) - return sd_r0; - - sd->expecting_acmd = true; - sd->card_status |= APP_CMD; - return sd_r1; - - case 56: /* CMD56: GEN_CMD */ - fprintf(stderr, "SD: GEN_CMD 0x%08x\n", req.arg); - - switch (sd->state) { - case sd_transfer_state: - sd->data_offset = 0; - if (req.arg & 1) - sd->state = sd_sendingdata_state; - else - sd->state = sd_receivingdata_state; - return sd_r1; - - default: - break; - } - break; - - default: - bad_cmd: - qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd); - return sd_illegal; - - unimplemented_cmd: - /* Commands that are recognised but not yet implemented in SPI mode. */ - qemu_log_mask(LOG_UNIMP, "SD: CMD%i not implemented in SPI mode\n", - req.cmd); - return sd_illegal; - } - - qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state\n", req.cmd); - return sd_illegal; -} - -static sd_rsp_type_t sd_app_command(SDState *sd, - SDRequest req) -{ - DPRINTF("ACMD%d 0x%08x\n", req.cmd, req.arg); - sd->card_status |= APP_CMD; - switch (req.cmd) { - case 6: /* ACMD6: SET_BUS_WIDTH */ - switch (sd->state) { - case sd_transfer_state: - sd->sd_status[0] &= 0x3f; - sd->sd_status[0] |= (req.arg & 0x03) << 6; - return sd_r1; - - default: - break; - } - break; - - case 13: /* ACMD13: SD_STATUS */ - switch (sd->state) { - case sd_transfer_state: - sd->state = sd_sendingdata_state; - sd->data_start = 0; - sd->data_offset = 0; - return sd_r1; - - default: - break; - } - break; - - case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ - switch (sd->state) { - case sd_transfer_state: - *(uint32_t *) sd->data = sd->blk_written; - - sd->state = sd_sendingdata_state; - sd->data_start = 0; - sd->data_offset = 0; - return sd_r1; - - default: - break; - } - break; - - case 23: /* ACMD23: SET_WR_BLK_ERASE_COUNT */ - switch (sd->state) { - case sd_transfer_state: - return sd_r1; - - default: - break; - } - break; - - case 41: /* ACMD41: SD_APP_OP_COND */ - if (sd->spi) { - /* SEND_OP_CMD */ - sd->state = sd_transfer_state; - return sd_r1; - } - switch (sd->state) { - case sd_idle_state: - /* If it's the first ACMD41 since reset, we need to decide - * whether to power up. If this is not an enquiry ACMD41, - * we immediately report power on and proceed below to the - * ready state, but if it is, we set a timer to model a - * delay for power up. This works around a bug in EDK2 - * UEFI, which sends an initial enquiry ACMD41, but - * assumes that the card is in ready state as soon as it - * sees the power up bit set. */ - if (!(sd->ocr & OCR_POWER_UP)) { - if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) { - timer_del(sd->ocr_power_timer); - sd_ocr_powerup(sd); - } else if (!timer_pending(sd->ocr_power_timer)) { - timer_mod_ns(sd->ocr_power_timer, - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - + OCR_POWER_DELAY_NS)); - } - } - - /* We accept any voltage. 10000 V is nothing. - * - * Once we're powered up, we advance straight to ready state - * unless it's an enquiry ACMD41 (bits 23:0 == 0). - */ - if (req.arg & ACMD41_ENQUIRY_MASK) { - sd->state = sd_ready_state; - } - - return sd_r3; - - default: - break; - } - break; - - case 42: /* ACMD42: SET_CLR_CARD_DETECT */ - switch (sd->state) { - case sd_transfer_state: - /* Bringing in the 50KOhm pull-up resistor... Done. */ - return sd_r1; - - default: - break; - } - break; - - case 51: /* ACMD51: SEND_SCR */ - switch (sd->state) { - case sd_transfer_state: - sd->state = sd_sendingdata_state; - sd->data_start = 0; - sd->data_offset = 0; - return sd_r1; - - default: - break; - } - break; - - default: - /* Fall back to standard commands. */ - return sd_normal_command(sd, req); - } - - qemu_log_mask(LOG_GUEST_ERROR, "SD: ACMD%i in a wrong state\n", req.cmd); - return sd_illegal; -} - -static int cmd_valid_while_locked(SDState *sd, SDRequest *req) -{ - /* Valid commands in locked state: - * basic class (0) - * lock card class (7) - * CMD16 - * implicitly, the ACMD prefix CMD55 - * ACMD41 and ACMD42 - * Anything else provokes an "illegal command" response. - */ - if (sd->expecting_acmd) { - return req->cmd == 41 || req->cmd == 42; - } - if (req->cmd == 16 || req->cmd == 55) { - return 1; - } - return sd_cmd_class[req->cmd & 0x3F] == 0 - || sd_cmd_class[req->cmd & 0x3F] == 7; -} - -int sd_do_command(SDState *sd, SDRequest *req, - uint8_t *response) { - int last_state; - sd_rsp_type_t rtype; - int rsplen; - - if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable) { - return 0; - } - - if (sd_req_crc_validate(req)) { - sd->card_status |= COM_CRC_ERROR; - rtype = sd_illegal; - goto send_response; - } - - if (sd->card_status & CARD_IS_LOCKED) { - if (!cmd_valid_while_locked(sd, req)) { - sd->card_status |= ILLEGAL_COMMAND; - sd->expecting_acmd = false; - qemu_log_mask(LOG_GUEST_ERROR, "SD: Card is locked\n"); - rtype = sd_illegal; - goto send_response; - } - } - - last_state = sd->state; - sd_set_mode(sd); - - if (sd->expecting_acmd) { - sd->expecting_acmd = false; - rtype = sd_app_command(sd, *req); - } else { - rtype = sd_normal_command(sd, *req); - } - - if (rtype == sd_illegal) { - sd->card_status |= ILLEGAL_COMMAND; - } else { - /* Valid command, we can update the 'state before command' bits. - * (Do this now so they appear in r1 responses.) - */ - sd->current_cmd = req->cmd; - sd->card_status &= ~CURRENT_STATE; - sd->card_status |= (last_state << 9); - } - -send_response: - switch (rtype) { - case sd_r1: - case sd_r1b: - sd_response_r1_make(sd, response); - rsplen = 4; - break; - - case sd_r2_i: - memcpy(response, sd->cid, sizeof(sd->cid)); - rsplen = 16; - break; - - case sd_r2_s: - memcpy(response, sd->csd, sizeof(sd->csd)); - rsplen = 16; - break; - - case sd_r3: - sd_response_r3_make(sd, response); - rsplen = 4; - break; - - case sd_r6: - sd_response_r6_make(sd, response); - rsplen = 4; - break; - - case sd_r7: - sd_response_r7_make(sd, response); - rsplen = 4; - break; - - case sd_r0: - case sd_illegal: - default: - rsplen = 0; - break; - } - - if (rtype != sd_illegal) { - /* Clear the "clear on valid command" status bits now we've - * sent any response - */ - sd->card_status &= ~CARD_STATUS_B; - } - -#ifdef DEBUG_SD - if (rsplen) { - int i; - DPRINTF("Response:"); - for (i = 0; i < rsplen; i++) - fprintf(stderr, " %02x", response[i]); - fprintf(stderr, " state %d\n", sd->state); - } else { - DPRINTF("No response %d\n", sd->state); - } -#endif - - return rsplen; -} - -static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len) -{ - uint64_t end = addr + len; - - DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n", - (unsigned long long) addr, len); - if (!sd->blk || blk_read(sd->blk, addr >> 9, sd->buf, 1) < 0) { - fprintf(stderr, "sd_blk_read: read error on host side\n"); - return; - } - - if (end > (addr & ~511) + 512) { - memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511)); - - if (blk_read(sd->blk, end >> 9, sd->buf, 1) < 0) { - fprintf(stderr, "sd_blk_read: read error on host side\n"); - return; - } - memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511); - } else - memcpy(sd->data, sd->buf + (addr & 511), len); -} - -static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len) -{ - uint64_t end = addr + len; - - if ((addr & 511) || len < 512) - if (!sd->blk || blk_read(sd->blk, addr >> 9, sd->buf, 1) < 0) { - fprintf(stderr, "sd_blk_write: read error on host side\n"); - return; - } - - if (end > (addr & ~511) + 512) { - memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511)); - if (blk_write(sd->blk, addr >> 9, sd->buf, 1) < 0) { - fprintf(stderr, "sd_blk_write: write error on host side\n"); - return; - } - - if (blk_read(sd->blk, end >> 9, sd->buf, 1) < 0) { - fprintf(stderr, "sd_blk_write: read error on host side\n"); - return; - } - memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511); - if (blk_write(sd->blk, end >> 9, sd->buf, 1) < 0) { - fprintf(stderr, "sd_blk_write: write error on host side\n"); - } - } else { - memcpy(sd->buf + (addr & 511), sd->data, len); - if (!sd->blk || blk_write(sd->blk, addr >> 9, sd->buf, 1) < 0) { - fprintf(stderr, "sd_blk_write: write error on host side\n"); - } - } -} - -#define BLK_READ_BLOCK(a, len) sd_blk_read(sd, a, len) -#define BLK_WRITE_BLOCK(a, len) sd_blk_write(sd, a, len) -#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len) -#define APP_WRITE_BLOCK(a, len) - -void sd_write_data(SDState *sd, uint8_t value) -{ - int i; - - if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable) - return; - - if (sd->state != sd_receivingdata_state) { - qemu_log_mask(LOG_GUEST_ERROR, - "sd_write_data: not in Receiving-Data state\n"); - return; - } - - if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) - return; - - switch (sd->current_cmd) { - case 24: /* CMD24: WRITE_SINGLE_BLOCK */ - sd->data[sd->data_offset ++] = value; - if (sd->data_offset >= sd->blk_len) { - /* TODO: Check CRC before committing */ - sd->state = sd_programming_state; - BLK_WRITE_BLOCK(sd->data_start, sd->data_offset); - sd->blk_written ++; - sd->csd[14] |= 0x40; - /* Bzzzzzzztt .... Operation complete. */ - sd->state = sd_transfer_state; - } - break; - - case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ - if (sd->data_offset == 0) { - /* Start of the block - let's check the address is valid */ - if (sd->data_start + sd->blk_len > sd->size) { - sd->card_status |= ADDRESS_ERROR; - break; - } - if (sd_wp_addr(sd, sd->data_start)) { - sd->card_status |= WP_VIOLATION; - break; - } - } - sd->data[sd->data_offset++] = value; - if (sd->data_offset >= sd->blk_len) { - /* TODO: Check CRC before committing */ - sd->state = sd_programming_state; - BLK_WRITE_BLOCK(sd->data_start, sd->data_offset); - sd->blk_written++; - sd->data_start += sd->blk_len; - sd->data_offset = 0; - sd->csd[14] |= 0x40; - - /* Bzzzzzzztt .... Operation complete. */ - if (sd->multi_blk_cnt != 0) { - if (--sd->multi_blk_cnt == 0) { - /* Stop! */ - sd->state = sd_transfer_state; - break; - } - } - - sd->state = sd_receivingdata_state; - } - break; - - case 26: /* CMD26: PROGRAM_CID */ - sd->data[sd->data_offset ++] = value; - if (sd->data_offset >= sizeof(sd->cid)) { - /* TODO: Check CRC before committing */ - sd->state = sd_programming_state; - for (i = 0; i < sizeof(sd->cid); i ++) - if ((sd->cid[i] | 0x00) != sd->data[i]) - sd->card_status |= CID_CSD_OVERWRITE; - - if (!(sd->card_status & CID_CSD_OVERWRITE)) - for (i = 0; i < sizeof(sd->cid); i ++) { - sd->cid[i] |= 0x00; - sd->cid[i] &= sd->data[i]; - } - /* Bzzzzzzztt .... Operation complete. */ - sd->state = sd_transfer_state; - } - break; - - case 27: /* CMD27: PROGRAM_CSD */ - sd->data[sd->data_offset ++] = value; - if (sd->data_offset >= sizeof(sd->csd)) { - /* TODO: Check CRC before committing */ - sd->state = sd_programming_state; - for (i = 0; i < sizeof(sd->csd); i ++) - if ((sd->csd[i] | sd_csd_rw_mask[i]) != - (sd->data[i] | sd_csd_rw_mask[i])) - sd->card_status |= CID_CSD_OVERWRITE; - - /* Copy flag (OTP) & Permanent write protect */ - if (sd->csd[14] & ~sd->data[14] & 0x60) - sd->card_status |= CID_CSD_OVERWRITE; - - if (!(sd->card_status & CID_CSD_OVERWRITE)) - for (i = 0; i < sizeof(sd->csd); i ++) { - sd->csd[i] |= sd_csd_rw_mask[i]; - sd->csd[i] &= sd->data[i]; - } - /* Bzzzzzzztt .... Operation complete. */ - sd->state = sd_transfer_state; - } - break; - - case 42: /* CMD42: LOCK_UNLOCK */ - sd->data[sd->data_offset ++] = value; - if (sd->data_offset >= sd->blk_len) { - /* TODO: Check CRC before committing */ - sd->state = sd_programming_state; - sd_lock_command(sd); - /* Bzzzzzzztt .... Operation complete. */ - sd->state = sd_transfer_state; - } - break; - - case 56: /* CMD56: GEN_CMD */ - sd->data[sd->data_offset ++] = value; - if (sd->data_offset >= sd->blk_len) { - APP_WRITE_BLOCK(sd->data_start, sd->data_offset); - sd->state = sd_transfer_state; - } - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, "sd_write_data: unknown command\n"); - break; - } -} - -uint8_t sd_read_data(SDState *sd) -{ - /* TODO: Append CRCs */ - uint8_t ret; - int io_len; - - if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable) - return 0x00; - - if (sd->state != sd_sendingdata_state) { - qemu_log_mask(LOG_GUEST_ERROR, - "sd_read_data: not in Sending-Data state\n"); - return 0x00; - } - - if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) - return 0x00; - - io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len; - - switch (sd->current_cmd) { - case 6: /* CMD6: SWITCH_FUNCTION */ - ret = sd->data[sd->data_offset ++]; - - if (sd->data_offset >= 64) - sd->state = sd_transfer_state; - break; - - case 9: /* CMD9: SEND_CSD */ - case 10: /* CMD10: SEND_CID */ - ret = sd->data[sd->data_offset ++]; - - if (sd->data_offset >= 16) - sd->state = sd_transfer_state; - break; - - case 11: /* CMD11: READ_DAT_UNTIL_STOP */ - if (sd->data_offset == 0) - BLK_READ_BLOCK(sd->data_start, io_len); - ret = sd->data[sd->data_offset ++]; - - if (sd->data_offset >= io_len) { - sd->data_start += io_len; - sd->data_offset = 0; - if (sd->data_start + io_len > sd->size) { - sd->card_status |= ADDRESS_ERROR; - break; - } - } - break; - - case 13: /* ACMD13: SD_STATUS */ - ret = sd->sd_status[sd->data_offset ++]; - - if (sd->data_offset >= sizeof(sd->sd_status)) - sd->state = sd_transfer_state; - break; - - case 17: /* CMD17: READ_SINGLE_BLOCK */ - if (sd->data_offset == 0) - BLK_READ_BLOCK(sd->data_start, io_len); - ret = sd->data[sd->data_offset ++]; - - if (sd->data_offset >= io_len) - sd->state = sd_transfer_state; - break; - - case 18: /* CMD18: READ_MULTIPLE_BLOCK */ - if (sd->data_offset == 0) - BLK_READ_BLOCK(sd->data_start, io_len); - ret = sd->data[sd->data_offset ++]; - - if (sd->data_offset >= io_len) { - sd->data_start += io_len; - sd->data_offset = 0; - - if (sd->multi_blk_cnt != 0) { - if (--sd->multi_blk_cnt == 0) { - /* Stop! */ - sd->state = sd_transfer_state; - break; - } - } - - if (sd->data_start + io_len > sd->size) { - sd->card_status |= ADDRESS_ERROR; - break; - } - } - break; - - case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ - ret = sd->data[sd->data_offset ++]; - - if (sd->data_offset >= 4) - sd->state = sd_transfer_state; - break; - - case 30: /* CMD30: SEND_WRITE_PROT */ - ret = sd->data[sd->data_offset ++]; - - if (sd->data_offset >= 4) - sd->state = sd_transfer_state; - break; - - case 51: /* ACMD51: SEND_SCR */ - ret = sd->scr[sd->data_offset ++]; - - if (sd->data_offset >= sizeof(sd->scr)) - sd->state = sd_transfer_state; - break; - - case 56: /* CMD56: GEN_CMD */ - if (sd->data_offset == 0) - APP_READ_BLOCK(sd->data_start, sd->blk_len); - ret = sd->data[sd->data_offset ++]; - - if (sd->data_offset >= sd->blk_len) - sd->state = sd_transfer_state; - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, "sd_read_data: unknown command\n"); - return 0x00; - } - - return ret; -} - -bool sd_data_ready(SDState *sd) -{ - return sd->state == sd_sendingdata_state; -} - -void sd_enable(SDState *sd, bool enable) -{ - sd->enable = enable; -} - -static void sd_instance_init(Object *obj) -{ - SDState *sd = SD_CARD(obj); - - sd->enable = true; - sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd); -} - -static void sd_realize(DeviceState *dev, Error **errp) -{ - SDState *sd = SD_CARD(dev); - - if (sd->blk && blk_is_read_only(sd->blk)) { - error_setg(errp, "Cannot use read-only drive as SD card"); - return; - } - - sd->buf = blk_blockalign(sd->blk, 512); - - if (sd->blk) { - blk_set_dev_ops(sd->blk, &sd_block_ops, sd); - } -} - -static Property sd_properties[] = { - DEFINE_PROP_DRIVE("drive", SDState, blk), - /* We do not model the chip select pin, so allow the board to select - * whether card should be in SSI or MMC/SD mode. It is also up to the - * board to ensure that ssi transfers only occur when the chip select - * is asserted. */ - DEFINE_PROP_BOOL("spi", SDState, spi, false), - DEFINE_PROP_END_OF_LIST() -}; - -static void sd_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SDCardClass *sc = SD_CARD_CLASS(klass); - - dc->realize = sd_realize; - dc->props = sd_properties; - dc->vmsd = &sd_vmstate; - dc->reset = sd_reset; - dc->bus_type = TYPE_SD_BUS; - - sc->do_command = sd_do_command; - sc->write_data = sd_write_data; - sc->read_data = sd_read_data; - sc->data_ready = sd_data_ready; - sc->enable = sd_enable; - sc->get_inserted = sd_get_inserted; - sc->get_readonly = sd_get_readonly; -} - -static const TypeInfo sd_info = { - .name = TYPE_SD_CARD, - .parent = TYPE_DEVICE, - .instance_size = sizeof(SDState), - .class_size = sizeof(SDCardClass), - .class_init = sd_class_init, - .instance_init = sd_instance_init, -}; - -static void sd_register_types(void) -{ - type_register_static(&sd_info); -} - -type_init(sd_register_types) diff --git a/qemu/hw/sd/sdhci-internal.h b/qemu/hw/sd/sdhci-internal.h deleted file mode 100644 index 161177cf3..000000000 --- a/qemu/hw/sd/sdhci-internal.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * SD Association Host Standard Specification v2.0 controller emulation - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * Mitsyanko Igor <i.mitsyanko@samsung.com> - * Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com> - * - * Based on MMC controller for Samsung S5PC1xx-based board emulation - * by Alexey Merkulov and Vladimir Monakhov. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ -#ifndef SDHCI_INTERNAL_H -#define SDHCI_INTERNAL_H - -#include "hw/sd/sdhci.h" - -/* R/W SDMA System Address register 0x0 */ -#define SDHC_SYSAD 0x00 - -/* R/W Host DMA Buffer Boundary and Transfer Block Size Register 0x0 */ -#define SDHC_BLKSIZE 0x04 - -/* R/W Blocks count for current transfer 0x0 */ -#define SDHC_BLKCNT 0x06 - -/* R/W Command Argument Register 0x0 */ -#define SDHC_ARGUMENT 0x08 - -/* R/W Transfer Mode Setting Register 0x0 */ -#define SDHC_TRNMOD 0x0C -#define SDHC_TRNS_DMA 0x0001 -#define SDHC_TRNS_BLK_CNT_EN 0x0002 -#define SDHC_TRNS_ACMD12 0x0004 -#define SDHC_TRNS_READ 0x0010 -#define SDHC_TRNS_MULTI 0x0020 - -/* R/W Command Register 0x0 */ -#define SDHC_CMDREG 0x0E -#define SDHC_CMD_RSP_WITH_BUSY (3 << 0) -#define SDHC_CMD_DATA_PRESENT (1 << 5) -#define SDHC_CMD_SUSPEND (1 << 6) -#define SDHC_CMD_RESUME (1 << 7) -#define SDHC_CMD_ABORT ((1 << 6)|(1 << 7)) -#define SDHC_CMD_TYPE_MASK ((1 << 6)|(1 << 7)) -#define SDHC_COMMAND_TYPE(x) ((x) & SDHC_CMD_TYPE_MASK) - -/* ROC Response Register 0 0x0 */ -#define SDHC_RSPREG0 0x10 -/* ROC Response Register 1 0x0 */ -#define SDHC_RSPREG1 0x14 -/* ROC Response Register 2 0x0 */ -#define SDHC_RSPREG2 0x18 -/* ROC Response Register 3 0x0 */ -#define SDHC_RSPREG3 0x1C - -/* R/W Buffer Data Register 0x0 */ -#define SDHC_BDATA 0x20 - -/* R/ROC Present State Register 0x000A0000 */ -#define SDHC_PRNSTS 0x24 -#define SDHC_CMD_INHIBIT 0x00000001 -#define SDHC_DATA_INHIBIT 0x00000002 -#define SDHC_DAT_LINE_ACTIVE 0x00000004 -#define SDHC_DOING_WRITE 0x00000100 -#define SDHC_DOING_READ 0x00000200 -#define SDHC_SPACE_AVAILABLE 0x00000400 -#define SDHC_DATA_AVAILABLE 0x00000800 -#define SDHC_CARD_PRESENT 0x00010000 -#define SDHC_CARD_DETECT 0x00040000 -#define SDHC_WRITE_PROTECT 0x00080000 -#define TRANSFERRING_DATA(x) \ - ((x) & (SDHC_DOING_READ | SDHC_DOING_WRITE)) - -/* R/W Host control Register 0x0 */ -#define SDHC_HOSTCTL 0x28 -#define SDHC_CTRL_DMA_CHECK_MASK 0x18 -#define SDHC_CTRL_SDMA 0x00 -#define SDHC_CTRL_ADMA1_32 0x08 -#define SDHC_CTRL_ADMA2_32 0x10 -#define SDHC_CTRL_ADMA2_64 0x18 -#define SDHC_DMA_TYPE(x) ((x) & SDHC_CTRL_DMA_CHECK_MASK) - -/* R/W Power Control Register 0x0 */ -#define SDHC_PWRCON 0x29 -#define SDHC_POWER_ON (1 << 0) - -/* R/W Block Gap Control Register 0x0 */ -#define SDHC_BLKGAP 0x2A -#define SDHC_STOP_AT_GAP_REQ 0x01 -#define SDHC_CONTINUE_REQ 0x02 - -/* R/W WakeUp Control Register 0x0 */ -#define SDHC_WAKCON 0x2B -#define SDHC_WKUP_ON_INS (1 << 1) -#define SDHC_WKUP_ON_RMV (1 << 2) - -/* CLKCON */ -#define SDHC_CLKCON 0x2C -#define SDHC_CLOCK_INT_STABLE 0x0002 -#define SDHC_CLOCK_INT_EN 0x0001 -#define SDHC_CLOCK_SDCLK_EN (1 << 2) -#define SDHC_CLOCK_CHK_MASK 0x0007 -#define SDHC_CLOCK_IS_ON(x) \ - (((x) & SDHC_CLOCK_CHK_MASK) == SDHC_CLOCK_CHK_MASK) - -/* R/W Timeout Control Register 0x0 */ -#define SDHC_TIMEOUTCON 0x2E - -/* R/W Software Reset Register 0x0 */ -#define SDHC_SWRST 0x2F -#define SDHC_RESET_ALL 0x01 -#define SDHC_RESET_CMD 0x02 -#define SDHC_RESET_DATA 0x04 - -/* ROC/RW1C Normal Interrupt Status Register 0x0 */ -#define SDHC_NORINTSTS 0x30 -#define SDHC_NIS_ERR 0x8000 -#define SDHC_NIS_CMDCMP 0x0001 -#define SDHC_NIS_TRSCMP 0x0002 -#define SDHC_NIS_BLKGAP 0x0004 -#define SDHC_NIS_DMA 0x0008 -#define SDHC_NIS_WBUFRDY 0x0010 -#define SDHC_NIS_RBUFRDY 0x0020 -#define SDHC_NIS_INSERT 0x0040 -#define SDHC_NIS_REMOVE 0x0080 -#define SDHC_NIS_CARDINT 0x0100 - -/* ROC/RW1C Error Interrupt Status Register 0x0 */ -#define SDHC_ERRINTSTS 0x32 -#define SDHC_EIS_CMDTIMEOUT 0x0001 -#define SDHC_EIS_BLKGAP 0x0004 -#define SDHC_EIS_CMDIDX 0x0008 -#define SDHC_EIS_CMD12ERR 0x0100 -#define SDHC_EIS_ADMAERR 0x0200 - -/* R/W Normal Interrupt Status Enable Register 0x0 */ -#define SDHC_NORINTSTSEN 0x34 -#define SDHC_NISEN_CMDCMP 0x0001 -#define SDHC_NISEN_TRSCMP 0x0002 -#define SDHC_NISEN_DMA 0x0008 -#define SDHC_NISEN_WBUFRDY 0x0010 -#define SDHC_NISEN_RBUFRDY 0x0020 -#define SDHC_NISEN_INSERT 0x0040 -#define SDHC_NISEN_REMOVE 0x0080 -#define SDHC_NISEN_CARDINT 0x0100 - -/* R/W Error Interrupt Status Enable Register 0x0 */ -#define SDHC_ERRINTSTSEN 0x36 -#define SDHC_EISEN_CMDTIMEOUT 0x0001 -#define SDHC_EISEN_BLKGAP 0x0004 -#define SDHC_EISEN_CMDIDX 0x0008 -#define SDHC_EISEN_ADMAERR 0x0200 - -/* R/W Normal Interrupt Signal Enable Register 0x0 */ -#define SDHC_NORINTSIGEN 0x38 -#define SDHC_NORINTSIG_INSERT (1 << 6) -#define SDHC_NORINTSIG_REMOVE (1 << 7) - -/* R/W Error Interrupt Signal Enable Register 0x0 */ -#define SDHC_ERRINTSIGEN 0x3A - -/* ROC Auto CMD12 error status register 0x0 */ -#define SDHC_ACMD12ERRSTS 0x3C - -/* HWInit Capabilities Register 0x05E80080 */ -#define SDHC_CAPAREG 0x40 -#define SDHC_CAN_DO_DMA 0x00400000 -#define SDHC_CAN_DO_ADMA2 0x00080000 -#define SDHC_CAN_DO_ADMA1 0x00100000 -#define SDHC_64_BIT_BUS_SUPPORT (1 << 28) -#define SDHC_CAPAB_BLOCKSIZE(x) (((x) >> 16) & 0x3) - -/* HWInit Maximum Current Capabilities Register 0x0 */ -#define SDHC_MAXCURR 0x48 - -/* W Force Event Auto CMD12 Error Interrupt Register 0x0000 */ -#define SDHC_FEAER 0x50 -/* W Force Event Error Interrupt Register Error Interrupt 0x0000 */ -#define SDHC_FEERR 0x52 - -/* R/W ADMA Error Status Register 0x00 */ -#define SDHC_ADMAERR 0x54 -#define SDHC_ADMAERR_LENGTH_MISMATCH (1 << 2) -#define SDHC_ADMAERR_STATE_ST_STOP (0 << 0) -#define SDHC_ADMAERR_STATE_ST_FDS (1 << 0) -#define SDHC_ADMAERR_STATE_ST_TFR (3 << 0) -#define SDHC_ADMAERR_STATE_MASK (3 << 0) - -/* R/W ADMA System Address Register 0x00 */ -#define SDHC_ADMASYSADDR 0x58 -#define SDHC_ADMA_ATTR_SET_LEN (1 << 4) -#define SDHC_ADMA_ATTR_ACT_TRAN (1 << 5) -#define SDHC_ADMA_ATTR_ACT_LINK (3 << 4) -#define SDHC_ADMA_ATTR_INT (1 << 2) -#define SDHC_ADMA_ATTR_END (1 << 1) -#define SDHC_ADMA_ATTR_VALID (1 << 0) -#define SDHC_ADMA_ATTR_ACT_MASK ((1 << 4)|(1 << 5)) - -/* Slot interrupt status */ -#define SDHC_SLOT_INT_STATUS 0xFC - -/* HWInit Host Controller Version Register 0x0401 */ -#define SDHC_HCVER 0xFE -#define SD_HOST_SPECv2_VERS 0x2401 - -#define SDHC_REGISTERS_MAP_SIZE 0x100 -#define SDHC_INSERTION_DELAY (NANOSECONDS_PER_SECOND) -#define SDHC_TRANSFER_DELAY 100 -#define SDHC_ADMA_DESCS_PER_DELAY 5 -#define SDHC_CMD_RESPONSE (3 << 0) - -enum { - sdhc_not_stopped = 0, /* normal SDHC state */ - sdhc_gap_read = 1, /* SDHC stopped at block gap during read operation */ - sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */ -}; - -extern const VMStateDescription sdhci_vmstate; - -#endif diff --git a/qemu/hw/sd/sdhci.c b/qemu/hw/sd/sdhci.c deleted file mode 100644 index d28b5871f..000000000 --- a/qemu/hw/sd/sdhci.c +++ /dev/null @@ -1,1394 +0,0 @@ -/* - * SD Association Host Standard Specification v2.0 controller emulation - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * Mitsyanko Igor <i.mitsyanko@samsung.com> - * Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com> - * - * Based on MMC controller for Samsung S5PC1xx-based board emulation - * by Alexey Merkulov and Vladimir Monakhov. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "sysemu/dma.h" -#include "qemu/timer.h" -#include "qemu/bitops.h" -#include "sdhci-internal.h" - -/* host controller debug messages */ -#ifndef SDHC_DEBUG -#define SDHC_DEBUG 0 -#endif - -#define DPRINT_L1(fmt, args...) \ - do { \ - if (SDHC_DEBUG) { \ - fprintf(stderr, "QEMU SDHC: " fmt, ## args); \ - } \ - } while (0) -#define DPRINT_L2(fmt, args...) \ - do { \ - if (SDHC_DEBUG > 1) { \ - fprintf(stderr, "QEMU SDHC: " fmt, ## args); \ - } \ - } while (0) -#define ERRPRINT(fmt, args...) \ - do { \ - if (SDHC_DEBUG) { \ - fprintf(stderr, "QEMU SDHC ERROR: " fmt, ## args); \ - } \ - } while (0) - -#define TYPE_SDHCI_BUS "sdhci-bus" -#define SDHCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SDHCI_BUS) - -/* Default SD/MMC host controller features information, which will be - * presented in CAPABILITIES register of generic SD host controller at reset. - * If not stated otherwise: - * 0 - not supported, 1 - supported, other - prohibited. - */ -#define SDHC_CAPAB_64BITBUS 0ul /* 64-bit System Bus Support */ -#define SDHC_CAPAB_18V 1ul /* Voltage support 1.8v */ -#define SDHC_CAPAB_30V 0ul /* Voltage support 3.0v */ -#define SDHC_CAPAB_33V 1ul /* Voltage support 3.3v */ -#define SDHC_CAPAB_SUSPRESUME 0ul /* Suspend/resume support */ -#define SDHC_CAPAB_SDMA 1ul /* SDMA support */ -#define SDHC_CAPAB_HIGHSPEED 1ul /* High speed support */ -#define SDHC_CAPAB_ADMA1 1ul /* ADMA1 support */ -#define SDHC_CAPAB_ADMA2 1ul /* ADMA2 support */ -/* Maximum host controller R/W buffers size - * Possible values: 512, 1024, 2048 bytes */ -#define SDHC_CAPAB_MAXBLOCKLENGTH 512ul -/* Maximum clock frequency for SDclock in MHz - * value in range 10-63 MHz, 0 - not defined */ -#define SDHC_CAPAB_BASECLKFREQ 52ul -#define SDHC_CAPAB_TOUNIT 1ul /* Timeout clock unit 0 - kHz, 1 - MHz */ -/* Timeout clock frequency 1-63, 0 - not defined */ -#define SDHC_CAPAB_TOCLKFREQ 52ul - -/* Now check all parameters and calculate CAPABILITIES REGISTER value */ -#if SDHC_CAPAB_64BITBUS > 1 || SDHC_CAPAB_18V > 1 || SDHC_CAPAB_30V > 1 || \ - SDHC_CAPAB_33V > 1 || SDHC_CAPAB_SUSPRESUME > 1 || SDHC_CAPAB_SDMA > 1 || \ - SDHC_CAPAB_HIGHSPEED > 1 || SDHC_CAPAB_ADMA2 > 1 || SDHC_CAPAB_ADMA1 > 1 ||\ - SDHC_CAPAB_TOUNIT > 1 -#error Capabilities features can have value 0 or 1 only! -#endif - -#if SDHC_CAPAB_MAXBLOCKLENGTH == 512 -#define MAX_BLOCK_LENGTH 0ul -#elif SDHC_CAPAB_MAXBLOCKLENGTH == 1024 -#define MAX_BLOCK_LENGTH 1ul -#elif SDHC_CAPAB_MAXBLOCKLENGTH == 2048 -#define MAX_BLOCK_LENGTH 2ul -#else -#error Max host controller block size can have value 512, 1024 or 2048 only! -#endif - -#if (SDHC_CAPAB_BASECLKFREQ > 0 && SDHC_CAPAB_BASECLKFREQ < 10) || \ - SDHC_CAPAB_BASECLKFREQ > 63 -#error SDclock frequency can have value in range 0, 10-63 only! -#endif - -#if SDHC_CAPAB_TOCLKFREQ > 63 -#error Timeout clock frequency can have value in range 0-63 only! -#endif - -#define SDHC_CAPAB_REG_DEFAULT \ - ((SDHC_CAPAB_64BITBUS << 28) | (SDHC_CAPAB_18V << 26) | \ - (SDHC_CAPAB_30V << 25) | (SDHC_CAPAB_33V << 24) | \ - (SDHC_CAPAB_SUSPRESUME << 23) | (SDHC_CAPAB_SDMA << 22) | \ - (SDHC_CAPAB_HIGHSPEED << 21) | (SDHC_CAPAB_ADMA1 << 20) | \ - (SDHC_CAPAB_ADMA2 << 19) | (MAX_BLOCK_LENGTH << 16) | \ - (SDHC_CAPAB_BASECLKFREQ << 8) | (SDHC_CAPAB_TOUNIT << 7) | \ - (SDHC_CAPAB_TOCLKFREQ)) - -#define MASKED_WRITE(reg, mask, val) (reg = (reg & (mask)) | (val)) - -static uint8_t sdhci_slotint(SDHCIState *s) -{ - return (s->norintsts & s->norintsigen) || (s->errintsts & s->errintsigen) || - ((s->norintsts & SDHC_NIS_INSERT) && (s->wakcon & SDHC_WKUP_ON_INS)) || - ((s->norintsts & SDHC_NIS_REMOVE) && (s->wakcon & SDHC_WKUP_ON_RMV)); -} - -static inline void sdhci_update_irq(SDHCIState *s) -{ - qemu_set_irq(s->irq, sdhci_slotint(s)); -} - -static void sdhci_raise_insertion_irq(void *opaque) -{ - SDHCIState *s = (SDHCIState *)opaque; - - if (s->norintsts & SDHC_NIS_REMOVE) { - timer_mod(s->insert_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY); - } else { - s->prnsts = 0x1ff0000; - if (s->norintstsen & SDHC_NISEN_INSERT) { - s->norintsts |= SDHC_NIS_INSERT; - } - sdhci_update_irq(s); - } -} - -static void sdhci_set_inserted(DeviceState *dev, bool level) -{ - SDHCIState *s = (SDHCIState *)dev; - DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject"); - - if ((s->norintsts & SDHC_NIS_REMOVE) && level) { - /* Give target some time to notice card ejection */ - timer_mod(s->insert_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_INSERTION_DELAY); - } else { - if (level) { - s->prnsts = 0x1ff0000; - if (s->norintstsen & SDHC_NISEN_INSERT) { - s->norintsts |= SDHC_NIS_INSERT; - } - } else { - s->prnsts = 0x1fa0000; - s->pwrcon &= ~SDHC_POWER_ON; - s->clkcon &= ~SDHC_CLOCK_SDCLK_EN; - if (s->norintstsen & SDHC_NISEN_REMOVE) { - s->norintsts |= SDHC_NIS_REMOVE; - } - } - sdhci_update_irq(s); - } -} - -static void sdhci_set_readonly(DeviceState *dev, bool level) -{ - SDHCIState *s = (SDHCIState *)dev; - - if (level) { - s->prnsts &= ~SDHC_WRITE_PROTECT; - } else { - /* Write enabled */ - s->prnsts |= SDHC_WRITE_PROTECT; - } -} - -static void sdhci_reset(SDHCIState *s) -{ - DeviceState *dev = DEVICE(s); - - timer_del(s->insert_timer); - timer_del(s->transfer_timer); - /* Set all registers to 0. Capabilities registers are not cleared - * and assumed to always preserve their value, given to them during - * initialization */ - memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad); - - /* Reset other state based on current card insertion/readonly status */ - sdhci_set_inserted(dev, sdbus_get_inserted(&s->sdbus)); - sdhci_set_readonly(dev, sdbus_get_readonly(&s->sdbus)); - - s->data_count = 0; - s->stopped_state = sdhc_not_stopped; - s->pending_insert_state = false; -} - -static void sdhci_poweron_reset(DeviceState *dev) -{ - /* QOM (ie power-on) reset. This is identical to reset - * commanded via device register apart from handling of the - * 'pending insert on powerup' quirk. - */ - SDHCIState *s = (SDHCIState *)dev; - - sdhci_reset(s); - - if (s->pending_insert_quirk) { - s->pending_insert_state = true; - } -} - -static void sdhci_data_transfer(void *opaque); - -static void sdhci_send_command(SDHCIState *s) -{ - SDRequest request; - uint8_t response[16]; - int rlen; - - s->errintsts = 0; - s->acmd12errsts = 0; - request.cmd = s->cmdreg >> 8; - request.arg = s->argument; - DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg); - rlen = sdbus_do_command(&s->sdbus, &request, response); - - if (s->cmdreg & SDHC_CMD_RESPONSE) { - if (rlen == 4) { - s->rspreg[0] = (response[0] << 24) | (response[1] << 16) | - (response[2] << 8) | response[3]; - s->rspreg[1] = s->rspreg[2] = s->rspreg[3] = 0; - DPRINT_L1("Response: RSPREG[31..0]=0x%08x\n", s->rspreg[0]); - } else if (rlen == 16) { - s->rspreg[0] = (response[11] << 24) | (response[12] << 16) | - (response[13] << 8) | response[14]; - s->rspreg[1] = (response[7] << 24) | (response[8] << 16) | - (response[9] << 8) | response[10]; - s->rspreg[2] = (response[3] << 24) | (response[4] << 16) | - (response[5] << 8) | response[6]; - s->rspreg[3] = (response[0] << 16) | (response[1] << 8) | - response[2]; - DPRINT_L1("Response received:\n RSPREG[127..96]=0x%08x, RSPREG[95.." - "64]=0x%08x,\n RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x\n", - s->rspreg[3], s->rspreg[2], s->rspreg[1], s->rspreg[0]); - } else { - ERRPRINT("Timeout waiting for command response\n"); - if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) { - s->errintsts |= SDHC_EIS_CMDTIMEOUT; - s->norintsts |= SDHC_NIS_ERR; - } - } - - if ((s->norintstsen & SDHC_NISEN_TRSCMP) && - (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) { - s->norintsts |= SDHC_NIS_TRSCMP; - } - } - - if (s->norintstsen & SDHC_NISEN_CMDCMP) { - s->norintsts |= SDHC_NIS_CMDCMP; - } - - sdhci_update_irq(s); - - if (s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { - s->data_count = 0; - sdhci_data_transfer(s); - } -} - -static void sdhci_end_transfer(SDHCIState *s) -{ - /* Automatically send CMD12 to stop transfer if AutoCMD12 enabled */ - if ((s->trnmod & SDHC_TRNS_ACMD12) != 0) { - SDRequest request; - uint8_t response[16]; - - request.cmd = 0x0C; - request.arg = 0; - DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg); - sdbus_do_command(&s->sdbus, &request, response); - /* Auto CMD12 response goes to the upper Response register */ - s->rspreg[3] = (response[0] << 24) | (response[1] << 16) | - (response[2] << 8) | response[3]; - } - - s->prnsts &= ~(SDHC_DOING_READ | SDHC_DOING_WRITE | - SDHC_DAT_LINE_ACTIVE | SDHC_DATA_INHIBIT | - SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE); - - if (s->norintstsen & SDHC_NISEN_TRSCMP) { - s->norintsts |= SDHC_NIS_TRSCMP; - } - - sdhci_update_irq(s); -} - -/* - * Programmed i/o data transfer - */ - -/* Fill host controller's read buffer with BLKSIZE bytes of data from card */ -static void sdhci_read_block_from_card(SDHCIState *s) -{ - int index = 0; - - if ((s->trnmod & SDHC_TRNS_MULTI) && - (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) { - return; - } - - for (index = 0; index < (s->blksize & 0x0fff); index++) { - s->fifo_buffer[index] = sdbus_read_data(&s->sdbus); - } - - /* New data now available for READ through Buffer Port Register */ - s->prnsts |= SDHC_DATA_AVAILABLE; - if (s->norintstsen & SDHC_NISEN_RBUFRDY) { - s->norintsts |= SDHC_NIS_RBUFRDY; - } - - /* Clear DAT line active status if that was the last block */ - if ((s->trnmod & SDHC_TRNS_MULTI) == 0 || - ((s->trnmod & SDHC_TRNS_MULTI) && s->blkcnt == 1)) { - s->prnsts &= ~SDHC_DAT_LINE_ACTIVE; - } - - /* If stop at block gap request was set and it's not the last block of - * data - generate Block Event interrupt */ - if (s->stopped_state == sdhc_gap_read && (s->trnmod & SDHC_TRNS_MULTI) && - s->blkcnt != 1) { - s->prnsts &= ~SDHC_DAT_LINE_ACTIVE; - if (s->norintstsen & SDHC_EISEN_BLKGAP) { - s->norintsts |= SDHC_EIS_BLKGAP; - } - } - - sdhci_update_irq(s); -} - -/* Read @size byte of data from host controller @s BUFFER DATA PORT register */ -static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size) -{ - uint32_t value = 0; - int i; - - /* first check that a valid data exists in host controller input buffer */ - if ((s->prnsts & SDHC_DATA_AVAILABLE) == 0) { - ERRPRINT("Trying to read from empty buffer\n"); - return 0; - } - - for (i = 0; i < size; i++) { - value |= s->fifo_buffer[s->data_count] << i * 8; - s->data_count++; - /* check if we've read all valid data (blksize bytes) from buffer */ - if ((s->data_count) >= (s->blksize & 0x0fff)) { - DPRINT_L2("All %u bytes of data have been read from input buffer\n", - s->data_count); - s->prnsts &= ~SDHC_DATA_AVAILABLE; /* no more data in a buffer */ - s->data_count = 0; /* next buff read must start at position [0] */ - - if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { - s->blkcnt--; - } - - /* if that was the last block of data */ - if ((s->trnmod & SDHC_TRNS_MULTI) == 0 || - ((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) || - /* stop at gap request */ - (s->stopped_state == sdhc_gap_read && - !(s->prnsts & SDHC_DAT_LINE_ACTIVE))) { - sdhci_end_transfer(s); - } else { /* if there are more data, read next block from card */ - sdhci_read_block_from_card(s); - } - break; - } - } - - return value; -} - -/* Write data from host controller FIFO to card */ -static void sdhci_write_block_to_card(SDHCIState *s) -{ - int index = 0; - - if (s->prnsts & SDHC_SPACE_AVAILABLE) { - if (s->norintstsen & SDHC_NISEN_WBUFRDY) { - s->norintsts |= SDHC_NIS_WBUFRDY; - } - sdhci_update_irq(s); - return; - } - - if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { - if (s->blkcnt == 0) { - return; - } else { - s->blkcnt--; - } - } - - for (index = 0; index < (s->blksize & 0x0fff); index++) { - sdbus_write_data(&s->sdbus, s->fifo_buffer[index]); - } - - /* Next data can be written through BUFFER DATORT register */ - s->prnsts |= SDHC_SPACE_AVAILABLE; - - /* Finish transfer if that was the last block of data */ - if ((s->trnmod & SDHC_TRNS_MULTI) == 0 || - ((s->trnmod & SDHC_TRNS_MULTI) && - (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0))) { - sdhci_end_transfer(s); - } else if (s->norintstsen & SDHC_NISEN_WBUFRDY) { - s->norintsts |= SDHC_NIS_WBUFRDY; - } - - /* Generate Block Gap Event if requested and if not the last block */ - if (s->stopped_state == sdhc_gap_write && (s->trnmod & SDHC_TRNS_MULTI) && - s->blkcnt > 0) { - s->prnsts &= ~SDHC_DOING_WRITE; - if (s->norintstsen & SDHC_EISEN_BLKGAP) { - s->norintsts |= SDHC_EIS_BLKGAP; - } - sdhci_end_transfer(s); - } - - sdhci_update_irq(s); -} - -/* Write @size bytes of @value data to host controller @s Buffer Data Port - * register */ -static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size) -{ - unsigned i; - - /* Check that there is free space left in a buffer */ - if (!(s->prnsts & SDHC_SPACE_AVAILABLE)) { - ERRPRINT("Can't write to data buffer: buffer full\n"); - return; - } - - for (i = 0; i < size; i++) { - s->fifo_buffer[s->data_count] = value & 0xFF; - s->data_count++; - value >>= 8; - if (s->data_count >= (s->blksize & 0x0fff)) { - DPRINT_L2("write buffer filled with %u bytes of data\n", - s->data_count); - s->data_count = 0; - s->prnsts &= ~SDHC_SPACE_AVAILABLE; - if (s->prnsts & SDHC_DOING_WRITE) { - sdhci_write_block_to_card(s); - } - } - } -} - -/* - * Single DMA data transfer - */ - -/* Multi block SDMA transfer */ -static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) -{ - bool page_aligned = false; - unsigned int n, begin; - const uint16_t block_size = s->blksize & 0x0fff; - uint32_t boundary_chk = 1 << (((s->blksize & 0xf000) >> 12) + 12); - uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk); - - /* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for - * possible stop at page boundary if initial address is not page aligned, - * allow them to work properly */ - if ((s->sdmasysad % boundary_chk) == 0) { - page_aligned = true; - } - - if (s->trnmod & SDHC_TRNS_READ) { - s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT | - SDHC_DAT_LINE_ACTIVE; - while (s->blkcnt) { - if (s->data_count == 0) { - for (n = 0; n < block_size; n++) { - s->fifo_buffer[n] = sdbus_read_data(&s->sdbus); - } - } - begin = s->data_count; - if (((boundary_count + begin) < block_size) && page_aligned) { - s->data_count = boundary_count + begin; - boundary_count = 0; - } else { - s->data_count = block_size; - boundary_count -= block_size - begin; - if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { - s->blkcnt--; - } - } - dma_memory_write(&address_space_memory, s->sdmasysad, - &s->fifo_buffer[begin], s->data_count - begin); - s->sdmasysad += s->data_count - begin; - if (s->data_count == block_size) { - s->data_count = 0; - } - if (page_aligned && boundary_count == 0) { - break; - } - } - } else { - s->prnsts |= SDHC_DOING_WRITE | SDHC_DATA_INHIBIT | - SDHC_DAT_LINE_ACTIVE; - while (s->blkcnt) { - begin = s->data_count; - if (((boundary_count + begin) < block_size) && page_aligned) { - s->data_count = boundary_count + begin; - boundary_count = 0; - } else { - s->data_count = block_size; - boundary_count -= block_size - begin; - } - dma_memory_read(&address_space_memory, s->sdmasysad, - &s->fifo_buffer[begin], s->data_count); - s->sdmasysad += s->data_count - begin; - if (s->data_count == block_size) { - for (n = 0; n < block_size; n++) { - sdbus_write_data(&s->sdbus, s->fifo_buffer[n]); - } - s->data_count = 0; - if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { - s->blkcnt--; - } - } - if (page_aligned && boundary_count == 0) { - break; - } - } - } - - if (s->blkcnt == 0) { - sdhci_end_transfer(s); - } else { - if (s->norintstsen & SDHC_NISEN_DMA) { - s->norintsts |= SDHC_NIS_DMA; - } - sdhci_update_irq(s); - } -} - -/* single block SDMA transfer */ - -static void sdhci_sdma_transfer_single_block(SDHCIState *s) -{ - int n; - uint32_t datacnt = s->blksize & 0x0fff; - - if (s->trnmod & SDHC_TRNS_READ) { - for (n = 0; n < datacnt; n++) { - s->fifo_buffer[n] = sdbus_read_data(&s->sdbus); - } - dma_memory_write(&address_space_memory, s->sdmasysad, s->fifo_buffer, - datacnt); - } else { - dma_memory_read(&address_space_memory, s->sdmasysad, s->fifo_buffer, - datacnt); - for (n = 0; n < datacnt; n++) { - sdbus_write_data(&s->sdbus, s->fifo_buffer[n]); - } - } - - if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { - s->blkcnt--; - } - - sdhci_end_transfer(s); -} - -typedef struct ADMADescr { - hwaddr addr; - uint16_t length; - uint8_t attr; - uint8_t incr; -} ADMADescr; - -static void get_adma_description(SDHCIState *s, ADMADescr *dscr) -{ - uint32_t adma1 = 0; - uint64_t adma2 = 0; - hwaddr entry_addr = (hwaddr)s->admasysaddr; - switch (SDHC_DMA_TYPE(s->hostctl)) { - case SDHC_CTRL_ADMA2_32: - dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma2, - sizeof(adma2)); - adma2 = le64_to_cpu(adma2); - /* The spec does not specify endianness of descriptor table. - * We currently assume that it is LE. - */ - dscr->addr = (hwaddr)extract64(adma2, 32, 32) & ~0x3ull; - dscr->length = (uint16_t)extract64(adma2, 16, 16); - dscr->attr = (uint8_t)extract64(adma2, 0, 7); - dscr->incr = 8; - break; - case SDHC_CTRL_ADMA1_32: - dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma1, - sizeof(adma1)); - adma1 = le32_to_cpu(adma1); - dscr->addr = (hwaddr)(adma1 & 0xFFFFF000); - dscr->attr = (uint8_t)extract32(adma1, 0, 7); - dscr->incr = 4; - if ((dscr->attr & SDHC_ADMA_ATTR_ACT_MASK) == SDHC_ADMA_ATTR_SET_LEN) { - dscr->length = (uint16_t)extract32(adma1, 12, 16); - } else { - dscr->length = 4096; - } - break; - case SDHC_CTRL_ADMA2_64: - dma_memory_read(&address_space_memory, entry_addr, - (uint8_t *)(&dscr->attr), 1); - dma_memory_read(&address_space_memory, entry_addr + 2, - (uint8_t *)(&dscr->length), 2); - dscr->length = le16_to_cpu(dscr->length); - dma_memory_read(&address_space_memory, entry_addr + 4, - (uint8_t *)(&dscr->addr), 8); - dscr->attr = le64_to_cpu(dscr->attr); - dscr->attr &= 0xfffffff8; - dscr->incr = 12; - break; - } -} - -/* Advanced DMA data transfer */ - -static void sdhci_do_adma(SDHCIState *s) -{ - unsigned int n, begin, length; - const uint16_t block_size = s->blksize & 0x0fff; - ADMADescr dscr; - int i; - - for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) { - s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH; - - get_adma_description(s, &dscr); - DPRINT_L2("ADMA loop: addr=" TARGET_FMT_plx ", len=%d, attr=%x\n", - dscr.addr, dscr.length, dscr.attr); - - if ((dscr.attr & SDHC_ADMA_ATTR_VALID) == 0) { - /* Indicate that error occurred in ST_FDS state */ - s->admaerr &= ~SDHC_ADMAERR_STATE_MASK; - s->admaerr |= SDHC_ADMAERR_STATE_ST_FDS; - - /* Generate ADMA error interrupt */ - if (s->errintstsen & SDHC_EISEN_ADMAERR) { - s->errintsts |= SDHC_EIS_ADMAERR; - s->norintsts |= SDHC_NIS_ERR; - } - - sdhci_update_irq(s); - return; - } - - length = dscr.length ? dscr.length : 65536; - - switch (dscr.attr & SDHC_ADMA_ATTR_ACT_MASK) { - case SDHC_ADMA_ATTR_ACT_TRAN: /* data transfer */ - - if (s->trnmod & SDHC_TRNS_READ) { - while (length) { - if (s->data_count == 0) { - for (n = 0; n < block_size; n++) { - s->fifo_buffer[n] = sdbus_read_data(&s->sdbus); - } - } - begin = s->data_count; - if ((length + begin) < block_size) { - s->data_count = length + begin; - length = 0; - } else { - s->data_count = block_size; - length -= block_size - begin; - } - dma_memory_write(&address_space_memory, dscr.addr, - &s->fifo_buffer[begin], - s->data_count - begin); - dscr.addr += s->data_count - begin; - if (s->data_count == block_size) { - s->data_count = 0; - if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { - s->blkcnt--; - if (s->blkcnt == 0) { - break; - } - } - } - } - } else { - while (length) { - begin = s->data_count; - if ((length + begin) < block_size) { - s->data_count = length + begin; - length = 0; - } else { - s->data_count = block_size; - length -= block_size - begin; - } - dma_memory_read(&address_space_memory, dscr.addr, - &s->fifo_buffer[begin], - s->data_count - begin); - dscr.addr += s->data_count - begin; - if (s->data_count == block_size) { - for (n = 0; n < block_size; n++) { - sdbus_write_data(&s->sdbus, s->fifo_buffer[n]); - } - s->data_count = 0; - if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { - s->blkcnt--; - if (s->blkcnt == 0) { - break; - } - } - } - } - } - s->admasysaddr += dscr.incr; - break; - case SDHC_ADMA_ATTR_ACT_LINK: /* link to next descriptor table */ - s->admasysaddr = dscr.addr; - DPRINT_L1("ADMA link: admasysaddr=0x%" PRIx64 "\n", - s->admasysaddr); - break; - default: - s->admasysaddr += dscr.incr; - break; - } - - if (dscr.attr & SDHC_ADMA_ATTR_INT) { - DPRINT_L1("ADMA interrupt: admasysaddr=0x%" PRIx64 "\n", - s->admasysaddr); - if (s->norintstsen & SDHC_NISEN_DMA) { - s->norintsts |= SDHC_NIS_DMA; - } - - sdhci_update_irq(s); - } - - /* ADMA transfer terminates if blkcnt == 0 or by END attribute */ - if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && - (s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) { - DPRINT_L2("ADMA transfer completed\n"); - if (length || ((dscr.attr & SDHC_ADMA_ATTR_END) && - (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && - s->blkcnt != 0)) { - ERRPRINT("SD/MMC host ADMA length mismatch\n"); - s->admaerr |= SDHC_ADMAERR_LENGTH_MISMATCH | - SDHC_ADMAERR_STATE_ST_TFR; - if (s->errintstsen & SDHC_EISEN_ADMAERR) { - ERRPRINT("Set ADMA error flag\n"); - s->errintsts |= SDHC_EIS_ADMAERR; - s->norintsts |= SDHC_NIS_ERR; - } - - sdhci_update_irq(s); - } - sdhci_end_transfer(s); - return; - } - - } - - /* we have unfinished business - reschedule to continue ADMA */ - timer_mod(s->transfer_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_TRANSFER_DELAY); -} - -/* Perform data transfer according to controller configuration */ - -static void sdhci_data_transfer(void *opaque) -{ - SDHCIState *s = (SDHCIState *)opaque; - - if (s->trnmod & SDHC_TRNS_DMA) { - switch (SDHC_DMA_TYPE(s->hostctl)) { - case SDHC_CTRL_SDMA: - if ((s->trnmod & SDHC_TRNS_MULTI) && - (!(s->trnmod & SDHC_TRNS_BLK_CNT_EN) || s->blkcnt == 0)) { - break; - } - - if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) { - sdhci_sdma_transfer_single_block(s); - } else { - sdhci_sdma_transfer_multi_blocks(s); - } - - break; - case SDHC_CTRL_ADMA1_32: - if (!(s->capareg & SDHC_CAN_DO_ADMA1)) { - ERRPRINT("ADMA1 not supported\n"); - break; - } - - sdhci_do_adma(s); - break; - case SDHC_CTRL_ADMA2_32: - if (!(s->capareg & SDHC_CAN_DO_ADMA2)) { - ERRPRINT("ADMA2 not supported\n"); - break; - } - - sdhci_do_adma(s); - break; - case SDHC_CTRL_ADMA2_64: - if (!(s->capareg & SDHC_CAN_DO_ADMA2) || - !(s->capareg & SDHC_64_BIT_BUS_SUPPORT)) { - ERRPRINT("64 bit ADMA not supported\n"); - break; - } - - sdhci_do_adma(s); - break; - default: - ERRPRINT("Unsupported DMA type\n"); - break; - } - } else { - if ((s->trnmod & SDHC_TRNS_READ) && sdbus_data_ready(&s->sdbus)) { - s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT | - SDHC_DAT_LINE_ACTIVE; - sdhci_read_block_from_card(s); - } else { - s->prnsts |= SDHC_DOING_WRITE | SDHC_DAT_LINE_ACTIVE | - SDHC_SPACE_AVAILABLE | SDHC_DATA_INHIBIT; - sdhci_write_block_to_card(s); - } - } -} - -static bool sdhci_can_issue_command(SDHCIState *s) -{ - if (!SDHC_CLOCK_IS_ON(s->clkcon) || - (((s->prnsts & SDHC_DATA_INHIBIT) || s->stopped_state) && - ((s->cmdreg & SDHC_CMD_DATA_PRESENT) || - ((s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY && - !(SDHC_COMMAND_TYPE(s->cmdreg) == SDHC_CMD_ABORT))))) { - return false; - } - - return true; -} - -/* The Buffer Data Port register must be accessed in sequential and - * continuous manner */ -static inline bool -sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num) -{ - if ((s->data_count & 0x3) != byte_num) { - ERRPRINT("Non-sequential access to Buffer Data Port register" - "is prohibited\n"); - return false; - } - return true; -} - -static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size) -{ - SDHCIState *s = (SDHCIState *)opaque; - uint32_t ret = 0; - - switch (offset & ~0x3) { - case SDHC_SYSAD: - ret = s->sdmasysad; - break; - case SDHC_BLKSIZE: - ret = s->blksize | (s->blkcnt << 16); - break; - case SDHC_ARGUMENT: - ret = s->argument; - break; - case SDHC_TRNMOD: - ret = s->trnmod | (s->cmdreg << 16); - break; - case SDHC_RSPREG0 ... SDHC_RSPREG3: - ret = s->rspreg[((offset & ~0x3) - SDHC_RSPREG0) >> 2]; - break; - case SDHC_BDATA: - if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) { - ret = sdhci_read_dataport(s, size); - DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset, - ret, ret); - return ret; - } - break; - case SDHC_PRNSTS: - ret = s->prnsts; - break; - case SDHC_HOSTCTL: - ret = s->hostctl | (s->pwrcon << 8) | (s->blkgap << 16) | - (s->wakcon << 24); - break; - case SDHC_CLKCON: - ret = s->clkcon | (s->timeoutcon << 16); - break; - case SDHC_NORINTSTS: - ret = s->norintsts | (s->errintsts << 16); - break; - case SDHC_NORINTSTSEN: - ret = s->norintstsen | (s->errintstsen << 16); - break; - case SDHC_NORINTSIGEN: - ret = s->norintsigen | (s->errintsigen << 16); - break; - case SDHC_ACMD12ERRSTS: - ret = s->acmd12errsts; - break; - case SDHC_CAPAREG: - ret = s->capareg; - break; - case SDHC_MAXCURR: - ret = s->maxcurr; - break; - case SDHC_ADMAERR: - ret = s->admaerr; - break; - case SDHC_ADMASYSADDR: - ret = (uint32_t)s->admasysaddr; - break; - case SDHC_ADMASYSADDR + 4: - ret = (uint32_t)(s->admasysaddr >> 32); - break; - case SDHC_SLOT_INT_STATUS: - ret = (SD_HOST_SPECv2_VERS << 16) | sdhci_slotint(s); - break; - default: - ERRPRINT("bad %ub read: addr[0x%04x]\n", size, (int)offset); - break; - } - - ret >>= (offset & 0x3) * 8; - ret &= (1ULL << (size * 8)) - 1; - DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset, ret, ret); - return ret; -} - -static inline void sdhci_blkgap_write(SDHCIState *s, uint8_t value) -{ - if ((value & SDHC_STOP_AT_GAP_REQ) && (s->blkgap & SDHC_STOP_AT_GAP_REQ)) { - return; - } - s->blkgap = value & SDHC_STOP_AT_GAP_REQ; - - if ((value & SDHC_CONTINUE_REQ) && s->stopped_state && - (s->blkgap & SDHC_STOP_AT_GAP_REQ) == 0) { - if (s->stopped_state == sdhc_gap_read) { - s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_READ; - sdhci_read_block_from_card(s); - } else { - s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_WRITE; - sdhci_write_block_to_card(s); - } - s->stopped_state = sdhc_not_stopped; - } else if (!s->stopped_state && (value & SDHC_STOP_AT_GAP_REQ)) { - if (s->prnsts & SDHC_DOING_READ) { - s->stopped_state = sdhc_gap_read; - } else if (s->prnsts & SDHC_DOING_WRITE) { - s->stopped_state = sdhc_gap_write; - } - } -} - -static inline void sdhci_reset_write(SDHCIState *s, uint8_t value) -{ - switch (value) { - case SDHC_RESET_ALL: - sdhci_reset(s); - break; - case SDHC_RESET_CMD: - s->prnsts &= ~SDHC_CMD_INHIBIT; - s->norintsts &= ~SDHC_NIS_CMDCMP; - break; - case SDHC_RESET_DATA: - s->data_count = 0; - s->prnsts &= ~(SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE | - SDHC_DOING_READ | SDHC_DOING_WRITE | - SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE); - s->blkgap &= ~(SDHC_STOP_AT_GAP_REQ | SDHC_CONTINUE_REQ); - s->stopped_state = sdhc_not_stopped; - s->norintsts &= ~(SDHC_NIS_WBUFRDY | SDHC_NIS_RBUFRDY | - SDHC_NIS_DMA | SDHC_NIS_TRSCMP | SDHC_NIS_BLKGAP); - break; - } -} - -static void -sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) -{ - SDHCIState *s = (SDHCIState *)opaque; - unsigned shift = 8 * (offset & 0x3); - uint32_t mask = ~(((1ULL << (size * 8)) - 1) << shift); - uint32_t value = val; - value <<= shift; - - switch (offset & ~0x3) { - case SDHC_SYSAD: - s->sdmasysad = (s->sdmasysad & mask) | value; - MASKED_WRITE(s->sdmasysad, mask, value); - /* Writing to last byte of sdmasysad might trigger transfer */ - if (!(mask & 0xFF000000) && TRANSFERRING_DATA(s->prnsts) && s->blkcnt && - s->blksize && SDHC_DMA_TYPE(s->hostctl) == SDHC_CTRL_SDMA) { - sdhci_sdma_transfer_multi_blocks(s); - } - break; - case SDHC_BLKSIZE: - if (!TRANSFERRING_DATA(s->prnsts)) { - MASKED_WRITE(s->blksize, mask, value); - MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); - } - - /* Limit block size to the maximum buffer size */ - if (extract32(s->blksize, 0, 12) > s->buf_maxsz) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Size 0x%x is larger than " \ - "the maximum buffer 0x%x", __func__, s->blksize, - s->buf_maxsz); - - s->blksize = deposit32(s->blksize, 0, 12, s->buf_maxsz); - } - - break; - case SDHC_ARGUMENT: - MASKED_WRITE(s->argument, mask, value); - break; - case SDHC_TRNMOD: - /* DMA can be enabled only if it is supported as indicated by - * capabilities register */ - if (!(s->capareg & SDHC_CAN_DO_DMA)) { - value &= ~SDHC_TRNS_DMA; - } - MASKED_WRITE(s->trnmod, mask, value); - MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16); - - /* Writing to the upper byte of CMDREG triggers SD command generation */ - if ((mask & 0xFF000000) || !sdhci_can_issue_command(s)) { - break; - } - - sdhci_send_command(s); - break; - case SDHC_BDATA: - if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) { - sdhci_write_dataport(s, value >> shift, size); - } - break; - case SDHC_HOSTCTL: - if (!(mask & 0xFF0000)) { - sdhci_blkgap_write(s, value >> 16); - } - MASKED_WRITE(s->hostctl, mask, value); - MASKED_WRITE(s->pwrcon, mask >> 8, value >> 8); - MASKED_WRITE(s->wakcon, mask >> 24, value >> 24); - if (!(s->prnsts & SDHC_CARD_PRESENT) || ((s->pwrcon >> 1) & 0x7) < 5 || - !(s->capareg & (1 << (31 - ((s->pwrcon >> 1) & 0x7))))) { - s->pwrcon &= ~SDHC_POWER_ON; - } - break; - case SDHC_CLKCON: - if (!(mask & 0xFF000000)) { - sdhci_reset_write(s, value >> 24); - } - MASKED_WRITE(s->clkcon, mask, value); - MASKED_WRITE(s->timeoutcon, mask >> 16, value >> 16); - if (s->clkcon & SDHC_CLOCK_INT_EN) { - s->clkcon |= SDHC_CLOCK_INT_STABLE; - } else { - s->clkcon &= ~SDHC_CLOCK_INT_STABLE; - } - break; - case SDHC_NORINTSTS: - if (s->norintstsen & SDHC_NISEN_CARDINT) { - value &= ~SDHC_NIS_CARDINT; - } - s->norintsts &= mask | ~value; - s->errintsts &= (mask >> 16) | ~(value >> 16); - if (s->errintsts) { - s->norintsts |= SDHC_NIS_ERR; - } else { - s->norintsts &= ~SDHC_NIS_ERR; - } - sdhci_update_irq(s); - break; - case SDHC_NORINTSTSEN: - MASKED_WRITE(s->norintstsen, mask, value); - MASKED_WRITE(s->errintstsen, mask >> 16, value >> 16); - s->norintsts &= s->norintstsen; - s->errintsts &= s->errintstsen; - if (s->errintsts) { - s->norintsts |= SDHC_NIS_ERR; - } else { - s->norintsts &= ~SDHC_NIS_ERR; - } - /* Quirk for Raspberry Pi: pending card insert interrupt - * appears when first enabled after power on */ - if ((s->norintstsen & SDHC_NISEN_INSERT) && s->pending_insert_state) { - assert(s->pending_insert_quirk); - s->norintsts |= SDHC_NIS_INSERT; - s->pending_insert_state = false; - } - sdhci_update_irq(s); - break; - case SDHC_NORINTSIGEN: - MASKED_WRITE(s->norintsigen, mask, value); - MASKED_WRITE(s->errintsigen, mask >> 16, value >> 16); - sdhci_update_irq(s); - break; - case SDHC_ADMAERR: - MASKED_WRITE(s->admaerr, mask, value); - break; - case SDHC_ADMASYSADDR: - s->admasysaddr = (s->admasysaddr & (0xFFFFFFFF00000000ULL | - (uint64_t)mask)) | (uint64_t)value; - break; - case SDHC_ADMASYSADDR + 4: - s->admasysaddr = (s->admasysaddr & (0x00000000FFFFFFFFULL | - ((uint64_t)mask << 32))) | ((uint64_t)value << 32); - break; - case SDHC_FEAER: - s->acmd12errsts |= value; - s->errintsts |= (value >> 16) & s->errintstsen; - if (s->acmd12errsts) { - s->errintsts |= SDHC_EIS_CMD12ERR; - } - if (s->errintsts) { - s->norintsts |= SDHC_NIS_ERR; - } - sdhci_update_irq(s); - break; - default: - ERRPRINT("bad %ub write offset: addr[0x%04x] <- %u(0x%x)\n", - size, (int)offset, value >> shift, value >> shift); - break; - } - DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n", - size, (int)offset, value >> shift, value >> shift); -} - -static const MemoryRegionOps sdhci_mmio_ops = { - .read = sdhci_read, - .write = sdhci_write, - .valid = { - .min_access_size = 1, - .max_access_size = 4, - .unaligned = false - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static inline unsigned int sdhci_get_fifolen(SDHCIState *s) -{ - switch (SDHC_CAPAB_BLOCKSIZE(s->capareg)) { - case 0: - return 512; - case 1: - return 1024; - case 2: - return 2048; - default: - hw_error("SDHC: unsupported value for maximum block size\n"); - return 0; - } -} - -static void sdhci_initfn(SDHCIState *s) -{ - qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), - TYPE_SDHCI_BUS, DEVICE(s), "sd-bus"); - - s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s); - s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s); -} - -static void sdhci_uninitfn(SDHCIState *s) -{ - timer_del(s->insert_timer); - timer_free(s->insert_timer); - timer_del(s->transfer_timer); - timer_free(s->transfer_timer); - qemu_free_irq(s->eject_cb); - qemu_free_irq(s->ro_cb); - - g_free(s->fifo_buffer); - s->fifo_buffer = NULL; -} - -static bool sdhci_pending_insert_vmstate_needed(void *opaque) -{ - SDHCIState *s = opaque; - - return s->pending_insert_state; -} - -static const VMStateDescription sdhci_pending_insert_vmstate = { - .name = "sdhci/pending-insert", - .version_id = 1, - .minimum_version_id = 1, - .needed = sdhci_pending_insert_vmstate_needed, - .fields = (VMStateField[]) { - VMSTATE_BOOL(pending_insert_state, SDHCIState), - VMSTATE_END_OF_LIST() - }, -}; - -const VMStateDescription sdhci_vmstate = { - .name = "sdhci", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(sdmasysad, SDHCIState), - VMSTATE_UINT16(blksize, SDHCIState), - VMSTATE_UINT16(blkcnt, SDHCIState), - VMSTATE_UINT32(argument, SDHCIState), - VMSTATE_UINT16(trnmod, SDHCIState), - VMSTATE_UINT16(cmdreg, SDHCIState), - VMSTATE_UINT32_ARRAY(rspreg, SDHCIState, 4), - VMSTATE_UINT32(prnsts, SDHCIState), - VMSTATE_UINT8(hostctl, SDHCIState), - VMSTATE_UINT8(pwrcon, SDHCIState), - VMSTATE_UINT8(blkgap, SDHCIState), - VMSTATE_UINT8(wakcon, SDHCIState), - VMSTATE_UINT16(clkcon, SDHCIState), - VMSTATE_UINT8(timeoutcon, SDHCIState), - VMSTATE_UINT8(admaerr, SDHCIState), - VMSTATE_UINT16(norintsts, SDHCIState), - VMSTATE_UINT16(errintsts, SDHCIState), - VMSTATE_UINT16(norintstsen, SDHCIState), - VMSTATE_UINT16(errintstsen, SDHCIState), - VMSTATE_UINT16(norintsigen, SDHCIState), - VMSTATE_UINT16(errintsigen, SDHCIState), - VMSTATE_UINT16(acmd12errsts, SDHCIState), - VMSTATE_UINT16(data_count, SDHCIState), - VMSTATE_UINT64(admasysaddr, SDHCIState), - VMSTATE_UINT8(stopped_state, SDHCIState), - VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, 0, buf_maxsz), - VMSTATE_TIMER_PTR(insert_timer, SDHCIState), - VMSTATE_TIMER_PTR(transfer_timer, SDHCIState), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &sdhci_pending_insert_vmstate, - NULL - }, -}; - -/* Capabilities registers provide information on supported features of this - * specific host controller implementation */ -static Property sdhci_pci_properties[] = { - DEFINE_PROP_UINT32("capareg", SDHCIState, capareg, - SDHC_CAPAB_REG_DEFAULT), - DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void sdhci_pci_realize(PCIDevice *dev, Error **errp) -{ - SDHCIState *s = PCI_SDHCI(dev); - dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */ - dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ - sdhci_initfn(s); - s->buf_maxsz = sdhci_get_fifolen(s); - s->fifo_buffer = g_malloc0(s->buf_maxsz); - s->irq = pci_allocate_irq(dev); - memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", - SDHC_REGISTERS_MAP_SIZE); - pci_register_bar(dev, 0, 0, &s->iomem); -} - -static void sdhci_pci_exit(PCIDevice *dev) -{ - SDHCIState *s = PCI_SDHCI(dev); - sdhci_uninitfn(s); -} - -static void sdhci_pci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->realize = sdhci_pci_realize; - k->exit = sdhci_pci_exit; - k->vendor_id = PCI_VENDOR_ID_REDHAT; - k->device_id = PCI_DEVICE_ID_REDHAT_SDHCI; - k->class_id = PCI_CLASS_SYSTEM_SDHCI; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->vmsd = &sdhci_vmstate; - dc->props = sdhci_pci_properties; - dc->reset = sdhci_poweron_reset; -} - -static const TypeInfo sdhci_pci_info = { - .name = TYPE_PCI_SDHCI, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(SDHCIState), - .class_init = sdhci_pci_class_init, -}; - -static Property sdhci_sysbus_properties[] = { - DEFINE_PROP_UINT32("capareg", SDHCIState, capareg, - SDHC_CAPAB_REG_DEFAULT), - DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0), - DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk, - false), - DEFINE_PROP_END_OF_LIST(), -}; - -static void sdhci_sysbus_init(Object *obj) -{ - SDHCIState *s = SYSBUS_SDHCI(obj); - - sdhci_initfn(s); -} - -static void sdhci_sysbus_finalize(Object *obj) -{ - SDHCIState *s = SYSBUS_SDHCI(obj); - sdhci_uninitfn(s); -} - -static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) -{ - SDHCIState *s = SYSBUS_SDHCI(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - s->buf_maxsz = sdhci_get_fifolen(s); - s->fifo_buffer = g_malloc0(s->buf_maxsz); - sysbus_init_irq(sbd, &s->irq); - memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", - SDHC_REGISTERS_MAP_SIZE); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void sdhci_sysbus_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &sdhci_vmstate; - dc->props = sdhci_sysbus_properties; - dc->realize = sdhci_sysbus_realize; - dc->reset = sdhci_poweron_reset; -} - -static const TypeInfo sdhci_sysbus_info = { - .name = TYPE_SYSBUS_SDHCI, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SDHCIState), - .instance_init = sdhci_sysbus_init, - .instance_finalize = sdhci_sysbus_finalize, - .class_init = sdhci_sysbus_class_init, -}; - -static void sdhci_bus_class_init(ObjectClass *klass, void *data) -{ - SDBusClass *sbc = SD_BUS_CLASS(klass); - - sbc->set_inserted = sdhci_set_inserted; - sbc->set_readonly = sdhci_set_readonly; -} - -static const TypeInfo sdhci_bus_info = { - .name = TYPE_SDHCI_BUS, - .parent = TYPE_SD_BUS, - .instance_size = sizeof(SDBus), - .class_init = sdhci_bus_class_init, -}; - -static void sdhci_register_types(void) -{ - type_register_static(&sdhci_pci_info); - type_register_static(&sdhci_sysbus_info); - type_register_static(&sdhci_bus_info); -} - -type_init(sdhci_register_types) diff --git a/qemu/hw/sd/ssi-sd.c b/qemu/hw/sd/ssi-sd.c deleted file mode 100644 index 075e4ed5d..000000000 --- a/qemu/hw/sd/ssi-sd.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * SSI to SD card adapter. - * - * Copyright (c) 2007-2009 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "hw/ssi/ssi.h" -#include "hw/sd/sd.h" - -//#define DEBUG_SSI_SD 1 - -#ifdef DEBUG_SSI_SD -#define DPRINTF(fmt, ...) \ -do { printf("ssi_sd: " fmt , ## __VA_ARGS__); } while (0) -#define BADF(fmt, ...) \ -do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#define BADF(fmt, ...) \ -do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0) -#endif - -typedef enum { - SSI_SD_CMD, - SSI_SD_CMDARG, - SSI_SD_RESPONSE, - SSI_SD_DATA_START, - SSI_SD_DATA_READ, -} ssi_sd_mode; - -typedef struct { - SSISlave ssidev; - ssi_sd_mode mode; - int cmd; - uint8_t cmdarg[4]; - uint8_t response[5]; - int arglen; - int response_pos; - int stopping; - SDState *sd; -} ssi_sd_state; - -/* State word bits. */ -#define SSI_SDR_LOCKED 0x0001 -#define SSI_SDR_WP_ERASE 0x0002 -#define SSI_SDR_ERROR 0x0004 -#define SSI_SDR_CC_ERROR 0x0008 -#define SSI_SDR_ECC_FAILED 0x0010 -#define SSI_SDR_WP_VIOLATION 0x0020 -#define SSI_SDR_ERASE_PARAM 0x0040 -#define SSI_SDR_OUT_OF_RANGE 0x0080 -#define SSI_SDR_IDLE 0x0100 -#define SSI_SDR_ERASE_RESET 0x0200 -#define SSI_SDR_ILLEGAL_COMMAND 0x0400 -#define SSI_SDR_COM_CRC_ERROR 0x0800 -#define SSI_SDR_ERASE_SEQ_ERROR 0x1000 -#define SSI_SDR_ADDRESS_ERROR 0x2000 -#define SSI_SDR_PARAMETER_ERROR 0x4000 - -static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val) -{ - ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev); - - /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data. */ - if (s->mode == SSI_SD_DATA_READ && val == 0x4d) { - s->mode = SSI_SD_CMD; - /* There must be at least one byte delay before the card responds. */ - s->stopping = 1; - } - - switch (s->mode) { - case SSI_SD_CMD: - if (val == 0xff) { - DPRINTF("NULL command\n"); - return 0xff; - } - s->cmd = val & 0x3f; - s->mode = SSI_SD_CMDARG; - s->arglen = 0; - return 0xff; - case SSI_SD_CMDARG: - if (s->arglen == 4) { - SDRequest request; - uint8_t longresp[16]; - /* FIXME: Check CRC. */ - request.cmd = s->cmd; - request.arg = (s->cmdarg[0] << 24) | (s->cmdarg[1] << 16) - | (s->cmdarg[2] << 8) | s->cmdarg[3]; - DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg); - s->arglen = sd_do_command(s->sd, &request, longresp); - if (s->arglen <= 0) { - s->arglen = 1; - s->response[0] = 4; - DPRINTF("SD command failed\n"); - } else if (s->cmd == 58) { - /* CMD58 returns R3 response (OCR) */ - DPRINTF("Returned OCR\n"); - s->arglen = 5; - s->response[0] = 1; - memcpy(&s->response[1], longresp, 4); - } else if (s->arglen != 4) { - BADF("Unexpected response to cmd %d\n", s->cmd); - /* Illegal command is about as near as we can get. */ - s->arglen = 1; - s->response[0] = 4; - } else { - /* All other commands return status. */ - uint32_t cardstatus; - uint16_t status; - /* CMD13 returns a 2-byte statuse work. Other commands - only return the first byte. */ - s->arglen = (s->cmd == 13) ? 2 : 1; - cardstatus = (longresp[0] << 24) | (longresp[1] << 16) - | (longresp[2] << 8) | longresp[3]; - status = 0; - if (((cardstatus >> 9) & 0xf) < 4) - status |= SSI_SDR_IDLE; - if (cardstatus & ERASE_RESET) - status |= SSI_SDR_ERASE_RESET; - if (cardstatus & ILLEGAL_COMMAND) - status |= SSI_SDR_ILLEGAL_COMMAND; - if (cardstatus & COM_CRC_ERROR) - status |= SSI_SDR_COM_CRC_ERROR; - if (cardstatus & ERASE_SEQ_ERROR) - status |= SSI_SDR_ERASE_SEQ_ERROR; - if (cardstatus & ADDRESS_ERROR) - status |= SSI_SDR_ADDRESS_ERROR; - if (cardstatus & CARD_IS_LOCKED) - status |= SSI_SDR_LOCKED; - if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP)) - status |= SSI_SDR_WP_ERASE; - if (cardstatus & SD_ERROR) - status |= SSI_SDR_ERROR; - if (cardstatus & CC_ERROR) - status |= SSI_SDR_CC_ERROR; - if (cardstatus & CARD_ECC_FAILED) - status |= SSI_SDR_ECC_FAILED; - if (cardstatus & WP_VIOLATION) - status |= SSI_SDR_WP_VIOLATION; - if (cardstatus & ERASE_PARAM) - status |= SSI_SDR_ERASE_PARAM; - if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE)) - status |= SSI_SDR_OUT_OF_RANGE; - /* ??? Don't know what Parameter Error really means, so - assume it's set if the second byte is nonzero. */ - if (status & 0xff) - status |= SSI_SDR_PARAMETER_ERROR; - s->response[0] = status >> 8; - s->response[1] = status; - DPRINTF("Card status 0x%02x\n", status); - } - s->mode = SSI_SD_RESPONSE; - s->response_pos = 0; - } else { - s->cmdarg[s->arglen++] = val; - } - return 0xff; - case SSI_SD_RESPONSE: - if (s->stopping) { - s->stopping = 0; - return 0xff; - } - if (s->response_pos < s->arglen) { - DPRINTF("Response 0x%02x\n", s->response[s->response_pos]); - return s->response[s->response_pos++]; - } - if (sd_data_ready(s->sd)) { - DPRINTF("Data read\n"); - s->mode = SSI_SD_DATA_START; - } else { - DPRINTF("End of command\n"); - s->mode = SSI_SD_CMD; - } - return 0xff; - case SSI_SD_DATA_START: - DPRINTF("Start read block\n"); - s->mode = SSI_SD_DATA_READ; - return 0xfe; - case SSI_SD_DATA_READ: - val = sd_read_data(s->sd); - if (!sd_data_ready(s->sd)) { - DPRINTF("Data read end\n"); - s->mode = SSI_SD_CMD; - } - return val; - } - /* Should never happen. */ - return 0xff; -} - -static void ssi_sd_save(QEMUFile *f, void *opaque) -{ - SSISlave *ss = SSI_SLAVE(opaque); - ssi_sd_state *s = (ssi_sd_state *)opaque; - int i; - - qemu_put_be32(f, s->mode); - qemu_put_be32(f, s->cmd); - for (i = 0; i < 4; i++) - qemu_put_be32(f, s->cmdarg[i]); - for (i = 0; i < 5; i++) - qemu_put_be32(f, s->response[i]); - qemu_put_be32(f, s->arglen); - qemu_put_be32(f, s->response_pos); - qemu_put_be32(f, s->stopping); - - qemu_put_be32(f, ss->cs); -} - -static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) -{ - SSISlave *ss = SSI_SLAVE(opaque); - ssi_sd_state *s = (ssi_sd_state *)opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - s->mode = qemu_get_be32(f); - s->cmd = qemu_get_be32(f); - for (i = 0; i < 4; i++) - s->cmdarg[i] = qemu_get_be32(f); - for (i = 0; i < 5; i++) - s->response[i] = qemu_get_be32(f); - s->arglen = qemu_get_be32(f); - if (s->mode == SSI_SD_CMDARG && - (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) { - return -EINVAL; - } - s->response_pos = qemu_get_be32(f); - s->stopping = qemu_get_be32(f); - if (s->mode == SSI_SD_RESPONSE && - (s->response_pos < 0 || s->response_pos >= ARRAY_SIZE(s->response) || - (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) { - return -EINVAL; - } - - ss->cs = qemu_get_be32(f); - - return 0; -} - -static int ssi_sd_init(SSISlave *d) -{ - DeviceState *dev = DEVICE(d); - ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); - DriveInfo *dinfo; - - s->mode = SSI_SD_CMD; - /* FIXME use a qdev drive property instead of drive_get_next() */ - dinfo = drive_get_next(IF_SD); - s->sd = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, true); - if (s->sd == NULL) { - return -1; - } - register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); - return 0; -} - -static void ssi_sd_class_init(ObjectClass *klass, void *data) -{ - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = ssi_sd_init; - k->transfer = ssi_sd_transfer; - k->cs_polarity = SSI_CS_LOW; -} - -static const TypeInfo ssi_sd_info = { - .name = "ssi-sd", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(ssi_sd_state), - .class_init = ssi_sd_class_init, -}; - -static void ssi_sd_register_types(void) -{ - type_register_static(&ssi_sd_info); -} - -type_init(ssi_sd_register_types) |