public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Kaustabh Chakraborty <kauschluss@disroot.org>,
	Ulf Hansson <ulf.hansson@linaro.org>,
	Sasha Levin <sashal@kernel.org>,
	jh80.chung@samsung.com, linux-mmc@vger.kernel.org
Subject: [PATCH AUTOSEL 6.13 20/24] mmc: dw_mmc: add a quirk for accessing 64-bit FIFOs in two halves
Date: Mon, 31 Mar 2025 10:54:00 -0400	[thread overview]
Message-ID: <20250331145404.1705141-20-sashal@kernel.org> (raw)
In-Reply-To: <20250331145404.1705141-1-sashal@kernel.org>

From: Kaustabh Chakraborty <kauschluss@disroot.org>

[ Upstream commit 57c0902f8bec51add5a1eb908d8b876592725d81 ]

In certain DW MMC implementations (such as in some Exynos7870
controllers), 64-bit read/write is not allowed from a 64-bit FIFO.
Add a quirk which facilitates accessing the 64-bit FIFO registers in two
32-bit halves.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
Link: https://lore.kernel.org/r/20250219-exynos7870-mmc-v2-2-b4255a3e39ed@disroot.org
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/mmc/host/dw_mmc.c | 94 ++++++++++++++++++++++++++++++++++++++-
 drivers/mmc/host/dw_mmc.h | 27 +++++++++++
 2 files changed, 119 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 3cbda98d08d28..74f224647bf1e 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2579,6 +2579,91 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
 	}
 }
 
