From patchwork Tue Nov 22 20:56:11 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 83503 Delivered-To: patches@linaro.org Received: by 10.140.97.165 with SMTP id m34csp2310925qge; Tue, 22 Nov 2016 12:56:29 -0800 (PST) X-Received: by 10.194.78.195 with SMTP id d3mr155759wjx.96.1479848189213; Tue, 22 Nov 2016 12:56:29 -0800 (PST) Return-Path: Received: from mail-wm0-x22d.google.com (mail-wm0-x22d.google.com. [2a00:1450:400c:c09::22d]) by mx.google.com with ESMTPS id zm4si27546682wjb.131.2016.11.22.12.56.29 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Nov 2016 12:56:29 -0800 (PST) Received-SPF: pass (google.com: domain of ulf.hansson@linaro.org designates 2a00:1450:400c:c09::22d as permitted sender) client-ip=2a00:1450:400c:c09::22d; 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::22d as permitted sender) smtp.mailfrom=ulf.hansson@linaro.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: by mail-wm0-x22d.google.com with SMTP id f82so46547412wmf.1 for ; Tue, 22 Nov 2016 12:56:29 -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=T+/7oTB+dZjg2tqOMbLvk7JPEh8x8rKjy6LAUr50qYA=; b=BtY3cVfdkOxWdwAEVQFWFAkxFxIovo7Ba6AfOAKVP79PYszncdDcKufzbZACw2Xk2/ AOJIqCtswG7AzRrmmZXQwzTjnUds2ip8JjtCV6+V1Nn+OUznNH96tI13Nn3eOpKL4LU5 ytK4kYwb58gTkPx1/8UAVdN/ouY8Q1L0bFug4= 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=T+/7oTB+dZjg2tqOMbLvk7JPEh8x8rKjy6LAUr50qYA=; b=XdgF+vbZJFHH8yLQH1XjQv3+q9/cVV89YMwkBusI6Tl1xDtjs1WuAP39GZnvLyOYV5 twebkkr+zDIivUG99XHMqkBO3wJJvAP98R9AjthGll/X8JKueLgfVQ91R4Q44PEtMnZa NZLjko13K+XylgPjjafKUQv3OecHrvXYDJbt0+Qd552y4CpO289BGbqc1dajNyvYYIEG SVV6mT+A8C7sidY3agnub9sGo6CMPcEmEx4oJLS/9Cy6DwnbSWL0lEJ/lRDzWHt5ME/q GuyVKKR4zmsRLxuF/gfG8tg5mVhE2OdNLLpn94BDFqXo0c+88XCkpr2B0bkcGb2RgzBk UFEw== X-Gm-Message-State: AKaTC004OD1+De+PjCCBZf8wDwf0ze1wJ6EDG3YdOvv/TdRnIbLtSVfISgFzbJY89Rq60sjjaQQ= X-Received: by 10.46.77.9 with SMTP id a9mr12286493ljb.25.1479848188737; Tue, 22 Nov 2016 12:56:28 -0800 (PST) Return-Path: Received: from localhost.localdomain (h-155-4-221-67.na.cust.bahnhof.se. [155.4.221.67]) by smtp.gmail.com with ESMTPSA id 196sm6619988lff.3.2016.11.22.12.56.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 22 Nov 2016 12:56:27 -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 v2 5/7] mmc: core: Enable __mmc_switch() to change bus speed timing for the host Date: Tue, 22 Nov 2016 21:56:11 +0100 Message-Id: <1479848173-20881-6-git-send-email-ulf.hansson@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1479848173-20881-1-git-send-email-ulf.hansson@linaro.org> References: <1479848173-20881-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 fba5d29..9b2617c 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -530,6 +530,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 @@ -537,13 +538,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); @@ -585,16 +587,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); @@ -604,8 +614,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