From patchwork Thu Dec 7 06:35:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?QXhlIFlhbmcgKOadqOejiik=?= X-Patchwork-Id: 13482730 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 845E6C46CA0 for ; Thu, 7 Dec 2023 06:56:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=mSrOKd31C+wYaNa67BZU4ZrIWtrwhE61cgz1GiImYKM=; b=a/BrXW0DOFuwOD lFYphIw1QQneeRO72D90Vf2t6cvLLY0Zf2DoQVjpycQ3IAfeMfaC6YApQvMLUf2XdD67Brpw4n3Z0 vH8X1xhOIXZTLzvPNJZ2l22RzTi/DYLpi1hLafp7GErYYvnCBB64dGYRpHNdqcgW/CvNIHcOerOQH 2jSjg6GoqCuOz/6ErCJb8AeZtmU77FIaaXNsjTiym0ExSdbmObpOGpmG0DeytvdJAVFCB2JemJcwf 4sLOMF15NqWz0Jq0kUNdHuEzPDK5XpxoujRgSzgqXKcwRMuDKiJtILiS5qxwz+tTQoYgIvAPHzsgp ZAGyjVu5+Ka1BYX4kZGA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1rB8JA-00C2JD-25; Thu, 07 Dec 2023 06:56:28 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1rB8J7-00C2Id-0o; Thu, 07 Dec 2023 06:56:26 +0000 X-UUID: b90d14dc94cd11ee9b09ad09c76753c8-20231206 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=RCJcyyZ8EMNjvJVmY4Ygro4ZBJTkkM+cPjU66561fik=; b=UTxcd1kGvh7vpHDIFyBSoCNlyxzPxfKVeJABcH6/JMM/jSqvAACF6uWEv+CPcCB5ELDqzcXrHuZ4DBtBL73H3eRBEiANJzHcjetxCgSQ71SXEgAXSD7PevKgJPz9vyiBjUkKV35yPUHvxfWAcyrjOmYc9x5rwoKJhYjQboSTPx0=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.35,REQID:1b0fc96a-ecfa-4f7c-8f6f-3a1187e134b7,IP:0,U RL:0,TC:0,Content:-5,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:-5 X-CID-META: VersionHash:5d391d7,CLOUDID:fae8ea60-c89d-4129-91cb-8ebfae4653fc,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:0,File:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES:1,SPR:NO, DKR:0,DKP:0,BRR:0,BRE:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: b90d14dc94cd11ee9b09ad09c76753c8-20231206 Received: from mtkmbs11n1.mediatek.inc [(172.21.101.185)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 531175737; Wed, 06 Dec 2023 23:56:18 -0700 Received: from mtkmbs11n1.mediatek.inc (172.21.101.185) by mtkmbs11n2.mediatek.inc (172.21.101.187) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 7 Dec 2023 14:35:40 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs11n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 7 Dec 2023 14:35:39 +0800 From: Axe Yang To: Chaotian Jing , Ulf Hansson , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Wenbin Mei CC: , , , , , , Axe Yang , Krzysztof Kozlowski Subject: [PATCH v4 1/2] dt-bindings: mmc: mtk-sd: add tuning steps related property Date: Thu, 7 Dec 2023 14:35:34 +0800 Message-ID: <20231207063535.29546-2-axe.yang@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231207063535.29546-1-axe.yang@mediatek.com> References: <20231207063535.29546-1-axe.yang@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20231206_225625_301417_05737393 X-CRM114-Status: UNSURE ( 9.08 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add 'mediatek,tuning-steps' setting. This property will give MSDC a chance to extend tuning steps up to 64. With more tuning steps, MSDC may achieve a more optimal calibration result, thus avoiding potential CRC issues. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Axe Yang Reviewed-by: AngeloGioacchino Del Regno --- Documentation/devicetree/bindings/mmc/mtk-sd.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml index 3fffa467e4e1..c532ec92d2d9 100644 --- a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml +++ b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml @@ -145,6 +145,15 @@ properties: minimum: 0 maximum: 7 + mediatek,tuning-step: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Some SoCs need extend tuning step for better delay value to avoid CRC issue. + If not present, default tuning step is 32. For eMMC and SD, this can yield + satisfactory calibration results in most cases. + enum: [32, 64] + default: 32 + resets: maxItems: 1 From patchwork Thu Dec 7 06:35:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?QXhlIFlhbmcgKOadqOejiik=?= X-Patchwork-Id: 13482714 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 92F19C4167B for ; Thu, 7 Dec 2023 06:47:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=RWdavkSxMcZADdJDPjWx6O3rfKnh3XKggQx7+3wOpho=; b=mtSp4rxWXSsm/o GsWT32JdivhJtJ+PCMDIsG+bMhvBll/NvbXtBq5/eiCEWKD8wUIkPZmhrH/KI5ZdQOycVJC6y7t5o vZmbQdwJvmrIPMaVN2xb+7/fgIa2eqH1bzzr4Bsjy+A4qj4O6x87qJCQ7wKnUD9EJVONM9ZkzH6Qp pEbHY8rLgwvDtdoh0vGn2rEQ557sPtHxNk9is56bONT/qWUvKU44tswk+L0r5UaD1JVpt8Zf9CUw1 kP48dQ8kn5PKhZGXJgD5eD24mpZvdGYRRAhvgC2tyLc6s31hjoVoivt86X14Guw3EeRl9VK+LQ245 VH+i4Dktyeiim05tt3SQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1rB89Y-00C16l-1c; Thu, 07 Dec 2023 06:46:32 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1rB89T-00C16B-0b; Thu, 07 Dec 2023 06:46:30 +0000 X-UUID: 5366328694cc11ee9b09ad09c76753c8-20231206 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=FXuG78bG9PDHbQlfYUkB8OFI6hQl9Lucg7hG903GvlQ=; b=cTGs3fi3WvyH1SSk7+SkCNXPNrFsJ9AJxbK10wcRkkr0pgaGRKYmNyKcOfjcNzO9EbHiTfyXnLh/5V4o79ovj+McHYknYdaBoZ/yhCxFVAaHON5PMQlIzlfw09Oi8NdzhaQ0XAbV89/nFeueZKF73Boq4xjNrupfQ2nbddr8RaA=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.35,REQID:5f6219f7-c3ca-4dca-ab51-b5a5210ab39a,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:5d391d7,CLOUDID:ee8063fd-4a48-46e2-b946-12f04f20af8c,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:0,File:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES:1,SPR:NO, DKR:0,DKP:0,BRR:0,BRE:0 X-CID-BVR: 0 X-CID-BAS: 0,_,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: 5366328694cc11ee9b09ad09c76753c8-20231206 Received: from mtkmbs11n1.mediatek.inc [(172.21.101.185)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 482460186; Wed, 06 Dec 2023 23:46:18 -0700 Received: from mtkmbs11n1.mediatek.inc (172.21.101.185) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Thu, 7 Dec 2023 14:35:41 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs11n1.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Thu, 7 Dec 2023 14:35:41 +0800 From: Axe Yang To: Chaotian Jing , Ulf Hansson , Rob Herring , "Krzysztof Kozlowski" , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , "Wenbin Mei" CC: , , , , , , Axe Yang Subject: [PATCH v4 2/2] mmc: mediatek: extend number of tuning steps Date: Thu, 7 Dec 2023 14:35:35 +0800 Message-ID: <20231207063535.29546-3-axe.yang@mediatek.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231207063535.29546-1-axe.yang@mediatek.com> References: <20231207063535.29546-1-axe.yang@mediatek.com> MIME-Version: 1.0 X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--8.836000-8.000000 X-TMASE-MatchedRID: 9N24rvusElB80yFIYo0rRuGonqgs5zxBRjqOkKPmpa4UlWIKEoGBmc+/ a0S0vHt4WZy+62a7b19rOAp0kI1DP9H/WqWljGhSSDkh6bW+bcckMBkEieOjZi8ggN9+4AxXDk6 /c+jKAHFIl95haju6JaPNT9pmq5xZMZPj25j8CtwD2WXLXdz+ASlayzmQ9QV0uGtlO4mJjG4p5V paXKVZ0ru/rdp1USGE53BNgT5ozCDJXsxRGJ73eQUNJ/OP1hfdaM4aPCtYABoT7lsB95pa6qUw+ JzU1GXBynCQnr2+AG9YW77ecurO05Coy9iDotiwDYcOzBwKciNfohHCqSnabhIp4u9jJZb6JETW X/pKcs5wbQxGhptmol5bBcpAanckN8PEWMb3wthH+PTjR9EWkuWNJG9Iamrc4pinC0b7AdUnJC0 FLrRqdyQzZXePPedHumMCMwce1mUfE8yM4pjsD23U7j2vVURrxEHRux+uk8h+ICquNi0WJCRACz TS4YvgXWwxxVcSCxCkqTSB73PKtxbpA9LwxbPUftwZ3X11IV0= X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--8.836000-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: F467CA4E97EA1C01F0B5CCE6592F5B85F7B06BFBF609AE761AFC0382009FB24A2000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20231206_224627_555655_6DB5DDBF X-CRM114-Status: GOOD ( 27.15 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Previously, during the MSDC calibration process, a full clock cycle actually not be covered, which in some cases didn't yield the best results and could cause CRC errors. This problem is particularly evident when MSDC is used as an SDIO host. In fact, MSDC support tuning up to a maximum of 64 steps, but by default, the step number is 32. By increase the tuning step, we are more likely to cover more parts of a clock cycle, and get better calibration result. To illustrate, when tuning 32 steps, if the obtained window has a hole near the middle, like this: 0xffc07ff (hex), then the selected delay will be the 6 (counting from right to left). (32 <- 1) 1111 1111 1100 0000 0000 0111 11(1)1 1111 However, if we tune 64 steps, the window obtained may look like this: 0xfffffffffffc07ff. The final selected delay will be 44, which is safer as it is further away from the hole: (64 <- 1) 1111 ... (1)111 1111 1111 1111 1111 1100 0000 0000 0111 1111 1111 In this case, delay 6 selected through 32 steps tuning is obviously not optimal, and this delay is closer to the hole, using it would easily cause CRC problems. As per mesaurements taken on mediatek SoC platform, the tuning phase will take: eMMC - 32 steps: ~3ms - 64 steps: ~6ms SDIO - 32 steps: ~4ms - 64 steos: ~7ms Tuning more steps won't prolong boot times by any meaningful amount of time, so for SD/SDIO the default tuning steps will be adjust to 64. But for eMMC, it is still preferred to use 32 steps tuning as otherwise there would be performance lose when accessing the RPMB partition(requiring retuning each time). You can configure property "mediatek,tuning-step" in MSDC dts node to adjust the step number. Signed-off-by: Axe Yang Reviewed-by: AngeloGioacchino Del Regno --- drivers/mmc/host/mtk-sd.c | 158 ++++++++++++++++++++++++++------------ 1 file changed, 110 insertions(+), 48 deletions(-) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 97f7c3d4be6e..f315db48ac02 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -252,12 +252,16 @@ #define MSDC_PAD_TUNE_DATWRDLY GENMASK(4, 0) /* RW */ #define MSDC_PAD_TUNE_DATRRDLY GENMASK(12, 8) /* RW */ +#define MSDC_PAD_TUNE_DATRRDLY2 GENMASK(12, 8) /* RW */ #define MSDC_PAD_TUNE_CMDRDLY GENMASK(20, 16) /* RW */ +#define MSDC_PAD_TUNE_CMDRDLY2 GENMASK(20, 16) /* RW */ #define MSDC_PAD_TUNE_CMDRRDLY GENMASK(26, 22) /* RW */ #define MSDC_PAD_TUNE_CLKTDLY GENMASK(31, 27) /* RW */ #define MSDC_PAD_TUNE_RXDLYSEL BIT(15) /* RW */ #define MSDC_PAD_TUNE_RD_SEL BIT(13) /* RW */ #define MSDC_PAD_TUNE_CMD_SEL BIT(21) /* RW */ +#define MSDC_PAD_TUNE_RD2_SEL BIT(13) /* RW */ +#define MSDC_PAD_TUNE_CMD2_SEL BIT(21) /* RW */ #define PAD_DS_TUNE_DLY_SEL BIT(0) /* RW */ #define PAD_DS_TUNE_DLY1 GENMASK(6, 2) /* RW */ @@ -325,7 +329,9 @@ #define DEFAULT_DEBOUNCE (8) /* 8 cycles CD debounce */ -#define PAD_DELAY_MAX 32 /* PAD delay cells */ +#define TUNING_REG2_FIXED_OFFEST 4 +#define PAD_DELAY_HALF 32 /* PAD delay cells */ +#define PAD_DELAY_FULL 64 /*--------------------------------------------------------------------------*/ /* Descriptor Structure */ /*--------------------------------------------------------------------------*/ @@ -461,6 +467,7 @@ struct msdc_host { u32 hs400_ds_dly3; u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */ u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */ + u32 tuning_step; bool hs400_cmd_resp_sel_rising; /* cmd response sample selection for HS400 */ bool hs400_mode; /* current eMMC will run at hs400 mode */ @@ -1615,7 +1622,7 @@ static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts) } if (cmd_err || dat_err) { - dev_err(host->dev, "cmd_err = %d, dat_err =%d, intsts = 0x%x", + dev_err(host->dev, "cmd_err = %d, dat_err = %d, intsts = 0x%x", cmd_err, dat_err, intsts); } @@ -1780,10 +1787,20 @@ static void msdc_init_hw(struct msdc_host *host) DATA_K_VALUE_SEL); sdr_set_bits(host->top_base + EMMC_TOP_CMD, PAD_CMD_RD_RXDLY_SEL); + if (host->tuning_step > PAD_DELAY_HALF) { + sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY2_SEL); + sdr_set_bits(host->top_base + EMMC_TOP_CMD, + PAD_CMD_RD_RXDLY2_SEL); + } } else { sdr_set_bits(host->base + tune_reg, MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL); + if (host->tuning_step > PAD_DELAY_HALF) + sdr_set_bits(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_RD2_SEL | + MSDC_PAD_TUNE_CMD2_SEL); } } else { /* choose clock tune */ @@ -1925,24 +1942,24 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) msdc_set_mclk(host, ios->timing, ios->clock); } -static u32 test_delay_bit(u32 delay, u32 bit) +static u64 test_delay_bit(u64 delay, u32 bit) { - bit %= PAD_DELAY_MAX; - return delay & BIT(bit); + bit %= PAD_DELAY_FULL; + return delay & BIT_ULL(bit); } -static int get_delay_len(u32 delay, u32 start_bit) +static int get_delay_len(u64 delay, u32 start_bit) { int i; - for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) { + for (i = 0; i < (PAD_DELAY_FULL - start_bit); i++) { if (test_delay_bit(delay, start_bit + i) == 0) return i; } - return PAD_DELAY_MAX - start_bit; + return PAD_DELAY_FULL - start_bit; } -static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) +static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u64 delay) { int start = 0, len = 0; int start_final = 0, len_final = 0; @@ -1950,28 +1967,28 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) struct msdc_delay_phase delay_phase = { 0, }; if (delay == 0) { - dev_err(host->dev, "phase error: [map:%x]\n", delay); + dev_err(host->dev, "phase error: [map:%016llx]\n", delay); delay_phase.final_phase = final_phase; return delay_phase; } - while (start < PAD_DELAY_MAX) { + while (start < PAD_DELAY_FULL) { len = get_delay_len(delay, start); if (len_final < len) { start_final = start; len_final = len; } start += len ? len : 1; - if (len >= 12 && start_final < 4) + if (!upper_32_bits(delay) && len >= 12 && start_final < 4) break; } /* The rule is that to find the smallest delay cell */ if (start_final == 0) - final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX; + final_phase = (start_final + len_final / 3) % PAD_DELAY_FULL; else - final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX; - dev_dbg(host->dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n", + final_phase = (start_final + len_final / 2) % PAD_DELAY_FULL; + dev_dbg(host->dev, "phase: [map:%016llx] [maxlen:%d] [final:%d]\n", delay, len_final, final_phase); delay_phase.maxlen = len_final; @@ -1984,30 +2001,64 @@ static inline void msdc_set_cmd_delay(struct msdc_host *host, u32 value) { u32 tune_reg = host->dev_comp->pad_tune_reg; - if (host->top_base) - sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, - value); - else - sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, - value); + if (host->top_base) { + if (value < PAD_DELAY_HALF) { + sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, value); + sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY2, 0); + } else { + sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, + PAD_DELAY_HALF - 1); + sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY2, + value - PAD_DELAY_HALF); + } + } else { + if (value < PAD_DELAY_HALF) { + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, value); + sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_CMDRDLY2, 0); + } else { + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, + PAD_DELAY_HALF - 1); + sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_CMDRDLY2, value - PAD_DELAY_HALF); + } + } } static inline void msdc_set_data_delay(struct msdc_host *host, u32 value) { u32 tune_reg = host->dev_comp->pad_tune_reg; - if (host->top_base) - sdr_set_field(host->top_base + EMMC_TOP_CONTROL, - PAD_DAT_RD_RXDLY, value); - else - sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, - value); + if (host->top_base) { + if (value < PAD_DELAY_HALF) { + sdr_set_field(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY, value); + sdr_set_field(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY2, 0); + } else { + sdr_set_field(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY, PAD_DELAY_HALF - 1); + sdr_set_field(host->top_base + EMMC_TOP_CONTROL, + PAD_DAT_RD_RXDLY2, value - PAD_DELAY_HALF); + } + } else { + if (value < PAD_DELAY_HALF) { + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, value); + sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_DATRRDLY2, 0); + } else { + sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, + PAD_DELAY_HALF - 1); + sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST, + MSDC_PAD_TUNE_DATRRDLY2, value - PAD_DELAY_HALF); + } + } } static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); - u32 rise_delay = 0, fall_delay = 0; + u64 rise_delay = 0, fall_delay = 0; struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; struct msdc_delay_phase internal_delay_phase; u8 final_delay, final_maxlen; @@ -2023,7 +2074,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) host->hs200_cmd_int_delay); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - for (i = 0 ; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); /* * Using the same parameters, it may sometimes pass the test, @@ -2033,9 +2084,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) for (j = 0; j < 3; j++) { mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) { - rise_delay |= BIT(i); + rise_delay |= BIT_ULL(i); } else { - rise_delay &= ~BIT(i); + rise_delay &= ~BIT_ULL(i); break; } } @@ -2047,7 +2098,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) goto skip_fall; sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); /* * Using the same parameters, it may sometimes pass the test, @@ -2057,9 +2108,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) for (j = 0; j < 3; j++) { mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) { - fall_delay |= BIT(i); + fall_delay |= BIT_ULL(i); } else { - fall_delay &= ~BIT(i); + fall_delay &= ~BIT_ULL(i); break; } } @@ -2082,12 +2133,12 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay) goto skip_internal; - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRRDLY, i); mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) - internal_delay |= BIT(i); + internal_delay |= BIT_ULL(i); } dev_dbg(host->dev, "Final internal delay: 0x%x\n", internal_delay); internal_delay_phase = get_best_delay(host, internal_delay); @@ -2121,7 +2172,8 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode) sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); else sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - for (i = 0 ; i < PAD_DELAY_MAX; i++) { + + for (i = 0; i < PAD_DELAY_HALF; i++) { sdr_set_field(host->base + PAD_CMD_TUNE, PAD_CMD_TUNE_RX_DLY3, i); /* @@ -2151,7 +2203,7 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode) static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); - u32 rise_delay = 0, fall_delay = 0; + u64 rise_delay = 0, fall_delay = 0; struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; u8 final_delay, final_maxlen; int i, ret; @@ -2160,11 +2212,11 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) host->latch_ck); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); - for (i = 0 ; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - rise_delay |= BIT(i); + rise_delay |= BIT_ULL(i); } final_rise_delay = get_best_delay(host, rise_delay); /* if rising edge has enough margin, then do not scan falling edge */ @@ -2174,11 +2226,11 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - fall_delay |= BIT(i); + fall_delay |= BIT_ULL(i); } final_fall_delay = get_best_delay(host, fall_delay); @@ -2206,7 +2258,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); - u32 rise_delay = 0, fall_delay = 0; + u64 rise_delay = 0, fall_delay = 0; struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; u8 final_delay, final_maxlen; int i, ret; @@ -2217,12 +2269,12 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); - for (i = 0 ; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - rise_delay |= BIT(i); + rise_delay |= BIT_ULL(i); } final_rise_delay = get_best_delay(host, rise_delay); /* if rising edge has enough margin, then do not scan falling edge */ @@ -2233,12 +2285,12 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - fall_delay |= BIT(i); + fall_delay |= BIT_ULL(i); } final_fall_delay = get_best_delay(host, fall_delay); @@ -2346,7 +2398,7 @@ static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card } host->hs400_tuning = true; - for (i = 0; i < PAD_DELAY_MAX; i++) { + for (i = 0; i < PAD_DELAY_HALF; i++) { if (host->top_base) sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE, PAD_DS_DLY1, i); @@ -2580,6 +2632,8 @@ static const struct cqhci_host_ops msdc_cmdq_ops = { static void msdc_of_property_parse(struct platform_device *pdev, struct msdc_host *host) { + struct mmc_host *mmc = mmc_from_priv(host); + of_property_read_u32(pdev->dev.of_node, "mediatek,latch-ck", &host->latch_ck); @@ -2601,6 +2655,14 @@ static void msdc_of_property_parse(struct platform_device *pdev, else host->hs400_cmd_resp_sel_rising = false; + if (of_property_read_u32(pdev->dev.of_node, "mediatek,tuning-step", + &host->tuning_step)) { + if (mmc->caps2 & MMC_CAP2_NO_MMC) + host->tuning_step = PAD_DELAY_FULL; + else + host->tuning_step = PAD_DELAY_HALF; + } + if (of_property_read_bool(pdev->dev.of_node, "supports-cqe")) host->cqhci = true;