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
next prev 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