From patchwork Wed Nov 16 10:51:16 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 82472 Delivered-To: patches@linaro.org Received: by 10.140.97.165 with SMTP id m34csp82390qge; Wed, 16 Nov 2016 02:51:39 -0800 (PST) X-Received: by 10.194.122.65 with SMTP id lq1mr1476536wjb.12.1479293499298; Wed, 16 Nov 2016 02:51:39 -0800 (PST) Return-Path: Received: from mail-wm0-x229.google.com (mail-wm0-x229.google.com. [2a00:1450:400c:c09::229]) by mx.google.com with ESMTPS id r73si6731934wmb.104.2016.11.16.02.51.39 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Nov 2016 02:51:39 -0800 (PST) Received-SPF: pass (google.com: domain of ulf.hansson@linaro.org designates 2a00:1450:400c:c09::229 as permitted sender) client-ip=2a00:1450:400c:c09::229; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: domain of ulf.hansson@linaro.org designates 2a00:1450:400c:c09::229 as permitted sender) smtp.mailfrom=ulf.hansson@linaro.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: by mail-wm0-x229.google.com with SMTP id f82so64232130wmf.1 for ; Wed, 16 Nov 2016 02:51:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=RvnV1JrpQB2KyVcc/cI1s1q7defAALoJ90fCuGJ1B7I=; b=h543aitJi5nYkvgrovBrW8NmRfqSO9qGiI7Ueb/A3V0xv4XCO8EzPXi/1lVm4KGqcz Ftqokmonrnt9OKS8gfX/iW4SJHJot40SXJShytlK5045zAmOqpm17+zgr/f00N9SWQwE 4AdAVKnxxWBTiNVUR2ui6VwGAFtl/Yrrso5ns= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=RvnV1JrpQB2KyVcc/cI1s1q7defAALoJ90fCuGJ1B7I=; b=lgian9vZPlvtUbhCpLF2Bbg5IMqKavvu7K1NOsRx/jdrxWRoUFy9eKOe4TACaPpppq YpHg78oIkzssBI9jHVFsMTLE1iJ+bKmdCu6NjscqoyvNfGe5f+VxWYcU9sqH6yNo92LY bYmvrP4VhliXkFuo38fM4GDuLyqE1O3vHVMtgRxmIajS/nHh1r9NnAos6A25Ph42iQWp 2T+8JEKvluGwmMxvsVWhL0BBL3A+dBQvpa/SBCnaVd8ywt0Taw5Fjv0TKYv1GkB+JfQr RFYXVFt3qkpOBW1VCKBHgbUWvkomyH5gM7B6sRyI4gv7OO+5MnMG9GFIk9djYQJuzNIG DGgQ== X-Gm-Message-State: ABUngvdAoIgalG61IobVoudx91SJzoe/ofKFTlweSl7FjeHssfSctT4+paaN71kTKiC4KCj86v4= X-Received: by 10.25.25.204 with SMTP id 195mr236874lfz.84.1479293498824; Wed, 16 Nov 2016 02:51:38 -0800 (PST) Return-Path: Received: from uffe-Latitude-E6430s.ideon.se ([85.235.10.227]) by smtp.gmail.com with ESMTPSA id 34sm7711369lja.25.2016.11.16.02.51.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 16 Nov 2016 02:51:37 -0800 (PST) From: Ulf Hansson To: linux-mmc@vger.kernel.org, Ulf Hansson Cc: Jaehoon Chung , Adrian Hunter , Linus Walleij , Chaotian Jing , Stephen Boyd , Michael Walle , Yong Mao , Shawn Lin Subject: [PATCH 4/9] mmc: core: Enable __mmc_switch() to change bus speed timing for the host Date: Wed, 16 Nov 2016 11:51:16 +0100 Message-Id: <1479293481-20186-5-git-send-email-ulf.hansson@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1479293481-20186-1-git-send-email-ulf.hansson@linaro.org> References: <1479293481-20186-1-git-send-email-ulf.hansson@linaro.org> In cases when a speed mode change is requested for mmc cards, a CMD6 is sent by calling __mmc_switch() during the card initialization. The CMD6 leads to the card entering a busy period. When that is completed, the host must parse the CMD6 status to find out whether the change of the speed mode succeeded. To enable the mmc core to poll the card by using CMD13 to find out when the busy period is completed, it's reasonable to make sure polling is done by having the mmc host and the mmc card, being configured to operate at the same selected bus speed timing. Therefore, let's extend __mmc_switch() to take yet another parameter, which allow its callers to update the bus speed timing of the mmc host. In this way, __mmc_switch() also becomes capable of reading and validating the CMD6 status by sending a CMD13, in cases when that's desired. If __mmc_switch() encounters a failure, we make sure to restores the old bus speed timing for the mmc host, before propagating the error code. Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 2 +- drivers/mmc/core/mmc.c | 18 +++++++++--------- drivers/mmc/core/mmc_ops.c | 20 +++++++++++++++----- drivers/mmc/core/mmc_ops.h | 4 ++-- 4 files changed, 27 insertions(+), 17 deletions(-) -- 1.9.1 diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 50bb9a1..060f767 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -380,7 +380,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) mmc_retune_hold(card->host); err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BKOPS_START, 1, timeout, + EXT_CSD_BKOPS_START, 1, timeout, 0, use_busy_signal, true, false); if (err) { pr_warn("%s: Error %d starting bkops\n", diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 9355366..cb1cf4e 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1012,7 +1012,7 @@ static int mmc_select_hs(struct mmc_card *card) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (!err) { mmc_set_timing(card->host, MMC_TIMING_MMC_HS); @@ -1115,7 +1115,7 @@ static int mmc_select_hs400(struct mmc_card *card) val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) { pr_err("%s: switch to high-speed from hs200 failed, err:%d\n", @@ -1150,7 +1150,7 @@ static int mmc_select_hs400(struct mmc_card *card) card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) { pr_err("%s: switch to hs400 failed, err:%d\n", @@ -1193,7 +1193,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) /* Switch HS400 to HS DDR */ val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, - val, card->ext_csd.generic_cmd6_time, + val, card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) goto out_err; @@ -1207,7 +1207,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) /* Switch HS DDR to HS */ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time, - true, false, true); + 0, true, false, true); if (err) goto out_err; @@ -1221,7 +1221,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) val = EXT_CSD_TIMING_HS200 | card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, - val, card->ext_csd.generic_cmd6_time, + val, card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) goto out_err; @@ -1295,7 +1295,7 @@ static int mmc_select_hs400es(struct mmc_card *card) card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) { pr_err("%s: switch to hs400es failed, err:%d\n", @@ -1377,7 +1377,7 @@ static int mmc_select_hs200(struct mmc_card *card) card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, - card->ext_csd.generic_cmd6_time, + card->ext_csd.generic_cmd6_time, 0, true, false, true); if (err) goto err; @@ -1841,7 +1841,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_POWER_OFF_NOTIFICATION, - notify_type, timeout, true, false, false); + notify_type, timeout, 0, true, false, false); if (err) pr_err("%s: Power Off Notification timed out, %u\n", mmc_hostname(card->host), timeout); diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 214e734..ab77fc3 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -526,6 +526,7 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, * @value: value to program into EXT_CSD register * @timeout_ms: timeout (ms) for operation performed by register write, * timeout of zero implies maximum possible timeout + * @timing: new timing to change to * @use_busy_signal: use the busy signal as response type * @send_status: send status cmd to poll for busy * @retry_crc_err: retry when CRC errors when polling with CMD13 for busy @@ -533,13 +534,14 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, * Modifies the EXT_CSD register for selected card. */ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, - unsigned int timeout_ms, bool use_busy_signal, bool send_status, - bool retry_crc_err) + unsigned int timeout_ms, unsigned char timing, + bool use_busy_signal, bool send_status, bool retry_crc_err) { struct mmc_host *host = card->host; int err; struct mmc_command cmd = {0}; bool use_r1b_resp = use_busy_signal; + unsigned char old_timing = host->ios.timing; mmc_retune_hold(host); @@ -581,16 +583,24 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (!use_busy_signal) goto out; + /* Switch to new timing before poll and check switch status. */ + if (timing) + mmc_set_timing(host, timing); + /*If SPI or used HW busy detection above, then we don't need to poll. */ if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) || mmc_host_is_spi(host)) { if (send_status) err = mmc_switch_status(card); - goto out; + goto out_tim; } /* Let's try to poll to find out when the command is completed. */ err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err); + +out_tim: + if (err && timing) + mmc_set_timing(host, old_timing); out: mmc_retune_release(host); @@ -600,8 +610,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms) { - return __mmc_switch(card, set, index, value, timeout_ms, true, true, - false); + return __mmc_switch(card, set, index, value, timeout_ms, 0, + true, true, false); } EXPORT_SYMBOL_GPL(mmc_switch); diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 9fccddb..761cb69 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -29,8 +29,8 @@ int mmc_can_ext_csd(struct mmc_card *card); int mmc_switch_status(struct mmc_card *card); int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, - unsigned int timeout_ms, bool use_busy_signal, bool send_status, - bool retry_crc_err); + unsigned int timeout_ms, unsigned char timing, + bool use_busy_signal, bool send_status, bool retry_crc_err); #endif