summaryrefslogtreecommitdiffstats
path: root/qemu/hw/sd
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/hw/sd')
-rw-r--r--qemu/hw/sd/Makefile.objs8
-rw-r--r--qemu/hw/sd/core.c146
-rw-r--r--qemu/hw/sd/milkymist-memcard.c317
-rw-r--r--qemu/hw/sd/omap_mmc.c647
-rw-r--r--qemu/hw/sd/pl181.c528
-rw-r--r--qemu/hw/sd/pxa2xx_mmci.c598
-rw-r--r--qemu/hw/sd/sd.c1979
-rw-r--r--qemu/hw/sd/sdhci-internal.h232
-rw-r--r--qemu/hw/sd/sdhci.c1394
-rw-r--r--qemu/hw/sd/ssi-sd.c290
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, &sect);
- } 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)