From patchwork Mon Oct 14 16:03:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 176298 Delivered-To: patch@linaro.org Received: by 2002:a92:7e96:0:0:0:0:0 with SMTP id q22csp4742694ill; Mon, 14 Oct 2019 09:38:48 -0700 (PDT) X-Google-Smtp-Source: APXvYqyk8oIJOcC4Y8pDYO/LTcNalTCU8qC5Ej8ecOvuo0FRjtt2maLpkQj4ljWQUGPy2jHHUYRs X-Received: by 2002:a05:620a:a04:: with SMTP id i4mr14909944qka.432.1571071128684; Mon, 14 Oct 2019 09:38:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571071128; cv=none; d=google.com; s=arc-20160816; b=JksLJLwC5BSWdwSDH5hw06hUkbRdlSNBgwEOGLxwdbyG/iw6QGb/AISdTRQ4Cn8K+/ VDLu64spjyovuBiznwwXY2jkftCjSRlWstLuMW47wISyaUw4p51G/RKS4BHZe86novTu ONEOSRImGlpadMol1r7ZdtBL15A2Qlixu275STEjDSqENxjliqKveAk4ieTiyOM5LqXF pNz5DFKMCYY2Hh/yGQSIx+u2SQHjVLUejmd/uoOAOhY/jWj31IDM49GTacj4nV0EZojt CjiPetJ2xfNWeXdyKRoTgsrwo7aBZUM5R+EKxUNTZz36Ie+oqTQDJbuvBsFjoaK9BLkp Vrcw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:to:from :dkim-signature; bh=Gbj/1vupet4wMXabBgwl0Oz2l4ch353ql/J//P2oXMo=; b=lAL6bPemqgDoLvZZcmfPYspBCLP0WNM8JwzjZjXnxFo4cV1nIN+gIXVFBZFgZf8Wy4 ZvjYE1NAuRE223Sm/5Xm17vrnq0PRrPHM6tpvi59O1DNd6II47iOv6mwBeFo9G2z25sc RCdj+9/8Hu5tMaQNXYlhER54R70BiZVNGdazN55hiutW/2BjYvYQwr5sJIZWPfQhX8WK mT+aAw2vLwGROXIBw5jnrAtxAIS0BtHfgruZDXDSBXjyjJw+l4Quogwqlc+kueeksXnV OGpRjxDACy44X89IhEDBumTR/iyaF0VFIwf5KP/3Dbi1ic8A5NPXOQWgmxCS3mVw1c9G fn4A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=hcdrDkSH; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id 48si18091019qvu.138.2019.10.14.09.38.48 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 14 Oct 2019 09:38:48 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=hcdrDkSH; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:53468 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK3Mu-0005v4-1r for patch@linaro.org; Mon, 14 Oct 2019 12:38:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:37242) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK2qV-0004ot-Cq for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:05:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK2qT-0007x6-7g for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:05:19 -0400 Received: from mail-wm1-x335.google.com ([2a00:1450:4864:20::335]:56006) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK2qT-0007w2-04 for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:05:17 -0400 Received: by mail-wm1-x335.google.com with SMTP id a6so17834570wma.5 for ; Mon, 14 Oct 2019 09:05:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=Gbj/1vupet4wMXabBgwl0Oz2l4ch353ql/J//P2oXMo=; b=hcdrDkSHEXLli4QyRDgqi+ZVv20MRnI9VBs2aF710nv7lVdL3U3xj98o0qxAnq5KKu WsmHFBkfPxEQpkNwtVcMetsoObNdUuJV068hpLq8iM2snhk/NnGrNfMeIghsGgRhdYg+ ZEEPeo6aLQCZVyRKMpuqgEvKyYKBQoKTxStwuPJU8U+ZzhNTtSb1wnap1SvzZ1h7Niz0 UkMh0eX9Ec8YRgihXMDby0sYtI0lp6LCts3OVqvXWkEOrhdeEAoxrkYtxCCmLshhlOJ3 zVEvqNAEKa3jsu1gOnQAQfhKUHXmSVVpoV537+9N4zH1uwKbxiT8LbhEIyYzxhOR9+k6 FERg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Gbj/1vupet4wMXabBgwl0Oz2l4ch353ql/J//P2oXMo=; b=E26xmt7pTqHUQ+ETAJ6jNDkUlwhtr8EPRVJ4y8XdXQtNrH+JUlodhfmxcUo7/NRqp5 9ghdeLen03ZfKEiSa0WiorkK+4uzMvsZvgNjmjkVhf21f5gZYOZD+nRpNUR3osg3Tjvd q1JOEpl9eHLAGkQDqiH7USu0qNvM/xAiGrdGiCk1HrRtln/BTJp3RXfvEA3O6hakka/g MFuEYImP8QENrF5Hjb+a5xLBRX9mks8TVXN1MytpmiK5e/JIfxwGuEN1sOlLqNw6xEQT ehprRqHl9JXQJI7HkcxYDmsdbWMVHocAFFJ3PQuEWlGiKpDB6Um1IqMKMbhquhWQ5FV9 evQw== X-Gm-Message-State: APjAAAVHBPjpNE3ZoZgOEM1c9+IXc02h5bjrKkEIewseotZqt7k/U7R1 xbyNrE7JGVQqGewh2CogJHL33aB3PRM4AQ== X-Received: by 2002:a1c:f00a:: with SMTP id a10mr16479939wmb.89.1571069115326; Mon, 14 Oct 2019 09:05:15 -0700 (PDT) Received: from orth.archaic.org.uk (orth.archaic.org.uk. [81.2.115.148]) by smtp.gmail.com with ESMTPSA id 5sm18029779wrk.86.2019.10.14.09.05.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Oct 2019 09:05:14 -0700 (PDT) From: Peter Maydell To: qemu-devel@nongnu.org Subject: [PULL 41/68] hw/sd/aspeed_sdhci: New device Date: Mon, 14 Oct 2019 17:03:37 +0100 Message-Id: <20191014160404.19553-42-peter.maydell@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191014160404.19553-1-peter.maydell@linaro.org> References: <20191014160404.19553-1-peter.maydell@linaro.org> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::335 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" From: Eddie James The Aspeed SOCs have two SD/MMC controllers. Add a device that encapsulates both of these controllers and models the Aspeed-specific registers and behavior. Tested by reading from mmcblk0 in Linux: qemu-system-arm -machine romulus-bmc -nographic \ -drive file=flash-romulus,format=raw,if=mtd \ -device sd-card,drive=sd0 -drive file=_tmp/kernel,format=raw,if=sd,id=sd0 Signed-off-by: Eddie James Reviewed-by: Cédric Le Goater Reviewed-by: Joel Stanley Signed-off-by: Cédric Le Goater Message-id: 20190925143248.10000-3-clg@kaod.org [clg: - changed the controller MMIO window size to 0x1000 - moved the MMIO mapping of the SDHCI slots at the SoC level - merged code to add SD drives on the SD buses at the machine level ] Signed-off-by: Cédric Le Goater Signed-off-by: Peter Maydell --- hw/sd/Makefile.objs | 1 + include/hw/arm/aspeed_soc.h | 3 + include/hw/sd/aspeed_sdhci.h | 34 ++++++ hw/arm/aspeed.c | 15 ++- hw/arm/aspeed_soc.c | 23 ++++ hw/sd/aspeed_sdhci.c | 198 +++++++++++++++++++++++++++++++++++ 6 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 include/hw/sd/aspeed_sdhci.h create mode 100644 hw/sd/aspeed_sdhci.c -- 2.20.1 diff --git a/hw/sd/Makefile.objs b/hw/sd/Makefile.objs index 06657279d18..a884c238dfb 100644 --- a/hw/sd/Makefile.objs +++ b/hw/sd/Makefile.objs @@ -8,3 +8,4 @@ obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o obj-$(CONFIG_OMAP) += omap_mmc.o obj-$(CONFIG_PXA2XX) += pxa2xx_mmci.o obj-$(CONFIG_RASPI) += bcm2835_sdhost.o +obj-$(CONFIG_ASPEED_SOC) += aspeed_sdhci.o diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index ab5052b12cb..ba5bbb53e1a 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -24,6 +24,7 @@ #include "hw/net/ftgmac100.h" #include "target/arm/cpu.h" #include "hw/gpio/aspeed_gpio.h" +#include "hw/sd/aspeed_sdhci.h" #define ASPEED_SPIS_NUM 2 #define ASPEED_WDTS_NUM 3 @@ -50,6 +51,7 @@ typedef struct AspeedSoCState { AspeedWDTState wdt[ASPEED_WDTS_NUM]; FTGMAC100State ftgmac100[ASPEED_MACS_NUM]; AspeedGPIOState gpio; + AspeedSDHCIState sdhci; } AspeedSoCState; #define TYPE_ASPEED_SOC "aspeed-soc" @@ -93,6 +95,7 @@ enum { ASPEED_SCU, ASPEED_ADC, ASPEED_SRAM, + ASPEED_SDHCI, ASPEED_GPIO, ASPEED_RTC, ASPEED_TIMER1, diff --git a/include/hw/sd/aspeed_sdhci.h b/include/hw/sd/aspeed_sdhci.h new file mode 100644 index 00000000000..dfdab437902 --- /dev/null +++ b/include/hw/sd/aspeed_sdhci.h @@ -0,0 +1,34 @@ +/* + * Aspeed SD Host Controller + * Eddie James + * + * Copyright (C) 2019 IBM Corp + * SPDX-License-Identifer: GPL-2.0-or-later + */ + +#ifndef ASPEED_SDHCI_H +#define ASPEED_SDHCI_H + +#include "hw/sd/sdhci.h" + +#define TYPE_ASPEED_SDHCI "aspeed.sdhci" +#define ASPEED_SDHCI(obj) OBJECT_CHECK(AspeedSDHCIState, (obj), \ + TYPE_ASPEED_SDHCI) + +#define ASPEED_SDHCI_CAPABILITIES 0x01E80080 +#define ASPEED_SDHCI_NUM_SLOTS 2 +#define ASPEED_SDHCI_NUM_REGS (ASPEED_SDHCI_REG_SIZE / sizeof(uint32_t)) +#define ASPEED_SDHCI_REG_SIZE 0x100 + +typedef struct AspeedSDHCIState { + SysBusDevice parent; + + SDHCIState slots[ASPEED_SDHCI_NUM_SLOTS]; + + MemoryRegion iomem; + qemu_irq irq; + + uint32_t regs[ASPEED_SDHCI_NUM_REGS]; +} AspeedSDHCIState; + +#endif /* ASPEED_SDHCI_H */ diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index aa72be309da..30e28048426 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -170,6 +170,7 @@ static void aspeed_board_init(MachineState *machine, AspeedSoCClass *sc; DriveInfo *drive0 = drive_get(IF_MTD, 0, 0); ram_addr_t max_ram_size; + int i; bmc = g_new0(AspeedBoardState, 1); @@ -252,6 +253,19 @@ static void aspeed_board_init(MachineState *machine, cfg->i2c_init(bmc); } + for (i = 0; i < ARRAY_SIZE(bmc->soc.sdhci.slots); i++) { + SDHCIState *sdhci = &bmc->soc.sdhci.slots[i]; + DriveInfo *dinfo = drive_get_next(IF_SD); + BlockBackend *blk; + DeviceState *card; + + blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; + card = qdev_create(qdev_get_child_bus(DEVICE(sdhci), "sd-bus"), + TYPE_SD_CARD); + qdev_prop_set_drive(card, "drive", blk, &error_fatal); + object_property_set_bool(OBJECT(card), true, "realized", &error_fatal); + } + arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo); } @@ -373,7 +387,6 @@ static void aspeed_machine_class_init(ObjectClass *oc, void *data) mc->desc = board->desc; mc->init = aspeed_machine_init; mc->max_cpus = ASPEED_CPUS_NUM; - mc->no_sdcard = 1; mc->no_floppy = 1; mc->no_cdrom = 1; mc->no_parallel = 1; diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index cf1d0cf921b..c3821a56273 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -36,6 +36,7 @@ static const hwaddr aspeed_soc_ast2400_memmap[] = { [ASPEED_XDMA] = 0x1E6E7000, [ASPEED_ADC] = 0x1E6E9000, [ASPEED_SRAM] = 0x1E720000, + [ASPEED_SDHCI] = 0x1E740000, [ASPEED_GPIO] = 0x1E780000, [ASPEED_RTC] = 0x1E781000, [ASPEED_TIMER1] = 0x1E782000, @@ -63,6 +64,7 @@ static const hwaddr aspeed_soc_ast2500_memmap[] = { [ASPEED_XDMA] = 0x1E6E7000, [ASPEED_ADC] = 0x1E6E9000, [ASPEED_SRAM] = 0x1E720000, + [ASPEED_SDHCI] = 0x1E740000, [ASPEED_GPIO] = 0x1E780000, [ASPEED_RTC] = 0x1E781000, [ASPEED_TIMER1] = 0x1E782000, @@ -108,6 +110,7 @@ static const int aspeed_soc_ast2400_irqmap[] = { [ASPEED_ETH1] = 2, [ASPEED_ETH2] = 3, [ASPEED_XDMA] = 6, + [ASPEED_SDHCI] = 26, }; #define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap @@ -230,6 +233,15 @@ static void aspeed_soc_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); sysbus_init_child_obj(obj, "gpio", OBJECT(&s->gpio), sizeof(s->gpio), typename); + + sysbus_init_child_obj(obj, "sdc", OBJECT(&s->sdhci), sizeof(s->sdhci), + TYPE_ASPEED_SDHCI); + + /* Init sd card slot class here so that they're under the correct parent */ + for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { + sysbus_init_child_obj(obj, "sdhci[*]", OBJECT(&s->sdhci.slots[i]), + sizeof(s->sdhci.slots[i]), TYPE_SYSBUS_SDHCI); + } } static void aspeed_soc_realize(DeviceState *dev, Error **errp) @@ -419,6 +431,17 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, sc->info->memmap[ASPEED_GPIO]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, aspeed_soc_get_irq(s, ASPEED_GPIO)); + + /* SDHCI */ + object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0, + sc->info->memmap[ASPEED_SDHCI]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, + aspeed_soc_get_irq(s, ASPEED_SDHCI)); } static Property aspeed_soc_properties[] = { DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0), diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c new file mode 100644 index 00000000000..cff3eb7dd21 --- /dev/null +++ b/hw/sd/aspeed_sdhci.c @@ -0,0 +1,198 @@ +/* + * Aspeed SD Host Controller + * Eddie James + * + * Copyright (C) 2019 IBM Corp + * SPDX-License-Identifer: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "hw/sd/aspeed_sdhci.h" +#include "qapi/error.h" +#include "hw/irq.h" +#include "migration/vmstate.h" + +#define ASPEED_SDHCI_INFO 0x00 +#define ASPEED_SDHCI_INFO_RESET 0x00030000 +#define ASPEED_SDHCI_DEBOUNCE 0x04 +#define ASPEED_SDHCI_DEBOUNCE_RESET 0x00000005 +#define ASPEED_SDHCI_BUS 0x08 +#define ASPEED_SDHCI_SDIO_140 0x10 +#define ASPEED_SDHCI_SDIO_148 0x18 +#define ASPEED_SDHCI_SDIO_240 0x20 +#define ASPEED_SDHCI_SDIO_248 0x28 +#define ASPEED_SDHCI_WP_POL 0xec +#define ASPEED_SDHCI_CARD_DET 0xf0 +#define ASPEED_SDHCI_IRQ_STAT 0xfc + +#define TO_REG(addr) ((addr) / sizeof(uint32_t)) + +static uint64_t aspeed_sdhci_read(void *opaque, hwaddr addr, unsigned int size) +{ + uint32_t val = 0; + AspeedSDHCIState *sdhci = opaque; + + switch (addr) { + case ASPEED_SDHCI_SDIO_140: + val = (uint32_t)sdhci->slots[0].capareg; + break; + case ASPEED_SDHCI_SDIO_148: + val = (uint32_t)sdhci->slots[0].maxcurr; + break; + case ASPEED_SDHCI_SDIO_240: + val = (uint32_t)sdhci->slots[1].capareg; + break; + case ASPEED_SDHCI_SDIO_248: + val = (uint32_t)sdhci->slots[1].maxcurr; + break; + default: + if (addr < ASPEED_SDHCI_REG_SIZE) { + val = sdhci->regs[TO_REG(addr)]; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds read at 0x%" HWADDR_PRIx "\n", + __func__, addr); + } + } + + return (uint64_t)val; +} + +static void aspeed_sdhci_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) +{ + AspeedSDHCIState *sdhci = opaque; + + switch (addr) { + case ASPEED_SDHCI_SDIO_140: + sdhci->slots[0].capareg = (uint64_t)(uint32_t)val; + break; + case ASPEED_SDHCI_SDIO_148: + sdhci->slots[0].maxcurr = (uint64_t)(uint32_t)val; + break; + case ASPEED_SDHCI_SDIO_240: + sdhci->slots[1].capareg = (uint64_t)(uint32_t)val; + break; + case ASPEED_SDHCI_SDIO_248: + sdhci->slots[1].maxcurr = (uint64_t)(uint32_t)val; + break; + default: + if (addr < ASPEED_SDHCI_REG_SIZE) { + sdhci->regs[TO_REG(addr)] = (uint32_t)val; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds write at 0x%" HWADDR_PRIx "\n", + __func__, addr); + } + } +} + +static const MemoryRegionOps aspeed_sdhci_ops = { + .read = aspeed_sdhci_read, + .write = aspeed_sdhci_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, +}; + +static void aspeed_sdhci_set_irq(void *opaque, int n, int level) +{ + AspeedSDHCIState *sdhci = opaque; + + if (level) { + sdhci->regs[TO_REG(ASPEED_SDHCI_IRQ_STAT)] |= BIT(n); + + qemu_irq_raise(sdhci->irq); + } else { + sdhci->regs[TO_REG(ASPEED_SDHCI_IRQ_STAT)] &= ~BIT(n); + + qemu_irq_lower(sdhci->irq); + } +} + +static void aspeed_sdhci_realize(DeviceState *dev, Error **errp) +{ + Error *err = NULL; + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev); + + /* Create input irqs for the slots */ + qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_sdhci_set_irq, + sdhci, NULL, ASPEED_SDHCI_NUM_SLOTS); + + sysbus_init_irq(sbd, &sdhci->irq); + memory_region_init_io(&sdhci->iomem, OBJECT(sdhci), &aspeed_sdhci_ops, + sdhci, TYPE_ASPEED_SDHCI, 0x1000); + sysbus_init_mmio(sbd, &sdhci->iomem); + + for (int i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) { + Object *sdhci_slot = OBJECT(&sdhci->slots[i]); + SysBusDevice *sbd_slot = SYS_BUS_DEVICE(&sdhci->slots[i]); + + object_property_set_int(sdhci_slot, 2, "sd-spec-version", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_uint(sdhci_slot, ASPEED_SDHCI_CAPABILITIES, + "capareg", &err); + if (err) { + error_propagate(errp, err); + return; + } + + object_property_set_bool(sdhci_slot, true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_connect_irq(sbd_slot, 0, qdev_get_gpio_in(DEVICE(sbd), i)); + memory_region_add_subregion(&sdhci->iomem, (i + 1) * 0x100, + &sdhci->slots[i].iomem); + } +} + +static void aspeed_sdhci_reset(DeviceState *dev) +{ + AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev); + + memset(sdhci->regs, 0, ASPEED_SDHCI_REG_SIZE); + sdhci->regs[TO_REG(ASPEED_SDHCI_INFO)] = ASPEED_SDHCI_INFO_RESET; + sdhci->regs[TO_REG(ASPEED_SDHCI_DEBOUNCE)] = ASPEED_SDHCI_DEBOUNCE_RESET; +} + +static const VMStateDescription vmstate_aspeed_sdhci = { + .name = TYPE_ASPEED_SDHCI, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, AspeedSDHCIState, ASPEED_SDHCI_NUM_REGS), + VMSTATE_END_OF_LIST(), + }, +}; + +static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(classp); + + dc->realize = aspeed_sdhci_realize; + dc->reset = aspeed_sdhci_reset; + dc->vmsd = &vmstate_aspeed_sdhci; +} + +static TypeInfo aspeed_sdhci_info = { + .name = TYPE_ASPEED_SDHCI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AspeedSDHCIState), + .class_init = aspeed_sdhci_class_init, +}; + +static void aspeed_sdhci_register_types(void) +{ + type_register_static(&aspeed_sdhci_info); +} + +type_init(aspeed_sdhci_register_types)