+static void dw_mci_push_data64_32(struct dw_mci *host, void *buf, int cnt)
+{
+	struct mmc_data *data = host->data;
+	int init_cnt = cnt;
+
+	/* try and push anything in the part_buf */
+	if (unlikely(host->part_buf_count)) {
+		int len = dw_mci_push_part_bytes(host, buf, cnt);
+
+		buf += len;
+		cnt -= len;
+
+		if (host->part_buf_count == 8) {
+			mci_fifo_l_writeq(host->fifo_reg, host->part_buf);
+			host->part_buf_count = 0;
+		}
+	}
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+	if (unlikely((unsigned long)buf & 0x7)) {
+		while (cnt >= 8) {
+			u64 aligned_buf[16];
+			int len = min(cnt & -8, (int)sizeof(aligned_buf));
+			int items = len >> 3;
+			int i;
+			/* memcpy from input buffer into aligned buffer */
+			memcpy(aligned_buf, buf, len);
+			buf += len;
+			cnt -= len;
+			/* push data from aligned buffer into fifo */
+			for (i = 0; i < items; ++i)
+				mci_fifo_l_writeq(host->fifo_reg, aligned_buf[i]);
+		}
+	} else
+#endif
+	{
+		u64 *pdata = buf;
+
+		for (; cnt >= 8; cnt -= 8)
+			mci_fifo_l_writeq(host->fifo_reg, *pdata++);
+		buf = pdata;
+	}
+	/* put anything remaining in the part_buf */
+	if (cnt) {
+		dw_mci_set_part_bytes(host, buf, cnt);
+		/* Push data if we have reached the expected data length */
+		if ((data->bytes_xfered + init_cnt) ==
+		    (data->blksz * data->blocks))
+			mci_fifo_l_writeq(host->fifo_reg, host->part_buf);
+	}
+}
+
+static void dw_mci_pull_data64_32(struct dw_mci *host, void *buf, int cnt)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+	if (unlikely((unsigned long)buf & 0x7)) {
+		while (cnt >= 8) {
+			/* pull data from fifo into aligned buffer */
+			u64 aligned_buf[16];
+			int len = min(cnt & -8, (int)sizeof(aligned_buf));
+			int items = len >> 3;
+			int i;
+
+			for (i = 0; i < items; ++i)
+				aligned_buf[i] = mci_fifo_l_readq(host->fifo_reg);
+
+			/* memcpy from aligned buffer into output buffer */
+			memcpy(buf, aligned_buf, len);
+			buf += len;
+			cnt -= len;
+		}
+	} else
+#endif
+	{
+		u64 *pdata = buf;
+
+		for (; cnt >= 8; cnt -= 8)
+			*pdata++ = mci_fifo_l_readq(host->fifo_reg);
+		buf = pdata;
+	}
+	if (cnt) {
+		host->part_buf = mci_fifo_l_readq(host->fifo_reg);
+		dw_mci_pull_final_bytes(host, buf, cnt);
+	}
+}
+
 static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
 {
 	int len;
@@ -3379,8 +3464,13 @@ int dw_mci_probe(struct dw_mci *host)
 		width = 16;
 		host->data_shift = 1;
 	} else if (i == 2) {
-		host->push_data = dw_mci_push_data64;
-		host->pull_data = dw_mci_pull_data64;
+		if ((host->quirks & DW_MMC_QUIRK_FIFO64_32)) {
+			host->push_data = dw_mci_push_data64_32;
+			host->pull_data = dw_mci_pull_data64_32;
+		} else {
+			host->push_data = dw_mci_push_data64;
+			host->pull_data = dw_mci_pull_data64;
+		}
 		width = 64;
 		host->data_shift = 3;
 	} else {
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 6447b916990dc..5463392dc8110 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -281,6 +281,8 @@ struct dw_mci_board {
 
 /* Support for longer data read timeout */
 #define DW_MMC_QUIRK_EXTENDED_TMOUT            BIT(0)
+/* Force 32-bit access to the FIFO */
+#define DW_MMC_QUIRK_FIFO64_32                 BIT(1)
 
 #define DW_MMC_240A		0x240a
 #define DW_MMC_280A		0x280a
@@ -472,6 +474,31 @@ struct dw_mci_board {
 #define mci_fifo_writel(__value, __reg)	__raw_writel(__reg, __value)
 #define mci_fifo_writeq(__value, __reg)	__raw_writeq(__reg, __value)
 
+/*
+ * Some dw_mmc devices have 64-bit FIFOs, but expect them to be
+ * accessed using two 32-bit accesses. If such controller is used
+ * with a 64-bit kernel, this has to be done explicitly.
+ */
+static inline u64 mci_fifo_l_readq(void __iomem *addr)
+{
+	u64 ans;
+	u32 proxy[2];
+
+	proxy[0] = mci_fifo_readl(addr);
+	proxy[1] = mci_fifo_readl(addr + 4);
+	memcpy(&ans, proxy, 8);
+	return ans;
+}
+
+static inline void mci_fifo_l_writeq(void __iomem *addr, u64 value)
+{
+	u32 proxy[2];
+
+	memcpy(proxy, &value, 8);
+	mci_fifo_writel(addr, proxy[0]);
+	mci_fifo_writel(addr + 4, proxy[1]);
+}
+
 /* Register access macros */
 #define mci_readl(dev, reg)			\
 	readl_relaxed((dev)->regs + SDMMC_##reg)
-- 
2.39.5


  parent reply	other threads:[~2025-03-31 14:55 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-31 14:53 [PATCH AUTOSEL 6.13 01/24] platform/chrome: cros_ec_lpc: Match on Framework ACPI device Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 02/24] ASoC: SOF: topology: Use krealloc_array() to replace krealloc() Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 03/24] HID: pidff: Convert infinite length from Linux API to PID standard Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 04/24] HID: pidff: Do not send effect envelope if it's empty Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 05/24] HID: pidff: Add MISSING_DELAY quirk and its detection Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 06/24] HID: pidff: Add MISSING_PBO " Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 07/24] HID: pidff: Add PERMISSIVE_CONTROL quirk Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 08/24] HID: pidff: Add hid_pidff_init_with_quirks and export as GPL symbol Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 09/24] HID: pidff: Add FIX_WHEEL_DIRECTION quirk Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 10/24] HID: Add hid-universal-pidff driver and supported device ids Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 11/24] HID: pidff: Add PERIODIC_SINE_ONLY quirk Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 12/24] HID: pidff: Fix null pointer dereference in pidff_find_fields Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 13/24] ASoC: amd: ps: use macro for ACP6.3 pci revision id Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 14/24] ASoC: amd: amd_sdw: Add quirks for Dell SKU's Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 15/24] ALSA: hda: intel: Fix Optimus when GPU has no sound Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 16/24] ALSA: hda: intel: Add Lenovo IdeaPad Z570 to probe denylist Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 17/24] ASoC: fsl_audmix: register card device depends on 'dais' property Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 18/24] media: uvcvideo: Add quirk for Actions UVC05 Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 19/24] media: s5p-mfc: Corrected NV12M/NV21M plane-sizes Sasha Levin
2025-03-31 14:54 ` Sasha Levin [this message]
2025-03-31 14:54 ` [PATCH AUTOSEL 6.13 21/24] ALSA: usb-audio: Fix CME quirk for UF series keyboards Sasha Levin
2025-03-31 14:54 ` [PATCH AUTOSEL 6.13 22/24] ASoC: amd: Add DMI quirk for ACP6X mic support Sasha Levin
2025-03-31 14:54 ` [PATCH AUTOSEL 6.13 23/24] ASoC: amd: yc: update quirk data for new Lenovo model Sasha Levin
2025-03-31 14:54 ` [PATCH AUTOSEL 6.13 24/24] platform/x86: x86-android-tablets: Add select POWER_SUPPLY to Kconfig Sasha Levin

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=20250331145404.1705141-20-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=jh80.chung@samsung.com \
    --cc=kauschluss@disroot.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=ulf.hansson@linaro.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