mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Changhuang Liang <changhuang.liang@starfivetech.com>
To: Ritesh Harjani <ritesh.list@gmail.com>,
	Ulf Hansson <ulfh@kernel.org>,
	Adrian Hunter <adrian.hunter@intel.com>,
	Shawn Lin <shawn.lin@rock-chips.com>
Cc: linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org,
	Changhuang Liang <changhuang.liang@starfivetech.com>
Subject: [PATCH v3 1/2] mmc: cqhci: Add support for setting the Send Status Command Idle Timer
Date: Mon,  9 Nov 2026 00:18:12 -0800	[thread overview]
Message-ID: <20261109081813.3846-2-changhuang.liang@starfivetech.com> (raw)
In-Reply-To: <20261109081813.3846-1-changhuang.liang@starfivetech.com>

Add cit_ns and cit members to struct cqhci_host so that host drivers can
set the Send Status Command Idle Timer (CIT) in CQHCI_SSC1, either in
nanoseconds or directly in internal timer clock cycles.

The CIT defines how long the bus has to be idle, in internal timer clock
cycles, before the CQE issues CMD13 to poll the Queue Status Register.
Its reset value is controller specific and can be far from optimal, so
host drivers may need to tune it for their platform.

If cit_ns is non-zero, cqhci_init() converts it to cycles of the internal
timer clock frequency (ITCF) derived from the ITCFMUL and ITCFVAL fields
of the CQHCI capabilities register. The result is rounded up so that the
programmed idle time is never shorter than requested. Expressing the
time in nanoseconds lets platforms with different ITCF share the same
setting. If the ITCF is not reported or the result does not fit the
16-bit CIT field, a warning is printed and cit is left unchanged. If
both are set, cit_ns takes precedence over cit.

If cit is non-zero, program it into CQHCI_SSC1 every time the CQE is
enabled in __cqhci_enable().

Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
---
 drivers/mmc/host/cqhci-core.c | 45 +++++++++++++++++++++++++++++++++++
 drivers/mmc/host/cqhci.h      | 13 ++++++++++
 2 files changed, 58 insertions(+)

diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c
index a466cd88b043..58182561e14e 100644
--- a/drivers/mmc/host/cqhci-core.c
+++ b/drivers/mmc/host/cqhci-core.c
@@ -279,6 +279,14 @@ static void __cqhci_enable(struct cqhci_host *cq_host)
 	cqhci_writel(cq_host, upper_32_bits(cq_host->desc_dma_base),
 		     CQHCI_TDLBAU);
 
+	if (cq_host->cit) {
+		u32 ssc1 = cqhci_readl(cq_host, CQHCI_SSC1);
+
+		ssc1 &= ~CQHCI_SSC1_CIT_MASK;
+		ssc1 |= FIELD_PREP(CQHCI_SSC1_CIT_MASK, cq_host->cit);
+		cqhci_writel(cq_host, ssc1, CQHCI_SSC1);
+	}
+
 	cqhci_writel(cq_host, cq_host->rca, CQHCI_SSC2);
 
 	cqhci_set_irqs(cq_host, 0);
@@ -1163,6 +1171,41 @@ struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev)
 }
 EXPORT_SYMBOL(cqhci_pltfm_init);
 
+static void cqhci_init_cit(struct cqhci_host *cq_host)
+{
+	u32 cap, itcfmul, itcfval;
+	u64 cit;
+
+	if (!cq_host->cit_ns)
+		return;
+
+	cap = cqhci_readl(cq_host, CQHCI_CAP);
+	itcfmul = CQHCI_ITCFMUL(cap);
+	itcfval = CQHCI_ITCFVAL(cap);
+
+	/* ITCFMUL: 0 = 1 kHz, 1 = 10 kHz, ..., 4 = 10 MHz, others reserved */
+	if (itcfmul > 4 || !itcfval) {
+		pr_warn("%s: cqhci: internal timer clock frequency not available (CAP 0x%08x), CIT not set\n",
+			mmc_hostname(cq_host->mmc), cap);
+		return;
+	}
+
+	/*
+	 * ITCF in kHz is int_pow(10, itcfmul) * itcfval, so kHz * ns / 10^6
+	 * gives the number of cycles. Round up so that the idle time is never
+	 * shorter than requested.
+	 */
+	cit = DIV_ROUND_UP_ULL(int_pow(10, itcfmul) * itcfval * cq_host->cit_ns,
+			       USEC_PER_SEC);
+	if (cit > FIELD_MAX(CQHCI_SSC1_CIT_MASK)) {
+		pr_warn("%s: cqhci: CIT %u ns out of range, CIT not set\n",
+			mmc_hostname(cq_host->mmc), cq_host->cit_ns);
+		return;
+	}
+
+	cq_host->cit = cit;
+}
+
 static unsigned int cqhci_ver_major(struct cqhci_host *cq_host)
 {
 	return CQHCI_VER_MAJOR(cqhci_readl(cq_host, CQHCI_VER));
@@ -1207,6 +1250,8 @@ int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc,
 		goto out_err;
 	}
 
+	cqhci_init_cit(cq_host);
+
 	spin_lock_init(&cq_host->lock);
 
 	init_completion(&cq_host->halt_comp);
diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h
index 8fbbc48c3f85..7381a2104449 100644
--- a/drivers/mmc/host/cqhci.h
+++ b/drivers/mmc/host/cqhci.h
@@ -26,6 +26,8 @@
 #define CQHCI_CAP_CS			0x10000000 /* Crypto Support */
 #define CQHCI_CAP_ITCFMUL		GENMASK(15, 12)
 #define CQHCI_ITCFMUL(x)		FIELD_GET(CQHCI_CAP_ITCFMUL, (x))
+#define CQHCI_CAP_ITCFVAL		GENMASK(9, 0)
+#define CQHCI_ITCFVAL(x)		FIELD_GET(CQHCI_CAP_ITCFVAL, (x))
 
 /* configuration */
 #define CQHCI_CFG			0x08
@@ -234,6 +236,17 @@ struct cqhci_host {
 	int num_slots;
 	int qcnt;
 
+	/*
+	 * Send Status Command Idle Timer (CIT), set by host drivers before
+	 * calling cqhci_init(), either in nanoseconds via @cit_ns or directly
+	 * in internal timer clock cycles via @cit. A non-zero @cit_ns takes
+	 * precedence and is converted to @cit by cqhci_init(). If the
+	 * conversion fails, @cit is left unchanged. A zero @cit keeps the
+	 * reset default.
+	 */
+	u32 cit_ns;
+	u16 cit;
+
 	u32 dcmd_slot;
 	u32 caps;
 #define CQHCI_TASK_DESC_SZ_128		0x1
-- 
2.25.1


  reply	other threads:[~2026-11-09  8:18 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-09  8:18 [PATCH v3 0/2] Improve eMMC performance for the StarFive JHB100 SoC Changhuang Liang
2026-11-09  8:18 ` Changhuang Liang [this message]
2026-11-09  8:18 ` [PATCH v3 2/2] mmc: sdhci-of-dwcmshc: Set CQHCI command idle time for StarFive JHB100 Changhuang Liang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261109081813.3846-2-changhuang.liang@starfivetech.com \
    --to=changhuang.liang@starfivetech.com \
    --cc=adrian.hunter@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=ritesh.list@gmail.com \
    --cc=shawn.lin@rock-chips.com \
    --cc=ulfh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®