Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/809747/?format=api
{ "id": 809747, "url": "http://patchwork.ozlabs.org/api/1.2/patches/809747/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/1504540582-11521-1-git-send-email-patrice.chotard@st.com/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/1.2/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1504540582-11521-1-git-send-email-patrice.chotard@st.com>", "list_archive_url": null, "date": "2017-09-04T15:56:22", "name": "[U-Boot,v5,1/1] mmc: Add MMC support for stm32h7 Socs", "commit_ref": "b312c590bcd836d2596afcf4f0c16a1bf6b21465", "pull_url": null, "state": "accepted", "archived": false, "hash": "d51320ecce736278dd9cb51141e1ba12467ce99f", "submitter": { "id": 63958, "url": "http://patchwork.ozlabs.org/api/1.2/people/63958/?format=api", "name": "Patrice CHOTARD", "email": "patrice.chotard@st.com" }, "delegate": { "id": 12423, "url": "http://patchwork.ozlabs.org/api/1.2/users/12423/?format=api", "username": "Jaehoon", "first_name": "Jaehoon", "last_name": "Chung", "email": "jh80.chung@samsung.com" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/1504540582-11521-1-git-send-email-patrice.chotard@st.com/mbox/", "series": [ { "id": 1414, "url": "http://patchwork.ozlabs.org/api/1.2/series/1414/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=1414", "date": "2017-09-04T15:56:22", "name": "[U-Boot,v5,1/1] mmc: Add MMC support for stm32h7 Socs", "version": 5, "mbox": "http://patchwork.ozlabs.org/series/1414/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/809747/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/809747/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.denx.de\n\t(client-ip=81.169.180.215; helo=lists.denx.de;\n\tenvelope-from=u-boot-bounces@lists.denx.de;\n\treceiver=<UNKNOWN>)", "Received": [ "from lists.denx.de (dione.denx.de [81.169.180.215])\n\tby ozlabs.org (Postfix) with ESMTP id 3xmDxN5X5Wz9sNq\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 5 Sep 2017 01:56:55 +1000 (AEST)", "by lists.denx.de (Postfix, from userid 105)\n\tid 2F818C21F25; Mon, 4 Sep 2017 15:56:53 +0000 (UTC)", "from lists.denx.de (localhost [IPv6:::1])\n\tby lists.denx.de (Postfix) with ESMTP id 7DBFBC21EB4;\n\tMon, 4 Sep 2017 15:56:47 +0000 (UTC)", "by lists.denx.de (Postfix, from userid 105)\n\tid D3A35C21EB4; Mon, 4 Sep 2017 15:56:45 +0000 (UTC)", "from mx07-00178001.pphosted.com (mx08-00178001.pphosted.com\n\t[91.207.212.93])\n\tby lists.denx.de (Postfix) with ESMTPS id 58DE0C21E52\n\tfor <u-boot@lists.denx.de>; Mon, 4 Sep 2017 15:56:45 +0000 (UTC)", "from pps.filterd (m0046661.ppops.net [127.0.0.1])\n\tby mx08-.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv84FrpCd020571; Mon, 4 Sep 2017 17:56:44 +0200", "from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35])\n\tby mx08-00178001.pphosted.com with ESMTP id 2crp3j50m2-1\n\t(version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT);\n\tMon, 04 Sep 2017 17:56:44 +0200", "from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9])\n\tby beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id EC90534;\n\tMon, 4 Sep 2017 15:56:42 +0000 (GMT)", "from Webmail-eu.st.com (sfhdag6node3.st.com [10.75.127.18])\n\tby zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id B34062D34;\n\tMon, 4 Sep 2017 15:56:42 +0000 (GMT)", "from localhost (10.75.127.50) by SFHDAG6NODE3.st.com (10.75.127.18)\n\twith Microsoft SMTP Server (TLS) id 15.0.1178.4;\n\tMon, 4 Sep 2017 17:56:42 +0200" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=-0.7 required=5.0 tests=RCVD_IN_DNSWL_LOW\n\tautolearn=unavailable autolearn_force=no version=3.4.0", "From": "<patrice.chotard@st.com>", "To": "<u-boot@lists.denx.de>, <sjg@chromium.org>, <jh80.chung@samsung.com>", "Date": "Mon, 4 Sep 2017 17:56:22 +0200", "Message-ID": "<1504540582-11521-1-git-send-email-patrice.chotard@st.com>", "X-Mailer": "git-send-email 1.9.1", "MIME-Version": "1.0", "X-Originating-IP": "[10.75.127.50]", "X-ClientProxiedBy": "SFHDAG1NODE2.st.com (10.75.127.2) To SFHDAG6NODE3.st.com\n\t(10.75.127.18)", "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-09-04_09:, , signatures=0", "Subject": "[U-Boot] [PATCH v5 1/1] mmc: Add MMC support for stm32h7 Socs", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.18", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<http://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=subscribe>", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "base64", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>" }, "content": "From: Patrice Chotard <patrice.chotard@st.com>\n\nThis patch adds SD/MMC support for STM32H7 SoCs.\n\nHere is an extraction of SDMMC main features, embedded in\nSTM32H7 SoCs.\nThe SD/MMC block include the following:\n _ Full compliance with MultiMediaCard System Specification\n Version 4.51. Card support for three different databus modes:\n 1-bit (default), 4-bit and 8-bit.\n _ Full compatibility with previous versions of MultiMediaCards\n (backward compatibility).\n _ Full compliance with SD memory card specifications version 4.1.\n (SDR104 SDMMC_CK speed limited to maximum allowed IO speed,\n SPI mode and UHS-II mode not supported).\n _ Full compliance with SDIO card specification version 4.0.\n Card support for two different databus modes: 1-bit (default)\n and 4-bit. (SDR104 SDMMC_CK speed limited to maximum allowed IO\n speed, SPI mode and UHS-II mode not supported).\n _ Data transfer up to 208 Mbyte/s for the 8 bit mode.\n (depending maximum allowed IO speed).\n _ Data and command output enable signals to control external\n bidirectional drivers.\n\nThe current version of the SDMMC supports only one SD/SDIO/MMC card\nat any one time and a stack of MMC Version 4.51 or previous.\n\nSigned-off-by: Christophe Kerello <christophe.kerello@st.com>\nSigned-off-by: Patrice Chotard <patrice.chotard@st.com>\n---\n\nv5: _ give a more meaningful name to stm32_sdmmc2_start_cmd() last param\n _ use readl_poll_timeout() instead of using while in stm32_sdmmc2_end_cmd()\nv4: _ replace mmc_create() usage by mmc_bind() callback\n _ rename struct stm32_sdmmc2_host to stm32_sdmmc2_priv\nv3: _ use registers offset instead of registers struct description\n _ rename clk_reg_add and pwr_reg_add to respectively clk_reg_msk and pwr_reg_msk\n _ don't exit in error if DT bus-width value is not correct, force it to 1\n and continue\nv2: _ add .get_cd() callback support\n\n drivers/mmc/Kconfig | 8 +\n drivers/mmc/Makefile | 1 +\n drivers/mmc/stm32_sdmmc2.c | 608 +++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 617 insertions(+)\n create mode 100644 drivers/mmc/stm32_sdmmc2.c", "diff": "diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig\nindex 82b8d75..6ac7ab2 100644\n--- a/drivers/mmc/Kconfig\n+++ b/drivers/mmc/Kconfig\n@@ -377,6 +377,14 @@ config GENERIC_ATMEL_MCI\n \t the SD Memory Card Specification V2.0, the SDIO V2.0 specification\n \t and CE-ATA V1.1.\n \n+config STM32_SDMMC2\n+\tbool \"STMicroelectronics STM32H7 SD/MMC Host Controller support\"\n+\tdepends on DM_MMC && BLK && OF_CONTROL && DM_MMC_OPS\n+\thelp\n+\t This selects support for the SD/MMC controller on STM32H7 SoCs.\n+\t If you have a board based on such a SoC and with a SD/MMC slot,\n+\t say Y or M here.\n+\n endif\n \n config TEGRA124_MMC_DISABLE_EXT_LOOPBACK\ndiff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile\nindex 2d781c3..2584663 100644\n--- a/drivers/mmc/Makefile\n+++ b/drivers/mmc/Makefile\n@@ -43,6 +43,7 @@ obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o\n obj-$(CONFIG_MMC_SANDBOX)\t\t+= sandbox_mmc.o\n obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o\n obj-$(CONFIG_SH_SDHI) += sh_sdhi.o\n+obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o\n \n # SDHCI\n obj-$(CONFIG_MMC_SDHCI)\t\t\t+= sdhci.o\ndiff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c\nnew file mode 100644\nindex 0000000..0e1f40b\n--- /dev/null\n+++ b/drivers/mmc/stm32_sdmmc2.c\n@@ -0,0 +1,608 @@\n+/*\n+ * Copyright (C) STMicroelectronics SA 2017\n+ * Author(s): Patrice CHOTARD, <patrice.chotard@st.com> for STMicroelectronics.\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include <common.h>\n+#include <clk.h>\n+#include <dm.h>\n+#include <fdtdec.h>\n+#include <libfdt.h>\n+#include <mmc.h>\n+#include <reset.h>\n+#include <asm/io.h>\n+#include <asm/gpio.h>\n+#include <linux/iopoll.h>\n+\n+struct stm32_sdmmc2_plat {\n+\tstruct mmc_config cfg;\n+\tstruct mmc mmc;\n+};\n+\n+struct stm32_sdmmc2_priv {\n+\tfdt_addr_t base;\n+\tstruct clk clk;\n+\tstruct reset_ctl reset_ctl;\n+\tstruct gpio_desc cd_gpio;\n+\tu32 clk_reg_msk;\n+\tu32 pwr_reg_msk;\n+};\n+\n+struct stm32_sdmmc2_ctx {\n+\tu32 cache_start;\n+\tu32 cache_end;\n+\tu32 data_length;\n+\tbool dpsm_abort;\n+};\n+\n+/* SDMMC REGISTERS OFFSET */\n+#define SDMMC_POWER\t\t0x00\t/* SDMMC power control */\n+#define SDMMC_CLKCR\t\t0x04\t/* SDMMC clock control */\n+#define SDMMC_ARG\t\t0x08\t/* SDMMC argument */\n+#define SDMMC_CMD\t\t0x0C\t/* SDMMC command */\n+#define SDMMC_RESP1\t\t0x14\t/* SDMMC response 1 */\n+#define SDMMC_RESP2\t\t0x18\t/* SDMMC response 2 */\n+#define SDMMC_RESP3\t\t0x1C\t/* SDMMC response 3 */\n+#define SDMMC_RESP4\t\t0x20\t/* SDMMC response 4 */\n+#define SDMMC_DTIMER\t\t0x24\t/* SDMMC data timer */\n+#define SDMMC_DLEN\t\t0x28\t/* SDMMC data length */\n+#define SDMMC_DCTRL\t\t0x2C\t/* SDMMC data control */\n+#define SDMMC_DCOUNT\t\t0x30\t/* SDMMC data counter */\n+#define SDMMC_STA\t\t0x34\t/* SDMMC status */\n+#define SDMMC_ICR\t\t0x38\t/* SDMMC interrupt clear */\n+#define SDMMC_MASK\t\t0x3C\t/* SDMMC mask */\n+#define SDMMC_IDMACTRL\t\t0x50\t/* SDMMC DMA control */\n+#define SDMMC_IDMABASE0\t\t0x58\t/* SDMMC DMA buffer 0 base address */\n+\n+/* SDMMC_POWER register */\n+#define SDMMC_POWER_PWRCTRL\t\tGENMASK(1, 0)\n+#define SDMMC_POWER_VSWITCH\t\tBIT(2)\n+#define SDMMC_POWER_VSWITCHEN\t\tBIT(3)\n+#define SDMMC_POWER_DIRPOL\t\tBIT(4)\n+\n+/* SDMMC_CLKCR register */\n+#define SDMMC_CLKCR_CLKDIV\t\tGENMASK(9, 0)\n+#define SDMMC_CLKCR_CLKDIV_MAX\t\tSDMMC_CLKCR_CLKDIV\n+#define SDMMC_CLKCR_PWRSAV\t\tBIT(12)\n+#define SDMMC_CLKCR_WIDBUS_4\t\tBIT(14)\n+#define SDMMC_CLKCR_WIDBUS_8\t\tBIT(15)\n+#define SDMMC_CLKCR_NEGEDGE\t\tBIT(16)\n+#define SDMMC_CLKCR_HWFC_EN\t\tBIT(17)\n+#define SDMMC_CLKCR_DDR\t\t\tBIT(18)\n+#define SDMMC_CLKCR_BUSSPEED\t\tBIT(19)\n+#define SDMMC_CLKCR_SELCLKRX\t\tGENMASK(21, 20)\n+\n+/* SDMMC_CMD register */\n+#define SDMMC_CMD_CMDINDEX\t\tGENMASK(5, 0)\n+#define SDMMC_CMD_CMDTRANS\t\tBIT(6)\n+#define SDMMC_CMD_CMDSTOP\t\tBIT(7)\n+#define SDMMC_CMD_WAITRESP\t\tGENMASK(9, 8)\n+#define SDMMC_CMD_WAITRESP_0\t\tBIT(8)\n+#define SDMMC_CMD_WAITRESP_1\t\tBIT(9)\n+#define SDMMC_CMD_WAITINT\t\tBIT(10)\n+#define SDMMC_CMD_WAITPEND\t\tBIT(11)\n+#define SDMMC_CMD_CPSMEN\t\tBIT(12)\n+#define SDMMC_CMD_DTHOLD\t\tBIT(13)\n+#define SDMMC_CMD_BOOTMODE\t\tBIT(14)\n+#define SDMMC_CMD_BOOTEN\t\tBIT(15)\n+#define SDMMC_CMD_CMDSUSPEND\t\tBIT(16)\n+\n+/* SDMMC_DCTRL register */\n+#define SDMMC_DCTRL_DTEN\t\tBIT(0)\n+#define SDMMC_DCTRL_DTDIR\t\tBIT(1)\n+#define SDMMC_DCTRL_DTMODE\t\tGENMASK(3, 2)\n+#define SDMMC_DCTRL_DBLOCKSIZE\t\tGENMASK(7, 4)\n+#define SDMMC_DCTRL_DBLOCKSIZE_SHIFT\t4\n+#define SDMMC_DCTRL_RWSTART\t\tBIT(8)\n+#define SDMMC_DCTRL_RWSTOP\t\tBIT(9)\n+#define SDMMC_DCTRL_RWMOD\t\tBIT(10)\n+#define SDMMC_DCTRL_SDMMCEN\t\tBIT(11)\n+#define SDMMC_DCTRL_BOOTACKEN\t\tBIT(12)\n+#define SDMMC_DCTRL_FIFORST\t\tBIT(13)\n+\n+/* SDMMC_STA register */\n+#define SDMMC_STA_CCRCFAIL\t\tBIT(0)\n+#define SDMMC_STA_DCRCFAIL\t\tBIT(1)\n+#define SDMMC_STA_CTIMEOUT\t\tBIT(2)\n+#define SDMMC_STA_DTIMEOUT\t\tBIT(3)\n+#define SDMMC_STA_TXUNDERR\t\tBIT(4)\n+#define SDMMC_STA_RXOVERR\t\tBIT(5)\n+#define SDMMC_STA_CMDREND\t\tBIT(6)\n+#define SDMMC_STA_CMDSENT\t\tBIT(7)\n+#define SDMMC_STA_DATAEND\t\tBIT(8)\n+#define SDMMC_STA_DHOLD\t\t\tBIT(9)\n+#define SDMMC_STA_DBCKEND\t\tBIT(10)\n+#define SDMMC_STA_DABORT\t\tBIT(11)\n+#define SDMMC_STA_DPSMACT\t\tBIT(12)\n+#define SDMMC_STA_CPSMACT\t\tBIT(13)\n+#define SDMMC_STA_TXFIFOHE\t\tBIT(14)\n+#define SDMMC_STA_RXFIFOHF\t\tBIT(15)\n+#define SDMMC_STA_TXFIFOF\t\tBIT(16)\n+#define SDMMC_STA_RXFIFOF\t\tBIT(17)\n+#define SDMMC_STA_TXFIFOE\t\tBIT(18)\n+#define SDMMC_STA_RXFIFOE\t\tBIT(19)\n+#define SDMMC_STA_BUSYD0\t\tBIT(20)\n+#define SDMMC_STA_BUSYD0END\t\tBIT(21)\n+#define SDMMC_STA_SDMMCIT\t\tBIT(22)\n+#define SDMMC_STA_ACKFAIL\t\tBIT(23)\n+#define SDMMC_STA_ACKTIMEOUT\t\tBIT(24)\n+#define SDMMC_STA_VSWEND\t\tBIT(25)\n+#define SDMMC_STA_CKSTOP\t\tBIT(26)\n+#define SDMMC_STA_IDMATE\t\tBIT(27)\n+#define SDMMC_STA_IDMABTC\t\tBIT(28)\n+\n+/* SDMMC_ICR register */\n+#define SDMMC_ICR_CCRCFAILC\t\tBIT(0)\n+#define SDMMC_ICR_DCRCFAILC\t\tBIT(1)\n+#define SDMMC_ICR_CTIMEOUTC\t\tBIT(2)\n+#define SDMMC_ICR_DTIMEOUTC\t\tBIT(3)\n+#define SDMMC_ICR_TXUNDERRC\t\tBIT(4)\n+#define SDMMC_ICR_RXOVERRC\t\tBIT(5)\n+#define SDMMC_ICR_CMDRENDC\t\tBIT(6)\n+#define SDMMC_ICR_CMDSENTC\t\tBIT(7)\n+#define SDMMC_ICR_DATAENDC\t\tBIT(8)\n+#define SDMMC_ICR_DHOLDC\t\tBIT(9)\n+#define SDMMC_ICR_DBCKENDC\t\tBIT(10)\n+#define SDMMC_ICR_DABORTC\t\tBIT(11)\n+#define SDMMC_ICR_BUSYD0ENDC\t\tBIT(21)\n+#define SDMMC_ICR_SDMMCITC\t\tBIT(22)\n+#define SDMMC_ICR_ACKFAILC\t\tBIT(23)\n+#define SDMMC_ICR_ACKTIMEOUTC\t\tBIT(24)\n+#define SDMMC_ICR_VSWENDC\t\tBIT(25)\n+#define SDMMC_ICR_CKSTOPC\t\tBIT(26)\n+#define SDMMC_ICR_IDMATEC\t\tBIT(27)\n+#define SDMMC_ICR_IDMABTCC\t\tBIT(28)\n+#define SDMMC_ICR_STATIC_FLAGS\t\t((GENMASK(28, 21)) | (GENMASK(11, 0)))\n+\n+/* SDMMC_MASK register */\n+#define SDMMC_MASK_CCRCFAILIE\t\tBIT(0)\n+#define SDMMC_MASK_DCRCFAILIE\t\tBIT(1)\n+#define SDMMC_MASK_CTIMEOUTIE\t\tBIT(2)\n+#define SDMMC_MASK_DTIMEOUTIE\t\tBIT(3)\n+#define SDMMC_MASK_TXUNDERRIE\t\tBIT(4)\n+#define SDMMC_MASK_RXOVERRIE\t\tBIT(5)\n+#define SDMMC_MASK_CMDRENDIE\t\tBIT(6)\n+#define SDMMC_MASK_CMDSENTIE\t\tBIT(7)\n+#define SDMMC_MASK_DATAENDIE\t\tBIT(8)\n+#define SDMMC_MASK_DHOLDIE\t\tBIT(9)\n+#define SDMMC_MASK_DBCKENDIE\t\tBIT(10)\n+#define SDMMC_MASK_DABORTIE\t\tBIT(11)\n+#define SDMMC_MASK_TXFIFOHEIE\t\tBIT(14)\n+#define SDMMC_MASK_RXFIFOHFIE\t\tBIT(15)\n+#define SDMMC_MASK_RXFIFOFIE\t\tBIT(17)\n+#define SDMMC_MASK_TXFIFOEIE\t\tBIT(18)\n+#define SDMMC_MASK_BUSYD0ENDIE\t\tBIT(21)\n+#define SDMMC_MASK_SDMMCITIE\t\tBIT(22)\n+#define SDMMC_MASK_ACKFAILIE\t\tBIT(23)\n+#define SDMMC_MASK_ACKTIMEOUTIE\t\tBIT(24)\n+#define SDMMC_MASK_VSWENDIE\t\tBIT(25)\n+#define SDMMC_MASK_CKSTOPIE\t\tBIT(26)\n+#define SDMMC_MASK_IDMABTCIE\t\tBIT(28)\n+\n+/* SDMMC_IDMACTRL register */\n+#define SDMMC_IDMACTRL_IDMAEN\t\tBIT(0)\n+\n+#define SDMMC_CMD_TIMEOUT\t\t0xFFFFFFFF\n+\n+DECLARE_GLOBAL_DATA_PTR;\n+\n+static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv,\n+\t\t\t\t struct mmc_data *data,\n+\t\t\t\t struct stm32_sdmmc2_ctx *ctx)\n+{\n+\tu32 data_ctrl, idmabase0;\n+\n+\t/* Configure the SDMMC DPSM (Data Path State Machine) */\n+\tdata_ctrl = (__ilog2(data->blocksize) <<\n+\t\t SDMMC_DCTRL_DBLOCKSIZE_SHIFT) &\n+\t\t SDMMC_DCTRL_DBLOCKSIZE;\n+\n+\tif (data->flags & MMC_DATA_READ) {\n+\t\tdata_ctrl |= SDMMC_DCTRL_DTDIR;\n+\t\tidmabase0 = (u32)data->dest;\n+\t} else {\n+\t\tidmabase0 = (u32)data->src;\n+\t}\n+\n+\t/* Set the SDMMC Data TimeOut value */\n+\twritel(SDMMC_CMD_TIMEOUT, priv->base + SDMMC_DTIMER);\n+\n+\t/* Set the SDMMC DataLength value */\n+\twritel(ctx->data_length, priv->base + SDMMC_DLEN);\n+\n+\t/* Write to SDMMC DCTRL */\n+\twritel(data_ctrl, priv->base + SDMMC_DCTRL);\n+\n+\t/* Cache align */\n+\tctx->cache_start = rounddown(idmabase0, ARCH_DMA_MINALIGN);\n+\tctx->cache_end = roundup(idmabase0 + ctx->data_length,\n+\t\t\t\t ARCH_DMA_MINALIGN);\n+\n+\t/*\n+\t * Flush data cache before DMA start (clean and invalidate)\n+\t * Clean also needed for read\n+\t * Avoid issue on buffer not cached-aligned\n+\t */\n+\tflush_dcache_range(ctx->cache_start, ctx->cache_end);\n+\n+\t/* Enable internal DMA */\n+\twritel(idmabase0, priv->base + SDMMC_IDMABASE0);\n+\twritel(SDMMC_IDMACTRL_IDMAEN, priv->base + SDMMC_IDMACTRL);\n+}\n+\n+static void stm32_sdmmc2_start_cmd(struct stm32_sdmmc2_priv *priv,\n+\t\t\t\t struct mmc_cmd *cmd, u32 cmd_param)\n+{\n+\tif (readl(priv->base + SDMMC_ARG) & SDMMC_CMD_CPSMEN)\n+\t\twritel(0, priv->base + SDMMC_ARG);\n+\n+\tcmd_param |= cmd->cmdidx | SDMMC_CMD_CPSMEN;\n+\tif (cmd->resp_type & MMC_RSP_PRESENT) {\n+\t\tif (cmd->resp_type & MMC_RSP_136)\n+\t\t\tcmd_param |= SDMMC_CMD_WAITRESP;\n+\t\telse if (cmd->resp_type & MMC_RSP_CRC)\n+\t\t\tcmd_param |= SDMMC_CMD_WAITRESP_0;\n+\t\telse\n+\t\t\tcmd_param |= SDMMC_CMD_WAITRESP_1;\n+\t}\n+\n+\t/* Clear flags */\n+\twritel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR);\n+\n+\t/* Set SDMMC argument value */\n+\twritel(cmd->cmdarg, priv->base + SDMMC_ARG);\n+\n+\t/* Set SDMMC command parameters */\n+\twritel(cmd_param, priv->base + SDMMC_CMD);\n+}\n+\n+static int stm32_sdmmc2_end_cmd(struct stm32_sdmmc2_priv *priv,\n+\t\t\t\tstruct mmc_cmd *cmd,\n+\t\t\t\tstruct stm32_sdmmc2_ctx *ctx)\n+{\n+\tu32 mask = SDMMC_STA_CTIMEOUT;\n+\tu32 status;\n+\tint ret;\n+\n+\tif (cmd->resp_type & MMC_RSP_PRESENT) {\n+\t\tmask |= SDMMC_STA_CMDREND;\n+\t\tif (cmd->resp_type & MMC_RSP_CRC)\n+\t\t\tmask |= SDMMC_STA_CCRCFAIL;\n+\t} else {\n+\t\tmask |= SDMMC_STA_CMDSENT;\n+\t}\n+\n+\t/* Polling status register */\n+\tret = readl_poll_timeout(priv->base + SDMMC_STA, status, status & mask,\n+\t\t\t\t 300);\n+\n+\tif (ret < 0) {\n+\t\tdebug(\"%s: timeout reading SDMMC_STA register\\n\", __func__);\n+\t\tctx->dpsm_abort = true;\n+\t\treturn ret;\n+\t}\n+\n+\t/* Check status */\n+\tif (status & SDMMC_STA_CTIMEOUT) {\n+\t\tdebug(\"%s: error SDMMC_STA_CTIMEOUT (0x%x) for cmd %d\\n\",\n+\t\t __func__, status, cmd->cmdidx);\n+\t\tctx->dpsm_abort = true;\n+\t\treturn -ETIMEDOUT;\n+\t}\n+\n+\tif (status & SDMMC_STA_CCRCFAIL && cmd->resp_type & MMC_RSP_CRC) {\n+\t\tdebug(\"%s: error SDMMC_STA_CCRCFAIL (0x%x) for cmd %d\\n\",\n+\t\t __func__, status, cmd->cmdidx);\n+\t\tctx->dpsm_abort = true;\n+\t\treturn -EILSEQ;\n+\t}\n+\n+\tif (status & SDMMC_STA_CMDREND && cmd->resp_type & MMC_RSP_PRESENT) {\n+\t\tcmd->response[0] = readl(priv->base + SDMMC_RESP1);\n+\t\tif (cmd->resp_type & MMC_RSP_136) {\n+\t\t\tcmd->response[1] = readl(priv->base + SDMMC_RESP2);\n+\t\t\tcmd->response[2] = readl(priv->base + SDMMC_RESP3);\n+\t\t\tcmd->response[3] = readl(priv->base + SDMMC_RESP4);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int stm32_sdmmc2_end_data(struct stm32_sdmmc2_priv *priv,\n+\t\t\t\t struct mmc_cmd *cmd,\n+\t\t\t\t struct mmc_data *data,\n+\t\t\t\t struct stm32_sdmmc2_ctx *ctx)\n+{\n+\tu32 mask = SDMMC_STA_DCRCFAIL | SDMMC_STA_DTIMEOUT |\n+\t\t SDMMC_STA_IDMATE | SDMMC_STA_DATAEND;\n+\tu32 status;\n+\n+\tif (data->flags & MMC_DATA_READ)\n+\t\tmask |= SDMMC_STA_RXOVERR;\n+\telse\n+\t\tmask |= SDMMC_STA_TXUNDERR;\n+\n+\tstatus = readl(priv->base + SDMMC_STA);\n+\twhile (!(status & mask))\n+\t\tstatus = readl(priv->base + SDMMC_STA);\n+\n+\t/*\n+\t * Need invalidate the dcache again to avoid any\n+\t * cache-refill during the DMA operations (pre-fetching)\n+\t */\n+\tif (data->flags & MMC_DATA_READ)\n+\t\tinvalidate_dcache_range(ctx->cache_start, ctx->cache_end);\n+\n+\tif (status & SDMMC_STA_DCRCFAIL) {\n+\t\tdebug(\"%s: error SDMMC_STA_DCRCFAIL (0x%x) for cmd %d\\n\",\n+\t\t __func__, status, cmd->cmdidx);\n+\t\tif (readl(priv->base + SDMMC_DCOUNT))\n+\t\t\tctx->dpsm_abort = true;\n+\t\treturn -EILSEQ;\n+\t}\n+\n+\tif (status & SDMMC_STA_DTIMEOUT) {\n+\t\tdebug(\"%s: error SDMMC_STA_DTIMEOUT (0x%x) for cmd %d\\n\",\n+\t\t __func__, status, cmd->cmdidx);\n+\t\tctx->dpsm_abort = true;\n+\t\treturn -ETIMEDOUT;\n+\t}\n+\n+\tif (status & SDMMC_STA_TXUNDERR) {\n+\t\tdebug(\"%s: error SDMMC_STA_TXUNDERR (0x%x) for cmd %d\\n\",\n+\t\t __func__, status, cmd->cmdidx);\n+\t\tctx->dpsm_abort = true;\n+\t\treturn -EIO;\n+\t}\n+\n+\tif (status & SDMMC_STA_RXOVERR) {\n+\t\tdebug(\"%s: error SDMMC_STA_RXOVERR (0x%x) for cmd %d\\n\",\n+\t\t __func__, status, cmd->cmdidx);\n+\t\tctx->dpsm_abort = true;\n+\t\treturn -EIO;\n+\t}\n+\n+\tif (status & SDMMC_STA_IDMATE) {\n+\t\tdebug(\"%s: error SDMMC_STA_IDMATE (0x%x) for cmd %d\\n\",\n+\t\t __func__, status, cmd->cmdidx);\n+\t\tctx->dpsm_abort = true;\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int stm32_sdmmc2_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,\n+\t\t\t\t struct mmc_data *data)\n+{\n+\tstruct stm32_sdmmc2_priv *priv = dev_get_priv(dev);\n+\tstruct stm32_sdmmc2_ctx ctx;\n+\tu32 cmdat = data ? SDMMC_CMD_CMDTRANS : 0;\n+\tint ret, retry = 3;\n+\n+retry_cmd:\n+\tctx.data_length = 0;\n+\tctx.dpsm_abort = false;\n+\n+\tif (data) {\n+\t\tctx.data_length = data->blocks * data->blocksize;\n+\t\tstm32_sdmmc2_start_data(priv, data, &ctx);\n+\t}\n+\n+\tstm32_sdmmc2_start_cmd(priv, cmd, cmdat);\n+\n+\tdebug(\"%s: send cmd %d data: 0x%x @ 0x%x\\n\",\n+\t __func__, cmd->cmdidx,\n+\t data ? ctx.data_length : 0, (unsigned int)data);\n+\n+\tret = stm32_sdmmc2_end_cmd(priv, cmd, &ctx);\n+\n+\tif (data && !ret)\n+\t\tret = stm32_sdmmc2_end_data(priv, cmd, data, &ctx);\n+\n+\t/* Clear flags */\n+\twritel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR);\n+\tif (data)\n+\t\twritel(0x0, priv->base + SDMMC_IDMACTRL);\n+\n+\t/*\n+\t * To stop Data Path State Machine, a stop_transmission command\n+\t * shall be send on cmd or data errors.\n+\t */\n+\tif (ctx.dpsm_abort && (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION)) {\n+\t\tstruct mmc_cmd stop_cmd;\n+\n+\t\tstop_cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;\n+\t\tstop_cmd.cmdarg = 0;\n+\t\tstop_cmd.resp_type = MMC_RSP_R1b;\n+\n+\t\tdebug(\"%s: send STOP command to abort dpsm treatments\\n\",\n+\t\t __func__);\n+\n+\t\tstm32_sdmmc2_start_cmd(priv, &stop_cmd, SDMMC_CMD_CMDSTOP);\n+\t\tstm32_sdmmc2_end_cmd(priv, &stop_cmd, &ctx);\n+\n+\t\twritel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR);\n+\t}\n+\n+\tif ((ret != -ETIMEDOUT) && (ret != 0) && retry) {\n+\t\tprintf(\"%s: cmd %d failed, retrying ...\\n\",\n+\t\t __func__, cmd->cmdidx);\n+\t\tretry--;\n+\t\tgoto retry_cmd;\n+\t}\n+\n+\tdebug(\"%s: end for CMD %d, ret = %d\\n\", __func__, cmd->cmdidx, ret);\n+\n+\treturn ret;\n+}\n+\n+static void stm32_sdmmc2_pwron(struct stm32_sdmmc2_priv *priv)\n+{\n+\t/* Reset */\n+\treset_assert(&priv->reset_ctl);\n+\tudelay(2);\n+\treset_deassert(&priv->reset_ctl);\n+\n+\tudelay(1000);\n+\n+\t/* Set Power State to ON */\n+\twritel(SDMMC_POWER_PWRCTRL | priv->pwr_reg_msk, priv->base + SDMMC_POWER);\n+\n+\t/*\n+\t * 1ms: required power up waiting time before starting the\n+\t * SD initialization sequence\n+\t */\n+\tudelay(1000);\n+}\n+\n+#define IS_RISING_EDGE(reg) (reg & SDMMC_CLKCR_NEGEDGE ? 0 : 1)\n+static int stm32_sdmmc2_set_ios(struct udevice *dev)\n+{\n+\tstruct mmc *mmc = mmc_get_mmc_dev(dev);\n+\tstruct stm32_sdmmc2_priv *priv = dev_get_priv(dev);\n+\tstruct stm32_sdmmc2_plat *plat = dev_get_platdata(dev);\n+\tstruct mmc_config *cfg = &plat->cfg;\n+\tu32 desired = mmc->clock;\n+\tu32 sys_clock = clk_get_rate(&priv->clk);\n+\tu32 clk = 0;\n+\n+\tdebug(\"%s: bus_with = %d, clock = %d\\n\", __func__,\n+\t mmc->bus_width, mmc->clock);\n+\n+\tif ((mmc->bus_width == 1) && (desired == cfg->f_min))\n+\t\tstm32_sdmmc2_pwron(priv);\n+\n+\t/*\n+\t * clk_div = 0 => command and data generated on SDMMCCLK falling edge\n+\t * clk_div > 0 and NEGEDGE = 0 => command and data generated on\n+\t * SDMMCCLK rising edge\n+\t * clk_div > 0 and NEGEDGE = 1 => command and data generated on\n+\t * SDMMCCLK falling edge\n+\t */\n+\tif (desired && ((sys_clock > desired) ||\n+\t\t\tIS_RISING_EDGE(priv->clk_reg_msk))) {\n+\t\tclk = DIV_ROUND_UP(sys_clock, 2 * desired);\n+\t\tif (clk > SDMMC_CLKCR_CLKDIV_MAX)\n+\t\t\tclk = SDMMC_CLKCR_CLKDIV_MAX;\n+\t}\n+\n+\tif (mmc->bus_width == 4)\n+\t\tclk |= SDMMC_CLKCR_WIDBUS_4;\n+\tif (mmc->bus_width == 8)\n+\t\tclk |= SDMMC_CLKCR_WIDBUS_8;\n+\n+\twritel(clk | priv->clk_reg_msk, priv->base + SDMMC_CLKCR);\n+\n+\treturn 0;\n+}\n+\n+static int stm32_sdmmc2_getcd(struct udevice *dev)\n+{\n+\tstruct stm32_sdmmc2_priv *priv = dev_get_priv(dev);\n+\n+\tdebug(\"stm32_sdmmc2_getcd called\\n\");\n+\n+\tif (dm_gpio_is_valid(&priv->cd_gpio))\n+\t\treturn dm_gpio_get_value(&priv->cd_gpio);\n+\n+\treturn 1;\n+}\n+\n+static const struct dm_mmc_ops stm32_sdmmc2_ops = {\n+\t.send_cmd = stm32_sdmmc2_send_cmd,\n+\t.set_ios = stm32_sdmmc2_set_ios,\n+\t.get_cd = stm32_sdmmc2_getcd,\n+};\n+\n+static int stm32_sdmmc2_probe(struct udevice *dev)\n+{\n+\tstruct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);\n+\tstruct stm32_sdmmc2_plat *plat = dev_get_platdata(dev);\n+\tstruct stm32_sdmmc2_priv *priv = dev_get_priv(dev);\n+\tstruct mmc_config *cfg = &plat->cfg;\n+\tint ret;\n+\n+\tpriv->base = dev_read_addr(dev);\n+\tif (priv->base == FDT_ADDR_T_NONE)\n+\t\treturn -EINVAL;\n+\n+\tif (dev_read_bool(dev, \"st,negedge\"))\n+\t\tpriv->clk_reg_msk |= SDMMC_CLKCR_NEGEDGE;\n+\tif (dev_read_bool(dev, \"st,dirpol\"))\n+\t\tpriv->pwr_reg_msk |= SDMMC_POWER_DIRPOL;\n+\n+\tret = clk_get_by_index(dev, 0, &priv->clk);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = clk_enable(&priv->clk);\n+\tif (ret)\n+\t\tgoto clk_free;\n+\n+\tret = reset_get_by_index(dev, 0, &priv->reset_ctl);\n+\tif (ret)\n+\t\tgoto clk_disable;\n+\n+\tgpio_request_by_name(dev, \"cd-gpios\", 0, &priv->cd_gpio,\n+\t\t\t GPIOD_IS_IN);\n+\n+\tcfg->f_min = 400000;\n+\tcfg->f_max = dev_read_u32_default(dev, \"max-frequency\", 52000000);\n+\tcfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;\n+\tcfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;\n+\tcfg->name = \"STM32 SDMMC2\";\n+\n+\tcfg->host_caps = 0;\n+\tif (cfg->f_max > 25000000)\n+\t\tcfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;\n+\n+\tswitch (dev_read_u32_default(dev, \"bus-width\", 1)) {\n+\tcase 8:\n+\t\tcfg->host_caps |= MMC_MODE_8BIT;\n+\tcase 4:\n+\t\tcfg->host_caps |= MMC_MODE_4BIT;\n+\t\tbreak;\n+\tcase 1:\n+\t\tbreak;\n+\tdefault:\n+\t\terror(\"invalid \\\"bus-width\\\" property, force to 1\\n\");\n+\t}\n+\n+\tupriv->mmc = &plat->mmc;\n+\n+\treturn 0;\n+\n+clk_disable:\n+\tclk_disable(&priv->clk);\n+clk_free:\n+\tclk_free(&priv->clk);\n+\n+\treturn ret;\n+}\n+\n+int stm32_sdmmc_bind(struct udevice *dev)\n+{\n+\tstruct stm32_sdmmc2_plat *plat = dev_get_platdata(dev);\n+\n+\treturn mmc_bind(dev, &plat->mmc, &plat->cfg);\n+}\n+\n+static const struct udevice_id stm32_sdmmc2_ids[] = {\n+\t{ .compatible = \"st,stm32-sdmmc2\" },\n+\t{ }\n+};\n+\n+U_BOOT_DRIVER(stm32_sdmmc2) = {\n+\t.name = \"stm32_sdmmc2\",\n+\t.id = UCLASS_MMC,\n+\t.of_match = stm32_sdmmc2_ids,\n+\t.ops = &stm32_sdmmc2_ops,\n+\t.probe = stm32_sdmmc2_probe,\n+\t.bind = stm32_sdmmc_bind,\n+\t.priv_auto_alloc_size = sizeof(struct stm32_sdmmc2_priv),\n+\t.platdata_auto_alloc_size = sizeof(struct stm32_sdmmc2_plat),\n+};\n", "prefixes": [ "U-Boot", "v5", "1/1" ] }