From patchwork Tue Feb 22 03:39:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 545148 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BEF37C433EF for ; Tue, 22 Feb 2022 03:39:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234134AbiBVDkS (ORCPT ); Mon, 21 Feb 2022 22:40:18 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:56100 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230249AbiBVDkS (ORCPT ); Mon, 21 Feb 2022 22:40:18 -0500 Received: from mail-pg1-x529.google.com (mail-pg1-x529.google.com [IPv6:2607:f8b0:4864:20::529]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2BCC7240B8 for ; Mon, 21 Feb 2022 19:39:54 -0800 (PST) Received: by mail-pg1-x529.google.com with SMTP id s16so15909483pgs.13 for ; Mon, 21 Feb 2022 19:39:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RSUTOvHR9x81DktuWwrA5BNOEcj+VMAMwFa5FNnQGgo=; b=O8hZg3EUmQGmSnyYk5Eo9OnJ8Mmm79l2v3PymvtLXPHvFjEBcWF+u9Z6rDfK3K6zP/ BWuqDaJTIG8dsqSupDdCD4dEzlpmEwsv8C5yNJfmOigqQUnIQn3O/4xcpcr/1MNiacY2 uyp+wRlyab4CqvRpuv/DtkIwIlPqP9ma+z86Amoljc5mKBJlVXYARVVWvQMx6VZH38ZM XMFsbIxq7bIpadSu6cpqMaGWIGpDLAu6CW0WABhy0Nz0Rqft4XwK8lORmY3IsE3r/HE9 1KCui2FqpC0BQm7by7AwDhmi7uFGu0MJEp5WmO78Fwz8YoYP2xhdI3I0ewZSBx73xxkz j7JA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RSUTOvHR9x81DktuWwrA5BNOEcj+VMAMwFa5FNnQGgo=; b=SauGKHz9FzrzXlx4tFykp4ccRMoeKg3b3pEGh4y5bBFDqghLXbBpKQNE2YhQ4I0u6T 4MB6Ytxw8+1O47espNasIPAPy6N71pFwmAI9MvTSMK8xynhP+NQ0dFedLfjFkX7DpqgI ki+LwY55TNhZyIzGia/A2uNjMm1tyKT3ebKrbRzwOub3wK6vCT+MUunggJviZBagtgRG U0ZgzIf63fJ7II7se2LLvLdUsmCjOCZmyj4aIFNAq8BpZcdgFoFq5JmtedOH44jO7K+m gbMgMXkyhQJANFnLIB5dddG0na4lkEo7IzGeBDX0hB5IZcQw+jCXxIt8T+WThNBG6aCI ZuRg== X-Gm-Message-State: AOAM530fMRXJy9ij5UFhOgQEkvqU7BmcdKKDmoi3yOP+Oss61no3uwWi h4UJh51i+bmXHD/d6DeNJS4= X-Google-Smtp-Source: ABdhPJwK9RxJPbv8WdAjLlN2wSmWI4OHB1eDctY+/TzsUVguanCEgFX/1HGQ/SiJHMWZoqtzfZG0Wg== X-Received: by 2002:a05:6a00:b51:b0:4c7:c1a3:3911 with SMTP id p17-20020a056a000b5100b004c7c1a33911mr22916096pfo.13.1645501193640; Mon, 21 Feb 2022 19:39:53 -0800 (PST) Received: from localhost.localdomain (220-128-190-163.hinet-ip.hinet.net. [220.128.190.163]) by smtp.gmail.com with ESMTPSA id ng16sm703542pjb.12.2022.02.21.19.39.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Feb 2022 19:39:53 -0800 (PST) From: Jason Lai To: ulf.hansson@linaro.org, takahiro.akashi@linaro.org, adrian.hunter@intel.com Cc: linux-mmc@vger.kernel.org, dlunev@chromium.org, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, jasonlai.genesyslogic@gmail.com Subject: [PATCH V3 1/7] mmc: core: Cleanup printing of speed mode at card insertion Date: Tue, 22 Feb 2022 11:39:25 +0800 Message-Id: <20220222033931.237638-2-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> References: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Ulf Hansson The current print of the bus speed mode in mmc_add_card() has grown over the years and is now difficult to parse. Let's clean up the code and also take the opportunity to properly announce "DDR" for eMMCs as "high speed DDR", which is according to the eMMC spec. Signed-off-by: Ulf Hansson --- drivers/mmc/core/bus.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 58a60afa650b..eefe74bf1356 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -299,6 +299,7 @@ int mmc_add_card(struct mmc_card *card) { int ret; const char *type; + const char *speed_mode = ""; const char *uhs_bus_speed_mode = ""; static const char *const uhs_speeds[] = { [UHS_SDR12_BUS_SPEED] = "SDR12 ", @@ -337,27 +338,30 @@ int mmc_add_card(struct mmc_card *card) break; } + if (mmc_card_hs(card)) + speed_mode = "high speed "; + else if (mmc_card_uhs(card)) + speed_mode = "ultra high speed "; + else if (mmc_card_ddr52(card)) + speed_mode = "high speed DDR "; + else if (mmc_card_hs200(card)) + speed_mode = "HS200 "; + else if (mmc_card_hs400es(card)) + speed_mode = "HS400 Enhanced strobe "; + else if (mmc_card_hs400(card)) + speed_mode = "HS400 "; + if (mmc_card_uhs(card) && (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; - if (mmc_host_is_spi(card->host)) { - pr_info("%s: new %s%s%s card on SPI\n", - mmc_hostname(card->host), - mmc_card_hs(card) ? "high speed " : "", - mmc_card_ddr52(card) ? "DDR " : "", - type); - } else { - pr_info("%s: new %s%s%s%s%s%s card at address %04x\n", - mmc_hostname(card->host), - mmc_card_uhs(card) ? "ultra high speed " : - (mmc_card_hs(card) ? "high speed " : ""), - mmc_card_hs400(card) ? "HS400 " : - (mmc_card_hs200(card) ? "HS200 " : ""), - mmc_card_hs400es(card) ? "Enhanced strobe " : "", - mmc_card_ddr52(card) ? "DDR " : "", + if (mmc_host_is_spi(card->host)) + pr_info("%s: new %s%s card on SPI\n", + mmc_hostname(card->host), speed_mode, type); + else + pr_info("%s: new %s%s%s card at address %04x\n", + mmc_hostname(card->host), speed_mode, uhs_bus_speed_mode, type, card->rca); - } #ifdef CONFIG_DEBUG_FS mmc_add_card_debugfs(card); From patchwork Tue Feb 22 03:39:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 545811 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 056D7C433F5 for ; Tue, 22 Feb 2022 03:40:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234161AbiBVDkZ (ORCPT ); Mon, 21 Feb 2022 22:40:25 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:56132 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230249AbiBVDkY (ORCPT ); Mon, 21 Feb 2022 22:40:24 -0500 Received: from mail-pj1-x102a.google.com (mail-pj1-x102a.google.com [IPv6:2607:f8b0:4864:20::102a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 86F72240BE for ; Mon, 21 Feb 2022 19:39:59 -0800 (PST) Received: by mail-pj1-x102a.google.com with SMTP id b8so17043030pjb.4 for ; Mon, 21 Feb 2022 19:39:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ydZMdx5zK+ddgngbL+7f2s9Gtnen1WZRpshtjB/Tkh4=; b=KMEpen6HbkNYfFFfyVyhUUDMDmSLe1pgBKQC3xz6mNi9ecBG/dPqVJxHv78TYkH/9x 3fsbHRlmsUWOuCB+lIHfhtPwW8YWwSpD0y33hMxt9gVT9Y5vBPNEiNoOTvPZ/Hid7iOJ vNOkeWtJ8GBV/5GWDDNEi3MhMhs54FowvW063ZzoLpEGAwFf74lFo501oGGaNorNN+JY rie2/WwAU2I93Y+G3YghfvOcb2ZCbMvkQxjAMHLXWJH8xfgtofEbceTXMLUWnsUJjh5E 8krIH3YB1+mTqWWUwqKVnNfMJ0gXw7C0NlOTFGXlxIHjt/FWgdFXaHBCUEdCXGpzBaBX ivaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ydZMdx5zK+ddgngbL+7f2s9Gtnen1WZRpshtjB/Tkh4=; b=0TxqU45TA+Z9nSAY2hKDV749lc0nmBBLDObJ55mKpGgSx7VrXUVtY/Ig4BYDZvIbNE yDuIBMnQhC/85qX3eN9bmGEP0+Pn4G1JZc2nuJladhTDrBMZYaW39+hR6/LAhqfTz+zv /QyB/nJpB1+btFFN5Ou8l+Q5adoHYKnC4F+6fItORmrLatdPnNhmWSDZ61i+YVzJXKtg VT/B5DwUlNP1N3aKtPr49ICjRvLi2olljONbq6wxdYyFiLSmR48gwi83C+TeBgZYr6KA bv4q0SzS40iOMimY2SKJDmEgmwQxyY2A3Zb4jrKUe5PbjTb/bMr7BYE1SVPFWgCy0Apy qkSA== X-Gm-Message-State: AOAM532ABkvp6Sx0gWzRqXbQ8EVvlfRbcWZ5v3mrWJmABQEGtpMndcZu zGRBAc5Jqf7xmnOjMrEWXuk= X-Google-Smtp-Source: ABdhPJyHhsaDfX2avzcODiswc8BelwJ5C/rkBl26tuyZz2+A4tA2kgwEkgkb2AuW+6W3fKWysuv5lA== X-Received: by 2002:a17:902:a3ca:b0:14f:d48e:aff3 with SMTP id q10-20020a170902a3ca00b0014fd48eaff3mr3499870plb.167.1645501198949; Mon, 21 Feb 2022 19:39:58 -0800 (PST) Received: from localhost.localdomain (220-128-190-163.hinet-ip.hinet.net. [220.128.190.163]) by smtp.gmail.com with ESMTPSA id ng16sm703542pjb.12.2022.02.21.19.39.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Feb 2022 19:39:58 -0800 (PST) From: Jason Lai To: ulf.hansson@linaro.org, takahiro.akashi@linaro.org, adrian.hunter@intel.com Cc: linux-mmc@vger.kernel.org, dlunev@chromium.org, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, jasonlai.genesyslogic@gmail.com Subject: [PATCH V3 2/7] mmc: core: Prepare to support SD UHS-II cards Date: Tue, 22 Feb 2022 11:39:26 +0800 Message-Id: <20220222033931.237638-3-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> References: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Ulf Hansson The SD UHS-II interface was introduced to the SD spec v4.00 several years ago. The interface is fundamentally different from an electrical and a protocol point of view, comparing to the legacy SD interface. However, the legacy SD protocol is supported through a specific transport layer (SD-TRAN) defined in the UHS-II addendum of the spec. This allows the SD card to be managed in a very similar way as a legacy SD card, hence a lot of code can be re-used to support these new types of cards through the mmc subsystem. Moreover, an SD card that supports the UHS-II interface shall also be backwards compatible with the legacy SD interface, which allows a UHS-II card to be inserted into a legacy slot. As a matter of fact, this is already supported by mmc subsystem as of today. To prepare to add support for UHS-II, this change puts the basic foundation in the mmc core in place, allowing it to be more easily reviewed before subsequent changes implements the actual support. Basically, the approach here adds a new UHS-II bus_ops type and adds a separate initialization path for the UHS-II card. The intent is to avoid us from sprinkling the legacy initialization path, but also to simplify implementation of the UHS-II specific bits. At this point, there is only one new host ops added to manage the various ios settings needed for UHS-II. Additional host ops that are needed, are being added from subsequent changes. Signed-off-by: Ulf Hansson --- drivers/mmc/core/Makefile | 2 +- drivers/mmc/core/core.c | 17 ++- drivers/mmc/core/core.h | 1 + drivers/mmc/core/sd_uhs2.c | 289 +++++++++++++++++++++++++++++++++++++ include/linux/mmc/card.h | 7 + include/linux/mmc/host.h | 22 +++ 6 files changed, 336 insertions(+), 2 deletions(-) create mode 100644 drivers/mmc/core/sd_uhs2.c diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 6a907736cd7a..15b067e8b0d1 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ - sdio_cis.o sdio_io.o sdio_irq.o \ + sdio_cis.o sdio_io.o sdio_irq.o sd_uhs2.o\ slot-gpio.o regulator.o mmc_core-$(CONFIG_OF) += pwrseq.o obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 368f10405e13..fc3d8d61a97c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2230,6 +2230,18 @@ void mmc_rescan(struct work_struct *work) goto out; } + /* + * Ideally we should favor initialization of legacy SD cards and defer + * UHS-II enumeration. However, it seems like cards doesn't reliably + * announce their support for UHS-II in the response to the ACMD41, + * while initializing the legacy SD interface. Therefore, let's start + * with UHS-II for now. + */ + if (!mmc_attach_sd_uhs2(host)) { + mmc_release_host(host); + goto out; + } + for (i = 0; i < ARRAY_SIZE(freqs); i++) { unsigned int freq = freqs[i]; if (freq > host->f_max) { @@ -2251,10 +2263,13 @@ void mmc_rescan(struct work_struct *work) void mmc_start_host(struct mmc_host *host) { + bool power_up = !(host->caps2 & + (MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_SD_UHS2)); + host->f_init = max(min(freqs[0], host->f_max), host->f_min); host->rescan_disable = 0; - if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) { + if (power_up) { mmc_claim_host(host); mmc_power_up(host, host->ocr_avail); mmc_release_host(host); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index f5f3f623ea49..2d80afc95e58 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -81,6 +81,7 @@ int mmc_detect_card_removed(struct mmc_host *host); int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host); int mmc_attach_sdio(struct mmc_host *host); +int mmc_attach_sd_uhs2(struct mmc_host *host); /* Module parameters */ extern bool use_spi_crc; diff --git a/drivers/mmc/core/sd_uhs2.c b/drivers/mmc/core/sd_uhs2.c new file mode 100644 index 000000000000..800957f74632 --- /dev/null +++ b/drivers/mmc/core/sd_uhs2.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Linaro Ltd + * + * Author: Ulf Hansson + * + * Support for SD UHS-II cards + */ +#include + +#include +#include + +#include "core.h" +#include "bus.h" +#include "sd.h" +#include "mmc_ops.h" + +static const unsigned int sd_uhs2_freqs[] = { 52000000, 26000000 }; + +static int sd_uhs2_set_ios(struct mmc_host *host) +{ + struct mmc_ios *ios = &host->ios; + + return host->ops->uhs2_set_ios(host, ios); +} + +static int sd_uhs2_power_up(struct mmc_host *host) +{ + host->ios.vdd = fls(host->ocr_avail) - 1; + host->ios.clock = host->f_init; + host->ios.timing = MMC_TIMING_SD_UHS2; + host->ios.power_mode = MMC_POWER_UP; + + return sd_uhs2_set_ios(host); +} + +static void sd_uhs2_power_off(struct mmc_host *host) +{ + host->ios.vdd = 0; + host->ios.clock = 0; + host->ios.timing = MMC_TIMING_LEGACY; + host->ios.power_mode = MMC_POWER_OFF; + + sd_uhs2_set_ios(host); +} + +/* + * Run the phy initialization sequence, which mainly relies on the UHS-II host + * to check that we reach the expected electrical state, between the host and + * the card. + */ +static int sd_uhs2_phy_init(struct mmc_host *host) +{ + return 0; +} + +/* + * Do the early initialization of the card, by sending the device init broadcast + * command and wait for the process to be completed. + */ +static int sd_uhs2_dev_init(struct mmc_host *host) +{ + return 0; +} + +/* + * Run the enumeration process by sending the enumerate command to the card. + * Note that, we currently support only the point to point connection, which + * means only one card can be attached per host/slot. + */ +static int sd_uhs2_enum(struct mmc_host *host, u32 *node_id) +{ + return 0; +} + +/* + * Read the UHS-II configuration registers (CFG_REG) of the card, by sending it + * commands and by parsing the responses. Store a copy of the relevant data in + * card->uhs2_config. + */ +static int sd_uhs2_config_read(struct mmc_host *host, struct mmc_card *card) +{ + return 0; +} + +/* + * Based on the card's and host's UHS-II capabilities, let's update the + * configuration of the card and the host. This may also include to move to a + * greater speed range/mode. Depending on the updated configuration, we may need + * to do a soft reset of the card via sending it a GO_DORMANT_STATE command. + * + * In the final step, let's check if the card signals "config completion", which + * indicates that the card has moved from config state into active state. + */ +static int sd_uhs2_config_write(struct mmc_host *host, struct mmc_card *card) +{ + return 0; +} + +/* + * Initialize the UHS-II card through the SD-TRAN transport layer. This enables + * commands/requests to be backwards compatible through the legacy SD protocol. + * UHS-II cards has a specific power limit specified for VDD1/VDD2, that should + * be set through a legacy CMD6. Note that, the power limit that becomes set, + * survives a soft reset through the GO_DORMANT_STATE command. + */ +static int sd_uhs2_legacy_init(struct mmc_host *host, struct mmc_card *card) +{ + return 0; +} + +/* + * Allocate the data structure for the mmc_card and run the UHS-II specific + * initialization sequence. + */ +static int sd_uhs2_init_card(struct mmc_host *host) +{ + struct mmc_card *card; + u32 node_id; + int err; + + err = sd_uhs2_dev_init(host); + if (err) + return err; + + err = sd_uhs2_enum(host, &node_id); + if (err) + return err; + + card = mmc_alloc_card(host, &sd_type); + if (IS_ERR(card)) + return PTR_ERR(card); + + card->uhs2_config.node_id = node_id; + card->type = MMC_TYPE_SD; + + err = sd_uhs2_config_read(host, card); + if (err) + goto err; + + err = sd_uhs2_config_write(host, card); + if (err) + goto err; + + err = sd_uhs2_legacy_init(host, card); + if (err) + goto err; + + host->card = card; + return 0; + +err: + mmc_remove_card(card); + return err; +} + +static void sd_uhs2_remove(struct mmc_host *host) +{ + mmc_remove_card(host->card); + host->card = NULL; +} + +static int sd_uhs2_alive(struct mmc_host *host) +{ + return mmc_send_status(host->card, NULL); +} + +static void sd_uhs2_detect(struct mmc_host *host) +{ + int err; + + mmc_get_card(host->card, NULL); + err = _mmc_detect_card_removed(host); + mmc_put_card(host->card, NULL); + + if (err) { + sd_uhs2_remove(host); + + mmc_claim_host(host); + mmc_detach_bus(host); + sd_uhs2_power_off(host); + mmc_release_host(host); + } +} + +static int sd_uhs2_suspend(struct mmc_host *host) +{ + return 0; +} + +static int sd_uhs2_resume(struct mmc_host *host) +{ + return 0; +} + +static int sd_uhs2_runtime_suspend(struct mmc_host *host) +{ + return 0; +} + +static int sd_uhs2_runtime_resume(struct mmc_host *host) +{ + return 0; +} + +static int sd_uhs2_shutdown(struct mmc_host *host) +{ + return 0; +} + +static int sd_uhs2_hw_reset(struct mmc_host *host) +{ + return 0; +} + +static const struct mmc_bus_ops sd_uhs2_ops = { + .remove = sd_uhs2_remove, + .alive = sd_uhs2_alive, + .detect = sd_uhs2_detect, + .suspend = sd_uhs2_suspend, + .resume = sd_uhs2_resume, + .runtime_suspend = sd_uhs2_runtime_suspend, + .runtime_resume = sd_uhs2_runtime_resume, + .shutdown = sd_uhs2_shutdown, + .hw_reset = sd_uhs2_hw_reset, +}; + +static int sd_uhs2_attach(struct mmc_host *host) +{ + int err; + + err = sd_uhs2_power_up(host); + if (err) + goto err; + + err = sd_uhs2_phy_init(host); + if (err) + goto err; + + err = sd_uhs2_init_card(host); + if (err) + goto err; + + mmc_attach_bus(host, &sd_uhs2_ops); + + mmc_release_host(host); + + err = mmc_add_card(host->card); + if (err) + goto remove_card; + + mmc_claim_host(host); + return 0; + +remove_card: + mmc_remove_card(host->card); + host->card = NULL; + mmc_claim_host(host); + mmc_detach_bus(host); +err: + sd_uhs2_power_off(host); + return err; +} + +int mmc_attach_sd_uhs2(struct mmc_host *host) +{ + int i, err = 0; + + if (!(host->caps2 & MMC_CAP2_SD_UHS2)) + return -EOPNOTSUPP; + + /* Turn off the legacy SD interface before trying with UHS-II. */ + mmc_power_off(host); + + /* + * Start UHS-II initialization at 52MHz and possibly make a retry at + * 26MHz according to the spec. It's required that the host driver + * validates ios->clock, to set a rate within the correct range. + */ + for (i = 0; i < ARRAY_SIZE(sd_uhs2_freqs); i++) { + host->f_init = sd_uhs2_freqs[i]; + err = sd_uhs2_attach(host); + if (!err) + break; + } + + return err; +} diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 37f975875102..610577d531c3 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -211,6 +211,11 @@ struct sd_ext_reg { #define SD_EXT_PERF_CMD_QUEUE (1<<4) }; +struct sd_uhs2_config { + u32 node_id; + /* TODO: Extend with more register configs. */ +}; + struct sdio_cccr { unsigned int sdio_vsn; unsigned int sd_vsn; @@ -315,6 +320,8 @@ struct mmc_card { struct sd_ext_reg ext_power; /* SD extension reg for PM */ struct sd_ext_reg ext_perf; /* SD extension reg for PERF */ + struct sd_uhs2_config uhs2_config; /* SD UHS-II config */ + unsigned int sdio_funcs; /* number of SDIO functions */ atomic_t sdio_funcs_probed; /* number of probed SDIO funcs */ struct sdio_cccr cccr; /* common card info */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 7afb57cab00b..16ccfb61fc58 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -63,6 +63,10 @@ struct mmc_ios { #define MMC_TIMING_MMC_HS400 10 #define MMC_TIMING_SD_EXP 11 #define MMC_TIMING_SD_EXP_1_2V 12 +#define MMC_TIMING_SD_UHS2 13 + + unsigned char vqmmc2_voltage; +#define MMC_VQMMC2_VOLTAGE_180 0 unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */ @@ -91,6 +95,10 @@ struct mmc_clk_phase_map { struct mmc_clk_phase phase[MMC_NUM_CLK_PHASES]; }; +struct sd_uhs2_caps { + /* TODO: Add UHS-II capabilities for the host. */ +}; + struct mmc_host; struct mmc_host_ops { @@ -126,6 +134,17 @@ struct mmc_host_ops { */ void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); + /* + * The uhs2_set_ios callback is mandatory to implement for hosts that + * supports the SD UHS-II interface (MMC_CAP2_SD_UHS2), while the + * callback is unused for the other cases. Note that, the struct + * mmc_ios is being re-used for this as well. + * + * Expected return values for the uhs2_set_ios callback are a negative + * errno in case of a failure or zero for success. + */ + int (*uhs2_set_ios)(struct mmc_host *host, struct mmc_ios *ios); + /* * Return values for the get_ro callback should be: * 0 for a read/write card @@ -377,6 +396,7 @@ struct mmc_host { MMC_CAP2_HS200_1_2V_SDR) #define MMC_CAP2_SD_EXP (1 << 7) /* SD express via PCIe */ #define MMC_CAP2_SD_EXP_1_2V (1 << 8) /* SD express 1.2V */ +#define MMC_CAP2_SD_UHS2 (1 << 9) /* SD UHS-II support */ #define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */ #define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */ #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ @@ -403,6 +423,8 @@ struct mmc_host { #endif #define MMC_CAP2_ALT_GPT_TEGRA (1 << 28) /* Host with eMMC that has GPT entry at a non-standard location */ + struct sd_uhs2_caps uhs2_caps; /* SD UHS-II capabilities */ + int fixed_drv_type; /* fixed driver type for non-removable media */ mmc_pm_flag_t pm_caps; /* supported pm features */ From patchwork Tue Feb 22 03:39:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 545147 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B9D63C433F5 for ; Tue, 22 Feb 2022 03:40:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234164AbiBVDkc (ORCPT ); Mon, 21 Feb 2022 22:40:32 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:56166 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230249AbiBVDkc (ORCPT ); Mon, 21 Feb 2022 22:40:32 -0500 Received: from mail-pj1-x1036.google.com (mail-pj1-x1036.google.com [IPv6:2607:f8b0:4864:20::1036]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 30813240B8 for ; Mon, 21 Feb 2022 19:40:08 -0800 (PST) Received: by mail-pj1-x1036.google.com with SMTP id ck4-20020a17090afe0400b001bc64ee7d3cso1183870pjb.4 for ; Mon, 21 Feb 2022 19:40:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=0xyYy0qN9Go4w6lNy+4hV42fbw4ce7eNrtB+9mtkTWo=; b=JQvJe6lTVYppAtNeHOwzX+rvDoBJXp//zDt11/DcRjxfeC54r4+nHogkdQ79MrynMT yf8T+6mxbe6RdrvMVAyuuFXmPjSfBth3Or+YMy+0XbEjlyGsCyk9ulpTqLEmfgtgJgxv K9pHVXdFXWWjnor2+i2gxHZr0OgVTISkOGzqqmFNUDDB5czp0RwjfNnAu3Bd6MYywlsc Fa8FfuCFN6fBLaQ8gzm0Of8QKNbNw1fSS1gyOoHokCZVZW1UZkL/g0cVsqKdk/JlKJ2k SVcF0oRfB0I22eMwrjy3Ya3C2BzQ8p9+OEdlELr0IVhjYe1ru7GkDCJawouSApqP3fYU e1ew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0xyYy0qN9Go4w6lNy+4hV42fbw4ce7eNrtB+9mtkTWo=; b=LDEJeXwsaufK7z9vCXnykRDAzn8GM0Usmdy0ks9RPg7kv2wQQgC1JfvwcdO+29UH7n KHdMer2aUwi3Uc1+fqMYVVRbLxQOkp3nXBU13lLyBG+0vQLw/BOjumHIzA6o0MNYBIXr SZdgpWn1zFtZpbhItZOLUZXggxVFlZ0OHyOCrx9Xu0BmQWqg1CK65V6bYSmBoIr16kvC 822H86MiPkqaP3fKwKXmC0ZIHZ19LuikmN0KG4GWsXeQdpuLIZOLQfAOTKw50y26rsdu xrxekj5sFrsQSBb4r4w0qxvNE/rU9fLSa9VD8thLTRVMeISEUvCBc7IdK3CDlqN5B4SS wb2w== X-Gm-Message-State: AOAM531rsac/N6b8TlOEEQYxlaf/nHh8reIGzBa6XT00nclEuFlBfVnj MLPnqKv0sZrZ7KT0F0QjgxY= X-Google-Smtp-Source: ABdhPJzumBFTOxY0GDEVriWKqPWyYCxcDz0lhxkM0CcRSl2iHDMGpVBOGjgkArYkbTeD4vwC1asUSg== X-Received: by 2002:a17:90a:aa0a:b0:1b4:e1e3:9651 with SMTP id k10-20020a17090aaa0a00b001b4e1e39651mr2030918pjq.235.1645501207759; Mon, 21 Feb 2022 19:40:07 -0800 (PST) Received: from localhost.localdomain (220-128-190-163.hinet-ip.hinet.net. [220.128.190.163]) by smtp.gmail.com with ESMTPSA id ng16sm703542pjb.12.2022.02.21.19.40.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Feb 2022 19:40:07 -0800 (PST) From: Jason Lai To: ulf.hansson@linaro.org, takahiro.akashi@linaro.org, adrian.hunter@intel.com Cc: linux-mmc@vger.kernel.org, dlunev@chromium.org, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, jasonlai.genesyslogic@gmail.com Subject: [PATCH V3 3/7] mmc: core: Announce successful insertion of an SD UHS-II card Date: Tue, 22 Feb 2022 11:39:27 +0800 Message-Id: <20220222033931.237638-4-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> References: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Ulf Hansson To inform the users about SD UHS-II cards, let's extend the print at card insertion with a "UHS-II" substring. Within this change, it seems reasonable to convert from using "ultra high speed" into "UHS-I speed", for the UHS-I type, as it should makes it more clear. Note that, the new print for UHS-II cards doesn't include the actual selected speed mode. Instead, this is going to be added from subsequent change. Signed-off-by: Ulf Hansson --- drivers/mmc/core/bus.c | 4 +++- drivers/mmc/core/host.h | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index eefe74bf1356..cceedc7a7213 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -341,7 +341,9 @@ int mmc_add_card(struct mmc_card *card) if (mmc_card_hs(card)) speed_mode = "high speed "; else if (mmc_card_uhs(card)) - speed_mode = "ultra high speed "; + speed_mode = "UHS-I speed "; + else if (mmc_card_uhs2(card)) + speed_mode = "UHS-II speed "; else if (mmc_card_ddr52(card)) speed_mode = "high speed DDR "; else if (mmc_card_hs200(card)) diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index 48c4952512a5..2c2ad9d63c0b 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -89,5 +89,9 @@ static inline bool mmc_card_sd_express(struct mmc_host *host) host->ios.timing == MMC_TIMING_SD_EXP_1_2V; } +static inline bool mmc_card_uhs2(struct mmc_card *card) +{ + return card->host->ios.timing == MMC_TIMING_SD_UHS2; +} #endif From patchwork Tue Feb 22 03:39:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 545810 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DFA42C433F5 for ; Tue, 22 Feb 2022 03:40:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234198AbiBVDkj (ORCPT ); Mon, 21 Feb 2022 22:40:39 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:56196 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230249AbiBVDki (ORCPT ); Mon, 21 Feb 2022 22:40:38 -0500 Received: from mail-pg1-x52e.google.com (mail-pg1-x52e.google.com [IPv6:2607:f8b0:4864:20::52e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 88F33240B8 for ; Mon, 21 Feb 2022 19:40:13 -0800 (PST) Received: by mail-pg1-x52e.google.com with SMTP id 12so12367535pgd.0 for ; Mon, 21 Feb 2022 19:40:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ejhGfYhEFe0sow+Ti+BIjLRrK683vxciwz2GFrR2geI=; b=kycwWPK775fgRt3XTnVI8eYhlnnrQWcUq/0h2TPDBkKqXl8iM4l6Kza+Cx0onfdiDp aQkefpn0IToiatTtddNtEG8W/OdBpYBPxjPudWJU54e6iY9z87vrZYCNUG6v2m3XKox0 xXSvO/t81eCfryWP43v6Q9y132vxOX8oowym+H18FezFeWckkYBWc2w3dvadrorEjpYq Vfy6w+JwD/f6XUMJPl24xo+hsvzub3wWbjye0MqTPHWrXqhdNrVtCFGvo1dZgJRG5Vqq h5DIAiR12UVDB8HVifG0VB98A/q1y5N7IgNpHrTJKWbh2/TleMgfdXevVUKeOh7z0+fy Ujxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ejhGfYhEFe0sow+Ti+BIjLRrK683vxciwz2GFrR2geI=; b=sECkM6m5sqqkDCKYluGt897ag8vGL4iQbwMrxsIW4ay9CdRloggenPT9uBABs20ZN/ jM/LpYNfRgXBzmIavXQ9R3+wbv9M55VpAsYYJI+9ku6sOa4/hXs8uYCE+MvZ3Jxs44TU 0l27g9C1uEkLZSzB5SCiop3hlxHA7eEt9X+LSOH2kjUqIPM/2wKAKXcJ5n10rlsPdimU r9EsYO/+tBr954WwequGltsI8Wj8JZ3wCYgzpiaSSuW1NVNUJIOdxy9T66iv3E6RObRq 7GW5D03BNGcWKHrfqTRB1/IIPidyuVKQ1T/c775QVZ+M4TwCmACPSgemzddWWPBmwJ3K 4b4w== X-Gm-Message-State: AOAM532+7/0LjWceDtXKtWrX8OE97OwLjNmD10Ee5eJMBURwyJ4o/OdL 9G0lD8Go0Uf5Y/t+8YhrnRk= X-Google-Smtp-Source: ABdhPJwhu0yCj2eXVe3NHzpbmTU8/MZPzgz/5GdN0dyUj0PABXza7MRfpGJw6sH/rL0I03m4epziUQ== X-Received: by 2002:aa7:9902:0:b0:4cb:95a7:a4c4 with SMTP id z2-20020aa79902000000b004cb95a7a4c4mr22546148pff.85.1645501213084; Mon, 21 Feb 2022 19:40:13 -0800 (PST) Received: from localhost.localdomain (220-128-190-163.hinet-ip.hinet.net. [220.128.190.163]) by smtp.gmail.com with ESMTPSA id ng16sm703542pjb.12.2022.02.21.19.40.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Feb 2022 19:40:12 -0800 (PST) From: Jason Lai To: ulf.hansson@linaro.org, takahiro.akashi@linaro.org, adrian.hunter@intel.com Cc: linux-mmc@vger.kernel.org, dlunev@chromium.org, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, jasonlai.genesyslogic@gmail.com Subject: [PATCH V3 4/7] mmc: core: Extend support for mmc regulators with a vqmmc2 Date: Tue, 22 Feb 2022 11:39:28 +0800 Message-Id: <20220222033931.237638-5-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> References: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Ulf Hansson To allow an additional external regulator to be controlled by an mmc host driver, let's add support for a vqmmc2 regulator to the mmc core. For an SD UHS-II interface the vqmmc2 regulator may correspond to the so called vdd2 supply, as described by the SD spec. Initially, only 1.8V is needed, hence limit the new helper function, mmc_regulator_set_vqmmc2() to this too. Note that, to allow for flexibility mmc host drivers need to manage the enable/disable of the vqmmc2 regulator themselves, while the regulator is looked up through the common mmc_regulator_get_supply(). Signed-off-by: Ulf Hansson --- drivers/mmc/core/regulator.c | 34 ++++++++++++++++++++++++++++++++++ include/linux/mmc/host.h | 8 ++++++++ 2 files changed, 42 insertions(+) diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c index 609201a467ef..3c189682797c 100644 --- a/drivers/mmc/core/regulator.c +++ b/drivers/mmc/core/regulator.c @@ -223,6 +223,33 @@ int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios) } EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc); +/** + * mmc_regulator_set_vqmmc2 - Set vqmmc2 as per the ios->vqmmc2_voltage + * @mmc: The mmc host to regulate + * @ios: The io bus settings + * + * Sets a new voltage level for the vqmmc2 regulator, which may correspond to + * the vdd2 regulator for an SD UHS-II interface. This function is expected to + * be called by mmc host drivers. + * + * Returns a negative error code on failure, zero if the voltage level was + * changed successfully or a positive value if the level didn't need to change. + */ +int mmc_regulator_set_vqmmc2(struct mmc_host *mmc, struct mmc_ios *ios) +{ + if (IS_ERR(mmc->supply.vqmmc2)) + return -EINVAL; + + switch (ios->vqmmc2_voltage) { + case MMC_VQMMC2_VOLTAGE_180: + return mmc_regulator_set_voltage_if_supported( + mmc->supply.vqmmc2, 1700000, 1800000, 1950000); + default: + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc2); + #else static inline int mmc_regulator_get_ocrmask(struct regulator *supply) @@ -249,6 +276,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc"); mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc"); + mmc->supply.vqmmc2 = devm_regulator_get_optional(dev, "vqmmc2"); if (IS_ERR(mmc->supply.vmmc)) { if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) @@ -268,6 +296,12 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) dev_dbg(dev, "No vqmmc regulator found\n"); } + if (IS_ERR(mmc->supply.vqmmc2)) { + if (PTR_ERR(mmc->supply.vqmmc2) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_dbg(dev, "No vqmmc2 regulator found\n"); + } + return 0; } EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 16ccfb61fc58..d770941f05c7 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -305,6 +305,7 @@ struct mmc_pwrseq; struct mmc_supply { struct regulator *vmmc; /* Card power supply */ struct regulator *vqmmc; /* Optional Vccq supply */ + struct regulator *vqmmc2; /* Optional supply for phy */ }; struct mmc_ctx { @@ -583,6 +584,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, struct regulator *supply, unsigned short vdd_bit); int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios); +int mmc_regulator_set_vqmmc2(struct mmc_host *mmc, struct mmc_ios *ios); #else static inline int mmc_regulator_set_ocr(struct mmc_host *mmc, struct regulator *supply, @@ -596,6 +598,12 @@ static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc, { return -EINVAL; } + +static inline int mmc_regulator_set_vqmmc2(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + return -EINVAL; +} #endif int mmc_regulator_get_supply(struct mmc_host *mmc); From patchwork Tue Feb 22 03:39:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 545146 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 64119C433F5 for ; Tue, 22 Feb 2022 03:40:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234211AbiBVDko (ORCPT ); Mon, 21 Feb 2022 22:40:44 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:56216 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230249AbiBVDkn (ORCPT ); Mon, 21 Feb 2022 22:40:43 -0500 Received: from mail-pf1-x433.google.com (mail-pf1-x433.google.com [IPv6:2607:f8b0:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1FD1E240B8 for ; Mon, 21 Feb 2022 19:40:19 -0800 (PST) Received: by mail-pf1-x433.google.com with SMTP id y11so10627168pfi.11 for ; Mon, 21 Feb 2022 19:40:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=wgefqjvydWGgiCUUrmzCVzKBCAf4TRKHlgXvLLgAE+0=; b=J237Z7FLU4orr/kazryb4QvkxzYh8RTc/UPEJnlTJJKKt/zdK1BG+2clqEcK1OJuY+ OxXRETc1treFQI6b7V7Sa9kWnxCsofAZIBq43w69jzYg0d6+0B52HBe2zejRhfElVTf5 aERiRztwJ8cApR7qKM3WUa7UVvUIM5uAkg7itwu7tPn6DvZzQal/rXQCXvTGf0NxMem9 ZDdwyZwkyjuHjIEXM7eT8yagu1p7/Uutc8Lznlpepghn485RlzTYKttV+c6cRi6X667d UfhIZbPGdrBH1LUCmqINf3DFOpzYKb5xilJeNWHBf/+PFXZ7v1hUFQTztZoTtIa/WkOC aYUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wgefqjvydWGgiCUUrmzCVzKBCAf4TRKHlgXvLLgAE+0=; b=opLaWNHq1pVXaM3YFoL+iIyQpOHlv91gA4MSDnm3CD4OvUBN8BgS06eq+OQWm3ROFf ATNYUwKNgfPwdIY35zoWdBx1Eq03K7LuSKFFJz7kDIFViJGnBB3ck7MuZ96mSwtqq39E A4LJyLHPRWePnXTJ51yI7fiqdylHCwt3ClKz8+ZT44ZsvB9w2YrJ0W42diUHg9UVT9qv LHbq3wDF059tOV3a8pF/+14wIVNBrt0oJ5yViCm/BOHcFzbJV2CSfJpNB2pLabiEqtc9 my932Mn05w7zV/KVsClldhS9F72djKq9SQ6TzK8h2KgQhTQBVrydW40G41MJcjEQN8Kq vuZw== X-Gm-Message-State: AOAM532IE69rXKnUe+MiamCQTqxuwIcJvw/GOF9bihVeTwnaq7NsRyvo ZcAQgc5bQ6GYv3bbJWjq2b0= X-Google-Smtp-Source: ABdhPJz2W8oeoKXZ6zc1bWVsz898rRDxFVy/QWj0U4cY7UOFvZhsRroVNhd/x5wsMqjqUR8kRp9Iig== X-Received: by 2002:a63:8bc9:0:b0:372:c564:621b with SMTP id j192-20020a638bc9000000b00372c564621bmr18624181pge.601.1645501218485; Mon, 21 Feb 2022 19:40:18 -0800 (PST) Received: from localhost.localdomain (220-128-190-163.hinet-ip.hinet.net. [220.128.190.163]) by smtp.gmail.com with ESMTPSA id ng16sm703542pjb.12.2022.02.21.19.40.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Feb 2022 19:40:18 -0800 (PST) From: Jason Lai To: ulf.hansson@linaro.org, takahiro.akashi@linaro.org, adrian.hunter@intel.com Cc: linux-mmc@vger.kernel.org, dlunev@chromium.org, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, jasonlai.genesyslogic@gmail.com Subject: [PATCH V3 5/7] mmc: add UHS-II related definitions in headers Date: Tue, 22 Feb 2022 11:39:29 +0800 Message-Id: <20220222033931.237638-6-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> References: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Jason Lai 1. Define UHS2 members in some data structures. 2. Define UHS2 registers and messages. Signed-off-by: Jason Lai --- drivers/mmc/core/sd_uhs2.h | 16 +++ include/linux/mmc/card.h | 30 +++++- include/linux/mmc/core.h | 6 ++ include/linux/mmc/host.h | 41 +++++++- include/linux/mmc/sd_uhs2.h | 198 ++++++++++++++++++++++++++++++++++++ 5 files changed, 289 insertions(+), 2 deletions(-) create mode 100644 drivers/mmc/core/sd_uhs2.h create mode 100644 include/linux/mmc/sd_uhs2.h diff --git a/drivers/mmc/core/sd_uhs2.h b/drivers/mmc/core/sd_uhs2.h new file mode 100644 index 000000000000..91e895b331e0 --- /dev/null +++ b/drivers/mmc/core/sd_uhs2.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Header file for UHS-II packets, Host Controller registers and I/O + * accessors. + * + * Copyright (C) 2014 Intel Corp, All Rights Reserved. + */ +#ifndef MMC_UHS2_H +#define MMC_UHS2_H + +struct mmc_host; +struct mmc_request; + +int sd_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq); + +#endif /* MMC_UHS2_H */ diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 610577d531c3..48c72bb75d74 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -213,7 +213,35 @@ struct sd_ext_reg { struct sd_uhs2_config { u32 node_id; - /* TODO: Extend with more register configs. */ + + u32 dap; + u32 gap; + u32 n_fcu; + u32 maxblk_len; + u8 n_lanes; + u8 dadr_len; + u8 app_type; + u8 phy_minor_rev; + u8 phy_major_rev; + u8 can_hibernate; + u8 n_lss_sync; + u8 n_lss_dir; + u8 link_minor_rev; + u8 link_major_rev; + u8 dev_type; + u8 n_data_gap; + + u32 n_fcu_set; + u32 maxblk_len_set; + u8 n_lanes_set; + u8 speed_range_set; + u8 n_lss_sync_set; + u8 n_lss_dir_set; + u8 n_data_gap_set; + u8 pwrctrl_mode_set; + u8 max_retry_set; + + u8 cfg_complete; }; struct sdio_cccr { diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 71101d1ec825..cfc87be6700a 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -2,6 +2,7 @@ /* * linux/include/linux/mmc/core.h */ + #ifndef LINUX_MMC_CORE_H #define LINUX_MMC_CORE_H @@ -109,6 +110,11 @@ struct mmc_command { unsigned int busy_timeout; /* busy detect timeout in ms */ struct mmc_data *data; /* data segment associated with cmd */ struct mmc_request *mrq; /* associated request */ + + struct uhs2_command *uhs2_cmd; /* UHS2 command */ + u8 *uhs2_resp; /* UHS2 native cmd resp */ + u8 uhs2_resp_len; /* UHS2 native cmd resp len */ + u8 uhs2_tmode0_flag; /* UHS2 transfer mode flag */ }; struct mmc_data { diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index d770941f05c7..39b39e0cdb2f 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -96,7 +97,38 @@ struct mmc_clk_phase_map { }; struct sd_uhs2_caps { - /* TODO: Add UHS-II capabilities for the host. */ + int flags; +#define MMC_UHS2_SUPPORT BIT(0) +#define MMC_UHS2_INITIALIZED BIT(1) +#define MMC_UHS2_2L_HD BIT(2) +#define MMC_UHS2_APP_CMD BIT(3) +#define MMC_UHS2_SPEED_B BIT(4) +#define MMC_SUPPORT_ADMA3 BIT(5) + + u32 dap; + u32 gap; + u32 group_desc; + u32 maxblk_len; + u32 n_fcu; + u8 n_lanes; + u8 addr64; + u8 card_type; + u8 phy_rev; + u8 speed_range; + u8 can_hibernate; + u8 n_lss_sync; + u8 n_lss_dir; + u8 link_rev; + u8 host_type; + u8 n_data_gap; + + u32 maxblk_len_set; + u32 n_fcu_set; + u8 n_lanes_set; + u8 n_lss_sync_set; + u8 n_lss_dir_set; + u8 n_data_gap_set; + u8 max_retry_set; }; struct mmc_host; @@ -212,6 +244,13 @@ struct mmc_host_ops { /* Initialize an SD express card, mandatory for MMC_CAP2_SD_EXP. */ int (*init_sd_express)(struct mmc_host *host, struct mmc_ios *ios); + + /* UHS2 interfaces */ + /* + * Every host controller can assign its own actions to set up their + * controller. + */ + int (*uhs2_host_operation)(struct mmc_host *host, enum uhs2_action act); }; struct mmc_cqe_ops { diff --git a/include/linux/mmc/sd_uhs2.h b/include/linux/mmc/sd_uhs2.h new file mode 100644 index 000000000000..e134e194d581 --- /dev/null +++ b/include/linux/mmc/sd_uhs2.h @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Header file for UHS-II packets, Host Controller registers and I/O + * accessors. + * + * Copyright (C) 2014 Intel Corp, All Rights Reserved. + */ +#ifndef LINUX_MMC_UHS2_H +#define LINUX_MMC_UHS2_H + +/* LINK Layer definition */ +/* UHS2 Header */ +#define UHS2_NATIVE_PACKET_POS 7 +#define UHS2_NATIVE_PACKET (1 << UHS2_NATIVE_PACKET_POS) + +#define UHS2_PACKET_TYPE_POS 4 +#define UHS2_PACKET_TYPE_CCMD (0 << UHS2_PACKET_TYPE_POS) +#define UHS2_PACKET_TYPE_DCMD (1 << UHS2_PACKET_TYPE_POS) +#define UHS2_PACKET_TYPE_RES (2 << UHS2_PACKET_TYPE_POS) +#define UHS2_PACKET_TYPE_DATA (3 << UHS2_PACKET_TYPE_POS) +#define UHS2_PACKET_TYPE_MSG (7 << UHS2_PACKET_TYPE_POS) + +#define UHS2_DEST_ID_MASK 0x0F +#define UHS2_DEST_ID 0x1 + +#define UHS2_SRC_ID_POS 12 +#define UHS2_SRC_ID_MASK 0xF000 + +#define UHS2_TRANS_ID_POS 8 +#define UHS2_TRANS_ID_MASK 0x0700 + +/* UHS2 MSG */ +#define UHS2_MSG_CTG_POS 5 +#define UHS2_MSG_CTG_LMSG 0x00 +#define UHS2_MSG_CTG_INT 0x60 +#define UHS2_MSG_CTG_AMSG 0x80 + +#define UHS2_MSG_CTG_FCREQ 0x00 +#define UHS2_MSG_CTG_FCRDY 0x01 +#define UHS2_MSG_CTG_STAT 0x02 + +#define UHS2_MSG_CODE_POS 8 +#define UHS2_MSG_CODE_FC_UNRECOVER_ERR 0x8 +#define UHS2_MSG_CODE_STAT_UNRECOVER_ERR 0x8 +#define UHS2_MSG_CODE_STAT_RECOVER_ERR 0x1 + +/* TRANS Layer definition */ + +/* Native packets*/ +#define UHS2_NATIVE_CMD_RW_POS 7 +#define UHS2_NATIVE_CMD_WRITE (1 << UHS2_NATIVE_CMD_RW_POS) +#define UHS2_NATIVE_CMD_READ (0 << UHS2_NATIVE_CMD_RW_POS) + +#define UHS2_NATIVE_CMD_PLEN_POS 4 +#define UHS2_NATIVE_CMD_PLEN_4B (1 << UHS2_NATIVE_CMD_PLEN_POS) +#define UHS2_NATIVE_CMD_PLEN_8B (2 << UHS2_NATIVE_CMD_PLEN_POS) +#define UHS2_NATIVE_CMD_PLEN_16B (3 << UHS2_NATIVE_CMD_PLEN_POS) + +#define UHS2_NATIVE_CCMD_GET_MIOADR_MASK 0xF00 +#define UHS2_NATIVE_CCMD_MIOADR_MASK 0x0F + +#define UHS2_NATIVE_CCMD_LIOADR_POS 8 +#define UHS2_NATIVE_CCMD_GET_LIOADR_MASK 0x0FF + +#define UHS2_DCMD_DM_POS 6 +#define UHS2_DCMD_2L_HD_MODE (1 << UHS2_DCMD_DM_POS) +#define UHS2_DCMD_LM_POS 5 +#define UHS2_DCMD_LM_TLEN_EXIST (1 << UHS2_DCMD_LM_POS) +#define UHS2_DCMD_TLUM_POS 4 +#define UHS2_DCMD_TLUM_BYTE_MODE (1 << UHS2_DCMD_TLUM_POS) +#define UHS2_NATIVE_DCMD_DAM_POS 3 +#define UHS2_NATIVE_DCMD_DAM_IO (1 << UHS2_NATIVE_DCMD_DAM_POS) + +#define UHS2_RES_NACK_POS 7 +#define UHS2_RES_NACK_MASK (0x1 << UHS2_RES_NACK_POS) + +#define UHS2_RES_ECODE_POS 4 +#define UHS2_RES_ECODE_MASK 0x7 +#define UHS2_RES_ECODE_COND 1 +#define UHS2_RES_ECODE_ARG 2 +#define UHS2_RES_ECODE_GEN 3 + +/* IOADR of device registers */ +#define UHS2_IOADR_GENERIC_CAPS 0x00 +#define UHS2_IOADR_PHY_CAPS 0x02 +#define UHS2_IOADR_LINK_CAPS 0x04 +#define UHS2_IOADR_RSV_CAPS 0x06 +#define UHS2_IOADR_GENERIC_SETTINGS 0x08 +#define UHS2_IOADR_PHY_SETTINGS 0x0A +#define UHS2_IOADR_LINK_SETTINGS 0x0C +#define UHS2_IOADR_PRESET 0x40 + +/* SD application packets */ +#define UHS2_SD_CMD_INDEX_POS 8 + +#define UHS2_SD_CMD_APP_POS 14 +#define UHS2_SD_CMD_APP (1 << UHS2_SD_CMD_APP_POS) + +struct uhs2_command { + u16 header; + u16 arg; + u32 *payload; + u32 payload_len; + u32 packet_len; +}; + +enum uhs2_action { + UHS2_SET_CONFIG, + UHS2_ENABLE_INT, + UHS2_DISABLE_INT, + UHS2_SET_SPEED_B, + UHS2_CHECK_DORMANT, + UHS2_SW_RESET, + UHS2_DETECT_INIT, + UHS2_DISABLE_CLK, + UHS2_ENABLE_CLK, + UHS2_POST_ATTACH_SD +}; + +/* UHS-II Device Registers */ +#define UHS2_DEV_CONFIG_REG 0x000 + +/* General Caps and Settings registers */ +#define UHS2_DEV_CONFIG_GEN_CAPS (UHS2_DEV_CONFIG_REG + 0x000) +#define UHS2_DEV_CONFIG_N_LANES_POS 8 +#define UHS2_DEV_CONFIG_N_LANES_MASK 0x3F +#define UHS2_DEV_CONFIG_2L_HD_FD 0x1 +#define UHS2_DEV_CONFIG_2D1U_FD 0x2 +#define UHS2_DEV_CONFIG_1D2U_FD 0x4 +#define UHS2_DEV_CONFIG_2D2U_FD 0x8 +#define UHS2_DEV_CONFIG_DADR_POS 14 +#define UHS2_DEV_CONFIG_DADR_MASK 0x1 +#define UHS2_DEV_CONFIG_APP_POS 16 +#define UHS2_DEV_CONFIG_APP_MASK 0xFF +#define UHS2_DEV_CONFIG_APP_SD_MEM 0x1 + +#define UHS2_DEV_CONFIG_GEN_SET (UHS2_DEV_CONFIG_REG + 0x008) +#define UHS2_DEV_CONFIG_GEN_SET_N_LANES_POS 8 +#define UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD 0x0 +#define UHS2_DEV_CONFIG_GEN_SET_2D1U_FD 0x2 +#define UHS2_DEV_CONFIG_GEN_SET_1D2U_FD 0x3 +#define UHS2_DEV_CONFIG_GEN_SET_2D2U_FD 0x4 +#define UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE (0x1 << 31) + +/* PHY Caps and Settings registers */ +#define UHS2_DEV_CONFIG_PHY_CAPS (UHS2_DEV_CONFIG_REG + 0x002) +#define UHS2_DEV_CONFIG_PHY_MINOR_MASK 0xF +#define UHS2_DEV_CONFIG_PHY_MAJOR_POS 4 +#define UHS2_DEV_CONFIG_PHY_MAJOR_MASK 0x3 +#define UHS2_DEV_CONFIG_CAN_HIBER_POS 15 +#define UHS2_DEV_CONFIG_CAN_HIBER_MASK 0x1 +#define UHS2_DEV_CONFIG_PHY_CAPS1 (UHS2_DEV_CONFIG_REG + 0x003) +#define UHS2_DEV_CONFIG_N_LSS_SYN_MASK 0xF +#define UHS2_DEV_CONFIG_N_LSS_DIR_POS 4 +#define UHS2_DEV_CONFIG_N_LSS_DIR_MASK 0xF + +#define UHS2_DEV_CONFIG_PHY_SET (UHS2_DEV_CONFIG_REG + 0x00A) +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_POS 6 +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_A 0x0 +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_B 0x1 + +/* LINK-TRAN Caps and Settings registers */ +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS (UHS2_DEV_CONFIG_REG + 0x004) +#define UHS2_DEV_CONFIG_LT_MINOR_MASK 0xF +#define UHS2_DEV_CONFIG_LT_MAJOR_POS 4 +#define UHS2_DEV_CONFIG_LT_MAJOR_MASK 0x3 +#define UHS2_DEV_CONFIG_N_FCU_POS 8 +#define UHS2_DEV_CONFIG_N_FCU_MASK 0xFF +#define UHS2_DEV_CONFIG_DEV_TYPE_POS 16 +#define UHS2_DEV_CONFIG_DEV_TYPE_MASK 0x7 +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_POS 20 +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK 0xFFF +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS1 (UHS2_DEV_CONFIG_REG + 0x005) +#define UHS2_DEV_CONFIG_N_DATA_GAP_MASK 0xFF + +#define UHS2_DEV_CONFIG_LINK_TRAN_SET (UHS2_DEV_CONFIG_REG + 0x00C) +#define UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN 0x200 +#define UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS 16 + +/* Preset register */ +#define UHS2_DEV_CONFIG_PRESET (UHS2_DEV_CONFIG_REG + 0x040) + +#define UHS2_DEV_INT_REG 0x100 + +#define UHS2_DEV_STATUS_REG 0x180 + +#define UHS2_DEV_CMD_REG 0x200 +#define UHS2_DEV_CMD_FULL_RESET (UHS2_DEV_CMD_REG + 0x000) +#define UHS2_DEV_CMD_GO_DORMANT_STATE (UHS2_DEV_CMD_REG + 0x001) +#define UHS2_DEV_CMD_DORMANT_HIBER (0x1 << 7) +#define UHS2_DEV_CMD_DEVICE_INIT (UHS2_DEV_CMD_REG + 0x002) +#define UHS2_DEV_CMD_ENUMERATE (UHS2_DEV_CMD_REG + 0x003) +#define UHS2_DEV_CMD_TRANS_ABORT (UHS2_DEV_CMD_REG + 0x004) + +#define UHS2_RCLK_MAX 52000000 +#define UHS2_RCLK_MIN 26000000 + +#endif /* LINUX_MMC_UHS2_H */ From patchwork Tue Feb 22 03:39:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 545809 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0C32DC433EF for ; Tue, 22 Feb 2022 03:40:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234225AbiBVDkt (ORCPT ); Mon, 21 Feb 2022 22:40:49 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:56248 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230249AbiBVDks (ORCPT ); Mon, 21 Feb 2022 22:40:48 -0500 Received: from mail-pg1-x532.google.com (mail-pg1-x532.google.com [IPv6:2607:f8b0:4864:20::532]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AE405240BE for ; Mon, 21 Feb 2022 19:40:22 -0800 (PST) Received: by mail-pg1-x532.google.com with SMTP id 27so10701306pgk.10 for ; Mon, 21 Feb 2022 19:40:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=sJ/Tg4NqxcmmBGY2LEJYmmLngKKIOsFPmTUyet+2pus=; b=qTVGalit/Zohkf29ljhVu2nzPWWLkLKy2FQ7c1pAMZ9JF6706G1s/5P42O1EUHuRI+ RmBtV1zGPi39tW8EnI7LY3i7EaEZrguHJ7BlDc79+IOaJcKuBJxMsrKyMi+amrxTcpqM UlBpUQB2QxdM/WiZRM1fAeeSeJ9rq6w/T0YFzcgfVeYjePKXZ2VvNDopYkjRnKu/s/Dv FjLByY3O0KBSy+bGjnKa+8m3mA/nMm3pTSQlYzjlNWoLemufHHOzrGLS2I5NIAWsfDnt ir0UNC8aVIG+OuauEUsJZ1zAxDMWs9e68bO8TXu+XnLSwAPoO/33kQH5wFn8oXcg12+J QMGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=sJ/Tg4NqxcmmBGY2LEJYmmLngKKIOsFPmTUyet+2pus=; b=K9hMm7NZ0/WtGZ6XtS+Xe8qTIYHtyHBq736nTC7ka8w8HpNMZt2ajTLBcmmD3lk/Ph fj5Ij0s+x9ugO5L71LIK0F79tp9H+V5T2dOVKLYlrECQGEMzR0YJHuN/pOKk7pac18x/ 0anuoipMe03QJx1uJcFAS4IM7KLa8VTeqc+AnP+8LsJBOFyPxmNgDvwaWirnjM+k3WW8 HoFZnaCRknOlfQ6lHbCZwb2Bf/CZht6Iqc5nurspd06GctrHggKpiVuSTENRl2eWTrWL qats4UxOyUabHAJ2lONZmNz+2vuTLAhhGGnMZ9eLEafR2FdcsK/fiNP1A5wd5OUKGWRr jFLg== X-Gm-Message-State: AOAM533wk+/sMzpaoqrb0qeDgevweDOdT+kStTEf5mGTk6EQLCUKAVuP l3uCGb+kRxIssMDKUmA5d8s= X-Google-Smtp-Source: ABdhPJxjoLrjeeOBGlA21q4D0MBuOdWQARC400tgVt0VFymLGXzDknWLd/ovgjPoALQLWlq7TYuIyQ== X-Received: by 2002:a05:6a00:84b:b0:4f2:a695:e356 with SMTP id q11-20020a056a00084b00b004f2a695e356mr2402667pfk.0.1645501221969; Mon, 21 Feb 2022 19:40:21 -0800 (PST) Received: from localhost.localdomain (220-128-190-163.hinet-ip.hinet.net. [220.128.190.163]) by smtp.gmail.com with ESMTPSA id ng16sm703542pjb.12.2022.02.21.19.40.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Feb 2022 19:40:21 -0800 (PST) From: Jason Lai To: ulf.hansson@linaro.org, takahiro.akashi@linaro.org, adrian.hunter@intel.com Cc: linux-mmc@vger.kernel.org, dlunev@chromium.org, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, jasonlai.genesyslogic@gmail.com Subject: [PATCH V3 6/7] mmc: Implement content of UHS-II card initialization functions Date: Tue, 22 Feb 2022 11:39:30 +0800 Message-Id: <20220222033931.237638-7-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> References: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Jason Lai UHS-II card initialization flow is divided into 2 categories: PHY & Card. Part 1 - PHY Initialization: Every host controller may need their own avtivation operation to establish LINK between controller and card. So we add a new member function(uhs2_detect_init) in struct mmc_host_ops for host controller use. Part 2 - Card Initialization: This part can be divided into 6 substeps. 1. Send UHS-II CCMD DEVICE_INIT to card. 2. Send UHS-II CCMD ENUMERATE to card. 3. Send UHS-II Native Read CCMD to obtain capabilities in CFG_REG of card. 4. Host compares capabilities of host controller and card, then write the negotiated values to Setting field in CFG_REG of card through UHS-II Native Write CCMD. 5. Switch host controller's clock to Range B if it is supported by both host controller and card. 6. Execute legacy SD initialization flow. Part 3 - Provide a function to tranaform legacy SD command packet into UHS-II SD-TRAN DCMD packet. Most of the code added above came from Intel's original patch[3]. [3] https://patchwork.kernel.org/project/linux-mmc/patch/1419672479-30852-2- git-send-email-yi.y.sun@intel.com/ Signed-off-by: Jason Lai --- drivers/mmc/core/sd_uhs2.c | 835 ++++++++++++++++++++++++++++++++++++- 1 file changed, 817 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/core/sd_uhs2.c b/drivers/mmc/core/sd_uhs2.c index 800957f74632..f1e8e30301eb 100644 --- a/drivers/mmc/core/sd_uhs2.c +++ b/drivers/mmc/core/sd_uhs2.c @@ -3,6 +3,7 @@ * Copyright (C) 2021 Linaro Ltd * * Author: Ulf Hansson + * Author: Jason Lai * * Support for SD UHS-II cards */ @@ -10,19 +11,31 @@ #include #include +#include +#include #include "core.h" #include "bus.h" +#include "card.h" #include "sd.h" +#include "sd_ops.h" #include "mmc_ops.h" +#include "sd_uhs2.h" static const unsigned int sd_uhs2_freqs[] = { 52000000, 26000000 }; static int sd_uhs2_set_ios(struct mmc_host *host) { struct mmc_ios *ios = &host->ios; + int err = 0; - return host->ops->uhs2_set_ios(host, ios); + pr_debug("%s: clock %uHz powermode %u Vdd %u timing %u\n", + mmc_hostname(host), ios->clock, ios->power_mode, ios->vdd, + ios->timing); + + host->ops->set_ios(host, ios); + + return err; } static int sd_uhs2_power_up(struct mmc_host *host) @@ -45,6 +58,43 @@ static void sd_uhs2_power_off(struct mmc_host *host) sd_uhs2_set_ios(host); } +/** + * sd_uhs2_cmd_assemble() - build up UHS-II command packet which is embedded in + * mmc_command structure + * @cmd: MMC command to executed + * @uhs2_cmd: UHS2 command corresponded to MMC command + * @header: Header field of UHS-II command cxpacket + * @arg: Argument field of UHS-II command packet + * @payload: Payload field of UHS-II command packet + * @plen: Payload length + * @resp: Response buffer is allocated by caller and it is used to keep + * the response of CM-TRAN command. For SD-TRAN command, uhs2_resp + * should be null and SD-TRAN command response should be stored in + * resp of mmc_command. + * @resp_len: Response buffer length + * + * The uhs2_command structure contains message packets which are transmited/ + * received on UHS-II bus. This function fills in the contents of uhs2_command + * structure and embededs UHS2 command into mmc_command structure, which is used + * in legacy SD operation functions. + * + */ +static void sd_uhs2_cmd_assemble(struct mmc_command *cmd, + struct uhs2_command *uhs2_cmd, + u16 header, u16 arg, u32 *payload, + u8 plen, u8 *resp, u8 resp_len) +{ + uhs2_cmd->header = header; + uhs2_cmd->arg = arg; + uhs2_cmd->payload = payload; + uhs2_cmd->payload_len = plen * sizeof(u32); + uhs2_cmd->packet_len = uhs2_cmd->payload_len + 4; + + cmd->uhs2_cmd = uhs2_cmd; + cmd->uhs2_resp = resp; + cmd->uhs2_resp_len = resp_len; +} + /* * Run the phy initialization sequence, which mainly relies on the UHS-II host * to check that we reach the expected electrical state, between the host and @@ -52,7 +102,15 @@ static void sd_uhs2_power_off(struct mmc_host *host) */ static int sd_uhs2_phy_init(struct mmc_host *host) { - return 0; + int err = 0; + + err = host->ops->uhs2_host_operation(host, UHS2_DETECT_INIT); + if (err) { + pr_err("%s: failed to initial phy for UHS-II!\n", + mmc_hostname(host)); + } + + return err; } /* @@ -61,6 +119,77 @@ static int sd_uhs2_phy_init(struct mmc_host *host) */ static int sd_uhs2_dev_init(struct mmc_host *host) { + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u32 cnt; + u32 dap, gap, resp_gap; + u16 header = 0, arg = 0; + u32 payload[1]; + u8 plen = 1; + u8 gd = 0, cf = 1; + u8 resp[6] = {0}; + u8 resp_len = 6; + int err; + + dap = host->uhs2_caps.dap; + gap = host->uhs2_caps.gap; + + header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD; + arg = ((UHS2_DEV_CMD_DEVICE_INIT & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_4B | + (UHS2_DEV_CMD_DEVICE_INIT >> 8); + + /* + * Refer to UHS-II Addendum Version 1.02 section 6.3.1. + * Max. time from DEVICE_INIT CCMD EOP reception on Device + * Rx to its SOP transmission on Device Tx(Tfwd_init_cmd) is + * 1 second. + */ + cmd.busy_timeout = 1000; + + /* + * Refer to UHS-II Addendum Version 1.02 section 6.2.6.3. + * When the number of the DEVICE_INIT commands is reach to + * 30 tiems, Host shall stop issuing DEVICE_INIT command + * and regard it as an error. + */ + for (cnt = 0; cnt < 30; cnt++) { + payload[0] = ((dap & 0xF) << 12) | + (cf << 11) | + ((gd & 0xF) << 4) | + (gap & 0xF); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, plen, resp, resp_len); + + err = mmc_wait_for_cmd(host, &cmd, 0); + + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + if (resp[3] != (UHS2_DEV_CMD_DEVICE_INIT & 0xFF)) { + pr_err("%s: DEVICE_INIT response is wrong!\n", + mmc_hostname(host)); + return -EIO; + } + + if (resp[5] & 0x8) { + host->uhs2_caps.group_desc = gd; + break; + } + resp_gap = resp[4] & 0x0F; + if (gap == resp_gap) + gd++; + } + if (cnt == 30) { + pr_err("%s: DEVICE_INIT fail, already 30 times!\n", + mmc_hostname(host)); + return -EIO; + } + return 0; } @@ -71,16 +200,168 @@ static int sd_uhs2_dev_init(struct mmc_host *host) */ static int sd_uhs2_enum(struct mmc_host *host, u32 *node_id) { + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u16 header = 0, arg = 0; + u32 payload[1]; + u8 plen = 1; + u8 id_f = 0xF, id_l = 0x0; + u8 resp[8] = {0}; + u8 resp_len = 8; + int err; + + header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD; + arg = ((UHS2_DEV_CMD_ENUMERATE & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_4B | + (UHS2_DEV_CMD_ENUMERATE >> 8); + + payload[0] = (id_f << 4) | id_l; + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, plen, resp, resp_len); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + if (resp[3] != (UHS2_DEV_CMD_ENUMERATE & 0xFF)) { + pr_err("%s: ENUMERATE response is wrong!\n", + mmc_hostname(host)); + return -EIO; + } + + id_f = (resp[4] >> 4) & 0xF; + id_l = resp[4] & 0xF; + *node_id = id_f; + return 0; } /* - * Read the UHS-II configuration registers (CFG_REG) of the card, by sending it - * commands and by parsing the responses. Store a copy of the relevant data in - * card->uhs2_config. + * Read the UHS-II configuration registers (CFG_REG) from card and store these + * configurations to card->uhs2_config. */ static int sd_uhs2_config_read(struct mmc_host *host, struct mmc_card *card) { + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u16 header = 0, arg = 0; + u32 cap; + int err; + + header = UHS2_NATIVE_PACKET | + UHS2_PACKET_TYPE_CCMD | + card->uhs2_config.node_id; + arg = ((UHS2_DEV_CONFIG_GEN_CAPS & 0xFF) << 8) | + UHS2_NATIVE_CMD_READ | + UHS2_NATIVE_CMD_PLEN_4B | + (UHS2_DEV_CONFIG_GEN_CAPS >> 8); + + /* There is no payload because per spec, there should be + * no payload field for read CCMD. + * Plen is set in arg. Per spec, plen for read CCMD + * represents the len of read data which is assigned in payload + * of following RES (p136). + */ + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, NULL, 0, NULL, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + cap = cmd.resp[0]; + card->uhs2_config.n_lanes = + (cap >> UHS2_DEV_CONFIG_N_LANES_POS) & + UHS2_DEV_CONFIG_N_LANES_MASK; + card->uhs2_config.dadr_len = + (cap >> UHS2_DEV_CONFIG_DADR_POS) & + UHS2_DEV_CONFIG_DADR_MASK; + card->uhs2_config.app_type = + (cap >> UHS2_DEV_CONFIG_APP_POS) & + UHS2_DEV_CONFIG_APP_MASK; + + arg = ((UHS2_DEV_CONFIG_PHY_CAPS & 0xFF) << 8) | + UHS2_NATIVE_CMD_READ | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_PHY_CAPS >> 8); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, NULL, 0, NULL, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + cap = cmd.resp[0]; + card->uhs2_config.phy_minor_rev = + cap & UHS2_DEV_CONFIG_PHY_MINOR_MASK; + card->uhs2_config.phy_major_rev = + (cap >> UHS2_DEV_CONFIG_PHY_MAJOR_POS) & + UHS2_DEV_CONFIG_PHY_MAJOR_MASK; + card->uhs2_config.can_hibernate = + (cap >> UHS2_DEV_CONFIG_CAN_HIBER_POS) & + UHS2_DEV_CONFIG_CAN_HIBER_MASK; + + cap = cmd.resp[1]; + card->uhs2_config.n_lss_sync = + cap & UHS2_DEV_CONFIG_N_LSS_SYN_MASK; + card->uhs2_config.n_lss_dir = + (cap >> UHS2_DEV_CONFIG_N_LSS_DIR_POS) & + UHS2_DEV_CONFIG_N_LSS_DIR_MASK; + if (card->uhs2_config.n_lss_sync == 0) + card->uhs2_config.n_lss_sync = 16 << 2; + else + card->uhs2_config.n_lss_sync <<= 2; + + if (card->uhs2_config.n_lss_dir == 0) + card->uhs2_config.n_lss_dir = 16 << 3; + else + card->uhs2_config.n_lss_dir <<= 3; + + arg = ((UHS2_DEV_CONFIG_LINK_TRAN_CAPS & 0xFF) << 8) | + UHS2_NATIVE_CMD_READ | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_LINK_TRAN_CAPS >> 8); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, NULL, 0, NULL, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + cap = cmd.resp[0]; + card->uhs2_config.link_minor_rev = + cap & UHS2_DEV_CONFIG_LT_MINOR_MASK; + card->uhs2_config.link_major_rev = + (cap >> UHS2_DEV_CONFIG_LT_MAJOR_POS) & + UHS2_DEV_CONFIG_LT_MAJOR_MASK; + card->uhs2_config.n_fcu = + (cap >> UHS2_DEV_CONFIG_N_FCU_POS) & + UHS2_DEV_CONFIG_N_FCU_MASK; + card->uhs2_config.dev_type = + (cap >> UHS2_DEV_CONFIG_DEV_TYPE_POS) & + UHS2_DEV_CONFIG_DEV_TYPE_MASK; + card->uhs2_config.maxblk_len = + (cap >> UHS2_DEV_CONFIG_MAX_BLK_LEN_POS) & + UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK; + + cap = cmd.resp[1]; + card->uhs2_config.n_data_gap = + cap & UHS2_DEV_CONFIG_N_DATA_GAP_MASK; + if (card->uhs2_config.n_fcu == 0) + card->uhs2_config.n_fcu = 256; + return 0; } @@ -95,9 +376,317 @@ static int sd_uhs2_config_read(struct mmc_host *host, struct mmc_card *card) */ static int sd_uhs2_config_write(struct mmc_host *host, struct mmc_card *card) { + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u16 header = 0, arg = 0; + u32 payload[2]; + u8 nMinDataGap; + u8 plen; + int err; + u8 resp[5] = {0}; + u8 resp_len = 5; + + header = UHS2_NATIVE_PACKET | + UHS2_PACKET_TYPE_CCMD | card->uhs2_config.node_id; + arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_GEN_SET >> 8); + + if (card->uhs2_config.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD && + host->uhs2_caps.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD) { + /* Support HD */ + host->uhs2_caps.flags |= MMC_UHS2_2L_HD; + nMinDataGap = 1; + } else { + /* Only support 2L-FD so far */ + host->uhs2_caps.flags &= ~MMC_UHS2_2L_HD; + nMinDataGap = 3; + } + + /* + * Most UHS-II cards only support FD and 2L-HD mode. Other lane numbers + * defined in UHS-II addendem Ver1.01 are optional. + */ + host->uhs2_caps.n_lanes_set = UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD; + card->uhs2_config.n_lanes_set = UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD; + + plen = 2; + payload[0] = card->uhs2_config.n_lanes_set << + UHS2_DEV_CONFIG_N_LANES_POS; + payload[1] = 0; + payload[0] = cpu_to_be32(payload[0]); + payload[1] = cpu_to_be32(payload[1]); + + /* + * There is no payload because per spec, there should be + * no payload field for read CCMD. + * Plen is set in arg. Per spec, plen for read CCMD + * represents the len of read data which is assigned in payload + * of following RES (p136). + */ + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, plen, NULL, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + arg = ((UHS2_DEV_CONFIG_PHY_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_PHY_SET >> 8); + + if (host->uhs2_caps.speed_range == UHS2_DEV_CONFIG_PHY_SET_SPEED_B) { + host->uhs2_caps.flags |= MMC_UHS2_SPEED_B; + card->uhs2_config.speed_range_set = + UHS2_DEV_CONFIG_PHY_SET_SPEED_B; + } else { + card->uhs2_config.speed_range_set = UHS2_DEV_CONFIG_PHY_SET_SPEED_A; + host->uhs2_caps.flags &= ~MMC_UHS2_SPEED_B; + } + + payload[0] = card->uhs2_config.speed_range_set << UHS2_DEV_CONFIG_PHY_SET_SPEED_POS; + + card->uhs2_config.n_lss_sync_set = (max(card->uhs2_config.n_lss_sync, + host->uhs2_caps.n_lss_sync) >> 2) & + UHS2_DEV_CONFIG_N_LSS_SYN_MASK; + host->uhs2_caps.n_lss_sync_set = card->uhs2_config.n_lss_sync_set; + + card->uhs2_config.n_lss_dir_set = (max(card->uhs2_config.n_lss_dir, + host->uhs2_caps.n_lss_dir) >> 3) & + UHS2_DEV_CONFIG_N_LSS_DIR_MASK; + host->uhs2_caps.n_lss_dir_set = card->uhs2_config.n_lss_dir_set; + + payload[1] = (card->uhs2_config.n_lss_dir_set << UHS2_DEV_CONFIG_N_LSS_DIR_POS) | + card->uhs2_config.n_lss_sync_set; + payload[0] = cpu_to_be32(payload[0]); + payload[1] = cpu_to_be32(payload[1]); + + resp_len = 4; + memset(resp, 0, sizeof(resp)); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, plen, resp, resp_len); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + if ((resp[2] & 0x80)) { + pr_err("%s: %s: UHS2 CMD not accepted, resp= 0x%x!\n", + mmc_hostname(host), __func__, resp[2]); + return -EIO; + } + + arg = ((UHS2_DEV_CONFIG_LINK_TRAN_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_LINK_TRAN_SET >> 8); + + plen = 2; + + if (card->uhs2_config.app_type == UHS2_DEV_CONFIG_APP_SD_MEM) + card->uhs2_config.maxblk_len_set = UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN; + else + card->uhs2_config.maxblk_len_set = min(card->uhs2_config.maxblk_len, + host->uhs2_caps.maxblk_len); + host->uhs2_caps.maxblk_len_set = card->uhs2_config.maxblk_len_set; + + card->uhs2_config.n_fcu_set = min(card->uhs2_config.n_fcu, host->uhs2_caps.n_fcu); + host->uhs2_caps.n_fcu_set = card->uhs2_config.n_fcu_set; + + card->uhs2_config.n_data_gap_set = max(nMinDataGap, card->uhs2_config.n_data_gap); + host->uhs2_caps.n_data_gap_set = card->uhs2_config.n_data_gap_set; + + host->uhs2_caps.max_retry_set = 3; + card->uhs2_config.max_retry_set = host->uhs2_caps.max_retry_set; + + payload[0] = (card->uhs2_config.maxblk_len_set << UHS2_DEV_CONFIG_MAX_BLK_LEN_POS) | + (card->uhs2_config.max_retry_set << UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS) | + (card->uhs2_config.n_fcu_set << UHS2_DEV_CONFIG_N_FCU_POS); + payload[1] = card->uhs2_config.n_data_gap_set; + payload[0] = cpu_to_be32(payload[0]); + payload[1] = cpu_to_be32(payload[1]); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, plen, NULL, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_GEN_SET >> 8); + + plen = 2; + payload[0] = 0; + payload[1] = UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE; + payload[0] = cpu_to_be32(payload[0]); + payload[1] = cpu_to_be32(payload[1]); + + resp_len = 5; + memset(resp, 0, sizeof(resp)); + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, plen, resp, resp_len); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + /* Set host Config Setting registers */ + if (!host->ops->uhs2_host_operation(host, UHS2_SET_CONFIG)) { + pr_err("%s: %s: UHS2 SET_CONFIG fail!\n", mmc_hostname(host), __func__); + return -EIO; + } + + return 0; +} + +static int sd_uhs2_go_dormant(struct mmc_host *host, bool hibernate, u32 node_id) +{ + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u16 header = 0, arg = 0; + u32 payload[1]; + u8 plen = 1; + int err; + + /* Disable Normal INT */ + if (!host->ops->uhs2_host_operation(host, UHS2_DISABLE_INT)) { + pr_err("%s: %s: UHS2 DISABLE_INT fail!\n", + mmc_hostname(host), __func__); + return -EIO; + } + + header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | node_id; + + arg = ((UHS2_DEV_CMD_GO_DORMANT_STATE & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_4B | + (UHS2_DEV_CMD_GO_DORMANT_STATE >> 8); + + if (hibernate) + payload[0] = UHS2_DEV_CMD_DORMANT_HIBER; + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, plen, NULL, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + /* Check Dormant State in Present */ + if (!host->ops->uhs2_host_operation(host, UHS2_CHECK_DORMANT)) { + pr_err("%s: %s: UHS2 GO_DORMANT_STATE fail!\n", + mmc_hostname(host), __func__); + return -EIO; + } + + host->ops->uhs2_host_operation(host, UHS2_DISABLE_CLK); + return 0; } +static int sd_uhs2_change_speed(struct mmc_host *host, u32 node_id) +{ + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u16 header = 0, arg = 0; + int err; + int timeout = 100; + + /* Change Speed Range at controller side. */ + if (!host->ops->uhs2_host_operation(host, UHS2_SET_SPEED_B)) { + pr_err("%s: %s: UHS2 SET_SPEED fail!\n", + mmc_hostname(host), __func__); + return -EIO; + } + + err = sd_uhs2_go_dormant(host, false, node_id); + if (err) { + pr_err("%s: %s: UHS2 GO_DORMANT_STATE fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + /* restore sd clock */ + mmc_delay(5); + host->ops->uhs2_host_operation(host, UHS2_ENABLE_CLK); + + /* Enable Normal INT */ + if (!host->ops->uhs2_host_operation(host, UHS2_ENABLE_INT)) { + pr_err("%s: %s: UHS2 ENABLE_INT fail!\n", + mmc_hostname(host), __func__); + return -EIO; + } + + /* + * According to UHS-II Addendum Version 1.01, chapter 6.2.3, wait card + * switch to Active State + */ + header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | node_id; + arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_READ | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_GEN_SET >> 8); + do { + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, NULL, 0, NULL, 0); + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return -EIO; + } + + if (cmd.resp[1] & UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE) + break; + + timeout--; + if (timeout == 0) { + pr_err("%s: %s: Not switch to Active in 100 ms\n", + mmc_hostname(host), __func__); + return -EIO; + } + + mmc_delay(1); + } while (1); + + return 0; +} + +static int sd_uhs2_get_ro(struct mmc_host *host) +{ + int ro; + + /* + * Some systems don't feature a write-protect pin and don't need one. + * E.g. because they only have micro-SD card slot. For those systems + * assume that the SD card is always read-write. + */ + if (host->caps2 & MMC_CAP2_NO_WRITE_PROTECT) + return 0; + + if (!host->ops->get_ro) + return -1; + + ro = host->ops->get_ro(host); + + return ro; +} + /* * Initialize the UHS-II card through the SD-TRAN transport layer. This enables * commands/requests to be backwards compatible through the legacy SD protocol. @@ -107,9 +696,127 @@ static int sd_uhs2_config_write(struct mmc_host *host, struct mmc_card *card) */ static int sd_uhs2_legacy_init(struct mmc_host *host, struct mmc_card *card) { + int err; + u32 cid[4]; + u32 ocr; + u32 rocr = 0; + int ro; + + WARN_ON(!host->claimed); + + /* Send CMD0 to reset SD card */ + mmc_go_idle(host); + + /* Send CMD8 to communicate SD interface operation condition */ + err = mmc_send_if_cond(host, host->ocr_avail); + if (err) { + pr_err("%s: %s: SEND_IF_COND fail!\n", + mmc_hostname(host), __func__); + return err; + } + + /* + * Probe SD card working voltage. + */ + err = mmc_send_app_op_cond(host, 0, &ocr); + if (err) { + pr_err("%s: %s: SD_SEND_OP_COND fail!\n", + mmc_hostname(host), __func__); + return err; + } + card->ocr = ocr; + + /* + * Some SD cards claims an out of spec VDD voltage range. Let's treat + * these bits as being in-valid and especially also bit7. + */ + ocr &= ~0x7FFF; + rocr = mmc_select_voltage(host, ocr); + + /* + * Some cards have zero value of rocr in UHS-II mode. Assign host's + * ocr value to rocr. + */ + if (!rocr) { + if (host->ocr_avail) { + rocr = host->ocr_avail; + } else { + pr_err("%s: %s: there is no valid OCR.\n", + mmc_hostname(host), __func__); + return -EINVAL; + } + } + + /* Wait SD power on ready */ + ocr = rocr; + err = mmc_send_app_op_cond(host, ocr, &rocr); + if (err) { + pr_err("%s: %s: SD_SEND_OP_COND fail!\n", mmc_hostname(host), + __func__); + return err; + } + + err = mmc_send_cid(host, cid); + if (err) { + pr_err("%s: %s: SD_SEND_CID fail!\n", mmc_hostname(host), + __func__); + return err; + } + memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); + + /* + * Call the optional HC's init_card function to handle quirks. + */ + if (host->ops->init_card) + host->ops->init_card(host, card); + + /* + * For native busses: get card RCA and quit open drain mode. + */ + err = mmc_send_relative_addr(host, &card->rca); + if (err) { + pr_err("%s: %s: SD_SEND_RCA fail!\n", mmc_hostname(host), + __func__); + return err; + } + + err = mmc_sd_get_csd(card); + if (err) { + pr_err("%s: %s: SD_SEND_CSD fail!\n", mmc_hostname(host), + __func__); + return err; + } + + /* + * Select card, as all following commands rely on that. + */ + err = mmc_select_card(card); + if (err) { + pr_err("%s: %s: SD_SEL_DSEL fail!\n", mmc_hostname(host), + __func__); + return err; + } + + /* + * Check if read-only switch is active. + */ + ro = sd_uhs2_get_ro(host); + if (ro < 0) { + pr_warn("%s: host does not support read-only switch, assuming write-enable\n", + mmc_hostname(host)); + } else if (ro > 0) { + mmc_card_set_readonly(card); + } + return 0; } +static void sd_uhs2_remove(struct mmc_host *host) +{ + mmc_remove_card(host->card); + host->card = NULL; +} + /* * Allocate the data structure for the mmc_card and run the UHS-II specific * initialization sequence. @@ -121,16 +828,21 @@ static int sd_uhs2_init_card(struct mmc_host *host) int err; err = sd_uhs2_dev_init(host); - if (err) + if (err) { + pr_err("%s: UHS2 DEVICE_INIT fail!\n", mmc_hostname(host)); return err; + } err = sd_uhs2_enum(host, &node_id); - if (err) + if (err) { + pr_err("%s: UHS2 ENUMERATE fail!\n", mmc_hostname(host)); return err; + } card = mmc_alloc_card(host, &sd_type); if (IS_ERR(card)) return PTR_ERR(card); + host->card = card; card->uhs2_config.node_id = node_id; card->type = MMC_TYPE_SD; @@ -139,6 +851,16 @@ static int sd_uhs2_init_card(struct mmc_host *host) if (err) goto err; + /* Change to Speed Range B if it is supported */ + if (host->uhs2_caps.flags & MMC_UHS2_SPEED_B) { + err = sd_uhs2_change_speed(host, node_id); + if (err) { + pr_err("%s: %s: UHS2 sd_uhs2_change_speed() fail!\n", + mmc_hostname(host), __func__); + return err; + } + } + err = sd_uhs2_config_write(host, card); if (err) goto err; @@ -147,20 +869,13 @@ static int sd_uhs2_init_card(struct mmc_host *host) if (err) goto err; - host->card = card; return 0; err: - mmc_remove_card(card); + sd_uhs2_remove(host); return err; } -static void sd_uhs2_remove(struct mmc_host *host) -{ - mmc_remove_card(host->card); - host->card = NULL; -} - static int sd_uhs2_alive(struct mmc_host *host) { return mmc_send_status(host->card, NULL); @@ -214,6 +929,70 @@ static int sd_uhs2_hw_reset(struct mmc_host *host) return 0; } +/* + * sd_uhs2_prepare_cmd - prepare for SD command packet + * @host: MMC host + * @mrq: MMC request + * + * Initialize and fill in a header and a payload of SD command packet. + * The caller should allocate uhs2_command in host->cmd->uhs2_cmd in + * advance. + * + * Return: 0 on success, non-zero error on failure + */ +int sd_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq) +{ + struct mmc_command *cmd; + struct uhs2_command *uhs2_cmd; + u16 header = 0, arg = 0; + u32 *payload; + u8 plen = 0; + + cmd = mrq->cmd; + header = host->card->uhs2_config.node_id; + if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) + header |= UHS2_PACKET_TYPE_DCMD; + else + header |= UHS2_PACKET_TYPE_CCMD; + + arg = cmd->opcode << UHS2_SD_CMD_INDEX_POS; + if (host->uhs2_caps.flags & MMC_UHS2_APP_CMD) { + arg |= UHS2_SD_CMD_APP; + host->uhs2_caps.flags &= ~MMC_UHS2_APP_CMD; + } + + uhs2_cmd = cmd->uhs2_cmd; + payload = uhs2_cmd->payload; + plen = 2; /* at the maximum */ + + if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC && + !cmd->uhs2_tmode0_flag) { + if (host->uhs2_caps.flags & MMC_UHS2_2L_HD) + arg |= UHS2_DCMD_2L_HD_MODE; + + arg |= UHS2_DCMD_LM_TLEN_EXIST; + + if (cmd->data->blocks == 1 && + cmd->data->blksz != 512 && + cmd->opcode != MMC_READ_SINGLE_BLOCK && + cmd->opcode != MMC_WRITE_BLOCK) { + arg |= UHS2_DCMD_TLUM_BYTE_MODE; + payload[1] = cpu_to_be32(cmd->data->blksz); + } else { + payload[1] = cpu_to_be32(cmd->data->blocks); + } + } else { + plen = 1; + } + + payload[0] = cpu_to_be32(cmd->arg); + + sd_uhs2_cmd_assemble(cmd, uhs2_cmd, header, arg, payload, plen, NULL, 0); + + return 0; +} +EXPORT_SYMBOL_GPL(sd_uhs2_prepare_cmd); + static const struct mmc_bus_ops sd_uhs2_ops = { .remove = sd_uhs2_remove, .alive = sd_uhs2_alive, @@ -251,18 +1030,33 @@ static int sd_uhs2_attach(struct mmc_host *host) goto remove_card; mmc_claim_host(host); + + host->ops->uhs2_host_operation(host, UHS2_POST_ATTACH_SD); + return 0; remove_card: - mmc_remove_card(host->card); - host->card = NULL; + sd_uhs2_remove(host); mmc_claim_host(host); - mmc_detach_bus(host); + err: + mmc_detach_bus(host); sd_uhs2_power_off(host); + if (host->uhs2_caps.flags & MMC_UHS2_INITIALIZED) + host->uhs2_caps.flags &= ~MMC_UHS2_INITIALIZED; + host->uhs2_caps.flags &= ~MMC_UHS2_SUPPORT; return err; } +/** + * mmc_attach_sd_uhs2 - select UHS2 interface + * @host: MMC host + * + * Try to select UHS2 interface and initialize the bus for a given + * frequency, @freq. + * + * Return: 0 on success, non-zero error on failure + */ int mmc_attach_sd_uhs2(struct mmc_host *host) { int i, err = 0; @@ -273,6 +1067,8 @@ int mmc_attach_sd_uhs2(struct mmc_host *host) /* Turn off the legacy SD interface before trying with UHS-II. */ mmc_power_off(host); + host->uhs2_caps.flags |= MMC_UHS2_SUPPORT; + /* * Start UHS-II initialization at 52MHz and possibly make a retry at * 26MHz according to the spec. It's required that the host driver @@ -280,6 +1076,9 @@ int mmc_attach_sd_uhs2(struct mmc_host *host) */ for (i = 0; i < ARRAY_SIZE(sd_uhs2_freqs); i++) { host->f_init = sd_uhs2_freqs[i]; + pr_info("%s: %s: trying to init UHS-II card at %u Hz\n", + mmc_hostname(host), __func__, host->f_init); + err = sd_uhs2_attach(host); if (!err) break; From patchwork Tue Feb 22 03:39:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 545145 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 81B99C433FE for ; Tue, 22 Feb 2022 03:40:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234283AbiBVDkv (ORCPT ); Mon, 21 Feb 2022 22:40:51 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:56262 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230249AbiBVDkt (ORCPT ); Mon, 21 Feb 2022 22:40:49 -0500 Received: from mail-pf1-x432.google.com (mail-pf1-x432.google.com [IPv6:2607:f8b0:4864:20::432]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BFF01240BF for ; Mon, 21 Feb 2022 19:40:25 -0800 (PST) Received: by mail-pf1-x432.google.com with SMTP id u16so10626060pfg.12 for ; Mon, 21 Feb 2022 19:40:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=NvjS1M3rcUh28hIfgWBVsCClvMhLur1EPoXMsswx40c=; b=kHR/KWxx+XeJNVhUZfXvLH9MJnsuRAewxhvW1xuVccBNWqjyHqARx27IyYJT2pz7UH W5SDbrIMfHPbij9kWO7mKsq58TZUqQ0WeB3zhFa7HNbfKGz2+S6IB5YEM2YIrup+mAPA 9FoQPcJOnJ4Cligp7rWjy7x8+DlOjQciNP631cyHEliZp4vv/45+RjgigPxTRGCrg6le e3sV4oEarW8tVQxWnsNbFt7h3dK/zR5vllCG9ZWbZJcu0zLEwy77dmONWMAY4vNV/LUt 0iSQhVz787m3bDJZffnrS4UYGef1dNI5jFZE+rrKiEcKHcMdfxw96a0byl+bdtx1j3+r WwbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=NvjS1M3rcUh28hIfgWBVsCClvMhLur1EPoXMsswx40c=; b=oh1gmMoF9ezItRbLblam2fhnxcvqQUAStVmdPtIm3+HsuRPlRoq2yaHKK2YKhyiUAT fn6k7c6aZZpW+JGBJNXvs5oFr67rJS/feoKgruTiF+o2DeyQDs9beSpR0DrX07E/a0PM jeZCj58MWnH3HAmwU3V8NPKym7qTgcbWPy4EDdcGMVYGq9Kv7ht3NtxYXI/x7TbgLF/T zADe32LGD6k/eZLFht7WDW1lXSq3/6K3QOWluCTglbINZld3jO5A1laEBTgrVUvnumjY JD2LAGHvIpID79yoha+Ubp/1cqbmxokibfJeFPX9Ag0Qp/Lf+iCxlzUyWjn0W88y6aNa FLtA== X-Gm-Message-State: AOAM532fuQz74AlJCTVJr3AE9xi+bJee+kF6Qjd0DbyqY8KWjzHL3iru iWx14UMJclCM59bKREDLDU4= X-Google-Smtp-Source: ABdhPJyFczlMKjCKBa0gmQGoP75Ta4TSGYCEiesDt5E4n6KGSu68DkXP4t6VTeFc2xKLBmm9Znp1jQ== X-Received: by 2002:a05:6a00:21cd:b0:4e1:b09b:18e8 with SMTP id t13-20020a056a0021cd00b004e1b09b18e8mr22713668pfj.60.1645501225296; Mon, 21 Feb 2022 19:40:25 -0800 (PST) Received: from localhost.localdomain (220-128-190-163.hinet-ip.hinet.net. [220.128.190.163]) by smtp.gmail.com with ESMTPSA id ng16sm703542pjb.12.2022.02.21.19.40.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 21 Feb 2022 19:40:25 -0800 (PST) From: Jason Lai To: ulf.hansson@linaro.org, takahiro.akashi@linaro.org, adrian.hunter@intel.com Cc: linux-mmc@vger.kernel.org, dlunev@chromium.org, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, jasonlai.genesyslogic@gmail.com Subject: [PATCH V3 7/7] mmc: core: Support UHS-II card access Date: Tue, 22 Feb 2022 11:39:31 +0800 Message-Id: <20220222033931.237638-8-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> References: <20220222033931.237638-1-jasonlai.genesyslogic@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Jason Lai Embed UHS-II access functionality into the MMC request processing flow. Signed-off-by: Jason Lai --- drivers/mmc/core/core.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index fc3d8d61a97c..d2dcaa64bf27 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -31,6 +31,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -42,6 +43,7 @@ #include "host.h" #include "sdio_bus.h" #include "pwrseq.h" +#include "sd_uhs2.h" #include "mmc_ops.h" #include "sd_ops.h" @@ -335,6 +337,8 @@ static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq) int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { + struct uhs2_command uhs2_cmd; + u32 payload[4]; /* for maximum size */ int err; init_completion(&mrq->cmd_completion); @@ -352,6 +356,13 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) if (err) return err; + if (host->uhs2_caps.flags & MMC_UHS2_SUPPORT && + host->uhs2_caps.flags & MMC_UHS2_INITIALIZED) { + uhs2_cmd.payload = payload; + mrq->cmd->uhs2_cmd = &uhs2_cmd; + sd_uhs2_prepare_cmd(host, mrq); + } + led_trigger_event(host->led, LED_FULL); __mmc_start_request(host, mrq); @@ -431,6 +442,8 @@ EXPORT_SYMBOL(mmc_wait_for_req_done); */ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq) { + struct uhs2_command uhs2_cmd; + u32 payload[4]; /* for maximum size */ int err; /* @@ -451,6 +464,13 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq) if (err) goto out_err; + if (host->uhs2_caps.flags & MMC_UHS2_SUPPORT && + host->uhs2_caps.flags & MMC_UHS2_INITIALIZED) { + uhs2_cmd.payload = payload; + mrq->cmd->uhs2_cmd = &uhs2_cmd; + sd_uhs2_prepare_cmd(host, mrq); + } + err = host->cqe_ops->cqe_request(host, mrq); if (err) goto out_err; @@ -899,8 +919,10 @@ static inline void mmc_set_ios(struct mmc_host *host) */ void mmc_set_chip_select(struct mmc_host *host, int mode) { - host->ios.chip_select = mode; - mmc_set_ios(host); + if (!(host->uhs2_caps.flags & MMC_UHS2_INITIALIZED)) { + host->ios.chip_select = mode; + mmc_set_ios(host); + } } /*