From patchwork Tue Jan 18 12:43:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 533096 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 42B02C433F5 for ; Tue, 18 Jan 2022 12:44:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237266AbiARMoJ (ORCPT ); Tue, 18 Jan 2022 07:44:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60398 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234111AbiARMoJ (ORCPT ); Tue, 18 Jan 2022 07:44:09 -0500 Received: from mail-pl1-x631.google.com (mail-pl1-x631.google.com [IPv6:2607:f8b0:4864:20::631]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DAE7DC061574 for ; Tue, 18 Jan 2022 04:44:08 -0800 (PST) Received: by mail-pl1-x631.google.com with SMTP id n11so22287151plf.4 for ; Tue, 18 Jan 2022 04:44: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=b35nb6YgyrbfZ2W4MAUEaXu8RLjP7Kjaeja9omZMEvQ=; b=F6azLcCJsEoWu6lmCAbi4k3i+CI2fnoPOh5FFHZQHL+9E8giDKuOtT+oCEsKqwRwHP Aw1GA0fY/gTLGDqzVtbc7nPs9yy+490nsQURY9ZkYzGIOAgIhyqg/+1jK1MAvgksI1mO ff2fVvzeWgTjv+c5SlvSExe6PjrTS9k7sGjqemeptAD/fknI1QKMNvYkHYDuS6LNBBbY ryjOjreT4nEl9F7vOMmypk4HTxP45w+UzGAkcNZE2jKk8zT6fcwF9stVUID7gOd8Nj+H XDaRE9ZtG1TuSSw0vx1APojql43P7rh/dbMF7s+tI4VgrKliqxRX8hqlank4jIIK0/oS /Mug== 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=b35nb6YgyrbfZ2W4MAUEaXu8RLjP7Kjaeja9omZMEvQ=; b=MzfAnfqmloSqr8XBJ6MSJYbxqhVvoQ3m+G+oysTbFxttbSJKewvSMRuXaJYixyHTzb ZPgB9Hy+tIGfADbOyImlXEZoz8VLyur8MHy3j3aa8OSvBL9boAPGcPD1I/e9qI7rYwvm 8yCHgJnzZglBxQE0da+2rM+ExASAuGGxjtKJ5qdfAkSk4S3D1chSZ3zBjR3XbjG03ZJz hhriO2RTv114STgjtGBBdU2asdVWxbRybScIKwnVgD75hLXlqzLxKHd7B2Iqt/mGj0ZW CNyjOV3uCpn/3EHfOYpKq5QTUOvWsUJAa7XnmbzRtXW9iAZkIMxAKf1gfrn+4H09FyhY gBNw== X-Gm-Message-State: AOAM5301c9NOZ6EJpyb7STfBVqI1kEQF7FVaCM8oCk35FFB6N8Eekw/X zFwfHIki81qBETTfsO0TyUc= X-Google-Smtp-Source: ABdhPJwDnBHlqgM9Uuo1M+YZ+rNfzvySpAhyFRi7ezi52mSdAI8ruw+V233boZIpTxqGaVH8v+MXbw== X-Received: by 2002:a17:90a:2ec4:: with SMTP id h4mr8759752pjs.173.1642509848472; Tue, 18 Jan 2022 04:44:08 -0800 (PST) Received: from jason-z170xgaming7.genesyslogic.com.tw (60-251-58-169.hinet-ip.hinet.net. [60.251.58.169]) by smtp.gmail.com with ESMTPSA id n10sm362005pfj.120.2022.01.18.04.44.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Jan 2022 04:44:08 -0800 (PST) From: Jason Lai To: ulf.hansson@linaro.org, takahiro.akashi@linaro.org, adrian.hunter@intel.com Cc: linux-mmc@vger.kernel.org, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, Jason Lai Subject: [PATCH v2 1/7] mmc: core: Cleanup printing of speed mode at card insertion Date: Tue, 18 Jan 2022 20:43:49 +0800 Message-Id: <20220118124355.167552-2-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20220118124355.167552-1-jasonlai.genesyslogic@gmail.com> References: <20220118124355.167552-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 4383c262b..27ba3c749 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -311,6 +311,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 ", @@ -349,27 +350,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 Jan 18 12:43:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 533095 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 9C796C433FE for ; Tue, 18 Jan 2022 12:44:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237394AbiARMoN (ORCPT ); Tue, 18 Jan 2022 07:44:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60420 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237302AbiARMoN (ORCPT ); Tue, 18 Jan 2022 07:44:13 -0500 Received: from mail-pl1-x630.google.com (mail-pl1-x630.google.com [IPv6:2607:f8b0:4864:20::630]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1386CC061574 for ; Tue, 18 Jan 2022 04:44:13 -0800 (PST) Received: by mail-pl1-x630.google.com with SMTP id n8so11050379plc.3 for ; Tue, 18 Jan 2022 04:44: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=yeECnpT9/+cnlgxlvvdwnIS1z4qnyOQPaY8ypGeXpP4=; b=Cx7bd/7vt3fB0wHZ1EoB5Xa24Wg4d9sefP035Eaygqd9YvTecmuaXHhmYlsb9JRah6 HJLfDhI6m6kL8d+KdElr7CKt5Ne7RcKJ0awA9injq5s4KVRJLqvCf7fbpke2fwucZPva R1qBK3T6b0QkxDbBwlj6AqscEigEqwU5MUxBDdIHLlNlargD22XrrPRFFNJitSlgvwAp rg6gWG4GO5zLMdVVeevt913T9TssYx9J5H2SjpJr65kVqUXnH3LhnVlPICqfaZg/iVKm lLIoALbm0HpI+2qPQqgSpWXVG+RFQyMzNM3TMti7cW8ZyaHnPNfv6wJu0n92Q8lxDzKL +yfA== 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=yeECnpT9/+cnlgxlvvdwnIS1z4qnyOQPaY8ypGeXpP4=; b=lJkiVrO4KYZfZNgLTwS7tSFT/cbgSs28F4ndfmgUbYoqJpV896/P4XsV1yrq6Ny6wf Y1NH93SRvT3r8CT9y0MtS7QCzZ/uSYt0UXqTfhcM+GlXwR4XhBVnjZI/rgboTOiNoJzX tm0xSKT/gOjAfs25LlIE1+XTApEYIPEm1O6vOhjB6PGLBaIDvbz9pJWGKI4Nn2CJkX6j wW9LVxmi9POVClqOSOXTsvwE7UV75YARm6na/I32+GJyBVoXFKTGkt/RiefS7rfY/R38 5RK0iEO+UDEv7CdMGWsnDywLvbu56F3ybB9D9G/gLySMFicHj07e/bPHGOhMKHYmiO68 zjVg== X-Gm-Message-State: AOAM5314Vyf6MqwE+m/h/x+BmblT+Nml6MwA9zE4+TDlfqQDhv6l/z14 uWx+Gw+irZwUD32q7J1XEAtG8px5yd2rcw== X-Google-Smtp-Source: ABdhPJx4KV24+4JsEgiQvbJCBLMsgbjvziF6tgH6RROFJZ4kPBdR9dYzky7cCP2AdipN9S7Mcpt/PA== X-Received: by 2002:a17:902:704a:b0:14a:b62b:f41b with SMTP id h10-20020a170902704a00b0014ab62bf41bmr10612949plt.93.1642509852633; Tue, 18 Jan 2022 04:44:12 -0800 (PST) Received: from jason-z170xgaming7.genesyslogic.com.tw (60-251-58-169.hinet-ip.hinet.net. [60.251.58.169]) by smtp.gmail.com with ESMTPSA id n10sm362005pfj.120.2022.01.18.04.44.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Jan 2022 04:44: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, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, Jason Lai Subject: [PATCH v2 3/7] mmc: core: Announce successful insertion of an SD UHS-II card Date: Tue, 18 Jan 2022 20:43:51 +0800 Message-Id: <20220118124355.167552-4-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20220118124355.167552-1-jasonlai.genesyslogic@gmail.com> References: <20220118124355.167552-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 27ba3c749..8fd46b5f5 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -353,7 +353,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 ba407617e..c243d3096 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -83,5 +83,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 Jan 18 12:43:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 533094 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 62A75C433EF for ; Tue, 18 Jan 2022 12:44:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237496AbiARMoR (ORCPT ); Tue, 18 Jan 2022 07:44:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60438 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237436AbiARMoR (ORCPT ); Tue, 18 Jan 2022 07:44:17 -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 40BECC061574 for ; Tue, 18 Jan 2022 04:44:17 -0800 (PST) Received: by mail-pj1-x102a.google.com with SMTP id o3so23194774pjs.1 for ; Tue, 18 Jan 2022 04:44:17 -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=jHdvJyYLqG4Cn517SGttmcCII1kWlh0ajHYNiJDKCx0=; b=U6emVYpXi8uVld16nBGFB1Kc54HHfibYaOU0rOXQiZmMkT6VqT5bYRWdkT2+QaQttG cioj29n3rfeh+BsBynlBxPown3dN9M4u2nnBaFMMGGbru+qKmMGQmw8Bn+31u1mbYvCC rS4qA/KsnBDY5u+yn7QFDPetPTWUJDJNetVFy0XzGKQZKkHFgjc8bRFLi+DBhqHndmY1 pH9ztRJLc7CslT9gtnMqvDxFAjxBwkaAXgYUPD4GMfIsVTUOKpRnaGBI2/p2jqWvJZ7r XvpQ10tgPDXsxsksFDRhtem4JDrT1aZCfSnf7/poTVos4MMBgCjibKraltifixdcFSCe YaQw== 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=jHdvJyYLqG4Cn517SGttmcCII1kWlh0ajHYNiJDKCx0=; b=V+aJe0SF3fVAiDduzfwVxKhFw/aFoY5mcXFaQiUFRp9CodRHk2ODv4CEZjZP3ZdnC6 KEJImPqRzsKNUvTGt2Ks0Vbn2Q2BzUK8JO9h6L1rt/gHgwta0fwBBgYJMfGupTocIheM +YWpEI7rd19YLQDFnpRUlrxghfOVzwAwy9Uty0Nbkxvj4ylrE1lQYzWqE00N0HJtI8pB FcnbSZUga+936wCdHPzRon5hf+rGSQlyjYJXPeB4v4t1snnVYFIqJ4ono3DKZdpLsxkp 6JmpB7PSb+4nQ6qB4qAYBTyKK3Cco3tpoji/HwPHOIrhafR1RKcIsmec6aswsyrKbtC+ RHag== X-Gm-Message-State: AOAM531ygXxJgel3kDdZxlhswHm7useKg8j89+EuGvyvXhYto92liCK4 wpDNBCyEArFYh+lnp08Jsms= X-Google-Smtp-Source: ABdhPJzc6AGiV4/91oXFw1v0gm8mY3rABRlPcH1r63RlDaXmsBfjCpAFuO15gQ7ii720fbJGsKUe9Q== X-Received: by 2002:a17:902:a404:b0:148:b897:c658 with SMTP id p4-20020a170902a40400b00148b897c658mr27258771plq.71.1642509856792; Tue, 18 Jan 2022 04:44:16 -0800 (PST) Received: from jason-z170xgaming7.genesyslogic.com.tw (60-251-58-169.hinet-ip.hinet.net. [60.251.58.169]) by smtp.gmail.com with ESMTPSA id n10sm362005pfj.120.2022.01.18.04.44.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Jan 2022 04:44:16 -0800 (PST) From: Jason Lai To: ulf.hansson@linaro.org, takahiro.akashi@linaro.org, adrian.hunter@intel.com Cc: linux-mmc@vger.kernel.org, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, Jason Lai Subject: [PATCH v2 5/7] mmc: add UHS-II related definitions in headers Date: Tue, 18 Jan 2022 20:43:53 +0800 Message-Id: <20220118124355.167552-6-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20220118124355.167552-1-jasonlai.genesyslogic@gmail.com> References: <20220118124355.167552-1-jasonlai.genesyslogic@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Jason Lai All LINK layer messages, registers and SD-TRAN command packet described in 'Part 1 UHS-II Addendum Ver 1.01' are defined in include/linux/mmc/sd_uhs2.h drivers/mmc/core/sd_uhs2.h contains exported function prototype. Signed-off-by: Jason Lai --- include/linux/mmc/card.h | 30 ++++++++++++++++++++++++++++- include/linux/mmc/core.h | 1 + include/linux/mmc/host.h | 41 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 82b07eac1..ee9fbeadb 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -212,7 +212,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 ab19245e9..c85d5aeb7 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 diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 69f8c8a8f..640c4bc81 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -96,7 +96,37 @@ struct mmc_clk_phase_map { }; struct sd_uhs2_caps { - /* TODO: Add UHS-II capabilities for the host. */ + int flags; +#define MMC_UHS2_SUPPORT (1 << 0) +#define MMC_UHS2_INITIALIZED (1 << 1) +#define MMC_UHS2_2L_HD (1 << 2) +#define MMC_UHS2_APP_CMD (1 << 3) +#define MMC_UHS2_SPEED_B (1 << 4) +#define MMC_SUPPORT_ADMA3 (1 << 5) + + u32 dap; + u32 gap; + 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; @@ -145,7 +175,6 @@ struct mmc_host_ops { */ 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 @@ -210,6 +239,14 @@ 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 { From patchwork Tue Jan 18 12:43:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jason X-Patchwork-Id: 533093 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 03F1CC433FE for ; Tue, 18 Jan 2022 12:44:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237912AbiARMoY (ORCPT ); Tue, 18 Jan 2022 07:44:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60456 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237803AbiARMoV (ORCPT ); Tue, 18 Jan 2022 07:44:21 -0500 Received: from mail-pl1-x636.google.com (mail-pl1-x636.google.com [IPv6:2607:f8b0:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0C03BC061574 for ; Tue, 18 Jan 2022 04:44:21 -0800 (PST) Received: by mail-pl1-x636.google.com with SMTP id e8so10651092plh.8 for ; Tue, 18 Jan 2022 04:44:21 -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=rg9p6aBG5MlrFkw9jt98+PfjVIAq9BIoXv+qMMqvrsQ=; b=CJ5BQd/Pv+DvDXm47FZDzFp5Es7MuCb7K5lY2LmG4MOo1g/CyIrUVhE4oyZZnnnUdO JQfrQG0S0cd4veNJbsm4Vmio5+KEMnTGB9MrbbKP5tHM7qDc5UN00s0+zQQ1P87Bbg+8 oOmVov9m1L5mLeTdPhWOKKznTpXTIo5xoTcjy4kPLWFy1c8hnf09IoAVJQulD1ee7ozo TWn8Lj55WQYC6VqSwxQgOwxmpX407SokgRlOE0uuT+aXpXmZLau/3wfaWAnpvfom44xP FpqMnQXqEjeo3eYbFfDdUF0Lia6KLXW6HLQAVJUHmxnW7LH/CCSrS6Vocub7eyqBEaie Rusw== 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=rg9p6aBG5MlrFkw9jt98+PfjVIAq9BIoXv+qMMqvrsQ=; b=QHgjB++SY0nsbUTbk1RnO95eBPzVUao5GSeTC6itGPFwhJzrbrLJFgafDnAEwnPr+M aZGyTfxi1h7kx66uksKTBTGNkcGR/k65sX6+fYQCzcMQQJy1mEGtePRPwI0wmiZrnDgT 0z4K0vnRUTQZN4acQGc+eZv+JOdnsSahfjnRbMWWiA0QUiG9sxvx9zkigNYFpejot0hd fHhH6RPJIl7ox9W348lFn12Q0mt+ClEfGoCd1CS/EmTraCHb+AjbhANRxsz1HPQZ/4hH 7P2pw5ihsgbFw0ot9+F7dh7yHuYPWqvymvVef1mQTB02ba+pFZWxidn7oKTZvZ0VIFoz eSxQ== X-Gm-Message-State: AOAM532qhKgOSgYmhx8vzJ03K0X/NL8urtummyeKByJOFG88+DXD5PXP fzFHSNs5EZJjI/QS1dCsUaE= X-Google-Smtp-Source: ABdhPJxrwAF4OklIStvA9RsCVKYNxy/R4P1FvCWkZNCCZtlFbGTxEJWZiViZ72PMb1XtKVIgZgvH3Q== X-Received: by 2002:a17:902:a616:b0:14a:c625:6a7a with SMTP id u22-20020a170902a61600b0014ac6256a7amr6768063plq.108.1642509858850; Tue, 18 Jan 2022 04:44:18 -0800 (PST) Received: from jason-z170xgaming7.genesyslogic.com.tw (60-251-58-169.hinet-ip.hinet.net. [60.251.58.169]) by smtp.gmail.com with ESMTPSA id n10sm362005pfj.120.2022.01.18.04.44.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Jan 2022 04:44: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, ben.chuang@genesyslogic.com.tw, greg.tu@genesyslogic.com.tw, jason.lai@genesyslogic.com.tw, otis.wu@genesyslogic.com.tw, Jason Lai Subject: [PATCH v2 6/7] mmc: Implement content of UHS-II card initialization functions Date: Tue, 18 Jan 2022 20:43:54 +0800 Message-Id: <20220118124355.167552-7-jasonlai.genesyslogic@gmail.com> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20220118124355.167552-1-jasonlai.genesyslogic@gmail.com> References: <20220118124355.167552-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 | 860 ++++++++++++++++++++++++++++++++++++- 1 file changed, 842 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/core/sd_uhs2.c b/drivers/mmc/core/sd_uhs2.c index 800957f74..6b711fd50 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,28 @@ #include #include +#include #include "core.h" #include "bus.h" #include "sd.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 +55,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 embeded 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 +99,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 +116,78 @@ 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->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 +198,169 @@ 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,6 +375,332 @@ 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; + u8 try; + 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); + + for (try = 0; try < 2; try++) { + plen = 2; + + 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 = + (min(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; + + if (try == 0) { + host->uhs2_caps.n_lss_dir_set = + (card->uhs2_config.n_lss_dir >> 3) & + UHS2_DEV_CONFIG_N_LSS_DIR_MASK; + card->uhs2_config.n_lss_dir_set = + ((host->uhs2_caps.n_lss_dir >> 3) + 1) & + UHS2_DEV_CONFIG_N_LSS_DIR_MASK; + } else { + 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)) + break; + } + + 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->mmc), __func__); + return -EIO; + } + + mmc_delay(1); + } while (1); + return 0; } @@ -107,9 +713,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 = mmc_sd_get_ro(host); + if (ro < 0) { + pr_warn("%s: host does not support reading 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 +845,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 +868,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 +886,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 +946,78 @@ 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); + } + + if (cmd->opcode == SD_IO_RW_EXTENDED) { + arg &= ~(UHS2_DCMD_LM_TLEN_EXIST | + UHS2_DCMD_TLUM_BYTE_MODE | + UHS2_NATIVE_DCMD_DAM_IO); + payload[1] = 0; + plen = 1; + } + } 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 +1055,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->card); 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 +1092,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 +1101,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;