From nobody Wed Oct 29 09:14:48 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1513028389595385.3867885751197; Mon, 11 Dec 2017 13:39:49 -0800 (PST) Received: from localhost ([::1]:55583 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eOVnf-0002Jj-V8 for importer@patchew.org; Mon, 11 Dec 2017 16:39:48 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35976) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eOVfJ-0000vi-JJ for qemu-devel@nongnu.org; Mon, 11 Dec 2017 16:31:13 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eOVfH-0004iH-MB for qemu-devel@nongnu.org; Mon, 11 Dec 2017 16:31:09 -0500 Received: from mail-pf0-x242.google.com ([2607:f8b0:400e:c00::242]:39141) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eOVfC-0004TW-VD; Mon, 11 Dec 2017 16:31:03 -0500 Received: by mail-pf0-x242.google.com with SMTP id l24so12535943pfj.6; Mon, 11 Dec 2017 13:31:02 -0800 (PST) Received: from squirtle.westlake.spaceflightindustries.com ([173.226.206.194]) by smtp.gmail.com with ESMTPSA id q10sm25359690pgc.84.2017.12.11.13.31.00 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 11 Dec 2017 13:31:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=kLkEoorDfNDUCXayBKQU01knduM+Q6nN0fHQ3lLZQbc=; b=Ul/Qi4fDv7uAtq2KqL6STDWXHZqQPZ4SQ9GP5bwucOSJ/fDT5xpwq21Si6zpWMgcI2 gKmNfYb79Q4sCf8O2RL5LiJtkZwJa1DoER6wPZukw+sZ3eDt8eOrSDzzvFcx/CA04xhV YsxEuaL33YSlvjNZoSMHOQXidb1fu31nCTR+CtJsJ3At2y/nVd1iQcr0MzGu3m/g2zSi 8Z/eahHD1qGbo7OzTp++LsMcz0untVtdn+Qii3VfgFNyXOharHyRIQz411SEtHyvZe9p 5PC+zBsJKN2gelOVO8n+6LsW19i9CGKWv/ERfT+xzvbwTf8zbA+D7dlUr/jJD0Hua/qw KgVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=kLkEoorDfNDUCXayBKQU01knduM+Q6nN0fHQ3lLZQbc=; b=eTTv3S5s32q0IqWrLyPMgJQQTBleOMKQpjtQAmThKq8rY/rvtKMqwU9locMbuksacF A3YzQpiDClFeCyOt1m26R6swUou5py9L2CN0xh3wyEsZeo03Z1YvUuO9rBfMUOku/4B1 gN0wiDlH5DTvBR2LEUEfFn9rxx/NOZPh+6/Iin8xajz6KyS7yLf5NkKqvRXTmp7Kw5BX Rtoh9BvDuG5T3UNU5yjsgF4jlUIu//Fth4einX5tIRe4aUtuURSErqQGdsf9A53E6vt+ PzK88PDHBklJoYOz+EI15QuQDUr2L6qIZ8llkfFRxyJa9XxDg0nWVAKwv0TkFA5++jSG xhzQ== X-Gm-Message-State: AKGB3mJ8W/9vAIiOwMBjI/DFh3wYqzAOERTbRNHE7gYCoSRjgVAiIyeh Rb1QIFVgHKF7VIK2tvP3tlSl+3hq X-Google-Smtp-Source: ACJfBoseJcP9/tVnBz1o6cdLqMCRFXLWja6FAbRtf1aCRnpkpBFzA7Cw0RNQNjlXSzLD1jWx4+ZUBQ== X-Received: by 10.159.250.148 with SMTP id k20mr1625072pls.149.1513027861667; Mon, 11 Dec 2017 13:31:01 -0800 (PST) From: Andrey Smirnov To: qemu-arm@nongnu.org Date: Mon, 11 Dec 2017 13:30:06 -0800 Message-Id: <20171211213007.7353-13-andrew.smirnov@gmail.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20171211213007.7353-1-andrew.smirnov@gmail.com> References: <20171211213007.7353-1-andrew.smirnov@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c00::242 Subject: [Qemu-devel] [PATCH 12/13] sdhci: Add i.MX specific subtype of SDHCI X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Andrey Smirnov , Jason Wang , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-devel@nongnu.org, yurovsky@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 IP block found on several generations of i.MX family does not use vanilla SDHCI implementation and it comes with a number of quirks. Introduce i.MX SDHCI subtype of SDHCI block to add code necessary to support unmodified Linux guest driver. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daud=C3=A9 Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Signed-off-by: Andrey Smirnov Reviewed-by: Peter Maydell --- hw/sd/sdhci-internal.h | 19 +++++ hw/sd/sdhci.c | 228 +++++++++++++++++++++++++++++++++++++++++++++= +++- include/hw/sd/sdhci.h | 8 ++ 3 files changed, 253 insertions(+), 2 deletions(-) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index 161177cf39..b86ac0791b 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -85,12 +85,18 @@ =20 /* R/W Host control Register 0x0 */ #define SDHC_HOSTCTL 0x28 +#define SDHC_CTRL_LED 0x01 #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) +#define SDHC_CTRL_4BITBUS 0x02 +#define SDHC_CTRL_8BITBUS 0x20 +#define SDHC_CTRL_CDTEST_INS 0x40 +#define SDHC_CTRL_CDTEST_EN 0x80 + =20 /* R/W Power Control Register 0x0 */ #define SDHC_PWRCON 0x29 @@ -229,4 +235,17 @@ enum { =20 extern const VMStateDescription sdhci_vmstate; =20 + +#define ESDHC_MIX_CTRL 0x48 +#define ESDHC_VENDOR_SPEC 0xc0 +#define ESDHC_DLL_CTRL 0x60 + +#define ESDHC_TUNING_CTRL 0xcc +#define ESDHC_TUNE_CTRL_STATUS 0x68 +#define ESDHC_WTMK_LVL 0x44 + +#define ESDHC_CTRL_4BITBUS (0x1 << 1) +#define ESDHC_CTRL_8BITBUS (0x2 << 1) + + #endif diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 6d6a791ee9..758af067f9 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -265,7 +265,8 @@ static void sdhci_send_command(SDHCIState *s) } } =20 - if ((s->norintstsen & SDHC_NISEN_TRSCMP) && + if (!(s->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && + (s->norintstsen & SDHC_NISEN_TRSCMP) && (s->cmdreg & SDHC_CMD_RESPONSE) =3D=3D SDHC_CMD_RSP_WITH_BUSY)= { s->norintsts |=3D SDHC_NIS_TRSCMP; } @@ -1191,6 +1192,8 @@ static void sdhci_initfn(SDHCIState *s) =20 s->insert_timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_inser= tion_irq, s); s->transfer_timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_tran= sfer, s); + + s->io_ops =3D &sdhci_mmio_ops; } =20 static void sdhci_uninitfn(SDHCIState *s) @@ -1347,7 +1350,7 @@ static void sdhci_sysbus_realize(DeviceState *dev, Er= ror ** errp) s->buf_maxsz =3D sdhci_get_fifolen(s); s->fifo_buffer =3D g_malloc0(s->buf_maxsz); sysbus_init_irq(sbd, &s->irq); - memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci= ", + memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci", SDHC_REGISTERS_MAP_SIZE); sysbus_init_mmio(sbd, &s->iomem); } @@ -1386,11 +1389,232 @@ static const TypeInfo sdhci_bus_info =3D { .class_init =3D sdhci_bus_class_init, }; =20 +static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size) +{ + SDHCIState *s =3D SYSBUS_SDHCI(opaque); + uint32_t ret; + uint16_t hostctl; + + switch (offset) { + default: + return sdhci_read(opaque, offset, size); + + case SDHC_HOSTCTL: + /* + * For a detailed explanation on the following bit + * manipulation code see comments in a similar part of + * usdhc_write() + */ + hostctl =3D SDHC_DMA_TYPE(s->hostctl) << (8 - 3); + + if (s->hostctl & SDHC_CTRL_8BITBUS) { + hostctl |=3D ESDHC_CTRL_8BITBUS; + } + + if (s->hostctl & SDHC_CTRL_4BITBUS) { + hostctl |=3D ESDHC_CTRL_4BITBUS; + } + + ret =3D hostctl; + ret |=3D (uint32_t)s->blkgap << 16; + ret |=3D (uint32_t)s->wakcon << 24; + + break; + + case ESDHC_DLL_CTRL: + case ESDHC_TUNE_CTRL_STATUS: + case 0x6c: + case ESDHC_TUNING_CTRL: + case ESDHC_VENDOR_SPEC: + case ESDHC_MIX_CTRL: + case ESDHC_WTMK_LVL: + ret =3D 0; + break; + } + + return ret; +} + +static void +usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) +{ + SDHCIState *s =3D SYSBUS_SDHCI(opaque); + uint8_t hostctl; + uint32_t value =3D (uint32_t)val; + + switch (offset) { + case ESDHC_DLL_CTRL: + case ESDHC_TUNE_CTRL_STATUS: + case 0x6c: + case ESDHC_TUNING_CTRL: + case ESDHC_WTMK_LVL: + case ESDHC_VENDOR_SPEC: + break; + + case SDHC_HOSTCTL: + /* + * Here's What ESDHCI has at offset 0x28 (SDHC_HOSTCTL) + * + * 7 6 5 4 3 2 1 0 + * |-----------+--------+--------+-----------+----------+---------| + * | Card | Card | Endian | DATA3 | Data | Led | + * | Detect | Detect | Mode | as Card | Transfer | Control | + * | Signal | Test | | Detection | Width | | + * | Selection | Level | | Pin | | | + * |-----------+--------+--------+-----------+----------+---------| + * + * and 0x29 + * + * 15 10 9 8 + * |----------+------| + * | Reserved | DMA | + * | | Sel. | + * | | | + * |----------+------| + * + * and here's what SDCHI spec expects those offsets to be: + * + * 0x28 (Host Control Register) + * + * 7 6 5 4 3 2 1 0 + * |--------+--------+----------+------+--------+----------+------= ---| + * | Card | Card | Extended | DMA | High | Data | LED = | + * | Detect | Detect | Data | Sel. | Speed | Transfer | Contr= ol | + * | Signal | Test | Transfer | | Enable | Width | = | + * | Sel. | Level | Width | | | | = | + * |--------+--------+----------+------+--------+----------+------= ---| + * + * and 0x29 (Power Control Register) + * + * |----------------------------------| + * | Power Control Register | + * | | + * | Description omitted, | + * | since it has no analog in ESDHCI | + * | | + * |----------------------------------| + * + * Since offsets 0x2A and 0x2B should be compatible between + * both IP specs we only need to reconcile least 16-bit of the + * word we've been given. + */ + + /* + * First, save bits 7 6 and 0 since they are identical + */ + hostctl =3D value & (SDHC_CTRL_LED | + SDHC_CTRL_CDTEST_INS | + SDHC_CTRL_CDTEST_EN); + /* + * Second, split "Data Transfer Width" from bits 2 and 1 in to + * bits 5 and 1 + */ + if (value & ESDHC_CTRL_8BITBUS) { + hostctl |=3D SDHC_CTRL_8BITBUS; + } + + if (value & ESDHC_CTRL_4BITBUS) { + hostctl |=3D ESDHC_CTRL_4BITBUS; + } + + /* + * Third, move DMA select from bits 9 and 8 to bits 4 and 3 + */ + hostctl |=3D SDHC_DMA_TYPE(value >> (8 - 3)); + + /* + * Now place the corrected value into low 16-bit of the value + * we are going to give standard SDHCI write function + * + * NOTE: This transformation should be the inverse of what can + * be found in drivers/mmc/host/sdhci-esdhc-imx.c in Linux + * kernel + */ + value &=3D ~UINT16_MAX; + value |=3D hostctl; + value |=3D (uint16_t)s->pwrcon << 8; + + sdhci_write(opaque, offset, value, size); + break; + + case ESDHC_MIX_CTRL: + /* + * So, when SD/MMC stack in Linux tries to write to "Transfer + * Mode Register", ESDHC i.MX quirk code will translate it + * into a write to ESDHC_MIX_CTRL, so we do the opposite in + * order to get where we started + * + * Note that Auto CMD23 Enable bit is located in a wrong place + * on i.MX, but since it is not used by QEMU we do not care. + * + * We don't want to call sdhci_write(.., SDHC_TRNMOD, ...) + * here becuase it will result in a call to + * sdhci_send_command(s) which we don't want. + * + */ + s->trnmod =3D value & UINT16_MAX; + break; + case SDHC_TRNMOD: + /* + * Similar to above, but this time a write to "Command + * Register" will be translated into a 4-byte write to + * "Transfer Mode register" where lower 16-bit of value would + * be set to zero. So what we do is fill those bits with + * cached value from s->trnmod and let the SDHCI + * infrastructure handle the rest + */ + sdhci_write(opaque, offset, val | s->trnmod, size); + break; + case SDHC_BLKSIZE: + /* + * ESDHCI does not implement "Host SDMA Buffer Boundary", and + * Linux driver will try to zero this field out which will + * break the rest of SDHCI emulation. + * + * Linux defaults to maximum possible setting (512K boundary) + * and it seems to be the only option that i.MX IP implements, + * so we artificially set it to that value. + */ + val |=3D 0x7 << 12; + /* FALLTHROUGH */ + default: + sdhci_write(opaque, offset, val, size); + break; + } +} + + +static const MemoryRegionOps usdhc_mmio_ops =3D { + .read =3D usdhc_read, + .write =3D usdhc_write, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + .unaligned =3D false + }, + .endianness =3D DEVICE_LITTLE_ENDIAN, +}; + +static void imx_usdhc_init(Object *obj) +{ + SDHCIState *s =3D SYSBUS_SDHCI(obj); + + s->io_ops =3D &usdhc_mmio_ops; + s->quirks =3D SDHCI_QUIRK_NO_BUSY_IRQ; +} + +static const TypeInfo imx_usdhc_info =3D { + .name =3D TYPE_IMX_USDHC, + .parent =3D TYPE_SYSBUS_SDHCI, + .instance_init =3D imx_usdhc_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_register_static(&imx_usdhc_info); } =20 type_init(sdhci_register_types) diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index 0f0c3f1e64..dc1856a33d 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -39,6 +39,7 @@ typedef struct SDHCIState { }; SDBus sdbus; MemoryRegion iomem; + const MemoryRegionOps *io_ops; =20 QEMUTimer *insert_timer; /* timer for 'changing' sd card. */ QEMUTimer *transfer_timer; @@ -83,8 +84,13 @@ typedef struct SDHCIState { /* Force Event Auto CMD12 Error Interrupt Reg - write only */ /* Force Event Error Interrupt Register- write only */ /* RO Host Controller Version Register always reads as 0x2401 */ + + unsigned long quirks; } SDHCIState; =20 +/* Controller does not provide transfer-complete interrupt when not busy */ +#define SDHCI_QUIRK_NO_BUSY_IRQ BIT(14) + #define TYPE_PCI_SDHCI "sdhci-pci" #define PCI_SDHCI(obj) OBJECT_CHECK(SDHCIState, (obj), TYPE_PCI_SDHCI) =20 @@ -92,4 +98,6 @@ typedef struct SDHCIState { #define SYSBUS_SDHCI(obj) \ OBJECT_CHECK(SDHCIState, (obj), TYPE_SYSBUS_SDHCI) =20 +#define TYPE_IMX_USDHC "imx-usdhc" + #endif /* SDHCI_H */ --=20 2.14.3