All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V5 00/26] Add support UHS-II for GL9755
@ 2022-10-19 11:06 Victor Shih
  2022-10-19 11:06 ` [PATCH V5 01/26] mmc: core: Cleanup printing of speed mode at card insertion Victor Shih
                   ` (27 more replies)
  0 siblings, 28 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih

Summary
=======
These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.

About UHS-II, roughly deal with the following three parts:
1) A UHS-II detection and initialization:
- Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
  [2]).
- Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
- In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
  3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
  Setup Sequence.

2) Send Legacy SD command through SD-TRAN
- Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
  compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
  Types and Format Overview[3]).
- Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
  CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).

3) UHS-II Interrupt
- Except for UHS-II error interrupts, most interrupts share the original
  interrupt registers.

Patch structure
===============
patch#1-#6:  for core
patch#7-#25: for sdhci
patch#26:    for GL9755

Changes in v5 (Oct. 19, 2022)
* rebased to the linux-kernel-v6.1-rc1 in Ulf Hansson next branch.
* according to the guidance and overall architecture provided 
  by Ulf Hansson, Ben Chuang and Jason Lai to implement the
  UHS-2 Core function based on the patches of the [V4,0/6] 
  Preparations to support SD UHS-II cards[5].
* according to the guidance and comments provided by 
  Adrian Hunter, Ben Chuang and AKASHI Takahiro to implement 
  the UHS-2 Host function based on the patches of the 
  [RFC,v3.1,00/27] Add support UHS-II for GL9755[4].
* implement the necessary function to let the UHS-2 Core/Host
  work properly.
* fix most of checkpatch warnings/errors

Reference
=========
[1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
[2] SD Host Controller Simplified Specification 4.20
[3] UHS-II Simplified Addendum 1.02
[4] https://patchwork.kernel.org/project/linux-mmc/cover/20201106022726.19831-1-takahiro.akashi@linaro.org/
[5] https://patchwork.kernel.org/project/linux-mmc/cover/20220418115833.10738-1-jasonlai.genesyslogic@gmail.com/
 
----------------- original cover letter from v3.1 -----------------
This is an interim snapshot of our next version, v4, for enabling
UHS-II on MMC/SD.

It is focused on 'sdhci' side to address Adrian's comments regarding
"modularising" sdhci-uhs2.c.
The whole aim of this version is to get early feedback from Adrian (and
others) on this issue. Without any consensus about the code structure,
it would make little sense to go further ahead on sdhci side.
(Actually, Adrian has made no comments other than "modularising" so far.)

I heavily reworked/refactored sdhci-uhs2.c and re-organised the patch
set to meet what I believe Adrian expects; no UHS-II related code in
Legacy (UHS-I) code or sdhci.c.

Nevertheless, almost of all changes I made are trivial and straightforward
in this direction, and I believe that there is no logic changed since v3
except sdhci_uhs2_irq(), as ops->irq hook, where we must deal with UHS-II
command sequences in addition to UHS-II errors. So I added extra handlings.

I admit that there is plenty of room for improvements (for example,
handling host->flags), but again the focal point here is how sdhci-uhs2.c
should be built as a module.

Please review this series (particularly Patch#8-#26 and #27) from this
viewpoint in the first place.
(Ben is working on 'host' side but there is no change on 'host' side
in this submission except a minor tweak.)

Thanks,
-Takahiro Akashi

------ original cover letter from v3 ------
Summary
=======
These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.

About UHS-II, roughly deal with the following three parts:
1) A UHS-II detection and initialization:
- Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
  [2]).
- Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
- In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
  3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
  Setup Sequence.

2) Send Legacy SD command through SD-TRAN
- Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
  compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
  Types and Format Overview[3]).
- Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
  CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).

3) UHS-II Interrupt
- Except for UHS-II error interrupts, most interrupts share the original
  interrupt registers.

Patch structure
===============
patch#1-#7: for core
patch#8-#17: for sdhci
patch#18-#21: for GL9755

Tests
=====
Ran 'dd' command to evaluate the performance:
(SanDisk UHS-II card on GL9755 controller)
                             Read    Write
UHS-II disabled (UHS-I): 88.3MB/s 60.7MB/s
UHS-II enabled         :  206MB/s   80MB/s

TODO
====
- replace some define with BIT macro

Reference
=========
[1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
[2] SD Host Controller Simplified Specification 4.20
[3] UHS-II Simplified Addendum 1.02

Changes in v3 (Jul. 10, 2020)
* rebased to v5.8-rc4
* add copyright notice
* reorganize the patch set and split some commits into smaller ones
* separate uhs-2 headers from others
* correct wrong spellings
* fix most of checkpatch warnings/errors
* remove all k[cz]alloc() from the code
* guard sdhci-uhs2 specific code with
      'if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))'
* make sdhci-uhs2.c as a module
* trivial changes, including
  - rename back sdhci-core.c to sdhci.c
  - allow vendor code to disable uhs2 if v4_mode == 0
      in __sdhci_add_host()
  - merge uhs2_power_up() into mmc_power_up()
  - remove flag_uhs2 from mmc_attach_sd()
  - add function descriptions to EXPORT'ed functions
  - other minor code optimization

Changes in v2 (Jan. 9, 2020)
* rebased to v5.5-rc5

AKASHI Takahiro (5):
  mmc: sdhci: add a kernel configuration for enabling UHS-II support
  mmc: sdhci: add UHS-II module
  mmc: sdhci-uhs2: dump UHS-II registers
  mmc: sdhci-uhs2: add set_timeout()
  mmc: sdhci-pci: add UHS-II support framework

Ben Chuang (1):
  mmc: sdhci-uhs2: add post-mmc_attach_sd hook

Ulf Hansson (4):
  mmc: core: Cleanup printing of speed mode at card insertion
  mmc: core: Prepare to support SD UHS-II cards
  mmc: core: Announce successful insertion of an SD UHS-II card
  mmc: core: Extend support for mmc regulators with a vqmmc2

Victor Shih (16):
  mmc: core: Add definitions for SD UHS-II cards
  mmc: core: Support UHS-II card control and access
  mmc: sdhci: add UHS-II related definitions in headers
  mmc: sdhci-uhs2: add reset function and uhs2_mode function
  mmc: sdhci-uhs2: add set_power() to support vdd2
  mmc: sdhci-uhs2: skip signal_voltage_switch()
  mmc: sdhci-uhs2: add set_ios()
  mmc: sdhci-uhs2: add detect_init() to detect the interface
  mmc: sdhci-uhs2: add clock operations
  mmc: sdhci-uhs2: add uhs2_control() to initialise the interface
  mmc: sdhci-uhs2: add request() and others
  mmc: sdhci-uhs2: add irq() and others
  mmc: sdhci-uhs2: add add_host() and others to set up the driver
  mmc: sdhci-uhs2: add pre-detect_init hook
  mmc: core: add post-mmc_attach_sd hook
  mmc: sdhci-pci-gli: enable UHS-II mode for GL9755

 drivers/mmc/core/Makefile         |    2 +-
 drivers/mmc/core/block.c          |    6 +-
 drivers/mmc/core/bus.c            |   38 +-
 drivers/mmc/core/core.c           |   49 +-
 drivers/mmc/core/core.h           |    1 +
 drivers/mmc/core/host.h           |    4 +
 drivers/mmc/core/mmc_ops.c        |   25 +-
 drivers/mmc/core/mmc_ops.h        |    1 +
 drivers/mmc/core/regulator.c      |   34 +
 drivers/mmc/core/sd.c             |   16 +-
 drivers/mmc/core/sd.h             |    3 +
 drivers/mmc/core/sd_ops.c         |   18 +
 drivers/mmc/core/sd_ops.h         |    3 +
 drivers/mmc/core/sd_uhs2.c        | 1394 +++++++++++++++++++++++++
 drivers/mmc/host/Kconfig          |   10 +
 drivers/mmc/host/Makefile         |    1 +
 drivers/mmc/host/sdhci-pci-core.c |   17 +-
 drivers/mmc/host/sdhci-pci-gli.c  |  310 +++++-
 drivers/mmc/host/sdhci-pci.h      |    3 +
 drivers/mmc/host/sdhci-uhs2.c     | 1606 +++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h     |  226 ++++
 drivers/mmc/host/sdhci.c          |  342 +++---
 drivers/mmc/host/sdhci.h          |  125 ++-
 include/linux/mmc/card.h          |   47 +
 include/linux/mmc/core.h          |   13 +
 include/linux/mmc/host.h          |   99 ++
 include/linux/mmc/sd_uhs2.h       |  263 +++++
 27 files changed, 4486 insertions(+), 170 deletions(-)
 create mode 100644 drivers/mmc/core/sd_uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h
 create mode 100644 include/linux/mmc/sd_uhs2.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH V5 01/26] mmc: core: Cleanup printing of speed mode at card insertion
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:06 ` [PATCH V5 02/26] mmc: core: Prepare to support SD UHS-II cards Victor Shih
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih

From: Ulf Hansson <ulf.hansson@linaro.org>

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 <ulf.hansson@linaro.org>
---
 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 d8762fa3d5cd..088ec34299c8 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -299,6 +299,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 ",
@@ -337,27 +338,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);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 02/26] mmc: core: Prepare to support SD UHS-II cards
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
  2022-10-19 11:06 ` [PATCH V5 01/26] mmc: core: Cleanup printing of speed mode at card insertion Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-04 12:16   ` Christophe JAILLET
  2022-10-19 11:06 ` [PATCH V5 03/26] mmc: core: Announce successful insertion of an SD UHS-II card Victor Shih
                   ` (25 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih

From: Ulf Hansson <ulf.hansson@linaro.org>

Updates in V4:
 - Re-based, updated a comment and removed white-space.
 - Moved MMC_VQMMC2_VOLTAGE_180 into a later patch in the series.

Update in previous version:
The SD UHS-II interface was introduced to the SD spec v4.00 several years
ago. The interface is fundamentally different from an electrical and a
protocol point of view, comparing to the legacy SD interface.

However, the legacy SD protocol is supported through a specific transport
layer (SD-TRAN) defined in the UHS-II addendum of the spec. This allows the
SD card to be managed in a very similar way as a legacy SD card, hence a
lot of code can be re-used to support these new types of cards through the
mmc subsystem.

Moreover, an SD card that supports the UHS-II interface shall also be
backwards compatible with the legacy SD interface, which allows a UHS-II
card to be inserted into a legacy slot. As a matter of fact, this is
already supported by mmc subsystem as of today.

To prepare to add support for UHS-II, this change puts the basic foundation
in the mmc core in place, allowing it to be more easily reviewed before
subsequent changes implements the actual support.

Basically, the approach here adds a new UHS-II bus_ops type and adds a
separate initialization path for the UHS-II card. The intent is to avoid us
from sprinkling the legacy initialization path, but also to simplify
implementation of the UHS-II specific bits.

At this point, there is only one new host ops added to manage the various
ios settings needed for UHS-II. Additional host ops that are needed, are
being added from subsequent changes.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/Makefile  |   2 +-
 drivers/mmc/core/core.c    |  17 ++-
 drivers/mmc/core/core.h    |   1 +
 drivers/mmc/core/sd_uhs2.c | 289 +++++++++++++++++++++++++++++++++++++
 include/linux/mmc/card.h   |   7 +
 include/linux/mmc/host.h   |  19 +++
 6 files changed, 333 insertions(+), 2 deletions(-)
 create mode 100644 drivers/mmc/core/sd_uhs2.c

diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 6a907736cd7a..15b067e8b0d1 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_MMC)		+= mmc_core.o
 mmc_core-y			:= core.o bus.o host.o \
 				   mmc.o mmc_ops.o sd.o sd_ops.o \
 				   sdio.o sdio_ops.o sdio_bus.o \
-				   sdio_cis.o sdio_io.o sdio_irq.o \
+				   sdio_cis.o sdio_io.o sdio_irq.o sd_uhs2.o\
 				   slot-gpio.o regulator.o
 mmc_core-$(CONFIG_OF)		+= pwrseq.o
 obj-$(CONFIG_PWRSEQ_SIMPLE)	+= pwrseq_simple.o
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 95fa8fb1d45f..8818a20571f7 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2234,6 +2234,18 @@ void mmc_rescan(struct work_struct *work)
 		goto out;
 	}
 
+	/*
+	 * Ideally we should favor initialization of legacy SD cards and defer
+	 * UHS-II enumeration. However, it seems like cards doesn't reliably
+	 * announce their support for UHS-II in the response to the ACMD41,
+	 * while initializing the legacy SD interface. Therefore, let's start
+	 * with UHS-II for now.
+	 */
+	if (!mmc_attach_sd_uhs2(host)) {
+		mmc_release_host(host);
+		goto out;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
 		unsigned int freq = freqs[i];
 		if (freq > host->f_max) {
@@ -2261,10 +2273,13 @@ void mmc_rescan(struct work_struct *work)
 
 void mmc_start_host(struct mmc_host *host)
 {
+	bool power_up = !(host->caps2 &
+			 (MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_SD_UHS2));
+
 	host->f_init = max(min(freqs[0], host->f_max), host->f_min);
 	host->rescan_disable = 0;
 
-	if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
+	if (power_up) {
 		mmc_claim_host(host);
 		mmc_power_up(host, host->ocr_avail);
 		mmc_release_host(host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index f5f3f623ea49..2d80afc95e58 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -81,6 +81,7 @@ int mmc_detect_card_removed(struct mmc_host *host);
 int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
 int mmc_attach_sdio(struct mmc_host *host);
+int mmc_attach_sd_uhs2(struct mmc_host *host);
 
 /* Module parameters */
 extern bool use_spi_crc;
diff --git a/drivers/mmc/core/sd_uhs2.c b/drivers/mmc/core/sd_uhs2.c
new file mode 100644
index 000000000000..800957f74632
--- /dev/null
+++ b/drivers/mmc/core/sd_uhs2.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Linaro Ltd
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * Support for SD UHS-II cards
+ */
+#include <linux/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+
+#include "core.h"
+#include "bus.h"
+#include "sd.h"
+#include "mmc_ops.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;
+
+	return host->ops->uhs2_set_ios(host, ios);
+}
+
+static int sd_uhs2_power_up(struct mmc_host *host)
+{
+	host->ios.vdd = fls(host->ocr_avail) - 1;
+	host->ios.clock = host->f_init;
+	host->ios.timing = MMC_TIMING_SD_UHS2;
+	host->ios.power_mode = MMC_POWER_UP;
+
+	return sd_uhs2_set_ios(host);
+}
+
+static void sd_uhs2_power_off(struct mmc_host *host)
+{
+	host->ios.vdd = 0;
+	host->ios.clock = 0;
+	host->ios.timing = MMC_TIMING_LEGACY;
+	host->ios.power_mode = MMC_POWER_OFF;
+
+	sd_uhs2_set_ios(host);
+}
+
+/*
+ * 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
+ * the card.
+ */
+static int sd_uhs2_phy_init(struct mmc_host *host)
+{
+	return 0;
+}
+
+/*
+ * Do the early initialization of the card, by sending the device init broadcast
+ * command and wait for the process to be completed.
+ */
+static int sd_uhs2_dev_init(struct mmc_host *host)
+{
+	return 0;
+}
+
+/*
+ * Run the enumeration process by sending the enumerate command to the card.
+ * Note that, we currently support only the point to point connection, which
+ * means only one card can be attached per host/slot.
+ */
+static int sd_uhs2_enum(struct mmc_host *host, u32 *node_id)
+{
+	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.
+ */
+static int sd_uhs2_config_read(struct mmc_host *host, struct mmc_card *card)
+{
+	return 0;
+}
+
+/*
+ * Based on the card's and host's UHS-II capabilities, let's update the
+ * configuration of the card and the host. This may also include to move to a
+ * greater speed range/mode. Depending on the updated configuration, we may need
+ * to do a soft reset of the card via sending it a GO_DORMANT_STATE command.
+ *
+ * In the final step, let's check if the card signals "config completion", which
+ * indicates that the card has moved from config state into active state.
+ */
+static int sd_uhs2_config_write(struct mmc_host *host, struct mmc_card *card)
+{
+	return 0;
+}
+
+/*
+ * Initialize the UHS-II card through the SD-TRAN transport layer. This enables
+ * commands/requests to be backwards compatible through the legacy SD protocol.
+ * UHS-II cards has a specific power limit specified for VDD1/VDD2, that should
+ * be set through a legacy CMD6. Note that, the power limit that becomes set,
+ * survives a soft reset through the GO_DORMANT_STATE command.
+ */
+static int sd_uhs2_legacy_init(struct mmc_host *host, struct mmc_card *card)
+{
+	return 0;
+}
+
+/*
+ * Allocate the data structure for the mmc_card and run the UHS-II specific
+ * initialization sequence.
+ */
+static int sd_uhs2_init_card(struct mmc_host *host)
+{
+	struct mmc_card *card;
+	u32 node_id;
+	int err;
+
+	err = sd_uhs2_dev_init(host);
+	if (err)
+		return err;
+
+	err = sd_uhs2_enum(host, &node_id);
+	if (err)
+		return err;
+
+	card = mmc_alloc_card(host, &sd_type);
+	if (IS_ERR(card))
+		return PTR_ERR(card);
+
+	card->uhs2_config.node_id = node_id;
+	card->type = MMC_TYPE_SD;
+
+	err = sd_uhs2_config_read(host, card);
+	if (err)
+		goto err;
+
+	err = sd_uhs2_config_write(host, card);
+	if (err)
+		goto err;
+
+	err = sd_uhs2_legacy_init(host, card);
+	if (err)
+		goto err;
+
+	host->card = card;
+	return 0;
+
+err:
+	mmc_remove_card(card);
+	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);
+}
+
+static void sd_uhs2_detect(struct mmc_host *host)
+{
+	int err;
+
+	mmc_get_card(host->card, NULL);
+	err = _mmc_detect_card_removed(host);
+	mmc_put_card(host->card, NULL);
+
+	if (err) {
+		sd_uhs2_remove(host);
+
+		mmc_claim_host(host);
+		mmc_detach_bus(host);
+		sd_uhs2_power_off(host);
+		mmc_release_host(host);
+	}
+}
+
+static int sd_uhs2_suspend(struct mmc_host *host)
+{
+	return 0;
+}
+
+static int sd_uhs2_resume(struct mmc_host *host)
+{
+	return 0;
+}
+
+static int sd_uhs2_runtime_suspend(struct mmc_host *host)
+{
+	return 0;
+}
+
+static int sd_uhs2_runtime_resume(struct mmc_host *host)
+{
+	return 0;
+}
+
+static int sd_uhs2_shutdown(struct mmc_host *host)
+{
+	return 0;
+}
+
+static int sd_uhs2_hw_reset(struct mmc_host *host)
+{
+	return 0;
+}
+
+static const struct mmc_bus_ops sd_uhs2_ops = {
+	.remove = sd_uhs2_remove,
+	.alive = sd_uhs2_alive,
+	.detect = sd_uhs2_detect,
+	.suspend = sd_uhs2_suspend,
+	.resume = sd_uhs2_resume,
+	.runtime_suspend = sd_uhs2_runtime_suspend,
+	.runtime_resume = sd_uhs2_runtime_resume,
+	.shutdown = sd_uhs2_shutdown,
+	.hw_reset = sd_uhs2_hw_reset,
+};
+
+static int sd_uhs2_attach(struct mmc_host *host)
+{
+	int err;
+
+	err = sd_uhs2_power_up(host);
+	if (err)
+		goto err;
+
+	err = sd_uhs2_phy_init(host);
+	if (err)
+		goto err;
+
+	err = sd_uhs2_init_card(host);
+	if (err)
+		goto err;
+
+	mmc_attach_bus(host, &sd_uhs2_ops);
+
+	mmc_release_host(host);
+
+	err = mmc_add_card(host->card);
+	if (err)
+		goto remove_card;
+
+	mmc_claim_host(host);
+	return 0;
+
+remove_card:
+	mmc_remove_card(host->card);
+	host->card = NULL;
+	mmc_claim_host(host);
+	mmc_detach_bus(host);
+err:
+	sd_uhs2_power_off(host);
+	return err;
+}
+
+int mmc_attach_sd_uhs2(struct mmc_host *host)
+{
+	int i, err = 0;
+
+	if (!(host->caps2 & MMC_CAP2_SD_UHS2))
+		return -EOPNOTSUPP;
+
+	/* Turn off the legacy SD interface before trying with UHS-II. */
+	mmc_power_off(host);
+
+	/*
+	 * Start UHS-II initialization at 52MHz and possibly make a retry at
+	 * 26MHz according to the spec. It's required that the host driver
+	 * validates ios->clock, to set a rate within the correct range.
+	 */
+	for (i = 0; i < ARRAY_SIZE(sd_uhs2_freqs); i++) {
+		host->f_init = sd_uhs2_freqs[i];
+		err = sd_uhs2_attach(host);
+		if (!err)
+			break;
+	}
+
+	return err;
+}
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c726ea781255..4a42f31b7bb0 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -211,6 +211,11 @@ struct sd_ext_reg {
 #define SD_EXT_PERF_CMD_QUEUE	(1<<4)
 };
 
+struct sd_uhs2_config {
+	u32			node_id;
+	/* TODO: Extend with more register configs. */
+};
+
 struct sdio_cccr {
 	unsigned int		sdio_vsn;
 	unsigned int		sd_vsn;
@@ -317,6 +322,8 @@ struct mmc_card {
 	struct sd_ext_reg	ext_power;	/* SD extension reg for PM */
 	struct sd_ext_reg	ext_perf;	/* SD extension reg for PERF */
 
+	struct sd_uhs2_config	uhs2_config;	/* SD UHS-II config */
+
 	unsigned int		sdio_funcs;	/* number of SDIO functions */
 	atomic_t		sdio_funcs_probed; /* number of probed SDIO funcs */
 	struct sdio_cccr	cccr;		/* common card info */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 8fdd3cf971a3..150d10d5e6f8 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -63,6 +63,7 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_HS400	10
 #define MMC_TIMING_SD_EXP	11
 #define MMC_TIMING_SD_EXP_1_2V	12
+#define MMC_TIMING_SD_UHS2	13
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -91,6 +92,10 @@ struct mmc_clk_phase_map {
 	struct mmc_clk_phase phase[MMC_NUM_CLK_PHASES];
 };
 
+struct sd_uhs2_caps {
+	/* TODO: Add UHS-II capabilities for the host. */
+};
+
 struct mmc_host;
 
 enum mmc_err_stat {
@@ -145,6 +150,17 @@ struct mmc_host_ops {
 	 */
 	void	(*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
 
+	/*
+	 * The uhs2_set_ios callback is mandatory to implement for hosts that
+	 * supports the SD UHS-II interface (MMC_CAP2_SD_UHS2), while the
+	 * callback is unused for the other cases. Note that, the struct
+	 * mmc_ios is being re-used for this as well.
+	 *
+	 * Expected return values for the uhs2_set_ios callback are a negative
+	 * errno in case of a failure or zero for success.
+	 */
+	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
@@ -396,6 +412,7 @@ struct mmc_host {
 				 MMC_CAP2_HS200_1_2V_SDR)
 #define MMC_CAP2_SD_EXP		(1 << 7)	/* SD express via PCIe */
 #define MMC_CAP2_SD_EXP_1_2V	(1 << 8)	/* SD express 1.2V */
+#define MMC_CAP2_SD_UHS2	(1 << 9)	/* SD UHS-II support */
 #define MMC_CAP2_CD_ACTIVE_HIGH	(1 << 10)	/* Card-detect signal active high */
 #define MMC_CAP2_RO_ACTIVE_HIGH	(1 << 11)	/* Write-protect signal active high */
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
@@ -422,6 +439,8 @@ struct mmc_host {
 #endif
 #define MMC_CAP2_ALT_GPT_TEGRA	(1 << 28)	/* Host with eMMC that has GPT entry at a non-standard location */
 
+	struct sd_uhs2_caps	uhs2_caps;	/* Host UHS-II capabilities */
+
 	int			fixed_drv_type;	/* fixed driver type for non-removable media */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 03/26] mmc: core: Announce successful insertion of an SD UHS-II card
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
  2022-10-19 11:06 ` [PATCH V5 01/26] mmc: core: Cleanup printing of speed mode at card insertion Victor Shih
  2022-10-19 11:06 ` [PATCH V5 02/26] mmc: core: Prepare to support SD UHS-II cards Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:06 ` [PATCH V5 04/26] mmc: core: Extend support for mmc regulators with a vqmmc2 Victor Shih
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih

From: Ulf Hansson <ulf.hansson@linaro.org>

Updates in V4:
 - Make mmc_card_uhs2() take struct mmc_host* as in-param.

Update in previous version:
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 <ulf.hansson@linaro.org>
---
 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 088ec34299c8..dcfbd014a871 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -341,7 +341,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->host))
+		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 48c4952512a5..ba6a80e9b360 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -89,5 +89,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_host *host)
+{
+	return host->ios.timing == MMC_TIMING_SD_UHS2;
+}
 #endif
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 04/26] mmc: core: Extend support for mmc regulators with a vqmmc2
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (2 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 03/26] mmc: core: Announce successful insertion of an SD UHS-II card Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:06 ` [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards Victor Shih
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih

From: Ulf Hansson <ulf.hansson@linaro.org>

Updates in V4:
 - Moved the voltage defines into this patch.

Update in previous version:
To allow an additional external regulator to be controlled by an mmc host
driver, let's add support for a vqmmc2 regulator to the mmc core.

For an SD UHS-II interface the vqmmc2 regulator may correspond to the so
called vdd2 supply, as described by the SD spec. Initially, only 1.8V is
needed, hence limit the new helper function, mmc_regulator_set_vqmmc2() to
this too.

Note that, to allow for flexibility mmc host drivers need to manage the
enable/disable of the vqmmc2 regulator themselves, while the regulator is
looked up through the common mmc_regulator_get_supply().

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/regulator.c | 34 ++++++++++++++++++++++++++++++++++
 include/linux/mmc/host.h     | 11 +++++++++++
 2 files changed, 45 insertions(+)

diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c
index 609201a467ef..3c189682797c 100644
--- a/drivers/mmc/core/regulator.c
+++ b/drivers/mmc/core/regulator.c
@@ -223,6 +223,33 @@ int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios)
 }
 EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc);
 
+/**
+ * mmc_regulator_set_vqmmc2 - Set vqmmc2 as per the ios->vqmmc2_voltage
+ * @mmc: The mmc host to regulate
+ * @ios: The io bus settings
+ *
+ * Sets a new voltage level for the vqmmc2 regulator, which may correspond to
+ * the vdd2 regulator for an SD UHS-II interface. This function is expected to
+ * be called by mmc host drivers.
+ *
+ * Returns a negative error code on failure, zero if the voltage level was
+ * changed successfully or a positive value if the level didn't need to change.
+ */
+int mmc_regulator_set_vqmmc2(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	if (IS_ERR(mmc->supply.vqmmc2))
+		return -EINVAL;
+
+	switch (ios->vqmmc2_voltage) {
+	case MMC_VQMMC2_VOLTAGE_180:
+		return mmc_regulator_set_voltage_if_supported(
+			mmc->supply.vqmmc2, 1700000, 1800000, 1950000);
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc2);
+
 #else
 
 static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
@@ -249,6 +276,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
 
 	mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
 	mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
+	mmc->supply.vqmmc2 = devm_regulator_get_optional(dev, "vqmmc2");
 
 	if (IS_ERR(mmc->supply.vmmc)) {
 		if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
@@ -268,6 +296,12 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
 		dev_dbg(dev, "No vqmmc regulator found\n");
 	}
 
+	if (IS_ERR(mmc->supply.vqmmc2)) {
+		if (PTR_ERR(mmc->supply.vqmmc2) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		dev_dbg(dev, "No vqmmc2 regulator found\n");
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 150d10d5e6f8..895bcf7f80b7 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -71,6 +71,9 @@ struct mmc_ios {
 #define MMC_SIGNAL_VOLTAGE_180	1
 #define MMC_SIGNAL_VOLTAGE_120	2
 
+	unsigned char	vqmmc2_voltage;
+#define MMC_VQMMC2_VOLTAGE_180	0
+
 	unsigned char	drv_type;		/* driver type (A, B, C, D) */
 
 #define MMC_SET_DRIVER_TYPE_B	0
@@ -321,6 +324,7 @@ struct mmc_pwrseq;
 struct mmc_supply {
 	struct regulator *vmmc;		/* Card power supply */
 	struct regulator *vqmmc;	/* Optional Vccq supply */
+	struct regulator *vqmmc2;	/* Optional supply for phy */
 };
 
 struct mmc_ctx {
@@ -600,6 +604,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
 			struct regulator *supply,
 			unsigned short vdd_bit);
 int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios);
+int mmc_regulator_set_vqmmc2(struct mmc_host *mmc, struct mmc_ios *ios);
 #else
 static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
 				 struct regulator *supply,
@@ -613,6 +618,12 @@ static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc,
 {
 	return -EINVAL;
 }
+
+static inline int mmc_regulator_set_vqmmc2(struct mmc_host *mmc,
+					   struct mmc_ios *ios)
+{
+	return -EINVAL;
+}
 #endif
 
 int mmc_regulator_get_supply(struct mmc_host *mmc);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (3 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 04/26] mmc: core: Extend support for mmc regulators with a vqmmc2 Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:12   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 06/26] mmc: core: Support UHS-II card control and access Victor Shih
                   ` (22 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Jason Lai

Add UHS-II specific data structures for commands and defines for
registers, as described in Part 1 UHS-II Addendum Version 1.01.

UHS-II related definitions are listed below:
  1. UHS-II card capability: sd_uhs2_caps{}
  2. UHS-II configuration: sd_uhs2_config{}
  3. UHS-II Command structure: uhs2_command{}
  4. UHS-II register I/O address and register field definitions: sd_uhs2.h

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---

Updates in V5:
 - Added UHS2 interfaces in mmc_host_ops: host.h
 - Added UHS2 VDD2 power supply in mmc_supply: host.h
 - Added UHS2-specific OCR and UHS2 VDD2 max current in mmc_host: host.h
 - Added definition of UHS2 VDD2 1.65v-1.95v in mmc_host: host.h
 - Added flags/MMC_UHS2_SUPPORT/MMC_UHS2_2L_HD in mmc_host: host.h
---
 include/linux/mmc/card.h    |  42 +++++-
 include/linux/mmc/core.h    |  13 ++
 include/linux/mmc/host.h    |  70 +++++++++-
 include/linux/mmc/sd_uhs2.h | 263 ++++++++++++++++++++++++++++++++++++
 4 files changed, 386 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/mmc/sd_uhs2.h

diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 4a42f31b7bb0..d638a2c689cf 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -190,6 +190,13 @@ struct sd_switch_caps {
 #define SD_MAX_CURRENT_400	(1 << SD_SET_CURRENT_LIMIT_400)
 #define SD_MAX_CURRENT_600	(1 << SD_SET_CURRENT_LIMIT_600)
 #define SD_MAX_CURRENT_800	(1 << SD_SET_CURRENT_LIMIT_800)
+	unsigned int		sd4_curr_limit;
+#define SD4_SET_POWER_LIMIT_0_72W	0
+#define SD4_SET_POWER_LIMIT_1_44W	1
+#define SD4_SET_POWER_LIMIT_2_16W	2
+#define SD4_SET_POWER_LIMIT_2_88W	3
+#define SD4_SET_POWER_LIMIT_1_80W	4
+#define SD4_SET_POWER_NO_CHANGE		(-1)
 };
 
 struct sd_ext_reg {
@@ -213,7 +220,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 {
@@ -323,6 +358,9 @@ struct mmc_card {
 	struct sd_ext_reg	ext_perf;	/* SD extension reg for PERF */
 
 	struct sd_uhs2_config	uhs2_config;	/* SD UHS-II config */
+	u8			uhs2_state;	/* SD UHS-II states */
+#define MMC_UHS2_INITIALIZED	BIT(1)
+#define MMC_UHS2_SPEED_B	BIT(2)
 
 	unsigned int		sdio_funcs;	/* number of SDIO functions */
 	atomic_t		sdio_funcs_probed; /* number of probed SDIO funcs */
@@ -364,4 +402,6 @@ bool mmc_card_is_blockaddr(struct mmc_card *card);
 #define mmc_card_sdio(c)	((c)->type == MMC_TYPE_SDIO)
 #define mmc_card_sd_combo(c)	((c)->type == MMC_TYPE_SD_COMBO)
 
+#define mmc_card_can_poweroff_notify(c)	((c)->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY)
+
 #endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 6efec0b9820c..2a0581d87706 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -23,6 +23,14 @@ enum mmc_blk_status {
 	MMC_BLK_NEW_REQUEST,
 };
 
+struct uhs2_command {
+	u16	header;
+	u16	arg;
+	__be32	*payload;
+	u32	payload_len;
+	u32	packet_len;
+};
+
 struct mmc_command {
 	u32			opcode;
 	u32			arg;
@@ -109,6 +117,11 @@ struct mmc_command {
 	unsigned int		busy_timeout;	/* busy detect timeout in ms */
 	struct mmc_data		*data;		/* data segment associated with cmd */
 	struct mmc_request	*mrq;		/* associated request */
+
+	struct uhs2_command	*uhs2_cmd;	/* UHS2 command */
+	u8			*uhs2_resp;	/* UHS2 native cmd resp */
+	u8			uhs2_resp_len;	/* UHS2 native cmd resp len */
+	u8			uhs2_tmode0_flag; /* UHS2 transfer mode flag */
 };
 
 struct mmc_data {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 895bcf7f80b7..249a9414ad10 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -16,6 +16,7 @@
 #include <linux/mmc/pm.h>
 #include <linux/dma-direction.h>
 #include <linux/blk-crypto-profile.h>
+#include <linux/mmc/sd_uhs2.h>
 
 struct mmc_ios {
 	unsigned int	clock;			/* clock rate */
@@ -96,7 +97,48 @@ struct mmc_clk_phase_map {
 };
 
 struct sd_uhs2_caps {
-	/* TODO: Add UHS-II capabilities for the host. */
+	u32	dap;
+	u32	gap;
+	u32	group_desc;
+	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 sd_uhs2_ios {
+	bool		is_2L_HD_mode;
+	bool		is_APP_CMD;
+	unsigned int	power_delay_ms;		/* waiting for stable power */
+};
+
+enum sd_uhs2_operation {
+	UHS2_PHY_INIT = 0,
+	UHS2_SET_CONFIG,
+	UHS2_ENABLE_INT,
+	UHS2_DISABLE_INT,
+	UHS2_ENABLE_CLK,
+	UHS2_DISABLE_CLK,
+	UHS2_CHECK_DORMANT,
+	UHS2_SET_SPEED_B,
+	UHS2_POST_ATTACH_SD,
 };
 
 struct mmc_host;
@@ -231,6 +273,20 @@ 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 */
+	int	(*uhs2_detect_init)(struct mmc_host *host);
+	int	(*uhs2_set_reg)(struct mmc_host *host, enum sd_uhs2_operation act);
+	int (*uhs2_disable_clk)(struct mmc_host *host);
+	int (*uhs2_enable_clk)(struct mmc_host *host);
+
+	/*
+	 * The uhs2_control callback is used to execute SD UHS-II specific
+	 * operations. It's mandatory to implement for hosts that supports the
+	 * SD UHS-II interface (MMC_CAP2_SD_UHS2). Expected return values are a
+	 * negative errno in case of a failure or zero for success.
+	 */
+	int	(*uhs2_control)(struct mmc_host *host, enum sd_uhs2_operation op);
 };
 
 struct mmc_cqe_ops {
@@ -323,6 +379,7 @@ struct mmc_pwrseq;
 
 struct mmc_supply {
 	struct regulator *vmmc;		/* Card power supply */
+	struct regulator *vmmc2;	/* UHS2 VDD2 power supply */
 	struct regulator *vqmmc;	/* Optional Vccq supply */
 	struct regulator *vqmmc2;	/* Optional supply for phy */
 };
@@ -344,10 +401,12 @@ struct mmc_host {
 	u32			ocr_avail_sdio;	/* SDIO-specific OCR */
 	u32			ocr_avail_sd;	/* SD-specific OCR */
 	u32			ocr_avail_mmc;	/* MMC-specific OCR */
+	u32			ocr_avail_uhs2; /* UHS2-specific OCR */
 	struct wakeup_source	*ws;		/* Enable consume of uevents */
 	u32			max_current_330;
 	u32			max_current_300;
 	u32			max_current_180;
+	u32			max_current_180_vdd2; /* UHS2 vdd2 max curt. */
 
 #define MMC_VDD_165_195		0x00000080	/* VDD voltage 1.65 - 1.95 */
 #define MMC_VDD_20_21		0x00000100	/* VDD voltage 2.0 ~ 2.1 */
@@ -366,6 +425,7 @@ struct mmc_host {
 #define MMC_VDD_33_34		0x00200000	/* VDD voltage 3.3 ~ 3.4 */
 #define MMC_VDD_34_35		0x00400000	/* VDD voltage 3.4 ~ 3.5 */
 #define MMC_VDD_35_36		0x00800000	/* VDD voltage 3.5 ~ 3.6 */
+#define MMC_VDD2_165_195	0x00000080	/* UHS2 VDD2 1.65 ~ 1.95 */
 
 	u32			caps;		/* Host capabilities */
 
@@ -443,7 +503,12 @@ struct mmc_host {
 #endif
 #define MMC_CAP2_ALT_GPT_TEGRA	(1 << 28)	/* Host with eMMC that has GPT entry at a non-standard location */
 
+	int flags;
+#define MMC_UHS2_SUPPORT	(1 << 0)
+#define MMC_UHS2_2L_HD		(1 << 2)
+
 	struct sd_uhs2_caps	uhs2_caps;	/* Host UHS-II capabilities */
+	struct sd_uhs2_ios	uhs2_ios;	/* Host UHS-II capabilities */
 
 	int			fixed_drv_type;	/* fixed driver type for non-removable media */
 
@@ -695,4 +760,7 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
 int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
 int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
 
+#define mmc_uhs2_2L_HD_mode(h)	((h)->uhs2_ios.is_2L_HD_mode)
+#define mmc_uhs2_APP_cmd(h)	((h)->uhs2_ios.is_APP_CMD)
+
 #endif /* LINUX_MMC_HOST_H */
diff --git a/include/linux/mmc/sd_uhs2.h b/include/linux/mmc/sd_uhs2.h
new file mode 100644
index 000000000000..8fcf702cf4a5
--- /dev/null
+++ b/include/linux/mmc/sd_uhs2.h
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Header file for UHS-II packets, Host Controller registers and I/O
+ * accessors.
+ *
+ *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ */
+#ifndef LINUX_MMC_UHS2_H
+#define LINUX_MMC_UHS2_H
+
+/* LINK Layer definition */
+/*
+ * UHS2 Header:
+ * Refer to UHS-II Addendum Version 1.02 Figure 5-2, the format of CCMD Header is described below:
+ *      bit [3:0]  : DID(Destination ID = Node ID of UHS2 card)
+ *      bit [6:4]  : TYP(Packet Type)
+ *                   000b: CCMD(Control command packet)
+ *                   001b: DCMD(Data command packet)
+ *                   010b: RES(Response packet)
+ *                   011b: DATA(Data payload packet)
+ *                   111b: MSG(Message packet)
+ *                   Others: Reserved
+ *      bit [7]    : NP(Native Packet)
+ *      bit [10:8] : TID(Transaction ID)
+ *      bit [11]   : Reserved
+ *      bit [15:12]: SID(Source ID 0: Node ID of Host)
+ *
+ * Broadcast CCMD issued by Host is represented as DID=SID=0.
+ */
+/*
+ * UHS2 Argument:
+ * Refer to UHS-II Addendum Version 1.02 Figure 6-5, the format of CCMD Argument is described below:
+ *      bit [3:0]  : MSB of IOADR
+ *      bit [5:4]  : PLEN(Payload Length)
+ *                   00b: 0 byte
+ *                   01b: 4 bytes
+ *                   10b: 8 bytes
+ *                   11b: 16 bytes
+ *      bit [6]    : Reserved
+ *      bit [7]    : R/W(Read/Write)
+ *                   0: Control read command
+ *                   1: Control write command
+ *      bit [15:8] : LSB of IOADR
+ *
+ * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
+ * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
+ */
+#define UHS2_NATIVE_PACKET_POS	7
+#define UHS2_NATIVE_PACKET	(1 << UHS2_NATIVE_PACKET_POS)
+
+#define UHS2_PACKET_TYPE_POS	4
+#define UHS2_PACKET_TYPE_CCMD	(0 << UHS2_PACKET_TYPE_POS)
+#define UHS2_PACKET_TYPE_DCMD	(1 << UHS2_PACKET_TYPE_POS)
+#define UHS2_PACKET_TYPE_RES	(2 << UHS2_PACKET_TYPE_POS)
+#define UHS2_PACKET_TYPE_DATA	(3 << UHS2_PACKET_TYPE_POS)
+#define UHS2_PACKET_TYPE_MSG	(7 << UHS2_PACKET_TYPE_POS)
+
+#define UHS2_DEST_ID_MASK	0x0F
+#define UHS2_DEST_ID		0x1
+
+#define UHS2_SRC_ID_POS		12
+#define UHS2_SRC_ID_MASK	0xF000
+
+#define UHS2_TRANS_ID_POS	8
+#define UHS2_TRANS_ID_MASK	0x0700
+
+/* UHS2 MSG */
+#define UHS2_MSG_CTG_POS	5
+#define UHS2_MSG_CTG_LMSG	0x00
+#define UHS2_MSG_CTG_INT	0x60
+#define UHS2_MSG_CTG_AMSG	0x80
+
+#define UHS2_MSG_CTG_FCREQ	0x00
+#define UHS2_MSG_CTG_FCRDY	0x01
+#define UHS2_MSG_CTG_STAT	0x02
+
+#define UHS2_MSG_CODE_POS			8
+#define UHS2_MSG_CODE_FC_UNRECOVER_ERR		0x8
+#define UHS2_MSG_CODE_STAT_UNRECOVER_ERR	0x8
+#define UHS2_MSG_CODE_STAT_RECOVER_ERR		0x1
+
+/* TRANS Layer definition */
+
+/* Native packets*/
+#define UHS2_NATIVE_CMD_RW_POS	7
+#define UHS2_NATIVE_CMD_WRITE	(1 << UHS2_NATIVE_CMD_RW_POS)
+#define UHS2_NATIVE_CMD_READ	(0 << UHS2_NATIVE_CMD_RW_POS)
+
+#define UHS2_NATIVE_CMD_PLEN_POS	4
+#define UHS2_NATIVE_CMD_PLEN_4B		(1 << UHS2_NATIVE_CMD_PLEN_POS)
+#define UHS2_NATIVE_CMD_PLEN_8B		(2 << UHS2_NATIVE_CMD_PLEN_POS)
+#define UHS2_NATIVE_CMD_PLEN_16B	(3 << UHS2_NATIVE_CMD_PLEN_POS)
+
+#define UHS2_NATIVE_CCMD_GET_MIOADR_MASK	0xF00
+#define UHS2_NATIVE_CCMD_MIOADR_MASK		0x0F
+
+#define UHS2_NATIVE_CCMD_LIOADR_POS		8
+#define UHS2_NATIVE_CCMD_GET_LIOADR_MASK	0x0FF
+
+#define UHS2_CCMD_DEV_INIT_COMPLETE_FLAG	BIT(11)
+#define UHS2_DEV_INIT_PAYLOAD_LEN		1
+#define UHS2_DEV_INIT_RESP_LEN			6
+#define UHS2_DEV_ENUM_PAYLOAD_LEN		1
+#define UHS2_DEV_ENUM_RESP_LEN			8
+#define UHS2_CFG_WRITE_PAYLOAD_LEN		2
+#define UHS2_CFG_WRITE_PHY_SET_RESP_LEN		4
+#define UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN	5
+#define UHS2_GO_DORMANT_PAYLOAD_LEN		1
+
+/*
+ * UHS2 Argument:
+ * Refer to UHS-II Addendum Version 1.02 Figure 6-8, the format of DCMD Argument is described below:
+ *      bit [3:0]  : Reserved
+ *      bit [6:3]  : TMODE(Transfer Mode)
+ *                   bit 3: DAM(Data Access Mode)
+ *                   bit 4: TLUM(TLEN Unit Mode)
+ *                   bit 5: LM(Length Mode)
+ *                   bit 6: DM(Duplex Mode)
+ *      bit [7]    : R/W(Read/Write)
+ *                   0: Control read command
+ *                   1: Control write command
+ *      bit [15:8] : Reserved
+ *
+ * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
+ * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
+ */
+#define UHS2_DCMD_DM_POS		6
+#define UHS2_DCMD_2L_HD_MODE		(1 << UHS2_DCMD_DM_POS)
+#define UHS2_DCMD_LM_POS		5
+#define UHS2_DCMD_LM_TLEN_EXIST		(1 << UHS2_DCMD_LM_POS)
+#define UHS2_DCMD_TLUM_POS		4
+#define UHS2_DCMD_TLUM_BYTE_MODE	(1 << UHS2_DCMD_TLUM_POS)
+#define UHS2_NATIVE_DCMD_DAM_POS	3
+#define UHS2_NATIVE_DCMD_DAM_IO		(1 << UHS2_NATIVE_DCMD_DAM_POS)
+
+/*
+ * Per UHS2 spec, DCMD payload should be MSB first. There may be
+ * two types of data be assembled to MSB:
+ * 1. TLEN: Input block size for single read/write and number of blocks
+ * for multiple read/write to calculate TLEN as MSB first per spec.
+ * 2. SD command argument.
+ */
+static inline __be32 uhs2_dcmd_convert_msb(u32 input)
+{
+	u32 ret = 0;
+
+	ret = ((input & 0xFF) << 24) |
+		(((input >> 8) & 0xFF) << 16) |
+		(((input >> 16) & 0xFF) << 8) |
+		((input >> 24) & 0xFF);
+	return cpu_to_be32(ret);
+}
+
+#define UHS2_RES_NACK_POS	7
+#define UHS2_RES_NACK_MASK	(0x1 << UHS2_RES_NACK_POS)
+
+#define UHS2_RES_ECODE_POS	4
+#define UHS2_RES_ECODE_MASK	0x7
+#define UHS2_RES_ECODE_COND	1
+#define UHS2_RES_ECODE_ARG	2
+#define UHS2_RES_ECODE_GEN	3
+
+/* IOADR of device registers */
+#define UHS2_IOADR_GENERIC_CAPS		0x00
+#define UHS2_IOADR_PHY_CAPS		0x02
+#define UHS2_IOADR_LINK_CAPS		0x04
+#define UHS2_IOADR_RSV_CAPS		0x06
+#define UHS2_IOADR_GENERIC_SETTINGS	0x08
+#define UHS2_IOADR_PHY_SETTINGS		0x0A
+#define UHS2_IOADR_LINK_SETTINGS	0x0C
+#define UHS2_IOADR_PRESET		0x40
+
+/* SD application packets */
+#define UHS2_SD_CMD_INDEX_POS	8
+
+#define UHS2_SD_CMD_APP_POS	14
+#define UHS2_SD_CMD_APP		(1 << UHS2_SD_CMD_APP_POS)
+
+/* UHS-II Device Registers */
+#define UHS2_DEV_CONFIG_REG	0x000
+
+/* General Caps and Settings registers */
+#define UHS2_DEV_CONFIG_GEN_CAPS	(UHS2_DEV_CONFIG_REG + 0x000)
+#define UHS2_DEV_CONFIG_N_LANES_POS	8
+#define UHS2_DEV_CONFIG_N_LANES_MASK	0x3F
+#define UHS2_DEV_CONFIG_2L_HD_FD	0x1
+#define UHS2_DEV_CONFIG_2D1U_FD		0x2
+#define UHS2_DEV_CONFIG_1D2U_FD		0x4
+#define UHS2_DEV_CONFIG_2D2U_FD		0x8
+#define UHS2_DEV_CONFIG_DADR_POS	14
+#define UHS2_DEV_CONFIG_DADR_MASK	0x1
+#define UHS2_DEV_CONFIG_APP_POS		16
+#define UHS2_DEV_CONFIG_APP_MASK	0xFF
+#define UHS2_DEV_CONFIG_APP_SD_MEM	0x1
+
+#define UHS2_DEV_CONFIG_GEN_SET			(UHS2_DEV_CONFIG_REG + 0x008)
+#define UHS2_DEV_CONFIG_GEN_SET_N_LANES_POS	8
+#define UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD	0x0
+#define UHS2_DEV_CONFIG_GEN_SET_2D1U_FD		0x2
+#define UHS2_DEV_CONFIG_GEN_SET_1D2U_FD		0x3
+#define UHS2_DEV_CONFIG_GEN_SET_2D2U_FD		0x4
+#define UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE	BIT(31)
+
+/* PHY Caps and Settings registers */
+#define UHS2_DEV_CONFIG_PHY_CAPS	(UHS2_DEV_CONFIG_REG + 0x002)
+#define UHS2_DEV_CONFIG_PHY_MINOR_MASK	0xF
+#define UHS2_DEV_CONFIG_PHY_MAJOR_POS	4
+#define UHS2_DEV_CONFIG_PHY_MAJOR_MASK	0x3
+#define UHS2_DEV_CONFIG_CAN_HIBER_POS	15
+#define UHS2_DEV_CONFIG_CAN_HIBER_MASK	0x1
+#define UHS2_DEV_CONFIG_PHY_CAPS1	(UHS2_DEV_CONFIG_REG + 0x003)
+#define UHS2_DEV_CONFIG_N_LSS_SYN_MASK	0xF
+#define UHS2_DEV_CONFIG_N_LSS_DIR_POS	4
+#define UHS2_DEV_CONFIG_N_LSS_DIR_MASK	0xF
+
+#define UHS2_DEV_CONFIG_PHY_SET			(UHS2_DEV_CONFIG_REG + 0x00A)
+#define UHS2_DEV_CONFIG_PHY_SET_SPEED_POS	6
+#define UHS2_DEV_CONFIG_PHY_SET_SPEED_A		0x0
+#define UHS2_DEV_CONFIG_PHY_SET_SPEED_B		0x1
+
+/* LINK-TRAN Caps and Settings registers */
+#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS		(UHS2_DEV_CONFIG_REG + 0x004)
+#define UHS2_DEV_CONFIG_LT_MINOR_MASK		0xF
+#define UHS2_DEV_CONFIG_LT_MAJOR_POS		4
+#define UHS2_DEV_CONFIG_LT_MAJOR_MASK		0x3
+#define UHS2_DEV_CONFIG_N_FCU_POS		8
+#define UHS2_DEV_CONFIG_N_FCU_MASK		0xFF
+#define UHS2_DEV_CONFIG_DEV_TYPE_POS		16
+#define UHS2_DEV_CONFIG_DEV_TYPE_MASK		0x7
+#define UHS2_DEV_CONFIG_MAX_BLK_LEN_POS		20
+#define UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK	0xFFF
+#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS1		(UHS2_DEV_CONFIG_REG + 0x005)
+#define UHS2_DEV_CONFIG_N_DATA_GAP_MASK		0xFF
+
+#define UHS2_DEV_CONFIG_LINK_TRAN_SET		(UHS2_DEV_CONFIG_REG + 0x00C)
+#define UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN	0x200
+#define UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS	16
+
+/* Preset register */
+#define UHS2_DEV_CONFIG_PRESET	(UHS2_DEV_CONFIG_REG + 0x040)
+
+#define UHS2_DEV_INT_REG	0x100
+
+#define UHS2_DEV_STATUS_REG	0x180
+
+#define UHS2_DEV_CMD_REG		0x200
+#define UHS2_DEV_CMD_FULL_RESET		(UHS2_DEV_CMD_REG + 0x000)
+#define UHS2_DEV_CMD_GO_DORMANT_STATE	(UHS2_DEV_CMD_REG + 0x001)
+#define UHS2_DEV_CMD_DORMANT_HIBER	BIT(7)
+#define UHS2_DEV_CMD_DEVICE_INIT	(UHS2_DEV_CMD_REG + 0x002)
+#define UHS2_DEV_INIT_COMPLETE_FLAG	BIT(11)
+#define UHS2_DEV_CMD_ENUMERATE		(UHS2_DEV_CMD_REG + 0x003)
+#define UHS2_DEV_CMD_TRANS_ABORT	(UHS2_DEV_CMD_REG + 0x004)
+
+#define UHS2_RCLK_MAX	52000000
+#define UHS2_RCLK_MIN	26000000
+
+struct sd_uhs2_wait_active_state_data {
+	struct mmc_host *host;
+	struct mmc_command *cmd;
+};
+
+#endif /* LINUX_MMC_UHS2_H */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 06/26] mmc: core: Support UHS-II card control and access
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (4 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:06 ` [PATCH V5 07/26] mmc: sdhci: add a kernel configuration for enabling UHS-II support Victor Shih
                   ` (21 subsequent siblings)
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Jason Lai

Embed UHS-II access/control functionality into the MMC request
processing flow.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---

Updates in V5:
 - Added uhs2_tmode0_flag in mmc_blk_rw_rq_prep: block.c
 - Added mechanism for confirming the completion of Card initialization
   in mmc_start_request: core.c
 - Added mechanism for confirming the completion of Card initialization
   in mmc_cqe_start_req: core.c
 - Added uhs2_tmode0_flag in mmc_send_adtc_data: mmc_ops.c
 - Added mechanism for confirming the completion of Card initialization
   in mmc_app_cmd: sd_ops.c
 - Added uhs2_tmode0_flag in mmc_app_send_scr: sd_ops.c
 - Added uhs2_tmode0_flag in mmc_app_sd_status: sd_ops.c
 - Added UHS2_PHY_INIT of uhs2_control for detect UHS2
   in sd_uhs2_go_dormant: sd_uhs2.c
 - Modified the ocr/rocr flow in sd_uhs2_legacy_init: sd_uhs2.c
 - Added mmc_decode_cid in sd_uhs2_legacy_init: sd_uhs2.c
 - Added remove MMC_UHS2_INITIALIZED of host->flags
   in sd_uhs2_remove: sd_uhs2.c
 - Added MMC_UHS2_INITIALIZED of host->flags and MMC_UHS2_INITIALIZED of
   host->card->uhs2_state in sd_uhs2_init_card: sd_uhs2.c
 - Added MMC_UHS2_SUPPORT of host->flags in sd_uhs2_attach: sd_uhs2.c

Update in V4:
  1. Rename sd_uhs2_prepare_cmd() into mmc_uhs2_prepare_cmd().
  2. Rename ->uhs2_host_operation() into ->uhs2_control().
  3. Declare ->uhs2_set_ios() which should be implemented in
     mmc/host/sdhci-uhs2.c.
  4. Implement call back functions in sd_uhs2_ops.
  5. Replace variables which are used as constant with constant
     definition.
  6. Change data type of uhs2_cmd->payload from u32 to __be32 because of
     the use of cpu_to_be32().
  7. Add comments to explain format of UHS-II CMD Header and Argument.
  8. Add comments to explain format of UHS-II CMD response.
  9. Remove unnecessary debug info.
  10. Use sd_uhs2_select_voltage() to replace mmc_select_voltage().
  11. Use __mmc_poll_for_busy() to replace while loop.
  12. Add processing of uhs2_cmd when starting request.
  13. Use macro 'mmc_card_can_poweroff_notify' to replace function
      "sd_can_poweroff_notify()" and put it to include/linux/mmc/card.h.
  14. Embed UHS-II access functionality into the MMC request processing
      flow.

Update in V3:
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[5].

[5]
https://patchwork.kernel.org/project/linux-mmc/patch/1419672479-30852-2-
git-send-email-yi.y.sun@intel.com/
---
 drivers/mmc/core/block.c   |    6 +-
 drivers/mmc/core/core.c    |   32 +
 drivers/mmc/core/mmc_ops.c |   25 +-
 drivers/mmc/core/mmc_ops.h |    1 +
 drivers/mmc/core/sd.c      |   11 +-
 drivers/mmc/core/sd.h      |    3 +
 drivers/mmc/core/sd_ops.c  |   18 +
 drivers/mmc/core/sd_ops.h  |    3 +
 drivers/mmc/core/sd_uhs2.c | 1165 +++++++++++++++++++++++++++++++++++-
 9 files changed, 1217 insertions(+), 47 deletions(-)

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index db6d8a099910..8245f59e6033 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1609,6 +1609,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
 	struct request *req = mmc_queue_req_to_req(mqrq);
 	struct mmc_blk_data *md = mq->blkdata;
 	bool do_rel_wr, do_data_tag;
+	bool do_multi;
+
+	do_multi = (card->uhs2_state & MMC_UHS2_INITIALIZED) ? true : false;
 
 	mmc_blk_data_prep(mq, mqrq, recovery_mode, &do_rel_wr, &do_data_tag);
 
@@ -1619,7 +1622,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
 		brq->cmd.arg <<= 9;
 	brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
-	if (brq->data.blocks > 1 || do_rel_wr) {
+	if (brq->data.blocks > 1 || do_rel_wr || do_multi) {
 		/* SPI multiblock writes terminate using a special
 		 * token, not a STOP_TRANSMISSION request.
 		 */
@@ -1632,6 +1635,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
 		brq->mrq.stop = NULL;
 		readcmd = MMC_READ_SINGLE_BLOCK;
 		writecmd = MMC_WRITE_BLOCK;
+		brq->cmd.uhs2_tmode0_flag = 1;
 	}
 	brq->cmd.opcode = rq_data_dir(req) == READ ? readcmd : writecmd;
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 8818a20571f7..025b8017f13d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -335,6 +335,8 @@ static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
 
 int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 {
+	struct uhs2_command uhs2_cmd;
+	__be32 payload[4]; /* for maximum size */
 	int err;
 
 	init_completion(&mrq->cmd_completion);
@@ -352,6 +354,20 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 	if (err)
 		return err;
 
+	if (host->card) {
+		if (host->card->uhs2_state & MMC_UHS2_INITIALIZED) {
+			uhs2_cmd.payload = payload;
+			mrq->cmd->uhs2_cmd = &uhs2_cmd;
+			mmc_uhs2_prepare_cmd(host, mrq);
+		}
+	} else {
+		if (host->flags & MMC_UHS2_INITIALIZED) {
+			uhs2_cmd.payload = payload;
+			mrq->cmd->uhs2_cmd = &uhs2_cmd;
+			mmc_uhs2_prepare_cmd(host, mrq);
+		}
+	}
+
 	led_trigger_event(host->led, LED_FULL);
 	__mmc_start_request(host, mrq);
 
@@ -431,6 +447,8 @@ EXPORT_SYMBOL(mmc_wait_for_req_done);
  */
 int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
+	struct uhs2_command uhs2_cmd;
+	__be32 payload[4]; /* for maximum size */
 	int err;
 
 	/*
@@ -451,6 +469,20 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
 	if (err)
 		goto out_err;
 
+	if (host->card) {
+		if (host->card->uhs2_state & MMC_UHS2_INITIALIZED) {
+			uhs2_cmd.payload = payload;
+			mrq->cmd->uhs2_cmd = &uhs2_cmd;
+			mmc_uhs2_prepare_cmd(host, mrq);
+		}
+	} else {
+		if (host->flags & MMC_UHS2_INITIALIZED) {
+			uhs2_cmd.payload = payload;
+			mrq->cmd->uhs2_cmd = &uhs2_cmd;
+			mmc_uhs2_prepare_cmd(host, mrq);
+		}
+	}
+
 	err = host->cqe_ops->cqe_request(host, mrq);
 	if (err)
 		goto out_err;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 81c55bfd6e0c..daa1f4ccd99a 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -144,10 +144,24 @@ int mmc_set_dsr(struct mmc_host *host)
 	return mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
 }
 
+int __mmc_go_idle(struct mmc_host *host)
+{
+	struct mmc_command cmd = {};
+	int err;
+
+	cmd.opcode = MMC_GO_IDLE_STATE;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	mmc_delay(1);
+
+	return err;
+}
+
 int mmc_go_idle(struct mmc_host *host)
 {
 	int err;
-	struct mmc_command cmd = {};
 
 	/*
 	 * Non-SPI hosts need to prevent chipselect going active during
@@ -163,13 +177,7 @@ int mmc_go_idle(struct mmc_host *host)
 		mmc_delay(1);
 	}
 
-	cmd.opcode = MMC_GO_IDLE_STATE;
-	cmd.arg = 0;
-	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
-
-	err = mmc_wait_for_cmd(host, &cmd, 0);
-
-	mmc_delay(1);
+	err = __mmc_go_idle(host);
 
 	if (!mmc_host_is_spi(host)) {
 		mmc_set_chip_select(host, MMC_CS_DONTCARE);
@@ -300,6 +308,7 @@ int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
 	 * not R1 plus a data block.
 	 */
 	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.uhs2_tmode0_flag = 1;
 
 	data.blksz = len;
 	data.blocks = 1;
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 09ffbc00908b..abda7492d578 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -25,6 +25,7 @@ struct mmc_command;
 int mmc_select_card(struct mmc_card *card);
 int mmc_deselect_cards(struct mmc_host *host);
 int mmc_set_dsr(struct mmc_host *host);
+int __mmc_go_idle(struct mmc_host *host);
 int mmc_go_idle(struct mmc_host *host);
 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 int mmc_set_relative_addr(struct mmc_card *card);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 3662bf5320ce..cab4725209c1 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -207,7 +207,7 @@ static int mmc_decode_csd(struct mmc_card *card)
 /*
  * Given a 64-bit response, decode to our card SCR structure.
  */
-static int mmc_decode_scr(struct mmc_card *card)
+int mmc_decode_scr(struct mmc_card *card)
 {
 	struct sd_scr *scr = &card->scr;
 	unsigned int scr_struct;
@@ -1611,11 +1611,6 @@ static void mmc_sd_detect(struct mmc_host *host)
 	}
 }
 
-static int sd_can_poweroff_notify(struct mmc_card *card)
-{
-	return card->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY;
-}
-
 static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy)
 {
 	struct sd_busy_data *data = cb_data;
@@ -1639,7 +1634,7 @@ static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy)
 	return 0;
 }
 
-static int sd_poweroff_notify(struct mmc_card *card)
+int sd_poweroff_notify(struct mmc_card *card)
 {
 	struct sd_busy_data cb_data;
 	u8 *reg_buf;
@@ -1687,7 +1682,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
 	if (mmc_card_suspended(card))
 		goto out;
 
-	if (sd_can_poweroff_notify(card))
+	if (mmc_card_can_poweroff_notify(card))
 		err = sd_poweroff_notify(card);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 1af5a038bae9..b573a809a0f4 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -17,4 +17,7 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 unsigned mmc_sd_get_max_clock(struct mmc_card *card);
 int mmc_sd_switch_hs(struct mmc_card *card);
 
+/* These call back functions were also used by UHS2 sd card */
+int sd_poweroff_notify(struct mmc_card *card);
+
 #endif
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index ef8d1dce5af1..85af5a2ea8ff 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -27,6 +27,22 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 	if (WARN_ON(card && card->host != host))
 		return -EINVAL;
 
+	/*
+	 * UHS2 packet has APP bit so only set APP_CMD flag here.
+	 * Will set the APP bit when assembling UHS2 packet.
+	 */
+	if (card) {
+		if (card->uhs2_state & MMC_UHS2_INITIALIZED) {
+			host->uhs2_ios.is_APP_CMD = true;
+			return 0;
+		}
+	} else {
+		if (host->flags & MMC_UHS2_INITIALIZED) {
+			host->uhs2_ios.is_APP_CMD = true;
+			return 0;
+		}
+	}
+
 	cmd.opcode = MMC_APP_CMD;
 
 	if (card) {
@@ -281,6 +297,7 @@ int mmc_app_send_scr(struct mmc_card *card)
 	cmd.opcode = SD_APP_SEND_SCR;
 	cmd.arg = 0;
 	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.uhs2_tmode0_flag = 1;
 
 	data.blksz = 8;
 	data.blocks = 1;
@@ -344,6 +361,7 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
 	cmd.opcode = SD_APP_SD_STATUS;
 	cmd.arg = 0;
 	cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.uhs2_tmode0_flag = 1;
 
 	data.blksz = 64;
 	data.blocks = 1;
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index 3ba7b3cf4652..29c802dec988 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 
 struct mmc_card;
+struct mmc_command;
 struct mmc_host;
 
 int mmc_app_set_bus_width(struct mmc_card *card, int width);
@@ -19,10 +20,12 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
 int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr);
 int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
 int mmc_app_send_scr(struct mmc_card *card);
+int mmc_decode_scr(struct mmc_card *card);
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 	u8 value, u8 *resp);
 int mmc_app_sd_status(struct mmc_card *card, void *ssr);
 int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
+void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq);
 
 #endif
 
diff --git a/drivers/mmc/core/sd_uhs2.c b/drivers/mmc/core/sd_uhs2.c
index 800957f74632..bccdd4283a67 100644
--- a/drivers/mmc/core/sd_uhs2.c
+++ b/drivers/mmc/core/sd_uhs2.c
@@ -1,48 +1,125 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2021 Linaro Ltd
- *
  * Author: Ulf Hansson <ulf.hansson@linaro.org>
  *
+ * Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ * Author: Yi Sun <yi.y.sun@intel.com>
+ *
+ * Copyright (C) 2020 Genesys Logic, Inc.
+ * Authors: Ben Chuang <ben.chuang@genesyslogic.com.tw>
+ *
+ * Copyright (C) 2020 Linaro Limited
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *
+ * Copyright (C) 2022 Genesys Logic, Inc.
+ * Authors: Jason Lai <jason.lai@genesyslogic.com.tw>
+ *
  * Support for SD UHS-II cards
  */
 #include <linux/err.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sd_uhs2.h>
 
+#include "card.h"
 #include "core.h"
 #include "bus.h"
 #include "sd.h"
+#include "sd_ops.h"
 #include "mmc_ops.h"
 
+#define UHS2_WAIT_CFG_COMPLETE_PERIOD_US	(1 * 1000)	/* 1ms */
+#define UHS2_WAIT_CFG_COMPLETE_TIMEOUT_MS	100		/* 100ms */
+
 static const unsigned int sd_uhs2_freqs[] = { 52000000, 26000000 };
+int sd_uhs2_reinit(struct mmc_host *host);
 
-static int sd_uhs2_set_ios(struct mmc_host *host)
+/*
+ * Internal function that does the actual ios call to the host driver,
+ * optionally printing some debug output.
+ */
+static inline int sd_uhs2_set_ios(struct mmc_host *host)
 {
 	struct mmc_ios *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);
+
 	return host->ops->uhs2_set_ios(host, ios);
 }
 
 static int sd_uhs2_power_up(struct mmc_host *host)
 {
+	int err;
+
+	if (host->ios.power_mode == MMC_POWER_ON)
+		return 0;
+
 	host->ios.vdd = fls(host->ocr_avail) - 1;
 	host->ios.clock = host->f_init;
 	host->ios.timing = MMC_TIMING_SD_UHS2;
-	host->ios.power_mode = MMC_POWER_UP;
+	host->ios.power_mode = MMC_POWER_ON;
 
-	return sd_uhs2_set_ios(host);
+	err = sd_uhs2_set_ios(host);
+
+	mmc_delay(host->uhs2_ios.power_delay_ms);
+
+	return err;
 }
 
-static void sd_uhs2_power_off(struct mmc_host *host)
+static int sd_uhs2_power_off(struct mmc_host *host)
 {
+	if (host->ios.power_mode == MMC_POWER_OFF)
+		return 0;
+
 	host->ios.vdd = 0;
 	host->ios.clock = 0;
 	host->ios.timing = MMC_TIMING_LEGACY;
 	host->ios.power_mode = MMC_POWER_OFF;
 
-	sd_uhs2_set_ios(host);
+	return sd_uhs2_set_ios(host);
+}
+
+/**
+ * sd_uhs2_cmd_assemble() - build up UHS-II command packet which is embedded 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, __be32 *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;
 }
 
 /*
@@ -52,7 +129,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_control(host, UHS2_PHY_INIT);
+	if (err) {
+		pr_err("%s: failed to initial phy for UHS-II!\n",
+		       mmc_hostname(host));
+	}
+
+	return err;
 }
 
 /*
@@ -61,6 +146,88 @@ 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, arg;
+	__be32 payload[UHS2_DEV_INIT_PAYLOAD_LEN];
+	u8 gd = 0;
+	u8 resp[UHS2_DEV_ENUM_RESP_LEN] = {0};
+	int err;
+
+	dap = host->uhs2_caps.dap;
+	gap = host->uhs2_caps.gap;
+
+	/*
+	 * Refer to UHS-II Addendum Version 1.02 Figure 6-21 to see DEVICE_INIT CCMD format.
+	 * Head:
+	 *      - Control Write(R/W=1) with 4-Byte payload(PLEN=01b).
+	 *      - IOADR = CMD_BASE + 002h
+	 * Payload:
+	 *      - bit [3:0]  : GAP(Group Allocated Power)
+	 *      - bit [7:4]  : GD(Group Descriptor)
+	 *      - bit [11]   : Complete Flag
+	 *      - bit [15:12]: DAP(Device Allocated Power)
+	 */
+	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) |
+			      UHS2_DEV_INIT_COMPLETE_FLAG |
+			      ((gd & 0xF) << 4) |
+			      (gap & 0xF);
+
+		sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg,
+				     payload, UHS2_DEV_INIT_PAYLOAD_LEN,
+				     resp, UHS2_DEV_INIT_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 err;
+		}
+
+		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->uhs2_caps.group_desc = gd;
+			return 0;
+		}
+		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,6 +238,52 @@ 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, arg;
+	__be32 payload[UHS2_DEV_ENUM_PAYLOAD_LEN];
+	u8 id_f = 0xF, id_l = 0x0;
+	u8 resp[UHS2_DEV_ENUM_RESP_LEN] = {0};
+	int err;
+
+	/*
+	 * Refer to UHS-II Addendum Version 1.02 Figure 6-28 to see ENUMERATE CCMD format.
+	 * Header:
+	 *      - Control Write(R/W=1) with 4-Byte payload(PLEN=01b).
+	 *      - IOADR = CMD_BASE + 003h
+	 * Payload:
+	 *      - bit [3:0]: ID_L(Last Node ID)
+	 *      - bit [7:4]: ID_F(First Node ID)
+	 */
+	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;
+	payload[0] = cpu_to_be32(payload[0]);
+
+	sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, UHS2_DEV_ENUM_PAYLOAD_LEN,
+			     resp, UHS2_DEV_ENUM_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 err;
+	}
+
+	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;
 }
 
@@ -81,6 +294,181 @@ static int sd_uhs2_enum(struct mmc_host *host, u32 *node_id)
  */
 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, arg;
+	u32 cap;
+	int err;
+
+	/*
+	 * Use Control Read CCMD to read Generic Capability from Configuration Register.
+	 * - Control Write(R/W=1) with 4-Byte payload(PLEN=01b).
+	 * - IOADR = Generic Capability Register(CFG_BASE + 000h)
+	 */
+	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;
+	}
+
+	/*
+	 * Generic Capability Register:
+	 * bit [7:0]  : Reserved
+	 * bit [13:8] : Device-Specific Number of Lanes and Functionality
+	 *              bit 8: 2L-HD
+	 *              bit 9: 2D-1U FD
+	 *              bit 10: 1D-2U FD
+	 *              bit 11: 2D-2U FD
+	 *              Others: Reserved
+	 * bit [14]   : DADR Length
+	 *              0: 4 bytes
+	 *              1: Reserved
+	 * bit [23:16]: Application Type
+	 *              bit 16: 0=Non-SD memory, 1=SD memory
+	 *              bit 17: 0=Non-SDIO, 1=SDIO
+	 *              bit 18: 0=Card, 1=Embedded
+	 * bit [63:24]: Reserved
+	 */
+	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;
+
+	/*
+	 * Use Control Read CCMD to read PHY Capability from Configuration Register.
+	 * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+	 * - IOADR = PHY Capability Register(CFG_BASE + 002h)
+	 */
+	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 err;
+	}
+
+	/*
+	 * PHY Capability Register:
+	 * bit [3:0]  : PHY Minor Revision
+	 * bit [5:4]  : PHY Major Revision
+	 * bit [15]   : Support Hibernate Mode
+	 *              0: Not support Hibernate Mode
+	 *              1: Support Hibernate Mode
+	 * bit [31:16]: Reserved
+	 * bit [35:32]: Device-Specific N_LSS_SYN
+	 * bit [39:36]: Device-Specific N_LSS_DIR
+	 * bit [63:40]: Reserved
+	 */
+	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;
+
+	/*
+	 * Use Control Read CCMD to read LINK/TRAN Capability from Configuration Register.
+	 * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+	 * - IOADR = LINK/TRAN Capability Register(CFG_BASE + 004h)
+	 */
+	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 err;
+	}
+
+	/*
+	 * LINK/TRAN Capability Register:
+	 * bit [3:0]  : LINK_TRAN Minor Revision
+	 * bit [5:4]  : LINK/TRAN Major Revision
+	 * bit [7:6]  : Reserved
+	 * bit [15:8] : Device-Specific N_FCU
+	 * bit [18:16]: Device Type
+	 *              001b=Host
+	 *              010b=Device
+	 *              011b=Reserved for CMD issuable Device
+	 * bit [19]   : Reserved
+	 * bit [31:20]: Device-Specific MAX_BLKLEN
+	 * bit [39:32]: Device-Specific N_DATA_GAP
+	 * bit [63:40]: Reserved
+	 */
+	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,9 +483,407 @@ 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, arg;
+	__be32 payload[UHS2_CFG_WRITE_PAYLOAD_LEN];
+	u8 nMinDataGap;
+	int err;
+	u8 resp[5] = {0};
+
+	/*
+	 * Use Control Write CCMD to set Generic Setting in Configuration Register.
+	 * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+	 * - IOADR = Generic Setting Register(CFG_BASE + 008h)
+	 * - Payload = New contents to be written to Generic Setting Register
+	 */
+	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_ios.is_2L_HD_mode = true;
+		nMinDataGap = 1;
+	} else {
+		/* Only support 2L-FD so far */
+		host->uhs2_ios.is_2L_HD_mode = false;
+		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;
+
+	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, UHS2_CFG_WRITE_PAYLOAD_LEN,
+			     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;
+	}
+
+	/*
+	 * Use Control Write CCMD to set PHY Setting in Configuration Register.
+	 * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+	 * - IOADR = PHY Setting Register(CFG_BASE + 00Ah)
+	 * - Payload = New contents to be written to PHY Setting Register
+	 */
+	arg = ((UHS2_DEV_CONFIG_PHY_SET & 0xFF) << 8) |
+	       UHS2_NATIVE_CMD_WRITE |
+	       UHS2_NATIVE_CMD_PLEN_8B |
+	       (UHS2_DEV_CONFIG_PHY_SET >> 8);
+
+	if (host->uhs2_caps.speed_range == UHS2_DEV_CONFIG_PHY_SET_SPEED_B) {
+		card->uhs2_state |= 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;
+		card->uhs2_state &= ~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 = (max(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;
+
+	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]);
+
+	memset(resp, 0, sizeof(resp));
+
+	sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, UHS2_CFG_WRITE_PAYLOAD_LEN,
+			     resp, UHS2_CFG_WRITE_PHY_SET_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 err;
+	}
+
+	if ((resp[2] & 0x80)) {
+		pr_err("%s: %s: UHS2 CMD not accepted, resp= 0x%x!\n",
+		       mmc_hostname(host), __func__, resp[2]);
+		return -EIO;
+	}
+
+	/*
+	 * Use Control Write CCMD to set LINK/TRAN Setting in Configuration Register.
+	 * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+	 * - IOADR = LINK/TRAN Setting Register(CFG_BASE + 00Ch)
+	 * - Payload = New contents to be written to LINK/TRAN Setting Register
+	 */
+	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);
+
+	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, UHS2_CFG_WRITE_PAYLOAD_LEN,
+			     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;
+	}
+
+	/*
+	 * Use Control Write CCMD to set Config Completion(payload bit 63) in Generic Setting
+	 * Register.
+	 * Header:
+	 *      - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+	 *      - IOADR = PGeneric Setting Register(CFG_BASE + 008h)
+	 * Payload:
+	 *      - bit [63]: Config Completion
+	 *
+	 * DLSM transits to Active state immediately when Config Completion is set to 1.
+	 */
+	arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) |
+	       UHS2_NATIVE_CMD_WRITE |
+	       UHS2_NATIVE_CMD_PLEN_8B |
+	       (UHS2_DEV_CONFIG_GEN_SET >> 8);
+
+	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]);
+
+	memset(resp, 0, sizeof(resp));
+	sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, UHS2_CFG_WRITE_PAYLOAD_LEN,
+			     resp, UHS2_CFG_WRITE_GENERIC_SET_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 err;
+	}
+
+	/* Set host Config Setting registers */
+	err = host->ops->uhs2_control(host, UHS2_SET_CONFIG);
+	if (err) {
+		pr_err("%s: %s: UHS2 SET_CONFIG fail!\n", mmc_hostname(host), __func__);
+		return err;
+	}
+
 	return 0;
 }
 
+static int sd_uhs2_go_dormant(struct mmc_host *host, u32 node_id)
+{
+	struct mmc_command cmd = {0};
+	struct uhs2_command uhs2_cmd = {};
+	u16 header, arg;
+	__be32 payload[1];
+	int err;
+
+	/* Disable Normal INT */
+	err = host->ops->uhs2_control(host, UHS2_DISABLE_INT);
+	if (err) {
+		pr_err("%s: %s: UHS2 DISABLE_INT fail!\n",
+		       mmc_hostname(host), __func__);
+		return err;
+	}
+
+	/*
+	 * Refer to UHS-II Addendum Version 1.02 Figure 6-17 to see GO_DORMANT_STATE CCMD format.
+	 * Header:
+	 *      - Control Write(R/W=1) with 4-Byte payload(PLEN=01b).
+	 *      - IOADR = CMD_BASE + 001h
+	 * Payload:
+	 *      - bit [7]: HBR(Entry to Hibernate Mode)
+	 *                 1: Host intends to enter Hibernate mode during Dormant state.
+	 *                 The default setting is 0 because hibernate is currently not supported.
+	 */
+	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);
+
+	sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, payload, UHS2_GO_DORMANT_PAYLOAD_LEN,
+			     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;
+	}
+
+	/* Check Dormant State in Present */
+	err = host->ops->uhs2_control(host, UHS2_CHECK_DORMANT);
+	if (err)
+		return err;
+
+	/* Disable UHS2 card clock */
+	err = host->ops->uhs2_control(host, UHS2_DISABLE_CLK);
+	if (err)
+		return err;
+
+	/* Restore sd clock */
+	mmc_delay(5);
+	err = host->ops->uhs2_control(host, UHS2_ENABLE_CLK);
+	if (err)
+		return err;
+
+	/* Enable Normal INT */
+	err = host->ops->uhs2_control(host, UHS2_ENABLE_INT);
+	if (err)
+		return err;
+
+	/* Detect UHS2 */
+	err = host->ops->uhs2_control(host, UHS2_PHY_INIT);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int __sd_uhs2_wait_active_state_cb(void *cb_data, bool *busy)
+{
+	struct sd_uhs2_wait_active_state_data *data = cb_data;
+	struct mmc_host *host = data->host;
+	struct mmc_command *cmd = data->cmd;
+	int err;
+
+	err = mmc_wait_for_cmd(host, cmd, 0);
+	if (err)
+		return err;
+
+	if (cmd->resp[1] & UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE)
+		*busy = false;
+	else
+		*busy = true;
+
+	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, arg;
+	int err;
+	struct sd_uhs2_wait_active_state_data cb_data = {
+		.host = host,
+		.cmd = &cmd
+	};
+
+	/* Change Speed Range at controller side. */
+	err = host->ops->uhs2_control(host, UHS2_SET_SPEED_B);
+	if (err) {
+		pr_err("%s: %s: UHS2 SET_SPEED fail!\n", mmc_hostname(host), __func__);
+		return err;
+	}
+
+	err = sd_uhs2_go_dormant(host, node_id);
+	if (err) {
+		pr_err("%s: %s: UHS2 GO_DORMANT_STATE fail, err= 0x%x!\n",
+		       mmc_hostname(host), __func__, err);
+		return err;
+	}
+
+	/*
+	 * Use Control Read CCMD to check Config Completion(bit 63) in Generic Setting Register.
+	 * - Control Read(R/W=0) with 8-Byte payload(PLEN=10b).
+	 * - IOADR = Generic Setting Register(CFG_BASE + 008h)
+	 *
+	 * When UHS-II card been switched to new speed mode, it will set Config Completion to 1.
+	 */
+	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);
+
+	sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, header, arg, NULL, 0, NULL, 0);
+	err = __mmc_poll_for_busy(host, UHS2_WAIT_CFG_COMPLETE_PERIOD_US,
+				  UHS2_WAIT_CFG_COMPLETE_TIMEOUT_MS,
+				  &__sd_uhs2_wait_active_state_cb, &cb_data);
+	if (err) {
+		pr_err("%s: %s: Not switch to Active in 100 ms\n", mmc_hostname(host), __func__);
+		return err;
+	}
+
+	return 0;
+}
+
+static int sd_uhs2_get_ro(struct mmc_host *host)
+{
+	/*
+	 * Some systems don't feature a write-protect pin and don't need one.
+	 * E.g. because they only have micro-SD card slot. For those systems
+	 * assume that the SD card is always read-write.
+	 */
+	if (host->caps2 & MMC_CAP2_NO_WRITE_PROTECT)
+		return 0;
+
+	if (!host->ops->get_ro)
+		return -1;
+
+	return host->ops->get_ro(host);
+}
+
+/*
+ * Mask off any voltages we don't support and select
+ * the lowest voltage
+ */
+u32 sd_uhs2_select_voltage(struct mmc_host *host, u32 ocr)
+{
+	int bit;
+	int err;
+
+	/*
+	 * Sanity check the voltages that the card claims to
+	 * support.
+	 */
+	if (ocr & 0x7F) {
+		dev_warn(mmc_dev(host), "card claims to support voltages below defined range\n");
+		ocr &= ~0x7F;
+	}
+
+	ocr &= host->ocr_avail;
+	if (!ocr) {
+		dev_warn(mmc_dev(host), "no support for card's volts\n");
+		return 0;
+	}
+
+	if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
+		bit = ffs(ocr) - 1;
+		ocr &= 3 << bit;
+		/* Power cycle */
+		err = sd_uhs2_power_off(host);
+		if (err)
+			return 0;
+		err = sd_uhs2_reinit(host);
+		if (err)
+			return 0;
+	} else {
+		bit = fls(ocr) - 1;
+		ocr &= 3 << bit;
+		if (bit != host->ios.vdd)
+			dev_warn(mmc_dev(host), "exceeding card's volts\n");
+	}
+
+	return ocr;
+}
+
 /*
  * Initialize the UHS-II card through the SD-TRAN transport layer. This enables
  * commands/requests to be backwards compatible through the legacy SD protocol.
@@ -107,14 +893,143 @@ 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;
+	u8  status[64];
+	int ro;
+
+	/* Send CMD0 to reset SD card */
+	err = __mmc_go_idle(host);
+	if (err)
+		return err;
+
+	mmc_delay(1);
+
+	/* Send CMD8 to communicate SD interface operation condition */
+	err = mmc_send_if_cond(host, host->ocr_avail);
+	if (err) {
+		dev_warn(mmc_dev(host), "CMD8 error\n");
+		return err;
+	}
+
+	/*
+	 * Probe SD card working voltage.
+	 */
+	err = mmc_send_app_op_cond(host, 0, &ocr);
+	if (err)
+		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 = sd_uhs2_select_voltage(host, ocr);
+	/*
+	 * Some cards have zero value of rocr in UHS-II mode. Assign host's
+	 * ocr value to rocr.
+	 */
+	if (!rocr)
+		rocr = host->ocr_avail;
+
+	rocr |= (SD_OCR_CCS | SD_OCR_XPC);
+
+	/* Wait SD power on ready */
+	ocr = rocr;
+
+	err = mmc_send_app_op_cond(host, ocr, &rocr);
+	if (err)
+		return err;
+
+	err = mmc_send_cid(host, cid);
+	if (err)
+		return err;
+
+	memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+	mmc_decode_cid(card);
+
+	/*
+	 * For native busses:  get card RCA and quit open drain mode.
+	 */
+	err = mmc_send_relative_addr(host, &card->rca);
+	if (err)
+		return err;
+
+	err = mmc_sd_get_csd(card);
+	if (err)
+		return err;
+
+	/*
+	 * Select card, as all following commands rely on that.
+	 */
+	err = mmc_select_card(card);
+	if (err)
+		return err;
+
+	/*
+	 * Fetch SCR from card.
+	 */
+	err = mmc_app_send_scr(card);
+	if (err)
+		return err;
+
+	err = mmc_decode_scr(card);
+	if (err)
+		return err;
+
+	/*
+	 * Switch to high power consumption mode.
+	 * Even switch failed, sd card can still work at lower power consumption mode, but
+	 * performance will be lower than high power consumption mode.
+	 */
+	if (!(card->csd.cmdclass & CCC_SWITCH)) {
+		pr_warn("%s: card lacks mandatory switch function, performance might suffer\n",
+			mmc_hostname(card->host));
+	} else {
+		/* send CMD6 to set Maximum Power Consumption to get better performance */
+		err = mmc_sd_switch(card, 0, 3, SD4_SET_POWER_LIMIT_1_80W, status);
+		if (!err)
+			err = mmc_sd_switch(card, 1, 3, SD4_SET_POWER_LIMIT_1_80W, status);
+
+		err = 0;
+	}
+
+	/*
+	 * Check if read-only switch is active.
+	 */
+	ro = sd_uhs2_get_ro(host);
+	if (ro < 0) {
+		pr_warn("%s: host does not support read-only switch, assuming write-enable\n",
+			mmc_hostname(host));
+	} else if (ro > 0) {
+		mmc_card_set_readonly(card);
+	}
+
+	/*
+	 * NOTE:
+	 * Should we read Externsion Register to check power notification feature here?
+	 */
+
 	return 0;
 }
 
+static void sd_uhs2_remove(struct mmc_host *host)
+{
+	mmc_remove_card(host->card);
+	host->card = NULL;
+	if (host->flags & MMC_UHS2_INITIALIZED)
+		host->flags &= ~MMC_UHS2_INITIALIZED;
+}
+
 /*
  * Allocate the data structure for the mmc_card and run the UHS-II specific
  * initialization sequence.
  */
-static int sd_uhs2_init_card(struct mmc_host *host)
+static int sd_uhs2_init_card(struct mmc_host *host, struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
 	u32 node_id;
@@ -128,9 +1043,14 @@ static int sd_uhs2_init_card(struct mmc_host *host)
 	if (err)
 		return err;
 
-	card = mmc_alloc_card(host, &sd_type);
-	if (IS_ERR(card))
-		return PTR_ERR(card);
+	if (oldcard) {
+		card = oldcard;
+	} else {
+		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;
@@ -143,22 +1063,47 @@ static int sd_uhs2_init_card(struct mmc_host *host)
 	if (err)
 		goto err;
 
+	/* Change to Speed Range B if it is supported */
+	if (card->uhs2_state & MMC_UHS2_SPEED_B) {
+		err = sd_uhs2_change_speed(host, node_id);
+		if (err)
+			return err;
+	}
+
+	host->card->uhs2_state |= MMC_UHS2_INITIALIZED;
+	host->flags |= MMC_UHS2_INITIALIZED;
+
 	err = sd_uhs2_legacy_init(host, card);
 	if (err)
 		goto err;
 
-	host->card = card;
 	return 0;
 
 err:
-	mmc_remove_card(card);
+	if (host->card->uhs2_state & MMC_UHS2_INITIALIZED)
+		host->card->uhs2_state &= ~MMC_UHS2_INITIALIZED;
+	if (host->flags & MMC_UHS2_INITIALIZED)
+		host->flags &= ~MMC_UHS2_INITIALIZED;
+	sd_uhs2_remove(host);
 	return err;
 }
 
-static void sd_uhs2_remove(struct mmc_host *host)
+int sd_uhs2_reinit(struct mmc_host *host)
 {
-	mmc_remove_card(host->card);
-	host->card = NULL;
+	struct mmc_card *card = host->card;
+	int err;
+
+	sd_uhs2_power_up(host);
+	err = sd_uhs2_phy_init(host);
+	if (err)
+		return err;
+
+	err = sd_uhs2_init_card(host, card);
+	if (err)
+		return err;
+
+	mmc_card_set_present(card);
+	return err;
 }
 
 static int sd_uhs2_alive(struct mmc_host *host)
@@ -184,34 +1129,176 @@ static void sd_uhs2_detect(struct mmc_host *host)
 	}
 }
 
+static int _sd_uhs2_suspend(struct mmc_host *host)
+{
+	struct mmc_card *card = host->card;
+	int err = 0;
+
+	mmc_claim_host(host);
+
+	if (mmc_card_suspended(card))
+		goto out;
+
+	if (mmc_card_can_poweroff_notify(card))
+		err = sd_poweroff_notify(card);
+
+	if (!err) {
+		sd_uhs2_power_off(host);
+		mmc_card_set_suspended(card);
+	}
+
+out:
+	mmc_release_host(host);
+	return err;
+}
+
+/*
+ * Callback for suspend
+ */
 static int sd_uhs2_suspend(struct mmc_host *host)
 {
-	return 0;
+	int err;
+
+	err = _sd_uhs2_suspend(host);
+	if (!err) {
+		pm_runtime_disable(&host->card->dev);
+		pm_runtime_set_suspended(&host->card->dev);
+	}
+
+	return err;
+}
+
+/*
+ * This function tries to determine if the same card is still present
+ * and, if so, restore all state to it.
+ */
+static int _mmc_sd_uhs2_resume(struct mmc_host *host)
+{
+	int err = 0;
+
+	mmc_claim_host(host);
+
+	if (!mmc_card_suspended(host->card))
+		goto out;
+
+	/* Power up UHS2 SD card and re-initialize it. */
+	err = sd_uhs2_reinit(host);
+	mmc_card_clr_suspended(host->card);
+
+out:
+	mmc_release_host(host);
+	return err;
 }
 
+/*
+ * Callback for resume
+ */
 static int sd_uhs2_resume(struct mmc_host *host)
 {
+	pm_runtime_enable(&host->card->dev);
 	return 0;
 }
 
+/*
+ * Callback for runtime_suspend.
+ */
 static int sd_uhs2_runtime_suspend(struct mmc_host *host)
 {
-	return 0;
+	int err;
+
+	if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+		return 0;
+
+	err = _sd_uhs2_suspend(host);
+	if (err)
+		pr_err("%s: error %d doing aggressive suspend\n", mmc_hostname(host), err);
+
+	return err;
 }
 
 static int sd_uhs2_runtime_resume(struct mmc_host *host)
 {
-	return 0;
+	int err;
+
+	err = _mmc_sd_uhs2_resume(host);
+	if (err && err != -ENOMEDIUM)
+		pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err);
+
+	return err;
 }
 
-static int sd_uhs2_shutdown(struct mmc_host *host)
+static int sd_uhs2_hw_reset(struct mmc_host *host)
 {
-	return 0;
+	int err;
+
+	sd_uhs2_power_off(host);
+	/* Wait at least 1 ms according to SD spec */
+	mmc_delay(1);
+	sd_uhs2_power_up(host);
+
+	err = sd_uhs2_reinit(host);
+
+	return err;
 }
 
-static int sd_uhs2_hw_reset(struct mmc_host *host)
+/*
+ * mmc_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
+ */
+void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq)
 {
-	return 0;
+	struct mmc_command *cmd;
+	struct uhs2_command *uhs2_cmd;
+	u16 header, arg;
+	__be32 *payload;
+	u8 plen;
+
+	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_ios.is_APP_CMD) {
+		arg |= UHS2_SD_CMD_APP;
+		host->uhs2_ios.is_APP_CMD = false;
+	}
+
+	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_ios.is_2L_HD_mode)
+			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);
+		}
+	} else {
+		plen = 1;
+	}
+
+	payload[0] = cpu_to_be32(cmd->arg);
+	sd_uhs2_cmd_assemble(cmd, uhs2_cmd, header, arg, payload, plen, NULL, 0);
 }
 
 static const struct mmc_bus_ops sd_uhs2_ops = {
@@ -222,7 +1309,7 @@ static const struct mmc_bus_ops sd_uhs2_ops = {
 	.resume = sd_uhs2_resume,
 	.runtime_suspend = sd_uhs2_runtime_suspend,
 	.runtime_resume = sd_uhs2_runtime_resume,
-	.shutdown = sd_uhs2_shutdown,
+	.shutdown = sd_uhs2_suspend,
 	.hw_reset = sd_uhs2_hw_reset,
 };
 
@@ -230,6 +1317,8 @@ static int sd_uhs2_attach(struct mmc_host *host)
 {
 	int err;
 
+	host->flags |= MMC_UHS2_SUPPORT;
+
 	err = sd_uhs2_power_up(host);
 	if (err)
 		goto err;
@@ -238,7 +1327,7 @@ static int sd_uhs2_attach(struct mmc_host *host)
 	if (err)
 		goto err;
 
-	err = sd_uhs2_init_card(host);
+	err = sd_uhs2_init_card(host, NULL);
 	if (err)
 		goto err;
 
@@ -251,21 +1340,34 @@ static int sd_uhs2_attach(struct mmc_host *host)
 		goto remove_card;
 
 	mmc_claim_host(host);
+
+	host->ops->uhs2_control(host, UHS2_POST_ATTACH_SD);
+
 	return 0;
 
 remove_card:
-	mmc_remove_card(host->card);
-	host->card = NULL;
+	sd_uhs2_remove(host);
 	mmc_claim_host(host);
-	mmc_detach_bus(host);
+
 err:
+	mmc_detach_bus(host);
 	sd_uhs2_power_off(host);
-	return err;
+	host->flags &= ~MMC_UHS2_SUPPORT;
+	return 1;
 }
 
+/**
+ * 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;
+	int i, err;
 
 	if (!(host->caps2 & MMC_CAP2_SD_UHS2))
 		return -EOPNOTSUPP;
@@ -280,6 +1382,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;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 07/26] mmc: sdhci: add a kernel configuration for enabling UHS-II support
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (5 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 06/26] mmc: core: Support UHS-II card control and access Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:12   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 08/26] mmc: sdhci: add UHS-II related definitions in headers Victor Shih
                   ` (20 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

From: AKASHI Takahiro <takahiro.akashi@linaro.org>

This kernel configuration, CONFIG_MMC_SDHCI_UHS2, will be used
in the following commits to indicate UHS-II specific code in sdhci
controllers.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 drivers/mmc/host/Kconfig | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index f324daadaf70..7e53cca97934 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -89,6 +89,15 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
 
 	  This is the case for the Nintendo Wii SDHCI.
 
+config MMC_SDHCI_UHS2
+	tristate "UHS2 support on SDHCI controller"
+	depends on MMC_SDHCI
+	help
+	  This option is selected by SDHCI controller drivers that want to
+	  support UHS2-capable devices.
+
+	  If you have a controller with this feature, say Y or M here.
+
 config MMC_SDHCI_PCI
 	tristate "SDHCI support on PCI bus"
 	depends on MMC_SDHCI && PCI
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 08/26] mmc: sdhci: add UHS-II related definitions in headers
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (6 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 07/26] mmc: sdhci: add a kernel configuration for enabling UHS-II support Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:12   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 09/26] mmc: sdhci: add UHS-II module Victor Shih
                   ` (19 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Add UHS-II related definitions in shdci.h and sdhci-uhs2.h.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.h | 210 ++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci.h      |  73 +++++++++++-
 2 files changed, 282 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h

diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
new file mode 100644
index 000000000000..5610affebdf3
--- /dev/null
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *  linux/drivers/mmc/host/sdhci-uhs2.h - Secure Digital Host Controller
+ *  Interface driver
+ *
+ * Header file for Host Controller UHS2 related registers and I/O accessors.
+ *
+ *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ */
+#ifndef __SDHCI_UHS2_H
+#define __SDHCI_UHS2_H
+
+#include <linux/bits.h>
+
+/*
+ * UHS-II Controller registers
+ * 0x74 preset in sdhci.h
+ * 0x80
+ * 0x84-0xB4
+ * 0xB8-0xCF
+ * 0xE0-0xE7
+ */
+/* UHS2 */
+#define SDHCI_UHS2_BLOCK_SIZE	0x80
+#define  SDHCI_UHS2_MAKE_BLKSZ(dma, blksz) \
+	((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
+
+#define SDHCI_UHS2_BLOCK_COUNT	0x84
+
+#define SDHCI_UHS2_CMD_PACKET	0x88
+#define  SDHCI_UHS2_CMD_PACK_MAX_LEN	20
+
+#define SDHCI_UHS2_TRANS_MODE	0x9C
+#define  SDHCI_UHS2_TRNS_DMA		BIT(0)
+#define  SDHCI_UHS2_TRNS_BLK_CNT_EN	BIT(1)
+#define  SDHCI_UHS2_TRNS_DATA_TRNS_WRT	BIT(4)
+#define  SDHCI_UHS2_TRNS_BLK_BYTE_MODE	BIT(5)
+#define  SDHCI_UHS2_TRNS_RES_R5		BIT(6)
+#define  SDHCI_UHS2_TRNS_RES_ERR_CHECK_EN	BIT(7)
+#define  SDHCI_UHS2_TRNS_RES_INT_DIS	BIT(8)
+#define  SDHCI_UHS2_TRNS_WAIT_EBSY	BIT(14)
+#define  SDHCI_UHS2_TRNS_2L_HD		BIT(15)
+
+#define SDHCI_UHS2_COMMAND	0x9E
+#define  SDHCI_UHS2_COMMAND_SUB_CMD	0x0004
+#define  SDHCI_UHS2_COMMAND_DATA	0x0020
+#define  SDHCI_UHS2_COMMAND_TRNS_ABORT	0x0040
+#define  SDHCI_UHS2_COMMAND_CMD12	0x0080
+#define  SDHCI_UHS2_COMMAND_DORMANT	0x00C0
+#define  SDHCI_UHS2_COMMAND_PACK_LEN_MASK	GENMASK(12, 8)
+#define  SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT	8
+
+#define SDHCI_UHS2_RESPONSE	0xA0
+#define  SDHCI_UHS2_RESPONSE_MAX_LEN	20
+
+#define SDHCI_UHS2_MSG_SELECT	0xB4
+#define SDHCI_UHS2_MSG_SELECT_CURR	0x0
+#define SDHCI_UHS2_MSG_SELECT_ONE	0x1
+#define SDHCI_UHS2_MSG_SELECT_TWO	0x2
+#define SDHCI_UHS2_MSG_SELECT_THREE	0x3
+
+#define SDHCI_UHS2_MSG		0xB8
+
+#define SDHCI_UHS2_DEV_INT_STATUS	0xBC
+
+#define SDHCI_UHS2_DEV_SELECT	0xBE
+#define SDHCI_UHS2_DEV_SELECT_DEV_SEL_MASK	GENMASK(3, 0)
+#define SDHCI_UHS2_DEV_SELECT_INT_MSG_EN	BIT(7)
+
+#define SDHCI_UHS2_DEV_INT_CODE	0xBF
+
+#define SDHCI_UHS2_SW_RESET	0xC0
+#define SDHCI_UHS2_SW_RESET_FULL	0x0001
+#define SDHCI_UHS2_SW_RESET_SD		0x0002
+
+#define SDHCI_UHS2_TIMER_CTRL	0xC2
+#define SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT	4
+
+#define SDHCI_UHS2_ERR_INT_STATUS		0xC4
+#define SDHCI_UHS2_ERR_INT_STATUS_EN		0xC8
+#define SDHCI_UHS2_ERR_INT_SIG_EN		0xCC
+#define SDHCI_UHS2_ERR_INT_STATUS_HEADER	BIT(0)
+#define SDHCI_UHS2_ERR_INT_STATUS_RES		BIT(1)
+#define SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP	BIT(2)
+#define SDHCI_UHS2_ERR_INT_STATUS_CRC		BIT(3)
+#define SDHCI_UHS2_ERR_INT_STATUS_FRAME		BIT(4)
+#define SDHCI_UHS2_ERR_INT_STATUS_TID		BIT(5)
+#define SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER	BIT(7)
+#define SDHCI_UHS2_ERR_INT_STATUS_EBUSY		BIT(8)
+#define SDHCI_UHS2_ERR_INT_STATUS_ADMA		BIT(15)
+#define SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT	BIT(16)
+#define SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT	BIT(17)
+#define SDHCI_UHS2_ERR_INT_STATUS_VENDOR	BIT(27)
+#define SDHCI_UHS2_ERR_INT_STATUS_MASK	\
+		(SDHCI_UHS2_ERR_INT_STATUS_HEADER |	\
+		SDHCI_UHS2_ERR_INT_STATUS_RES |		\
+		SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP |	\
+		SDHCI_UHS2_ERR_INT_STATUS_CRC |		\
+		SDHCI_UHS2_ERR_INT_STATUS_FRAME |	\
+		SDHCI_UHS2_ERR_INT_STATUS_TID |		\
+		SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER |	\
+		SDHCI_UHS2_ERR_INT_STATUS_EBUSY |	\
+		SDHCI_UHS2_ERR_INT_STATUS_ADMA |	\
+		SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |	\
+		SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT)
+#define SDHCI_UHS2_ERR_INT_STATUS_CMD_MASK	\
+		(SDHCI_UHS2_ERR_INT_STATUS_HEADER |	\
+		SDHCI_UHS2_ERR_INT_STATUS_RES |		\
+		SDHCI_UHS2_ERR_INT_STATUS_FRAME |	\
+		SDHCI_UHS2_ERR_INT_STATUS_TID |		\
+		SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT)
+/* CRC Error occurs during a packet receiving */
+#define SDHCI_UHS2_ERR_INT_STATUS_DATA_MASK	\
+		(SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP |	\
+		SDHCI_UHS2_ERR_INT_STATUS_CRC |		\
+		SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER |	\
+		SDHCI_UHS2_ERR_INT_STATUS_EBUSY |	\
+		SDHCI_UHS2_ERR_INT_STATUS_ADMA |	\
+		SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT)
+
+#define SDHCI_UHS2_SET_PTR	0xE0
+#define   SDHCI_UHS2_GEN_SET_POWER_LOW		0x0001
+#define   SDHCI_UHS2_GEN_SET_N_LANES_POS	8
+#define   SDHCI_UHS2_GEN_SET_2L_FD_HD		0x0
+#define   SDHCI_UHS2_GEN_SET_2D1U_FD		0x2
+#define   SDHCI_UHS2_GEN_SET_1D2U_FD		0x3
+#define   SDHCI_UHS2_GEN_SET_2D2U_FD		0x4
+
+#define   SDHCI_UHS2_PHY_SET_SPEED_POS		6
+#define   SDHCI_UHS2_PHY_SET_HIBER_EN		BIT(12)
+#define   SDHCI_UHS2_PHY_SET_N_LSS_SYN_MASK	GENMASK(19, 16)
+#define   SDHCI_UHS2_PHY_SET_N_LSS_SYN_POS	16
+#define   SDHCI_UHS2_PHY_SET_N_LSS_DIR_MASK	GENMASK(23, 20)
+#define   SDHCI_UHS2_PHY_SET_N_LSS_DIR_POS	20
+
+#define   SDHCI_UHS2_TRAN_SET_N_FCU_MASK	GENMASK(15, 8)
+#define   SDHCI_UHS2_TRAN_SET_N_FCU_POS		8
+#define   SDHCI_UHS2_TRAN_SET_RETRY_CNT_MASK	GENMASK(17, 16)
+#define   SDHCI_UHS2_TRAN_SET_RETRY_CNT_POS	16
+
+#define   SDHCI_UHS2_TRAN_SET_1_N_DAT_GAP_MASK	GENMASK(7, 0)
+
+#define SDHCI_UHS2_HOST_CAPS_PTR	0xE2
+#define  SDHCI_UHS2_HOST_CAPS_GEN_OFFSET	0
+#define   SDHCI_UHS2_HOST_CAPS_GEN_DAP_MASK	GENMASK(3, 0)
+#define   SDHCI_UHS2_HOST_CAPS_GEN_GAP_MASK	GENMASK(7, 4)
+#define   SDHCI_UHS2_HOST_CAPS_GEN_GAP(gap)	((gap) * 360)
+#define SDHCI_UHS2_HOST_CAPS_GEN_GAP_SHIFT 4
+#define   SDHCI_UHS2_HOST_CAPS_GEN_LANE_MASK	GENMASK(13, 8)
+#define   SDHCI_UHS2_HOST_CAPS_GEN_LANE_SHIFT	8
+#define    SDHCI_UHS2_HOST_CAPS_GEN_2L_HD_FD	1
+#define    SDHCI_UHS2_HOST_CAPS_GEN_2D1U_FD	2
+#define    SDHCI_UHS2_HOST_CAPS_GEN_1D2U_FD	4
+#define    SDHCI_UHS2_HOST_CAPS_GEN_2D2U_FD	8
+#define   SDHCI_UHS2_HOST_CAPS_GEN_ADDR_64	BIT(14)
+#define   SDHCI_UHS2_HOST_CAPS_GEN_BOOT		BIT(15)
+#define   SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_MASK	GENMASK(17, 16)
+#define   SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_SHIFT	16
+#define    SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_RMV	0
+#define    SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_EMB	1
+#define    SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_EMB_RMV	2
+#define   SDHCI_UHS2_HOST_CAPS_GEN_NUM_DEV_MASK		GENMASK(21, 18)
+#define   SDHCI_UHS2_HOST_CAPS_GEN_NUM_DEV_SHIFT	18
+#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_MASK	GENMASK(23, 22)
+#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_SHIFT	22
+#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_P2P		0
+#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_RING	1
+#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_HUB		2
+#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_HUB_RING	3
+
+#define  SDHCI_UHS2_HOST_CAPS_PHY_OFFSET	4
+#define   SDHCI_UHS2_HOST_CAPS_PHY_REV_MASK		GENMASK(5, 0)
+#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_MASK		GENMASK(7, 6)
+#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_SHIFT		6
+#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_A		0
+#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_B		1
+#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_MASK	GENMASK(19, 16)
+#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_SHIFT	16
+#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_MASK	GENMASK(23, 20)
+#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_SHIFT	20
+#define  SDHCI_UHS2_HOST_CAPS_TRAN_OFFSET	8
+#define   SDHCI_UHS2_HOST_CAPS_TRAN_LINK_REV_MASK	GENMASK(5, 0)
+#define   SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_MASK		GENMASK(15, 8)
+#define   SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_SHIFT		8
+#define   SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_MASK	GENMASK(18, 16)
+#define   SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_SHIFT	16
+#define   SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_MASK	GENMASK(31, 20)
+#define   SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_SHIFT	20
+
+#define  SDHCI_UHS2_HOST_CAPS_TRAN_1_OFFSET	12
+#define  SDHCI_UHS2_HOST_CAPS_TRAN_1_N_DATA_GAP_MASK	GENMASK(7, 0)
+
+#define SDHCI_UHS2_TEST_PTR	0xE4
+#define  SDHCI_UHS2_TEST_ERR_HEADER	BIT(0)
+#define  SDHCI_UHS2_TEST_ERR_RES	BIT(1)
+#define  SDHCI_UHS2_TEST_ERR_RETRY_EXP	BIT(2)
+#define  SDHCI_UHS2_TEST_ERR_CRC	BIT(3)
+#define  SDHCI_UHS2_TEST_ERR_FRAME	BIT(4)
+#define  SDHCI_UHS2_TEST_ERR_TID	BIT(5)
+#define  SDHCI_UHS2_TEST_ERR_UNRECOVER	BIT(7)
+#define  SDHCI_UHS2_TEST_ERR_EBUSY	BIT(8)
+#define  SDHCI_UHS2_TEST_ERR_ADMA	BIT(15)
+#define  SDHCI_UHS2_TEST_ERR_RES_TIMEOUT	BIT(16)
+#define  SDHCI_UHS2_TEST_ERR_DEADLOCK_TIMEOUT	BIT(17)
+#define  SDHCI_UHS2_TEST_ERR_VENDOR	BIT(27)
+
+#define SDHCI_UHS2_EMBED_CTRL	0xE6
+#define SDHCI_UHS2_VENDOR	0xE8
+
+#endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d750c464bd1e..bbed850241d4 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -43,8 +43,27 @@
 #define  SDHCI_TRNS_READ	0x10
 #define  SDHCI_TRNS_MULTI	0x20
 
+/*
+ * Defined in Host Version 4.10.
+ * 1 - R5 (SDIO)
+ * 0 - R1 (Memory)
+ */
+#define  SDHCI_TRNS_RES_TYPE		0x40
+#define  SDHCI_TRNS_RES_ERR_CHECK	0x80
+#define  SDHCI_TRNS_RES_INT_DIS		0x0100
+
 #define SDHCI_COMMAND		0x0E
 #define  SDHCI_CMD_RESP_MASK	0x03
+
+/*
+ * Host Version 4.10 adds this bit to distinguish a main command or
+ * sub command.
+ * CMD53(SDIO) - main command
+ * CMD52(SDIO) - sub command which doesn't have data block or doesn't
+ * indicate busy.
+ */
+#define  SDHCI_CMD_SUB_CMD	0x04
+
 #define  SDHCI_CMD_CRC		0x08
 #define  SDHCI_CMD_INDEX	0x10
 #define  SDHCI_CMD_DATA		0x20
@@ -60,11 +79,19 @@
 
 #define SDHCI_RESPONSE		0x10
 
+#define  SDHCI_RESPONSE_CM_TRAN_ABORT_OFFSET	0x10
+#define  SDHCI_RESPONSE_CM_TRAN_ABORT_SIZE	4
+#define  SDHCI_RESPONSE_SD_TRAN_ABORT_OFFSET	0x18
+#define  SDHCI_RESPONSE_SD_TRAN_ABORT_SIZE	8
+
 #define SDHCI_BUFFER		0x20
 
 #define SDHCI_PRESENT_STATE	0x24
 #define  SDHCI_CMD_INHIBIT	0x00000001
 #define  SDHCI_DATA_INHIBIT	0x00000002
+
+#define  SDHCI_DATA_HIGH_LVL_MASK	0x000000F0
+
 #define  SDHCI_DOING_WRITE	0x00000100
 #define  SDHCI_DOING_READ	0x00000200
 #define  SDHCI_SPACE_AVAILABLE	0x00000400
@@ -80,6 +107,13 @@
 #define   SDHCI_DATA_0_LVL_MASK	0x00100000
 #define  SDHCI_CMD_LVL		0x01000000
 
+#define  SDHCI_HOST_REGULATOR_STABLE	0x02000000
+#define  SDHCI_CMD_NOT_ISSUE_ERR	0x08000000
+#define  SDHCI_SUB_CMD_STATUS		0x10000000
+#define  SDHCI_UHS2_IN_DORMANT_STATE	0x20000000
+#define  SDHCI_UHS2_LANE_SYNC		0x40000000
+#define  SDHCI_UHS2_IF_DETECT		0x80000000
+
 #define SDHCI_HOST_CONTROL	0x28
 #define  SDHCI_CTRL_LED		0x01
 #define  SDHCI_CTRL_4BITBUS	0x02
@@ -100,6 +134,11 @@
 #define  SDHCI_POWER_300	0x0C
 #define  SDHCI_POWER_330	0x0E
 
+/* VDD2 - UHS2 */
+#define  SDHCI_VDD2_POWER_ON		0x10
+#define  SDHCI_VDD2_POWER_180		0xA0
+#define  SDHCI_VDD2_POWER_120		0x80
+
 #define SDHCI_BLOCK_GAP_CONTROL	0x2A
 
 #define SDHCI_WAKE_UP_CONTROL	0x2B
@@ -110,7 +149,7 @@
 #define SDHCI_CLOCK_CONTROL	0x2C
 #define  SDHCI_DIVIDER_SHIFT	8
 #define  SDHCI_DIVIDER_HI_SHIFT	6
-#define  SDHCI_DIV_MASK	0xFF
+#define  SDHCI_DIV_MASK		0xFF
 #define  SDHCI_DIV_MASK_LEN	8
 #define  SDHCI_DIV_HI_MASK	0x300
 #define  SDHCI_PROG_CLOCK_MODE	0x0020
@@ -139,6 +178,10 @@
 #define  SDHCI_INT_CARD_REMOVE	0x00000080
 #define  SDHCI_INT_CARD_INT	0x00000100
 #define  SDHCI_INT_RETUNE	0x00001000
+
+/* Host Version 4.10 */
+#define  SDHCI_INT_FX_EVENT	0x00002000
+
 #define  SDHCI_INT_CQE		0x00004000
 #define  SDHCI_INT_ERROR	0x00008000
 #define  SDHCI_INT_TIMEOUT	0x00010000
@@ -152,6 +195,9 @@
 #define  SDHCI_INT_AUTO_CMD_ERR	0x01000000
 #define  SDHCI_INT_ADMA_ERROR	0x02000000
 
+/* Host Version 4.0 */
+#define  SDHCI_INT_RESPONSE_ERROR	0x08000000
+
 #define  SDHCI_INT_NORMAL_MASK	0x00007FFF
 #define  SDHCI_INT_ERROR_MASK	0xFFFF8000
 
@@ -178,6 +224,9 @@
 #define  SDHCI_AUTO_CMD_END_BIT	0x00000008
 #define  SDHCI_AUTO_CMD_INDEX	0x00000010
 
+/* Host Version 4.10 */
+#define  SDHCI_ACMD_RESPONSE_ERROR	0x0020
+
 #define SDHCI_HOST_CONTROL2		0x3E
 #define  SDHCI_CTRL_UHS_MASK		0x0007
 #define   SDHCI_CTRL_UHS_SDR12		0x0000
@@ -186,6 +235,7 @@
 #define   SDHCI_CTRL_UHS_SDR104		0x0003
 #define   SDHCI_CTRL_UHS_DDR50		0x0004
 #define   SDHCI_CTRL_HS400		0x0005 /* Non-standard */
+#define   SDHCI_CTRL_UHS_2		0x0007 /* UHS-2 */
 #define  SDHCI_CTRL_VDD_180		0x0008
 #define  SDHCI_CTRL_DRV_TYPE_MASK	0x0030
 #define   SDHCI_CTRL_DRV_TYPE_B		0x0000
@@ -194,9 +244,12 @@
 #define   SDHCI_CTRL_DRV_TYPE_D		0x0030
 #define  SDHCI_CTRL_EXEC_TUNING		0x0040
 #define  SDHCI_CTRL_TUNED_CLK		0x0080
+#define  SDHCI_CTRL_UHS2_INTERFACE_EN	0x0100 /* UHS-2 */
+#define  SDHCI_CTRL_ADMA2_LEN_MODE	0x0400
 #define  SDHCI_CMD23_ENABLE		0x0800
 #define  SDHCI_CTRL_V4_MODE		0x1000
 #define  SDHCI_CTRL_64BIT_ADDR		0x2000
+#define  SDHCI_CTRL_ASYNC_INT_EN	0x4000
 #define  SDHCI_CTRL_PRESET_VAL_ENABLE	0x8000
 
 #define SDHCI_CAPABILITIES	0x40
@@ -219,11 +272,13 @@
 #define  SDHCI_CAN_VDD_180	0x04000000
 #define  SDHCI_CAN_64BIT_V4	0x08000000
 #define  SDHCI_CAN_64BIT	0x10000000
+#define  SDHCI_CAN_ASYNC_INT	0x20000000
 
 #define SDHCI_CAPABILITIES_1	0x44
 #define  SDHCI_SUPPORT_SDR50	0x00000001
 #define  SDHCI_SUPPORT_SDR104	0x00000002
 #define  SDHCI_SUPPORT_DDR50	0x00000004
+#define  SDHCI_SUPPORT_UHS2	0x00000008 /* UHS-2 support */
 #define  SDHCI_DRIVER_TYPE_A	0x00000010
 #define  SDHCI_DRIVER_TYPE_C	0x00000020
 #define  SDHCI_DRIVER_TYPE_D	0x00000040
@@ -232,19 +287,28 @@
 #define  SDHCI_RETUNING_MODE_MASK		GENMASK(15, 14)
 #define  SDHCI_CLOCK_MUL_MASK			GENMASK(23, 16)
 #define  SDHCI_CAN_DO_ADMA3	0x08000000
+#define  SDHCI_SUPPORT_VDD2_180	0x10000000 /* UHS-2 1.8V VDD2 */
+#define  SDHCI_RSVD_FOR_VDD2    0x20000000 /* Rsvd for future VDD2 */
 #define  SDHCI_SUPPORT_HS400	0x80000000 /* Non-standard */
 
 #define SDHCI_MAX_CURRENT		0x48
+#define SDHCI_MAX_CURRENT_1		0x4C
 #define  SDHCI_MAX_CURRENT_LIMIT	GENMASK(7, 0)
 #define  SDHCI_MAX_CURRENT_330_MASK	GENMASK(7, 0)
 #define  SDHCI_MAX_CURRENT_300_MASK	GENMASK(15, 8)
 #define  SDHCI_MAX_CURRENT_180_MASK	GENMASK(23, 16)
+#define  SDHCI_MAX_CURRENT_VDD2_180_MASK	GENMASK(7, 0) /* UHS2 */
 #define   SDHCI_MAX_CURRENT_MULTIPLIER	4
 
 /* 4C-4F reserved for more max current */
 
 #define SDHCI_SET_ACMD12_ERROR	0x50
+/* Host Version 4.10 */
+#define SDHCI_SET_ACMD_RESPONSE_ERROR	0x20
 #define SDHCI_SET_INT_ERROR	0x52
+/* Host Version 4.10 */
+#define SDHCI_SET_INT_TUNING_ERROR	0x0400
+#define SDHCI_SET_INT_RESPONSE_ERROR	0x0800
 
 #define SDHCI_ADMA_ERROR	0x54
 
@@ -262,10 +326,16 @@
 #define SDHCI_PRESET_FOR_SDR104        0x6C
 #define SDHCI_PRESET_FOR_DDR50 0x6E
 #define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
+
+/* TODO: 0x74 is used for UHS2 in 4.10. How about HS400? */
+/* UHS2 */
+#define SDHCI_PRESET_FOR_UHS2  0x74
 #define SDHCI_PRESET_DRV_MASK		GENMASK(15, 14)
 #define SDHCI_PRESET_CLKGEN_SEL		BIT(10)
 #define SDHCI_PRESET_SDCLK_FREQ_MASK	GENMASK(9, 0)
 
+#define SDHCI_ADMA3_ADDRESS	0x78
+
 #define SDHCI_SLOT_INT_STATUS	0xFC
 
 #define SDHCI_HOST_VERSION	0xFE
@@ -659,6 +729,7 @@ struct sdhci_ops {
 	void	(*request_done)(struct sdhci_host *host,
 				struct mmc_request *mrq);
 	void    (*dump_vendor_regs)(struct sdhci_host *host);
+	void	(*dump_uhs2_regs)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 09/26] mmc: sdhci: add UHS-II module
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (7 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 08/26] mmc: sdhci: add UHS-II related definitions in headers Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:12   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 10/26] mmc: sdhci-uhs2: dump UHS-II registers Victor Shih
                   ` (18 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

From: AKASHI Takahiro <takahiro.akashi@linaro.org>

This patch adds sdhci-uhs2.c as a module for UHS-II support.
This is a skelton for further development in this patch series.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 drivers/mmc/host/Makefile     |  1 +
 drivers/mmc/host/sdhci-uhs2.c | 46 +++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c

diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 4e4ceb32c4b4..c4ae7c6d9c04 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_PXA)		+= pxamci.o
 obj-$(CONFIG_MMC_MXC)		+= mxcmmc.o
 obj-$(CONFIG_MMC_MXS)		+= mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
+obj-$(CONFIG_MMC_SDHCI_UHS2)	+= sdhci-uhs2.o
 obj-$(CONFIG_MMC_SDHCI_PCI)	+= sdhci-pci.o
 sdhci-pci-y			+= sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
 				   sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
new file mode 100644
index 000000000000..f29d3a4ed43c
--- /dev/null
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  linux/drivers/mmc/host/sdhci_uhs2.c - Secure Digital Host Controller
+ *  Interface driver
+ *
+ *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ *  Copyright (C) 2020 Genesys Logic, Inc.
+ *  Authors: Ben Chuang <ben.chuang@genesyslogic.com.tw>
+ *  Copyright (C) 2020 Linaro Limited
+ *  Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ */
+
+#include <linux/module.h>
+
+#include "sdhci.h"
+#include "sdhci-uhs2.h"
+
+#define DRIVER_NAME "sdhci_uhs2"
+#define DBG(f, x...) \
+	pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
+{
+	return 0;
+}
+
+static int __init sdhci_uhs2_mod_init(void)
+{
+	return 0;
+}
+module_init(sdhci_uhs2_mod_init);
+
+static void __exit sdhci_uhs2_exit(void)
+{
+}
+module_exit(sdhci_uhs2_exit);
+
+MODULE_AUTHOR("Intel, Genesys Logic, Linaro");
+MODULE_DESCRIPTION("MMC UHS-II Support");
+MODULE_LICENSE("GPL v2");
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 10/26] mmc: sdhci-uhs2: dump UHS-II registers
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (8 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 09/26] mmc: sdhci: add UHS-II module Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:13   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 11/26] mmc: sdhci-uhs2: add reset function and uhs2_mode function Victor Shih
                   ` (17 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

From: AKASHI Takahiro <takahiro.akashi@linaro.org>

Dump UHS-II specific registers, if available, in sdhci_dumpregs()
for informative/debugging use.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 drivers/mmc/host/sdhci-uhs2.c | 30 ++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h |  4 ++++
 drivers/mmc/host/sdhci.c      |  3 +++
 3 files changed, 37 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index f29d3a4ed43c..08905ed081fb 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -18,6 +18,36 @@
 #define DRIVER_NAME "sdhci_uhs2"
 #define DBG(f, x...) \
 	pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
+#define SDHCI_UHS2_DUMP(f, x...) \
+	pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
+
+void sdhci_uhs2_dump_regs(struct sdhci_host *host)
+{
+	if (!host->mmc || !(host->mmc->flags & MMC_UHS2_SUPPORT))
+		return;
+
+	SDHCI_UHS2_DUMP("==================== UHS2 ==================\n");
+	SDHCI_UHS2_DUMP("Blk Size:  0x%08x | Blk Cnt:  0x%08x\n",
+			sdhci_readw(host, SDHCI_UHS2_BLOCK_SIZE),
+			sdhci_readl(host, SDHCI_UHS2_BLOCK_COUNT));
+	SDHCI_UHS2_DUMP("Cmd:       0x%08x | Trn mode: 0x%08x\n",
+			sdhci_readw(host, SDHCI_UHS2_COMMAND),
+			sdhci_readw(host, SDHCI_UHS2_TRANS_MODE));
+	SDHCI_UHS2_DUMP("Int Stat:  0x%08x | Dev Sel : 0x%08x\n",
+			sdhci_readw(host, SDHCI_UHS2_DEV_INT_STATUS),
+			sdhci_readb(host, SDHCI_UHS2_DEV_SELECT));
+	SDHCI_UHS2_DUMP("Dev Int Code:  0x%08x\n",
+			sdhci_readb(host, SDHCI_UHS2_DEV_INT_CODE));
+	SDHCI_UHS2_DUMP("Reset:     0x%08x | Timer:    0x%08x\n",
+			sdhci_readw(host, SDHCI_UHS2_SW_RESET),
+			sdhci_readw(host, SDHCI_UHS2_TIMER_CTRL));
+	SDHCI_UHS2_DUMP("ErrInt:    0x%08x | ErrIntEn: 0x%08x\n",
+			sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS),
+			sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN));
+	SDHCI_UHS2_DUMP("ErrSigEn:  0x%08x\n",
+			sdhci_readl(host, SDHCI_UHS2_ERR_INT_SIG_EN));
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
 
 /*****************************************************************************\
  *                                                                           *
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index 5610affebdf3..afdb05d6056b 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -207,4 +207,8 @@
 #define SDHCI_UHS2_EMBED_CTRL	0xE6
 #define SDHCI_UHS2_VENDOR	0xE8
 
+struct sdhci_host;
+
+void sdhci_uhs2_dump_regs(struct sdhci_host *host);
+
 #endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index fef03de85b99..2cdd183c8ada 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -110,6 +110,9 @@ void sdhci_dumpregs(struct sdhci_host *host)
 		}
 	}
 
+	if (host->ops->dump_uhs2_regs)
+		host->ops->dump_uhs2_regs(host);
+
 	if (host->ops->dump_vendor_regs)
 		host->ops->dump_vendor_regs(host);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 11/26] mmc: sdhci-uhs2: add reset function and uhs2_mode function
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (9 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 10/26] mmc: sdhci-uhs2: dump UHS-II registers Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:13   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 12/26] mmc: sdhci-uhs2: add set_power() to support vdd2 Victor Shih
                   ` (16 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Sdhci_uhs2_reset() does a UHS-II specific reset operation.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-pci-core.c |  1 +
 drivers/mmc/host/sdhci-pci-gli.c  |  1 +
 drivers/mmc/host/sdhci-uhs2.c     | 68 +++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h     |  3 ++
 drivers/mmc/host/sdhci.c          |  3 +-
 drivers/mmc/host/sdhci.h          | 14 +++++++
 6 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 34ea1acbb3cc..cba5bba994b8 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1955,6 +1955,7 @@ static const struct sdhci_ops sdhci_pci_ops = {
 	.reset		= sdhci_reset,
 	.set_uhs_signaling = sdhci_set_uhs_signaling,
 	.hw_reset		= sdhci_pci_hw_reset,
+	.uhs2_reset		= sdhci_uhs2_reset,
 };
 
 /*****************************************************************************\
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 4d509f656188..607cf69f45d0 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -1097,6 +1097,7 @@ static const struct sdhci_ops sdhci_gl9755_ops = {
 	.reset			= sdhci_reset,
 	.set_uhs_signaling	= sdhci_set_uhs_signaling,
 	.voltage_switch		= sdhci_gli_voltage_switch,
+	.uhs2_reset		= sdhci_uhs2_reset,
 };
 
 const struct sdhci_pci_fixes sdhci_gl9755 = {
diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 08905ed081fb..0e82f98d1967 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -10,6 +10,7 @@
  *  Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
  */
 
+#include <linux/delay.h>
 #include <linux/module.h>
 
 #include "sdhci.h"
@@ -49,6 +50,73 @@ void sdhci_uhs2_dump_regs(struct sdhci_host *host)
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
 
+/*****************************************************************************\
+ *                                                                           *
+ * Low level functions                                                       *
+ *                                                                           *
+\*****************************************************************************/
+
+bool sdhci_uhs2_mode(struct sdhci_host *host)
+{
+	if ((host->mmc->caps2 & MMC_CAP2_SD_UHS2) &&
+	    (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+		(host->version >= SDHCI_SPEC_400) &&
+		(host->mmc->flags & MMC_UHS2_SUPPORT)))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * sdhci_uhs2_reset - invoke SW reset
+ * @host: SDHCI host
+ * @mask: Control mask
+ *
+ * Invoke SW reset, depending on a bit in @mask and wait for completion.
+ */
+void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
+{
+	unsigned long timeout;
+	u32 val;
+
+	if (!(sdhci_uhs2_mode(host))) {
+		/**
+		 * u8  mask for legacy.
+		 * u16 mask for uhs-2.
+		 */
+		u8 u8_mask;
+
+		u8_mask = (mask & 0xFF);
+		sdhci_reset(host, u8_mask);
+
+		return;
+	}
+
+	sdhci_writew(host, mask, SDHCI_UHS2_SW_RESET);
+
+	if (mask & SDHCI_UHS2_SW_RESET_FULL) {
+		host->clock = 0;
+		/* Reset-all turns off SD Bus Power */
+		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+			sdhci_runtime_pm_bus_off(host);
+	}
+
+	/* Wait max 100 ms */
+	timeout = 10000;
+
+	/* hw clears the bit when it's done */
+	if (read_poll_timeout_atomic(sdhci_readw, val, !(val & mask), 10,
+				     timeout, true, host, SDHCI_UHS2_SW_RESET)) {
+		pr_err("%s: %s: Reset 0x%x never completed.\n",
+					       __func__, mmc_hostname(host->mmc), (int)mask);
+		pr_err("%s: clean reset bit\n",
+					       mmc_hostname(host->mmc));
+		sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET);
+		return;
+	}
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
+
 /*****************************************************************************\
  *                                                                           *
  * Driver init/exit                                                          *
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index afdb05d6056b..31776dcca5cf 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -11,6 +11,7 @@
 #define __SDHCI_UHS2_H
 
 #include <linux/bits.h>
+#include <linux/iopoll.h>
 
 /*
  * UHS-II Controller registers
@@ -210,5 +211,7 @@
 struct sdhci_host;
 
 void sdhci_uhs2_dump_regs(struct sdhci_host *host);
+bool sdhci_uhs2_mode(struct sdhci_host *host);
+void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
 
 #endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 2cdd183c8ada..bd017c59a020 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -194,13 +194,14 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
 	pm_runtime_get_noresume(mmc_dev(host->mmc));
 }
 
-static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
+void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
 {
 	if (!host->bus_on)
 		return;
 	host->bus_on = false;
 	pm_runtime_put_noidle(mmc_dev(host->mmc));
 }
+EXPORT_SYMBOL_GPL(sdhci_runtime_pm_bus_off);
 
 void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index bbed850241d4..28716105da61 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -715,6 +715,19 @@ struct sdhci_ops {
 					     u8 power_mode);
 	unsigned int    (*get_ro)(struct sdhci_host *host);
 	void		(*reset)(struct sdhci_host *host, u8 mask);
+	/**
+	 * The sdhci_uhs2_reset callback is to implement for reset
+	 * @host: SDHCI host
+	 * @mask: Control mask
+	 *
+	 * Invoke reset, depending on a bit in @mask and wait for completion.
+	 * SD mode				UHS-II mode
+	 * SDHCI_RESET_ALL		SDHCI_UHS2_SW_RESET_FULL
+	 * SDHCI_RESET_CMD		SDHCI_RESET_CMD
+	 * SDHCI_RESET_DATA		SDHCI_UHS2_SW_RESET_SD
+	 *
+	 **/
+	void (*uhs2_reset)(struct sdhci_host *host, u16 mask);
 	int	(*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
 	void	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
 	void	(*hw_reset)(struct sdhci_host *host);
@@ -837,6 +850,7 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
 	__sdhci_read_caps(host, NULL, NULL, NULL);
 }
 
+void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
 u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
 		   unsigned int *actual_clock);
 void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 12/26] mmc: sdhci-uhs2: add set_power() to support vdd2
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (10 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 11/26] mmc: sdhci-uhs2: add reset function and uhs2_mode function Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:13   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 13/26] mmc: sdhci-uhs2: skip signal_voltage_switch() Victor Shih
                   ` (15 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

This is a UHS-II version of sdhci's set_power operation.
VDD2, as well as VDD, is handled here.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 79 +++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h |  2 +
 drivers/mmc/host/sdhci.c      | 66 ++++++++++++++++-------------
 drivers/mmc/host/sdhci.h      |  2 +
 4 files changed, 120 insertions(+), 29 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 0e82f98d1967..896a1c8e55cf 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -117,6 +117,85 @@ void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
 
+void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
+			  unsigned short vdd)
+{
+	struct mmc_host *mmc = host->mmc;
+	u8 pwr;
+
+	/* FIXME: check if flags & MMC_UHS2_SUPPORT? */
+	if (!(sdhci_uhs2_mode(host))) {
+		sdhci_set_power(host, mode, vdd);
+		return;
+	}
+
+	if (mode != MMC_POWER_OFF) {
+		pwr = sdhci_get_vdd_value(vdd);
+		if (!pwr)
+			WARN(1, "%s: Invalid vdd %#x\n",
+			     mmc_hostname(host->mmc), vdd);
+		pwr |= SDHCI_VDD2_POWER_180;
+	}
+
+	if (host->pwr == pwr)
+		return;
+	host->pwr = pwr;
+
+	if (pwr == 0) {
+		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+
+		if (!IS_ERR(host->mmc->supply.vmmc))
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+		if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
+
+		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+			sdhci_runtime_pm_bus_off(host);
+	} else {
+		if (!IS_ERR(host->mmc->supply.vmmc))
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+		if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
+			/* support 1.8v only for now */
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2,
+					      fls(MMC_VDD2_165_195) - 1);
+
+		/*
+		 * Spec says that we should clear the power reg before setting
+		 * a new value. Some controllers don't seem to like this though.
+		 */
+		if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+			sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+
+		/*
+		 * At least the Marvell CaFe chip gets confused if we set the
+		 * voltage and set turn on power at the same time, so set the
+		 * voltage first.
+		 */
+		if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
+			sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+		/* vdd first */
+		pwr |= SDHCI_POWER_ON;
+		sdhci_writeb(host, pwr & 0xf, SDHCI_POWER_CONTROL);
+		mdelay(5);
+
+		pwr |= SDHCI_VDD2_POWER_ON;
+		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+		mdelay(5);
+
+		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+			sdhci_runtime_pm_bus_on(host);
+
+		/*
+		 * Some controllers need an extra 10ms delay of 10ms before
+		 * they can apply clock after applying power
+		 */
+		if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
+			mdelay(10);
+	}
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
+
 /*****************************************************************************\
  *                                                                           *
  * Driver init/exit                                                          *
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index 31776dcca5cf..3179915f7f79 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -213,5 +213,7 @@ struct sdhci_host;
 void sdhci_uhs2_dump_regs(struct sdhci_host *host);
 bool sdhci_uhs2_mode(struct sdhci_host *host);
 void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
+void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
+			  unsigned short vdd);
 
 #endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index bd017c59a020..dfa0939a9058 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -23,7 +23,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
-
+#include <linux/bug.h>
 #include <linux/leds.h>
 
 #include <linux/mmc/mmc.h>
@@ -186,13 +186,14 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
 	sdhci_set_card_detection(host, false);
 }
 
-static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
+void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
 {
 	if (host->bus_on)
 		return;
 	host->bus_on = true;
 	pm_runtime_get_noresume(mmc_dev(host->mmc));
 }
+EXPORT_SYMBOL_GPL(sdhci_runtime_pm_bus_on);
 
 void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
 {
@@ -2071,41 +2072,48 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
 		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 }
 
+unsigned short sdhci_get_vdd_value(unsigned short vdd)
+{
+	u8 pwr;
+
+	switch (1 << vdd) {
+	case MMC_VDD_165_195:
+	/*
+	 * Without a regulator, SDHCI does not support 2.0v
+	 * so we only get here if the driver deliberately
+	 * added the 2.0v range to ocr_avail. Map it to 1.8v
+	 * for the purpose of turning on the power.
+	 */
+	case MMC_VDD_20_21:
+		pwr = SDHCI_POWER_180;
+		break;
+	case MMC_VDD_29_30:
+	case MMC_VDD_30_31:
+		pwr = SDHCI_POWER_300;
+		break;
+	case MMC_VDD_32_33:
+	case MMC_VDD_33_34:
+		pwr = SDHCI_POWER_330;
+		break;
+	default:
+		pwr = 0;
+		break;
+	}
+
+	return pwr;
+}
+EXPORT_SYMBOL_GPL(sdhci_get_vdd_value);
+
 void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
 			   unsigned short vdd)
 {
 	u8 pwr = 0;
 
 	if (mode != MMC_POWER_OFF) {
-		switch (1 << vdd) {
-		case MMC_VDD_165_195:
-		/*
-		 * Without a regulator, SDHCI does not support 2.0v
-		 * so we only get here if the driver deliberately
-		 * added the 2.0v range to ocr_avail. Map it to 1.8v
-		 * for the purpose of turning on the power.
-		 */
-		case MMC_VDD_20_21:
-			pwr = SDHCI_POWER_180;
-			break;
-		case MMC_VDD_29_30:
-		case MMC_VDD_30_31:
-			pwr = SDHCI_POWER_300;
-			break;
-		case MMC_VDD_32_33:
-		case MMC_VDD_33_34:
-		/*
-		 * 3.4 ~ 3.6V are valid only for those platforms where it's
-		 * known that the voltage range is supported by hardware.
-		 */
-		case MMC_VDD_34_35:
-		case MMC_VDD_35_36:
-			pwr = SDHCI_POWER_330;
-			break;
-		default:
+		pwr = sdhci_get_vdd_value(vdd);
+		if (!pwr) {
 			WARN(1, "%s: Invalid vdd %#x\n",
 			     mmc_hostname(host->mmc), vdd);
-			break;
 		}
 	}
 
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 28716105da61..c34ca6ffbff6 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -850,6 +850,7 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
 	__sdhci_read_caps(host, NULL, NULL, NULL);
 }
 
+void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
 void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
 u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
 		   unsigned int *actual_clock);
@@ -860,6 +861,7 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
 void sdhci_set_power_and_bus_voltage(struct sdhci_host *host,
 				     unsigned char mode,
 				     unsigned short vdd);
+unsigned short sdhci_get_vdd_value(unsigned short vdd);
 void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
 			   unsigned short vdd);
 int sdhci_get_cd_nogpio(struct mmc_host *mmc);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 13/26] mmc: sdhci-uhs2: skip signal_voltage_switch()
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (11 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 12/26] mmc: sdhci-uhs2: add set_power() to support vdd2 Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:06 ` [PATCH V5 14/26] mmc: sdhci-uhs2: add set_timeout() Victor Shih
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

For UHS2, the signal voltage is supplied by vdd2 which is already 1.8v,
so no voltage switch required.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 896a1c8e55cf..4dc3e904d7d2 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -196,6 +196,27 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
 
+/*****************************************************************************\
+ *                                                                           *
+ * MMC callbacks                                                             *
+ *                                                                           *
+\*****************************************************************************/
+
+static int sdhci_uhs2_start_signal_voltage_switch(struct mmc_host *mmc,
+						  struct mmc_ios *ios)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+
+	/*
+	 * For UHS2, the signal voltage is supplied by vdd2 which is
+	 * already 1.8v so no voltage switch required.
+	 */
+	if (sdhci_uhs2_mode(host))
+		return 0;
+
+	return sdhci_start_signal_voltage_switch(mmc, ios);
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Driver init/exit                                                          *
@@ -204,6 +225,9 @@ EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
 
 static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
 {
+	host->mmc_host_ops.start_signal_voltage_switch =
+		sdhci_uhs2_start_signal_voltage_switch;
+
 	return 0;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 14/26] mmc: sdhci-uhs2: add set_timeout()
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (12 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 13/26] mmc: sdhci-uhs2: skip signal_voltage_switch() Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:14   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 15/26] mmc: sdhci-uhs2: add set_ios() Victor Shih
                   ` (13 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

From: AKASHI Takahiro <takahiro.akashi@linaro.org>

This is a UHS-II version of sdhci's set_timeout() operation.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 drivers/mmc/host/sdhci-uhs2.c | 85 +++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h |  1 +
 2 files changed, 86 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 4dc3e904d7d2..2b90e5308764 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -196,6 +196,91 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
 
+static u8 sdhci_calc_timeout_uhs2(struct sdhci_host *host, u8 *cmd_res,
+				  u8 *dead_lock)
+{
+	u8 count;
+	unsigned int cmd_res_timeout, dead_lock_timeout, current_timeout;
+
+	/*
+	 * If the host controller provides us with an incorrect timeout
+	 * value, just skip the check and use 0xE.  The hardware may take
+	 * longer to time out, but that's much better than having a too-short
+	 * timeout value.
+	 */
+	if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) {
+		*cmd_res = 0xE;
+		*dead_lock = 0xE;
+		return 0xE;
+	}
+
+	/* timeout in us */
+	cmd_res_timeout = 5 * 1000;
+	dead_lock_timeout = 1 * 1000 * 1000;
+
+	/*
+	 * Figure out needed cycles.
+	 * We do this in steps in order to fit inside a 32 bit int.
+	 * The first step is the minimum timeout, which will have a
+	 * minimum resolution of 6 bits:
+	 * (1) 2^13*1000 > 2^22,
+	 * (2) host->timeout_clk < 2^16
+	 *     =>
+	 *     (1) / (2) > 2^6
+	 */
+	count = 0;
+	current_timeout = (1 << 13) * 1000 / host->timeout_clk;
+	while (current_timeout < cmd_res_timeout) {
+		count++;
+		current_timeout <<= 1;
+		if (count >= 0xF)
+			break;
+	}
+
+	if (count >= 0xF) {
+		DBG("%s: Too large timeout 0x%x requested for CMD_RES!\n",
+		    mmc_hostname(host->mmc), count);
+		count = 0xE;
+	}
+	*cmd_res = count;
+
+	count = 0;
+	current_timeout = (1 << 13) * 1000 / host->timeout_clk;
+	while (current_timeout < dead_lock_timeout) {
+		count++;
+		current_timeout <<= 1;
+		if (count >= 0xF)
+			break;
+	}
+
+	if (count >= 0xF) {
+		DBG("%s: Too large timeout 0x%x requested for DEADLOCK!\n",
+		    mmc_hostname(host->mmc), count);
+		count = 0xE;
+	}
+	*dead_lock = count;
+
+	return count;
+}
+
+static void __sdhci_uhs2_set_timeout(struct sdhci_host *host)
+{
+	u8 cmd_res, dead_lock;
+
+	sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
+	cmd_res |= dead_lock << SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT;
+	sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
+}
+
+void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+{
+	__sdhci_set_timeout(host, cmd);
+
+	if (host->mmc->flags & MMC_UHS2_SUPPORT)
+		__sdhci_uhs2_set_timeout(host);
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
+
 /*****************************************************************************\
  *                                                                           *
  * MMC callbacks                                                             *
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index 3179915f7f79..5ea235b14108 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -215,5 +215,6 @@ bool sdhci_uhs2_mode(struct sdhci_host *host);
 void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
 void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
 			  unsigned short vdd);
+void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
 
 #endif /* __SDHCI_UHS2_H */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 15/26] mmc: sdhci-uhs2: add set_ios()
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (13 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 14/26] mmc: sdhci-uhs2: add set_timeout() Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:14   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 16/26] mmc: sdhci-uhs2: add detect_init() to detect the interface Victor Shih
                   ` (12 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

This is a sdhci version of mmc's set_ios operation.
It covers both UHS-I and UHS-II.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 102 ++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h |   1 +
 drivers/mmc/host/sdhci.c      |  40 ++++++++-----
 drivers/mmc/host/sdhci.h      |   2 +
 4 files changed, 130 insertions(+), 15 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 2b90e5308764..b535a47dc55a 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -281,6 +281,74 @@ void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
 
+/**
+ * sdhci_uhs2_clear_set_irqs - set Error Interrupt Status Enable register
+ * @host:	SDHCI host
+ * @clear:	bit-wise clear mask
+ * @set:	bit-wise set mask
+ *
+ * Set/unset bits in UHS-II Error Interrupt Status Enable register
+ */
+void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
+{
+	u32 ier;
+
+	ier = sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN);
+	ier &= ~clear;
+	ier |= set;
+	sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_STATUS_EN);
+	sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_SIG_EN);
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_clear_set_irqs);
+
+static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	u8 cmd_res, dead_lock;
+	u16 ctrl_2;
+	unsigned long flags;
+
+	/* FIXME: why lock? */
+	spin_lock_irqsave(&host->lock, flags);
+
+	/* UHS2 Timeout Control */
+	sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
+
+	/* change to use calculate value */
+	cmd_res |= dead_lock << SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT;
+
+	sdhci_uhs2_clear_set_irqs(host,
+				  SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
+				  SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT,
+				  0);
+	sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
+	sdhci_uhs2_clear_set_irqs(host, 0,
+				  SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
+				  SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT);
+
+	/* UHS2 timing */
+	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+	if (ios->timing == MMC_TIMING_SD_UHS2)
+		ctrl_2 |= SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN;
+	else
+		ctrl_2 &= ~(SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN);
+	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+	if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
+		sdhci_enable_preset_value(host, true);
+
+	if (host->ops->set_power)
+		host->ops->set_power(host, ios->power_mode, ios->vdd);
+	else
+		sdhci_uhs2_set_power(host, ios->power_mode, ios->vdd);
+	udelay(100);
+
+	host->timing = ios->timing;
+	sdhci_set_clock(host, host->clock);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
 /*****************************************************************************\
  *                                                                           *
  * MMC callbacks                                                             *
@@ -302,6 +370,39 @@ static int sdhci_uhs2_start_signal_voltage_switch(struct mmc_host *mmc,
 	return sdhci_start_signal_voltage_switch(mmc, ios);
 }
 
+int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+
+	if (!(host->version >= SDHCI_SPEC_400) ||
+	    !(host->mmc->flags & MMC_UHS2_SUPPORT &&
+	      host->mmc->caps2 & MMC_CAP2_SD_UHS2)) {
+		sdhci_set_ios(mmc, ios);
+		return 0;
+	}
+
+	if (ios->power_mode == MMC_POWER_UNDEFINED)
+		return 1;
+
+	if (host->flags & SDHCI_DEVICE_DEAD) {
+		if (!IS_ERR(mmc->supply.vmmc) &&
+		    ios->power_mode == MMC_POWER_OFF)
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+		if (!IS_ERR_OR_NULL(mmc->supply.vmmc2) &&
+		    ios->power_mode == MMC_POWER_OFF)
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
+		return 1;
+	}
+
+	/* FIXME: host->timing = ios->timing */
+
+	sdhci_set_ios_common(mmc, ios);
+
+	__sdhci_uhs2_set_ios(mmc, ios);
+
+	return 0;
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Driver init/exit                                                          *
@@ -312,6 +413,7 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
 {
 	host->mmc_host_ops.start_signal_voltage_switch =
 		sdhci_uhs2_start_signal_voltage_switch;
+	host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
 
 	return 0;
 }
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index 5ea235b14108..23368448ccd4 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -216,5 +216,6 @@ void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
 void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
 			  unsigned short vdd);
 void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
+void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
 
 #endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index dfa0939a9058..de47c71995fb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -47,8 +47,6 @@
 static unsigned int debug_quirks = 0;
 static unsigned int debug_quirks2;
 
-static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-
 static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
 
 void sdhci_dumpregs(struct sdhci_host *host)
@@ -1888,6 +1886,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
 	case MMC_TIMING_MMC_HS400:
 		preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
 		break;
+	case MMC_TIMING_SD_UHS2:
+		preset = sdhci_readw(host, SDHCI_PRESET_FOR_UHS2);
+		break;
 	default:
 		pr_warn("%s: Invalid UHS-I mode selected\n",
 			mmc_hostname(host->mmc));
@@ -2305,20 +2306,9 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
 }
 EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
 
-void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
-	u8 ctrl;
-
-	if (ios->power_mode == MMC_POWER_UNDEFINED)
-		return;
-
-	if (host->flags & SDHCI_DEVICE_DEAD) {
-		if (!IS_ERR(mmc->supply.vmmc) &&
-		    ios->power_mode == MMC_POWER_OFF)
-			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
-		return;
-	}
 
 	/*
 	 * Reset the chip on each power off.
@@ -2355,6 +2345,25 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		host->ops->set_power(host, ios->power_mode, ios->vdd);
 	else
 		sdhci_set_power(host, ios->power_mode, ios->vdd);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_ios_common);
+
+void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	u8 ctrl;
+
+	if (ios->power_mode == MMC_POWER_UNDEFINED)
+		return;
+
+	if (host->flags & SDHCI_DEVICE_DEAD) {
+		if (!IS_ERR(mmc->supply.vmmc) &&
+		    ios->power_mode == MMC_POWER_OFF)
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+		return;
+	}
+
+	sdhci_set_ios_common(mmc, ios);
 
 	if (host->ops->platform_send_init_74_clocks)
 		host->ops->platform_send_init_74_clocks(host, ios->power_mode);
@@ -2935,7 +2944,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 }
 EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
 
-static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
+void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
 {
 	/* Host Controller v3.00 defines preset value registers */
 	if (host->version < SDHCI_SPEC_300)
@@ -2963,6 +2972,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
 		host->preset_enabled = enable;
 	}
 }
+EXPORT_SYMBOL_GPL(sdhci_enable_preset_value);
 
 static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
 				int err)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c34ca6ffbff6..22d7f47862ae 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -871,6 +871,8 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width);
 void sdhci_reset(struct sdhci_host *host, u8 mask);
 void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
 int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
+void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
+void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios);
 void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
 int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 				      struct mmc_ios *ios);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 16/26] mmc: sdhci-uhs2: add detect_init() to detect the interface
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (14 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 15/26] mmc: sdhci-uhs2: add set_ios() Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:14   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 17/26] mmc: sdhci-uhs2: add clock operations Victor Shih
                   ` (11 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Sdhci_uhs2_do_detect_init() is a sdhci version of mmc's uhs2_detect_init
operation. After detected, the host's UHS-II capabilities will be set up
here and interrupts will also be enabled.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 146 ++++++++++++++++++++++++++++++++++
 1 file changed, 146 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index b535a47dc55a..9ceae552c323 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -409,12 +409,158 @@ int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
  *                                                                           *
 \*****************************************************************************/
 
+static int sdhci_uhs2_interface_detect(struct sdhci_host *host)
+{
+	/* 100ms */
+	int timeout = 100000;
+	u32 val;
+
+	udelay(200); /* wait for 200us before check */
+
+	if (read_poll_timeout_atomic(sdhci_readl, val, (val & SDHCI_UHS2_IF_DETECT),
+				     100, timeout, true, host, SDHCI_PRESENT_STATE)) {
+		pr_warn("%s: not detect UHS2 interface in 200us.\n", mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+		return -EIO;
+	}
+
+	/* Enable UHS2 error interrupts */
+	sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
+				  SDHCI_UHS2_ERR_INT_STATUS_MASK);
+
+	/* 150ms */
+	timeout = 150000;
+	if (read_poll_timeout_atomic(sdhci_readl, val, (val & SDHCI_UHS2_LANE_SYNC),
+				     100, timeout, true, host, SDHCI_PRESENT_STATE)) {
+		pr_warn("%s: UHS2 Lane sync fail in 150ms.\n", mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+		return -EIO;
+	}
+
+	DBG("%s: UHS2 Lane synchronized in UHS2 mode, PHY is initialized.\n",
+	    mmc_hostname(host->mmc));
+	return 0;
+}
+
+static int sdhci_uhs2_init(struct sdhci_host *host)
+{
+	u16 caps_ptr = 0;
+	u32 caps_gen = 0;
+	u32 caps_phy = 0;
+	u32 caps_tran[2] = {0, 0};
+	struct mmc_host *mmc = host->mmc;
+
+	caps_ptr = sdhci_readw(host, SDHCI_UHS2_HOST_CAPS_PTR);
+	if (caps_ptr < 0x100 || caps_ptr > 0x1FF) {
+		pr_err("%s: SDHCI_UHS2_HOST_CAPS_PTR(%d) is wrong.\n",
+		       mmc_hostname(mmc), caps_ptr);
+		return -ENODEV;
+	}
+	caps_gen = sdhci_readl(host,
+			       caps_ptr + SDHCI_UHS2_HOST_CAPS_GEN_OFFSET);
+	caps_phy = sdhci_readl(host,
+			       caps_ptr + SDHCI_UHS2_HOST_CAPS_PHY_OFFSET);
+	caps_tran[0] = sdhci_readl(host,
+				   caps_ptr + SDHCI_UHS2_HOST_CAPS_TRAN_OFFSET);
+	caps_tran[1] = sdhci_readl(host,
+				   caps_ptr
+					+ SDHCI_UHS2_HOST_CAPS_TRAN_1_OFFSET);
+
+	/* General Caps */
+	mmc->uhs2_caps.dap = caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_DAP_MASK;
+	mmc->uhs2_caps.gap = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_GAP_MASK) >>
+			     SDHCI_UHS2_HOST_CAPS_GEN_GAP_SHIFT;
+	mmc->uhs2_caps.n_lanes = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_LANE_MASK)
+			>> SDHCI_UHS2_HOST_CAPS_GEN_LANE_SHIFT;
+	mmc->uhs2_caps.addr64 =
+		(caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_ADDR_64) ? 1 : 0;
+	mmc->uhs2_caps.card_type =
+		(caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_MASK) >>
+		SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_SHIFT;
+
+	/* PHY Caps */
+	mmc->uhs2_caps.phy_rev = caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_REV_MASK;
+	mmc->uhs2_caps.speed_range =
+		(caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_RANGE_MASK)
+		>> SDHCI_UHS2_HOST_CAPS_PHY_RANGE_SHIFT;
+	mmc->uhs2_caps.n_lss_sync =
+		(caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_MASK)
+		>> SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_SHIFT;
+	mmc->uhs2_caps.n_lss_dir =
+		(caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_MASK)
+		>> SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_SHIFT;
+	if (mmc->uhs2_caps.n_lss_sync == 0)
+		mmc->uhs2_caps.n_lss_sync = 16 << 2;
+	else
+		mmc->uhs2_caps.n_lss_sync <<= 2;
+	if (mmc->uhs2_caps.n_lss_dir == 0)
+		mmc->uhs2_caps.n_lss_dir = 16 << 3;
+	else
+		mmc->uhs2_caps.n_lss_dir <<= 3;
+
+	/* LINK/TRAN Caps */
+	mmc->uhs2_caps.link_rev =
+		caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_LINK_REV_MASK;
+	mmc->uhs2_caps.n_fcu =
+		(caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_MASK)
+		>> SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_SHIFT;
+	if (mmc->uhs2_caps.n_fcu == 0)
+		mmc->uhs2_caps.n_fcu = 256;
+	mmc->uhs2_caps.host_type =
+		(caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_MASK)
+		>> SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_SHIFT;
+	mmc->uhs2_caps.maxblk_len =
+		(caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_MASK)
+		>> SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_SHIFT;
+	mmc->uhs2_caps.n_data_gap =
+		caps_tran[1] & SDHCI_UHS2_HOST_CAPS_TRAN_1_N_DATA_GAP_MASK;
+
+	return 0;
+}
+
+static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	int ret = -EIO;
+
+	DBG("%s: begin UHS2 init.\n", __func__);
+
+	if (sdhci_uhs2_interface_detect(host)) {
+		pr_warn("%s: cannot detect UHS2 interface.\n",
+			mmc_hostname(host->mmc));
+		goto out;
+	}
+
+	if (sdhci_uhs2_init(host)) {
+		pr_warn("%s: UHS2 init fail.\n", mmc_hostname(host->mmc));
+		goto out;
+	}
+
+	/* Init complete, do soft reset and enable UHS2 error irqs. */
+	host->ops->uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD);
+	sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
+				  SDHCI_UHS2_ERR_INT_STATUS_MASK);
+	/*
+	 * !!! SDHCI_INT_ENABLE and SDHCI_SIGNAL_ENABLE was cleared
+	 * by SDHCI_UHS2_SW_RESET_SD
+	 */
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+
+	ret = 0;
+out:
+	return ret;
+}
+
 static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
 {
 	host->mmc_host_ops.start_signal_voltage_switch =
 		sdhci_uhs2_start_signal_voltage_switch;
 	host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
 
+	if (!host->mmc_host_ops.uhs2_detect_init)
+		host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
+
 	return 0;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 17/26] mmc: sdhci-uhs2: add clock operations
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (15 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 16/26] mmc: sdhci-uhs2: add detect_init() to detect the interface Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:14   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 18/26] mmc: sdhci-uhs2: add uhs2_control() to initialise the interface Victor Shih
                   ` (10 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

This is a sdhci version of mmc's uhs2_[enable|disable]_clk operations.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 36 +++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 9ceae552c323..afaca5d96938 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/ktime.h>
 #include <linux/module.h>
 
 #include "sdhci.h"
@@ -403,6 +404,37 @@ int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	return 0;
 }
 
+static int sdhci_uhs2_disable_clk(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+
+	clk &= ~SDHCI_CLOCK_CARD_EN;
+	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+	return 0;
+}
+
+static int sdhci_uhs2_enable_clk(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+	u32 val;
+	/* 20ms */
+	int timeout_us = 20000;
+
+	clk |= SDHCI_CLOCK_CARD_EN;
+	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+	if (read_poll_timeout_atomic(sdhci_readw, val, (val & SDHCI_CLOCK_INT_STABLE),
+				     10, timeout_us, true, host, SDHCI_CLOCK_CONTROL)) {
+		pr_err("%s: Internal clock never stabilised.\n", mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+		return 1;
+	}
+	return 0;
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Driver init/exit                                                          *
@@ -560,6 +592,10 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
 
 	if (!host->mmc_host_ops.uhs2_detect_init)
 		host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
+	if (!host->mmc_host_ops.uhs2_disable_clk)
+		host->mmc_host_ops.uhs2_disable_clk = sdhci_uhs2_disable_clk;
+	if (!host->mmc_host_ops.uhs2_enable_clk)
+		host->mmc_host_ops.uhs2_enable_clk = sdhci_uhs2_enable_clk;
 
 	return 0;
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 18/26] mmc: sdhci-uhs2: add uhs2_control() to initialise the interface
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (16 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 17/26] mmc: sdhci-uhs2: add clock operations Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:15   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 19/26] mmc: sdhci-uhs2: add request() and others Victor Shih
                   ` (9 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

This is a sdhci version of mmc's uhs2_set_reg operation.
UHS-II interface (related registers) will be initialised here.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 103 ++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci.c      |  12 ++++
 drivers/mmc/host/sdhci.h      |   1 +
 3 files changed, 116 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index afaca5d96938..c9d59b8ac37f 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -350,6 +350,53 @@ static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static void sdhci_uhs2_set_config(struct sdhci_host *host)
+{
+	u32 value;
+	u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
+	u16 sdhci_uhs2_gen_set_reg = (sdhci_uhs2_set_ptr + 0);
+	u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
+	u16 sdhci_uhs2_tran_set_reg = (sdhci_uhs2_set_ptr + 8);
+	u16 sdhci_uhs2_tran_set_1_reg = (sdhci_uhs2_set_ptr + 12);
+
+	/* Set Gen Settings */
+	sdhci_writel(host, host->mmc->uhs2_caps.n_lanes_set <<
+		SDHCI_UHS2_GEN_SET_N_LANES_POS, sdhci_uhs2_gen_set_reg);
+
+	/* Set PHY Settings */
+	value = (host->mmc->uhs2_caps.n_lss_dir_set <<
+			SDHCI_UHS2_PHY_SET_N_LSS_DIR_POS) |
+		(host->mmc->uhs2_caps.n_lss_sync_set <<
+			SDHCI_UHS2_PHY_SET_N_LSS_SYN_POS);
+	if (host->mmc->flags & MMC_UHS2_SPEED_B)
+		value |= 1 << SDHCI_UHS2_PHY_SET_SPEED_POS;
+	sdhci_writel(host, value, sdhci_uhs2_phy_set_reg);
+
+	/* Set LINK-TRAN Settings */
+	value = (host->mmc->uhs2_caps.max_retry_set <<
+			SDHCI_UHS2_TRAN_SET_RETRY_CNT_POS) |
+		(host->mmc->uhs2_caps.n_fcu_set <<
+			SDHCI_UHS2_TRAN_SET_N_FCU_POS);
+	sdhci_writel(host, value, sdhci_uhs2_tran_set_reg);
+	sdhci_writel(host, host->mmc->uhs2_caps.n_data_gap_set,
+		     sdhci_uhs2_tran_set_1_reg);
+}
+
+static int sdhci_uhs2_check_dormant(struct sdhci_host *host)
+{
+	u32 val;
+	/* 100ms */
+	int timeout = 100000;
+
+	if (read_poll_timeout_atomic(sdhci_readl, val, (val & SDHCI_UHS2_IN_DORMANT_STATE),
+				     100, timeout, true, host, SDHCI_PRESENT_STATE)) {
+		pr_warn("%s: UHS2 IN_DORMANT fail in 100ms.\n", mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+		return -EIO;
+	}
+	return 0;
+}
+
 /*****************************************************************************\
  *                                                                           *
  * MMC callbacks                                                             *
@@ -435,6 +482,61 @@ static int sdhci_uhs2_enable_clk(struct mmc_host *mmc)
 	return 0;
 }
 
+static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc);
+
+static int sdhci_uhs2_control(struct mmc_host *mmc, enum sd_uhs2_operation op)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	unsigned long flags;
+	int err = 0;
+	u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
+	u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
+
+	DBG("Begin %s, act %d.\n", __func__, op);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	switch (op) {
+	case UHS2_PHY_INIT:
+		err = sdhci_uhs2_do_detect_init(mmc);
+		break;
+	case UHS2_SET_CONFIG:
+		sdhci_uhs2_set_config(host);
+		break;
+	case UHS2_ENABLE_INT:
+		sdhci_clear_set_irqs(host, 0, SDHCI_INT_CARD_INT);
+		break;
+	case UHS2_DISABLE_INT:
+		sdhci_clear_set_irqs(host, SDHCI_INT_CARD_INT, 0);
+		break;
+	case UHS2_SET_SPEED_B:
+		sdhci_writeb(host, 1 << SDHCI_UHS2_PHY_SET_SPEED_POS,
+			     sdhci_uhs2_phy_set_reg);
+		break;
+	case UHS2_CHECK_DORMANT:
+		err = sdhci_uhs2_check_dormant(host);
+		break;
+	case UHS2_DISABLE_CLK:
+		err = sdhci_uhs2_disable_clk(mmc);
+		break;
+	case UHS2_ENABLE_CLK:
+		err = sdhci_uhs2_enable_clk(mmc);
+		break;
+	case UHS2_POST_ATTACH_SD:
+		host->ops->uhs2_post_attach_sd(host);
+		break;
+	default:
+		pr_err("%s: input sd uhs2 operation %d is wrong!\n",
+		       mmc_hostname(host->mmc), op);
+		err = -EIO;
+		break;
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return err;
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Driver init/exit                                                          *
@@ -589,6 +691,7 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
 	host->mmc_host_ops.start_signal_voltage_switch =
 		sdhci_uhs2_start_signal_voltage_switch;
 	host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
+	host->mmc_host_ops.uhs2_control = sdhci_uhs2_control;
 
 	if (!host->mmc_host_ops.uhs2_detect_init)
 		host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index de47c71995fb..b9db2e976010 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -236,6 +236,18 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
 }
 EXPORT_SYMBOL_GPL(sdhci_reset);
 
+void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
+{
+	u32 ier;
+
+	ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+	ier &= ~clear;
+	ier |= set;
+	sdhci_writel(host, ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+}
+EXPORT_SYMBOL_GPL(sdhci_clear_set_irqs);
+
 static bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
 {
 	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 22d7f47862ae..f049331bd0bc 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -869,6 +869,7 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq);
 int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
 void sdhci_set_bus_width(struct sdhci_host *host, int width);
 void sdhci_reset(struct sdhci_host *host, u8 mask);
+void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
 void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
 int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 19/26] mmc: sdhci-uhs2: add request() and others
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (17 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 18/26] mmc: sdhci-uhs2: add uhs2_control() to initialise the interface Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:15   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 20/26] mmc: sdhci-uhs2: add irq() " Victor Shih
                   ` (8 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

This is a sdhci version of mmc's request operation.
It covers both UHS-I and UHS-II.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 475 ++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci.c      |  91 ++++---
 drivers/mmc/host/sdhci.h      |  17 ++
 3 files changed, 550 insertions(+), 33 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index c9d59b8ac37f..41b089ccc200 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/ktime.h>
 #include <linux/module.h>
+#include <linux/mmc/mmc.h>
 
 #include "sdhci.h"
 #include "sdhci-uhs2.h"
@@ -537,6 +538,479 @@ static int sdhci_uhs2_control(struct mmc_host *mmc, enum sd_uhs2_operation op)
 	return err;
 }
 
+/*****************************************************************************\
+ *                                                                           *
+ * Core functions                                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_uhs2_prepare_data(struct sdhci_host *host,
+				    struct mmc_command *cmd)
+{
+	struct mmc_data *data = cmd->data;
+
+	sdhci_initialize_data(host, data);
+
+	sdhci_prepare_dma(host, data);
+
+	sdhci_writew(host, data->blksz, SDHCI_UHS2_BLOCK_SIZE);
+	sdhci_writew(host, data->blocks, SDHCI_UHS2_BLOCK_COUNT);
+}
+
+#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
+static void sdhci_uhs2_external_dma_prepare_data(struct sdhci_host *host,
+						 struct mmc_command *cmd)
+{
+	if (!sdhci_external_dma_setup(host, cmd)) {
+		__sdhci_external_dma_prepare_data(host, cmd);
+	} else {
+		sdhci_external_dma_release(host);
+		pr_err("%s: Cannot use external DMA, switch to the DMA/PIO which standard SDHCI provides.\n",
+		       mmc_hostname(host->mmc));
+		sdhci_uhs2_prepare_data(host, cmd);
+	}
+}
+#else
+static inline void sdhci_uhs2_external_dma_prepare_data(struct sdhci_host *host,
+							struct mmc_command *cmd)
+{
+	/* This should never happen */
+	WARN_ON_ONCE(1);
+}
+
+static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
+						   struct mmc_command *cmd)
+{
+}
+#endif /* CONFIG_MMC_SDHCI_EXTERNAL_DMA */
+
+static void sdhci_uhs2_finish_data(struct sdhci_host *host)
+{
+	struct mmc_data *data = host->data;
+
+	__sdhci_finish_data_common(host);
+
+	/*
+	 *  FIXME: Is this condition needed?
+	    if (host->mmc->flags & MMC_UHS2_INITIALIZED)
+	 */
+	__sdhci_finish_mrq(host, data->mrq);
+}
+
+static void sdhci_uhs2_set_transfer_mode(struct sdhci_host *host,
+					 struct mmc_command *cmd)
+{
+	u16 mode;
+	struct mmc_data *data = cmd->data;
+	u16 arg;
+
+	if (!data) {
+		/* clear Auto CMD settings for no data CMDs */
+		arg = cmd->uhs2_cmd->arg;
+		if ((((arg & 0xF) << 8) | ((arg >> 8) & 0xFF)) ==
+		       UHS2_DEV_CMD_TRANS_ABORT) {
+			mode =  0;
+		} else {
+			mode = sdhci_readw(host, SDHCI_UHS2_TRANS_MODE);
+			if (cmd->opcode == MMC_STOP_TRANSMISSION ||
+			    cmd->opcode == MMC_ERASE)
+				mode |= SDHCI_UHS2_TRNS_WAIT_EBSY;
+			else
+				/* send status mode */
+				if (cmd->opcode == MMC_SEND_STATUS)
+					mode = 0;
+		}
+
+		if (IS_ENABLED(CONFIG_MMC_DEBUG))
+			DBG("UHS2 no data trans mode is 0x%x.\n", mode);
+
+		sdhci_writew(host, mode, SDHCI_UHS2_TRANS_MODE);
+		return;
+	}
+
+	WARN_ON(!host->data);
+
+	mode = SDHCI_UHS2_TRNS_BLK_CNT_EN | SDHCI_UHS2_TRNS_WAIT_EBSY;
+	if (data->flags & MMC_DATA_WRITE)
+		mode |= SDHCI_UHS2_TRNS_DATA_TRNS_WRT;
+
+	if (data->blocks == 1 &&
+	    data->blksz != 512 &&
+	    cmd->opcode != MMC_READ_SINGLE_BLOCK &&
+	    cmd->opcode != MMC_WRITE_BLOCK) {
+		mode &= ~SDHCI_UHS2_TRNS_BLK_CNT_EN;
+		mode |= SDHCI_UHS2_TRNS_BLK_BYTE_MODE;
+	}
+
+	if (host->flags & SDHCI_REQ_USE_DMA)
+		mode |= SDHCI_UHS2_TRNS_DMA;
+
+	if ((host->mmc->uhs2_ios.is_2L_HD_mode) && !cmd->uhs2_tmode0_flag)
+		mode |= SDHCI_UHS2_TRNS_2L_HD;
+
+	sdhci_writew(host, mode, SDHCI_UHS2_TRANS_MODE);
+
+	if (IS_ENABLED(CONFIG_MMC_DEBUG))
+		DBG("UHS2 trans mode is 0x%x.\n", mode);
+}
+
+static void __sdhci_uhs2_send_command(struct sdhci_host *host,
+				      struct mmc_command *cmd)
+{
+	int i, j;
+	int cmd_reg;
+
+	if (host->mmc->flags & MMC_UHS2_INITIALIZED) {
+		if (!cmd->uhs2_cmd) {
+			pr_err("%s: fatal error, no uhs2_cmd!\n",
+			       mmc_hostname(host->mmc));
+			return;
+		}
+	}
+
+	i = 0;
+	sdhci_writel(host,
+		     ((u32)cmd->uhs2_cmd->arg << 16) |
+				(u32)cmd->uhs2_cmd->header,
+		     SDHCI_UHS2_CMD_PACKET + i);
+	i += 4;
+
+	/*
+	 * Per spec, playload (config) should be MSB before sending out.
+	 * But we don't need convert here because had set payload as
+	 * MSB when preparing config read/write commands.
+	 */
+	for (j = 0; j < cmd->uhs2_cmd->payload_len / sizeof(u32); j++) {
+		sdhci_writel(host, *(cmd->uhs2_cmd->payload + j),
+			     SDHCI_UHS2_CMD_PACKET + i);
+		i += 4;
+	}
+
+	for ( ; i < SDHCI_UHS2_CMD_PACK_MAX_LEN; i += 4)
+		sdhci_writel(host, 0, SDHCI_UHS2_CMD_PACKET + i);
+
+	if (IS_ENABLED(CONFIG_MMC_DEBUG)) {
+		DBG("UHS2 CMD packet_len = %d.\n", cmd->uhs2_cmd->packet_len);
+		for (i = 0; i < cmd->uhs2_cmd->packet_len; i++)
+			DBG("UHS2 CMD_PACKET[%d] = 0x%x.\n", i,
+			    sdhci_readb(host, SDHCI_UHS2_CMD_PACKET + i));
+	}
+
+	cmd_reg = cmd->uhs2_cmd->packet_len <<
+		SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT;
+	if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC)
+		cmd_reg |= SDHCI_UHS2_COMMAND_DATA;
+	if (cmd->opcode == MMC_STOP_TRANSMISSION)
+		cmd_reg |= SDHCI_UHS2_COMMAND_CMD12;
+
+	/* UHS2 Native ABORT */
+	if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) &&
+	    ((((cmd->uhs2_cmd->arg & 0xF) << 8) |
+	    ((cmd->uhs2_cmd->arg >> 8) & 0xFF)) == UHS2_DEV_CMD_TRANS_ABORT))
+		cmd_reg |= SDHCI_UHS2_COMMAND_TRNS_ABORT;
+
+	/* UHS2 Native DORMANT */
+	if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) &&
+	    ((((cmd->uhs2_cmd->arg & 0xF) << 8) |
+	     ((cmd->uhs2_cmd->arg >> 8) & 0xFF)) ==
+				UHS2_DEV_CMD_GO_DORMANT_STATE))
+		cmd_reg |= SDHCI_UHS2_COMMAND_DORMANT;
+
+	DBG("0x%x is set to UHS2 CMD register.\n", cmd_reg);
+
+	sdhci_writew(host, cmd_reg, SDHCI_UHS2_COMMAND);
+}
+
+static bool sdhci_uhs2_send_command(struct sdhci_host *host,
+				    struct mmc_command *cmd)
+{
+	int flags;
+	u32 mask;
+	unsigned long timeout;
+
+	WARN_ON(host->cmd);
+
+	/* Initially, a command has no error */
+	cmd->error = 0;
+
+	if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
+		return sdhci_send_command(host, cmd);
+
+	if (cmd->opcode == MMC_STOP_TRANSMISSION)
+		cmd->flags |= MMC_RSP_BUSY;
+
+	mask = SDHCI_CMD_INHIBIT;
+
+	if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)
+		return false;
+
+	host->cmd = cmd;
+	host->data_timeout = 0;
+	if (sdhci_data_line_cmd(cmd)) {
+		WARN_ON(host->data_cmd);
+		host->data_cmd = cmd;
+		__sdhci_uhs2_set_timeout(host);
+	}
+
+	if (cmd->data) {
+		if (host->use_external_dma)
+			sdhci_uhs2_external_dma_prepare_data(host, cmd);
+		else
+			sdhci_uhs2_prepare_data(host, cmd);
+	}
+
+	sdhci_uhs2_set_transfer_mode(host, cmd);
+
+	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
+		WARN_ONCE(1, "Unsupported response type!\n");
+		/*
+		 * This does not happen in practice because 136-bit response
+		 * commands never have busy waiting, so rather than complicate
+		 * the error path, just remove busy waiting and continue.
+		 */
+		cmd->flags &= ~MMC_RSP_BUSY;
+	}
+
+	if (!(cmd->flags & MMC_RSP_PRESENT))
+		flags = SDHCI_CMD_RESP_NONE;
+	else if (cmd->flags & MMC_RSP_136)
+		flags = SDHCI_CMD_RESP_LONG;
+	else if (cmd->flags & MMC_RSP_BUSY)
+		flags = SDHCI_CMD_RESP_SHORT_BUSY;
+	else
+		flags = SDHCI_CMD_RESP_SHORT;
+
+	if (cmd->flags & MMC_RSP_CRC)
+		flags |= SDHCI_CMD_CRC;
+	if (cmd->flags & MMC_RSP_OPCODE)
+		flags |= SDHCI_CMD_INDEX;
+
+	timeout = jiffies;
+	if (host->data_timeout)
+		timeout += nsecs_to_jiffies(host->data_timeout);
+	else if (!cmd->data && cmd->busy_timeout > 9000)
+		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
+	else
+		timeout += 10 * HZ;
+	sdhci_mod_timer(host, cmd->mrq, timeout);
+
+	if (host->use_external_dma)
+		sdhci_external_dma_pre_transfer(host, cmd);
+
+	__sdhci_uhs2_send_command(host, cmd);
+
+	return true;
+}
+
+static bool sdhci_uhs2_send_command_retry(struct sdhci_host *host,
+				     struct mmc_command *cmd,
+				     unsigned long flags)
+	__releases(host->lock)
+	__acquires(host->lock)
+{
+	struct mmc_command *deferred_cmd = host->deferred_cmd;
+	int timeout = 10; /* Approx. 10 ms */
+	bool present;
+
+	while (!sdhci_uhs2_send_command(host, cmd)) {
+		if (!timeout--) {
+			pr_err("%s: Controller never released inhibit bit(s).\n",
+			       mmc_hostname(host->mmc));
+			sdhci_dumpregs(host);
+			cmd->error = -EIO;
+			return false;
+		}
+
+		spin_unlock_irqrestore(&host->lock, flags);
+
+		usleep_range(1000, 1250);
+
+		present = host->mmc->ops->get_cd(host->mmc);
+
+		spin_lock_irqsave(&host->lock, flags);
+
+		/* A deferred command might disappear, handle that */
+		if (cmd == deferred_cmd && cmd != host->deferred_cmd)
+			return true;
+
+		if (sdhci_present_error(host, cmd, present))
+			return false;
+	}
+
+	if (cmd == host->deferred_cmd)
+		host->deferred_cmd = NULL;
+
+	return true;
+}
+
+static void __sdhci_uhs2_finish_command(struct sdhci_host *host)
+{
+	struct mmc_command *cmd = host->cmd;
+	u8 resp;
+	u8 ecode;
+	bool bReadA0 = 0;
+	int i;
+
+	if (host->mmc->flags & MMC_UHS2_INITIALIZED) {
+		resp = sdhci_readb(host, SDHCI_UHS2_RESPONSE + 2);
+		if (resp & UHS2_RES_NACK_MASK) {
+			ecode = (resp >> UHS2_RES_ECODE_POS) &
+				UHS2_RES_ECODE_MASK;
+			pr_err("%s: NACK is got, ECODE=0x%x.\n",
+			       mmc_hostname(host->mmc), ecode);
+		}
+		bReadA0 = 1;
+	}
+
+	if (cmd->uhs2_resp &&
+	    cmd->uhs2_resp_len && cmd->uhs2_resp_len <= 20) {
+		/* Get whole response of some native CCMD, like
+		 * DEVICE_INIT, ENUMERATE.
+		 */
+		for (i = 0; i < cmd->uhs2_resp_len; i++)
+			cmd->uhs2_resp[i] =
+				sdhci_readb(host, SDHCI_UHS2_RESPONSE + i);
+	} else {
+		/* Get SD CMD response and Payload for some read
+		 * CCMD, like INQUIRY_CFG.
+		 */
+		/* Per spec (p136), payload field is divided into
+		 * a unit of DWORD and transmission order within
+		 * a DWORD is big endian.
+		 */
+		if (!bReadA0)
+			sdhci_readl(host, SDHCI_UHS2_RESPONSE);
+		for (i = 4; i < 20; i += 4) {
+			cmd->resp[i / 4 - 1] =
+				(sdhci_readb(host,
+					     SDHCI_UHS2_RESPONSE + i) << 24) |
+				(sdhci_readb(host,
+					     SDHCI_UHS2_RESPONSE + i + 1)
+					<< 16) |
+				(sdhci_readb(host,
+					     SDHCI_UHS2_RESPONSE + i + 2)
+					<< 8) |
+				sdhci_readb(host, SDHCI_UHS2_RESPONSE + i + 3);
+		}
+	}
+}
+
+static void sdhci_uhs2_finish_command(struct sdhci_host *host)
+{
+	struct mmc_command *cmd = host->cmd;
+
+	/* FIXME: Is this check necessary? */
+	if (!(host->mmc->flags & MMC_UHS2_SUPPORT)) {
+		sdhci_finish_command(host);
+		return;
+	}
+
+	__sdhci_uhs2_finish_command(host);
+
+	host->cmd = NULL;
+
+	if (cmd->mrq->cap_cmd_during_tfr && cmd == cmd->mrq->cmd)
+		mmc_command_done(host->mmc, cmd->mrq);
+
+	/*
+	 * The host can send and interrupt when the busy state has
+	 * ended, allowing us to wait without wasting CPU cycles.
+	 * The busy signal uses DAT0 so this is similar to waiting
+	 * for data to complete.
+	 *
+	 * Note: The 1.0 specification is a bit ambiguous about this
+	 *       feature so there might be some problems with older
+	 *       controllers.
+	 */
+	if (cmd->flags & MMC_RSP_BUSY) {
+		if (cmd->data) {
+			DBG("Cannot wait for busy signal when also doing a data transfer");
+		} else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) &&
+			   cmd == host->data_cmd) {
+			/* Command complete before busy is ended */
+			return;
+		}
+	}
+
+	/* Processed actual command. */
+	if (host->data && host->data_early)
+		sdhci_uhs2_finish_data(host);
+
+	if (!cmd->data)
+		__sdhci_finish_mrq(host, cmd->mrq);
+}
+
+void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct mmc_command *cmd;
+	unsigned long flags;
+	bool present;
+
+	/* FIXME: check more flags? */
+	if (!(sdhci_uhs2_mode(host))) {
+		sdhci_request(mmc, mrq);
+		return;
+	}
+
+	/* Firstly check card presence */
+	present = mmc->ops->get_cd(mmc);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (sdhci_present_error(host, mrq->cmd, present))
+		goto out_finish;
+
+	cmd = mrq->cmd;
+
+	if (!sdhci_uhs2_send_command(host, cmd))
+		goto out_finish;
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return;
+
+out_finish:
+	sdhci_finish_mrq(host, mrq);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_request);
+
+int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct mmc_command *cmd;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!host->mmc->flags & MMC_UHS2_SUPPORT)
+		return sdhci_request_atomic(mmc, mrq);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (sdhci_present_error(host, mrq->cmd, true)) {
+		sdhci_finish_mrq(host, mrq);
+		goto out_finish;
+	}
+
+	cmd = mrq->cmd;
+
+	/*
+	 * The HSQ may send a command in interrupt context without polling
+	 * the busy signaling, which means we should return BUSY if controller
+	 * has not released inhibit bits to allow HSQ trying to send request
+	 * again in non-atomic context. So we should not finish this request
+	 * here.
+	 */
+	if (!sdhci_uhs2_send_command(host, cmd))
+		ret = -EBUSY;
+
+out_finish:
+	spin_unlock_irqrestore(&host->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_request_atomic);
+
 /*****************************************************************************\
  *                                                                           *
  * Driver init/exit                                                          *
@@ -692,6 +1166,7 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
 		sdhci_uhs2_start_signal_voltage_switch;
 	host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
 	host->mmc_host_ops.uhs2_control = sdhci_uhs2_control;
+	host->mmc_host_ops.request = sdhci_uhs2_request;
 
 	if (!host->mmc_host_ops.uhs2_detect_init)
 		host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index b9db2e976010..407169468927 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -47,8 +47,6 @@
 static unsigned int debug_quirks = 0;
 static unsigned int debug_quirks2;
 
-static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
-
 void sdhci_dumpregs(struct sdhci_host *host)
 {
 	SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n");
@@ -147,10 +145,11 @@ void sdhci_enable_v4_mode(struct sdhci_host *host)
 }
 EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode);
 
-static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
+bool sdhci_data_line_cmd(struct mmc_command *cmd)
 {
 	return cmd->data || cmd->flags & MMC_RSP_BUSY;
 }
+EXPORT_SYMBOL_GPL(sdhci_data_line_cmd);
 
 static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 {
@@ -409,7 +408,7 @@ static void sdhci_reinit(struct sdhci_host *host)
 		mmc_detect_change(host->mmc, msecs_to_jiffies(200));
 }
 
-static void __sdhci_led_activate(struct sdhci_host *host)
+void __sdhci_led_activate(struct sdhci_host *host)
 {
 	u8 ctrl;
 
@@ -420,8 +419,9 @@ static void __sdhci_led_activate(struct sdhci_host *host)
 	ctrl |= SDHCI_CTRL_LED;
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 }
+EXPORT_SYMBOL_GPL(__sdhci_led_activate);
 
-static void __sdhci_led_deactivate(struct sdhci_host *host)
+void __sdhci_led_deactivate(struct sdhci_host *host)
 {
 	u8 ctrl;
 
@@ -432,6 +432,7 @@ static void __sdhci_led_deactivate(struct sdhci_host *host)
 	ctrl &= ~SDHCI_CTRL_LED;
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 }
+EXPORT_SYMBOL_GPL(__sdhci_led_deactivate);
 
 #if IS_REACHABLE(CONFIG_LEDS_CLASS)
 static void sdhci_led_control(struct led_classdev *led,
@@ -510,14 +511,15 @@ static inline void sdhci_led_deactivate(struct sdhci_host *host)
 
 #endif
 
-static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
-			    unsigned long timeout)
+void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
+		     unsigned long timeout)
 {
 	if (sdhci_data_line_cmd(mrq->cmd))
 		mod_timer(&host->data_timer, timeout);
 	else
 		mod_timer(&host->timer, timeout);
 }
+EXPORT_SYMBOL_GPL(sdhci_mod_timer);
 
 static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
 {
@@ -1098,8 +1100,7 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 		__sdhci_set_timeout(host, cmd);
 }
 
-static void sdhci_initialize_data(struct sdhci_host *host,
-				  struct mmc_data *data)
+void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data)
 {
 	WARN_ON(host->data);
 
@@ -1112,6 +1113,7 @@ static void sdhci_initialize_data(struct sdhci_host *host,
 	host->data_early = 0;
 	host->data->bytes_xfered = 0;
 }
+EXPORT_SYMBOL_GPL(sdhci_initialize_data);
 
 static inline void sdhci_set_block_info(struct sdhci_host *host,
 					struct mmc_data *data)
@@ -1134,12 +1136,8 @@ static inline void sdhci_set_block_info(struct sdhci_host *host,
 	}
 }
 
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
+void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data)
 {
-	struct mmc_data *data = cmd->data;
-
-	sdhci_initialize_data(host, data);
-
 	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
 		struct scatterlist *sg;
 		unsigned int length_mask, offset_mask;
@@ -1224,6 +1222,16 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
 	}
 
 	sdhci_set_transfer_irqs(host);
+}
+EXPORT_SYMBOL_GPL(sdhci_prepare_dma);
+
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
+{
+	struct mmc_data *data = cmd->data;
+
+	sdhci_initialize_data(host, data);
+
+	sdhci_prepare_dma(host, data);
 
 	sdhci_set_block_info(host, data);
 }
@@ -1266,8 +1274,7 @@ static struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
 	return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
 }
 
-static int sdhci_external_dma_setup(struct sdhci_host *host,
-				    struct mmc_command *cmd)
+int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	int ret, i;
 	enum dma_transfer_direction dir;
@@ -1320,8 +1327,9 @@ static int sdhci_external_dma_setup(struct sdhci_host *host,
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(sdhci_external_dma_setup);
 
-static void sdhci_external_dma_release(struct sdhci_host *host)
+void sdhci_external_dma_release(struct sdhci_host *host)
 {
 	if (host->tx_chan) {
 		dma_release_channel(host->tx_chan);
@@ -1335,9 +1343,10 @@ static void sdhci_external_dma_release(struct sdhci_host *host)
 
 	sdhci_switch_external_dma(host, false);
 }
+EXPORT_SYMBOL_GPL(sdhci_external_dma_release);
 
-static void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
-					      struct mmc_command *cmd)
+void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
+				       struct mmc_command *cmd)
 {
 	struct mmc_data *data = cmd->data;
 
@@ -1348,6 +1357,7 @@ static void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
 
 	sdhci_set_block_info(host, data);
 }
+EXPORT_SYMBOL(__sdhci_external_dma_prepare_data);
 
 static void sdhci_external_dma_prepare_data(struct sdhci_host *host,
 					    struct mmc_command *cmd)
@@ -1362,8 +1372,8 @@ static void sdhci_external_dma_prepare_data(struct sdhci_host *host,
 	}
 }
 
-static void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
-					    struct mmc_command *cmd)
+void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
+				     struct mmc_command *cmd)
 {
 	struct dma_chan *chan;
 
@@ -1374,6 +1384,7 @@ static void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
 	if (chan)
 		dma_async_issue_pending(chan);
 }
+EXPORT_SYMBOL_GPL(sdhci_external_dma_pre_transfer);
 
 #else
 
@@ -1425,11 +1436,11 @@ static inline bool sdhci_auto_cmd23(struct sdhci_host *host,
 	return mrq->sbc && (host->flags & SDHCI_AUTO_CMD23);
 }
 
-static inline bool sdhci_manual_cmd23(struct sdhci_host *host,
-				      struct mmc_request *mrq)
+bool sdhci_manual_cmd23(struct sdhci_host *host, struct mmc_request *mrq)
 {
 	return mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23);
 }
+EXPORT_SYMBOL_GPL(sdhci_manual_cmd23);
 
 static inline void sdhci_auto_cmd_select(struct sdhci_host *host,
 					 struct mmc_command *cmd,
@@ -1541,7 +1552,7 @@ static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
 	WARN_ON(i >= SDHCI_MAX_MRQS);
 }
 
-static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
+void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
 {
 	if (host->cmd && host->cmd->mrq == mrq)
 		host->cmd = NULL;
@@ -1565,15 +1576,17 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
 	if (!sdhci_has_requests(host))
 		sdhci_led_deactivate(host);
 }
+EXPORT_SYMBOL_GPL(__sdhci_finish_mrq);
 
-static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
+void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
 {
 	__sdhci_finish_mrq(host, mrq);
 
 	queue_work(host->complete_wq, &host->complete_work);
 }
+EXPORT_SYMBOL_GPL(sdhci_finish_mrq);
 
-static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
+void __sdhci_finish_data_common(struct sdhci_host *host)
 {
 	struct mmc_command *data_cmd = host->data_cmd;
 	struct mmc_data *data = host->data;
@@ -1607,6 +1620,14 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
 		data->bytes_xfered = 0;
 	else
 		data->bytes_xfered = data->blksz * data->blocks;
+}
+EXPORT_SYMBOL_GPL(__sdhci_finish_data_common);
+
+static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
+{
+	struct mmc_data *data = host->data;
+
+	__sdhci_finish_data_common(host);
 
 	/*
 	 * Need to send CMD12 if -
@@ -1645,12 +1666,13 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
 	}
 }
 
-static void sdhci_finish_data(struct sdhci_host *host)
+void sdhci_finish_data(struct sdhci_host *host)
 {
 	__sdhci_finish_data(host, false);
 }
+EXPORT_SYMBOL_GPL(sdhci_finish_data);
 
-static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	int flags;
 	u32 mask;
@@ -1692,8 +1714,6 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 			sdhci_prepare_data(host, cmd);
 	}
 
-	sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
-
 	sdhci_set_transfer_mode(host, cmd);
 
 	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
@@ -1737,13 +1757,16 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 	if (host->use_external_dma)
 		sdhci_external_dma_pre_transfer(host, cmd);
 
+	sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
+
 	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
 
 	return true;
 }
+EXPORT_SYMBOL_GPL(sdhci_send_command);
 
-static bool sdhci_present_error(struct sdhci_host *host,
-				struct mmc_command *cmd, bool present)
+bool sdhci_present_error(struct sdhci_host *host,
+			 struct mmc_command *cmd, bool present)
 {
 	if (!present || host->flags & SDHCI_DEVICE_DEAD) {
 		cmd->error = -ENOMEDIUM;
@@ -1752,6 +1775,7 @@ static bool sdhci_present_error(struct sdhci_host *host,
 
 	return false;
 }
+EXPORT_SYMBOL_GPL(sdhci_present_error);
 
 static bool sdhci_send_command_retry(struct sdhci_host *host,
 				     struct mmc_command *cmd,
@@ -1815,7 +1839,7 @@ static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd)
 	}
 }
 
-static void sdhci_finish_command(struct sdhci_host *host)
+void sdhci_finish_command(struct sdhci_host *host)
 {
 	struct mmc_command *cmd = host->cmd;
 
@@ -1868,6 +1892,7 @@ static void sdhci_finish_command(struct sdhci_host *host)
 			__sdhci_finish_mrq(host, cmd->mrq);
 	}
 }
+EXPORT_SYMBOL_GPL(sdhci_finish_command);
 
 static u16 sdhci_get_preset_value(struct sdhci_host *host)
 {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index f049331bd0bc..1a9924e7972d 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -850,8 +850,25 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
 	__sdhci_read_caps(host, NULL, NULL, NULL);
 }
 
+bool sdhci_data_line_cmd(struct mmc_command *cmd);
 void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
 void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
+void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, unsigned long timeout);
+void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data);
+void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data);
+#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
+int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd);
+void sdhci_external_dma_release(struct sdhci_host *host);
+void __sdhci_external_dma_prepare_data(struct sdhci_host *host, struct mmc_command *cmd);
+void sdhci_external_dma_pre_transfer(struct sdhci_host *host, struct mmc_command *cmd);
+#endif
+bool sdhci_manual_cmd23(struct sdhci_host *host, struct mmc_request *mrq);
+void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
+void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
+void __sdhci_finish_data_common(struct sdhci_host *host);
+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
+void sdhci_finish_command(struct sdhci_host *host);
+bool sdhci_present_error(struct sdhci_host *host, struct mmc_command *cmd, bool present);
 u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
 		   unsigned int *actual_clock);
 void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 20/26] mmc: sdhci-uhs2: add irq() and others
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (18 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 19/26] mmc: sdhci-uhs2: add request() and others Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:15   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 21/26] mmc: sdhci-uhs2: add add_host() and others to set up the driver Victor Shih
                   ` (7 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

This is a UHS-II version of sdhci's request() operation.
It handles UHS-II related command interrupts and errors.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 237 ++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h |   3 +
 drivers/mmc/host/sdhci.c      | 106 ++++++++-------
 drivers/mmc/host/sdhci.h      |   5 +
 4 files changed, 304 insertions(+), 47 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 41b089ccc200..883e18d849ad 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
 #include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/mmc/mmc.h>
@@ -582,6 +583,12 @@ static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
 						   struct mmc_command *cmd)
 {
 }
+
+static inline struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
+							  struct mmc_data *data)
+{
+	return NULL;
+}
 #endif /* CONFIG_MMC_SDHCI_EXTERNAL_DMA */
 
 static void sdhci_uhs2_finish_data(struct sdhci_host *host)
@@ -940,6 +947,236 @@ static void sdhci_uhs2_finish_command(struct sdhci_host *host)
 		__sdhci_finish_mrq(host, cmd->mrq);
 }
 
+/*****************************************************************************\
+ *                                                                           *
+ * Request done                                                              *
+ *                                                                           *
+\*****************************************************************************/
+
+static bool sdhci_uhs2_request_done(struct sdhci_host *host)
+{
+	unsigned long flags;
+	struct mmc_request *mrq;
+	int i;
+
+	/* FIXME: UHS2_INITIALIZED, instead? */
+	if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
+		return sdhci_request_done(host);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+		mrq = host->mrqs_done[i];
+		if (mrq)
+			break;
+	}
+
+	if (!mrq) {
+		spin_unlock_irqrestore(&host->lock, flags);
+		return true;
+	}
+
+	/*
+	 * Always unmap the data buffers if they were mapped by
+	 * sdhci_prepare_data() whenever we finish with a request.
+	 * This avoids leaking DMA mappings on error.
+	 */
+	if (host->flags & SDHCI_REQ_USE_DMA) {
+		struct mmc_data *data = mrq->data;
+
+		if (host->use_external_dma && data &&
+		    (mrq->cmd->error || data->error)) {
+			struct dma_chan *chan = sdhci_external_dma_channel(host, data);
+
+			host->mrqs_done[i] = NULL;
+			spin_unlock_irqrestore(&host->lock, flags);
+			dmaengine_terminate_sync(chan);
+			spin_lock_irqsave(&host->lock, flags);
+			sdhci_set_mrq_done(host, mrq);
+		}
+
+		sdhci_request_done_dma(host, mrq);
+	}
+
+	/*
+	 * The controller needs a reset of internal state machines
+	 * upon error conditions.
+	 */
+	if (sdhci_needs_reset(host, mrq)) {
+		/*
+		 * Do not finish until command and data lines are available for
+		 * reset. Note there can only be one other mrq, so it cannot
+		 * also be in mrqs_done, otherwise host->cmd and host->data_cmd
+		 * would both be null.
+		 */
+		if (host->cmd || host->data_cmd) {
+			spin_unlock_irqrestore(&host->lock, flags);
+			return true;
+		}
+
+		/* Some controllers need this kick or reset won't work here */
+		if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
+			/* This is to force an update */
+			host->ops->set_clock(host, host->clock);
+
+		host->ops->uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD);
+		host->pending_reset = false;
+	}
+
+	host->mrqs_done[i] = NULL;
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (host->ops->request_done)
+		host->ops->request_done(host, mrq);
+	else
+		mmc_request_done(host->mmc, mrq);
+
+	return false;
+}
+
+static void sdhci_uhs2_complete_work(struct work_struct *work)
+{
+	struct sdhci_host *host = container_of(work, struct sdhci_host,
+					       complete_work);
+
+	while (!sdhci_uhs2_request_done(host))
+		;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Interrupt handling                                                        *
+ *                                                                           *
+\*****************************************************************************/
+
+static void __sdhci_uhs2_irq(struct sdhci_host *host, u32 uhs2mask)
+{
+	struct mmc_command *cmd = host->cmd;
+
+	DBG("*** %s got UHS2 error interrupt: 0x%08x\n",
+	    mmc_hostname(host->mmc), uhs2mask);
+
+	if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_CMD_MASK) {
+		if (!host->cmd) {
+			pr_err("%s: Got cmd interrupt 0x%08x but no cmd.\n",
+			       mmc_hostname(host->mmc),
+			       (unsigned int)uhs2mask);
+			sdhci_dumpregs(host);
+			return;
+		}
+		host->cmd->error = -EILSEQ;
+		if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT)
+			host->cmd->error = -ETIMEDOUT;
+	}
+
+	if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_DATA_MASK) {
+		if (!host->data) {
+			pr_err("%s: Got data interrupt 0x%08x but no data.\n",
+			       mmc_hostname(host->mmc),
+			       (unsigned int)uhs2mask);
+			sdhci_dumpregs(host);
+			return;
+		}
+
+		if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT) {
+			pr_err("%s: Got deadlock timeout interrupt 0x%08x\n",
+			       mmc_hostname(host->mmc),
+			       (unsigned int)uhs2mask);
+			host->data->error = -ETIMEDOUT;
+		} else if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_ADMA) {
+			pr_err("%s: ADMA error = 0x %x\n",
+			       mmc_hostname(host->mmc),
+			       sdhci_readb(host, SDHCI_ADMA_ERROR));
+			host->data->error = -EIO;
+		} else {
+			host->data->error = -EILSEQ;
+		}
+	}
+
+	if (host->data && host->data->error)
+		sdhci_uhs2_finish_data(host);
+	else
+		sdhci_finish_mrq(host, cmd->mrq);
+}
+
+u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask)
+{
+	u32 mask = intmask, uhs2mask;
+
+	if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
+		goto out;
+
+	if (intmask & SDHCI_INT_ERROR) {
+		uhs2mask = sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS);
+		if (!(uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_MASK))
+			goto cmd_irq;
+
+		/* Clear error interrupts */
+		sdhci_writel(host, uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_MASK,
+			     SDHCI_UHS2_ERR_INT_STATUS);
+
+		/* Handle error interrupts */
+		__sdhci_uhs2_irq(host, uhs2mask);
+
+		/* Caller, shdci_irq(), doesn't have to care UHS-2 errors */
+		intmask &= ~SDHCI_INT_ERROR;
+		mask &= SDHCI_INT_ERROR;
+	}
+
+cmd_irq:
+	if (intmask & SDHCI_INT_CMD_MASK) {
+		/* Clear command interrupt */
+		sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, SDHCI_INT_STATUS);
+
+		/* Handle command interrupt */
+		if (intmask & SDHCI_INT_RESPONSE)
+			sdhci_uhs2_finish_command(host);
+
+		/* Caller, shdci_irq(), doesn't have to care UHS-2 command */
+		intmask &= ~SDHCI_INT_CMD_MASK;
+		mask &= SDHCI_INT_CMD_MASK;
+	}
+
+	/* Clear already-handled interrupts. */
+	sdhci_writel(host, mask, SDHCI_INT_STATUS);
+
+out:
+	return intmask;
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_irq);
+
+static irqreturn_t sdhci_uhs2_thread_irq(int irq, void *dev_id)
+{
+	struct sdhci_host *host = dev_id;
+	struct mmc_command *cmd;
+	unsigned long flags;
+	u32 isr;
+
+	while (!sdhci_uhs2_request_done(host))
+		;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	isr = host->thread_isr;
+	host->thread_isr = 0;
+
+	cmd = host->deferred_cmd;
+	if (cmd && !sdhci_uhs2_send_command_retry(host, cmd, flags))
+		sdhci_finish_mrq(host, cmd->mrq);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+		struct mmc_host *mmc = host->mmc;
+
+		mmc->ops->card_event(mmc);
+		mmc_detect_change(mmc, msecs_to_jiffies(200));
+	}
+
+	return IRQ_HANDLED;
+}
+
 void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index 23368448ccd4..d32a8602d045 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -217,5 +217,8 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
 			  unsigned short vdd);
 void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
 void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
+void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq);
+int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
+u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask);
 
 #endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 407169468927..e44ede049559 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1268,11 +1268,12 @@ static int sdhci_external_dma_init(struct sdhci_host *host)
 	return ret;
 }
 
-static struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
-						   struct mmc_data *data)
+struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
+					    struct mmc_data *data)
 {
 	return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
 }
+EXPORT_SYMBOL_GPL(sdhci_external_dma_channel);
 
 int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd)
 {
@@ -1522,7 +1523,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
 	sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
 }
 
-static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
+bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
 {
 	return (!(host->flags & SDHCI_DEVICE_DEAD) &&
 		((mrq->cmd && mrq->cmd->error) ||
@@ -1530,8 +1531,9 @@ static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
 		 (mrq->data && mrq->data->stop && mrq->data->stop->error) ||
 		 (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
 }
+EXPORT_SYMBOL_GPL(sdhci_needs_reset);
 
-static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
+void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
 {
 	int i;
 
@@ -1551,6 +1553,7 @@ static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
 
 	WARN_ON(i >= SDHCI_MAX_MRQS);
 }
+EXPORT_SYMBOL_GPL(sdhci_set_mrq_done);
 
 void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
 {
@@ -3103,7 +3106,56 @@ static const struct mmc_host_ops sdhci_ops = {
  *                                                                           *
 \*****************************************************************************/
 
-static bool sdhci_request_done(struct sdhci_host *host)
+void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq)
+{
+	struct mmc_data *data = mrq->data;
+
+	if (data && data->host_cookie == COOKIE_MAPPED) {
+		if (host->bounce_buffer) {
+			/*
+			 * On reads, copy the bounced data into the
+			 * sglist
+			 */
+			if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
+				unsigned int length = data->bytes_xfered;
+
+				if (length > host->bounce_buffer_size) {
+					pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
+					       mmc_hostname(host->mmc),
+					       host->bounce_buffer_size,
+					       data->bytes_xfered);
+					/* Cap it down and continue */
+					length = host->bounce_buffer_size;
+				}
+				dma_sync_single_for_cpu(
+					host->mmc->parent,
+					host->bounce_addr,
+					host->bounce_buffer_size,
+					DMA_FROM_DEVICE);
+				sg_copy_from_buffer(data->sg,
+					data->sg_len,
+					host->bounce_buffer,
+					length);
+			} else {
+				/* No copying, just switch ownership */
+				dma_sync_single_for_cpu(
+					host->mmc->parent,
+					host->bounce_addr,
+					host->bounce_buffer_size,
+					mmc_get_dma_dir(data));
+			}
+		} else {
+			/* Unmap the raw data */
+			dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+				     data->sg_len,
+				     mmc_get_dma_dir(data));
+		}
+		data->host_cookie = COOKIE_UNMAPPED;
+	}
+}
+EXPORT_SYMBOL_GPL(sdhci_request_done_dma);
+
+bool sdhci_request_done(struct sdhci_host *host)
 {
 	unsigned long flags;
 	struct mmc_request *mrq;
@@ -3167,48 +3219,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
 			sdhci_set_mrq_done(host, mrq);
 		}
 
-		if (data && data->host_cookie == COOKIE_MAPPED) {
-			if (host->bounce_buffer) {
-				/*
-				 * On reads, copy the bounced data into the
-				 * sglist
-				 */
-				if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
-					unsigned int length = data->bytes_xfered;
-
-					if (length > host->bounce_buffer_size) {
-						pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
-						       mmc_hostname(host->mmc),
-						       host->bounce_buffer_size,
-						       data->bytes_xfered);
-						/* Cap it down and continue */
-						length = host->bounce_buffer_size;
-					}
-					dma_sync_single_for_cpu(
-						mmc_dev(host->mmc),
-						host->bounce_addr,
-						host->bounce_buffer_size,
-						DMA_FROM_DEVICE);
-					sg_copy_from_buffer(data->sg,
-						data->sg_len,
-						host->bounce_buffer,
-						length);
-				} else {
-					/* No copying, just switch ownership */
-					dma_sync_single_for_cpu(
-						mmc_dev(host->mmc),
-						host->bounce_addr,
-						host->bounce_buffer_size,
-						mmc_get_dma_dir(data));
-				}
-			} else {
-				/* Unmap the raw data */
-				dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-					     data->sg_len,
-					     mmc_get_dma_dir(data));
-			}
-			data->host_cookie = COOKIE_UNMAPPED;
-		}
+		sdhci_request_done_dma(host, mrq);
 	}
 
 	host->mrqs_done[i] = NULL;
@@ -3222,6 +3233,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
 
 	return false;
 }
+EXPORT_SYMBOL_GPL(sdhci_request_done);
 
 static void sdhci_complete_work(struct work_struct *work)
 {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 1a9924e7972d..49de8fdbd7a3 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -861,8 +861,11 @@ int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd);
 void sdhci_external_dma_release(struct sdhci_host *host);
 void __sdhci_external_dma_prepare_data(struct sdhci_host *host, struct mmc_command *cmd);
 void sdhci_external_dma_pre_transfer(struct sdhci_host *host, struct mmc_command *cmd);
+struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host, struct mmc_data *data);
 #endif
 bool sdhci_manual_cmd23(struct sdhci_host *host, struct mmc_request *mrq);
+bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq);
+void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq);
 void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
 void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
 void __sdhci_finish_data_common(struct sdhci_host *host);
@@ -895,6 +898,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
 int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 				      struct mmc_ios *ios);
 void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
+void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq);
+bool sdhci_request_done(struct sdhci_host *host);
 void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
 			   dma_addr_t addr, int len, unsigned int cmd);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 21/26] mmc: sdhci-uhs2: add add_host() and others to set up the driver
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (19 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 20/26] mmc: sdhci-uhs2: add irq() " Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-11-01 17:15   ` Adrian Hunter
  2022-10-19 11:06 ` [PATCH V5 22/26] mmc: sdhci-uhs2: add pre-detect_init hook Victor Shih
                   ` (6 subsequent siblings)
  27 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

This is a UHS-II version of sdhci's add_host/remove_host operation.
Any sdhci drivers which are capable of handling UHS-II cards must
call those functions instead of the corresponding sdhci's.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 172 ++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h |   2 +
 drivers/mmc/host/sdhci.c      |  21 +++--
 drivers/mmc/host/sdhci.h      |   9 ++
 4 files changed, 197 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 883e18d849ad..eb3241bf95a2 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -15,6 +15,7 @@
 #include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/mmc/mmc.h>
+#include <linux/regulator/consumer.h>
 
 #include "sdhci.h"
 #include "sdhci-uhs2.h"
@@ -1177,6 +1178,177 @@ static irqreturn_t sdhci_uhs2_thread_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/*****************************************************************************\
+ *
+ * Device allocation/registration                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __sdhci_uhs2_add_host_v4(struct sdhci_host *host, u32 caps1)
+{
+	struct mmc_host *mmc;
+	u32 max_current_caps2;
+
+	if (host->version < SDHCI_SPEC_400)
+		return 0;
+
+	mmc = host->mmc;
+
+	/* Support UHS2 */
+	if (caps1 & SDHCI_SUPPORT_UHS2)
+		mmc->caps2 |= MMC_CAP2_SD_UHS2;
+
+	max_current_caps2 = sdhci_readl(host, SDHCI_MAX_CURRENT_1);
+
+	if ((caps1 & SDHCI_SUPPORT_VDD2_180) &&
+	    !max_current_caps2 &&
+	    !IS_ERR(mmc->supply.vmmc2)) {
+		/* UHS2 - VDD2 */
+		int curr = regulator_get_current_limit(mmc->supply.vmmc2);
+
+		if (curr > 0) {
+			/* convert to SDHCI_MAX_CURRENT format */
+			curr = curr / 1000;  /* convert to mA */
+			curr = curr / SDHCI_MAX_CURRENT_MULTIPLIER;
+			curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
+			max_current_caps2 = curr;
+		}
+	}
+
+	if (caps1 & SDHCI_SUPPORT_VDD2_180) {
+		mmc->ocr_avail_uhs2 |= MMC_VDD2_165_195;
+		/*
+		 * UHS2 doesn't require this. Only UHS-I bus needs to set
+		 * max current.
+		 */
+		mmc->max_current_180_vdd2 = (max_current_caps2 &
+					SDHCI_MAX_CURRENT_VDD2_180_MASK) *
+					SDHCI_MAX_CURRENT_MULTIPLIER;
+	} else {
+		mmc->caps2 &= ~MMC_CAP2_SD_UHS2;
+	}
+
+	return 0;
+}
+
+static int sdhci_uhs2_host_ops_init(struct sdhci_host *host);
+
+static int __sdhci_uhs2_add_host(struct sdhci_host *host)
+{
+	unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI;
+	struct mmc_host *mmc = host->mmc;
+	int ret;
+
+	if ((mmc->caps2 & MMC_CAP2_CQE) &&
+	    (host->quirks & SDHCI_QUIRK_BROKEN_CQE)) {
+		mmc->caps2 &= ~MMC_CAP2_CQE;
+		mmc->cqe_ops = NULL;
+	}
+
+	/* overwrite ops */
+	if (mmc->caps2 & MMC_CAP2_SD_UHS2)
+		sdhci_uhs2_host_ops_init(host);
+
+	host->complete_wq = alloc_workqueue("sdhci", flags, 0);
+	if (!host->complete_wq)
+		return -ENOMEM;
+
+	INIT_WORK(&host->complete_work, sdhci_uhs2_complete_work);
+
+	timer_setup(&host->timer, sdhci_timeout_timer, 0);
+	timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
+
+	init_waitqueue_head(&host->buf_ready_int);
+
+	sdhci_init(host, 0);
+
+	ret = request_threaded_irq(host->irq, sdhci_irq,
+				   sdhci_uhs2_thread_irq,
+				   IRQF_SHARED,	mmc_hostname(mmc), host);
+	if (ret) {
+		pr_err("%s: Failed to request IRQ %d: %d\n",
+		       mmc_hostname(mmc), host->irq, ret);
+		goto unwq;
+	}
+
+	ret = mmc_add_host(mmc);
+		if (ret)
+			return 1;
+
+	pr_info("%s: SDHCI controller on %s [%s] using %s\n",
+		mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
+		host->use_external_dma ? "External DMA" :
+		(host->flags & SDHCI_USE_ADMA) ?
+		(host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" :
+		(host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
+
+	sdhci_enable_card_detection(host);
+
+	return 0;
+
+unwq:
+	destroy_workqueue(host->complete_wq);
+
+	return ret;
+}
+
+static void __sdhci_uhs2_remove_host(struct sdhci_host *host, int dead)
+{
+	if (!(host->mmc) || !(host->mmc->flags & MMC_UHS2_SUPPORT))
+		return;
+
+	if (!dead)
+		host->ops->uhs2_reset(host, SDHCI_UHS2_SW_RESET_FULL);
+
+	sdhci_writel(host, 0, SDHCI_UHS2_ERR_INT_STATUS_EN);
+	sdhci_writel(host, 0, SDHCI_UHS2_ERR_INT_SIG_EN);
+	host->mmc->flags &= ~MMC_UHS2_INITIALIZED;
+}
+
+int sdhci_uhs2_add_host(struct sdhci_host *host)
+{
+	struct mmc_host *mmc = host->mmc;
+	int ret;
+
+	ret = sdhci_setup_host(host);
+	if (ret)
+		return ret;
+
+	if (host->version >= SDHCI_SPEC_400) {
+		ret = __sdhci_uhs2_add_host_v4(host, host->caps1);
+		if (ret)
+			goto cleanup;
+	}
+
+	if ((mmc->caps2 & MMC_CAP2_SD_UHS2) && !host->v4_mode)
+		/* host doesn't want to enable UHS2 support */
+		/* FIXME: Do we have to do some cleanup here? */
+		mmc->caps2 &= ~MMC_CAP2_SD_UHS2;
+
+	ret = __sdhci_uhs2_add_host(host);
+	if (ret)
+		goto cleanup2;
+
+	return 0;
+
+cleanup2:
+	if (host->version >= SDHCI_SPEC_400)
+		__sdhci_uhs2_remove_host(host, 0);
+cleanup:
+	sdhci_cleanup_host(host);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_add_host);
+
+void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead)
+{
+	__sdhci_uhs2_remove_host(host, dead);
+
+	sdhci_remove_host(host, dead);
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_remove_host);
+
 void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index d32a8602d045..54241a7adfca 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -220,5 +220,7 @@ void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
 void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq);
 int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
 u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask);
+int sdhci_uhs2_add_host(struct sdhci_host *host);
+void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead);
 
 #endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index e44ede049559..df433ad0ba66 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -173,10 +173,11 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
-static void sdhci_enable_card_detection(struct sdhci_host *host)
+void sdhci_enable_card_detection(struct sdhci_host *host)
 {
 	sdhci_set_card_detection(host, true);
 }
+EXPORT_SYMBOL_GPL(sdhci_enable_card_detection);
 
 static void sdhci_disable_card_detection(struct sdhci_host *host)
 {
@@ -365,7 +366,7 @@ static void sdhci_config_dma(struct sdhci_host *host)
 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 }
 
-static void sdhci_init(struct sdhci_host *host, int soft)
+void sdhci_init(struct sdhci_host *host, int soft)
 {
 	struct mmc_host *mmc = host->mmc;
 	unsigned long flags;
@@ -390,6 +391,7 @@ static void sdhci_init(struct sdhci_host *host, int soft)
 		mmc->ops->set_ios(mmc, &mmc->ios);
 	}
 }
+EXPORT_SYMBOL_GPL(sdhci_init);
 
 static void sdhci_reinit(struct sdhci_host *host)
 {
@@ -454,7 +456,7 @@ static void sdhci_led_control(struct led_classdev *led,
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_led_register(struct sdhci_host *host)
+int sdhci_led_register(struct sdhci_host *host)
 {
 	struct mmc_host *mmc = host->mmc;
 
@@ -471,14 +473,16 @@ static int sdhci_led_register(struct sdhci_host *host)
 
 	return led_classdev_register(mmc_dev(mmc), &host->led);
 }
+EXPORT_SYMBOL_GPL(sdhci_led_register);
 
-static void sdhci_led_unregister(struct sdhci_host *host)
+void sdhci_led_unregister(struct sdhci_host *host)
 {
 	if (host->quirks & SDHCI_QUIRK_NO_LED)
 		return;
 
 	led_classdev_unregister(&host->led);
 }
+EXPORT_SYMBOL_GPL(sdhci_led_unregister);
 
 static inline void sdhci_led_activate(struct sdhci_host *host)
 {
@@ -3244,7 +3248,7 @@ static void sdhci_complete_work(struct work_struct *work)
 		;
 }
 
-static void sdhci_timeout_timer(struct timer_list *t)
+void sdhci_timeout_timer(struct timer_list *t)
 {
 	struct sdhci_host *host;
 	unsigned long flags;
@@ -3265,8 +3269,9 @@ static void sdhci_timeout_timer(struct timer_list *t)
 
 	spin_unlock_irqrestore(&host->lock, flags);
 }
+EXPORT_SYMBOL_GPL(sdhci_timeout_timer);
 
-static void sdhci_timeout_data_timer(struct timer_list *t)
+void sdhci_timeout_data_timer(struct timer_list *t)
 {
 	struct sdhci_host *host;
 	unsigned long flags;
@@ -3297,6 +3302,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t)
 
 	spin_unlock_irqrestore(&host->lock, flags);
 }
+EXPORT_SYMBOL_GPL(sdhci_timeout_data_timer);
 
 /*****************************************************************************\
  *                                                                           *
@@ -3560,7 +3566,7 @@ static inline bool sdhci_defer_done(struct sdhci_host *host,
 		data->host_cookie == COOKIE_MAPPED);
 }
 
-static irqreturn_t sdhci_irq(int irq, void *dev_id)
+irqreturn_t sdhci_irq(int irq, void *dev_id)
 {
 	struct mmc_request *mrqs_done[SDHCI_MAX_MRQS] = {0};
 	irqreturn_t result = IRQ_NONE;
@@ -3701,6 +3707,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
 	return result;
 }
+EXPORT_SYMBOL_GPL(sdhci_irq);
 
 static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
 {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 49de8fdbd7a3..0970fe392d49 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -851,8 +851,14 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
 }
 
 bool sdhci_data_line_cmd(struct mmc_command *cmd);
+void sdhci_enable_card_detection(struct sdhci_host *host);
 void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
 void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
+void sdhci_init(struct sdhci_host *host, int soft);
+#if IS_REACHABLE(CONFIG_LEDS_CLASS)
+int sdhci_led_register(struct sdhci_host *host);
+void sdhci_led_unregister(struct sdhci_host *host);
+#endif
 void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, unsigned long timeout);
 void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data);
 void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data);
@@ -900,6 +906,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
 void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq);
 bool sdhci_request_done(struct sdhci_host *host);
+void sdhci_timeout_timer(struct timer_list *t);
+void sdhci_timeout_data_timer(struct timer_list *t);
+irqreturn_t sdhci_irq(int irq, void *dev_id);
 void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
 			   dma_addr_t addr, int len, unsigned int cmd);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 22/26] mmc: sdhci-uhs2: add pre-detect_init hook
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (20 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 21/26] mmc: sdhci-uhs2: add add_host() and others to set up the driver Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:06 ` [PATCH V5 23/26] mmc: core: add post-mmc_attach_sd hook Victor Shih
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

From: Victor Shih <Victor.Shih@genesyslogic.com.tw>

This "pre" hook for detect_init(), uhs2_pre_detect_init, will be required
to enable UHS-II support, at least, on GL9755.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/sdhci-uhs2.c | 3 +++
 drivers/mmc/host/sdhci.h      | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index eb3241bf95a2..212701267d2d 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -1542,6 +1542,9 @@ static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc)
 
 	DBG("%s: begin UHS2 init.\n", __func__);
 
+	if (host->ops && host->ops->uhs2_pre_detect_init)
+		host->ops->uhs2_pre_detect_init(host);
+
 	if (sdhci_uhs2_interface_detect(host)) {
 		pr_warn("%s: cannot detect UHS2 interface.\n",
 			mmc_hostname(host->mmc));
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 0970fe392d49..97728eee5b25 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -743,6 +743,7 @@ struct sdhci_ops {
 				struct mmc_request *mrq);
 	void    (*dump_vendor_regs)(struct sdhci_host *host);
 	void	(*dump_uhs2_regs)(struct sdhci_host *host);
+	void    (*uhs2_pre_detect_init)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 23/26] mmc: core: add post-mmc_attach_sd hook
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (21 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 22/26] mmc: sdhci-uhs2: add pre-detect_init hook Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:06 ` [PATCH V5 24/26] mmc: sdhci-uhs2: " Victor Shih
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

This "post" hook for mmc_attach_sd() will be required to enable UHS-II
support, at least, on GL9755.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/core/sd.c    | 5 +++++
 include/linux/mmc/host.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index cab4725209c1..3edd1530ec51 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1855,6 +1855,11 @@ int mmc_attach_sd(struct mmc_host *host)
 		goto remove_card;
 
 	mmc_claim_host(host);
+
+	if ((host->flags & MMC_UHS2_INITIALIZED) &&
+	    host->ops->uhs2_post_attach_sd)
+		host->ops->uhs2_post_attach_sd(host);
+
 	return 0;
 
 remove_card:
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 249a9414ad10..89e82559cb73 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -279,6 +279,7 @@ struct mmc_host_ops {
 	int	(*uhs2_set_reg)(struct mmc_host *host, enum sd_uhs2_operation act);
 	int (*uhs2_disable_clk)(struct mmc_host *host);
 	int (*uhs2_enable_clk)(struct mmc_host *host);
+	void (*uhs2_post_attach_sd)(struct mmc_host *host);
 
 	/*
 	 * The uhs2_control callback is used to execute SD UHS-II specific
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 24/26] mmc: sdhci-uhs2: add post-mmc_attach_sd hook
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (22 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 23/26] mmc: core: add post-mmc_attach_sd hook Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:06 ` [PATCH V5 25/26] mmc: sdhci-pci: add UHS-II support framework Victor Shih
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

From: Ben Chuang <ben.chuang@genesyslogic.com.tw>

This "post" hook for mmc_attach_sd(), uhs2_post_attach_sd, will be required
to enable UHS-II support, at least, on GL9755.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 drivers/mmc/host/sdhci.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 97728eee5b25..180b4f0548e2 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -744,6 +744,7 @@ struct sdhci_ops {
 	void    (*dump_vendor_regs)(struct sdhci_host *host);
 	void	(*dump_uhs2_regs)(struct sdhci_host *host);
 	void    (*uhs2_pre_detect_init)(struct sdhci_host *host);
+	void    (*uhs2_post_attach_sd)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 25/26] mmc: sdhci-pci: add UHS-II support framework
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (23 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 24/26] mmc: sdhci-uhs2: " Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:06 ` [PATCH V5 26/26] mmc: sdhci-pci-gli: enable UHS-II mode for GL9755 Victor Shih
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

From: AKASHI Takahiro <takahiro.akashi@linaro.org>

This patch prepares for adding UHS-II support at a specific UHS-II
capable sdhci-pci controller, GL9755 for now.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 drivers/mmc/host/sdhci-pci-core.c | 16 +++++++++++++++-
 drivers/mmc/host/sdhci-pci.h      |  3 +++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index cba5bba994b8..e0523a775a1d 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -39,6 +39,7 @@
 
 #include "sdhci.h"
 #include "sdhci-pci.h"
+#include "sdhci-uhs2.h"
 
 static void sdhci_pci_hw_reset(struct sdhci_host *host);
 
@@ -2159,7 +2160,10 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
 	if (scratch == (u32)-1)
 		dead = 1;
 
-	sdhci_remove_host(slot->host, dead);
+	if (slot->chip->fixes && slot->chip->fixes->remove_host)
+		slot->chip->fixes->remove_host(slot, dead);
+	else
+		sdhci_remove_host(slot->host, dead);
 
 	if (slot->chip->fixes && slot->chip->fixes->remove_slot)
 		slot->chip->fixes->remove_slot(slot, dead);
@@ -2167,6 +2171,16 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
 	sdhci_free_host(slot->host);
 }
 
+int sdhci_pci_uhs2_add_host(struct sdhci_pci_slot *slot)
+{
+	return sdhci_uhs2_add_host(slot->host);
+}
+
+void sdhci_pci_uhs2_remove_host(struct sdhci_pci_slot *slot, int dead)
+{
+	sdhci_uhs2_remove_host(slot->host, dead);
+}
+
 static void sdhci_pci_runtime_pm_allow(struct device *dev)
 {
 	pm_suspend_ignore_children(dev, 1);
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index 3661a224fb04..7f4a981c0e63 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -140,6 +140,7 @@ struct sdhci_pci_fixes {
 	int			(*probe_slot) (struct sdhci_pci_slot *);
 	int			(*add_host) (struct sdhci_pci_slot *);
 	void			(*remove_slot) (struct sdhci_pci_slot *, int);
+	void			(*remove_host) (struct sdhci_pci_slot *, int);
 
 #ifdef CONFIG_PM_SLEEP
 	int			(*suspend) (struct sdhci_pci_chip *);
@@ -184,6 +185,8 @@ static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot)
 	return (void *)slot->private;
 }
 
+int sdhci_pci_uhs2_add_host(struct sdhci_pci_slot *slot);
+void sdhci_pci_uhs2_remove_host(struct sdhci_pci_slot *slot, int dead);
 #ifdef CONFIG_PM_SLEEP
 int sdhci_pci_resume_host(struct sdhci_pci_chip *chip);
 #endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH V5 26/26] mmc: sdhci-pci-gli: enable UHS-II mode for GL9755
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (24 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 25/26] mmc: sdhci-pci: add UHS-II support framework Victor Shih
@ 2022-10-19 11:06 ` Victor Shih
  2022-10-19 11:29 ` [PATCH V5 00/26] Add support UHS-II " Ulf Hansson
  2022-11-01 17:28 ` Adrian Hunter
  27 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:06 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Changes are:
* Disable GL9755 overcurrent interrupt when power on/off on UHS-II.
* Enable the internal clock when do reset on UHS-II mode.
* Set ZC to 0x0 for Sandisk cards and set ZC to 0xB for others.
* Increase timeout value before detecting UHS-II interface.
* Add vendor settings fro UHS-II mode.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
---
 drivers/mmc/host/Kconfig         |   1 +
 drivers/mmc/host/sdhci-pci-gli.c | 309 ++++++++++++++++++++++++++++++-
 2 files changed, 309 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 7e53cca97934..56f412dbadc8 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -102,6 +102,7 @@ config MMC_SDHCI_PCI
 	tristate "SDHCI support on PCI bus"
 	depends on MMC_SDHCI && PCI
 	select MMC_CQHCI
+	select MMC_SDHCI_UHS2
 	select IOSF_MBI if X86
 	select MMC_SDHCI_IO_ACCESSORS
 	help
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 607cf69f45d0..f3a9a5e7aabb 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -17,6 +17,7 @@
 #include "sdhci.h"
 #include "sdhci-pci.h"
 #include "cqhci.h"
+#include "sdhci-uhs2.h"
 
 /*  Genesys Logic extra registers */
 #define SDHCI_GLI_9750_WT         0x800
@@ -138,9 +139,36 @@
 
 #define PCI_GLI_9755_PLLSSC        0x68
 #define   PCI_GLI_9755_PLLSSC_PPM    GENMASK(15, 0)
+#define   PCI_GLI_9755_PLLSSC_RTL             BIT(24)
+#define   GLI_9755_PLLSSC_RTL_VALUE           0x1
+#define   PCI_GLI_9755_PLLSSC_TRANS_PASS      BIT(27)
+#define   GLI_9755_PLLSSC_TRANS_PASS_VALUE    0x1
+#define   PCI_GLI_9755_PLLSSC_RECV            GENMASK(29, 28)
+#define   GLI_9755_PLLSSC_RECV_VALUE          0x3
+#define   PCI_GLI_9755_PLLSSC_TRAN            GENMASK(31, 30)
+#define   GLI_9755_PLLSSC_TRAN_VALUE          0x3
+
+#define PCI_GLI_9755_UHS2_PLL            0x6C
+#define   PCI_GLI_9755_UHS2_PLL_SSC        GENMASK(9, 8)
+#define   GLI_9755_UHS2_PLL_SSC_VALUE      0x0
+#define   PCI_GLI_9755_UHS2_PLL_DELAY      BIT(18)
+#define   GLI_9755_UHS2_PLL_DELAY_VALUE    0x1
+#define   PCI_GLI_9755_UHS2_PLL_PDRST      BIT(27)
+#define   GLI_9755_UHS2_PLL_PDRST_VALUE    0x1
 
 #define PCI_GLI_9755_SerDes  0x70
+#define   PCI_GLI_9755_UHS2_SERDES_INTR       GENMASK(2, 0)
+#define   GLI_9755_UHS2_SERDES_INTR_VALUE     0x3
+#define   PCI_GLI_9755_UHS2_SERDES_ZC1        BIT(3)
+#define   GLI_9755_UHS2_SERDES_ZC1_VALUE      0x0
+#define   PCI_GLI_9755_UHS2_SERDES_ZC2        GENMASK(7, 4)
+#define   GLI_9755_UHS2_SERDES_ZC2_DEFAULT    0xB
+#define   GLI_9755_UHS2_SERDES_ZC2_SANDISK    0x0
 #define PCI_GLI_9755_SCP_DIS   BIT(19)
+#define   PCI_GLI_9755_UHS2_SERDES_TRAN       GENMASK(27, 24)
+#define   GLI_9755_UHS2_SERDES_TRAN_VALUE     0xC
+#define   PCI_GLI_9755_UHS2_SERDES_RECV       GENMASK(31, 28)
+#define   GLI_9755_UHS2_SERDES_RECV_VALUE     0xF
 
 #define PCI_GLI_9755_MISC	    0x78
 #define   PCI_GLI_9755_MISC_SSC_OFF    BIT(26)
@@ -692,6 +720,276 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
 	gl9755_wt_off(pdev);
 }
 
+static void gl9755_vendor_init(struct sdhci_host *host)
+{
+	struct sdhci_pci_slot *slot = sdhci_priv(host);
+	struct pci_dev *pdev = slot->chip->pdev;
+	u32 serdes;
+	u32 pllssc;
+	u32 uhs2_pll;
+
+	gl9755_wt_on(pdev);
+
+	pci_read_config_dword(pdev, PCI_GLI_9755_SerDes, &serdes);
+	serdes &= ~PCI_GLI_9755_UHS2_SERDES_TRAN;
+	serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_TRAN,
+			     GLI_9755_UHS2_SERDES_TRAN_VALUE);
+	serdes &= ~PCI_GLI_9755_UHS2_SERDES_RECV;
+	serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_RECV,
+			     GLI_9755_UHS2_SERDES_RECV_VALUE);
+	serdes &= ~PCI_GLI_9755_UHS2_SERDES_INTR;
+	serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_INTR,
+			     GLI_9755_UHS2_SERDES_INTR_VALUE);
+	serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC1;
+	serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC1,
+			     GLI_9755_UHS2_SERDES_ZC1_VALUE);
+	serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC2;
+	serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC2,
+			     GLI_9755_UHS2_SERDES_ZC2_DEFAULT);
+	pci_write_config_dword(pdev, PCI_GLI_9755_SerDes, serdes);
+
+	pci_read_config_dword(pdev, PCI_GLI_9755_UHS2_PLL, &uhs2_pll);
+	uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_SSC;
+	uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_SSC,
+			  GLI_9755_UHS2_PLL_SSC_VALUE);
+	uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_DELAY;
+	uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_DELAY,
+			  GLI_9755_UHS2_PLL_DELAY_VALUE);
+	uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_PDRST;
+	uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_PDRST,
+			  GLI_9755_UHS2_PLL_PDRST_VALUE);
+	pci_write_config_dword(pdev, PCI_GLI_9755_UHS2_PLL, uhs2_pll);
+
+	pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &pllssc);
+	pllssc &= ~PCI_GLI_9755_PLLSSC_RTL;
+	pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_RTL,
+			  GLI_9755_PLLSSC_RTL_VALUE);
+	pllssc &= ~PCI_GLI_9755_PLLSSC_TRANS_PASS;
+	pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_TRANS_PASS,
+			  GLI_9755_PLLSSC_TRANS_PASS_VALUE);
+	pllssc &= ~PCI_GLI_9755_PLLSSC_RECV;
+	pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_RECV,
+			  GLI_9755_PLLSSC_RECV_VALUE);
+	pllssc &= ~PCI_GLI_9755_PLLSSC_TRAN;
+	pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_TRAN,
+			  GLI_9755_PLLSSC_TRAN_VALUE);
+	pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, pllssc);
+
+	gl9755_wt_off(pdev);
+}
+
+static void gl9755_pre_detect_init(struct sdhci_host *host)
+{
+	/* GL9755 need more time on UHS2 detect flow */
+	sdhci_writeb(host, 0xA7, SDHCI_UHS2_TIMER_CTRL);
+}
+
+static void gl9755_post_attach_sd(struct sdhci_host *host)
+{
+	struct pci_dev *pdev;
+	struct sdhci_pci_chip *chip;
+	struct sdhci_pci_slot *slot;
+	u32 serdes;
+
+	slot = sdhci_priv(host);
+	chip = slot->chip;
+	pdev = chip->pdev;
+
+	gl9755_wt_on(pdev);
+
+	pci_read_config_dword(pdev, PCI_GLI_9755_SerDes, &serdes);
+	serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC1;
+	serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC2;
+	serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC1,
+			     GLI_9755_UHS2_SERDES_ZC1_VALUE);
+
+	/* the manfid of sandisk card is 0x3 */
+	if (host->mmc->card->cid.manfid == 0x3)
+		serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC2,
+				     GLI_9755_UHS2_SERDES_ZC2_SANDISK);
+	else
+		serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC2,
+				     GLI_9755_UHS2_SERDES_ZC2_DEFAULT);
+
+	pci_write_config_dword(pdev, PCI_GLI_9755_SerDes, serdes);
+
+	gl9755_wt_off(pdev);
+}
+
+static void gl9755_overcurrent_event_enable(struct sdhci_host *host,
+					    bool enable)
+{
+	u32 mask;
+
+	mask = sdhci_readl(host, SDHCI_SIGNAL_ENABLE);
+	if (enable)
+		mask |= SDHCI_INT_BUS_POWER;
+	else
+		mask &= ~SDHCI_INT_BUS_POWER;
+
+	sdhci_writel(host, mask, SDHCI_SIGNAL_ENABLE);
+
+	mask = sdhci_readl(host, SDHCI_INT_ENABLE);
+	if (enable)
+		mask |= SDHCI_INT_BUS_POWER;
+	else
+		mask &= ~SDHCI_INT_BUS_POWER;
+
+	sdhci_writel(host, mask, SDHCI_INT_ENABLE);
+}
+
+static void gl9755_set_power(struct sdhci_host *host, unsigned char mode,
+			     unsigned short vdd)
+{
+	u8 pwr = 0;
+
+	if (mode != MMC_POWER_OFF) {
+		switch (1 << vdd) {
+		case MMC_VDD_165_195:
+		/*
+		 * Without a regulator, SDHCI does not support 2.0v
+		 * so we only get here if the driver deliberately
+		 * added the 2.0v range to ocr_avail. Map it to 1.8v
+		 * for the purpose of turning on the power.
+		 */
+		case MMC_VDD_20_21:
+			pwr = SDHCI_POWER_180;
+			break;
+		case MMC_VDD_29_30:
+		case MMC_VDD_30_31:
+			pwr = SDHCI_POWER_300;
+			break;
+		case MMC_VDD_32_33:
+		case MMC_VDD_33_34:
+			pwr = SDHCI_POWER_330;
+			break;
+		default:
+			WARN(1, "%s: Invalid vdd %#x\n",
+			     mmc_hostname(host->mmc), vdd);
+			break;
+		}
+
+		pwr |= SDHCI_VDD2_POWER_180;
+	}
+
+	if (host->pwr == pwr)
+		return;
+
+	host->pwr = pwr;
+
+	if (pwr == 0) {
+		gl9755_overcurrent_event_enable(host, false);
+		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+	} else {
+		gl9755_overcurrent_event_enable(host, false);
+		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+
+		pwr |= (SDHCI_POWER_ON | SDHCI_VDD2_POWER_ON);
+
+		sdhci_writeb(host, pwr & 0xf, SDHCI_POWER_CONTROL);
+		/* wait stable */
+		mdelay(5);
+		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+		/* wait stable */
+		mdelay(5);
+		gl9755_overcurrent_event_enable(host, true);
+	}
+}
+
+static bool sdhci_wait_clock_stable(struct sdhci_host *host)
+{
+	u16 clk = 0;
+	ktime_t timeout;
+
+	/* Wait max 20 ms */
+	timeout = ktime_add_ms(ktime_get(), 20);
+	while (1) {
+		bool timedout = ktime_after(ktime_get(), timeout);
+
+		clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+		if (clk & SDHCI_CLOCK_INT_STABLE)
+			break;
+		if (timedout) {
+			pr_err("%s: Internal clock never stabilised.\n",
+			       mmc_hostname(host->mmc));
+			sdhci_dumpregs(host);
+			return false;
+		}
+		udelay(10);
+	}
+	return true;
+}
+
+static void gl9755_uhs2_reset_sd_tran(struct sdhci_host *host)
+{
+	/* do this on UHS2 mode */
+	if (host->mmc->flags & MMC_UHS2_INITIALIZED) {
+		sdhci_uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD);
+		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+		sdhci_uhs2_clear_set_irqs(host,
+					  SDHCI_INT_ALL_MASK,
+					  SDHCI_UHS2_ERR_INT_STATUS_MASK);
+	}
+}
+
+static void sdhci_gl9755_reset(struct sdhci_host *host, u8 mask)
+{
+	ktime_t timeout;
+	u16 ctrl2;
+	u16 clk_ctrl;
+
+	/* need internal clock */
+	if (mask & SDHCI_RESET_ALL) {
+		ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+		clk_ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+
+		if ((ctrl2 & SDHCI_CTRL_V4_MODE) &&
+		    (ctrl2 & SDHCI_CTRL_UHS2_INTERFACE_EN)) {
+			sdhci_writew(host,
+				     SDHCI_CLOCK_INT_EN,
+				     SDHCI_CLOCK_CONTROL);
+		} else {
+			sdhci_writew(host,
+				     SDHCI_CLOCK_INT_EN,
+				     SDHCI_CLOCK_CONTROL);
+			sdhci_wait_clock_stable(host);
+			sdhci_writew(host,
+				     SDHCI_CTRL_V4_MODE,
+				     SDHCI_HOST_CONTROL2);
+		}
+	}
+
+	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
+
+	/* reset sd-tran on UHS2 mode if need to reset cmd/data */
+	if ((mask & SDHCI_RESET_CMD) | (mask & SDHCI_RESET_DATA))
+		gl9755_uhs2_reset_sd_tran(host);
+
+	if (mask & SDHCI_RESET_ALL)
+		host->clock = 0;
+
+	/* Wait max 100 ms */
+	timeout = ktime_add_ms(ktime_get(), 100);
+
+	/* hw clears the bit when it's done */
+	while (1) {
+		bool timedout = ktime_after(ktime_get(), timeout);
+
+		if (!(sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask))
+			break;
+		if (timedout) {
+			pr_err("%s: Reset 0x%x never completed.\n",
+			       mmc_hostname(host->mmc), (int)mask);
+			sdhci_dumpregs(host);
+			/* manual clear */
+			sdhci_writeb(host, 0, SDHCI_SOFTWARE_RESET);
+			return;
+		}
+		udelay(10);
+	}
+}
+
 static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
 {
 	struct sdhci_host *host = slot->host;
@@ -712,6 +1010,7 @@ static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
 	gli_pcie_enable_msi(slot);
 	slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
 	sdhci_enable_v4_mode(host);
+	gl9755_vendor_init(host);
 
 	return 0;
 }
@@ -1092,18 +1391,26 @@ static const struct sdhci_ops sdhci_gl9755_ops = {
 	.read_w			= sdhci_gli_readw,
 	.read_b			= sdhci_gli_readb,
 	.set_clock		= sdhci_gl9755_set_clock,
+	.set_power		= gl9755_set_power,
 	.enable_dma		= sdhci_pci_enable_dma,
 	.set_bus_width		= sdhci_set_bus_width,
-	.reset			= sdhci_reset,
+	.reset			= sdhci_gl9755_reset,
 	.set_uhs_signaling	= sdhci_set_uhs_signaling,
 	.voltage_switch		= sdhci_gli_voltage_switch,
 	.uhs2_reset		= sdhci_uhs2_reset,
+	.dump_uhs2_regs		= sdhci_uhs2_dump_regs,
+	.set_timeout		= sdhci_uhs2_set_timeout,
+	.irq			= sdhci_uhs2_irq,
+	.uhs2_pre_detect_init   = gl9755_pre_detect_init,
+	.uhs2_post_attach_sd    = gl9755_post_attach_sd,
 };
 
 const struct sdhci_pci_fixes sdhci_gl9755 = {
 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
 	.quirks2	= SDHCI_QUIRK2_BROKEN_DDR50,
 	.probe_slot	= gli_probe_slot_gl9755,
+	.add_host	= sdhci_pci_uhs2_add_host,
+	.remove_host	= sdhci_pci_uhs2_remove_host,
 	.ops            = &sdhci_gl9755_ops,
 #ifdef CONFIG_PM_SLEEP
 	.resume         = sdhci_pci_gli_resume,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 00/26] Add support UHS-II for GL9755
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (25 preceding siblings ...)
  2022-10-19 11:06 ` [PATCH V5 26/26] mmc: sdhci-pci-gli: enable UHS-II mode for GL9755 Victor Shih
@ 2022-10-19 11:29 ` Ulf Hansson
  2022-11-01  2:24   ` Victor Shih
  2022-11-01 17:28 ` Adrian Hunter
  27 siblings, 1 reply; 72+ messages in thread
From: Ulf Hansson @ 2022-10-19 11:29 UTC (permalink / raw)
  To: Victor Shih
  Cc: adrian.hunter, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih

On Wed, 19 Oct 2022 at 13:06, Victor Shih <victorshihgli@gmail.com> wrote:
>
> Summary
> =======
> These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
>
> About UHS-II, roughly deal with the following three parts:
> 1) A UHS-II detection and initialization:
> - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
>   [2]).
> - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
>   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
>   Setup Sequence.
>
> 2) Send Legacy SD command through SD-TRAN
> - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
>   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
>   Types and Format Overview[3]).
> - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
>   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
>
> 3) UHS-II Interrupt
> - Except for UHS-II error interrupts, most interrupts share the original
>   interrupt registers.
>
> Patch structure
> ===============
> patch#1-#6:  for core
> patch#7-#25: for sdhci
> patch#26:    for GL9755
>
> Changes in v5 (Oct. 19, 2022)
> * rebased to the linux-kernel-v6.1-rc1 in Ulf Hansson next branch.

Thanks for rebasing!

Although, future wise, if you make any kind of changes to any patch in
the series, please bump the version and explain what has been changed.
This avoids confusion.

I need some more time to have a closer look at the series, so I will
get back to you again.

Kind regards
Uffe


> * according to the guidance and overall architecture provided
>   by Ulf Hansson, Ben Chuang and Jason Lai to implement the
>   UHS-2 Core function based on the patches of the [V4,0/6]
>   Preparations to support SD UHS-II cards[5].
> * according to the guidance and comments provided by
>   Adrian Hunter, Ben Chuang and AKASHI Takahiro to implement
>   the UHS-2 Host function based on the patches of the
>   [RFC,v3.1,00/27] Add support UHS-II for GL9755[4].
> * implement the necessary function to let the UHS-2 Core/Host
>   work properly.
> * fix most of checkpatch warnings/errors
>
> Reference
> =========
> [1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
> [2] SD Host Controller Simplified Specification 4.20
> [3] UHS-II Simplified Addendum 1.02
> [4] https://patchwork.kernel.org/project/linux-mmc/cover/20201106022726.19831-1-takahiro.akashi@linaro.org/
> [5] https://patchwork.kernel.org/project/linux-mmc/cover/20220418115833.10738-1-jasonlai.genesyslogic@gmail.com/
>
> ----------------- original cover letter from v3.1 -----------------
> This is an interim snapshot of our next version, v4, for enabling
> UHS-II on MMC/SD.
>
> It is focused on 'sdhci' side to address Adrian's comments regarding
> "modularising" sdhci-uhs2.c.
> The whole aim of this version is to get early feedback from Adrian (and
> others) on this issue. Without any consensus about the code structure,
> it would make little sense to go further ahead on sdhci side.
> (Actually, Adrian has made no comments other than "modularising" so far.)
>
> I heavily reworked/refactored sdhci-uhs2.c and re-organised the patch
> set to meet what I believe Adrian expects; no UHS-II related code in
> Legacy (UHS-I) code or sdhci.c.
>
> Nevertheless, almost of all changes I made are trivial and straightforward
> in this direction, and I believe that there is no logic changed since v3
> except sdhci_uhs2_irq(), as ops->irq hook, where we must deal with UHS-II
> command sequences in addition to UHS-II errors. So I added extra handlings.
>
> I admit that there is plenty of room for improvements (for example,
> handling host->flags), but again the focal point here is how sdhci-uhs2.c
> should be built as a module.
>
> Please review this series (particularly Patch#8-#26 and #27) from this
> viewpoint in the first place.
> (Ben is working on 'host' side but there is no change on 'host' side
> in this submission except a minor tweak.)
>
> Thanks,
> -Takahiro Akashi
>
> ------ original cover letter from v3 ------
> Summary
> =======
> These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
>
> About UHS-II, roughly deal with the following three parts:
> 1) A UHS-II detection and initialization:
> - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
>   [2]).
> - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
>   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
>   Setup Sequence.
>
> 2) Send Legacy SD command through SD-TRAN
> - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
>   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
>   Types and Format Overview[3]).
> - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
>   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
>
> 3) UHS-II Interrupt
> - Except for UHS-II error interrupts, most interrupts share the original
>   interrupt registers.
>
> Patch structure
> ===============
> patch#1-#7: for core
> patch#8-#17: for sdhci
> patch#18-#21: for GL9755
>
> Tests
> =====
> Ran 'dd' command to evaluate the performance:
> (SanDisk UHS-II card on GL9755 controller)
>                              Read    Write
> UHS-II disabled (UHS-I): 88.3MB/s 60.7MB/s
> UHS-II enabled         :  206MB/s   80MB/s
>
> TODO
> ====
> - replace some define with BIT macro
>
> Reference
> =========
> [1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
> [2] SD Host Controller Simplified Specification 4.20
> [3] UHS-II Simplified Addendum 1.02
>
> Changes in v3 (Jul. 10, 2020)
> * rebased to v5.8-rc4
> * add copyright notice
> * reorganize the patch set and split some commits into smaller ones
> * separate uhs-2 headers from others
> * correct wrong spellings
> * fix most of checkpatch warnings/errors
> * remove all k[cz]alloc() from the code
> * guard sdhci-uhs2 specific code with
>       'if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))'
> * make sdhci-uhs2.c as a module
> * trivial changes, including
>   - rename back sdhci-core.c to sdhci.c
>   - allow vendor code to disable uhs2 if v4_mode == 0
>       in __sdhci_add_host()
>   - merge uhs2_power_up() into mmc_power_up()
>   - remove flag_uhs2 from mmc_attach_sd()
>   - add function descriptions to EXPORT'ed functions
>   - other minor code optimization
>
> Changes in v2 (Jan. 9, 2020)
> * rebased to v5.5-rc5
>
> AKASHI Takahiro (5):
>   mmc: sdhci: add a kernel configuration for enabling UHS-II support
>   mmc: sdhci: add UHS-II module
>   mmc: sdhci-uhs2: dump UHS-II registers
>   mmc: sdhci-uhs2: add set_timeout()
>   mmc: sdhci-pci: add UHS-II support framework
>
> Ben Chuang (1):
>   mmc: sdhci-uhs2: add post-mmc_attach_sd hook
>
> Ulf Hansson (4):
>   mmc: core: Cleanup printing of speed mode at card insertion
>   mmc: core: Prepare to support SD UHS-II cards
>   mmc: core: Announce successful insertion of an SD UHS-II card
>   mmc: core: Extend support for mmc regulators with a vqmmc2
>
> Victor Shih (16):
>   mmc: core: Add definitions for SD UHS-II cards
>   mmc: core: Support UHS-II card control and access
>   mmc: sdhci: add UHS-II related definitions in headers
>   mmc: sdhci-uhs2: add reset function and uhs2_mode function
>   mmc: sdhci-uhs2: add set_power() to support vdd2
>   mmc: sdhci-uhs2: skip signal_voltage_switch()
>   mmc: sdhci-uhs2: add set_ios()
>   mmc: sdhci-uhs2: add detect_init() to detect the interface
>   mmc: sdhci-uhs2: add clock operations
>   mmc: sdhci-uhs2: add uhs2_control() to initialise the interface
>   mmc: sdhci-uhs2: add request() and others
>   mmc: sdhci-uhs2: add irq() and others
>   mmc: sdhci-uhs2: add add_host() and others to set up the driver
>   mmc: sdhci-uhs2: add pre-detect_init hook
>   mmc: core: add post-mmc_attach_sd hook
>   mmc: sdhci-pci-gli: enable UHS-II mode for GL9755
>
>  drivers/mmc/core/Makefile         |    2 +-
>  drivers/mmc/core/block.c          |    6 +-
>  drivers/mmc/core/bus.c            |   38 +-
>  drivers/mmc/core/core.c           |   49 +-
>  drivers/mmc/core/core.h           |    1 +
>  drivers/mmc/core/host.h           |    4 +
>  drivers/mmc/core/mmc_ops.c        |   25 +-
>  drivers/mmc/core/mmc_ops.h        |    1 +
>  drivers/mmc/core/regulator.c      |   34 +
>  drivers/mmc/core/sd.c             |   16 +-
>  drivers/mmc/core/sd.h             |    3 +
>  drivers/mmc/core/sd_ops.c         |   18 +
>  drivers/mmc/core/sd_ops.h         |    3 +
>  drivers/mmc/core/sd_uhs2.c        | 1394 +++++++++++++++++++++++++
>  drivers/mmc/host/Kconfig          |   10 +
>  drivers/mmc/host/Makefile         |    1 +
>  drivers/mmc/host/sdhci-pci-core.c |   17 +-
>  drivers/mmc/host/sdhci-pci-gli.c  |  310 +++++-
>  drivers/mmc/host/sdhci-pci.h      |    3 +
>  drivers/mmc/host/sdhci-uhs2.c     | 1606 +++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-uhs2.h     |  226 ++++
>  drivers/mmc/host/sdhci.c          |  342 +++---
>  drivers/mmc/host/sdhci.h          |  125 ++-
>  include/linux/mmc/card.h          |   47 +
>  include/linux/mmc/core.h          |   13 +
>  include/linux/mmc/host.h          |   99 ++
>  include/linux/mmc/sd_uhs2.h       |  263 +++++
>  27 files changed, 4486 insertions(+), 170 deletions(-)
>  create mode 100644 drivers/mmc/core/sd_uhs2.c
>  create mode 100644 drivers/mmc/host/sdhci-uhs2.c
>  create mode 100644 drivers/mmc/host/sdhci-uhs2.h
>  create mode 100644 include/linux/mmc/sd_uhs2.h
>
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 00/26] Add support UHS-II for GL9755
  2022-10-19 11:29 ` [PATCH V5 00/26] Add support UHS-II " Ulf Hansson
@ 2022-11-01  2:24   ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-11-01  2:24 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: adrian.hunter, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih

Hi, Ulf

Ulf Hansson <ulf.hansson@linaro.org> 於 2022年10月19日 週三 晚上7:30寫道:
>
> On Wed, 19 Oct 2022 at 13:06, Victor Shih <victorshihgli@gmail.com> wrote:
> >
> > Summary
> > =======
> > These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
> >
> > About UHS-II, roughly deal with the following three parts:
> > 1) A UHS-II detection and initialization:
> > - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
> >   [2]).
> > - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> > - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
> >   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
> >   Setup Sequence.
> >
> > 2) Send Legacy SD command through SD-TRAN
> > - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
> >   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
> >   Types and Format Overview[3]).
> > - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
> >   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
> >
> > 3) UHS-II Interrupt
> > - Except for UHS-II error interrupts, most interrupts share the original
> >   interrupt registers.
> >
> > Patch structure
> > ===============
> > patch#1-#6:  for core
> > patch#7-#25: for sdhci
> > patch#26:    for GL9755
> >
> > Changes in v5 (Oct. 19, 2022)
> > * rebased to the linux-kernel-v6.1-rc1 in Ulf Hansson next branch.
>
> Thanks for rebasing!
>
> Although, future wise, if you make any kind of changes to any patch in
> the series, please bump the version and explain what has been changed.
> This avoids confusion.
>
> I need some more time to have a closer look at the series, so I will
> get back to you again.
>
> Kind regards
> Uffe
>

I will follow your advice. When I make any kind of changes to any patch in
 the series, I will update the version and explain it.

I have a small hope that if you already have a closer look a paragraph at
 the series, could you let me know your comments first, let me check it first.

Thanks, Victor Shih

>
> > * according to the guidance and overall architecture provided
> >   by Ulf Hansson, Ben Chuang and Jason Lai to implement the
> >   UHS-2 Core function based on the patches of the [V4,0/6]
> >   Preparations to support SD UHS-II cards[5].
> > * according to the guidance and comments provided by
> >   Adrian Hunter, Ben Chuang and AKASHI Takahiro to implement
> >   the UHS-2 Host function based on the patches of the
> >   [RFC,v3.1,00/27] Add support UHS-II for GL9755[4].
> > * implement the necessary function to let the UHS-2 Core/Host
> >   work properly.
> > * fix most of checkpatch warnings/errors
> >
> > Reference
> > =========
> > [1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
> > [2] SD Host Controller Simplified Specification 4.20
> > [3] UHS-II Simplified Addendum 1.02
> > [4] https://patchwork.kernel.org/project/linux-mmc/cover/20201106022726.19831-1-takahiro.akashi@linaro.org/
> > [5] https://patchwork.kernel.org/project/linux-mmc/cover/20220418115833.10738-1-jasonlai.genesyslogic@gmail.com/
> >
> > ----------------- original cover letter from v3.1 -----------------
> > This is an interim snapshot of our next version, v4, for enabling
> > UHS-II on MMC/SD.
> >
> > It is focused on 'sdhci' side to address Adrian's comments regarding
> > "modularising" sdhci-uhs2.c.
> > The whole aim of this version is to get early feedback from Adrian (and
> > others) on this issue. Without any consensus about the code structure,
> > it would make little sense to go further ahead on sdhci side.
> > (Actually, Adrian has made no comments other than "modularising" so far.)
> >
> > I heavily reworked/refactored sdhci-uhs2.c and re-organised the patch
> > set to meet what I believe Adrian expects; no UHS-II related code in
> > Legacy (UHS-I) code or sdhci.c.
> >
> > Nevertheless, almost of all changes I made are trivial and straightforward
> > in this direction, and I believe that there is no logic changed since v3
> > except sdhci_uhs2_irq(), as ops->irq hook, where we must deal with UHS-II
> > command sequences in addition to UHS-II errors. So I added extra handlings.
> >
> > I admit that there is plenty of room for improvements (for example,
> > handling host->flags), but again the focal point here is how sdhci-uhs2.c
> > should be built as a module.
> >
> > Please review this series (particularly Patch#8-#26 and #27) from this
> > viewpoint in the first place.
> > (Ben is working on 'host' side but there is no change on 'host' side
> > in this submission except a minor tweak.)
> >
> > Thanks,
> > -Takahiro Akashi
> >
> > ------ original cover letter from v3 ------
> > Summary
> > =======
> > These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
> >
> > About UHS-II, roughly deal with the following three parts:
> > 1) A UHS-II detection and initialization:
> > - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
> >   [2]).
> > - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> > - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
> >   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
> >   Setup Sequence.
> >
> > 2) Send Legacy SD command through SD-TRAN
> > - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
> >   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
> >   Types and Format Overview[3]).
> > - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
> >   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
> >
> > 3) UHS-II Interrupt
> > - Except for UHS-II error interrupts, most interrupts share the original
> >   interrupt registers.
> >
> > Patch structure
> > ===============
> > patch#1-#7: for core
> > patch#8-#17: for sdhci
> > patch#18-#21: for GL9755
> >
> > Tests
> > =====
> > Ran 'dd' command to evaluate the performance:
> > (SanDisk UHS-II card on GL9755 controller)
> >                              Read    Write
> > UHS-II disabled (UHS-I): 88.3MB/s 60.7MB/s
> > UHS-II enabled         :  206MB/s   80MB/s
> >
> > TODO
> > ====
> > - replace some define with BIT macro
> >
> > Reference
> > =========
> > [1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
> > [2] SD Host Controller Simplified Specification 4.20
> > [3] UHS-II Simplified Addendum 1.02
> >
> > Changes in v3 (Jul. 10, 2020)
> > * rebased to v5.8-rc4
> > * add copyright notice
> > * reorganize the patch set and split some commits into smaller ones
> > * separate uhs-2 headers from others
> > * correct wrong spellings
> > * fix most of checkpatch warnings/errors
> > * remove all k[cz]alloc() from the code
> > * guard sdhci-uhs2 specific code with
> >       'if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))'
> > * make sdhci-uhs2.c as a module
> > * trivial changes, including
> >   - rename back sdhci-core.c to sdhci.c
> >   - allow vendor code to disable uhs2 if v4_mode == 0
> >       in __sdhci_add_host()
> >   - merge uhs2_power_up() into mmc_power_up()
> >   - remove flag_uhs2 from mmc_attach_sd()
> >   - add function descriptions to EXPORT'ed functions
> >   - other minor code optimization
> >
> > Changes in v2 (Jan. 9, 2020)
> > * rebased to v5.5-rc5
> >
> > AKASHI Takahiro (5):
> >   mmc: sdhci: add a kernel configuration for enabling UHS-II support
> >   mmc: sdhci: add UHS-II module
> >   mmc: sdhci-uhs2: dump UHS-II registers
> >   mmc: sdhci-uhs2: add set_timeout()
> >   mmc: sdhci-pci: add UHS-II support framework
> >
> > Ben Chuang (1):
> >   mmc: sdhci-uhs2: add post-mmc_attach_sd hook
> >
> > Ulf Hansson (4):
> >   mmc: core: Cleanup printing of speed mode at card insertion
> >   mmc: core: Prepare to support SD UHS-II cards
> >   mmc: core: Announce successful insertion of an SD UHS-II card
> >   mmc: core: Extend support for mmc regulators with a vqmmc2
> >
> > Victor Shih (16):
> >   mmc: core: Add definitions for SD UHS-II cards
> >   mmc: core: Support UHS-II card control and access
> >   mmc: sdhci: add UHS-II related definitions in headers
> >   mmc: sdhci-uhs2: add reset function and uhs2_mode function
> >   mmc: sdhci-uhs2: add set_power() to support vdd2
> >   mmc: sdhci-uhs2: skip signal_voltage_switch()
> >   mmc: sdhci-uhs2: add set_ios()
> >   mmc: sdhci-uhs2: add detect_init() to detect the interface
> >   mmc: sdhci-uhs2: add clock operations
> >   mmc: sdhci-uhs2: add uhs2_control() to initialise the interface
> >   mmc: sdhci-uhs2: add request() and others
> >   mmc: sdhci-uhs2: add irq() and others
> >   mmc: sdhci-uhs2: add add_host() and others to set up the driver
> >   mmc: sdhci-uhs2: add pre-detect_init hook
> >   mmc: core: add post-mmc_attach_sd hook
> >   mmc: sdhci-pci-gli: enable UHS-II mode for GL9755
> >
> >  drivers/mmc/core/Makefile         |    2 +-
> >  drivers/mmc/core/block.c          |    6 +-
> >  drivers/mmc/core/bus.c            |   38 +-
> >  drivers/mmc/core/core.c           |   49 +-
> >  drivers/mmc/core/core.h           |    1 +
> >  drivers/mmc/core/host.h           |    4 +
> >  drivers/mmc/core/mmc_ops.c        |   25 +-
> >  drivers/mmc/core/mmc_ops.h        |    1 +
> >  drivers/mmc/core/regulator.c      |   34 +
> >  drivers/mmc/core/sd.c             |   16 +-
> >  drivers/mmc/core/sd.h             |    3 +
> >  drivers/mmc/core/sd_ops.c         |   18 +
> >  drivers/mmc/core/sd_ops.h         |    3 +
> >  drivers/mmc/core/sd_uhs2.c        | 1394 +++++++++++++++++++++++++
> >  drivers/mmc/host/Kconfig          |   10 +
> >  drivers/mmc/host/Makefile         |    1 +
> >  drivers/mmc/host/sdhci-pci-core.c |   17 +-
> >  drivers/mmc/host/sdhci-pci-gli.c  |  310 +++++-
> >  drivers/mmc/host/sdhci-pci.h      |    3 +
> >  drivers/mmc/host/sdhci-uhs2.c     | 1606 +++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci-uhs2.h     |  226 ++++
> >  drivers/mmc/host/sdhci.c          |  342 +++---
> >  drivers/mmc/host/sdhci.h          |  125 ++-
> >  include/linux/mmc/card.h          |   47 +
> >  include/linux/mmc/core.h          |   13 +
> >  include/linux/mmc/host.h          |   99 ++
> >  include/linux/mmc/sd_uhs2.h       |  263 +++++
> >  27 files changed, 4486 insertions(+), 170 deletions(-)
> >  create mode 100644 drivers/mmc/core/sd_uhs2.c
> >  create mode 100644 drivers/mmc/host/sdhci-uhs2.c
> >  create mode 100644 drivers/mmc/host/sdhci-uhs2.h
> >  create mode 100644 include/linux/mmc/sd_uhs2.h
> >
> > --
> > 2.25.1
> >

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards
  2022-10-19 11:06 ` [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards Victor Shih
@ 2022-11-01 17:12   ` Adrian Hunter
  2022-11-16 11:06     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:12 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Jason Lai

On 19/10/22 14:06, Victor Shih wrote:
> Add UHS-II specific data structures for commands and defines for
> registers, as described in Part 1 UHS-II Addendum Version 1.01.
> 
> UHS-II related definitions are listed below:
>   1. UHS-II card capability: sd_uhs2_caps{}
>   2. UHS-II configuration: sd_uhs2_config{}
>   3. UHS-II Command structure: uhs2_command{}
>   4. UHS-II register I/O address and register field definitions: sd_uhs2.h
> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
> 
> Updates in V5:
>  - Added UHS2 interfaces in mmc_host_ops: host.h
>  - Added UHS2 VDD2 power supply in mmc_supply: host.h
>  - Added UHS2-specific OCR and UHS2 VDD2 max current in mmc_host: host.h
>  - Added definition of UHS2 VDD2 1.65v-1.95v in mmc_host: host.h
>  - Added flags/MMC_UHS2_SUPPORT/MMC_UHS2_2L_HD in mmc_host: host.h
> ---
>  include/linux/mmc/card.h    |  42 +++++-
>  include/linux/mmc/core.h    |  13 ++
>  include/linux/mmc/host.h    |  70 +++++++++-
>  include/linux/mmc/sd_uhs2.h | 263 ++++++++++++++++++++++++++++++++++++
>  4 files changed, 386 insertions(+), 2 deletions(-)
>  create mode 100644 include/linux/mmc/sd_uhs2.h
> 
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 4a42f31b7bb0..d638a2c689cf 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -190,6 +190,13 @@ struct sd_switch_caps {
>  #define SD_MAX_CURRENT_400	(1 << SD_SET_CURRENT_LIMIT_400)
>  #define SD_MAX_CURRENT_600	(1 << SD_SET_CURRENT_LIMIT_600)
>  #define SD_MAX_CURRENT_800	(1 << SD_SET_CURRENT_LIMIT_800)
> +	unsigned int		sd4_curr_limit;
> +#define SD4_SET_POWER_LIMIT_0_72W	0
> +#define SD4_SET_POWER_LIMIT_1_44W	1
> +#define SD4_SET_POWER_LIMIT_2_16W	2
> +#define SD4_SET_POWER_LIMIT_2_88W	3
> +#define SD4_SET_POWER_LIMIT_1_80W	4
> +#define SD4_SET_POWER_NO_CHANGE		(-1)
>  };
>  
>  struct sd_ext_reg {
> @@ -213,7 +220,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 {
> @@ -323,6 +358,9 @@ struct mmc_card {
>  	struct sd_ext_reg	ext_perf;	/* SD extension reg for PERF */
>  
>  	struct sd_uhs2_config	uhs2_config;	/* SD UHS-II config */
> +	u8			uhs2_state;	/* SD UHS-II states */
> +#define MMC_UHS2_INITIALIZED	BIT(1)
> +#define MMC_UHS2_SPEED_B	BIT(2)
>  
>  	unsigned int		sdio_funcs;	/* number of SDIO functions */
>  	atomic_t		sdio_funcs_probed; /* number of probed SDIO funcs */
> @@ -364,4 +402,6 @@ bool mmc_card_is_blockaddr(struct mmc_card *card);
>  #define mmc_card_sdio(c)	((c)->type == MMC_TYPE_SDIO)
>  #define mmc_card_sd_combo(c)	((c)->type == MMC_TYPE_SD_COMBO)
>  
> +#define mmc_card_can_poweroff_notify(c)	((c)->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY)
> +
>  #endif /* LINUX_MMC_CARD_H */
> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> index 6efec0b9820c..2a0581d87706 100644
> --- a/include/linux/mmc/core.h
> +++ b/include/linux/mmc/core.h
> @@ -23,6 +23,14 @@ enum mmc_blk_status {
>  	MMC_BLK_NEW_REQUEST,
>  };
>  
> +struct uhs2_command {
> +	u16	header;
> +	u16	arg;
> +	__be32	*payload;
> +	u32	payload_len;
> +	u32	packet_len;
> +};
> +
>  struct mmc_command {
>  	u32			opcode;
>  	u32			arg;
> @@ -109,6 +117,11 @@ struct mmc_command {
>  	unsigned int		busy_timeout;	/* busy detect timeout in ms */
>  	struct mmc_data		*data;		/* data segment associated with cmd */
>  	struct mmc_request	*mrq;		/* associated request */
> +
> +	struct uhs2_command	*uhs2_cmd;	/* UHS2 command */
> +	u8			*uhs2_resp;	/* UHS2 native cmd resp */
> +	u8			uhs2_resp_len;	/* UHS2 native cmd resp len */
> +	u8			uhs2_tmode0_flag; /* UHS2 transfer mode flag */
>  };
>  
>  struct mmc_data {
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 895bcf7f80b7..249a9414ad10 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -16,6 +16,7 @@
>  #include <linux/mmc/pm.h>
>  #include <linux/dma-direction.h>
>  #include <linux/blk-crypto-profile.h>
> +#include <linux/mmc/sd_uhs2.h>
>  
>  struct mmc_ios {
>  	unsigned int	clock;			/* clock rate */
> @@ -96,7 +97,48 @@ struct mmc_clk_phase_map {
>  };
>  
>  struct sd_uhs2_caps {
> -	/* TODO: Add UHS-II capabilities for the host. */
> +	u32	dap;
> +	u32	gap;
> +	u32	group_desc;
> +	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 sd_uhs2_ios {
> +	bool		is_2L_HD_mode;
> +	bool		is_APP_CMD;
> +	unsigned int	power_delay_ms;		/* waiting for stable power */
> +};
> +
> +enum sd_uhs2_operation {
> +	UHS2_PHY_INIT = 0,
> +	UHS2_SET_CONFIG,
> +	UHS2_ENABLE_INT,
> +	UHS2_DISABLE_INT,
> +	UHS2_ENABLE_CLK,
> +	UHS2_DISABLE_CLK,
> +	UHS2_CHECK_DORMANT,
> +	UHS2_SET_SPEED_B,
> +	UHS2_POST_ATTACH_SD,
>  };
>  
>  struct mmc_host;
> @@ -231,6 +273,20 @@ 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 */
> +	int	(*uhs2_detect_init)(struct mmc_host *host);

Never called?

> +	int	(*uhs2_set_reg)(struct mmc_host *host, enum sd_uhs2_operation act);

Never called?

> +	int (*uhs2_disable_clk)(struct mmc_host *host);

Never called?

> +	int (*uhs2_enable_clk)(struct mmc_host *host);

Never called?

> +
> +	/*
> +	 * The uhs2_control callback is used to execute SD UHS-II specific
> +	 * operations. It's mandatory to implement for hosts that supports the
> +	 * SD UHS-II interface (MMC_CAP2_SD_UHS2). Expected return values are a
> +	 * negative errno in case of a failure or zero for success.
> +	 */
> +	int	(*uhs2_control)(struct mmc_host *host, enum sd_uhs2_operation op);
>  };
>  
>  struct mmc_cqe_ops {
> @@ -323,6 +379,7 @@ struct mmc_pwrseq;
>  
>  struct mmc_supply {
>  	struct regulator *vmmc;		/* Card power supply */
> +	struct regulator *vmmc2;	/* UHS2 VDD2 power supply */
>  	struct regulator *vqmmc;	/* Optional Vccq supply */
>  	struct regulator *vqmmc2;	/* Optional supply for phy */
>  };
> @@ -344,10 +401,12 @@ struct mmc_host {
>  	u32			ocr_avail_sdio;	/* SDIO-specific OCR */
>  	u32			ocr_avail_sd;	/* SD-specific OCR */
>  	u32			ocr_avail_mmc;	/* MMC-specific OCR */
> +	u32			ocr_avail_uhs2; /* UHS2-specific OCR */
>  	struct wakeup_source	*ws;		/* Enable consume of uevents */
>  	u32			max_current_330;
>  	u32			max_current_300;
>  	u32			max_current_180;
> +	u32			max_current_180_vdd2; /* UHS2 vdd2 max curt. */
>  
>  #define MMC_VDD_165_195		0x00000080	/* VDD voltage 1.65 - 1.95 */
>  #define MMC_VDD_20_21		0x00000100	/* VDD voltage 2.0 ~ 2.1 */
> @@ -366,6 +425,7 @@ struct mmc_host {
>  #define MMC_VDD_33_34		0x00200000	/* VDD voltage 3.3 ~ 3.4 */
>  #define MMC_VDD_34_35		0x00400000	/* VDD voltage 3.4 ~ 3.5 */
>  #define MMC_VDD_35_36		0x00800000	/* VDD voltage 3.5 ~ 3.6 */
> +#define MMC_VDD2_165_195	0x00000080	/* UHS2 VDD2 1.65 ~ 1.95 */
>  
>  	u32			caps;		/* Host capabilities */
>  
> @@ -443,7 +503,12 @@ struct mmc_host {
>  #endif
>  #define MMC_CAP2_ALT_GPT_TEGRA	(1 << 28)	/* Host with eMMC that has GPT entry at a non-standard location */
>  
> +	int flags;
> +#define MMC_UHS2_SUPPORT	(1 << 0)

MMC_UHS2_SUPPORT is getting mixed up with MMC_UHS2_INITIALIZED.
Both have the same value, but MMC_UHS2_SUPPORT is for
host->flags and MMC_UHS2_INITIALIZED is for card->uhs2_state

Please use the correct flag with the correct variable.

> +#define MMC_UHS2_2L_HD		(1 << 2)

MMC_UHS2_2L_HD does not seem to be used. Is it needed?

> +
>  	struct sd_uhs2_caps	uhs2_caps;	/* Host UHS-II capabilities */
> +	struct sd_uhs2_ios	uhs2_ios;	/* Host UHS-II capabilities */
>  
>  	int			fixed_drv_type;	/* fixed driver type for non-removable media */
>  
> @@ -695,4 +760,7 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
>  int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
>  int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
>  
> +#define mmc_uhs2_2L_HD_mode(h)	((h)->uhs2_ios.is_2L_HD_mode)
> +#define mmc_uhs2_APP_cmd(h)	((h)->uhs2_ios.is_APP_CMD)
> +
>  #endif /* LINUX_MMC_HOST_H */
> diff --git a/include/linux/mmc/sd_uhs2.h b/include/linux/mmc/sd_uhs2.h
> new file mode 100644
> index 000000000000..8fcf702cf4a5
> --- /dev/null
> +++ b/include/linux/mmc/sd_uhs2.h
> @@ -0,0 +1,263 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Header file for UHS-II packets, Host Controller registers and I/O
> + * accessors.
> + *
> + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> + */
> +#ifndef LINUX_MMC_UHS2_H
> +#define LINUX_MMC_UHS2_H
> +
> +/* LINK Layer definition */
> +/*
> + * UHS2 Header:
> + * Refer to UHS-II Addendum Version 1.02 Figure 5-2, the format of CCMD Header is described below:
> + *      bit [3:0]  : DID(Destination ID = Node ID of UHS2 card)
> + *      bit [6:4]  : TYP(Packet Type)
> + *                   000b: CCMD(Control command packet)
> + *                   001b: DCMD(Data command packet)
> + *                   010b: RES(Response packet)
> + *                   011b: DATA(Data payload packet)
> + *                   111b: MSG(Message packet)
> + *                   Others: Reserved
> + *      bit [7]    : NP(Native Packet)
> + *      bit [10:8] : TID(Transaction ID)
> + *      bit [11]   : Reserved
> + *      bit [15:12]: SID(Source ID 0: Node ID of Host)
> + *
> + * Broadcast CCMD issued by Host is represented as DID=SID=0.
> + */
> +/*
> + * UHS2 Argument:
> + * Refer to UHS-II Addendum Version 1.02 Figure 6-5, the format of CCMD Argument is described below:
> + *      bit [3:0]  : MSB of IOADR
> + *      bit [5:4]  : PLEN(Payload Length)
> + *                   00b: 0 byte
> + *                   01b: 4 bytes
> + *                   10b: 8 bytes
> + *                   11b: 16 bytes
> + *      bit [6]    : Reserved
> + *      bit [7]    : R/W(Read/Write)
> + *                   0: Control read command
> + *                   1: Control write command
> + *      bit [15:8] : LSB of IOADR
> + *
> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> + */
> +#define UHS2_NATIVE_PACKET_POS	7
> +#define UHS2_NATIVE_PACKET	(1 << UHS2_NATIVE_PACKET_POS)
> +
> +#define UHS2_PACKET_TYPE_POS	4
> +#define UHS2_PACKET_TYPE_CCMD	(0 << UHS2_PACKET_TYPE_POS)
> +#define UHS2_PACKET_TYPE_DCMD	(1 << UHS2_PACKET_TYPE_POS)
> +#define UHS2_PACKET_TYPE_RES	(2 << UHS2_PACKET_TYPE_POS)
> +#define UHS2_PACKET_TYPE_DATA	(3 << UHS2_PACKET_TYPE_POS)
> +#define UHS2_PACKET_TYPE_MSG	(7 << UHS2_PACKET_TYPE_POS)
> +
> +#define UHS2_DEST_ID_MASK	0x0F
> +#define UHS2_DEST_ID		0x1
> +
> +#define UHS2_SRC_ID_POS		12
> +#define UHS2_SRC_ID_MASK	0xF000
> +
> +#define UHS2_TRANS_ID_POS	8
> +#define UHS2_TRANS_ID_MASK	0x0700
> +
> +/* UHS2 MSG */
> +#define UHS2_MSG_CTG_POS	5
> +#define UHS2_MSG_CTG_LMSG	0x00
> +#define UHS2_MSG_CTG_INT	0x60
> +#define UHS2_MSG_CTG_AMSG	0x80
> +
> +#define UHS2_MSG_CTG_FCREQ	0x00
> +#define UHS2_MSG_CTG_FCRDY	0x01
> +#define UHS2_MSG_CTG_STAT	0x02
> +
> +#define UHS2_MSG_CODE_POS			8
> +#define UHS2_MSG_CODE_FC_UNRECOVER_ERR		0x8
> +#define UHS2_MSG_CODE_STAT_UNRECOVER_ERR	0x8
> +#define UHS2_MSG_CODE_STAT_RECOVER_ERR		0x1
> +
> +/* TRANS Layer definition */
> +
> +/* Native packets*/
> +#define UHS2_NATIVE_CMD_RW_POS	7
> +#define UHS2_NATIVE_CMD_WRITE	(1 << UHS2_NATIVE_CMD_RW_POS)
> +#define UHS2_NATIVE_CMD_READ	(0 << UHS2_NATIVE_CMD_RW_POS)
> +
> +#define UHS2_NATIVE_CMD_PLEN_POS	4
> +#define UHS2_NATIVE_CMD_PLEN_4B		(1 << UHS2_NATIVE_CMD_PLEN_POS)
> +#define UHS2_NATIVE_CMD_PLEN_8B		(2 << UHS2_NATIVE_CMD_PLEN_POS)
> +#define UHS2_NATIVE_CMD_PLEN_16B	(3 << UHS2_NATIVE_CMD_PLEN_POS)
> +
> +#define UHS2_NATIVE_CCMD_GET_MIOADR_MASK	0xF00
> +#define UHS2_NATIVE_CCMD_MIOADR_MASK		0x0F
> +
> +#define UHS2_NATIVE_CCMD_LIOADR_POS		8
> +#define UHS2_NATIVE_CCMD_GET_LIOADR_MASK	0x0FF
> +
> +#define UHS2_CCMD_DEV_INIT_COMPLETE_FLAG	BIT(11)
> +#define UHS2_DEV_INIT_PAYLOAD_LEN		1
> +#define UHS2_DEV_INIT_RESP_LEN			6
> +#define UHS2_DEV_ENUM_PAYLOAD_LEN		1
> +#define UHS2_DEV_ENUM_RESP_LEN			8
> +#define UHS2_CFG_WRITE_PAYLOAD_LEN		2
> +#define UHS2_CFG_WRITE_PHY_SET_RESP_LEN		4
> +#define UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN	5
> +#define UHS2_GO_DORMANT_PAYLOAD_LEN		1
> +
> +/*
> + * UHS2 Argument:
> + * Refer to UHS-II Addendum Version 1.02 Figure 6-8, the format of DCMD Argument is described below:
> + *      bit [3:0]  : Reserved
> + *      bit [6:3]  : TMODE(Transfer Mode)
> + *                   bit 3: DAM(Data Access Mode)
> + *                   bit 4: TLUM(TLEN Unit Mode)
> + *                   bit 5: LM(Length Mode)
> + *                   bit 6: DM(Duplex Mode)
> + *      bit [7]    : R/W(Read/Write)
> + *                   0: Control read command
> + *                   1: Control write command
> + *      bit [15:8] : Reserved
> + *
> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> + */
> +#define UHS2_DCMD_DM_POS		6
> +#define UHS2_DCMD_2L_HD_MODE		(1 << UHS2_DCMD_DM_POS)
> +#define UHS2_DCMD_LM_POS		5
> +#define UHS2_DCMD_LM_TLEN_EXIST		(1 << UHS2_DCMD_LM_POS)
> +#define UHS2_DCMD_TLUM_POS		4
> +#define UHS2_DCMD_TLUM_BYTE_MODE	(1 << UHS2_DCMD_TLUM_POS)
> +#define UHS2_NATIVE_DCMD_DAM_POS	3
> +#define UHS2_NATIVE_DCMD_DAM_IO		(1 << UHS2_NATIVE_DCMD_DAM_POS)
> +
> +/*
> + * Per UHS2 spec, DCMD payload should be MSB first. There may be
> + * two types of data be assembled to MSB:
> + * 1. TLEN: Input block size for single read/write and number of blocks
> + * for multiple read/write to calculate TLEN as MSB first per spec.
> + * 2. SD command argument.
> + */
> +static inline __be32 uhs2_dcmd_convert_msb(u32 input)
> +{
> +	u32 ret = 0;
> +
> +	ret = ((input & 0xFF) << 24) |
> +		(((input >> 8) & 0xFF) << 16) |
> +		(((input >> 16) & 0xFF) << 8) |
> +		((input >> 24) & 0xFF);
> +	return cpu_to_be32(ret);
> +}
> +
> +#define UHS2_RES_NACK_POS	7
> +#define UHS2_RES_NACK_MASK	(0x1 << UHS2_RES_NACK_POS)
> +
> +#define UHS2_RES_ECODE_POS	4
> +#define UHS2_RES_ECODE_MASK	0x7
> +#define UHS2_RES_ECODE_COND	1
> +#define UHS2_RES_ECODE_ARG	2
> +#define UHS2_RES_ECODE_GEN	3
> +
> +/* IOADR of device registers */
> +#define UHS2_IOADR_GENERIC_CAPS		0x00
> +#define UHS2_IOADR_PHY_CAPS		0x02
> +#define UHS2_IOADR_LINK_CAPS		0x04
> +#define UHS2_IOADR_RSV_CAPS		0x06
> +#define UHS2_IOADR_GENERIC_SETTINGS	0x08
> +#define UHS2_IOADR_PHY_SETTINGS		0x0A
> +#define UHS2_IOADR_LINK_SETTINGS	0x0C
> +#define UHS2_IOADR_PRESET		0x40
> +
> +/* SD application packets */
> +#define UHS2_SD_CMD_INDEX_POS	8
> +
> +#define UHS2_SD_CMD_APP_POS	14
> +#define UHS2_SD_CMD_APP		(1 << UHS2_SD_CMD_APP_POS)
> +
> +/* UHS-II Device Registers */
> +#define UHS2_DEV_CONFIG_REG	0x000
> +
> +/* General Caps and Settings registers */
> +#define UHS2_DEV_CONFIG_GEN_CAPS	(UHS2_DEV_CONFIG_REG + 0x000)
> +#define UHS2_DEV_CONFIG_N_LANES_POS	8
> +#define UHS2_DEV_CONFIG_N_LANES_MASK	0x3F
> +#define UHS2_DEV_CONFIG_2L_HD_FD	0x1
> +#define UHS2_DEV_CONFIG_2D1U_FD		0x2
> +#define UHS2_DEV_CONFIG_1D2U_FD		0x4
> +#define UHS2_DEV_CONFIG_2D2U_FD		0x8
> +#define UHS2_DEV_CONFIG_DADR_POS	14
> +#define UHS2_DEV_CONFIG_DADR_MASK	0x1
> +#define UHS2_DEV_CONFIG_APP_POS		16
> +#define UHS2_DEV_CONFIG_APP_MASK	0xFF
> +#define UHS2_DEV_CONFIG_APP_SD_MEM	0x1
> +
> +#define UHS2_DEV_CONFIG_GEN_SET			(UHS2_DEV_CONFIG_REG + 0x008)
> +#define UHS2_DEV_CONFIG_GEN_SET_N_LANES_POS	8
> +#define UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD	0x0
> +#define UHS2_DEV_CONFIG_GEN_SET_2D1U_FD		0x2
> +#define UHS2_DEV_CONFIG_GEN_SET_1D2U_FD		0x3
> +#define UHS2_DEV_CONFIG_GEN_SET_2D2U_FD		0x4
> +#define UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE	BIT(31)
> +
> +/* PHY Caps and Settings registers */
> +#define UHS2_DEV_CONFIG_PHY_CAPS	(UHS2_DEV_CONFIG_REG + 0x002)
> +#define UHS2_DEV_CONFIG_PHY_MINOR_MASK	0xF
> +#define UHS2_DEV_CONFIG_PHY_MAJOR_POS	4
> +#define UHS2_DEV_CONFIG_PHY_MAJOR_MASK	0x3
> +#define UHS2_DEV_CONFIG_CAN_HIBER_POS	15
> +#define UHS2_DEV_CONFIG_CAN_HIBER_MASK	0x1
> +#define UHS2_DEV_CONFIG_PHY_CAPS1	(UHS2_DEV_CONFIG_REG + 0x003)
> +#define UHS2_DEV_CONFIG_N_LSS_SYN_MASK	0xF
> +#define UHS2_DEV_CONFIG_N_LSS_DIR_POS	4
> +#define UHS2_DEV_CONFIG_N_LSS_DIR_MASK	0xF
> +
> +#define UHS2_DEV_CONFIG_PHY_SET			(UHS2_DEV_CONFIG_REG + 0x00A)
> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_POS	6
> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_A		0x0
> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_B		0x1
> +
> +/* LINK-TRAN Caps and Settings registers */
> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS		(UHS2_DEV_CONFIG_REG + 0x004)
> +#define UHS2_DEV_CONFIG_LT_MINOR_MASK		0xF
> +#define UHS2_DEV_CONFIG_LT_MAJOR_POS		4
> +#define UHS2_DEV_CONFIG_LT_MAJOR_MASK		0x3
> +#define UHS2_DEV_CONFIG_N_FCU_POS		8
> +#define UHS2_DEV_CONFIG_N_FCU_MASK		0xFF
> +#define UHS2_DEV_CONFIG_DEV_TYPE_POS		16
> +#define UHS2_DEV_CONFIG_DEV_TYPE_MASK		0x7
> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_POS		20
> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK	0xFFF
> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS1		(UHS2_DEV_CONFIG_REG + 0x005)
> +#define UHS2_DEV_CONFIG_N_DATA_GAP_MASK		0xFF
> +
> +#define UHS2_DEV_CONFIG_LINK_TRAN_SET		(UHS2_DEV_CONFIG_REG + 0x00C)
> +#define UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN	0x200
> +#define UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS	16
> +
> +/* Preset register */
> +#define UHS2_DEV_CONFIG_PRESET	(UHS2_DEV_CONFIG_REG + 0x040)
> +
> +#define UHS2_DEV_INT_REG	0x100
> +
> +#define UHS2_DEV_STATUS_REG	0x180
> +
> +#define UHS2_DEV_CMD_REG		0x200
> +#define UHS2_DEV_CMD_FULL_RESET		(UHS2_DEV_CMD_REG + 0x000)
> +#define UHS2_DEV_CMD_GO_DORMANT_STATE	(UHS2_DEV_CMD_REG + 0x001)
> +#define UHS2_DEV_CMD_DORMANT_HIBER	BIT(7)
> +#define UHS2_DEV_CMD_DEVICE_INIT	(UHS2_DEV_CMD_REG + 0x002)
> +#define UHS2_DEV_INIT_COMPLETE_FLAG	BIT(11)
> +#define UHS2_DEV_CMD_ENUMERATE		(UHS2_DEV_CMD_REG + 0x003)
> +#define UHS2_DEV_CMD_TRANS_ABORT	(UHS2_DEV_CMD_REG + 0x004)
> +
> +#define UHS2_RCLK_MAX	52000000
> +#define UHS2_RCLK_MIN	26000000
> +
> +struct sd_uhs2_wait_active_state_data {
> +	struct mmc_host *host;
> +	struct mmc_command *cmd;
> +};
> +
> +#endif /* LINUX_MMC_UHS2_H */


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 07/26] mmc: sdhci: add a kernel configuration for enabling UHS-II support
  2022-10-19 11:06 ` [PATCH V5 07/26] mmc: sdhci: add a kernel configuration for enabling UHS-II support Victor Shih
@ 2022-11-01 17:12   ` Adrian Hunter
  2022-12-13  8:45     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:12 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> From: AKASHI Takahiro <takahiro.akashi@linaro.org>
> 
> This kernel configuration, CONFIG_MMC_SDHCI_UHS2, will be used
> in the following commits to indicate UHS-II specific code in sdhci
> controllers.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

Please merge this patch with:
	[PATCH V5 09/26] mmc: sdhci: add UHS-II module

> ---
>  drivers/mmc/host/Kconfig | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index f324daadaf70..7e53cca97934 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -89,6 +89,15 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
>  
>  	  This is the case for the Nintendo Wii SDHCI.
>  
> +config MMC_SDHCI_UHS2
> +	tristate "UHS2 support on SDHCI controller"
> +	depends on MMC_SDHCI
> +	help
> +	  This option is selected by SDHCI controller drivers that want to
> +	  support UHS2-capable devices.
> +
> +	  If you have a controller with this feature, say Y or M here.
> +
>  config MMC_SDHCI_PCI
>  	tristate "SDHCI support on PCI bus"
>  	depends on MMC_SDHCI && PCI


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 08/26] mmc: sdhci: add UHS-II related definitions in headers
  2022-10-19 11:06 ` [PATCH V5 08/26] mmc: sdhci: add UHS-II related definitions in headers Victor Shih
@ 2022-11-01 17:12   ` Adrian Hunter
  2022-12-13  8:45     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:12 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> Add UHS-II related definitions in shdci.h and sdhci-uhs2.h.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---

I hope you don't mind, but some of the names seem a bit long,
or could be more like regular SDHCI equivalents.  Also
BIT() anf GENMASK() could be used more in some cases.  See
comments below.

>  drivers/mmc/host/sdhci-uhs2.h | 210 ++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci.h      |  73 +++++++++++-
>  2 files changed, 282 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/mmc/host/sdhci-uhs2.h
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> new file mode 100644
> index 000000000000..5610affebdf3
> --- /dev/null
> +++ b/drivers/mmc/host/sdhci-uhs2.h
> @@ -0,0 +1,210 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + *  linux/drivers/mmc/host/sdhci-uhs2.h - Secure Digital Host Controller
> + *  Interface driver
> + *
> + * Header file for Host Controller UHS2 related registers and I/O accessors.

I/O accessors?

> + *
> + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> + */
> +#ifndef __SDHCI_UHS2_H
> +#define __SDHCI_UHS2_H
> +
> +#include <linux/bits.h>
> +
> +/*
> + * UHS-II Controller registers
> + * 0x74 preset in sdhci.h
> + * 0x80
> + * 0x84-0xB4
> + * 0xB8-0xCF
> + * 0xE0-0xE7
> + */
> +/* UHS2 */

Rather than above, let's just have one simple comment:

/* SDHCI Category B registers : UHS2 only */

> +#define SDHCI_UHS2_BLOCK_SIZE	0x80
> +#define  SDHCI_UHS2_MAKE_BLKSZ(dma, blksz) \
> +	((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))

I would prefer to wrap only lines over 100 columns

> +
> +#define SDHCI_UHS2_BLOCK_COUNT	0x84
> +
> +#define SDHCI_UHS2_CMD_PACKET	0x88
> +#define  SDHCI_UHS2_CMD_PACK_MAX_LEN	20
> +
> +#define SDHCI_UHS2_TRANS_MODE	0x9C
> +#define  SDHCI_UHS2_TRNS_DMA		BIT(0)
> +#define  SDHCI_UHS2_TRNS_BLK_CNT_EN	BIT(1)
> +#define  SDHCI_UHS2_TRNS_DATA_TRNS_WRT	BIT(4)
> +#define  SDHCI_UHS2_TRNS_BLK_BYTE_MODE	BIT(5)
> +#define  SDHCI_UHS2_TRNS_RES_R5		BIT(6)
> +#define  SDHCI_UHS2_TRNS_RES_ERR_CHECK_EN	BIT(7)
> +#define  SDHCI_UHS2_TRNS_RES_INT_DIS	BIT(8)
> +#define  SDHCI_UHS2_TRNS_WAIT_EBSY	BIT(14)
> +#define  SDHCI_UHS2_TRNS_2L_HD		BIT(15)
> +
> +#define SDHCI_UHS2_COMMAND	0x9E

Please line up all the values.  Also some names could be
shortened.  There are suggestions in the comments below.

> +#define  SDHCI_UHS2_COMMAND_SUB_CMD	0x0004

Please use BIT() and GENMASK() macros here and elsewhere.

Also could keep the name "SDHCI_UHS2_COMMAND" for the
register but abbreviate "COMMAND" to "CMD" for the fields.
SDHCI_COMMAND register does it that way.

> +#define  SDHCI_UHS2_COMMAND_DATA	0x0020
> +#define  SDHCI_UHS2_COMMAND_TRNS_ABORT	0x0040
> +#define  SDHCI_UHS2_COMMAND_CMD12	0x0080
> +#define  SDHCI_UHS2_COMMAND_DORMANT	0x00C0
> +#define  SDHCI_UHS2_COMMAND_PACK_LEN_MASK	GENMASK(12, 8)
> +#define  SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT	8

If possible, please avoid macros for shift value.
Instead use FIELD_GET() and FIELD_PREP(), or even
__bf_shf() if FIELD_GET() and FIELD_PREP() don't
work.

> +
> +#define SDHCI_UHS2_RESPONSE	0xA0
> +#define  SDHCI_UHS2_RESPONSE_MAX_LEN	20
> +
> +#define SDHCI_UHS2_MSG_SELECT	0xB4
> +#define SDHCI_UHS2_MSG_SELECT_CURR	0x0
> +#define SDHCI_UHS2_MSG_SELECT_ONE	0x1
> +#define SDHCI_UHS2_MSG_SELECT_TWO	0x2
> +#define SDHCI_UHS2_MSG_SELECT_THREE	0x3
> +
> +#define SDHCI_UHS2_MSG		0xB8
> +
> +#define SDHCI_UHS2_DEV_INT_STATUS	0xBC
> +
> +#define SDHCI_UHS2_DEV_SELECT	0xBE
> +#define SDHCI_UHS2_DEV_SELECT_DEV_SEL_MASK	GENMASK(3, 0)

Perhaps just SDHCI_UHS2_DEV_SEL_MASK

> +#define SDHCI_UHS2_DEV_SELECT_INT_MSG_EN	BIT(7)

Perhaps just SDHCI_UHS2_DEV_SEL_INT_MSG_EN

> +
> +#define SDHCI_UHS2_DEV_INT_CODE	0xBF
> +
> +#define SDHCI_UHS2_SW_RESET	0xC0
> +#define SDHCI_UHS2_SW_RESET_FULL	0x0001
> +#define SDHCI_UHS2_SW_RESET_SD		0x0002

Please use BIT() macros

> +
> +#define SDHCI_UHS2_TIMER_CTRL	0xC2
> +#define SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT	4

Please use GENMASK()

> +
> +#define SDHCI_UHS2_ERR_INT_STATUS		0xC4
> +#define SDHCI_UHS2_ERR_INT_STATUS_EN		0xC8
> +#define SDHCI_UHS2_ERR_INT_SIG_EN		0xCC

Let's make those 3 more like regular SDHCI names i.e.

#define SDHCI_UHS2_INT_STATUS			0xC4
#define SDHCI_UHS2_INT_STATUS_ENABLE		0xC8
#define SDHCI_UHS2_INT_SIGNAL_ENABLE		0xCC

> +#define SDHCI_UHS2_ERR_INT_STATUS_HEADER	BIT(0)
> +#define SDHCI_UHS2_ERR_INT_STATUS_RES		BIT(1)
> +#define SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP	BIT(2)
> +#define SDHCI_UHS2_ERR_INT_STATUS_CRC		BIT(3)
> +#define SDHCI_UHS2_ERR_INT_STATUS_FRAME		BIT(4)
> +#define SDHCI_UHS2_ERR_INT_STATUS_TID		BIT(5)
> +#define SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER	BIT(7)
> +#define SDHCI_UHS2_ERR_INT_STATUS_EBUSY		BIT(8)
> +#define SDHCI_UHS2_ERR_INT_STATUS_ADMA		BIT(15)
> +#define SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT	BIT(16)
> +#define SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT	BIT(17)
> +#define SDHCI_UHS2_ERR_INT_STATUS_VENDOR	BIT(27)

Again, let's make the interrupt bits above more like regular SDHCI
names i.e.

#define SDHCI_UHS2_INT_HEADER_ERR	BIT(0)
#define SDHCI_UHS2_INT_RES_ERR		BIT(1)
#define SDHCI_UHS2_INT_RETRY_EXP	BIT(2)
#define SDHCI_UHS2_INT_CRC		BIT(3)
#define SDHCI_UHS2_INT_FRAME_ERR	BIT(4)
#define SDHCI_UHS2_INT_TID_ERR		BIT(5)
#define SDHCI_UHS2_INT_UNRECOVERABLE	BIT(7)
#define SDHCI_UHS2_INT_EBUSY_ERR	BIT(8)
#define SDHCI_UHS2_INT_ADMA_ERROR	BIT(15)
#define SDHCI_UHS2_INT_CMD_TIMEOUT	BIT(16)
#define SDHCI_UHS2_INT_DEADLOCK_TIMEOUT	BIT(17)
#define SDHCI_UHS2_INT_VENDOR_ERR	BIT(27)

> +#define SDHCI_UHS2_ERR_INT_STATUS_MASK	\

More like regular SDHCI name

#define SDHCI_UHS2_INT_ERROR_MASK

> +		(SDHCI_UHS2_ERR_INT_STATUS_HEADER |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_RES |		\
> +		SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_CRC |		\
> +		SDHCI_UHS2_ERR_INT_STATUS_FRAME |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_TID |		\
> +		SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_EBUSY |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_ADMA |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT)
> +#define SDHCI_UHS2_ERR_INT_STATUS_CMD_MASK	\

SDHCI_UHS2_INT_CMD_ERR_MASK

> +		(SDHCI_UHS2_ERR_INT_STATUS_HEADER |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_RES |		\
> +		SDHCI_UHS2_ERR_INT_STATUS_FRAME |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_TID |		\
> +		SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT)
> +/* CRC Error occurs during a packet receiving */
> +#define SDHCI_UHS2_ERR_INT_STATUS_DATA_MASK	\

SDHCI_UHS2_INT_DATA_ERR_MASK

> +		(SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_CRC |		\
> +		SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_EBUSY |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_ADMA |	\
> +		SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT)
> +
> +#define SDHCI_UHS2_SET_PTR	0xE0

"SET" is not clear. "SETTINGS" would be better

> +#define   SDHCI_UHS2_GEN_SET_POWER_LOW		0x0001

Please use BIT() macros

> +#define   SDHCI_UHS2_GEN_SET_N_LANES_POS	8

Please use GENMASK()

Also I would call this SDHCI_UHS2_LANES

> +#define   SDHCI_UHS2_GEN_SET_2L_FD_HD		0x0
> +#define   SDHCI_UHS2_GEN_SET_2D1U_FD		0x2
> +#define   SDHCI_UHS2_GEN_SET_1D2U_FD		0x3
> +#define   SDHCI_UHS2_GEN_SET_2D2U_FD		0x4

#define   SDHCI_UHS2_FD_OR_2L_HD		0 /* 2 lanes */
#define   SDHCI_UHS2_2D1U_FD			2 /* 3 lanes, 2 down, 1 up, full duplex */
#define   SDHCI_UHS2_1D2U_FD			3 /* 3 lanes, 1 down, 2 up, full duplex */
#define   SDHCI_UHS2_2D2U_FD			4 /* 4 lanes, 2 down, 2 up, full duplex */

> +
> +#define   SDHCI_UHS2_PHY_SET_SPEED_POS		6

Please use GENMASK()

> +#define   SDHCI_UHS2_PHY_SET_HIBER_EN		BIT(12)

HIBER -> HIBERNATE

> +#define   SDHCI_UHS2_PHY_SET_N_LSS_SYN_MASK	GENMASK(19, 16)
> +#define   SDHCI_UHS2_PHY_SET_N_LSS_SYN_POS	16
> +#define   SDHCI_UHS2_PHY_SET_N_LSS_DIR_MASK	GENMASK(23, 20)
> +#define   SDHCI_UHS2_PHY_SET_N_LSS_DIR_POS	20
> +
> +#define   SDHCI_UHS2_TRAN_SET_N_FCU_MASK	GENMASK(15, 8)
> +#define   SDHCI_UHS2_TRAN_SET_N_FCU_POS		8
> +#define   SDHCI_UHS2_TRAN_SET_RETRY_CNT_MASK	GENMASK(17, 16)
> +#define   SDHCI_UHS2_TRAN_SET_RETRY_CNT_POS	16
> +
> +#define   SDHCI_UHS2_TRAN_SET_1_N_DAT_GAP_MASK	GENMASK(7, 0)

"_SET_" in the names above is not needed

Also please do not use *_POS macros - use FEILD_GET()
and FIELD_PREP()

> +
> +#define SDHCI_UHS2_HOST_CAPS_PTR	0xE2

To make them shorter, let's change all "SDHCI_UHS2_HOST_CAPS_"
to "SDHCI_UHS2_CAP_"

Also _GEN_ is a bit meaningless in the field names, and no
_SHIFT please

> +#define  SDHCI_UHS2_HOST_CAPS_GEN_OFFSET	0
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_DAP_MASK	GENMASK(3, 0)
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_GAP_MASK	GENMASK(7, 4)
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_GAP(gap)	((gap) * 360)
> +#define SDHCI_UHS2_HOST_CAPS_GEN_GAP_SHIFT 4
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_LANE_MASK	GENMASK(13, 8)
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_LANE_SHIFT	8
> +#define    SDHCI_UHS2_HOST_CAPS_GEN_2L_HD_FD	1
> +#define    SDHCI_UHS2_HOST_CAPS_GEN_2D1U_FD	2
> +#define    SDHCI_UHS2_HOST_CAPS_GEN_1D2U_FD	4
> +#define    SDHCI_UHS2_HOST_CAPS_GEN_2D2U_FD	8
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_ADDR_64	BIT(14)
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_BOOT		BIT(15)
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_MASK	GENMASK(17, 16)
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_SHIFT	16
> +#define    SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_RMV	0
> +#define    SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_EMB	1
> +#define    SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_EMB_RMV	2
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_NUM_DEV_MASK		GENMASK(21, 18)
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_NUM_DEV_SHIFT	18
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_MASK	GENMASK(23, 22)
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_SHIFT	22
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_P2P		0
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_RING	1
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_HUB		2
> +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_HUB_RING	3
> +
> +#define  SDHCI_UHS2_HOST_CAPS_PHY_OFFSET	4
> +#define   SDHCI_UHS2_HOST_CAPS_PHY_REV_MASK		GENMASK(5, 0)
> +#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_MASK		GENMASK(7, 6)
> +#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_SHIFT		6
> +#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_A		0
> +#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_B		1
> +#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_MASK	GENMASK(19, 16)
> +#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_SHIFT	16
> +#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_MASK	GENMASK(23, 20)
> +#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_SHIFT	20
> +#define  SDHCI_UHS2_HOST_CAPS_TRAN_OFFSET	8
> +#define   SDHCI_UHS2_HOST_CAPS_TRAN_LINK_REV_MASK	GENMASK(5, 0)
> +#define   SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_MASK		GENMASK(15, 8)
> +#define   SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_SHIFT		8
> +#define   SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_MASK	GENMASK(18, 16)
> +#define   SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_SHIFT	16
> +#define   SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_MASK	GENMASK(31, 20)
> +#define   SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_SHIFT	20
> +
> +#define  SDHCI_UHS2_HOST_CAPS_TRAN_1_OFFSET	12
> +#define  SDHCI_UHS2_HOST_CAPS_TRAN_1_N_DATA_GAP_MASK	GENMASK(7, 0)
> +
> +#define SDHCI_UHS2_TEST_PTR	0xE4
> +#define  SDHCI_UHS2_TEST_ERR_HEADER	BIT(0)
> +#define  SDHCI_UHS2_TEST_ERR_RES	BIT(1)
> +#define  SDHCI_UHS2_TEST_ERR_RETRY_EXP	BIT(2)
> +#define  SDHCI_UHS2_TEST_ERR_CRC	BIT(3)
> +#define  SDHCI_UHS2_TEST_ERR_FRAME	BIT(4)
> +#define  SDHCI_UHS2_TEST_ERR_TID	BIT(5)
> +#define  SDHCI_UHS2_TEST_ERR_UNRECOVER	BIT(7)
> +#define  SDHCI_UHS2_TEST_ERR_EBUSY	BIT(8)
> +#define  SDHCI_UHS2_TEST_ERR_ADMA	BIT(15)
> +#define  SDHCI_UHS2_TEST_ERR_RES_TIMEOUT	BIT(16)
> +#define  SDHCI_UHS2_TEST_ERR_DEADLOCK_TIMEOUT	BIT(17)
> +#define  SDHCI_UHS2_TEST_ERR_VENDOR	BIT(27)

The Test register has the same bit fields as the interrupt
registers, so we don't really need them do we?

> +
> +#define SDHCI_UHS2_EMBED_CTRL	0xE6
> +#define SDHCI_UHS2_VENDOR	0xE8

For pointer registers like above 2, let's always name them *_PTR

> +
> +#endif /* __SDHCI_UHS2_H */
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index d750c464bd1e..bbed850241d4 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -43,8 +43,27 @@
>  #define  SDHCI_TRNS_READ	0x10
>  #define  SDHCI_TRNS_MULTI	0x20
>  
> +/*
> + * Defined in Host Version 4.10.

Spec says version 4.0 not version 4.1

> + * 1 - R5 (SDIO)
> + * 0 - R1 (Memory)

Without reading the spec, it is not obvious what the above
means, so please just remove it.

> + */
> +#define  SDHCI_TRNS_RES_TYPE		0x40
> +#define  SDHCI_TRNS_RES_ERR_CHECK	0x80
> +#define  SDHCI_TRNS_RES_INT_DIS		0x0100
> +
>  #define SDHCI_COMMAND		0x0E
>  #define  SDHCI_CMD_RESP_MASK	0x03
> +
> +/*
> + * Host Version 4.10 adds this bit to distinguish a main command or
> + * sub command.
> + * CMD53(SDIO) - main command
> + * CMD52(SDIO) - sub command which doesn't have data block or doesn't
> + * indicate busy.

This isn't very clear.  How about just this instead:

For example with SDIO, CMD52 (sub command) issued during CMD53 (main command)

> + */
> +#define  SDHCI_CMD_SUB_CMD	0x04
> +
>  #define  SDHCI_CMD_CRC		0x08
>  #define  SDHCI_CMD_INDEX	0x10
>  #define  SDHCI_CMD_DATA		0x20
> @@ -60,11 +79,19 @@
>  
>  #define SDHCI_RESPONSE		0x10
>  
> +#define  SDHCI_RESPONSE_CM_TRAN_ABORT_OFFSET	0x10
> +#define  SDHCI_RESPONSE_CM_TRAN_ABORT_SIZE	4
> +#define  SDHCI_RESPONSE_SD_TRAN_ABORT_OFFSET	0x18
> +#define  SDHCI_RESPONSE_SD_TRAN_ABORT_SIZE	8

These are UHS2 registers, so I would expect them in
sdhci-uhs2.h.  We don't put register sizes, and for
8-byte registers we add "_1" for the upper 4-bytes.
i.e.

#define SDHCI_UHS2_CM_TRAN_RESP		0x10
#define SDHCI_UHS2_SD_TRAN_RESP		0x18
#define SDHCI_UHS2_SD_TRAN_RESP_1	0x1C

> +
>  #define SDHCI_BUFFER		0x20
>  
>  #define SDHCI_PRESENT_STATE	0x24
>  #define  SDHCI_CMD_INHIBIT	0x00000001
>  #define  SDHCI_DATA_INHIBIT	0x00000002
> +
> +#define  SDHCI_DATA_HIGH_LVL_MASK	0x000000F0

"HIGH" is not that clear.  Instead, what about:

	SDHCI_DAT_4_TO_7_LVL_MASK

> +
>  #define  SDHCI_DOING_WRITE	0x00000100
>  #define  SDHCI_DOING_READ	0x00000200
>  #define  SDHCI_SPACE_AVAILABLE	0x00000400
> @@ -80,6 +107,13 @@
>  #define   SDHCI_DATA_0_LVL_MASK	0x00100000
>  #define  SDHCI_CMD_LVL		0x01000000
>  

/* Host Version 4.10 */

> +#define  SDHCI_HOST_REGULATOR_STABLE	0x02000000
> +#define  SDHCI_CMD_NOT_ISSUE_ERR	0x08000000

Please change:
	ISSUE -> ISSUED

> +#define  SDHCI_SUB_CMD_STATUS		0x10000000

> +#define  SDHCI_UHS2_IN_DORMANT_STATE	0x20000000
> +#define  SDHCI_UHS2_LANE_SYNC		0x40000000
> +#define  SDHCI_UHS2_IF_DETECT		0x80000000
> +
>  #define SDHCI_HOST_CONTROL	0x28
>  #define  SDHCI_CTRL_LED		0x01
>  #define  SDHCI_CTRL_4BITBUS	0x02
> @@ -100,6 +134,11 @@
>  #define  SDHCI_POWER_300	0x0C
>  #define  SDHCI_POWER_330	0x0E
>  
> +/* VDD2 - UHS2 */

Please be more explicit here:

/* VDD2 power on/off and voltage select (UHS2) */

> +#define  SDHCI_VDD2_POWER_ON		0x10
> +#define  SDHCI_VDD2_POWER_180		0xA0
> +#define  SDHCI_VDD2_POWER_120		0x80

Last 3 values could be lined up with further above.

> +
>  #define SDHCI_BLOCK_GAP_CONTROL	0x2A
>  
>  #define SDHCI_WAKE_UP_CONTROL	0x2B
> @@ -110,7 +149,7 @@
>  #define SDHCI_CLOCK_CONTROL	0x2C
>  #define  SDHCI_DIVIDER_SHIFT	8
>  #define  SDHCI_DIVIDER_HI_SHIFT	6
> -#define  SDHCI_DIV_MASK	0xFF
> +#define  SDHCI_DIV_MASK		0xFF
>  #define  SDHCI_DIV_MASK_LEN	8
>  #define  SDHCI_DIV_HI_MASK	0x300
>  #define  SDHCI_PROG_CLOCK_MODE	0x0020
> @@ -139,6 +178,10 @@
>  #define  SDHCI_INT_CARD_REMOVE	0x00000080
>  #define  SDHCI_INT_CARD_INT	0x00000100
>  #define  SDHCI_INT_RETUNE	0x00001000
> +
> +/* Host Version 4.10 */
> +#define  SDHCI_INT_FX_EVENT	0x00002000
> +
>  #define  SDHCI_INT_CQE		0x00004000
>  #define  SDHCI_INT_ERROR	0x00008000
>  #define  SDHCI_INT_TIMEOUT	0x00010000
> @@ -152,6 +195,9 @@
>  #define  SDHCI_INT_AUTO_CMD_ERR	0x01000000
>  #define  SDHCI_INT_ADMA_ERROR	0x02000000
>  
> +/* Host Version 4.0 */
> +#define  SDHCI_INT_RESPONSE_ERROR	0x08000000

Could be shorter:

SDHCI_INT_RESPONSE_ERROR -> SDHCI_INT_RESP_ERR

> +
>  #define  SDHCI_INT_NORMAL_MASK	0x00007FFF
>  #define  SDHCI_INT_ERROR_MASK	0xFFFF8000
>  
> @@ -178,6 +224,9 @@
>  #define  SDHCI_AUTO_CMD_END_BIT	0x00000008
>  #define  SDHCI_AUTO_CMD_INDEX	0x00000010
>  
> +/* Host Version 4.10 */
> +#define  SDHCI_ACMD_RESPONSE_ERROR	0x0020

Could be shorter:

SDHCI_ACMD_RESPONSE_ERROR -> SDHCI_AUTO_CMD_RESP_ERR

> +
>  #define SDHCI_HOST_CONTROL2		0x3E
>  #define  SDHCI_CTRL_UHS_MASK		0x0007
>  #define   SDHCI_CTRL_UHS_SDR12		0x0000
> @@ -186,6 +235,7 @@
>  #define   SDHCI_CTRL_UHS_SDR104		0x0003
>  #define   SDHCI_CTRL_UHS_DDR50		0x0004
>  #define   SDHCI_CTRL_HS400		0x0005 /* Non-standard */
> +#define   SDHCI_CTRL_UHS_2		0x0007 /* UHS-2 */

We are using UHS2 in other places, so do it here too:

SDHCI_CTRL_UHS_2 -> SDHCI_CTRL_UHS2

Also the comment /* UHS-2 */ is not needed

>  #define  SDHCI_CTRL_VDD_180		0x0008
>  #define  SDHCI_CTRL_DRV_TYPE_MASK	0x0030
>  #define   SDHCI_CTRL_DRV_TYPE_B		0x0000
> @@ -194,9 +244,12 @@
>  #define   SDHCI_CTRL_DRV_TYPE_D		0x0030
>  #define  SDHCI_CTRL_EXEC_TUNING		0x0040
>  #define  SDHCI_CTRL_TUNED_CLK		0x0080
> +#define  SDHCI_CTRL_UHS2_INTERFACE_EN	0x0100 /* UHS-2 */

Already have "SDHCI_CTRL_PRESET_VAL_ENABLE" so let's
spell out ENABLE here too.

SDHCI_CTRL_UHS2_INTERFACE_EN -> SDHCI_CTRL_UHS2_ENABLE

Also the comment /* UHS-2 */ is not needed

> +#define  SDHCI_CTRL_ADMA2_LEN_MODE	0x0400
>  #define  SDHCI_CMD23_ENABLE		0x0800
>  #define  SDHCI_CTRL_V4_MODE		0x1000
>  #define  SDHCI_CTRL_64BIT_ADDR		0x2000
> +#define  SDHCI_CTRL_ASYNC_INT_EN	0x4000

Ditto

SDHCI_CTRL_ASYNC_INT_EN -> SDHCI_CTRL_ASYNC_INT_ENABLE

>  #define  SDHCI_CTRL_PRESET_VAL_ENABLE	0x8000
>  
>  #define SDHCI_CAPABILITIES	0x40
> @@ -219,11 +272,13 @@
>  #define  SDHCI_CAN_VDD_180	0x04000000
>  #define  SDHCI_CAN_64BIT_V4	0x08000000
>  #define  SDHCI_CAN_64BIT	0x10000000
> +#define  SDHCI_CAN_ASYNC_INT	0x20000000
>  
>  #define SDHCI_CAPABILITIES_1	0x44
>  #define  SDHCI_SUPPORT_SDR50	0x00000001
>  #define  SDHCI_SUPPORT_SDR104	0x00000002
>  #define  SDHCI_SUPPORT_DDR50	0x00000004
> +#define  SDHCI_SUPPORT_UHS2	0x00000008 /* UHS-2 support */

Please remove the comment - the name says it all.

>  #define  SDHCI_DRIVER_TYPE_A	0x00000010
>  #define  SDHCI_DRIVER_TYPE_C	0x00000020
>  #define  SDHCI_DRIVER_TYPE_D	0x00000040
> @@ -232,19 +287,28 @@
>  #define  SDHCI_RETUNING_MODE_MASK		GENMASK(15, 14)
>  #define  SDHCI_CLOCK_MUL_MASK			GENMASK(23, 16)
>  #define  SDHCI_CAN_DO_ADMA3	0x08000000
> +#define  SDHCI_SUPPORT_VDD2_180	0x10000000 /* UHS-2 1.8V VDD2 */

Better to be like VDD bit names i.e.

SDHCI_SUPPORT_VDD2_180 -> SDHCI_CAN_VDD2_180

> +#define  SDHCI_RSVD_FOR_VDD2    0x20000000 /* Rsvd for future VDD2 */

Please drop SDHCI_RSVD_FOR_VDD2

>  #define  SDHCI_SUPPORT_HS400	0x80000000 /* Non-standard */
>  
>  #define SDHCI_MAX_CURRENT		0x48
> +#define SDHCI_MAX_CURRENT_1		0x4C

Let's put SDHCI_MAX_CURRENT_1 just above
SDHCI_MAX_CURRENT_VDD2_180_MASK

>  #define  SDHCI_MAX_CURRENT_LIMIT	GENMASK(7, 0)
>  #define  SDHCI_MAX_CURRENT_330_MASK	GENMASK(7, 0)
>  #define  SDHCI_MAX_CURRENT_300_MASK	GENMASK(15, 8)
>  #define  SDHCI_MAX_CURRENT_180_MASK	GENMASK(23, 16)
> +#define  SDHCI_MAX_CURRENT_VDD2_180_MASK	GENMASK(7, 0) /* UHS2 */
>  #define   SDHCI_MAX_CURRENT_MULTIPLIER	4
>  
>  /* 4C-4F reserved for more max current */
>  
>  #define SDHCI_SET_ACMD12_ERROR	0x50
> +/* Host Version 4.10 */
> +#define SDHCI_SET_ACMD_RESPONSE_ERROR	0x20

This isn't being used is it?  Then let's leave it out.

>  #define SDHCI_SET_INT_ERROR	0x52
> +/* Host Version 4.10 */
> +#define SDHCI_SET_INT_TUNING_ERROR	0x0400
> +#define SDHCI_SET_INT_RESPONSE_ERROR	0x0800

These aren't being used are they?  Then let's leave them out.

>  
>  #define SDHCI_ADMA_ERROR	0x54
>  
> @@ -262,10 +326,16 @@
>  #define SDHCI_PRESET_FOR_SDR104        0x6C
>  #define SDHCI_PRESET_FOR_DDR50 0x6E
>  #define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
> +
> +/* TODO: 0x74 is used for UHS2 in 4.10. How about HS400? */
> +/* UHS2 */

A host controller cannot be using it for both at the same time.
The drivers should be able to sort it out if needed. For now,
just remove your comments.

> +#define SDHCI_PRESET_FOR_UHS2  0x74
>  #define SDHCI_PRESET_DRV_MASK		GENMASK(15, 14)
>  #define SDHCI_PRESET_CLKGEN_SEL		BIT(10)
>  #define SDHCI_PRESET_SDCLK_FREQ_MASK	GENMASK(9, 0)
>  
> +#define SDHCI_ADMA3_ADDRESS	0x78
> +
>  #define SDHCI_SLOT_INT_STATUS	0xFC
>  
>  #define SDHCI_HOST_VERSION	0xFE
> @@ -659,6 +729,7 @@ struct sdhci_ops {
>  	void	(*request_done)(struct sdhci_host *host,
>  				struct mmc_request *mrq);
>  	void    (*dump_vendor_regs)(struct sdhci_host *host);
> +	void	(*dump_uhs2_regs)(struct sdhci_host *host);

Please move this to patch "mmc: sdhci-uhs2: dump UHS-II registers"

>  };
>  
>  #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 09/26] mmc: sdhci: add UHS-II module
  2022-10-19 11:06 ` [PATCH V5 09/26] mmc: sdhci: add UHS-II module Victor Shih
@ 2022-11-01 17:12   ` Adrian Hunter
  2022-12-13  8:45     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:12 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> From: AKASHI Takahiro <takahiro.akashi@linaro.org>
> 
> This patch adds sdhci-uhs2.c as a module for UHS-II support.
> This is a skelton for further development in this patch series.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
>  drivers/mmc/host/Makefile     |  1 +
>  drivers/mmc/host/sdhci-uhs2.c | 46 +++++++++++++++++++++++++++++++++++
>  2 files changed, 47 insertions(+)
>  create mode 100644 drivers/mmc/host/sdhci-uhs2.c
> 
> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> index 4e4ceb32c4b4..c4ae7c6d9c04 100644
> --- a/drivers/mmc/host/Makefile
> +++ b/drivers/mmc/host/Makefile
> @@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_PXA)		+= pxamci.o
>  obj-$(CONFIG_MMC_MXC)		+= mxcmmc.o
>  obj-$(CONFIG_MMC_MXS)		+= mxs-mmc.o
>  obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
> +obj-$(CONFIG_MMC_SDHCI_UHS2)	+= sdhci-uhs2.o
>  obj-$(CONFIG_MMC_SDHCI_PCI)	+= sdhci-pci.o
>  sdhci-pci-y			+= sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
>  				   sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> new file mode 100644
> index 000000000000..f29d3a4ed43c
> --- /dev/null
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -0,0 +1,46 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *  linux/drivers/mmc/host/sdhci_uhs2.c - Secure Digital Host Controller
> + *  Interface driver
> + *
> + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> + *  Copyright (C) 2020 Genesys Logic, Inc.
> + *  Authors: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> + *  Copyright (C) 2020 Linaro Limited
> + *  Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> + */
> +
> +#include <linux/module.h>
> +
> +#include "sdhci.h"
> +#include "sdhci-uhs2.h"
> +
> +#define DRIVER_NAME "sdhci_uhs2"
> +#define DBG(f, x...) \
> +	pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
> +
> +/*****************************************************************************\
> + *                                                                           *
> + * Driver init/exit                                                          *
> + *                                                                           *
> +\*****************************************************************************/
> +
> +static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
> +{
> +	return 0;
> +}
> +
> +static int __init sdhci_uhs2_mod_init(void)
> +{
> +	return 0;
> +}
> +module_init(sdhci_uhs2_mod_init);
> +
> +static void __exit sdhci_uhs2_exit(void)

It would be better to match the form of the init name
e.g. sdhci_uhs2_mod_exit

> +{
> +}
> +module_exit(sdhci_uhs2_exit);
> +
> +MODULE_AUTHOR("Intel, Genesys Logic, Linaro");
> +MODULE_DESCRIPTION("MMC UHS-II Support");
> +MODULE_LICENSE("GPL v2");


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 10/26] mmc: sdhci-uhs2: dump UHS-II registers
  2022-10-19 11:06 ` [PATCH V5 10/26] mmc: sdhci-uhs2: dump UHS-II registers Victor Shih
@ 2022-11-01 17:13   ` Adrian Hunter
  2022-12-13  8:45     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:13 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> From: AKASHI Takahiro <takahiro.akashi@linaro.org>
> 
> Dump UHS-II specific registers, if available, in sdhci_dumpregs()
> for informative/debugging use.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 30 ++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-uhs2.h |  4 ++++
>  drivers/mmc/host/sdhci.c      |  3 +++
>  3 files changed, 37 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index f29d3a4ed43c..08905ed081fb 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -18,6 +18,36 @@
>  #define DRIVER_NAME "sdhci_uhs2"
>  #define DBG(f, x...) \
>  	pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
> +#define SDHCI_UHS2_DUMP(f, x...) \
> +	pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
> +
> +void sdhci_uhs2_dump_regs(struct sdhci_host *host)
> +{
> +	if (!host->mmc || !(host->mmc->flags & MMC_UHS2_SUPPORT))

!host->mmc is not possible

> +		return;
> +
> +	SDHCI_UHS2_DUMP("==================== UHS2 ==================\n");
> +	SDHCI_UHS2_DUMP("Blk Size:  0x%08x | Blk Cnt:  0x%08x\n",
> +			sdhci_readw(host, SDHCI_UHS2_BLOCK_SIZE),
> +			sdhci_readl(host, SDHCI_UHS2_BLOCK_COUNT));
> +	SDHCI_UHS2_DUMP("Cmd:       0x%08x | Trn mode: 0x%08x\n",
> +			sdhci_readw(host, SDHCI_UHS2_COMMAND),
> +			sdhci_readw(host, SDHCI_UHS2_TRANS_MODE));
> +	SDHCI_UHS2_DUMP("Int Stat:  0x%08x | Dev Sel : 0x%08x\n",
> +			sdhci_readw(host, SDHCI_UHS2_DEV_INT_STATUS),
> +			sdhci_readb(host, SDHCI_UHS2_DEV_SELECT));
> +	SDHCI_UHS2_DUMP("Dev Int Code:  0x%08x\n",
> +			sdhci_readb(host, SDHCI_UHS2_DEV_INT_CODE));
> +	SDHCI_UHS2_DUMP("Reset:     0x%08x | Timer:    0x%08x\n",
> +			sdhci_readw(host, SDHCI_UHS2_SW_RESET),
> +			sdhci_readw(host, SDHCI_UHS2_TIMER_CTRL));
> +	SDHCI_UHS2_DUMP("ErrInt:    0x%08x | ErrIntEn: 0x%08x\n",
> +			sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS),
> +			sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN));
> +	SDHCI_UHS2_DUMP("ErrSigEn:  0x%08x\n",
> +			sdhci_readl(host, SDHCI_UHS2_ERR_INT_SIG_EN));
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
>  
>  /*****************************************************************************\
>   *                                                                           *
> diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> index 5610affebdf3..afdb05d6056b 100644
> --- a/drivers/mmc/host/sdhci-uhs2.h
> +++ b/drivers/mmc/host/sdhci-uhs2.h
> @@ -207,4 +207,8 @@
>  #define SDHCI_UHS2_EMBED_CTRL	0xE6
>  #define SDHCI_UHS2_VENDOR	0xE8
>  
> +struct sdhci_host;
> +
> +void sdhci_uhs2_dump_regs(struct sdhci_host *host);
> +
>  #endif /* __SDHCI_UHS2_H */
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index fef03de85b99..2cdd183c8ada 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -110,6 +110,9 @@ void sdhci_dumpregs(struct sdhci_host *host)
>  		}
>  	}
>  
> +	if (host->ops->dump_uhs2_regs)
> +		host->ops->dump_uhs2_regs(host);
> +
>  	if (host->ops->dump_vendor_regs)
>  		host->ops->dump_vendor_regs(host);
>  


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 11/26] mmc: sdhci-uhs2: add reset function and uhs2_mode function
  2022-10-19 11:06 ` [PATCH V5 11/26] mmc: sdhci-uhs2: add reset function and uhs2_mode function Victor Shih
@ 2022-11-01 17:13   ` Adrian Hunter
  2022-12-13  8:45     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:13 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> Sdhci_uhs2_reset() does a UHS-II specific reset operation.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
>  drivers/mmc/host/sdhci-pci-core.c |  1 +
>  drivers/mmc/host/sdhci-pci-gli.c  |  1 +
>  drivers/mmc/host/sdhci-uhs2.c     | 68 +++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-uhs2.h     |  3 ++
>  drivers/mmc/host/sdhci.c          |  3 +-
>  drivers/mmc/host/sdhci.h          | 14 +++++++
>  6 files changed, 89 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
> index 34ea1acbb3cc..cba5bba994b8 100644
> --- a/drivers/mmc/host/sdhci-pci-core.c
> +++ b/drivers/mmc/host/sdhci-pci-core.c
> @@ -1955,6 +1955,7 @@ static const struct sdhci_ops sdhci_pci_ops = {
>  	.reset		= sdhci_reset,
>  	.set_uhs_signaling = sdhci_set_uhs_signaling,
>  	.hw_reset		= sdhci_pci_hw_reset,
> +	.uhs2_reset		= sdhci_uhs2_reset,

AFAICT this isn't needed

>  };
>  
>  /*****************************************************************************\
> diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
> index 4d509f656188..607cf69f45d0 100644
> --- a/drivers/mmc/host/sdhci-pci-gli.c
> +++ b/drivers/mmc/host/sdhci-pci-gli.c
> @@ -1097,6 +1097,7 @@ static const struct sdhci_ops sdhci_gl9755_ops = {
>  	.reset			= sdhci_reset,
>  	.set_uhs_signaling	= sdhci_set_uhs_signaling,
>  	.voltage_switch		= sdhci_gli_voltage_switch,
> +	.uhs2_reset		= sdhci_uhs2_reset,
>  };
>  
>  const struct sdhci_pci_fixes sdhci_gl9755 = {
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index 08905ed081fb..0e82f98d1967 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -10,6 +10,7 @@
>   *  Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
>   */
>  
> +#include <linux/delay.h>
>  #include <linux/module.h>
>  
>  #include "sdhci.h"
> @@ -49,6 +50,73 @@ void sdhci_uhs2_dump_regs(struct sdhci_host *host)
>  }
>  EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
>  
> +/*****************************************************************************\
> + *                                                                           *
> + * Low level functions                                                       *
> + *                                                                           *
> +\*****************************************************************************/
> +
> +bool sdhci_uhs2_mode(struct sdhci_host *host)
> +{
> +	if ((host->mmc->caps2 & MMC_CAP2_SD_UHS2) &&
> +	    (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> +		(host->version >= SDHCI_SPEC_400) &&
> +		(host->mmc->flags & MMC_UHS2_SUPPORT)))
> +		return true;
> +	else
> +		return false;

For now, let's just make this:

	return host->mmc->flags & MMC_UHS2_SUPPORT;

> +}
> +
> +/**
> + * sdhci_uhs2_reset - invoke SW reset
> + * @host: SDHCI host
> + * @mask: Control mask
> + *
> + * Invoke SW reset, depending on a bit in @mask and wait for completion.
> + */
> +void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
> +{
> +	unsigned long timeout;
> +	u32 val;
> +
> +	if (!(sdhci_uhs2_mode(host))) {

That isn't possible.

> +		/**
> +		 * u8  mask for legacy.
> +		 * u16 mask for uhs-2.
> +		 */
> +		u8 u8_mask;
> +
> +		u8_mask = (mask & 0xFF);
> +		sdhci_reset(host, u8_mask);

Probably should call host->ops->reset() but !sdhci_uhs2_mode(host)
isn't possible

> +
> +		return;
> +	}
> +
> +	sdhci_writew(host, mask, SDHCI_UHS2_SW_RESET);
> +
> +	if (mask & SDHCI_UHS2_SW_RESET_FULL) {
> +		host->clock = 0;
> +		/* Reset-all turns off SD Bus Power */
> +		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
> +			sdhci_runtime_pm_bus_off(host);

We don't know what other drivers will opt for UHS-II
support, but I doubt this quirk will be used, so  let's
not support SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON for UHS-II

> +	}
> +
> +	/* Wait max 100 ms */
> +	timeout = 10000;

Isn't that 10ms

> +
> +	/* hw clears the bit when it's done */
> +	if (read_poll_timeout_atomic(sdhci_readw, val, !(val & mask), 10,
> +				     timeout, true, host, SDHCI_UHS2_SW_RESET)) {
> +		pr_err("%s: %s: Reset 0x%x never completed.\n",
> +					       __func__, mmc_hostname(host->mmc), (int)mask);
> +		pr_err("%s: clean reset bit\n",
> +					       mmc_hostname(host->mmc));
> +		sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET);
> +		return;
> +	}
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
> +
>  /*****************************************************************************\
>   *                                                                           *
>   * Driver init/exit                                                          *
> diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> index afdb05d6056b..31776dcca5cf 100644
> --- a/drivers/mmc/host/sdhci-uhs2.h
> +++ b/drivers/mmc/host/sdhci-uhs2.h
> @@ -11,6 +11,7 @@
>  #define __SDHCI_UHS2_H
>  
>  #include <linux/bits.h>
> +#include <linux/iopoll.h>

Not needed in header.  Can just be in .c

>  
>  /*
>   * UHS-II Controller registers
> @@ -210,5 +211,7 @@
>  struct sdhci_host;
>  
>  void sdhci_uhs2_dump_regs(struct sdhci_host *host);
> +bool sdhci_uhs2_mode(struct sdhci_host *host);
> +void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
>  
>  #endif /* __SDHCI_UHS2_H */
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 2cdd183c8ada..bd017c59a020 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -194,13 +194,14 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
>  	pm_runtime_get_noresume(mmc_dev(host->mmc));
>  }
>  
> -static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
> +void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
>  {
>  	if (!host->bus_on)
>  		return;
>  	host->bus_on = false;
>  	pm_runtime_put_noidle(mmc_dev(host->mmc));
>  }
> +EXPORT_SYMBOL_GPL(sdhci_runtime_pm_bus_off);

Let's not support SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON for UHS-II

>  
>  void sdhci_reset(struct sdhci_host *host, u8 mask)
>  {
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index bbed850241d4..28716105da61 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -715,6 +715,19 @@ struct sdhci_ops {
>  					     u8 power_mode);
>  	unsigned int    (*get_ro)(struct sdhci_host *host);
>  	void		(*reset)(struct sdhci_host *host, u8 mask);
> +	/**
> +	 * The sdhci_uhs2_reset callback is to implement for reset
> +	 * @host: SDHCI host
> +	 * @mask: Control mask
> +	 *
> +	 * Invoke reset, depending on a bit in @mask and wait for completion.
> +	 * SD mode				UHS-II mode
> +	 * SDHCI_RESET_ALL		SDHCI_UHS2_SW_RESET_FULL
> +	 * SDHCI_RESET_CMD		SDHCI_RESET_CMD
> +	 * SDHCI_RESET_DATA		SDHCI_UHS2_SW_RESET_SD
> +	 *
> +	 **/
> +	void (*uhs2_reset)(struct sdhci_host *host, u16 mask);

This is only being called from sdhci_uhs2.c so let's just call it
directly for now, instead of using a callback.

>  	int	(*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
>  	void	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
>  	void	(*hw_reset)(struct sdhci_host *host);
> @@ -837,6 +850,7 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
>  	__sdhci_read_caps(host, NULL, NULL, NULL);
>  }
>  
> +void sdhci_runtime_pm_bus_off(struct sdhci_host *host);

Let's not support SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON for UHS-II

>  u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
>  		   unsigned int *actual_clock);
>  void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 12/26] mmc: sdhci-uhs2: add set_power() to support vdd2
  2022-10-19 11:06 ` [PATCH V5 12/26] mmc: sdhci-uhs2: add set_power() to support vdd2 Victor Shih
@ 2022-11-01 17:13   ` Adrian Hunter
  2022-12-13  8:46     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:13 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> This is a UHS-II version of sdhci's set_power operation.
> VDD2, as well as VDD, is handled here.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 79 +++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-uhs2.h |  2 +
>  drivers/mmc/host/sdhci.c      | 66 ++++++++++++++++-------------
>  drivers/mmc/host/sdhci.h      |  2 +
>  4 files changed, 120 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index 0e82f98d1967..896a1c8e55cf 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -117,6 +117,85 @@ void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
>  }
>  EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
>  
> +void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
> +			  unsigned short vdd)
> +{
> +	struct mmc_host *mmc = host->mmc;
> +	u8 pwr;
> +
> +	/* FIXME: check if flags & MMC_UHS2_SUPPORT? */
> +	if (!(sdhci_uhs2_mode(host))) {
> +		sdhci_set_power(host, mode, vdd);
> +		return;
> +	}

sdhci_uhs2_set_power() is called via ->uhs2_set_ios().  That should
not be called if not in UHS2 mode, so no check should be needed here.


> +
> +	if (mode != MMC_POWER_OFF) {
> +		pwr = sdhci_get_vdd_value(vdd);
> +		if (!pwr)
> +			WARN(1, "%s: Invalid vdd %#x\n",
> +			     mmc_hostname(host->mmc), vdd);
> +		pwr |= SDHCI_VDD2_POWER_180;
> +	}
> +
> +	if (host->pwr == pwr)
> +		return;
> +	host->pwr = pwr;
> +
> +	if (pwr == 0) {
> +		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
> +
> +		if (!IS_ERR(host->mmc->supply.vmmc))
> +			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);

Seems to be a common if-clause.  Looks like we could use a
helper like:

static inline int mmc_opt_regulator_set_ocr(struct mmc_host *mmc,
					    struct regulator *supply,
					    unsigned short vdd_bit)
{
	return IS_ERR_OR_NULL(supply) ? 0 : mmc_regulator_set_ocr(mmc, supply, vdd_bit);
}


> +		if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
> +			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
> +
> +		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
> +			sdhci_runtime_pm_bus_off(host);

Let's not support quirks that you don't need like
SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON

> +	} else {
> +		if (!IS_ERR(host->mmc->supply.vmmc))
> +			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
> +		if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
> +			/* support 1.8v only for now */
> +			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2,
> +					      fls(MMC_VDD2_165_195) - 1);
> +
> +		/*
> +		 * Spec says that we should clear the power reg before setting
> +		 * a new value. Some controllers don't seem to like this though.
> +		 */
> +		if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))

Let's not support quirks that you don't need like
SDHCI_QUIRK_SINGLE_POWER_WRITE
note this one is !

> +			sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
> +
> +		/*
> +		 * At least the Marvell CaFe chip gets confused if we set the
> +		 * voltage and set turn on power at the same time, so set the
> +		 * voltage first.
> +		 */
> +		if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
> +			sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);

Let's not support quirks that you don't need like
SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER

> +
> +		/* vdd first */
> +		pwr |= SDHCI_POWER_ON;
> +		sdhci_writeb(host, pwr & 0xf, SDHCI_POWER_CONTROL);
> +		mdelay(5);
> +
> +		pwr |= SDHCI_VDD2_POWER_ON;
> +		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
> +		mdelay(5);
> +
> +		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
> +			sdhci_runtime_pm_bus_on(host);

Let's not support quirks that you don't need like
SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON

> +
> +		/*
> +		 * Some controllers need an extra 10ms delay of 10ms before
> +		 * they can apply clock after applying power
> +		 */
> +		if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
> +			mdelay(10);

Let's not support quirks that you don't need like
SDHCI_QUIRK_DELAY_AFTER_POWER

> +	}
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);

It is only used in this file, so let's not export it.

> +
>  /*****************************************************************************\
>   *                                                                           *
>   * Driver init/exit                                                          *
> diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> index 31776dcca5cf..3179915f7f79 100644
> --- a/drivers/mmc/host/sdhci-uhs2.h
> +++ b/drivers/mmc/host/sdhci-uhs2.h
> @@ -213,5 +213,7 @@ struct sdhci_host;
>  void sdhci_uhs2_dump_regs(struct sdhci_host *host);
>  bool sdhci_uhs2_mode(struct sdhci_host *host);
>  void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
> +void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
> +			  unsigned short vdd);

Let's not export it for now.

>  
>  #endif /* __SDHCI_UHS2_H */
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index bd017c59a020..dfa0939a9058 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -23,7 +23,7 @@
>  #include <linux/regulator/consumer.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/of.h>
> -
> +#include <linux/bug.h>
>  #include <linux/leds.h>
>  
>  #include <linux/mmc/mmc.h>
> @@ -186,13 +186,14 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
>  	sdhci_set_card_detection(host, false);
>  }
>  
> -static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
> +void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
>  {
>  	if (host->bus_on)
>  		return;
>  	host->bus_on = true;
>  	pm_runtime_get_noresume(mmc_dev(host->mmc));
>  }
> +EXPORT_SYMBOL_GPL(sdhci_runtime_pm_bus_on);
>  
>  void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
>  {
> @@ -2071,41 +2072,48 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
>  		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
>  }
>  
> +unsigned short sdhci_get_vdd_value(unsigned short vdd)
> +{
> +	u8 pwr;
> +
> +	switch (1 << vdd) {
> +	case MMC_VDD_165_195:
> +	/*
> +	 * Without a regulator, SDHCI does not support 2.0v
> +	 * so we only get here if the driver deliberately
> +	 * added the 2.0v range to ocr_avail. Map it to 1.8v
> +	 * for the purpose of turning on the power.
> +	 */
> +	case MMC_VDD_20_21:
> +		pwr = SDHCI_POWER_180;
> +		break;
> +	case MMC_VDD_29_30:
> +	case MMC_VDD_30_31:
> +		pwr = SDHCI_POWER_300;
> +		break;
> +	case MMC_VDD_32_33:
> +	case MMC_VDD_33_34:
> +		pwr = SDHCI_POWER_330;
> +		break;
> +	default:
> +		pwr = 0;
> +		break;
> +	}
> +
> +	return pwr;
> +}
> +EXPORT_SYMBOL_GPL(sdhci_get_vdd_value);
> +
>  void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
>  			   unsigned short vdd)
>  {
>  	u8 pwr = 0;
>  
>  	if (mode != MMC_POWER_OFF) {
> -		switch (1 << vdd) {
> -		case MMC_VDD_165_195:
> -		/*
> -		 * Without a regulator, SDHCI does not support 2.0v
> -		 * so we only get here if the driver deliberately
> -		 * added the 2.0v range to ocr_avail. Map it to 1.8v
> -		 * for the purpose of turning on the power.
> -		 */
> -		case MMC_VDD_20_21:
> -			pwr = SDHCI_POWER_180;
> -			break;
> -		case MMC_VDD_29_30:
> -		case MMC_VDD_30_31:
> -			pwr = SDHCI_POWER_300;
> -			break;
> -		case MMC_VDD_32_33:
> -		case MMC_VDD_33_34:
> -		/*
> -		 * 3.4 ~ 3.6V are valid only for those platforms where it's
> -		 * known that the voltage range is supported by hardware.
> -		 */
> -		case MMC_VDD_34_35:
> -		case MMC_VDD_35_36:
> -			pwr = SDHCI_POWER_330;
> -			break;
> -		default:
> +		pwr = sdhci_get_vdd_value(vdd);
> +		if (!pwr) {
>  			WARN(1, "%s: Invalid vdd %#x\n",
>  			     mmc_hostname(host->mmc), vdd);
> -			break;
>  		}
>  	}
>  
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index 28716105da61..c34ca6ffbff6 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -850,6 +850,7 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
>  	__sdhci_read_caps(host, NULL, NULL, NULL);
>  }
>  
> +void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
>  void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
>  u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
>  		   unsigned int *actual_clock);
> @@ -860,6 +861,7 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
>  void sdhci_set_power_and_bus_voltage(struct sdhci_host *host,
>  				     unsigned char mode,
>  				     unsigned short vdd);
> +unsigned short sdhci_get_vdd_value(unsigned short vdd);
>  void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
>  			   unsigned short vdd);
>  int sdhci_get_cd_nogpio(struct mmc_host *mmc);


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 14/26] mmc: sdhci-uhs2: add set_timeout()
  2022-10-19 11:06 ` [PATCH V5 14/26] mmc: sdhci-uhs2: add set_timeout() Victor Shih
@ 2022-11-01 17:14   ` Adrian Hunter
  2022-12-13  8:46     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:14 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> From: AKASHI Takahiro <takahiro.akashi@linaro.org>
> 
> This is a UHS-II version of sdhci's set_timeout() operation.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 85 +++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-uhs2.h |  1 +
>  2 files changed, 86 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index 4dc3e904d7d2..2b90e5308764 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -196,6 +196,91 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
>  }
>  EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
>  
> +static u8 sdhci_calc_timeout_uhs2(struct sdhci_host *host, u8 *cmd_res,
> +				  u8 *dead_lock)
> +{
> +	u8 count;
> +	unsigned int cmd_res_timeout, dead_lock_timeout, current_timeout;
> +
> +	/*
> +	 * If the host controller provides us with an incorrect timeout
> +	 * value, just skip the check and use 0xE.  The hardware may take
> +	 * longer to time out, but that's much better than having a too-short
> +	 * timeout value.
> +	 */
> +	if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) {
> +		*cmd_res = 0xE;
> +		*dead_lock = 0xE;
> +		return 0xE;
> +	}

Let's skip quirks you don't need for now.

> +
> +	/* timeout in us */
> +	cmd_res_timeout = 5 * 1000;
> +	dead_lock_timeout = 1 * 1000 * 1000;
> +
> +	/*
> +	 * Figure out needed cycles.
> +	 * We do this in steps in order to fit inside a 32 bit int.
> +	 * The first step is the minimum timeout, which will have a
> +	 * minimum resolution of 6 bits:
> +	 * (1) 2^13*1000 > 2^22,
> +	 * (2) host->timeout_clk < 2^16
> +	 *     =>
> +	 *     (1) / (2) > 2^6
> +	 */
> +	count = 0;
> +	current_timeout = (1 << 13) * 1000 / host->timeout_clk;
> +	while (current_timeout < cmd_res_timeout) {
> +		count++;
> +		current_timeout <<= 1;
> +		if (count >= 0xF)
> +			break;
> +	}
> +
> +	if (count >= 0xF) {
> +		DBG("%s: Too large timeout 0x%x requested for CMD_RES!\n",
> +		    mmc_hostname(host->mmc), count);
> +		count = 0xE;
> +	}
> +	*cmd_res = count;
> +
> +	count = 0;
> +	current_timeout = (1 << 13) * 1000 / host->timeout_clk;
> +	while (current_timeout < dead_lock_timeout) {
> +		count++;
> +		current_timeout <<= 1;
> +		if (count >= 0xF)
> +			break;
> +	}
> +
> +	if (count >= 0xF) {
> +		DBG("%s: Too large timeout 0x%x requested for DEADLOCK!\n",
> +		    mmc_hostname(host->mmc), count);
> +		count = 0xE;
> +	}
> +	*dead_lock = count;
> +
> +	return count;
> +}
> +
> +static void __sdhci_uhs2_set_timeout(struct sdhci_host *host)
> +{
> +	u8 cmd_res, dead_lock;
> +
> +	sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
> +	cmd_res |= dead_lock << SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT;

GENMASK() and FIELD_PREP() please

> +	sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
> +}
> +
> +void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
> +{
> +	__sdhci_set_timeout(host, cmd);
> +
> +	if (host->mmc->flags & MMC_UHS2_SUPPORT)

	if (sdhci_uhs2_mode(host))

> +		__sdhci_uhs2_set_timeout(host);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
> +
>  /*****************************************************************************\
>   *                                                                           *
>   * MMC callbacks                                                             *
> diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> index 3179915f7f79..5ea235b14108 100644
> --- a/drivers/mmc/host/sdhci-uhs2.h
> +++ b/drivers/mmc/host/sdhci-uhs2.h
> @@ -215,5 +215,6 @@ bool sdhci_uhs2_mode(struct sdhci_host *host);
>  void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
>  void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
>  			  unsigned short vdd);
> +void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
>  
>  #endif /* __SDHCI_UHS2_H */


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 15/26] mmc: sdhci-uhs2: add set_ios()
  2022-10-19 11:06 ` [PATCH V5 15/26] mmc: sdhci-uhs2: add set_ios() Victor Shih
@ 2022-11-01 17:14   ` Adrian Hunter
  2022-12-13  8:46     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:14 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> This is a sdhci version of mmc's set_ios operation.
> It covers both UHS-I and UHS-II.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 102 ++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-uhs2.h |   1 +
>  drivers/mmc/host/sdhci.c      |  40 ++++++++-----
>  drivers/mmc/host/sdhci.h      |   2 +
>  4 files changed, 130 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index 2b90e5308764..b535a47dc55a 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -281,6 +281,74 @@ void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>  }
>  EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
>  
> +/**
> + * sdhci_uhs2_clear_set_irqs - set Error Interrupt Status Enable register
> + * @host:	SDHCI host
> + * @clear:	bit-wise clear mask
> + * @set:	bit-wise set mask
> + *
> + * Set/unset bits in UHS-II Error Interrupt Status Enable register
> + */
> +void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
> +{
> +	u32 ier;
> +
> +	ier = sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN);
> +	ier &= ~clear;
> +	ier |= set;
> +	sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_STATUS_EN);
> +	sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_SIG_EN);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_clear_set_irqs);
> +
> +static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +	u8 cmd_res, dead_lock;
> +	u16 ctrl_2;
> +	unsigned long flags;
> +
> +	/* FIXME: why lock? */
> +	spin_lock_irqsave(&host->lock, flags);

->uhs2_set_ios() should not be racing with anything, so the lock
should not be needed.  Please remove for now.

> +
> +	/* UHS2 Timeout Control */
> +	sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
> +
> +	/* change to use calculate value */
> +	cmd_res |= dead_lock << SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT;
> +
> +	sdhci_uhs2_clear_set_irqs(host,
> +				  SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
> +				  SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT,
> +				  0);
> +	sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
> +	sdhci_uhs2_clear_set_irqs(host, 0,
> +				  SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
> +				  SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT);
> +
> +	/* UHS2 timing */
> +	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +	if (ios->timing == MMC_TIMING_SD_UHS2)
> +		ctrl_2 |= SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN;
> +	else
> +		ctrl_2 &= ~(SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN);
> +	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
> +
> +	if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
> +		sdhci_enable_preset_value(host, true);
> +
> +	if (host->ops->set_power)
> +		host->ops->set_power(host, ios->power_mode, ios->vdd);
> +	else
> +		sdhci_uhs2_set_power(host, ios->power_mode, ios->vdd);
> +	udelay(100);
> +
> +	host->timing = ios->timing;
> +	sdhci_set_clock(host, host->clock);
> +
> +	spin_unlock_irqrestore(&host->lock, flags);
> +}
> +
>  /*****************************************************************************\
>   *                                                                           *
>   * MMC callbacks                                                             *
> @@ -302,6 +370,39 @@ static int sdhci_uhs2_start_signal_voltage_switch(struct mmc_host *mmc,
>  	return sdhci_start_signal_voltage_switch(mmc, ios);
>  }
>  
> +int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +
> +	if (!(host->version >= SDHCI_SPEC_400) ||
> +	    !(host->mmc->flags & MMC_UHS2_SUPPORT &&
> +	      host->mmc->caps2 & MMC_CAP2_SD_UHS2)) {
> +		sdhci_set_ios(mmc, ios);
> +		return 0;
> +	}
> +
> +	if (ios->power_mode == MMC_POWER_UNDEFINED)
> +		return 1;

->uhs2_set_ios() expects 0 or a negative error code.
This case is not an error.

		return 0;

> +
> +	if (host->flags & SDHCI_DEVICE_DEAD) {
> +		if (!IS_ERR(mmc->supply.vmmc) &&
> +		    ios->power_mode == MMC_POWER_OFF)
> +			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> +		if (!IS_ERR_OR_NULL(mmc->supply.vmmc2) &&
> +		    ios->power_mode == MMC_POWER_OFF)
> +			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
> +		return 1;

This is an error, so a negative code is needed

> +	}
> +
> +	/* FIXME: host->timing = ios->timing */

Yes, __sdhci_uhs2_set_ios() should do that when it sets the timing

> +
> +	sdhci_set_ios_common(mmc, ios);
> +
> +	__sdhci_uhs2_set_ios(mmc, ios);
> +
> +	return 0;
> +}
> +
>  /*****************************************************************************\
>   *                                                                           *
>   * Driver init/exit                                                          *
> @@ -312,6 +413,7 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
>  {
>  	host->mmc_host_ops.start_signal_voltage_switch =
>  		sdhci_uhs2_start_signal_voltage_switch;
> +	host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
>  
>  	return 0;
>  }
> diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> index 5ea235b14108..23368448ccd4 100644
> --- a/drivers/mmc/host/sdhci-uhs2.h
> +++ b/drivers/mmc/host/sdhci-uhs2.h
> @@ -216,5 +216,6 @@ void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
>  void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
>  			  unsigned short vdd);
>  void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
> +void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
>  
>  #endif /* __SDHCI_UHS2_H */
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index dfa0939a9058..de47c71995fb 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -47,8 +47,6 @@
>  static unsigned int debug_quirks = 0;
>  static unsigned int debug_quirks2;
>  
> -static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
> -
>  static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
>  
>  void sdhci_dumpregs(struct sdhci_host *host)
> @@ -1888,6 +1886,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
>  	case MMC_TIMING_MMC_HS400:
>  		preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
>  		break;
> +	case MMC_TIMING_SD_UHS2:
> +		preset = sdhci_readw(host, SDHCI_PRESET_FOR_UHS2);
> +		break;
>  	default:
>  		pr_warn("%s: Invalid UHS-I mode selected\n",
>  			mmc_hostname(host->mmc));
> @@ -2305,20 +2306,9 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
>  }
>  EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
>  
> -void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> +void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios)
>  {
>  	struct sdhci_host *host = mmc_priv(mmc);
> -	u8 ctrl;
> -
> -	if (ios->power_mode == MMC_POWER_UNDEFINED)
> -		return;
> -
> -	if (host->flags & SDHCI_DEVICE_DEAD) {
> -		if (!IS_ERR(mmc->supply.vmmc) &&
> -		    ios->power_mode == MMC_POWER_OFF)
> -			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> -		return;
> -	}
>  
>  	/*
>  	 * Reset the chip on each power off.
> @@ -2355,6 +2345,25 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>  		host->ops->set_power(host, ios->power_mode, ios->vdd);
>  	else
>  		sdhci_set_power(host, ios->power_mode, ios->vdd);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_set_ios_common);
> +
> +void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +	u8 ctrl;
> +
> +	if (ios->power_mode == MMC_POWER_UNDEFINED)
> +		return;
> +
> +	if (host->flags & SDHCI_DEVICE_DEAD) {
> +		if (!IS_ERR(mmc->supply.vmmc) &&
> +		    ios->power_mode == MMC_POWER_OFF)
> +			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> +		return;
> +	}
> +
> +	sdhci_set_ios_common(mmc, ios);
>  
>  	if (host->ops->platform_send_init_74_clocks)
>  		host->ops->platform_send_init_74_clocks(host, ios->power_mode);
> @@ -2935,7 +2944,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
>  }
>  EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
>  
> -static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
> +void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
>  {
>  	/* Host Controller v3.00 defines preset value registers */
>  	if (host->version < SDHCI_SPEC_300)
> @@ -2963,6 +2972,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
>  		host->preset_enabled = enable;
>  	}
>  }
> +EXPORT_SYMBOL_GPL(sdhci_enable_preset_value);
>  
>  static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
>  				int err)
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index c34ca6ffbff6..22d7f47862ae 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -871,6 +871,8 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width);
>  void sdhci_reset(struct sdhci_host *host, u8 mask);
>  void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
>  int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
> +void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
> +void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios);
>  void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
>  int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
>  				      struct mmc_ios *ios);


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 16/26] mmc: sdhci-uhs2: add detect_init() to detect the interface
  2022-10-19 11:06 ` [PATCH V5 16/26] mmc: sdhci-uhs2: add detect_init() to detect the interface Victor Shih
@ 2022-11-01 17:14   ` Adrian Hunter
  2022-12-13  8:47     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:14 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> Sdhci_uhs2_do_detect_init() is a sdhci version of mmc's uhs2_detect_init
> operation. After detected, the host's UHS-II capabilities will be set up
> here and interrupts will also be enabled.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 146 ++++++++++++++++++++++++++++++++++
>  1 file changed, 146 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index b535a47dc55a..9ceae552c323 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -409,12 +409,158 @@ int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>   *                                                                           *
>  \*****************************************************************************/
>  
> +static int sdhci_uhs2_interface_detect(struct sdhci_host *host)
> +{
> +	/* 100ms */
> +	int timeout = 100000;
> +	u32 val;
> +
> +	udelay(200); /* wait for 200us before check */
> +
> +	if (read_poll_timeout_atomic(sdhci_readl, val, (val & SDHCI_UHS2_IF_DETECT),
> +				     100, timeout, true, host, SDHCI_PRESENT_STATE)) {
> +		pr_warn("%s: not detect UHS2 interface in 200us.\n", mmc_hostname(host->mmc));
> +		sdhci_dumpregs(host);
> +		return -EIO;
> +	}
> +
> +	/* Enable UHS2 error interrupts */
> +	sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
> +				  SDHCI_UHS2_ERR_INT_STATUS_MASK);
> +
> +	/* 150ms */
> +	timeout = 150000;
> +	if (read_poll_timeout_atomic(sdhci_readl, val, (val & SDHCI_UHS2_LANE_SYNC),
> +				     100, timeout, true, host, SDHCI_PRESENT_STATE)) {
> +		pr_warn("%s: UHS2 Lane sync fail in 150ms.\n", mmc_hostname(host->mmc));
> +		sdhci_dumpregs(host);
> +		return -EIO;
> +	}
> +
> +	DBG("%s: UHS2 Lane synchronized in UHS2 mode, PHY is initialized.\n",
> +	    mmc_hostname(host->mmc));
> +	return 0;
> +}
> +
> +static int sdhci_uhs2_init(struct sdhci_host *host)
> +{
> +	u16 caps_ptr = 0;
> +	u32 caps_gen = 0;
> +	u32 caps_phy = 0;
> +	u32 caps_tran[2] = {0, 0};
> +	struct mmc_host *mmc = host->mmc;
> +
> +	caps_ptr = sdhci_readw(host, SDHCI_UHS2_HOST_CAPS_PTR);
> +	if (caps_ptr < 0x100 || caps_ptr > 0x1FF) {
> +		pr_err("%s: SDHCI_UHS2_HOST_CAPS_PTR(%d) is wrong.\n",
> +		       mmc_hostname(mmc), caps_ptr);
> +		return -ENODEV;
> +	}
> +	caps_gen = sdhci_readl(host,
> +			       caps_ptr + SDHCI_UHS2_HOST_CAPS_GEN_OFFSET);

Please wrap at 100 columns not 80, here and elsewhere.

> +	caps_phy = sdhci_readl(host,
> +			       caps_ptr + SDHCI_UHS2_HOST_CAPS_PHY_OFFSET);
> +	caps_tran[0] = sdhci_readl(host,
> +				   caps_ptr + SDHCI_UHS2_HOST_CAPS_TRAN_OFFSET);
> +	caps_tran[1] = sdhci_readl(host,
> +				   caps_ptr
> +					+ SDHCI_UHS2_HOST_CAPS_TRAN_1_OFFSET);
> +
> +	/* General Caps */
> +	mmc->uhs2_caps.dap = caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_DAP_MASK;
> +	mmc->uhs2_caps.gap = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_GAP_MASK) >>
> +			     SDHCI_UHS2_HOST_CAPS_GEN_GAP_SHIFT;
> +	mmc->uhs2_caps.n_lanes = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_LANE_MASK)
> +			>> SDHCI_UHS2_HOST_CAPS_GEN_LANE_SHIFT;
> +	mmc->uhs2_caps.addr64 =
> +		(caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_ADDR_64) ? 1 : 0;
> +	mmc->uhs2_caps.card_type =
> +		(caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_MASK) >>
> +		SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_SHIFT;
> +
> +	/* PHY Caps */
> +	mmc->uhs2_caps.phy_rev = caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_REV_MASK;
> +	mmc->uhs2_caps.speed_range =
> +		(caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_RANGE_MASK)
> +		>> SDHCI_UHS2_HOST_CAPS_PHY_RANGE_SHIFT;
> +	mmc->uhs2_caps.n_lss_sync =
> +		(caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_MASK)
> +		>> SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_SHIFT;
> +	mmc->uhs2_caps.n_lss_dir =
> +		(caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_MASK)
> +		>> SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_SHIFT;
> +	if (mmc->uhs2_caps.n_lss_sync == 0)
> +		mmc->uhs2_caps.n_lss_sync = 16 << 2;
> +	else
> +		mmc->uhs2_caps.n_lss_sync <<= 2;
> +	if (mmc->uhs2_caps.n_lss_dir == 0)
> +		mmc->uhs2_caps.n_lss_dir = 16 << 3;
> +	else
> +		mmc->uhs2_caps.n_lss_dir <<= 3;
> +
> +	/* LINK/TRAN Caps */
> +	mmc->uhs2_caps.link_rev =
> +		caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_LINK_REV_MASK;
> +	mmc->uhs2_caps.n_fcu =
> +		(caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_MASK)
> +		>> SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_SHIFT;
> +	if (mmc->uhs2_caps.n_fcu == 0)
> +		mmc->uhs2_caps.n_fcu = 256;
> +	mmc->uhs2_caps.host_type =
> +		(caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_MASK)
> +		>> SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_SHIFT;
> +	mmc->uhs2_caps.maxblk_len =
> +		(caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_MASK)
> +		>> SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_SHIFT;
> +	mmc->uhs2_caps.n_data_gap =
> +		caps_tran[1] & SDHCI_UHS2_HOST_CAPS_TRAN_1_N_DATA_GAP_MASK;
> +
> +	return 0;
> +}
> +
> +static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +	int ret = -EIO;
> +
> +	DBG("%s: begin UHS2 init.\n", __func__);
> +
> +	if (sdhci_uhs2_interface_detect(host)) {
> +		pr_warn("%s: cannot detect UHS2 interface.\n",
> +			mmc_hostname(host->mmc));
> +		goto out;
> +	}
> +
> +	if (sdhci_uhs2_init(host)) {
> +		pr_warn("%s: UHS2 init fail.\n", mmc_hostname(host->mmc));
> +		goto out;
> +	}
> +
> +	/* Init complete, do soft reset and enable UHS2 error irqs. */
> +	host->ops->uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD);
> +	sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
> +				  SDHCI_UHS2_ERR_INT_STATUS_MASK);
> +	/*
> +	 * !!! SDHCI_INT_ENABLE and SDHCI_SIGNAL_ENABLE was cleared

!!! is a little dramatic, what about just N.B.

> +	 * by SDHCI_UHS2_SW_RESET_SD
> +	 */
> +	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> +	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
> +
> +	ret = 0;
> +out:
> +	return ret;
> +}
> +
>  static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
>  {
>  	host->mmc_host_ops.start_signal_voltage_switch =
>  		sdhci_uhs2_start_signal_voltage_switch;
>  	host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
>  
> +	if (!host->mmc_host_ops.uhs2_detect_init)
> +		host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;

As mentioned before ->uhs2_detect_init() is never called.

> +
>  	return 0;
>  }
>  


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 17/26] mmc: sdhci-uhs2: add clock operations
  2022-10-19 11:06 ` [PATCH V5 17/26] mmc: sdhci-uhs2: add clock operations Victor Shih
@ 2022-11-01 17:14   ` Adrian Hunter
  2022-12-13  8:47     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:14 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> This is a sdhci version of mmc's uhs2_[enable|disable]_clk operations.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 36 +++++++++++++++++++++++++++++++++++
>  1 file changed, 36 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index 9ceae552c323..afaca5d96938 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -11,6 +11,7 @@
>   */
>  
>  #include <linux/delay.h>
> +#include <linux/ktime.h>
>  #include <linux/module.h>
>  
>  #include "sdhci.h"
> @@ -403,6 +404,37 @@ int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>  	return 0;
>  }
>  
> +static int sdhci_uhs2_disable_clk(struct mmc_host *mmc)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +	u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> +
> +	clk &= ~SDHCI_CLOCK_CARD_EN;
> +	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> +
> +	return 0;
> +}
> +
> +static int sdhci_uhs2_enable_clk(struct mmc_host *mmc)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +	u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> +	u32 val;
> +	/* 20ms */
> +	int timeout_us = 20000;
> +
> +	clk |= SDHCI_CLOCK_CARD_EN;
> +	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> +
> +	if (read_poll_timeout_atomic(sdhci_readw, val, (val & SDHCI_CLOCK_INT_STABLE),
> +				     10, timeout_us, true, host, SDHCI_CLOCK_CONTROL)) {
> +		pr_err("%s: Internal clock never stabilised.\n", mmc_hostname(host->mmc));
> +		sdhci_dumpregs(host);
> +		return 1;
> +	}
> +	return 0;
> +}
> +
>  /*****************************************************************************\
>   *                                                                           *
>   * Driver init/exit                                                          *
> @@ -560,6 +592,10 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
>  
>  	if (!host->mmc_host_ops.uhs2_detect_init)
>  		host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
> +	if (!host->mmc_host_ops.uhs2_disable_clk)
> +		host->mmc_host_ops.uhs2_disable_clk = sdhci_uhs2_disable_clk;
> +	if (!host->mmc_host_ops.uhs2_enable_clk)
> +		host->mmc_host_ops.uhs2_enable_clk = sdhci_uhs2_enable_clk;

As mentioned before ->uhs2_disable_clk() and ->uhs2_enable_clk()
are never called.

>  
>  	return 0;
>  }


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 18/26] mmc: sdhci-uhs2: add uhs2_control() to initialise the interface
  2022-10-19 11:06 ` [PATCH V5 18/26] mmc: sdhci-uhs2: add uhs2_control() to initialise the interface Victor Shih
@ 2022-11-01 17:15   ` Adrian Hunter
  2022-12-13  8:47     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:15 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> This is a sdhci version of mmc's uhs2_set_reg operation.
> UHS-II interface (related registers) will be initialised here.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 103 ++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci.c      |  12 ++++
>  drivers/mmc/host/sdhci.h      |   1 +
>  3 files changed, 116 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index afaca5d96938..c9d59b8ac37f 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -350,6 +350,53 @@ static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>  	spin_unlock_irqrestore(&host->lock, flags);
>  }
>  
> +static void sdhci_uhs2_set_config(struct sdhci_host *host)
> +{
> +	u32 value;
> +	u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
> +	u16 sdhci_uhs2_gen_set_reg = (sdhci_uhs2_set_ptr + 0);
> +	u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
> +	u16 sdhci_uhs2_tran_set_reg = (sdhci_uhs2_set_ptr + 8);
> +	u16 sdhci_uhs2_tran_set_1_reg = (sdhci_uhs2_set_ptr + 12);
> +
> +	/* Set Gen Settings */
> +	sdhci_writel(host, host->mmc->uhs2_caps.n_lanes_set <<
> +		SDHCI_UHS2_GEN_SET_N_LANES_POS, sdhci_uhs2_gen_set_reg);
> +
> +	/* Set PHY Settings */
> +	value = (host->mmc->uhs2_caps.n_lss_dir_set <<
> +			SDHCI_UHS2_PHY_SET_N_LSS_DIR_POS) |
> +		(host->mmc->uhs2_caps.n_lss_sync_set <<
> +			SDHCI_UHS2_PHY_SET_N_LSS_SYN_POS);
> +	if (host->mmc->flags & MMC_UHS2_SPEED_B)
> +		value |= 1 << SDHCI_UHS2_PHY_SET_SPEED_POS;
> +	sdhci_writel(host, value, sdhci_uhs2_phy_set_reg);
> +
> +	/* Set LINK-TRAN Settings */
> +	value = (host->mmc->uhs2_caps.max_retry_set <<
> +			SDHCI_UHS2_TRAN_SET_RETRY_CNT_POS) |
> +		(host->mmc->uhs2_caps.n_fcu_set <<
> +			SDHCI_UHS2_TRAN_SET_N_FCU_POS);
> +	sdhci_writel(host, value, sdhci_uhs2_tran_set_reg);
> +	sdhci_writel(host, host->mmc->uhs2_caps.n_data_gap_set,
> +		     sdhci_uhs2_tran_set_1_reg);
> +}
> +
> +static int sdhci_uhs2_check_dormant(struct sdhci_host *host)
> +{
> +	u32 val;
> +	/* 100ms */
> +	int timeout = 100000;
> +
> +	if (read_poll_timeout_atomic(sdhci_readl, val, (val & SDHCI_UHS2_IN_DORMANT_STATE),
> +				     100, timeout, true, host, SDHCI_PRESENT_STATE)) {
> +		pr_warn("%s: UHS2 IN_DORMANT fail in 100ms.\n", mmc_hostname(host->mmc));
> +		sdhci_dumpregs(host);
> +		return -EIO;
> +	}
> +	return 0;
> +}
> +
>  /*****************************************************************************\
>   *                                                                           *
>   * MMC callbacks                                                             *
> @@ -435,6 +482,61 @@ static int sdhci_uhs2_enable_clk(struct mmc_host *mmc)
>  	return 0;
>  }
>  
> +static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc);
> +
> +static int sdhci_uhs2_control(struct mmc_host *mmc, enum sd_uhs2_operation op)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +	unsigned long flags;
> +	int err = 0;
> +	u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
> +	u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
> +
> +	DBG("Begin %s, act %d.\n", __func__, op);

DBG already has __func__.  Please also check other DBG that
have duplicate __func__

> +
> +	spin_lock_irqsave(&host->lock, flags);

This all relates to initialization or reinitialization, so I suspect
the spinlock is not needed here.  What could it be racing with?

> +
> +	switch (op) {
> +	case UHS2_PHY_INIT:
> +		err = sdhci_uhs2_do_detect_init(mmc);
> +		break;
> +	case UHS2_SET_CONFIG:
> +		sdhci_uhs2_set_config(host);
> +		break;
> +	case UHS2_ENABLE_INT:
> +		sdhci_clear_set_irqs(host, 0, SDHCI_INT_CARD_INT);
> +		break;
> +	case UHS2_DISABLE_INT:
> +		sdhci_clear_set_irqs(host, SDHCI_INT_CARD_INT, 0);
> +		break;
> +	case UHS2_SET_SPEED_B:
> +		sdhci_writeb(host, 1 << SDHCI_UHS2_PHY_SET_SPEED_POS,
> +			     sdhci_uhs2_phy_set_reg);
> +		break;
> +	case UHS2_CHECK_DORMANT:
> +		err = sdhci_uhs2_check_dormant(host);
> +		break;
> +	case UHS2_DISABLE_CLK:
> +		err = sdhci_uhs2_disable_clk(mmc);
> +		break;
> +	case UHS2_ENABLE_CLK:
> +		err = sdhci_uhs2_enable_clk(mmc);
> +		break;
> +	case UHS2_POST_ATTACH_SD:
> +		host->ops->uhs2_post_attach_sd(host);
> +		break;
> +	default:
> +		pr_err("%s: input sd uhs2 operation %d is wrong!\n",
> +		       mmc_hostname(host->mmc), op);
> +		err = -EIO;
> +		break;
> +	}
> +
> +	spin_unlock_irqrestore(&host->lock, flags);
> +
> +	return err;
> +}
> +
>  /*****************************************************************************\
>   *                                                                           *
>   * Driver init/exit                                                          *
> @@ -589,6 +691,7 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
>  	host->mmc_host_ops.start_signal_voltage_switch =
>  		sdhci_uhs2_start_signal_voltage_switch;
>  	host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
> +	host->mmc_host_ops.uhs2_control = sdhci_uhs2_control;
>  
>  	if (!host->mmc_host_ops.uhs2_detect_init)
>  		host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index de47c71995fb..b9db2e976010 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -236,6 +236,18 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
>  }
>  EXPORT_SYMBOL_GPL(sdhci_reset);
>  
> +void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
> +{
> +	u32 ier;
> +
> +	ier = sdhci_readl(host, SDHCI_INT_ENABLE);
> +	ier &= ~clear;
> +	ier |= set;
> +	sdhci_writel(host, ier, SDHCI_INT_ENABLE);
> +	sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_clear_set_irqs);

This might as well be in sdhci-uhs2.c since that is the only
place that calls it.  Then there is no need to export it.

> +
>  static bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
>  {
>  	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index 22d7f47862ae..f049331bd0bc 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -869,6 +869,7 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq);
>  int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
>  void sdhci_set_bus_width(struct sdhci_host *host, int width);
>  void sdhci_reset(struct sdhci_host *host, u8 mask);
> +void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
>  void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
>  int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
>  void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 19/26] mmc: sdhci-uhs2: add request() and others
  2022-10-19 11:06 ` [PATCH V5 19/26] mmc: sdhci-uhs2: add request() and others Victor Shih
@ 2022-11-01 17:15   ` Adrian Hunter
  2022-12-13  8:47     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:15 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> This is a sdhci version of mmc's request operation.
> It covers both UHS-I and UHS-II.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 475 ++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci.c      |  91 ++++---
>  drivers/mmc/host/sdhci.h      |  17 ++
>  3 files changed, 550 insertions(+), 33 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index c9d59b8ac37f..41b089ccc200 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -13,6 +13,7 @@
>  #include <linux/delay.h>
>  #include <linux/ktime.h>
>  #include <linux/module.h>
> +#include <linux/mmc/mmc.h>
>  
>  #include "sdhci.h"
>  #include "sdhci-uhs2.h"
> @@ -537,6 +538,479 @@ static int sdhci_uhs2_control(struct mmc_host *mmc, enum sd_uhs2_operation op)
>  	return err;
>  }
>  
> +/*****************************************************************************\
> + *                                                                           *
> + * Core functions                                                            *
> + *                                                                           *
> +\*****************************************************************************/
> +
> +static void sdhci_uhs2_prepare_data(struct sdhci_host *host,
> +				    struct mmc_command *cmd)
> +{
> +	struct mmc_data *data = cmd->data;
> +
> +	sdhci_initialize_data(host, data);
> +
> +	sdhci_prepare_dma(host, data);
> +
> +	sdhci_writew(host, data->blksz, SDHCI_UHS2_BLOCK_SIZE);
> +	sdhci_writew(host, data->blocks, SDHCI_UHS2_BLOCK_COUNT);
> +}
> +
> +#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
> +static void sdhci_uhs2_external_dma_prepare_data(struct sdhci_host *host,
> +						 struct mmc_command *cmd)
> +{
> +	if (!sdhci_external_dma_setup(host, cmd)) {
> +		__sdhci_external_dma_prepare_data(host, cmd);
> +	} else {
> +		sdhci_external_dma_release(host);
> +		pr_err("%s: Cannot use external DMA, switch to the DMA/PIO which standard SDHCI provides.\n",
> +		       mmc_hostname(host->mmc));
> +		sdhci_uhs2_prepare_data(host, cmd);
> +	}
> +}
> +#else
> +static inline void sdhci_uhs2_external_dma_prepare_data(struct sdhci_host *host,
> +							struct mmc_command *cmd)
> +{
> +	/* This should never happen */
> +	WARN_ON_ONCE(1);
> +}
> +
> +static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
> +						   struct mmc_command *cmd)
> +{
> +}
> +#endif /* CONFIG_MMC_SDHCI_EXTERNAL_DMA */

Let's skip external DMA support to start with.

> +
> +static void sdhci_uhs2_finish_data(struct sdhci_host *host)
> +{
> +	struct mmc_data *data = host->data;
> +
> +	__sdhci_finish_data_common(host);
> +
> +	/*
> +	 *  FIXME: Is this condition needed?
> +	    if (host->mmc->flags & MMC_UHS2_INITIALIZED)
> +	 */

No

> +	__sdhci_finish_mrq(host, data->mrq);
> +}
> +
> +static void sdhci_uhs2_set_transfer_mode(struct sdhci_host *host,
> +					 struct mmc_command *cmd)
> +{
> +	u16 mode;
> +	struct mmc_data *data = cmd->data;
> +	u16 arg;
> +
> +	if (!data) {
> +		/* clear Auto CMD settings for no data CMDs */
> +		arg = cmd->uhs2_cmd->arg;
> +		if ((((arg & 0xF) << 8) | ((arg >> 8) & 0xFF)) ==

Please don't open code byte-swapping

This should be an inline function so it can be used again
further below:

#define UHS2_ARG_IOADR_MASK 0xfff

static inline u16 uhs2_dev_cmd(struct mmc_command *cmd)
{
	return be16_to_cpu((__be16)cmd->uhs2_cmd->arg) & UHS2_ARG_IOADR_MASK;
}


> +		       UHS2_DEV_CMD_TRANS_ABORT) {

Please wrap at 100 columns instead of 80, here and elsewhere.

> +			mode =  0;
> +		} else {
> +			mode = sdhci_readw(host, SDHCI_UHS2_TRANS_MODE);
> +			if (cmd->opcode == MMC_STOP_TRANSMISSION ||
> +			    cmd->opcode == MMC_ERASE)
> +				mode |= SDHCI_UHS2_TRNS_WAIT_EBSY;
> +			else
> +				/* send status mode */
> +				if (cmd->opcode == MMC_SEND_STATUS)
> +					mode = 0;
> +		}
> +
> +		if (IS_ENABLED(CONFIG_MMC_DEBUG))

Please don't use CONFIG_MMC_DEBUG

> +			DBG("UHS2 no data trans mode is 0x%x.\n", mode);
> +
> +		sdhci_writew(host, mode, SDHCI_UHS2_TRANS_MODE);
> +		return;
> +	}
> +
> +	WARN_ON(!host->data);
> +
> +	mode = SDHCI_UHS2_TRNS_BLK_CNT_EN | SDHCI_UHS2_TRNS_WAIT_EBSY;
> +	if (data->flags & MMC_DATA_WRITE)
> +		mode |= SDHCI_UHS2_TRNS_DATA_TRNS_WRT;
> +
> +	if (data->blocks == 1 &&
> +	    data->blksz != 512 &&
> +	    cmd->opcode != MMC_READ_SINGLE_BLOCK &&
> +	    cmd->opcode != MMC_WRITE_BLOCK) {
> +		mode &= ~SDHCI_UHS2_TRNS_BLK_CNT_EN;
> +		mode |= SDHCI_UHS2_TRNS_BLK_BYTE_MODE;
> +	}
> +
> +	if (host->flags & SDHCI_REQ_USE_DMA)
> +		mode |= SDHCI_UHS2_TRNS_DMA;
> +
> +	if ((host->mmc->uhs2_ios.is_2L_HD_mode) && !cmd->uhs2_tmode0_flag)
> +		mode |= SDHCI_UHS2_TRNS_2L_HD;
> +
> +	sdhci_writew(host, mode, SDHCI_UHS2_TRANS_MODE);
> +
> +	if (IS_ENABLED(CONFIG_MMC_DEBUG))

Please don't use CONFIG_MMC_DEBUG

> +		DBG("UHS2 trans mode is 0x%x.\n", mode);
> +}
> +
> +static void __sdhci_uhs2_send_command(struct sdhci_host *host,
> +				      struct mmc_command *cmd)
> +{
> +	int i, j;
> +	int cmd_reg;
> +
> +	if (host->mmc->flags & MMC_UHS2_INITIALIZED) {

Not necessary to check MMC_UHS2_INITIALIZED here

> +		if (!cmd->uhs2_cmd) {
> +			pr_err("%s: fatal error, no uhs2_cmd!\n",
> +			       mmc_hostname(host->mmc));
> +			return;
> +		}
> +	}
> +
> +	i = 0;
> +	sdhci_writel(host,
> +		     ((u32)cmd->uhs2_cmd->arg << 16) |
> +				(u32)cmd->uhs2_cmd->header,
> +		     SDHCI_UHS2_CMD_PACKET + i);
> +	i += 4;
> +
> +	/*
> +	 * Per spec, playload (config) should be MSB before sending out.
> +	 * But we don't need convert here because had set payload as
> +	 * MSB when preparing config read/write commands.
> +	 */
> +	for (j = 0; j < cmd->uhs2_cmd->payload_len / sizeof(u32); j++) {
> +		sdhci_writel(host, *(cmd->uhs2_cmd->payload + j),
> +			     SDHCI_UHS2_CMD_PACKET + i);
> +		i += 4;
> +	}
> +
> +	for ( ; i < SDHCI_UHS2_CMD_PACK_MAX_LEN; i += 4)
> +		sdhci_writel(host, 0, SDHCI_UHS2_CMD_PACKET + i);
> +
> +	if (IS_ENABLED(CONFIG_MMC_DEBUG)) {

Please don't use CONFIG_MMC_DEBUG

> +		DBG("UHS2 CMD packet_len = %d.\n", cmd->uhs2_cmd->packet_len);
> +		for (i = 0; i < cmd->uhs2_cmd->packet_len; i++)
> +			DBG("UHS2 CMD_PACKET[%d] = 0x%x.\n", i,
> +			    sdhci_readb(host, SDHCI_UHS2_CMD_PACKET + i));
> +	}
> +
> +	cmd_reg = cmd->uhs2_cmd->packet_len <<
> +		SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT;
> +	if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC)
> +		cmd_reg |= SDHCI_UHS2_COMMAND_DATA;
> +	if (cmd->opcode == MMC_STOP_TRANSMISSION)
> +		cmd_reg |= SDHCI_UHS2_COMMAND_CMD12;
> +
> +	/* UHS2 Native ABORT */
> +	if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) &&
> +	    ((((cmd->uhs2_cmd->arg & 0xF) << 8) |
> +	    ((cmd->uhs2_cmd->arg >> 8) & 0xFF)) == UHS2_DEV_CMD_TRANS_ABORT))

 From above, can use (uhs2_dev_cmd(cmd) == UHS2_DEV_CMD_TRANS_ABORT)

> +		cmd_reg |= SDHCI_UHS2_COMMAND_TRNS_ABORT;
> +
> +	/* UHS2 Native DORMANT */
> +	if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) &&
> +	    ((((cmd->uhs2_cmd->arg & 0xF) << 8) |
> +	     ((cmd->uhs2_cmd->arg >> 8) & 0xFF)) ==
> +				UHS2_DEV_CMD_GO_DORMANT_STATE))

 From above, can use (uhs2_dev_cmd(cmd) == UHS2_DEV_CMD_GO_DORMANT_STATE)

> +		cmd_reg |= SDHCI_UHS2_COMMAND_DORMANT;
> +
> +	DBG("0x%x is set to UHS2 CMD register.\n", cmd_reg);
> +
> +	sdhci_writew(host, cmd_reg, SDHCI_UHS2_COMMAND);
> +}
> +
> +static bool sdhci_uhs2_send_command(struct sdhci_host *host,
> +				    struct mmc_command *cmd)
> +{
> +	int flags;
> +	u32 mask;
> +	unsigned long timeout;
> +
> +	WARN_ON(host->cmd);
> +
> +	/* Initially, a command has no error */
> +	cmd->error = 0;
> +
> +	if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
> +		return sdhci_send_command(host, cmd);

No check necessary, can remove, and please do not export
sdhci_send_command().

> +
> +	if (cmd->opcode == MMC_STOP_TRANSMISSION)
> +		cmd->flags |= MMC_RSP_BUSY;
> +
> +	mask = SDHCI_CMD_INHIBIT;
> +
> +	if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)
> +		return false;
> +
> +	host->cmd = cmd;
> +	host->data_timeout = 0;
> +	if (sdhci_data_line_cmd(cmd)) {
> +		WARN_ON(host->data_cmd);
> +		host->data_cmd = cmd;
> +		__sdhci_uhs2_set_timeout(host);
> +	}
> +
> +	if (cmd->data) {
> +		if (host->use_external_dma)

Let's skip external DMA support for now

> +			sdhci_uhs2_external_dma_prepare_data(host, cmd);
> +		else
> +			sdhci_uhs2_prepare_data(host, cmd);
> +	}
> +
> +	sdhci_uhs2_set_transfer_mode(host, cmd);
> +
> +	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
> +		WARN_ONCE(1, "Unsupported response type!\n");
> +		/*
> +		 * This does not happen in practice because 136-bit response
> +		 * commands never have busy waiting, so rather than complicate
> +		 * the error path, just remove busy waiting and continue.
> +		 */
> +		cmd->flags &= ~MMC_RSP_BUSY;
> +	}
> +
> +	if (!(cmd->flags & MMC_RSP_PRESENT))
> +		flags = SDHCI_CMD_RESP_NONE;
> +	else if (cmd->flags & MMC_RSP_136)
> +		flags = SDHCI_CMD_RESP_LONG;
> +	else if (cmd->flags & MMC_RSP_BUSY)
> +		flags = SDHCI_CMD_RESP_SHORT_BUSY;
> +	else
> +		flags = SDHCI_CMD_RESP_SHORT;
> +
> +	if (cmd->flags & MMC_RSP_CRC)
> +		flags |= SDHCI_CMD_CRC;
> +	if (cmd->flags & MMC_RSP_OPCODE)
> +		flags |= SDHCI_CMD_INDEX;
> +
> +	timeout = jiffies;
> +	if (host->data_timeout)
> +		timeout += nsecs_to_jiffies(host->data_timeout);
> +	else if (!cmd->data && cmd->busy_timeout > 9000)
> +		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
> +	else
> +		timeout += 10 * HZ;
> +	sdhci_mod_timer(host, cmd->mrq, timeout);
> +
> +	if (host->use_external_dma)
> +		sdhci_external_dma_pre_transfer(host, cmd);
> +
> +	__sdhci_uhs2_send_command(host, cmd);
> +
> +	return true;
> +}
> +
> +static bool sdhci_uhs2_send_command_retry(struct sdhci_host *host,
> +				     struct mmc_command *cmd,
> +				     unsigned long flags)
> +	__releases(host->lock)
> +	__acquires(host->lock)
> +{
> +	struct mmc_command *deferred_cmd = host->deferred_cmd;
> +	int timeout = 10; /* Approx. 10 ms */
> +	bool present;
> +
> +	while (!sdhci_uhs2_send_command(host, cmd)) {
> +		if (!timeout--) {
> +			pr_err("%s: Controller never released inhibit bit(s).\n",
> +			       mmc_hostname(host->mmc));
> +			sdhci_dumpregs(host);
> +			cmd->error = -EIO;
> +			return false;
> +		}
> +
> +		spin_unlock_irqrestore(&host->lock, flags);
> +
> +		usleep_range(1000, 1250);
> +
> +		present = host->mmc->ops->get_cd(host->mmc);
> +
> +		spin_lock_irqsave(&host->lock, flags);
> +
> +		/* A deferred command might disappear, handle that */
> +		if (cmd == deferred_cmd && cmd != host->deferred_cmd)
> +			return true;
> +
> +		if (sdhci_present_error(host, cmd, present))
> +			return false;
> +	}
> +
> +	if (cmd == host->deferred_cmd)
> +		host->deferred_cmd = NULL;
> +
> +	return true;
> +}
> +
> +static void __sdhci_uhs2_finish_command(struct sdhci_host *host)
> +{
> +	struct mmc_command *cmd = host->cmd;
> +	u8 resp;
> +	u8 ecode;
> +	bool bReadA0 = 0;
> +	int i;
> +
> +	if (host->mmc->flags & MMC_UHS2_INITIALIZED) {
> +		resp = sdhci_readb(host, SDHCI_UHS2_RESPONSE + 2);
> +		if (resp & UHS2_RES_NACK_MASK) {
> +			ecode = (resp >> UHS2_RES_ECODE_POS) &
> +				UHS2_RES_ECODE_MASK;
> +			pr_err("%s: NACK is got, ECODE=0x%x.\n",
> +			       mmc_hostname(host->mmc), ecode);
> +		}
> +		bReadA0 = 1;
> +	}
> +
> +	if (cmd->uhs2_resp &&
> +	    cmd->uhs2_resp_len && cmd->uhs2_resp_len <= 20) {
> +		/* Get whole response of some native CCMD, like
> +		 * DEVICE_INIT, ENUMERATE.
> +		 */
> +		for (i = 0; i < cmd->uhs2_resp_len; i++)
> +			cmd->uhs2_resp[i] =
> +				sdhci_readb(host, SDHCI_UHS2_RESPONSE + i);
> +	} else {
> +		/* Get SD CMD response and Payload for some read
> +		 * CCMD, like INQUIRY_CFG.
> +		 */
> +		/* Per spec (p136), payload field is divided into
> +		 * a unit of DWORD and transmission order within
> +		 * a DWORD is big endian.
> +		 */
> +		if (!bReadA0)
> +			sdhci_readl(host, SDHCI_UHS2_RESPONSE);
> +		for (i = 4; i < 20; i += 4) {
> +			cmd->resp[i / 4 - 1] =
> +				(sdhci_readb(host,
> +					     SDHCI_UHS2_RESPONSE + i) << 24) |
> +				(sdhci_readb(host,
> +					     SDHCI_UHS2_RESPONSE + i + 1)
> +					<< 16) |
> +				(sdhci_readb(host,
> +					     SDHCI_UHS2_RESPONSE + i + 2)
> +					<< 8) |
> +				sdhci_readb(host, SDHCI_UHS2_RESPONSE + i + 3);
> +		}
> +	}
> +}
> +
> +static void sdhci_uhs2_finish_command(struct sdhci_host *host)
> +{
> +	struct mmc_command *cmd = host->cmd;
> +
> +	/* FIXME: Is this check necessary? */

No

> +	if (!(host->mmc->flags & MMC_UHS2_SUPPORT)) {
> +		sdhci_finish_command(host);

Please do not export sdhci_finish_command()

> +		return;
> +	}
> +
> +	__sdhci_uhs2_finish_command(host);
> +
> +	host->cmd = NULL;
> +
> +	if (cmd->mrq->cap_cmd_during_tfr && cmd == cmd->mrq->cmd)
> +		mmc_command_done(host->mmc, cmd->mrq);
> +
> +	/*
> +	 * The host can send and interrupt when the busy state has
> +	 * ended, allowing us to wait without wasting CPU cycles.
> +	 * The busy signal uses DAT0 so this is similar to waiting
> +	 * for data to complete.
> +	 *
> +	 * Note: The 1.0 specification is a bit ambiguous about this
> +	 *       feature so there might be some problems with older
> +	 *       controllers.
> +	 */
> +	if (cmd->flags & MMC_RSP_BUSY) {
> +		if (cmd->data) {
> +			DBG("Cannot wait for busy signal when also doing a data transfer");
> +		} else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) &&
> +			   cmd == host->data_cmd) {
> +			/* Command complete before busy is ended */
> +			return;
> +		}
> +	}
> +
> +	/* Processed actual command. */
> +	if (host->data && host->data_early)
> +		sdhci_uhs2_finish_data(host);
> +
> +	if (!cmd->data)
> +		__sdhci_finish_mrq(host, cmd->mrq);
> +}
> +
> +void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +	struct mmc_command *cmd;
> +	unsigned long flags;
> +	bool present;
> +
> +	/* FIXME: check more flags? */

No, it's fine.

> +	if (!(sdhci_uhs2_mode(host))) {
> +		sdhci_request(mmc, mrq);
> +		return;
> +	}

We need to clear the stop cmd and sbc to prevent the
driver using them.

	mrq->stop = NULL;
	mrq->sbc = NULL;
	if (mrq->data)
		mrq->data->stop = NULL;

> +
> +	/* Firstly check card presence */
> +	present = mmc->ops->get_cd(mmc);
> +
> +	spin_lock_irqsave(&host->lock, flags);
> +
> +	if (sdhci_present_error(host, mrq->cmd, present))
> +		goto out_finish;
> +
> +	cmd = mrq->cmd;
> +
> +	if (!sdhci_uhs2_send_command(host, cmd))
> +		goto out_finish;
> +
> +	spin_unlock_irqrestore(&host->lock, flags);
> +
> +	return;
> +
> +out_finish:
> +	sdhci_finish_mrq(host, mrq);
> +	spin_unlock_irqrestore(&host->lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_request);
> +
> +int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +	struct mmc_command *cmd;
> +	unsigned long flags;
> +	int ret = 0;
> +
> +	if (!host->mmc->flags & MMC_UHS2_SUPPORT)
> +		return sdhci_request_atomic(mmc, mrq);
> +
> +	spin_lock_irqsave(&host->lock, flags);
> +
> +	if (sdhci_present_error(host, mrq->cmd, true)) {
> +		sdhci_finish_mrq(host, mrq);
> +		goto out_finish;
> +	}
> +
> +	cmd = mrq->cmd;
> +
> +	/*
> +	 * The HSQ may send a command in interrupt context without polling
> +	 * the busy signaling, which means we should return BUSY if controller
> +	 * has not released inhibit bits to allow HSQ trying to send request
> +	 * again in non-atomic context. So we should not finish this request
> +	 * here.
> +	 */
> +	if (!sdhci_uhs2_send_command(host, cmd))
> +		ret = -EBUSY;
> +
> +out_finish:
> +	spin_unlock_irqrestore(&host->lock, flags);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_request_atomic);
> +
>  /*****************************************************************************\
>   *                                                                           *
>   * Driver init/exit                                                          *
> @@ -692,6 +1166,7 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
>  		sdhci_uhs2_start_signal_voltage_switch;
>  	host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
>  	host->mmc_host_ops.uhs2_control = sdhci_uhs2_control;
> +	host->mmc_host_ops.request = sdhci_uhs2_request;
>  
>  	if (!host->mmc_host_ops.uhs2_detect_init)
>  		host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index b9db2e976010..407169468927 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -47,8 +47,6 @@
>  static unsigned int debug_quirks = 0;
>  static unsigned int debug_quirks2;
>  
> -static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
> -
>  void sdhci_dumpregs(struct sdhci_host *host)
>  {
>  	SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n");
> @@ -147,10 +145,11 @@ void sdhci_enable_v4_mode(struct sdhci_host *host)
>  }
>  EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode);
>  
> -static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
> +bool sdhci_data_line_cmd(struct mmc_command *cmd)
>  {
>  	return cmd->data || cmd->flags & MMC_RSP_BUSY;
>  }
> +EXPORT_SYMBOL_GPL(sdhci_data_line_cmd);
>  
>  static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
>  {
> @@ -409,7 +408,7 @@ static void sdhci_reinit(struct sdhci_host *host)
>  		mmc_detect_change(host->mmc, msecs_to_jiffies(200));
>  }
>  
> -static void __sdhci_led_activate(struct sdhci_host *host)
> +void __sdhci_led_activate(struct sdhci_host *host)
>  {
>  	u8 ctrl;
>  
> @@ -420,8 +419,9 @@ static void __sdhci_led_activate(struct sdhci_host *host)
>  	ctrl |= SDHCI_CTRL_LED;
>  	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
>  }
> +EXPORT_SYMBOL_GPL(__sdhci_led_activate);

The LED functions like __sdhci_led_activate() are not being used
and don't need to be exported.

>  
> -static void __sdhci_led_deactivate(struct sdhci_host *host)
> +void __sdhci_led_deactivate(struct sdhci_host *host)
>  {
>  	u8 ctrl;
>  
> @@ -432,6 +432,7 @@ static void __sdhci_led_deactivate(struct sdhci_host *host)
>  	ctrl &= ~SDHCI_CTRL_LED;
>  	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
>  }
> +EXPORT_SYMBOL_GPL(__sdhci_led_deactivate);
>  
>  #if IS_REACHABLE(CONFIG_LEDS_CLASS)
>  static void sdhci_led_control(struct led_classdev *led,
> @@ -510,14 +511,15 @@ static inline void sdhci_led_deactivate(struct sdhci_host *host)
>  
>  #endif
>  
> -static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
> -			    unsigned long timeout)
> +void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
> +		     unsigned long timeout)
>  {
>  	if (sdhci_data_line_cmd(mrq->cmd))
>  		mod_timer(&host->data_timer, timeout);
>  	else
>  		mod_timer(&host->timer, timeout);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_mod_timer);
>  
>  static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
>  {
> @@ -1098,8 +1100,7 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>  		__sdhci_set_timeout(host, cmd);
>  }
>  
> -static void sdhci_initialize_data(struct sdhci_host *host,
> -				  struct mmc_data *data)
> +void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data)
>  {
>  	WARN_ON(host->data);
>  
> @@ -1112,6 +1113,7 @@ static void sdhci_initialize_data(struct sdhci_host *host,
>  	host->data_early = 0;
>  	host->data->bytes_xfered = 0;
>  }
> +EXPORT_SYMBOL_GPL(sdhci_initialize_data);
>  
>  static inline void sdhci_set_block_info(struct sdhci_host *host,
>  					struct mmc_data *data)
> @@ -1134,12 +1136,8 @@ static inline void sdhci_set_block_info(struct sdhci_host *host,
>  	}
>  }
>  
> -static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
> +void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data)
>  {
> -	struct mmc_data *data = cmd->data;
> -
> -	sdhci_initialize_data(host, data);
> -
>  	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
>  		struct scatterlist *sg;
>  		unsigned int length_mask, offset_mask;
> @@ -1224,6 +1222,16 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
>  	}
>  
>  	sdhci_set_transfer_irqs(host);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_prepare_dma);
> +
> +static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
> +{
> +	struct mmc_data *data = cmd->data;
> +
> +	sdhci_initialize_data(host, data);
> +
> +	sdhci_prepare_dma(host, data);
>  
>  	sdhci_set_block_info(host, data);
>  }
> @@ -1266,8 +1274,7 @@ static struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
>  	return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
>  }
>  
> -static int sdhci_external_dma_setup(struct sdhci_host *host,
> -				    struct mmc_command *cmd)
> +int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd)
>  {
>  	int ret, i;
>  	enum dma_transfer_direction dir;
> @@ -1320,8 +1327,9 @@ static int sdhci_external_dma_setup(struct sdhci_host *host,
>  
>  	return ret;
>  }
> +EXPORT_SYMBOL_GPL(sdhci_external_dma_setup);
>  
> -static void sdhci_external_dma_release(struct sdhci_host *host)
> +void sdhci_external_dma_release(struct sdhci_host *host)
>  {
>  	if (host->tx_chan) {
>  		dma_release_channel(host->tx_chan);
> @@ -1335,9 +1343,10 @@ static void sdhci_external_dma_release(struct sdhci_host *host)
>  
>  	sdhci_switch_external_dma(host, false);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_external_dma_release);
>  
> -static void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
> -					      struct mmc_command *cmd)
> +void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
> +				       struct mmc_command *cmd)
>  {
>  	struct mmc_data *data = cmd->data;
>  
> @@ -1348,6 +1357,7 @@ static void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
>  
>  	sdhci_set_block_info(host, data);
>  }
> +EXPORT_SYMBOL(__sdhci_external_dma_prepare_data);
>  
>  static void sdhci_external_dma_prepare_data(struct sdhci_host *host,
>  					    struct mmc_command *cmd)
> @@ -1362,8 +1372,8 @@ static void sdhci_external_dma_prepare_data(struct sdhci_host *host,
>  	}
>  }
>  
> -static void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
> -					    struct mmc_command *cmd)
> +void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
> +				     struct mmc_command *cmd)
>  {
>  	struct dma_chan *chan;
>  
> @@ -1374,6 +1384,7 @@ static void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
>  	if (chan)
>  		dma_async_issue_pending(chan);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_external_dma_pre_transfer);
>  
>  #else
>  
> @@ -1425,11 +1436,11 @@ static inline bool sdhci_auto_cmd23(struct sdhci_host *host,
>  	return mrq->sbc && (host->flags & SDHCI_AUTO_CMD23);
>  }
>  
> -static inline bool sdhci_manual_cmd23(struct sdhci_host *host,
> -				      struct mmc_request *mrq)
> +bool sdhci_manual_cmd23(struct sdhci_host *host, struct mmc_request *mrq)
>  {
>  	return mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_manual_cmd23);

Also don't see sdhci_manual_cmd23() being used.
Please check what is being exported.

>  
>  static inline void sdhci_auto_cmd_select(struct sdhci_host *host,
>  					 struct mmc_command *cmd,
> @@ -1541,7 +1552,7 @@ static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
>  	WARN_ON(i >= SDHCI_MAX_MRQS);
>  }
>  
> -static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
> +void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
>  {
>  	if (host->cmd && host->cmd->mrq == mrq)
>  		host->cmd = NULL;
> @@ -1565,15 +1576,17 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
>  	if (!sdhci_has_requests(host))
>  		sdhci_led_deactivate(host);
>  }
> +EXPORT_SYMBOL_GPL(__sdhci_finish_mrq);
>  
> -static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
> +void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
>  {
>  	__sdhci_finish_mrq(host, mrq);
>  
>  	queue_work(host->complete_wq, &host->complete_work);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_finish_mrq);
>  
> -static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
> +void __sdhci_finish_data_common(struct sdhci_host *host)
>  {
>  	struct mmc_command *data_cmd = host->data_cmd;
>  	struct mmc_data *data = host->data;
> @@ -1607,6 +1620,14 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
>  		data->bytes_xfered = 0;
>  	else
>  		data->bytes_xfered = data->blksz * data->blocks;
> +}
> +EXPORT_SYMBOL_GPL(__sdhci_finish_data_common);
> +
> +static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
> +{
> +	struct mmc_data *data = host->data;
> +
> +	__sdhci_finish_data_common(host);
>  
>  	/*
>  	 * Need to send CMD12 if -
> @@ -1645,12 +1666,13 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
>  	}
>  }
>  
> -static void sdhci_finish_data(struct sdhci_host *host)
> +void sdhci_finish_data(struct sdhci_host *host)
>  {
>  	__sdhci_finish_data(host, false);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_finish_data);

Also don't see sdhci_finish_data() being used.
Please check what is being exported.

>  
> -static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
> +bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>  {
>  	int flags;
>  	u32 mask;
> @@ -1692,8 +1714,6 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>  			sdhci_prepare_data(host, cmd);
>  	}
>  
> -	sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
> -
>  	sdhci_set_transfer_mode(host, cmd);
>  
>  	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
> @@ -1737,13 +1757,16 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>  	if (host->use_external_dma)
>  		sdhci_external_dma_pre_transfer(host, cmd);
>  
> +	sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);

If this move of "sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT)"
is intentional, it should be a separate patch.

> +
>  	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
>  
>  	return true;
>  }
> +EXPORT_SYMBOL_GPL(sdhci_send_command);

It is not necessary to export sdhci_send_command()

>  
> -static bool sdhci_present_error(struct sdhci_host *host,
> -				struct mmc_command *cmd, bool present)
> +bool sdhci_present_error(struct sdhci_host *host,
> +			 struct mmc_command *cmd, bool present)
>  {
>  	if (!present || host->flags & SDHCI_DEVICE_DEAD) {
>  		cmd->error = -ENOMEDIUM;
> @@ -1752,6 +1775,7 @@ static bool sdhci_present_error(struct sdhci_host *host,
>  
>  	return false;
>  }
> +EXPORT_SYMBOL_GPL(sdhci_present_error);
>  
>  static bool sdhci_send_command_retry(struct sdhci_host *host,
>  				     struct mmc_command *cmd,
> @@ -1815,7 +1839,7 @@ static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd)
>  	}
>  }
>  
> -static void sdhci_finish_command(struct sdhci_host *host)
> +void sdhci_finish_command(struct sdhci_host *host)
>  {
>  	struct mmc_command *cmd = host->cmd;
>  
> @@ -1868,6 +1892,7 @@ static void sdhci_finish_command(struct sdhci_host *host)
>  			__sdhci_finish_mrq(host, cmd->mrq);
>  	}
>  }
> +EXPORT_SYMBOL_GPL(sdhci_finish_command);

It is not necessary to export sdhci_finish_command()

>  
>  static u16 sdhci_get_preset_value(struct sdhci_host *host)
>  {
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index f049331bd0bc..1a9924e7972d 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -850,8 +850,25 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
>  	__sdhci_read_caps(host, NULL, NULL, NULL);
>  }
>  
> +bool sdhci_data_line_cmd(struct mmc_command *cmd);
>  void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
>  void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
> +void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, unsigned long timeout);
> +void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data);
> +void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data);
> +#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
> +int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd);
> +void sdhci_external_dma_release(struct sdhci_host *host);
> +void __sdhci_external_dma_prepare_data(struct sdhci_host *host, struct mmc_command *cmd);
> +void sdhci_external_dma_pre_transfer(struct sdhci_host *host, struct mmc_command *cmd);
> +#endif
> +bool sdhci_manual_cmd23(struct sdhci_host *host, struct mmc_request *mrq);
> +void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
> +void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
> +void __sdhci_finish_data_common(struct sdhci_host *host);
> +bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
> +void sdhci_finish_command(struct sdhci_host *host);
> +bool sdhci_present_error(struct sdhci_host *host, struct mmc_command *cmd, bool present);
>  u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
>  		   unsigned int *actual_clock);
>  void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 20/26] mmc: sdhci-uhs2: add irq() and others
  2022-10-19 11:06 ` [PATCH V5 20/26] mmc: sdhci-uhs2: add irq() " Victor Shih
@ 2022-11-01 17:15   ` Adrian Hunter
  2022-12-13  8:48     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:15 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> This is a UHS-II version of sdhci's request() operation.
> It handles UHS-II related command interrupts and errors.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 237 ++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-uhs2.h |   3 +
>  drivers/mmc/host/sdhci.c      | 106 ++++++++-------
>  drivers/mmc/host/sdhci.h      |   5 +
>  4 files changed, 304 insertions(+), 47 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index 41b089ccc200..883e18d849ad 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -11,6 +11,7 @@
>   */
>  
>  #include <linux/delay.h>
> +#include <linux/dmaengine.h>
>  #include <linux/ktime.h>
>  #include <linux/module.h>
>  #include <linux/mmc/mmc.h>
> @@ -582,6 +583,12 @@ static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
>  						   struct mmc_command *cmd)
>  {
>  }
> +
> +static inline struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
> +							  struct mmc_data *data)
> +{
> +	return NULL;
> +}
>  #endif /* CONFIG_MMC_SDHCI_EXTERNAL_DMA */
>  
>  static void sdhci_uhs2_finish_data(struct sdhci_host *host)
> @@ -940,6 +947,236 @@ static void sdhci_uhs2_finish_command(struct sdhci_host *host)
>  		__sdhci_finish_mrq(host, cmd->mrq);
>  }
>  
> +/*****************************************************************************\
> + *                                                                           *
> + * Request done                                                              *
> + *                                                                           *
> +\*****************************************************************************/
> +
> +static bool sdhci_uhs2_request_done(struct sdhci_host *host)
> +{
> +	unsigned long flags;
> +	struct mmc_request *mrq;
> +	int i;
> +
> +	/* FIXME: UHS2_INITIALIZED, instead? */
> +	if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
> +		return sdhci_request_done(host);

Please do not put this check here, and sdhci_request_done()
does not need to be exported.

> +
> +	spin_lock_irqsave(&host->lock, flags);
> +
> +	for (i = 0; i < SDHCI_MAX_MRQS; i++) {
> +		mrq = host->mrqs_done[i];
> +		if (mrq)
> +			break;
> +	}
> +
> +	if (!mrq) {
> +		spin_unlock_irqrestore(&host->lock, flags);
> +		return true;
> +	}
> +
> +	/*
> +	 * Always unmap the data buffers if they were mapped by
> +	 * sdhci_prepare_data() whenever we finish with a request.
> +	 * This avoids leaking DMA mappings on error.
> +	 */
> +	if (host->flags & SDHCI_REQ_USE_DMA) {
> +		struct mmc_data *data = mrq->data;
> +
> +		if (host->use_external_dma && data &&
> +		    (mrq->cmd->error || data->error)) {
> +			struct dma_chan *chan = sdhci_external_dma_channel(host, data);
> +
> +			host->mrqs_done[i] = NULL;
> +			spin_unlock_irqrestore(&host->lock, flags);
> +			dmaengine_terminate_sync(chan);
> +			spin_lock_irqsave(&host->lock, flags);
> +			sdhci_set_mrq_done(host, mrq);
> +		}
> +
> +		sdhci_request_done_dma(host, mrq);
> +	}
> +
> +	/*
> +	 * The controller needs a reset of internal state machines
> +	 * upon error conditions.
> +	 */
> +	if (sdhci_needs_reset(host, mrq)) {
> +		/*
> +		 * Do not finish until command and data lines are available for
> +		 * reset. Note there can only be one other mrq, so it cannot
> +		 * also be in mrqs_done, otherwise host->cmd and host->data_cmd
> +		 * would both be null.
> +		 */
> +		if (host->cmd || host->data_cmd) {
> +			spin_unlock_irqrestore(&host->lock, flags);
> +			return true;
> +		}
> +
> +		/* Some controllers need this kick or reset won't work here */
> +		if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
> +			/* This is to force an update */
> +			host->ops->set_clock(host, host->clock);
> +
> +		host->ops->uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD);
> +		host->pending_reset = false;
> +	}
> +
> +	host->mrqs_done[i] = NULL;
> +
> +	spin_unlock_irqrestore(&host->lock, flags);
> +
> +	if (host->ops->request_done)
> +		host->ops->request_done(host, mrq);
> +	else
> +		mmc_request_done(host->mmc, mrq);
> +
> +	return false;
> +}
> +
> +static void sdhci_uhs2_complete_work(struct work_struct *work)
> +{
> +	struct sdhci_host *host = container_of(work, struct sdhci_host,
> +					       complete_work);

Put a check for UHS2 mode here:

	if (sdhci_uhs2_mode(host)) {
		sdhci_complete_work(work);
		return;
	}

> +
> +	while (!sdhci_uhs2_request_done(host))
> +		;
> +}
> +
> +/*****************************************************************************\
> + *                                                                           *
> + * Interrupt handling                                                        *
> + *                                                                           *
> +\*****************************************************************************/
> +
> +static void __sdhci_uhs2_irq(struct sdhci_host *host, u32 uhs2mask)
> +{
> +	struct mmc_command *cmd = host->cmd;
> +
> +	DBG("*** %s got UHS2 error interrupt: 0x%08x\n",
> +	    mmc_hostname(host->mmc), uhs2mask);
> +
> +	if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_CMD_MASK) {
> +		if (!host->cmd) {
> +			pr_err("%s: Got cmd interrupt 0x%08x but no cmd.\n",
> +			       mmc_hostname(host->mmc),
> +			       (unsigned int)uhs2mask);
> +			sdhci_dumpregs(host);
> +			return;
> +		}
> +		host->cmd->error = -EILSEQ;
> +		if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT)
> +			host->cmd->error = -ETIMEDOUT;
> +	}
> +
> +	if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_DATA_MASK) {
> +		if (!host->data) {
> +			pr_err("%s: Got data interrupt 0x%08x but no data.\n",
> +			       mmc_hostname(host->mmc),
> +			       (unsigned int)uhs2mask);
> +			sdhci_dumpregs(host);
> +			return;
> +		}
> +
> +		if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT) {
> +			pr_err("%s: Got deadlock timeout interrupt 0x%08x\n",
> +			       mmc_hostname(host->mmc),
> +			       (unsigned int)uhs2mask);
> +			host->data->error = -ETIMEDOUT;
> +		} else if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_ADMA) {
> +			pr_err("%s: ADMA error = 0x %x\n",
> +			       mmc_hostname(host->mmc),
> +			       sdhci_readb(host, SDHCI_ADMA_ERROR));
> +			host->data->error = -EIO;
> +		} else {
> +			host->data->error = -EILSEQ;
> +		}
> +	}
> +
> +	if (host->data && host->data->error)
> +		sdhci_uhs2_finish_data(host);
> +	else
> +		sdhci_finish_mrq(host, cmd->mrq);
> +}
> +
> +u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask)
> +{
> +	u32 mask = intmask, uhs2mask;
> +
> +	if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
> +		goto out;
> +
> +	if (intmask & SDHCI_INT_ERROR) {
> +		uhs2mask = sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS);
> +		if (!(uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_MASK))
> +			goto cmd_irq;
> +
> +		/* Clear error interrupts */
> +		sdhci_writel(host, uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_MASK,
> +			     SDHCI_UHS2_ERR_INT_STATUS);
> +
> +		/* Handle error interrupts */
> +		__sdhci_uhs2_irq(host, uhs2mask);
> +
> +		/* Caller, shdci_irq(), doesn't have to care UHS-2 errors */
> +		intmask &= ~SDHCI_INT_ERROR;
> +		mask &= SDHCI_INT_ERROR;
> +	}
> +
> +cmd_irq:
> +	if (intmask & SDHCI_INT_CMD_MASK) {
> +		/* Clear command interrupt */
> +		sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, SDHCI_INT_STATUS);
> +
> +		/* Handle command interrupt */
> +		if (intmask & SDHCI_INT_RESPONSE)
> +			sdhci_uhs2_finish_command(host);
> +
> +		/* Caller, shdci_irq(), doesn't have to care UHS-2 command */
> +		intmask &= ~SDHCI_INT_CMD_MASK;
> +		mask &= SDHCI_INT_CMD_MASK;
> +	}
> +
> +	/* Clear already-handled interrupts. */
> +	sdhci_writel(host, mask, SDHCI_INT_STATUS);
> +
> +out:
> +	return intmask;
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_irq);
> +
> +static irqreturn_t sdhci_uhs2_thread_irq(int irq, void *dev_id)
> +{
> +	struct sdhci_host *host = dev_id;
> +	struct mmc_command *cmd;
> +	unsigned long flags;
> +	u32 isr;

Put a check for UHS2 mode here:

	if (sdhci_uhs2_mode(host))
		return sdhci_uhs2_thread_irq(irq, dev_id);

> +
> +	while (!sdhci_uhs2_request_done(host))
> +		;
> +
> +	spin_lock_irqsave(&host->lock, flags);
> +
> +	isr = host->thread_isr;
> +	host->thread_isr = 0;
> +
> +	cmd = host->deferred_cmd;
> +	if (cmd && !sdhci_uhs2_send_command_retry(host, cmd, flags))
> +		sdhci_finish_mrq(host, cmd->mrq);
> +
> +	spin_unlock_irqrestore(&host->lock, flags);
> +
> +	if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
> +		struct mmc_host *mmc = host->mmc;
> +
> +		mmc->ops->card_event(mmc);
> +		mmc_detect_change(mmc, msecs_to_jiffies(200));
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
>  void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
>  {
>  	struct sdhci_host *host = mmc_priv(mmc);
> diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> index 23368448ccd4..d32a8602d045 100644
> --- a/drivers/mmc/host/sdhci-uhs2.h
> +++ b/drivers/mmc/host/sdhci-uhs2.h
> @@ -217,5 +217,8 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
>  			  unsigned short vdd);
>  void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
>  void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
> +void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq);
> +int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
> +u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask);
>  
>  #endif /* __SDHCI_UHS2_H */
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 407169468927..e44ede049559 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -1268,11 +1268,12 @@ static int sdhci_external_dma_init(struct sdhci_host *host)
>  	return ret;
>  }
>  
> -static struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
> -						   struct mmc_data *data)
> +struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
> +					    struct mmc_data *data)
>  {
>  	return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
>  }
> +EXPORT_SYMBOL_GPL(sdhci_external_dma_channel);
>  
>  int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd)
>  {
> @@ -1522,7 +1523,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
>  	sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
>  }
>  
> -static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
> +bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
>  {
>  	return (!(host->flags & SDHCI_DEVICE_DEAD) &&
>  		((mrq->cmd && mrq->cmd->error) ||
> @@ -1530,8 +1531,9 @@ static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
>  		 (mrq->data && mrq->data->stop && mrq->data->stop->error) ||
>  		 (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
>  }
> +EXPORT_SYMBOL_GPL(sdhci_needs_reset);
>  
> -static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
> +void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
>  {
>  	int i;
>  
> @@ -1551,6 +1553,7 @@ static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
>  
>  	WARN_ON(i >= SDHCI_MAX_MRQS);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_set_mrq_done);
>  
>  void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
>  {
> @@ -3103,7 +3106,56 @@ static const struct mmc_host_ops sdhci_ops = {
>   *                                                                           *
>  \*****************************************************************************/
>  
> -static bool sdhci_request_done(struct sdhci_host *host)
> +void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq)
> +{
> +	struct mmc_data *data = mrq->data;
> +
> +	if (data && data->host_cookie == COOKIE_MAPPED) {
> +		if (host->bounce_buffer) {
> +			/*
> +			 * On reads, copy the bounced data into the
> +			 * sglist
> +			 */
> +			if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
> +				unsigned int length = data->bytes_xfered;
> +
> +				if (length > host->bounce_buffer_size) {
> +					pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
> +					       mmc_hostname(host->mmc),
> +					       host->bounce_buffer_size,
> +					       data->bytes_xfered);
> +					/* Cap it down and continue */
> +					length = host->bounce_buffer_size;
> +				}
> +				dma_sync_single_for_cpu(
> +					host->mmc->parent,
> +					host->bounce_addr,
> +					host->bounce_buffer_size,
> +					DMA_FROM_DEVICE);
> +				sg_copy_from_buffer(data->sg,
> +					data->sg_len,
> +					host->bounce_buffer,
> +					length);
> +			} else {
> +				/* No copying, just switch ownership */
> +				dma_sync_single_for_cpu(
> +					host->mmc->parent,
> +					host->bounce_addr,
> +					host->bounce_buffer_size,
> +					mmc_get_dma_dir(data));
> +			}
> +		} else {
> +			/* Unmap the raw data */
> +			dma_unmap_sg(mmc_dev(host->mmc), data->sg,
> +				     data->sg_len,
> +				     mmc_get_dma_dir(data));
> +		}
> +		data->host_cookie = COOKIE_UNMAPPED;
> +	}
> +}
> +EXPORT_SYMBOL_GPL(sdhci_request_done_dma);
> +
> +bool sdhci_request_done(struct sdhci_host *host)
>  {
>  	unsigned long flags;
>  	struct mmc_request *mrq;
> @@ -3167,48 +3219,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
>  			sdhci_set_mrq_done(host, mrq);
>  		}
>  
> -		if (data && data->host_cookie == COOKIE_MAPPED) {
> -			if (host->bounce_buffer) {
> -				/*
> -				 * On reads, copy the bounced data into the
> -				 * sglist
> -				 */
> -				if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
> -					unsigned int length = data->bytes_xfered;
> -
> -					if (length > host->bounce_buffer_size) {
> -						pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
> -						       mmc_hostname(host->mmc),
> -						       host->bounce_buffer_size,
> -						       data->bytes_xfered);
> -						/* Cap it down and continue */
> -						length = host->bounce_buffer_size;
> -					}
> -					dma_sync_single_for_cpu(
> -						mmc_dev(host->mmc),
> -						host->bounce_addr,
> -						host->bounce_buffer_size,
> -						DMA_FROM_DEVICE);
> -					sg_copy_from_buffer(data->sg,
> -						data->sg_len,
> -						host->bounce_buffer,
> -						length);
> -				} else {
> -					/* No copying, just switch ownership */
> -					dma_sync_single_for_cpu(
> -						mmc_dev(host->mmc),
> -						host->bounce_addr,
> -						host->bounce_buffer_size,
> -						mmc_get_dma_dir(data));
> -				}
> -			} else {
> -				/* Unmap the raw data */
> -				dma_unmap_sg(mmc_dev(host->mmc), data->sg,
> -					     data->sg_len,
> -					     mmc_get_dma_dir(data));
> -			}
> -			data->host_cookie = COOKIE_UNMAPPED;
> -		}
> +		sdhci_request_done_dma(host, mrq);
>  	}
>  
>  	host->mrqs_done[i] = NULL;
> @@ -3222,6 +3233,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
>  
>  	return false;
>  }
> +EXPORT_SYMBOL_GPL(sdhci_request_done);
>  
>  static void sdhci_complete_work(struct work_struct *work)
>  {
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index 1a9924e7972d..49de8fdbd7a3 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -861,8 +861,11 @@ int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd);
>  void sdhci_external_dma_release(struct sdhci_host *host);
>  void __sdhci_external_dma_prepare_data(struct sdhci_host *host, struct mmc_command *cmd);
>  void sdhci_external_dma_pre_transfer(struct sdhci_host *host, struct mmc_command *cmd);
> +struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host, struct mmc_data *data);
>  #endif
>  bool sdhci_manual_cmd23(struct sdhci_host *host, struct mmc_request *mrq);
> +bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq);
> +void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq);
>  void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
>  void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
>  void __sdhci_finish_data_common(struct sdhci_host *host);
> @@ -895,6 +898,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
>  int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
>  				      struct mmc_ios *ios);
>  void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
> +void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq);
> +bool sdhci_request_done(struct sdhci_host *host);
>  void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
>  			   dma_addr_t addr, int len, unsigned int cmd);
>  


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 21/26] mmc: sdhci-uhs2: add add_host() and others to set up the driver
  2022-10-19 11:06 ` [PATCH V5 21/26] mmc: sdhci-uhs2: add add_host() and others to set up the driver Victor Shih
@ 2022-11-01 17:15   ` Adrian Hunter
  2022-12-13  8:48     ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:15 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih, Ben Chuang

On 19/10/22 14:06, Victor Shih wrote:
> This is a UHS-II version of sdhci's add_host/remove_host operation.
> Any sdhci drivers which are capable of handling UHS-II cards must
> call those functions instead of the corresponding sdhci's.
> 
> Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> ---
>  drivers/mmc/host/sdhci-uhs2.c | 172 ++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-uhs2.h |   2 +
>  drivers/mmc/host/sdhci.c      |  21 +++--
>  drivers/mmc/host/sdhci.h      |   9 ++
>  4 files changed, 197 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> index 883e18d849ad..eb3241bf95a2 100644
> --- a/drivers/mmc/host/sdhci-uhs2.c
> +++ b/drivers/mmc/host/sdhci-uhs2.c
> @@ -15,6 +15,7 @@
>  #include <linux/ktime.h>
>  #include <linux/module.h>
>  #include <linux/mmc/mmc.h>
> +#include <linux/regulator/consumer.h>
>  
>  #include "sdhci.h"
>  #include "sdhci-uhs2.h"
> @@ -1177,6 +1178,177 @@ static irqreturn_t sdhci_uhs2_thread_irq(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> +/*****************************************************************************\
> + *
> + * Device allocation/registration                                            *
> + *                                                                           *
> +\*****************************************************************************/
> +
> +static int __sdhci_uhs2_add_host_v4(struct sdhci_host *host, u32 caps1)
> +{
> +	struct mmc_host *mmc;
> +	u32 max_current_caps2;
> +
> +	if (host->version < SDHCI_SPEC_400)
> +		return 0;
> +
> +	mmc = host->mmc;
> +
> +	/* Support UHS2 */
> +	if (caps1 & SDHCI_SUPPORT_UHS2)
> +		mmc->caps2 |= MMC_CAP2_SD_UHS2;
> +
> +	max_current_caps2 = sdhci_readl(host, SDHCI_MAX_CURRENT_1);
> +
> +	if ((caps1 & SDHCI_SUPPORT_VDD2_180) &&
> +	    !max_current_caps2 &&
> +	    !IS_ERR(mmc->supply.vmmc2)) {
> +		/* UHS2 - VDD2 */
> +		int curr = regulator_get_current_limit(mmc->supply.vmmc2);
> +
> +		if (curr > 0) {
> +			/* convert to SDHCI_MAX_CURRENT format */
> +			curr = curr / 1000;  /* convert to mA */
> +			curr = curr / SDHCI_MAX_CURRENT_MULTIPLIER;
> +			curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
> +			max_current_caps2 = curr;
> +		}
> +	}
> +
> +	if (caps1 & SDHCI_SUPPORT_VDD2_180) {
> +		mmc->ocr_avail_uhs2 |= MMC_VDD2_165_195;
> +		/*
> +		 * UHS2 doesn't require this. Only UHS-I bus needs to set
> +		 * max current.
> +		 */
> +		mmc->max_current_180_vdd2 = (max_current_caps2 &
> +					SDHCI_MAX_CURRENT_VDD2_180_MASK) *
> +					SDHCI_MAX_CURRENT_MULTIPLIER;
> +	} else {
> +		mmc->caps2 &= ~MMC_CAP2_SD_UHS2;
> +	}
> +
> +	return 0;
> +}
> +
> +static int sdhci_uhs2_host_ops_init(struct sdhci_host *host);
> +
> +static int __sdhci_uhs2_add_host(struct sdhci_host *host)

The only thing this does differently is to use
sdhci_uhs2_complete_work() and sdhci_uhs2_thread_irq().
Better to add variables in struct sdhci_host, set them in
sdhci_alloc_host:

	host->complete_work_fn = sdhci_complete_work;
	host->thread_irq_fn = sdhci_thread_irq;

override them in sdhci_uhs2_add_host():

	host->complete_work_fn = sdhci_uhs2_complete_work;
	host->thread_irq_fn = sdhci_uhs2_thread_irq;

and use them in __sdhci_add_host().

> +{
> +	unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI;
> +	struct mmc_host *mmc = host->mmc;
> +	int ret;
> +
> +	if ((mmc->caps2 & MMC_CAP2_CQE) &&
> +	    (host->quirks & SDHCI_QUIRK_BROKEN_CQE)) {
> +		mmc->caps2 &= ~MMC_CAP2_CQE;
> +		mmc->cqe_ops = NULL;
> +	}
> +
> +	/* overwrite ops */
> +	if (mmc->caps2 & MMC_CAP2_SD_UHS2)
> +		sdhci_uhs2_host_ops_init(host);

Do in sdhci_uhs2_add_host() instead of here

> +
> +	host->complete_wq = alloc_workqueue("sdhci", flags, 0);
> +	if (!host->complete_wq)
> +		return -ENOMEM;
> +
> +	INIT_WORK(&host->complete_work, sdhci_uhs2_complete_work);
> +
> +	timer_setup(&host->timer, sdhci_timeout_timer, 0);
> +	timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
> +
> +	init_waitqueue_head(&host->buf_ready_int);
> +
> +	sdhci_init(host, 0);
> +
> +	ret = request_threaded_irq(host->irq, sdhci_irq,
> +				   sdhci_uhs2_thread_irq,
> +				   IRQF_SHARED,	mmc_hostname(mmc), host);
> +	if (ret) {
> +		pr_err("%s: Failed to request IRQ %d: %d\n",
> +		       mmc_hostname(mmc), host->irq, ret);
> +		goto unwq;
> +	}
> +
> +	ret = mmc_add_host(mmc);
> +		if (ret)
> +			return 1;
> +
> +	pr_info("%s: SDHCI controller on %s [%s] using %s\n",
> +		mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
> +		host->use_external_dma ? "External DMA" :
> +		(host->flags & SDHCI_USE_ADMA) ?
> +		(host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" :
> +		(host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
> +
> +	sdhci_enable_card_detection(host);
> +
> +	return 0;
> +
> +unwq:
> +	destroy_workqueue(host->complete_wq);
> +
> +	return ret;
> +}
> +
> +static void __sdhci_uhs2_remove_host(struct sdhci_host *host, int dead)
> +{
> +	if (!(host->mmc) || !(host->mmc->flags & MMC_UHS2_SUPPORT))
> +		return;

Just use sdhci_uhs2_mode() i.e

	if (!sdhci_uhs2_mode(host))
		return;

> +
> +	if (!dead)
> +		host->ops->uhs2_reset(host, SDHCI_UHS2_SW_RESET_FULL);
> +
> +	sdhci_writel(host, 0, SDHCI_UHS2_ERR_INT_STATUS_EN);
> +	sdhci_writel(host, 0, SDHCI_UHS2_ERR_INT_SIG_EN);

Do not write registers if it is dead.

> +	host->mmc->flags &= ~MMC_UHS2_INITIALIZED;

Not the drivers job to change host->mmc->flags

> +}
> +
> +int sdhci_uhs2_add_host(struct sdhci_host *host)
> +{
> +	struct mmc_host *mmc = host->mmc;
> +	int ret;
> +
> +	ret = sdhci_setup_host(host);
> +	if (ret)
> +		return ret;
> +
> +	if (host->version >= SDHCI_SPEC_400) {
> +		ret = __sdhci_uhs2_add_host_v4(host, host->caps1);
> +		if (ret)
> +			goto cleanup;
> +	}
> +
> +	if ((mmc->caps2 & MMC_CAP2_SD_UHS2) && !host->v4_mode)
> +		/* host doesn't want to enable UHS2 support */
> +		/* FIXME: Do we have to do some cleanup here? */
> +		mmc->caps2 &= ~MMC_CAP2_SD_UHS2;
> +
> +	ret = __sdhci_uhs2_add_host(host);
> +	if (ret)
> +		goto cleanup2;
> +
> +	return 0;
> +
> +cleanup2:
> +	if (host->version >= SDHCI_SPEC_400)
> +		__sdhci_uhs2_remove_host(host, 0);
> +cleanup:
> +	sdhci_cleanup_host(host);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_add_host);
> +
> +void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead)
> +{
> +	__sdhci_uhs2_remove_host(host, dead);
> +
> +	sdhci_remove_host(host, dead);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_uhs2_remove_host);
> +
>  void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
>  {
>  	struct sdhci_host *host = mmc_priv(mmc);
> diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> index d32a8602d045..54241a7adfca 100644
> --- a/drivers/mmc/host/sdhci-uhs2.h
> +++ b/drivers/mmc/host/sdhci-uhs2.h
> @@ -220,5 +220,7 @@ void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
>  void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq);
>  int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
>  u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask);
> +int sdhci_uhs2_add_host(struct sdhci_host *host);
> +void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead);
>  
>  #endif /* __SDHCI_UHS2_H */
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index e44ede049559..df433ad0ba66 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -173,10 +173,11 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
>  	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
>  }
>  
> -static void sdhci_enable_card_detection(struct sdhci_host *host)
> +void sdhci_enable_card_detection(struct sdhci_host *host)
>  {
>  	sdhci_set_card_detection(host, true);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_enable_card_detection);
>  
>  static void sdhci_disable_card_detection(struct sdhci_host *host)
>  {
> @@ -365,7 +366,7 @@ static void sdhci_config_dma(struct sdhci_host *host)
>  	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
>  }
>  
> -static void sdhci_init(struct sdhci_host *host, int soft)
> +void sdhci_init(struct sdhci_host *host, int soft)
>  {
>  	struct mmc_host *mmc = host->mmc;
>  	unsigned long flags;
> @@ -390,6 +391,7 @@ static void sdhci_init(struct sdhci_host *host, int soft)
>  		mmc->ops->set_ios(mmc, &mmc->ios);
>  	}
>  }
> +EXPORT_SYMBOL_GPL(sdhci_init);
>  
>  static void sdhci_reinit(struct sdhci_host *host)
>  {
> @@ -454,7 +456,7 @@ static void sdhci_led_control(struct led_classdev *led,
>  	spin_unlock_irqrestore(&host->lock, flags);
>  }
>  
> -static int sdhci_led_register(struct sdhci_host *host)
> +int sdhci_led_register(struct sdhci_host *host)
>  {
>  	struct mmc_host *mmc = host->mmc;
>  
> @@ -471,14 +473,16 @@ static int sdhci_led_register(struct sdhci_host *host)
>  
>  	return led_classdev_register(mmc_dev(mmc), &host->led);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_led_register);
>  
> -static void sdhci_led_unregister(struct sdhci_host *host)
> +void sdhci_led_unregister(struct sdhci_host *host)
>  {
>  	if (host->quirks & SDHCI_QUIRK_NO_LED)
>  		return;
>  
>  	led_classdev_unregister(&host->led);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_led_unregister);
>  
>  static inline void sdhci_led_activate(struct sdhci_host *host)
>  {
> @@ -3244,7 +3248,7 @@ static void sdhci_complete_work(struct work_struct *work)
>  		;
>  }
>  
> -static void sdhci_timeout_timer(struct timer_list *t)
> +void sdhci_timeout_timer(struct timer_list *t)
>  {
>  	struct sdhci_host *host;
>  	unsigned long flags;
> @@ -3265,8 +3269,9 @@ static void sdhci_timeout_timer(struct timer_list *t)
>  
>  	spin_unlock_irqrestore(&host->lock, flags);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_timeout_timer);
>  
> -static void sdhci_timeout_data_timer(struct timer_list *t)
> +void sdhci_timeout_data_timer(struct timer_list *t)
>  {
>  	struct sdhci_host *host;
>  	unsigned long flags;
> @@ -3297,6 +3302,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t)
>  
>  	spin_unlock_irqrestore(&host->lock, flags);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_timeout_data_timer);
>  
>  /*****************************************************************************\
>   *                                                                           *
> @@ -3560,7 +3566,7 @@ static inline bool sdhci_defer_done(struct sdhci_host *host,
>  		data->host_cookie == COOKIE_MAPPED);
>  }
>  
> -static irqreturn_t sdhci_irq(int irq, void *dev_id)
> +irqreturn_t sdhci_irq(int irq, void *dev_id)
>  {
>  	struct mmc_request *mrqs_done[SDHCI_MAX_MRQS] = {0};
>  	irqreturn_t result = IRQ_NONE;
> @@ -3701,6 +3707,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
>  
>  	return result;
>  }
> +EXPORT_SYMBOL_GPL(sdhci_irq);

This doesn't need to be exported when __sdhci_uhs2_add_host()
isn't needed.

>  
>  static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
>  {
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index 49de8fdbd7a3..0970fe392d49 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -851,8 +851,14 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
>  }
>  
>  bool sdhci_data_line_cmd(struct mmc_command *cmd);
> +void sdhci_enable_card_detection(struct sdhci_host *host);
>  void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
>  void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
> +void sdhci_init(struct sdhci_host *host, int soft);
> +#if IS_REACHABLE(CONFIG_LEDS_CLASS)
> +int sdhci_led_register(struct sdhci_host *host);
> +void sdhci_led_unregister(struct sdhci_host *host);
> +#endif

Don't support LEDs.  Just set:

	/* LED support not implemented for UHS2 */
	host->quirks |= SDHCI_QUIRK_NO_LED;

>  void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, unsigned long timeout);
>  void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data);
>  void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data);
> @@ -900,6 +906,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
>  void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
>  void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq);
>  bool sdhci_request_done(struct sdhci_host *host);
> +void sdhci_timeout_timer(struct timer_list *t);
> +void sdhci_timeout_data_timer(struct timer_list *t);
> +irqreturn_t sdhci_irq(int irq, void *dev_id);
>  void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
>  			   dma_addr_t addr, int len, unsigned int cmd);
>  


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 00/26] Add support UHS-II for GL9755
  2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
                   ` (26 preceding siblings ...)
  2022-10-19 11:29 ` [PATCH V5 00/26] Add support UHS-II " Ulf Hansson
@ 2022-11-01 17:28 ` Adrian Hunter
  2022-11-04 10:43   ` Victor Shih
  27 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-01 17:28 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih

On 19/10/22 14:06, Victor Shih wrote:
> Summary
> =======
> These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
> 
> About UHS-II, roughly deal with the following three parts:
> 1) A UHS-II detection and initialization:
> - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
>   [2]).
> - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
>   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
>   Setup Sequence.
> 
> 2) Send Legacy SD command through SD-TRAN
> - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
>   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
>   Types and Format Overview[3]).
> - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
>   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
> 
> 3) UHS-II Interrupt
> - Except for UHS-II error interrupts, most interrupts share the original
>   interrupt registers.
> 
> Patch structure
> ===============
> patch#1-#6:  for core
> patch#7-#25: for sdhci
> patch#26:    for GL9755

Thanks for putting this together.

I haven't looked at all the patches, but have requested quite
a lot of small changes, so there should be enough to be going
on with for now.

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 00/26] Add support UHS-II for GL9755
  2022-11-01 17:28 ` Adrian Hunter
@ 2022-11-04 10:43   ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-11-04 10:43 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih

Hi, Adrian

Adrian Hunter <adrian.hunter@intel.com> 於 2022年11月2日 週三 凌晨1:28寫道:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > Summary
> > =======
> > These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
> >
> > About UHS-II, roughly deal with the following three parts:
> > 1) A UHS-II detection and initialization:
> > - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
> >   [2]).
> > - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> > - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
> >   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
> >   Setup Sequence.
> >
> > 2) Send Legacy SD command through SD-TRAN
> > - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
> >   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
> >   Types and Format Overview[3]).
> > - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
> >   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
> >
> > 3) UHS-II Interrupt
> > - Except for UHS-II error interrupts, most interrupts share the original
> >   interrupt registers.
> >
> > Patch structure
> > ===============
> > patch#1-#6:  for core
> > patch#7-#25: for sdhci
> > patch#26:    for GL9755
>
> Thanks for putting this together.
>
> I haven't looked at all the patches, but have requested quite
> a lot of small changes, so there should be enough to be going
> on with for now.

Thanks for your help. I will confirm your advice in each patch and
follow your advice to change.

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 02/26] mmc: core: Prepare to support SD UHS-II cards
  2022-10-19 11:06 ` [PATCH V5 02/26] mmc: core: Prepare to support SD UHS-II cards Victor Shih
@ 2022-11-04 12:16   ` Christophe JAILLET
  2022-11-04 15:09     ` Ulf Hansson
  0 siblings, 1 reply; 72+ messages in thread
From: Christophe JAILLET @ 2022-11-04 12:16 UTC (permalink / raw)
  To: Victor Shih, ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih

Le 19/10/2022 à 13:06, Victor Shih a écrit :
> From: Ulf Hansson <ulf.hansson@linaro.org>
> 
> Updates in V4:
>   - Re-based, updated a comment and removed white-space.
>   - Moved MMC_VQMMC2_VOLTAGE_180 into a later patch in the series.
> 
> Update in previous version:
> The SD UHS-II interface was introduced to the SD spec v4.00 several years
> ago. The interface is fundamentally different from an electrical and a
> protocol point of view, comparing to the legacy SD interface.
> 
> However, the legacy SD protocol is supported through a specific transport
> layer (SD-TRAN) defined in the UHS-II addendum of the spec. This allows the
> SD card to be managed in a very similar way as a legacy SD card, hence a
> lot of code can be re-used to support these new types of cards through the
> mmc subsystem.
> 
> Moreover, an SD card that supports the UHS-II interface shall also be
> backwards compatible with the legacy SD interface, which allows a UHS-II
> card to be inserted into a legacy slot. As a matter of fact, this is
> already supported by mmc subsystem as of today.
> 
> To prepare to add support for UHS-II, this change puts the basic foundation
> in the mmc core in place, allowing it to be more easily reviewed before
> subsequent changes implements the actual support.
> 
> Basically, the approach here adds a new UHS-II bus_ops type and adds a
> separate initialization path for the UHS-II card. The intent is to avoid us
> from sprinkling the legacy initialization path, but also to simplify
> implementation of the UHS-II specific bits.
> 
> At this point, there is only one new host ops added to manage the various
> ios settings needed for UHS-II. Additional host ops that are needed, are
> being added from subsequent changes.
> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---

[]

> +static int sd_uhs2_attach(struct mmc_host *host)
> +{
> +	int err;
> +
> +	err = sd_uhs2_power_up(host);
> +	if (err)
> +		goto err;
> +
> +	err = sd_uhs2_phy_init(host);
> +	if (err)
> +		goto err;
> +
> +	err = sd_uhs2_init_card(host);
> +	if (err)
> +		goto err;
> +
> +	mmc_attach_bus(host, &sd_uhs2_ops);
> +
> +	mmc_release_host(host);
> +
> +	err = mmc_add_card(host->card);
> +	if (err)
> +		goto remove_card;
> +
> +	mmc_claim_host(host);
> +	return 0;
> +
> +remove_card:
> +	mmc_remove_card(host->card);

Hi,

If we arrive here, mmc_add_card() has failed.
is it correct to call mmc_remove_card() in such a case?

> +	host->card = NULL;
> +	mmc_claim_host(host);
> +	mmc_detach_bus(host);
> +err:
> +	sd_uhs2_power_off(host);

If sd_uhs2_power_up() fails, we arrive here.
Is its correct to call sd_uhs2_power_off() in such a case, or should we 
return directly if sd_uhs2_power_up() fails?

CJ

> +	return err;
> +}
> +

[]


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 02/26] mmc: core: Prepare to support SD UHS-II cards
  2022-11-04 12:16   ` Christophe JAILLET
@ 2022-11-04 15:09     ` Ulf Hansson
  0 siblings, 0 replies; 72+ messages in thread
From: Ulf Hansson @ 2022-11-04 15:09 UTC (permalink / raw)
  To: Christophe JAILLET
  Cc: Victor Shih, adrian.hunter, linux-mmc, linux-kernel,
	benchuanggli, HL.Liu, Greg.tu, takahiro.akashi, dlunev,
	Victor Shih

On Fri, 4 Nov 2022 at 13:16, Christophe JAILLET
<christophe.jaillet@wanadoo.fr> wrote:
>
> Le 19/10/2022 à 13:06, Victor Shih a écrit :
> > From: Ulf Hansson <ulf.hansson@linaro.org>
> >
> > Updates in V4:
> >   - Re-based, updated a comment and removed white-space.
> >   - Moved MMC_VQMMC2_VOLTAGE_180 into a later patch in the series.
> >
> > Update in previous version:
> > The SD UHS-II interface was introduced to the SD spec v4.00 several years
> > ago. The interface is fundamentally different from an electrical and a
> > protocol point of view, comparing to the legacy SD interface.
> >
> > However, the legacy SD protocol is supported through a specific transport
> > layer (SD-TRAN) defined in the UHS-II addendum of the spec. This allows the
> > SD card to be managed in a very similar way as a legacy SD card, hence a
> > lot of code can be re-used to support these new types of cards through the
> > mmc subsystem.
> >
> > Moreover, an SD card that supports the UHS-II interface shall also be
> > backwards compatible with the legacy SD interface, which allows a UHS-II
> > card to be inserted into a legacy slot. As a matter of fact, this is
> > already supported by mmc subsystem as of today.
> >
> > To prepare to add support for UHS-II, this change puts the basic foundation
> > in the mmc core in place, allowing it to be more easily reviewed before
> > subsequent changes implements the actual support.
> >
> > Basically, the approach here adds a new UHS-II bus_ops type and adds a
> > separate initialization path for the UHS-II card. The intent is to avoid us
> > from sprinkling the legacy initialization path, but also to simplify
> > implementation of the UHS-II specific bits.
> >
> > At this point, there is only one new host ops added to manage the various
> > ios settings needed for UHS-II. Additional host ops that are needed, are
> > being added from subsequent changes.
> >
> > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> > ---
>
> []
>
> > +static int sd_uhs2_attach(struct mmc_host *host)
> > +{
> > +     int err;
> > +
> > +     err = sd_uhs2_power_up(host);
> > +     if (err)
> > +             goto err;
> > +
> > +     err = sd_uhs2_phy_init(host);
> > +     if (err)
> > +             goto err;
> > +
> > +     err = sd_uhs2_init_card(host);
> > +     if (err)
> > +             goto err;
> > +
> > +     mmc_attach_bus(host, &sd_uhs2_ops);
> > +
> > +     mmc_release_host(host);
> > +
> > +     err = mmc_add_card(host->card);
> > +     if (err)
> > +             goto remove_card;
> > +
> > +     mmc_claim_host(host);
> > +     return 0;
> > +
> > +remove_card:
> > +     mmc_remove_card(host->card);
>
> Hi,
>
> If we arrive here, mmc_add_card() has failed.
> is it correct to call mmc_remove_card() in such a case?

Yes. There are some additional checks in mmc_add_card() to help to
manage this too.

Although, there are certainly some cleanups that can be made to
simplify the code in the mmc core around this, but that's a different
story.

>
> > +     host->card = NULL;
> > +     mmc_claim_host(host);
> > +     mmc_detach_bus(host);
> > +err:
> > +     sd_uhs2_power_off(host);
>
> If sd_uhs2_power_up() fails, we arrive here.
> Is its correct to call sd_uhs2_power_off() in such a case, or should we
> return directly if sd_uhs2_power_up() fails?

That's an option that could make the code a bit clearer. I have no
strong opinion around this.

Although, if changing this, we need to make sure sd_uhs2_power_up()
restores things correctly after a failure, but it doesn't do that in
the current version of the patch.

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards
  2022-11-01 17:12   ` Adrian Hunter
@ 2022-11-16 11:06     ` Victor Shih
  2022-11-16 13:48       ` Adrian Hunter
  0 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-11-16 11:06 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Jason Lai

Hi, Adrian

On Wed, Nov 2, 2022 at 1:12 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > Add UHS-II specific data structures for commands and defines for
> > registers, as described in Part 1 UHS-II Addendum Version 1.01.
> >
> > UHS-II related definitions are listed below:
> >   1. UHS-II card capability: sd_uhs2_caps{}
> >   2. UHS-II configuration: sd_uhs2_config{}
> >   3. UHS-II Command structure: uhs2_command{}
> >   4. UHS-II register I/O address and register field definitions: sd_uhs2.h
> >
> > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> > Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >
> > Updates in V5:
> >  - Added UHS2 interfaces in mmc_host_ops: host.h
> >  - Added UHS2 VDD2 power supply in mmc_supply: host.h
> >  - Added UHS2-specific OCR and UHS2 VDD2 max current in mmc_host: host.h
> >  - Added definition of UHS2 VDD2 1.65v-1.95v in mmc_host: host.h
> >  - Added flags/MMC_UHS2_SUPPORT/MMC_UHS2_2L_HD in mmc_host: host.h
> > ---
> >  include/linux/mmc/card.h    |  42 +++++-
> >  include/linux/mmc/core.h    |  13 ++
> >  include/linux/mmc/host.h    |  70 +++++++++-
> >  include/linux/mmc/sd_uhs2.h | 263 ++++++++++++++++++++++++++++++++++++
> >  4 files changed, 386 insertions(+), 2 deletions(-)
> >  create mode 100644 include/linux/mmc/sd_uhs2.h
> >
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index 4a42f31b7bb0..d638a2c689cf 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -190,6 +190,13 @@ struct sd_switch_caps {
> >  #define SD_MAX_CURRENT_400   (1 << SD_SET_CURRENT_LIMIT_400)
> >  #define SD_MAX_CURRENT_600   (1 << SD_SET_CURRENT_LIMIT_600)
> >  #define SD_MAX_CURRENT_800   (1 << SD_SET_CURRENT_LIMIT_800)
> > +     unsigned int            sd4_curr_limit;
> > +#define SD4_SET_POWER_LIMIT_0_72W    0
> > +#define SD4_SET_POWER_LIMIT_1_44W    1
> > +#define SD4_SET_POWER_LIMIT_2_16W    2
> > +#define SD4_SET_POWER_LIMIT_2_88W    3
> > +#define SD4_SET_POWER_LIMIT_1_80W    4
> > +#define SD4_SET_POWER_NO_CHANGE              (-1)
> >  };
> >
> >  struct sd_ext_reg {
> > @@ -213,7 +220,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 {
> > @@ -323,6 +358,9 @@ struct mmc_card {
> >       struct sd_ext_reg       ext_perf;       /* SD extension reg for PERF */
> >
> >       struct sd_uhs2_config   uhs2_config;    /* SD UHS-II config */
> > +     u8                      uhs2_state;     /* SD UHS-II states */
> > +#define MMC_UHS2_INITIALIZED BIT(1)
> > +#define MMC_UHS2_SPEED_B     BIT(2)
> >
> >       unsigned int            sdio_funcs;     /* number of SDIO functions */
> >       atomic_t                sdio_funcs_probed; /* number of probed SDIO funcs */
> > @@ -364,4 +402,6 @@ bool mmc_card_is_blockaddr(struct mmc_card *card);
> >  #define mmc_card_sdio(c)     ((c)->type == MMC_TYPE_SDIO)
> >  #define mmc_card_sd_combo(c) ((c)->type == MMC_TYPE_SD_COMBO)
> >
> > +#define mmc_card_can_poweroff_notify(c)      ((c)->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY)
> > +
> >  #endif /* LINUX_MMC_CARD_H */
> > diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> > index 6efec0b9820c..2a0581d87706 100644
> > --- a/include/linux/mmc/core.h
> > +++ b/include/linux/mmc/core.h
> > @@ -23,6 +23,14 @@ enum mmc_blk_status {
> >       MMC_BLK_NEW_REQUEST,
> >  };
> >
> > +struct uhs2_command {
> > +     u16     header;
> > +     u16     arg;
> > +     __be32  *payload;
> > +     u32     payload_len;
> > +     u32     packet_len;
> > +};
> > +
> >  struct mmc_command {
> >       u32                     opcode;
> >       u32                     arg;
> > @@ -109,6 +117,11 @@ struct mmc_command {
> >       unsigned int            busy_timeout;   /* busy detect timeout in ms */
> >       struct mmc_data         *data;          /* data segment associated with cmd */
> >       struct mmc_request      *mrq;           /* associated request */
> > +
> > +     struct uhs2_command     *uhs2_cmd;      /* UHS2 command */
> > +     u8                      *uhs2_resp;     /* UHS2 native cmd resp */
> > +     u8                      uhs2_resp_len;  /* UHS2 native cmd resp len */
> > +     u8                      uhs2_tmode0_flag; /* UHS2 transfer mode flag */
> >  };
> >
> >  struct mmc_data {
> > diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > index 895bcf7f80b7..249a9414ad10 100644
> > --- a/include/linux/mmc/host.h
> > +++ b/include/linux/mmc/host.h
> > @@ -16,6 +16,7 @@
> >  #include <linux/mmc/pm.h>
> >  #include <linux/dma-direction.h>
> >  #include <linux/blk-crypto-profile.h>
> > +#include <linux/mmc/sd_uhs2.h>
> >
> >  struct mmc_ios {
> >       unsigned int    clock;                  /* clock rate */
> > @@ -96,7 +97,48 @@ struct mmc_clk_phase_map {
> >  };
> >
> >  struct sd_uhs2_caps {
> > -     /* TODO: Add UHS-II capabilities for the host. */
> > +     u32     dap;
> > +     u32     gap;
> > +     u32     group_desc;
> > +     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 sd_uhs2_ios {
> > +     bool            is_2L_HD_mode;
> > +     bool            is_APP_CMD;
> > +     unsigned int    power_delay_ms;         /* waiting for stable power */
> > +};
> > +
> > +enum sd_uhs2_operation {
> > +     UHS2_PHY_INIT = 0,
> > +     UHS2_SET_CONFIG,
> > +     UHS2_ENABLE_INT,
> > +     UHS2_DISABLE_INT,
> > +     UHS2_ENABLE_CLK,
> > +     UHS2_DISABLE_CLK,
> > +     UHS2_CHECK_DORMANT,
> > +     UHS2_SET_SPEED_B,
> > +     UHS2_POST_ATTACH_SD,
> >  };
> >
> >  struct mmc_host;
> > @@ -231,6 +273,20 @@ 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 */
> > +     int     (*uhs2_detect_init)(struct mmc_host *host);
>
> Never called?

Yes, I will delete it.

>
> > +     int     (*uhs2_set_reg)(struct mmc_host *host, enum sd_uhs2_operation act);
>
> Never called?

Yes, I will delete it.

>
> > +     int (*uhs2_disable_clk)(struct mmc_host *host);
>
> Never called?

Yes, I will delete it.

>
> > +     int (*uhs2_enable_clk)(struct mmc_host *host);
>
> Never called?

Yes, I will delete it.

>
> > +
> > +     /*
> > +      * The uhs2_control callback is used to execute SD UHS-II specific
> > +      * operations. It's mandatory to implement for hosts that supports the
> > +      * SD UHS-II interface (MMC_CAP2_SD_UHS2). Expected return values are a
> > +      * negative errno in case of a failure or zero for success.
> > +      */
> > +     int     (*uhs2_control)(struct mmc_host *host, enum sd_uhs2_operation op);
> >  };
> >
> >  struct mmc_cqe_ops {
> > @@ -323,6 +379,7 @@ struct mmc_pwrseq;
> >
> >  struct mmc_supply {
> >       struct regulator *vmmc;         /* Card power supply */
> > +     struct regulator *vmmc2;        /* UHS2 VDD2 power supply */
> >       struct regulator *vqmmc;        /* Optional Vccq supply */
> >       struct regulator *vqmmc2;       /* Optional supply for phy */
> >  };
> > @@ -344,10 +401,12 @@ struct mmc_host {
> >       u32                     ocr_avail_sdio; /* SDIO-specific OCR */
> >       u32                     ocr_avail_sd;   /* SD-specific OCR */
> >       u32                     ocr_avail_mmc;  /* MMC-specific OCR */
> > +     u32                     ocr_avail_uhs2; /* UHS2-specific OCR */
> >       struct wakeup_source    *ws;            /* Enable consume of uevents */
> >       u32                     max_current_330;
> >       u32                     max_current_300;
> >       u32                     max_current_180;
> > +     u32                     max_current_180_vdd2; /* UHS2 vdd2 max curt. */
> >
> >  #define MMC_VDD_165_195              0x00000080      /* VDD voltage 1.65 - 1.95 */
> >  #define MMC_VDD_20_21                0x00000100      /* VDD voltage 2.0 ~ 2.1 */
> > @@ -366,6 +425,7 @@ struct mmc_host {
> >  #define MMC_VDD_33_34                0x00200000      /* VDD voltage 3.3 ~ 3.4 */
> >  #define MMC_VDD_34_35                0x00400000      /* VDD voltage 3.4 ~ 3.5 */
> >  #define MMC_VDD_35_36                0x00800000      /* VDD voltage 3.5 ~ 3.6 */
> > +#define MMC_VDD2_165_195     0x00000080      /* UHS2 VDD2 1.65 ~ 1.95 */
> >
> >       u32                     caps;           /* Host capabilities */
> >
> > @@ -443,7 +503,12 @@ struct mmc_host {
> >  #endif
> >  #define MMC_CAP2_ALT_GPT_TEGRA       (1 << 28)       /* Host with eMMC that has GPT entry at a non-standard location */
> >
> > +     int flags;
> > +#define MMC_UHS2_SUPPORT     (1 << 0)
>
> MMC_UHS2_SUPPORT is getting mixed up with MMC_UHS2_INITIALIZED.
> Both have the same value, but MMC_UHS2_SUPPORT is for
> host->flags and MMC_UHS2_INITIALIZED is for card->uhs2_state
>
> Please use the correct flag with the correct variable.
>

The value of MMC_UHS2_SUPPORT is (1<<0) and the value of
MMC_UHS2_INITIALIZED is BIT(1).
Both have different values, therefore I'm not sure what you mean.
May you give me some more advice? Thanks.

> > +#define MMC_UHS2_2L_HD               (1 << 2)
>
> MMC_UHS2_2L_HD does not seem to be used. Is it needed?

I confirmed this, I don't use it, I will delete it.

>
> > +
> >       struct sd_uhs2_caps     uhs2_caps;      /* Host UHS-II capabilities */
> > +     struct sd_uhs2_ios      uhs2_ios;       /* Host UHS-II capabilities */
> >
> >       int                     fixed_drv_type; /* fixed driver type for non-removable media */
> >
> > @@ -695,4 +760,7 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
> >  int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
> >  int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
> >
> > +#define mmc_uhs2_2L_HD_mode(h)       ((h)->uhs2_ios.is_2L_HD_mode)
> > +#define mmc_uhs2_APP_cmd(h)  ((h)->uhs2_ios.is_APP_CMD)
> > +
> >  #endif /* LINUX_MMC_HOST_H */
> > diff --git a/include/linux/mmc/sd_uhs2.h b/include/linux/mmc/sd_uhs2.h
> > new file mode 100644
> > index 000000000000..8fcf702cf4a5
> > --- /dev/null
> > +++ b/include/linux/mmc/sd_uhs2.h
> > @@ -0,0 +1,263 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + * Header file for UHS-II packets, Host Controller registers and I/O
> > + * accessors.
> > + *
> > + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> > + */
> > +#ifndef LINUX_MMC_UHS2_H
> > +#define LINUX_MMC_UHS2_H
> > +
> > +/* LINK Layer definition */
> > +/*
> > + * UHS2 Header:
> > + * Refer to UHS-II Addendum Version 1.02 Figure 5-2, the format of CCMD Header is described below:
> > + *      bit [3:0]  : DID(Destination ID = Node ID of UHS2 card)
> > + *      bit [6:4]  : TYP(Packet Type)
> > + *                   000b: CCMD(Control command packet)
> > + *                   001b: DCMD(Data command packet)
> > + *                   010b: RES(Response packet)
> > + *                   011b: DATA(Data payload packet)
> > + *                   111b: MSG(Message packet)
> > + *                   Others: Reserved
> > + *      bit [7]    : NP(Native Packet)
> > + *      bit [10:8] : TID(Transaction ID)
> > + *      bit [11]   : Reserved
> > + *      bit [15:12]: SID(Source ID 0: Node ID of Host)
> > + *
> > + * Broadcast CCMD issued by Host is represented as DID=SID=0.
> > + */
> > +/*
> > + * UHS2 Argument:
> > + * Refer to UHS-II Addendum Version 1.02 Figure 6-5, the format of CCMD Argument is described below:
> > + *      bit [3:0]  : MSB of IOADR
> > + *      bit [5:4]  : PLEN(Payload Length)
> > + *                   00b: 0 byte
> > + *                   01b: 4 bytes
> > + *                   10b: 8 bytes
> > + *                   11b: 16 bytes
> > + *      bit [6]    : Reserved
> > + *      bit [7]    : R/W(Read/Write)
> > + *                   0: Control read command
> > + *                   1: Control write command
> > + *      bit [15:8] : LSB of IOADR
> > + *
> > + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> > + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> > + */
> > +#define UHS2_NATIVE_PACKET_POS       7
> > +#define UHS2_NATIVE_PACKET   (1 << UHS2_NATIVE_PACKET_POS)
> > +
> > +#define UHS2_PACKET_TYPE_POS 4
> > +#define UHS2_PACKET_TYPE_CCMD        (0 << UHS2_PACKET_TYPE_POS)
> > +#define UHS2_PACKET_TYPE_DCMD        (1 << UHS2_PACKET_TYPE_POS)
> > +#define UHS2_PACKET_TYPE_RES (2 << UHS2_PACKET_TYPE_POS)
> > +#define UHS2_PACKET_TYPE_DATA        (3 << UHS2_PACKET_TYPE_POS)
> > +#define UHS2_PACKET_TYPE_MSG (7 << UHS2_PACKET_TYPE_POS)
> > +
> > +#define UHS2_DEST_ID_MASK    0x0F
> > +#define UHS2_DEST_ID         0x1
> > +
> > +#define UHS2_SRC_ID_POS              12
> > +#define UHS2_SRC_ID_MASK     0xF000
> > +
> > +#define UHS2_TRANS_ID_POS    8
> > +#define UHS2_TRANS_ID_MASK   0x0700
> > +
> > +/* UHS2 MSG */
> > +#define UHS2_MSG_CTG_POS     5
> > +#define UHS2_MSG_CTG_LMSG    0x00
> > +#define UHS2_MSG_CTG_INT     0x60
> > +#define UHS2_MSG_CTG_AMSG    0x80
> > +
> > +#define UHS2_MSG_CTG_FCREQ   0x00
> > +#define UHS2_MSG_CTG_FCRDY   0x01
> > +#define UHS2_MSG_CTG_STAT    0x02
> > +
> > +#define UHS2_MSG_CODE_POS                    8
> > +#define UHS2_MSG_CODE_FC_UNRECOVER_ERR               0x8
> > +#define UHS2_MSG_CODE_STAT_UNRECOVER_ERR     0x8
> > +#define UHS2_MSG_CODE_STAT_RECOVER_ERR               0x1
> > +
> > +/* TRANS Layer definition */
> > +
> > +/* Native packets*/
> > +#define UHS2_NATIVE_CMD_RW_POS       7
> > +#define UHS2_NATIVE_CMD_WRITE        (1 << UHS2_NATIVE_CMD_RW_POS)
> > +#define UHS2_NATIVE_CMD_READ (0 << UHS2_NATIVE_CMD_RW_POS)
> > +
> > +#define UHS2_NATIVE_CMD_PLEN_POS     4
> > +#define UHS2_NATIVE_CMD_PLEN_4B              (1 << UHS2_NATIVE_CMD_PLEN_POS)
> > +#define UHS2_NATIVE_CMD_PLEN_8B              (2 << UHS2_NATIVE_CMD_PLEN_POS)
> > +#define UHS2_NATIVE_CMD_PLEN_16B     (3 << UHS2_NATIVE_CMD_PLEN_POS)
> > +
> > +#define UHS2_NATIVE_CCMD_GET_MIOADR_MASK     0xF00
> > +#define UHS2_NATIVE_CCMD_MIOADR_MASK         0x0F
> > +
> > +#define UHS2_NATIVE_CCMD_LIOADR_POS          8
> > +#define UHS2_NATIVE_CCMD_GET_LIOADR_MASK     0x0FF
> > +
> > +#define UHS2_CCMD_DEV_INIT_COMPLETE_FLAG     BIT(11)
> > +#define UHS2_DEV_INIT_PAYLOAD_LEN            1
> > +#define UHS2_DEV_INIT_RESP_LEN                       6
> > +#define UHS2_DEV_ENUM_PAYLOAD_LEN            1
> > +#define UHS2_DEV_ENUM_RESP_LEN                       8
> > +#define UHS2_CFG_WRITE_PAYLOAD_LEN           2
> > +#define UHS2_CFG_WRITE_PHY_SET_RESP_LEN              4
> > +#define UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN  5
> > +#define UHS2_GO_DORMANT_PAYLOAD_LEN          1
> > +
> > +/*
> > + * UHS2 Argument:
> > + * Refer to UHS-II Addendum Version 1.02 Figure 6-8, the format of DCMD Argument is described below:
> > + *      bit [3:0]  : Reserved
> > + *      bit [6:3]  : TMODE(Transfer Mode)
> > + *                   bit 3: DAM(Data Access Mode)
> > + *                   bit 4: TLUM(TLEN Unit Mode)
> > + *                   bit 5: LM(Length Mode)
> > + *                   bit 6: DM(Duplex Mode)
> > + *      bit [7]    : R/W(Read/Write)
> > + *                   0: Control read command
> > + *                   1: Control write command
> > + *      bit [15:8] : Reserved
> > + *
> > + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> > + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> > + */
> > +#define UHS2_DCMD_DM_POS             6
> > +#define UHS2_DCMD_2L_HD_MODE         (1 << UHS2_DCMD_DM_POS)
> > +#define UHS2_DCMD_LM_POS             5
> > +#define UHS2_DCMD_LM_TLEN_EXIST              (1 << UHS2_DCMD_LM_POS)
> > +#define UHS2_DCMD_TLUM_POS           4
> > +#define UHS2_DCMD_TLUM_BYTE_MODE     (1 << UHS2_DCMD_TLUM_POS)
> > +#define UHS2_NATIVE_DCMD_DAM_POS     3
> > +#define UHS2_NATIVE_DCMD_DAM_IO              (1 << UHS2_NATIVE_DCMD_DAM_POS)
> > +
> > +/*
> > + * Per UHS2 spec, DCMD payload should be MSB first. There may be
> > + * two types of data be assembled to MSB:
> > + * 1. TLEN: Input block size for single read/write and number of blocks
> > + * for multiple read/write to calculate TLEN as MSB first per spec.
> > + * 2. SD command argument.
> > + */
> > +static inline __be32 uhs2_dcmd_convert_msb(u32 input)
> > +{
> > +     u32 ret = 0;
> > +
> > +     ret = ((input & 0xFF) << 24) |
> > +             (((input >> 8) & 0xFF) << 16) |
> > +             (((input >> 16) & 0xFF) << 8) |
> > +             ((input >> 24) & 0xFF);
> > +     return cpu_to_be32(ret);
> > +}
> > +
> > +#define UHS2_RES_NACK_POS    7
> > +#define UHS2_RES_NACK_MASK   (0x1 << UHS2_RES_NACK_POS)
> > +
> > +#define UHS2_RES_ECODE_POS   4
> > +#define UHS2_RES_ECODE_MASK  0x7
> > +#define UHS2_RES_ECODE_COND  1
> > +#define UHS2_RES_ECODE_ARG   2
> > +#define UHS2_RES_ECODE_GEN   3
> > +
> > +/* IOADR of device registers */
> > +#define UHS2_IOADR_GENERIC_CAPS              0x00
> > +#define UHS2_IOADR_PHY_CAPS          0x02
> > +#define UHS2_IOADR_LINK_CAPS         0x04
> > +#define UHS2_IOADR_RSV_CAPS          0x06
> > +#define UHS2_IOADR_GENERIC_SETTINGS  0x08
> > +#define UHS2_IOADR_PHY_SETTINGS              0x0A
> > +#define UHS2_IOADR_LINK_SETTINGS     0x0C
> > +#define UHS2_IOADR_PRESET            0x40
> > +
> > +/* SD application packets */
> > +#define UHS2_SD_CMD_INDEX_POS        8
> > +
> > +#define UHS2_SD_CMD_APP_POS  14
> > +#define UHS2_SD_CMD_APP              (1 << UHS2_SD_CMD_APP_POS)
> > +
> > +/* UHS-II Device Registers */
> > +#define UHS2_DEV_CONFIG_REG  0x000
> > +
> > +/* General Caps and Settings registers */
> > +#define UHS2_DEV_CONFIG_GEN_CAPS     (UHS2_DEV_CONFIG_REG + 0x000)
> > +#define UHS2_DEV_CONFIG_N_LANES_POS  8
> > +#define UHS2_DEV_CONFIG_N_LANES_MASK 0x3F
> > +#define UHS2_DEV_CONFIG_2L_HD_FD     0x1
> > +#define UHS2_DEV_CONFIG_2D1U_FD              0x2
> > +#define UHS2_DEV_CONFIG_1D2U_FD              0x4
> > +#define UHS2_DEV_CONFIG_2D2U_FD              0x8
> > +#define UHS2_DEV_CONFIG_DADR_POS     14
> > +#define UHS2_DEV_CONFIG_DADR_MASK    0x1
> > +#define UHS2_DEV_CONFIG_APP_POS              16
> > +#define UHS2_DEV_CONFIG_APP_MASK     0xFF
> > +#define UHS2_DEV_CONFIG_APP_SD_MEM   0x1
> > +
> > +#define UHS2_DEV_CONFIG_GEN_SET                      (UHS2_DEV_CONFIG_REG + 0x008)
> > +#define UHS2_DEV_CONFIG_GEN_SET_N_LANES_POS  8
> > +#define UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD     0x0
> > +#define UHS2_DEV_CONFIG_GEN_SET_2D1U_FD              0x2
> > +#define UHS2_DEV_CONFIG_GEN_SET_1D2U_FD              0x3
> > +#define UHS2_DEV_CONFIG_GEN_SET_2D2U_FD              0x4
> > +#define UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE BIT(31)
> > +
> > +/* PHY Caps and Settings registers */
> > +#define UHS2_DEV_CONFIG_PHY_CAPS     (UHS2_DEV_CONFIG_REG + 0x002)
> > +#define UHS2_DEV_CONFIG_PHY_MINOR_MASK       0xF
> > +#define UHS2_DEV_CONFIG_PHY_MAJOR_POS        4
> > +#define UHS2_DEV_CONFIG_PHY_MAJOR_MASK       0x3
> > +#define UHS2_DEV_CONFIG_CAN_HIBER_POS        15
> > +#define UHS2_DEV_CONFIG_CAN_HIBER_MASK       0x1
> > +#define UHS2_DEV_CONFIG_PHY_CAPS1    (UHS2_DEV_CONFIG_REG + 0x003)
> > +#define UHS2_DEV_CONFIG_N_LSS_SYN_MASK       0xF
> > +#define UHS2_DEV_CONFIG_N_LSS_DIR_POS        4
> > +#define UHS2_DEV_CONFIG_N_LSS_DIR_MASK       0xF
> > +
> > +#define UHS2_DEV_CONFIG_PHY_SET                      (UHS2_DEV_CONFIG_REG + 0x00A)
> > +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_POS    6
> > +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_A              0x0
> > +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_B              0x1
> > +
> > +/* LINK-TRAN Caps and Settings registers */
> > +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS               (UHS2_DEV_CONFIG_REG + 0x004)
> > +#define UHS2_DEV_CONFIG_LT_MINOR_MASK                0xF
> > +#define UHS2_DEV_CONFIG_LT_MAJOR_POS         4
> > +#define UHS2_DEV_CONFIG_LT_MAJOR_MASK                0x3
> > +#define UHS2_DEV_CONFIG_N_FCU_POS            8
> > +#define UHS2_DEV_CONFIG_N_FCU_MASK           0xFF
> > +#define UHS2_DEV_CONFIG_DEV_TYPE_POS         16
> > +#define UHS2_DEV_CONFIG_DEV_TYPE_MASK                0x7
> > +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_POS              20
> > +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK     0xFFF
> > +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS1              (UHS2_DEV_CONFIG_REG + 0x005)
> > +#define UHS2_DEV_CONFIG_N_DATA_GAP_MASK              0xFF
> > +
> > +#define UHS2_DEV_CONFIG_LINK_TRAN_SET                (UHS2_DEV_CONFIG_REG + 0x00C)
> > +#define UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN   0x200
> > +#define UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS 16
> > +
> > +/* Preset register */
> > +#define UHS2_DEV_CONFIG_PRESET       (UHS2_DEV_CONFIG_REG + 0x040)
> > +
> > +#define UHS2_DEV_INT_REG     0x100
> > +
> > +#define UHS2_DEV_STATUS_REG  0x180
> > +
> > +#define UHS2_DEV_CMD_REG             0x200
> > +#define UHS2_DEV_CMD_FULL_RESET              (UHS2_DEV_CMD_REG + 0x000)
> > +#define UHS2_DEV_CMD_GO_DORMANT_STATE        (UHS2_DEV_CMD_REG + 0x001)
> > +#define UHS2_DEV_CMD_DORMANT_HIBER   BIT(7)
> > +#define UHS2_DEV_CMD_DEVICE_INIT     (UHS2_DEV_CMD_REG + 0x002)
> > +#define UHS2_DEV_INIT_COMPLETE_FLAG  BIT(11)
> > +#define UHS2_DEV_CMD_ENUMERATE               (UHS2_DEV_CMD_REG + 0x003)
> > +#define UHS2_DEV_CMD_TRANS_ABORT     (UHS2_DEV_CMD_REG + 0x004)
> > +
> > +#define UHS2_RCLK_MAX        52000000
> > +#define UHS2_RCLK_MIN        26000000
> > +
> > +struct sd_uhs2_wait_active_state_data {
> > +     struct mmc_host *host;
> > +     struct mmc_command *cmd;
> > +};
> > +
> > +#endif /* LINUX_MMC_UHS2_H */
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards
  2022-11-16 11:06     ` Victor Shih
@ 2022-11-16 13:48       ` Adrian Hunter
  2022-11-17  6:19         ` Ben Chuang
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-16 13:48 UTC (permalink / raw)
  To: Victor Shih
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Jason Lai

On 16/11/22 13:06, Victor Shih wrote:
> Hi, Adrian
> 
> On Wed, Nov 2, 2022 at 1:12 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> On 19/10/22 14:06, Victor Shih wrote:
>>> Add UHS-II specific data structures for commands and defines for
>>> registers, as described in Part 1 UHS-II Addendum Version 1.01.
>>>
>>> UHS-II related definitions are listed below:
>>>   1. UHS-II card capability: sd_uhs2_caps{}
>>>   2. UHS-II configuration: sd_uhs2_config{}
>>>   3. UHS-II Command structure: uhs2_command{}
>>>   4. UHS-II register I/O address and register field definitions: sd_uhs2.h
>>>
>>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>>> Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
>>> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
>>> ---
>>>
>>> Updates in V5:
>>>  - Added UHS2 interfaces in mmc_host_ops: host.h
>>>  - Added UHS2 VDD2 power supply in mmc_supply: host.h
>>>  - Added UHS2-specific OCR and UHS2 VDD2 max current in mmc_host: host.h
>>>  - Added definition of UHS2 VDD2 1.65v-1.95v in mmc_host: host.h
>>>  - Added flags/MMC_UHS2_SUPPORT/MMC_UHS2_2L_HD in mmc_host: host.h
>>> ---
>>>  include/linux/mmc/card.h    |  42 +++++-
>>>  include/linux/mmc/core.h    |  13 ++
>>>  include/linux/mmc/host.h    |  70 +++++++++-
>>>  include/linux/mmc/sd_uhs2.h | 263 ++++++++++++++++++++++++++++++++++++
>>>  4 files changed, 386 insertions(+), 2 deletions(-)
>>>  create mode 100644 include/linux/mmc/sd_uhs2.h
>>>
>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>> index 4a42f31b7bb0..d638a2c689cf 100644
>>> --- a/include/linux/mmc/card.h
>>> +++ b/include/linux/mmc/card.h
>>> @@ -190,6 +190,13 @@ struct sd_switch_caps {
>>>  #define SD_MAX_CURRENT_400   (1 << SD_SET_CURRENT_LIMIT_400)
>>>  #define SD_MAX_CURRENT_600   (1 << SD_SET_CURRENT_LIMIT_600)
>>>  #define SD_MAX_CURRENT_800   (1 << SD_SET_CURRENT_LIMIT_800)
>>> +     unsigned int            sd4_curr_limit;
>>> +#define SD4_SET_POWER_LIMIT_0_72W    0
>>> +#define SD4_SET_POWER_LIMIT_1_44W    1
>>> +#define SD4_SET_POWER_LIMIT_2_16W    2
>>> +#define SD4_SET_POWER_LIMIT_2_88W    3
>>> +#define SD4_SET_POWER_LIMIT_1_80W    4
>>> +#define SD4_SET_POWER_NO_CHANGE              (-1)
>>>  };
>>>
>>>  struct sd_ext_reg {
>>> @@ -213,7 +220,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 {
>>> @@ -323,6 +358,9 @@ struct mmc_card {
>>>       struct sd_ext_reg       ext_perf;       /* SD extension reg for PERF */
>>>
>>>       struct sd_uhs2_config   uhs2_config;    /* SD UHS-II config */
>>> +     u8                      uhs2_state;     /* SD UHS-II states */
>>> +#define MMC_UHS2_INITIALIZED BIT(1)
>>> +#define MMC_UHS2_SPEED_B     BIT(2)
>>>
>>>       unsigned int            sdio_funcs;     /* number of SDIO functions */
>>>       atomic_t                sdio_funcs_probed; /* number of probed SDIO funcs */
>>> @@ -364,4 +402,6 @@ bool mmc_card_is_blockaddr(struct mmc_card *card);
>>>  #define mmc_card_sdio(c)     ((c)->type == MMC_TYPE_SDIO)
>>>  #define mmc_card_sd_combo(c) ((c)->type == MMC_TYPE_SD_COMBO)
>>>
>>> +#define mmc_card_can_poweroff_notify(c)      ((c)->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY)
>>> +
>>>  #endif /* LINUX_MMC_CARD_H */
>>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
>>> index 6efec0b9820c..2a0581d87706 100644
>>> --- a/include/linux/mmc/core.h
>>> +++ b/include/linux/mmc/core.h
>>> @@ -23,6 +23,14 @@ enum mmc_blk_status {
>>>       MMC_BLK_NEW_REQUEST,
>>>  };
>>>
>>> +struct uhs2_command {
>>> +     u16     header;
>>> +     u16     arg;
>>> +     __be32  *payload;
>>> +     u32     payload_len;
>>> +     u32     packet_len;
>>> +};
>>> +
>>>  struct mmc_command {
>>>       u32                     opcode;
>>>       u32                     arg;
>>> @@ -109,6 +117,11 @@ struct mmc_command {
>>>       unsigned int            busy_timeout;   /* busy detect timeout in ms */
>>>       struct mmc_data         *data;          /* data segment associated with cmd */
>>>       struct mmc_request      *mrq;           /* associated request */
>>> +
>>> +     struct uhs2_command     *uhs2_cmd;      /* UHS2 command */
>>> +     u8                      *uhs2_resp;     /* UHS2 native cmd resp */
>>> +     u8                      uhs2_resp_len;  /* UHS2 native cmd resp len */
>>> +     u8                      uhs2_tmode0_flag; /* UHS2 transfer mode flag */
>>>  };
>>>
>>>  struct mmc_data {
>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>>> index 895bcf7f80b7..249a9414ad10 100644
>>> --- a/include/linux/mmc/host.h
>>> +++ b/include/linux/mmc/host.h
>>> @@ -16,6 +16,7 @@
>>>  #include <linux/mmc/pm.h>
>>>  #include <linux/dma-direction.h>
>>>  #include <linux/blk-crypto-profile.h>
>>> +#include <linux/mmc/sd_uhs2.h>
>>>
>>>  struct mmc_ios {
>>>       unsigned int    clock;                  /* clock rate */
>>> @@ -96,7 +97,48 @@ struct mmc_clk_phase_map {
>>>  };
>>>
>>>  struct sd_uhs2_caps {
>>> -     /* TODO: Add UHS-II capabilities for the host. */
>>> +     u32     dap;
>>> +     u32     gap;
>>> +     u32     group_desc;
>>> +     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 sd_uhs2_ios {
>>> +     bool            is_2L_HD_mode;
>>> +     bool            is_APP_CMD;
>>> +     unsigned int    power_delay_ms;         /* waiting for stable power */
>>> +};
>>> +
>>> +enum sd_uhs2_operation {
>>> +     UHS2_PHY_INIT = 0,
>>> +     UHS2_SET_CONFIG,
>>> +     UHS2_ENABLE_INT,
>>> +     UHS2_DISABLE_INT,
>>> +     UHS2_ENABLE_CLK,
>>> +     UHS2_DISABLE_CLK,
>>> +     UHS2_CHECK_DORMANT,
>>> +     UHS2_SET_SPEED_B,
>>> +     UHS2_POST_ATTACH_SD,
>>>  };
>>>
>>>  struct mmc_host;
>>> @@ -231,6 +273,20 @@ 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 */
>>> +     int     (*uhs2_detect_init)(struct mmc_host *host);
>>
>> Never called?
> 
> Yes, I will delete it.
> 
>>
>>> +     int     (*uhs2_set_reg)(struct mmc_host *host, enum sd_uhs2_operation act);
>>
>> Never called?
> 
> Yes, I will delete it.
> 
>>
>>> +     int (*uhs2_disable_clk)(struct mmc_host *host);
>>
>> Never called?
> 
> Yes, I will delete it.
> 
>>
>>> +     int (*uhs2_enable_clk)(struct mmc_host *host);
>>
>> Never called?
> 
> Yes, I will delete it.
> 
>>
>>> +
>>> +     /*
>>> +      * The uhs2_control callback is used to execute SD UHS-II specific
>>> +      * operations. It's mandatory to implement for hosts that supports the
>>> +      * SD UHS-II interface (MMC_CAP2_SD_UHS2). Expected return values are a
>>> +      * negative errno in case of a failure or zero for success.
>>> +      */
>>> +     int     (*uhs2_control)(struct mmc_host *host, enum sd_uhs2_operation op);
>>>  };
>>>
>>>  struct mmc_cqe_ops {
>>> @@ -323,6 +379,7 @@ struct mmc_pwrseq;
>>>
>>>  struct mmc_supply {
>>>       struct regulator *vmmc;         /* Card power supply */
>>> +     struct regulator *vmmc2;        /* UHS2 VDD2 power supply */
>>>       struct regulator *vqmmc;        /* Optional Vccq supply */
>>>       struct regulator *vqmmc2;       /* Optional supply for phy */
>>>  };
>>> @@ -344,10 +401,12 @@ struct mmc_host {
>>>       u32                     ocr_avail_sdio; /* SDIO-specific OCR */
>>>       u32                     ocr_avail_sd;   /* SD-specific OCR */
>>>       u32                     ocr_avail_mmc;  /* MMC-specific OCR */
>>> +     u32                     ocr_avail_uhs2; /* UHS2-specific OCR */
>>>       struct wakeup_source    *ws;            /* Enable consume of uevents */
>>>       u32                     max_current_330;
>>>       u32                     max_current_300;
>>>       u32                     max_current_180;
>>> +     u32                     max_current_180_vdd2; /* UHS2 vdd2 max curt. */
>>>
>>>  #define MMC_VDD_165_195              0x00000080      /* VDD voltage 1.65 - 1.95 */
>>>  #define MMC_VDD_20_21                0x00000100      /* VDD voltage 2.0 ~ 2.1 */
>>> @@ -366,6 +425,7 @@ struct mmc_host {
>>>  #define MMC_VDD_33_34                0x00200000      /* VDD voltage 3.3 ~ 3.4 */
>>>  #define MMC_VDD_34_35                0x00400000      /* VDD voltage 3.4 ~ 3.5 */
>>>  #define MMC_VDD_35_36                0x00800000      /* VDD voltage 3.5 ~ 3.6 */
>>> +#define MMC_VDD2_165_195     0x00000080      /* UHS2 VDD2 1.65 ~ 1.95 */
>>>
>>>       u32                     caps;           /* Host capabilities */
>>>
>>> @@ -443,7 +503,12 @@ struct mmc_host {
>>>  #endif
>>>  #define MMC_CAP2_ALT_GPT_TEGRA       (1 << 28)       /* Host with eMMC that has GPT entry at a non-standard location */
>>>
>>> +     int flags;
>>> +#define MMC_UHS2_SUPPORT     (1 << 0)
>>
>> MMC_UHS2_SUPPORT is getting mixed up with MMC_UHS2_INITIALIZED.
>> Both have the same value, but MMC_UHS2_SUPPORT is for
>> host->flags and MMC_UHS2_INITIALIZED is for card->uhs2_state
>>
>> Please use the correct flag with the correct variable.
>>
> 
> The value of MMC_UHS2_SUPPORT is (1<<0) and the value of
> MMC_UHS2_INITIALIZED is BIT(1).
> Both have different values, therefore I'm not sure what you mean.
> May you give me some more advice? Thanks.

I guess I got confused about the values, however it is not OK to
use MMC_UHS2_INITIALIZED for both mmc->flags and card->uhs2_state.
Please make a separate define with a different name for mmc->flags
version of MMC_UHS2_INITIALIZED.

Also, I am confused about the purpose of mmc->flags and
card->uhs2_state.

A host is UHS-II capable as represented by MMC_CAP2_SD_UHS2.
To initialize and use a UHS-II card in UHS-II mode, the host
must be in UHS-II mode.
To initialize and use a UHS-II card in SD mode, the host
must be in SD mode.
So the state of the card and host is always the same:
either UHS-II or not.  Note, that is a consequence of the
hardware I/F.  Whether SD I/F or UHS-II I/F is used is
decided before sending any UHS-II commands. SD I/F is
disabled during UHS-II PHY initialization, whereas
UHS-II I/F is disabled before execution of ACMD41 is
completed.

So it seems like there would only be a need for one flag
to indicate UHS-II mode?

> 
>>> +#define MMC_UHS2_2L_HD               (1 << 2)
>>
>> MMC_UHS2_2L_HD does not seem to be used. Is it needed?
> 
> I confirmed this, I don't use it, I will delete it.
> 
>>
>>> +
>>>       struct sd_uhs2_caps     uhs2_caps;      /* Host UHS-II capabilities */
>>> +     struct sd_uhs2_ios      uhs2_ios;       /* Host UHS-II capabilities */
>>>
>>>       int                     fixed_drv_type; /* fixed driver type for non-removable media */
>>>
>>> @@ -695,4 +760,7 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
>>>  int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
>>>  int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
>>>
>>> +#define mmc_uhs2_2L_HD_mode(h)       ((h)->uhs2_ios.is_2L_HD_mode)
>>> +#define mmc_uhs2_APP_cmd(h)  ((h)->uhs2_ios.is_APP_CMD)
>>> +
>>>  #endif /* LINUX_MMC_HOST_H */
>>> diff --git a/include/linux/mmc/sd_uhs2.h b/include/linux/mmc/sd_uhs2.h
>>> new file mode 100644
>>> index 000000000000..8fcf702cf4a5
>>> --- /dev/null
>>> +++ b/include/linux/mmc/sd_uhs2.h
>>> @@ -0,0 +1,263 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>> +/*
>>> + * Header file for UHS-II packets, Host Controller registers and I/O
>>> + * accessors.
>>> + *
>>> + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
>>> + */
>>> +#ifndef LINUX_MMC_UHS2_H
>>> +#define LINUX_MMC_UHS2_H
>>> +
>>> +/* LINK Layer definition */
>>> +/*
>>> + * UHS2 Header:
>>> + * Refer to UHS-II Addendum Version 1.02 Figure 5-2, the format of CCMD Header is described below:
>>> + *      bit [3:0]  : DID(Destination ID = Node ID of UHS2 card)
>>> + *      bit [6:4]  : TYP(Packet Type)
>>> + *                   000b: CCMD(Control command packet)
>>> + *                   001b: DCMD(Data command packet)
>>> + *                   010b: RES(Response packet)
>>> + *                   011b: DATA(Data payload packet)
>>> + *                   111b: MSG(Message packet)
>>> + *                   Others: Reserved
>>> + *      bit [7]    : NP(Native Packet)
>>> + *      bit [10:8] : TID(Transaction ID)
>>> + *      bit [11]   : Reserved
>>> + *      bit [15:12]: SID(Source ID 0: Node ID of Host)
>>> + *
>>> + * Broadcast CCMD issued by Host is represented as DID=SID=0.
>>> + */
>>> +/*
>>> + * UHS2 Argument:
>>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-5, the format of CCMD Argument is described below:
>>> + *      bit [3:0]  : MSB of IOADR
>>> + *      bit [5:4]  : PLEN(Payload Length)
>>> + *                   00b: 0 byte
>>> + *                   01b: 4 bytes
>>> + *                   10b: 8 bytes
>>> + *                   11b: 16 bytes
>>> + *      bit [6]    : Reserved
>>> + *      bit [7]    : R/W(Read/Write)
>>> + *                   0: Control read command
>>> + *                   1: Control write command
>>> + *      bit [15:8] : LSB of IOADR
>>> + *
>>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
>>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
>>> + */
>>> +#define UHS2_NATIVE_PACKET_POS       7
>>> +#define UHS2_NATIVE_PACKET   (1 << UHS2_NATIVE_PACKET_POS)
>>> +
>>> +#define UHS2_PACKET_TYPE_POS 4
>>> +#define UHS2_PACKET_TYPE_CCMD        (0 << UHS2_PACKET_TYPE_POS)
>>> +#define UHS2_PACKET_TYPE_DCMD        (1 << UHS2_PACKET_TYPE_POS)
>>> +#define UHS2_PACKET_TYPE_RES (2 << UHS2_PACKET_TYPE_POS)
>>> +#define UHS2_PACKET_TYPE_DATA        (3 << UHS2_PACKET_TYPE_POS)
>>> +#define UHS2_PACKET_TYPE_MSG (7 << UHS2_PACKET_TYPE_POS)
>>> +
>>> +#define UHS2_DEST_ID_MASK    0x0F
>>> +#define UHS2_DEST_ID         0x1
>>> +
>>> +#define UHS2_SRC_ID_POS              12
>>> +#define UHS2_SRC_ID_MASK     0xF000
>>> +
>>> +#define UHS2_TRANS_ID_POS    8
>>> +#define UHS2_TRANS_ID_MASK   0x0700
>>> +
>>> +/* UHS2 MSG */
>>> +#define UHS2_MSG_CTG_POS     5
>>> +#define UHS2_MSG_CTG_LMSG    0x00
>>> +#define UHS2_MSG_CTG_INT     0x60
>>> +#define UHS2_MSG_CTG_AMSG    0x80
>>> +
>>> +#define UHS2_MSG_CTG_FCREQ   0x00
>>> +#define UHS2_MSG_CTG_FCRDY   0x01
>>> +#define UHS2_MSG_CTG_STAT    0x02
>>> +
>>> +#define UHS2_MSG_CODE_POS                    8
>>> +#define UHS2_MSG_CODE_FC_UNRECOVER_ERR               0x8
>>> +#define UHS2_MSG_CODE_STAT_UNRECOVER_ERR     0x8
>>> +#define UHS2_MSG_CODE_STAT_RECOVER_ERR               0x1
>>> +
>>> +/* TRANS Layer definition */
>>> +
>>> +/* Native packets*/
>>> +#define UHS2_NATIVE_CMD_RW_POS       7
>>> +#define UHS2_NATIVE_CMD_WRITE        (1 << UHS2_NATIVE_CMD_RW_POS)
>>> +#define UHS2_NATIVE_CMD_READ (0 << UHS2_NATIVE_CMD_RW_POS)
>>> +
>>> +#define UHS2_NATIVE_CMD_PLEN_POS     4
>>> +#define UHS2_NATIVE_CMD_PLEN_4B              (1 << UHS2_NATIVE_CMD_PLEN_POS)
>>> +#define UHS2_NATIVE_CMD_PLEN_8B              (2 << UHS2_NATIVE_CMD_PLEN_POS)
>>> +#define UHS2_NATIVE_CMD_PLEN_16B     (3 << UHS2_NATIVE_CMD_PLEN_POS)
>>> +
>>> +#define UHS2_NATIVE_CCMD_GET_MIOADR_MASK     0xF00
>>> +#define UHS2_NATIVE_CCMD_MIOADR_MASK         0x0F
>>> +
>>> +#define UHS2_NATIVE_CCMD_LIOADR_POS          8
>>> +#define UHS2_NATIVE_CCMD_GET_LIOADR_MASK     0x0FF
>>> +
>>> +#define UHS2_CCMD_DEV_INIT_COMPLETE_FLAG     BIT(11)
>>> +#define UHS2_DEV_INIT_PAYLOAD_LEN            1
>>> +#define UHS2_DEV_INIT_RESP_LEN                       6
>>> +#define UHS2_DEV_ENUM_PAYLOAD_LEN            1
>>> +#define UHS2_DEV_ENUM_RESP_LEN                       8
>>> +#define UHS2_CFG_WRITE_PAYLOAD_LEN           2
>>> +#define UHS2_CFG_WRITE_PHY_SET_RESP_LEN              4
>>> +#define UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN  5
>>> +#define UHS2_GO_DORMANT_PAYLOAD_LEN          1
>>> +
>>> +/*
>>> + * UHS2 Argument:
>>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-8, the format of DCMD Argument is described below:
>>> + *      bit [3:0]  : Reserved
>>> + *      bit [6:3]  : TMODE(Transfer Mode)
>>> + *                   bit 3: DAM(Data Access Mode)
>>> + *                   bit 4: TLUM(TLEN Unit Mode)
>>> + *                   bit 5: LM(Length Mode)
>>> + *                   bit 6: DM(Duplex Mode)
>>> + *      bit [7]    : R/W(Read/Write)
>>> + *                   0: Control read command
>>> + *                   1: Control write command
>>> + *      bit [15:8] : Reserved
>>> + *
>>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
>>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
>>> + */
>>> +#define UHS2_DCMD_DM_POS             6
>>> +#define UHS2_DCMD_2L_HD_MODE         (1 << UHS2_DCMD_DM_POS)
>>> +#define UHS2_DCMD_LM_POS             5
>>> +#define UHS2_DCMD_LM_TLEN_EXIST              (1 << UHS2_DCMD_LM_POS)
>>> +#define UHS2_DCMD_TLUM_POS           4
>>> +#define UHS2_DCMD_TLUM_BYTE_MODE     (1 << UHS2_DCMD_TLUM_POS)
>>> +#define UHS2_NATIVE_DCMD_DAM_POS     3
>>> +#define UHS2_NATIVE_DCMD_DAM_IO              (1 << UHS2_NATIVE_DCMD_DAM_POS)
>>> +
>>> +/*
>>> + * Per UHS2 spec, DCMD payload should be MSB first. There may be
>>> + * two types of data be assembled to MSB:
>>> + * 1. TLEN: Input block size for single read/write and number of blocks
>>> + * for multiple read/write to calculate TLEN as MSB first per spec.
>>> + * 2. SD command argument.
>>> + */
>>> +static inline __be32 uhs2_dcmd_convert_msb(u32 input)
>>> +{
>>> +     u32 ret = 0;
>>> +
>>> +     ret = ((input & 0xFF) << 24) |
>>> +             (((input >> 8) & 0xFF) << 16) |
>>> +             (((input >> 16) & 0xFF) << 8) |
>>> +             ((input >> 24) & 0xFF);
>>> +     return cpu_to_be32(ret);
>>> +}
>>> +
>>> +#define UHS2_RES_NACK_POS    7
>>> +#define UHS2_RES_NACK_MASK   (0x1 << UHS2_RES_NACK_POS)
>>> +
>>> +#define UHS2_RES_ECODE_POS   4
>>> +#define UHS2_RES_ECODE_MASK  0x7
>>> +#define UHS2_RES_ECODE_COND  1
>>> +#define UHS2_RES_ECODE_ARG   2
>>> +#define UHS2_RES_ECODE_GEN   3
>>> +
>>> +/* IOADR of device registers */
>>> +#define UHS2_IOADR_GENERIC_CAPS              0x00
>>> +#define UHS2_IOADR_PHY_CAPS          0x02
>>> +#define UHS2_IOADR_LINK_CAPS         0x04
>>> +#define UHS2_IOADR_RSV_CAPS          0x06
>>> +#define UHS2_IOADR_GENERIC_SETTINGS  0x08
>>> +#define UHS2_IOADR_PHY_SETTINGS              0x0A
>>> +#define UHS2_IOADR_LINK_SETTINGS     0x0C
>>> +#define UHS2_IOADR_PRESET            0x40
>>> +
>>> +/* SD application packets */
>>> +#define UHS2_SD_CMD_INDEX_POS        8
>>> +
>>> +#define UHS2_SD_CMD_APP_POS  14
>>> +#define UHS2_SD_CMD_APP              (1 << UHS2_SD_CMD_APP_POS)
>>> +
>>> +/* UHS-II Device Registers */
>>> +#define UHS2_DEV_CONFIG_REG  0x000
>>> +
>>> +/* General Caps and Settings registers */
>>> +#define UHS2_DEV_CONFIG_GEN_CAPS     (UHS2_DEV_CONFIG_REG + 0x000)
>>> +#define UHS2_DEV_CONFIG_N_LANES_POS  8
>>> +#define UHS2_DEV_CONFIG_N_LANES_MASK 0x3F
>>> +#define UHS2_DEV_CONFIG_2L_HD_FD     0x1
>>> +#define UHS2_DEV_CONFIG_2D1U_FD              0x2
>>> +#define UHS2_DEV_CONFIG_1D2U_FD              0x4
>>> +#define UHS2_DEV_CONFIG_2D2U_FD              0x8
>>> +#define UHS2_DEV_CONFIG_DADR_POS     14
>>> +#define UHS2_DEV_CONFIG_DADR_MASK    0x1
>>> +#define UHS2_DEV_CONFIG_APP_POS              16
>>> +#define UHS2_DEV_CONFIG_APP_MASK     0xFF
>>> +#define UHS2_DEV_CONFIG_APP_SD_MEM   0x1
>>> +
>>> +#define UHS2_DEV_CONFIG_GEN_SET                      (UHS2_DEV_CONFIG_REG + 0x008)
>>> +#define UHS2_DEV_CONFIG_GEN_SET_N_LANES_POS  8
>>> +#define UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD     0x0
>>> +#define UHS2_DEV_CONFIG_GEN_SET_2D1U_FD              0x2
>>> +#define UHS2_DEV_CONFIG_GEN_SET_1D2U_FD              0x3
>>> +#define UHS2_DEV_CONFIG_GEN_SET_2D2U_FD              0x4
>>> +#define UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE BIT(31)
>>> +
>>> +/* PHY Caps and Settings registers */
>>> +#define UHS2_DEV_CONFIG_PHY_CAPS     (UHS2_DEV_CONFIG_REG + 0x002)
>>> +#define UHS2_DEV_CONFIG_PHY_MINOR_MASK       0xF
>>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_POS        4
>>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_MASK       0x3
>>> +#define UHS2_DEV_CONFIG_CAN_HIBER_POS        15
>>> +#define UHS2_DEV_CONFIG_CAN_HIBER_MASK       0x1
>>> +#define UHS2_DEV_CONFIG_PHY_CAPS1    (UHS2_DEV_CONFIG_REG + 0x003)
>>> +#define UHS2_DEV_CONFIG_N_LSS_SYN_MASK       0xF
>>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_POS        4
>>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_MASK       0xF
>>> +
>>> +#define UHS2_DEV_CONFIG_PHY_SET                      (UHS2_DEV_CONFIG_REG + 0x00A)
>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_POS    6
>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_A              0x0
>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_B              0x1
>>> +
>>> +/* LINK-TRAN Caps and Settings registers */
>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS               (UHS2_DEV_CONFIG_REG + 0x004)
>>> +#define UHS2_DEV_CONFIG_LT_MINOR_MASK                0xF
>>> +#define UHS2_DEV_CONFIG_LT_MAJOR_POS         4
>>> +#define UHS2_DEV_CONFIG_LT_MAJOR_MASK                0x3
>>> +#define UHS2_DEV_CONFIG_N_FCU_POS            8
>>> +#define UHS2_DEV_CONFIG_N_FCU_MASK           0xFF
>>> +#define UHS2_DEV_CONFIG_DEV_TYPE_POS         16
>>> +#define UHS2_DEV_CONFIG_DEV_TYPE_MASK                0x7
>>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_POS              20
>>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK     0xFFF
>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS1              (UHS2_DEV_CONFIG_REG + 0x005)
>>> +#define UHS2_DEV_CONFIG_N_DATA_GAP_MASK              0xFF
>>> +
>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_SET                (UHS2_DEV_CONFIG_REG + 0x00C)
>>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN   0x200
>>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS 16
>>> +
>>> +/* Preset register */
>>> +#define UHS2_DEV_CONFIG_PRESET       (UHS2_DEV_CONFIG_REG + 0x040)
>>> +
>>> +#define UHS2_DEV_INT_REG     0x100
>>> +
>>> +#define UHS2_DEV_STATUS_REG  0x180
>>> +
>>> +#define UHS2_DEV_CMD_REG             0x200
>>> +#define UHS2_DEV_CMD_FULL_RESET              (UHS2_DEV_CMD_REG + 0x000)
>>> +#define UHS2_DEV_CMD_GO_DORMANT_STATE        (UHS2_DEV_CMD_REG + 0x001)
>>> +#define UHS2_DEV_CMD_DORMANT_HIBER   BIT(7)
>>> +#define UHS2_DEV_CMD_DEVICE_INIT     (UHS2_DEV_CMD_REG + 0x002)
>>> +#define UHS2_DEV_INIT_COMPLETE_FLAG  BIT(11)
>>> +#define UHS2_DEV_CMD_ENUMERATE               (UHS2_DEV_CMD_REG + 0x003)
>>> +#define UHS2_DEV_CMD_TRANS_ABORT     (UHS2_DEV_CMD_REG + 0x004)
>>> +
>>> +#define UHS2_RCLK_MAX        52000000
>>> +#define UHS2_RCLK_MIN        26000000
>>> +
>>> +struct sd_uhs2_wait_active_state_data {
>>> +     struct mmc_host *host;
>>> +     struct mmc_command *cmd;
>>> +};
>>> +
>>> +#endif /* LINUX_MMC_UHS2_H */
>>
> 
> Thanks, Victor Shih


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards
  2022-11-16 13:48       ` Adrian Hunter
@ 2022-11-17  6:19         ` Ben Chuang
  2022-11-17 16:03           ` Adrian Hunter
  0 siblings, 1 reply; 72+ messages in thread
From: Ben Chuang @ 2022-11-17  6:19 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Victor Shih, ulf.hansson, linux-mmc, linux-kernel, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Jason Lai

Hi,

On Wed, Nov 16, 2022 at 9:48 PM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 16/11/22 13:06, Victor Shih wrote:
> > Hi, Adrian
> >
> > On Wed, Nov 2, 2022 at 1:12 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>
> >> On 19/10/22 14:06, Victor Shih wrote:
> >>> Add UHS-II specific data structures for commands and defines for
> >>> registers, as described in Part 1 UHS-II Addendum Version 1.01.
> >>>
> >>> UHS-II related definitions are listed below:
> >>>   1. UHS-II card capability: sd_uhs2_caps{}
> >>>   2. UHS-II configuration: sd_uhs2_config{}
> >>>   3. UHS-II Command structure: uhs2_command{}
> >>>   4. UHS-II register I/O address and register field definitions: sd_uhs2.h
> >>>
> >>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> >>> Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
> >>> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> >>> ---
> >>>
> >>> Updates in V5:
> >>>  - Added UHS2 interfaces in mmc_host_ops: host.h
> >>>  - Added UHS2 VDD2 power supply in mmc_supply: host.h
> >>>  - Added UHS2-specific OCR and UHS2 VDD2 max current in mmc_host: host.h
> >>>  - Added definition of UHS2 VDD2 1.65v-1.95v in mmc_host: host.h
> >>>  - Added flags/MMC_UHS2_SUPPORT/MMC_UHS2_2L_HD in mmc_host: host.h
> >>> ---
> >>>  include/linux/mmc/card.h    |  42 +++++-
> >>>  include/linux/mmc/core.h    |  13 ++
> >>>  include/linux/mmc/host.h    |  70 +++++++++-
> >>>  include/linux/mmc/sd_uhs2.h | 263 ++++++++++++++++++++++++++++++++++++
> >>>  4 files changed, 386 insertions(+), 2 deletions(-)
> >>>  create mode 100644 include/linux/mmc/sd_uhs2.h
> >>>
> >>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >>> index 4a42f31b7bb0..d638a2c689cf 100644
> >>> --- a/include/linux/mmc/card.h
> >>> +++ b/include/linux/mmc/card.h
> >>> @@ -190,6 +190,13 @@ struct sd_switch_caps {
> >>>  #define SD_MAX_CURRENT_400   (1 << SD_SET_CURRENT_LIMIT_400)
> >>>  #define SD_MAX_CURRENT_600   (1 << SD_SET_CURRENT_LIMIT_600)
> >>>  #define SD_MAX_CURRENT_800   (1 << SD_SET_CURRENT_LIMIT_800)
> >>> +     unsigned int            sd4_curr_limit;
> >>> +#define SD4_SET_POWER_LIMIT_0_72W    0
> >>> +#define SD4_SET_POWER_LIMIT_1_44W    1
> >>> +#define SD4_SET_POWER_LIMIT_2_16W    2
> >>> +#define SD4_SET_POWER_LIMIT_2_88W    3
> >>> +#define SD4_SET_POWER_LIMIT_1_80W    4
> >>> +#define SD4_SET_POWER_NO_CHANGE              (-1)
> >>>  };
> >>>
> >>>  struct sd_ext_reg {
> >>> @@ -213,7 +220,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 {
> >>> @@ -323,6 +358,9 @@ struct mmc_card {
> >>>       struct sd_ext_reg       ext_perf;       /* SD extension reg for PERF */
> >>>
> >>>       struct sd_uhs2_config   uhs2_config;    /* SD UHS-II config */
> >>> +     u8                      uhs2_state;     /* SD UHS-II states */
> >>> +#define MMC_UHS2_INITIALIZED BIT(1)
> >>> +#define MMC_UHS2_SPEED_B     BIT(2)
> >>>
> >>>       unsigned int            sdio_funcs;     /* number of SDIO functions */
> >>>       atomic_t                sdio_funcs_probed; /* number of probed SDIO funcs */
> >>> @@ -364,4 +402,6 @@ bool mmc_card_is_blockaddr(struct mmc_card *card);
> >>>  #define mmc_card_sdio(c)     ((c)->type == MMC_TYPE_SDIO)
> >>>  #define mmc_card_sd_combo(c) ((c)->type == MMC_TYPE_SD_COMBO)
> >>>
> >>> +#define mmc_card_can_poweroff_notify(c)      ((c)->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY)
> >>> +
> >>>  #endif /* LINUX_MMC_CARD_H */
> >>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> >>> index 6efec0b9820c..2a0581d87706 100644
> >>> --- a/include/linux/mmc/core.h
> >>> +++ b/include/linux/mmc/core.h
> >>> @@ -23,6 +23,14 @@ enum mmc_blk_status {
> >>>       MMC_BLK_NEW_REQUEST,
> >>>  };
> >>>
> >>> +struct uhs2_command {
> >>> +     u16     header;
> >>> +     u16     arg;
> >>> +     __be32  *payload;
> >>> +     u32     payload_len;
> >>> +     u32     packet_len;
> >>> +};
> >>> +
> >>>  struct mmc_command {
> >>>       u32                     opcode;
> >>>       u32                     arg;
> >>> @@ -109,6 +117,11 @@ struct mmc_command {
> >>>       unsigned int            busy_timeout;   /* busy detect timeout in ms */
> >>>       struct mmc_data         *data;          /* data segment associated with cmd */
> >>>       struct mmc_request      *mrq;           /* associated request */
> >>> +
> >>> +     struct uhs2_command     *uhs2_cmd;      /* UHS2 command */
> >>> +     u8                      *uhs2_resp;     /* UHS2 native cmd resp */
> >>> +     u8                      uhs2_resp_len;  /* UHS2 native cmd resp len */
> >>> +     u8                      uhs2_tmode0_flag; /* UHS2 transfer mode flag */
> >>>  };
> >>>
> >>>  struct mmc_data {
> >>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >>> index 895bcf7f80b7..249a9414ad10 100644
> >>> --- a/include/linux/mmc/host.h
> >>> +++ b/include/linux/mmc/host.h
> >>> @@ -16,6 +16,7 @@
> >>>  #include <linux/mmc/pm.h>
> >>>  #include <linux/dma-direction.h>
> >>>  #include <linux/blk-crypto-profile.h>
> >>> +#include <linux/mmc/sd_uhs2.h>
> >>>
> >>>  struct mmc_ios {
> >>>       unsigned int    clock;                  /* clock rate */
> >>> @@ -96,7 +97,48 @@ struct mmc_clk_phase_map {
> >>>  };
> >>>
> >>>  struct sd_uhs2_caps {
> >>> -     /* TODO: Add UHS-II capabilities for the host. */
> >>> +     u32     dap;
> >>> +     u32     gap;
> >>> +     u32     group_desc;
> >>> +     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 sd_uhs2_ios {
> >>> +     bool            is_2L_HD_mode;
> >>> +     bool            is_APP_CMD;
> >>> +     unsigned int    power_delay_ms;         /* waiting for stable power */
> >>> +};
> >>> +
> >>> +enum sd_uhs2_operation {
> >>> +     UHS2_PHY_INIT = 0,
> >>> +     UHS2_SET_CONFIG,
> >>> +     UHS2_ENABLE_INT,
> >>> +     UHS2_DISABLE_INT,
> >>> +     UHS2_ENABLE_CLK,
> >>> +     UHS2_DISABLE_CLK,
> >>> +     UHS2_CHECK_DORMANT,
> >>> +     UHS2_SET_SPEED_B,
> >>> +     UHS2_POST_ATTACH_SD,
> >>>  };
> >>>
> >>>  struct mmc_host;
> >>> @@ -231,6 +273,20 @@ 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 */
> >>> +     int     (*uhs2_detect_init)(struct mmc_host *host);
> >>
> >> Never called?
> >
> > Yes, I will delete it.
> >
> >>
> >>> +     int     (*uhs2_set_reg)(struct mmc_host *host, enum sd_uhs2_operation act);
> >>
> >> Never called?
> >
> > Yes, I will delete it.
> >
> >>
> >>> +     int (*uhs2_disable_clk)(struct mmc_host *host);
> >>
> >> Never called?
> >
> > Yes, I will delete it.
> >
> >>
> >>> +     int (*uhs2_enable_clk)(struct mmc_host *host);
> >>
> >> Never called?
> >
> > Yes, I will delete it.
> >
> >>
> >>> +
> >>> +     /*
> >>> +      * The uhs2_control callback is used to execute SD UHS-II specific
> >>> +      * operations. It's mandatory to implement for hosts that supports the
> >>> +      * SD UHS-II interface (MMC_CAP2_SD_UHS2). Expected return values are a
> >>> +      * negative errno in case of a failure or zero for success.
> >>> +      */
> >>> +     int     (*uhs2_control)(struct mmc_host *host, enum sd_uhs2_operation op);
> >>>  };
> >>>
> >>>  struct mmc_cqe_ops {
> >>> @@ -323,6 +379,7 @@ struct mmc_pwrseq;
> >>>
> >>>  struct mmc_supply {
> >>>       struct regulator *vmmc;         /* Card power supply */
> >>> +     struct regulator *vmmc2;        /* UHS2 VDD2 power supply */
> >>>       struct regulator *vqmmc;        /* Optional Vccq supply */
> >>>       struct regulator *vqmmc2;       /* Optional supply for phy */
> >>>  };
> >>> @@ -344,10 +401,12 @@ struct mmc_host {
> >>>       u32                     ocr_avail_sdio; /* SDIO-specific OCR */
> >>>       u32                     ocr_avail_sd;   /* SD-specific OCR */
> >>>       u32                     ocr_avail_mmc;  /* MMC-specific OCR */
> >>> +     u32                     ocr_avail_uhs2; /* UHS2-specific OCR */
> >>>       struct wakeup_source    *ws;            /* Enable consume of uevents */
> >>>       u32                     max_current_330;
> >>>       u32                     max_current_300;
> >>>       u32                     max_current_180;
> >>> +     u32                     max_current_180_vdd2; /* UHS2 vdd2 max curt. */
> >>>
> >>>  #define MMC_VDD_165_195              0x00000080      /* VDD voltage 1.65 - 1.95 */
> >>>  #define MMC_VDD_20_21                0x00000100      /* VDD voltage 2.0 ~ 2.1 */
> >>> @@ -366,6 +425,7 @@ struct mmc_host {
> >>>  #define MMC_VDD_33_34                0x00200000      /* VDD voltage 3.3 ~ 3.4 */
> >>>  #define MMC_VDD_34_35                0x00400000      /* VDD voltage 3.4 ~ 3.5 */
> >>>  #define MMC_VDD_35_36                0x00800000      /* VDD voltage 3.5 ~ 3.6 */
> >>> +#define MMC_VDD2_165_195     0x00000080      /* UHS2 VDD2 1.65 ~ 1.95 */
> >>>
> >>>       u32                     caps;           /* Host capabilities */
> >>>
> >>> @@ -443,7 +503,12 @@ struct mmc_host {
> >>>  #endif
> >>>  #define MMC_CAP2_ALT_GPT_TEGRA       (1 << 28)       /* Host with eMMC that has GPT entry at a non-standard location */
> >>>
> >>> +     int flags;
> >>> +#define MMC_UHS2_SUPPORT     (1 << 0)
> >>
> >> MMC_UHS2_SUPPORT is getting mixed up with MMC_UHS2_INITIALIZED.
> >> Both have the same value, but MMC_UHS2_SUPPORT is for
> >> host->flags and MMC_UHS2_INITIALIZED is for card->uhs2_state
> >>
> >> Please use the correct flag with the correct variable.
> >>
> >
> > The value of MMC_UHS2_SUPPORT is (1<<0) and the value of
> > MMC_UHS2_INITIALIZED is BIT(1).
> > Both have different values, therefore I'm not sure what you mean.
> > May you give me some more advice? Thanks.
>
> I guess I got confused about the values, however it is not OK to
> use MMC_UHS2_INITIALIZED for both mmc->flags and card->uhs2_state.
> Please make a separate define with a different name for mmc->flags
> version of MMC_UHS2_INITIALIZED.

MMC_UHS2_INITIALIZED here is used to judge that the UHS-II I/F has been
initialized and can run in SD-TRAN. In this state,  some SD commands
require a distinction. For example, ACMD (CMD55) should be set by the APP
field in UHS-II packet.

>
> Also, I am confused about the purpose of mmc->flags and
> card->uhs2_state.

It looks like the mmc->flags and card->uhs2_state have the same purpose.
I think it is having trouble with card == NULL in mmc_app_cmd(*host, *card)
in patch [V5, 06/26] so just add one more mmc->flags.
Can wait for confirmation from Victor.

>
> A host is UHS-II capable as represented by MMC_CAP2_SD_UHS2.
> To initialize and use a UHS-II card in UHS-II mode, the host
> must be in UHS-II mode.
> To initialize and use a UHS-II card in SD mode, the host
> must be in SD mode.
> So the state of the card and host is always the same:
> either UHS-II or not.  Note, that is a consequence of the
> hardware I/F.  Whether SD I/F or UHS-II I/F is used is
> decided before sending any UHS-II commands. SD I/F is
> disabled during UHS-II PHY initialization, whereas
> UHS-II I/F is disabled before execution of ACMD41 is
> completed.
>
> So it seems like there would only be a need for one flag
> to indicate UHS-II mode?
>
> >
> >>> +#define MMC_UHS2_2L_HD               (1 << 2)
> >>
> >> MMC_UHS2_2L_HD does not seem to be used. Is it needed?
> >
> > I confirmed this, I don't use it, I will delete it.
> >
> >>
> >>> +
> >>>       struct sd_uhs2_caps     uhs2_caps;      /* Host UHS-II capabilities */
> >>> +     struct sd_uhs2_ios      uhs2_ios;       /* Host UHS-II capabilities */
> >>>
> >>>       int                     fixed_drv_type; /* fixed driver type for non-removable media */
> >>>
> >>> @@ -695,4 +760,7 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
> >>>  int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
> >>>  int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
> >>>
> >>> +#define mmc_uhs2_2L_HD_mode(h)       ((h)->uhs2_ios.is_2L_HD_mode)
> >>> +#define mmc_uhs2_APP_cmd(h)  ((h)->uhs2_ios.is_APP_CMD)
> >>> +
> >>>  #endif /* LINUX_MMC_HOST_H */
> >>> diff --git a/include/linux/mmc/sd_uhs2.h b/include/linux/mmc/sd_uhs2.h
> >>> new file mode 100644
> >>> index 000000000000..8fcf702cf4a5
> >>> --- /dev/null
> >>> +++ b/include/linux/mmc/sd_uhs2.h
> >>> @@ -0,0 +1,263 @@
> >>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> >>> +/*
> >>> + * Header file for UHS-II packets, Host Controller registers and I/O
> >>> + * accessors.
> >>> + *
> >>> + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> >>> + */
> >>> +#ifndef LINUX_MMC_UHS2_H
> >>> +#define LINUX_MMC_UHS2_H
> >>> +
> >>> +/* LINK Layer definition */
> >>> +/*
> >>> + * UHS2 Header:
> >>> + * Refer to UHS-II Addendum Version 1.02 Figure 5-2, the format of CCMD Header is described below:
> >>> + *      bit [3:0]  : DID(Destination ID = Node ID of UHS2 card)
> >>> + *      bit [6:4]  : TYP(Packet Type)
> >>> + *                   000b: CCMD(Control command packet)
> >>> + *                   001b: DCMD(Data command packet)
> >>> + *                   010b: RES(Response packet)
> >>> + *                   011b: DATA(Data payload packet)
> >>> + *                   111b: MSG(Message packet)
> >>> + *                   Others: Reserved
> >>> + *      bit [7]    : NP(Native Packet)
> >>> + *      bit [10:8] : TID(Transaction ID)
> >>> + *      bit [11]   : Reserved
> >>> + *      bit [15:12]: SID(Source ID 0: Node ID of Host)
> >>> + *
> >>> + * Broadcast CCMD issued by Host is represented as DID=SID=0.
> >>> + */
> >>> +/*
> >>> + * UHS2 Argument:
> >>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-5, the format of CCMD Argument is described below:
> >>> + *      bit [3:0]  : MSB of IOADR
> >>> + *      bit [5:4]  : PLEN(Payload Length)
> >>> + *                   00b: 0 byte
> >>> + *                   01b: 4 bytes
> >>> + *                   10b: 8 bytes
> >>> + *                   11b: 16 bytes
> >>> + *      bit [6]    : Reserved
> >>> + *      bit [7]    : R/W(Read/Write)
> >>> + *                   0: Control read command
> >>> + *                   1: Control write command
> >>> + *      bit [15:8] : LSB of IOADR
> >>> + *
> >>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> >>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> >>> + */
> >>> +#define UHS2_NATIVE_PACKET_POS       7
> >>> +#define UHS2_NATIVE_PACKET   (1 << UHS2_NATIVE_PACKET_POS)
> >>> +
> >>> +#define UHS2_PACKET_TYPE_POS 4
> >>> +#define UHS2_PACKET_TYPE_CCMD        (0 << UHS2_PACKET_TYPE_POS)
> >>> +#define UHS2_PACKET_TYPE_DCMD        (1 << UHS2_PACKET_TYPE_POS)
> >>> +#define UHS2_PACKET_TYPE_RES (2 << UHS2_PACKET_TYPE_POS)
> >>> +#define UHS2_PACKET_TYPE_DATA        (3 << UHS2_PACKET_TYPE_POS)
> >>> +#define UHS2_PACKET_TYPE_MSG (7 << UHS2_PACKET_TYPE_POS)
> >>> +
> >>> +#define UHS2_DEST_ID_MASK    0x0F
> >>> +#define UHS2_DEST_ID         0x1
> >>> +
> >>> +#define UHS2_SRC_ID_POS              12
> >>> +#define UHS2_SRC_ID_MASK     0xF000
> >>> +
> >>> +#define UHS2_TRANS_ID_POS    8
> >>> +#define UHS2_TRANS_ID_MASK   0x0700
> >>> +
> >>> +/* UHS2 MSG */
> >>> +#define UHS2_MSG_CTG_POS     5
> >>> +#define UHS2_MSG_CTG_LMSG    0x00
> >>> +#define UHS2_MSG_CTG_INT     0x60
> >>> +#define UHS2_MSG_CTG_AMSG    0x80
> >>> +
> >>> +#define UHS2_MSG_CTG_FCREQ   0x00
> >>> +#define UHS2_MSG_CTG_FCRDY   0x01
> >>> +#define UHS2_MSG_CTG_STAT    0x02
> >>> +
> >>> +#define UHS2_MSG_CODE_POS                    8
> >>> +#define UHS2_MSG_CODE_FC_UNRECOVER_ERR               0x8
> >>> +#define UHS2_MSG_CODE_STAT_UNRECOVER_ERR     0x8
> >>> +#define UHS2_MSG_CODE_STAT_RECOVER_ERR               0x1
> >>> +
> >>> +/* TRANS Layer definition */
> >>> +
> >>> +/* Native packets*/
> >>> +#define UHS2_NATIVE_CMD_RW_POS       7
> >>> +#define UHS2_NATIVE_CMD_WRITE        (1 << UHS2_NATIVE_CMD_RW_POS)
> >>> +#define UHS2_NATIVE_CMD_READ (0 << UHS2_NATIVE_CMD_RW_POS)
> >>> +
> >>> +#define UHS2_NATIVE_CMD_PLEN_POS     4
> >>> +#define UHS2_NATIVE_CMD_PLEN_4B              (1 << UHS2_NATIVE_CMD_PLEN_POS)
> >>> +#define UHS2_NATIVE_CMD_PLEN_8B              (2 << UHS2_NATIVE_CMD_PLEN_POS)
> >>> +#define UHS2_NATIVE_CMD_PLEN_16B     (3 << UHS2_NATIVE_CMD_PLEN_POS)
> >>> +
> >>> +#define UHS2_NATIVE_CCMD_GET_MIOADR_MASK     0xF00
> >>> +#define UHS2_NATIVE_CCMD_MIOADR_MASK         0x0F
> >>> +
> >>> +#define UHS2_NATIVE_CCMD_LIOADR_POS          8
> >>> +#define UHS2_NATIVE_CCMD_GET_LIOADR_MASK     0x0FF
> >>> +
> >>> +#define UHS2_CCMD_DEV_INIT_COMPLETE_FLAG     BIT(11)
> >>> +#define UHS2_DEV_INIT_PAYLOAD_LEN            1
> >>> +#define UHS2_DEV_INIT_RESP_LEN                       6
> >>> +#define UHS2_DEV_ENUM_PAYLOAD_LEN            1
> >>> +#define UHS2_DEV_ENUM_RESP_LEN                       8
> >>> +#define UHS2_CFG_WRITE_PAYLOAD_LEN           2
> >>> +#define UHS2_CFG_WRITE_PHY_SET_RESP_LEN              4
> >>> +#define UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN  5
> >>> +#define UHS2_GO_DORMANT_PAYLOAD_LEN          1
> >>> +
> >>> +/*
> >>> + * UHS2 Argument:
> >>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-8, the format of DCMD Argument is described below:
> >>> + *      bit [3:0]  : Reserved
> >>> + *      bit [6:3]  : TMODE(Transfer Mode)
> >>> + *                   bit 3: DAM(Data Access Mode)
> >>> + *                   bit 4: TLUM(TLEN Unit Mode)
> >>> + *                   bit 5: LM(Length Mode)
> >>> + *                   bit 6: DM(Duplex Mode)
> >>> + *      bit [7]    : R/W(Read/Write)
> >>> + *                   0: Control read command
> >>> + *                   1: Control write command
> >>> + *      bit [15:8] : Reserved
> >>> + *
> >>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> >>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> >>> + */
> >>> +#define UHS2_DCMD_DM_POS             6
> >>> +#define UHS2_DCMD_2L_HD_MODE         (1 << UHS2_DCMD_DM_POS)
> >>> +#define UHS2_DCMD_LM_POS             5
> >>> +#define UHS2_DCMD_LM_TLEN_EXIST              (1 << UHS2_DCMD_LM_POS)
> >>> +#define UHS2_DCMD_TLUM_POS           4
> >>> +#define UHS2_DCMD_TLUM_BYTE_MODE     (1 << UHS2_DCMD_TLUM_POS)
> >>> +#define UHS2_NATIVE_DCMD_DAM_POS     3
> >>> +#define UHS2_NATIVE_DCMD_DAM_IO              (1 << UHS2_NATIVE_DCMD_DAM_POS)
> >>> +
> >>> +/*
> >>> + * Per UHS2 spec, DCMD payload should be MSB first. There may be
> >>> + * two types of data be assembled to MSB:
> >>> + * 1. TLEN: Input block size for single read/write and number of blocks
> >>> + * for multiple read/write to calculate TLEN as MSB first per spec.
> >>> + * 2. SD command argument.
> >>> + */
> >>> +static inline __be32 uhs2_dcmd_convert_msb(u32 input)
> >>> +{
> >>> +     u32 ret = 0;
> >>> +
> >>> +     ret = ((input & 0xFF) << 24) |
> >>> +             (((input >> 8) & 0xFF) << 16) |
> >>> +             (((input >> 16) & 0xFF) << 8) |
> >>> +             ((input >> 24) & 0xFF);
> >>> +     return cpu_to_be32(ret);
> >>> +}
> >>> +
> >>> +#define UHS2_RES_NACK_POS    7
> >>> +#define UHS2_RES_NACK_MASK   (0x1 << UHS2_RES_NACK_POS)
> >>> +
> >>> +#define UHS2_RES_ECODE_POS   4
> >>> +#define UHS2_RES_ECODE_MASK  0x7
> >>> +#define UHS2_RES_ECODE_COND  1
> >>> +#define UHS2_RES_ECODE_ARG   2
> >>> +#define UHS2_RES_ECODE_GEN   3
> >>> +
> >>> +/* IOADR of device registers */
> >>> +#define UHS2_IOADR_GENERIC_CAPS              0x00
> >>> +#define UHS2_IOADR_PHY_CAPS          0x02
> >>> +#define UHS2_IOADR_LINK_CAPS         0x04
> >>> +#define UHS2_IOADR_RSV_CAPS          0x06
> >>> +#define UHS2_IOADR_GENERIC_SETTINGS  0x08
> >>> +#define UHS2_IOADR_PHY_SETTINGS              0x0A
> >>> +#define UHS2_IOADR_LINK_SETTINGS     0x0C
> >>> +#define UHS2_IOADR_PRESET            0x40
> >>> +
> >>> +/* SD application packets */
> >>> +#define UHS2_SD_CMD_INDEX_POS        8
> >>> +
> >>> +#define UHS2_SD_CMD_APP_POS  14
> >>> +#define UHS2_SD_CMD_APP              (1 << UHS2_SD_CMD_APP_POS)
> >>> +
> >>> +/* UHS-II Device Registers */
> >>> +#define UHS2_DEV_CONFIG_REG  0x000
> >>> +
> >>> +/* General Caps and Settings registers */
> >>> +#define UHS2_DEV_CONFIG_GEN_CAPS     (UHS2_DEV_CONFIG_REG + 0x000)
> >>> +#define UHS2_DEV_CONFIG_N_LANES_POS  8
> >>> +#define UHS2_DEV_CONFIG_N_LANES_MASK 0x3F
> >>> +#define UHS2_DEV_CONFIG_2L_HD_FD     0x1
> >>> +#define UHS2_DEV_CONFIG_2D1U_FD              0x2
> >>> +#define UHS2_DEV_CONFIG_1D2U_FD              0x4
> >>> +#define UHS2_DEV_CONFIG_2D2U_FD              0x8
> >>> +#define UHS2_DEV_CONFIG_DADR_POS     14
> >>> +#define UHS2_DEV_CONFIG_DADR_MASK    0x1
> >>> +#define UHS2_DEV_CONFIG_APP_POS              16
> >>> +#define UHS2_DEV_CONFIG_APP_MASK     0xFF
> >>> +#define UHS2_DEV_CONFIG_APP_SD_MEM   0x1
> >>> +
> >>> +#define UHS2_DEV_CONFIG_GEN_SET                      (UHS2_DEV_CONFIG_REG + 0x008)
> >>> +#define UHS2_DEV_CONFIG_GEN_SET_N_LANES_POS  8
> >>> +#define UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD     0x0
> >>> +#define UHS2_DEV_CONFIG_GEN_SET_2D1U_FD              0x2
> >>> +#define UHS2_DEV_CONFIG_GEN_SET_1D2U_FD              0x3
> >>> +#define UHS2_DEV_CONFIG_GEN_SET_2D2U_FD              0x4
> >>> +#define UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE BIT(31)
> >>> +
> >>> +/* PHY Caps and Settings registers */
> >>> +#define UHS2_DEV_CONFIG_PHY_CAPS     (UHS2_DEV_CONFIG_REG + 0x002)
> >>> +#define UHS2_DEV_CONFIG_PHY_MINOR_MASK       0xF
> >>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_POS        4
> >>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_MASK       0x3
> >>> +#define UHS2_DEV_CONFIG_CAN_HIBER_POS        15
> >>> +#define UHS2_DEV_CONFIG_CAN_HIBER_MASK       0x1
> >>> +#define UHS2_DEV_CONFIG_PHY_CAPS1    (UHS2_DEV_CONFIG_REG + 0x003)
> >>> +#define UHS2_DEV_CONFIG_N_LSS_SYN_MASK       0xF
> >>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_POS        4
> >>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_MASK       0xF
> >>> +
> >>> +#define UHS2_DEV_CONFIG_PHY_SET                      (UHS2_DEV_CONFIG_REG + 0x00A)
> >>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_POS    6
> >>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_A              0x0
> >>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_B              0x1
> >>> +
> >>> +/* LINK-TRAN Caps and Settings registers */
> >>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS               (UHS2_DEV_CONFIG_REG + 0x004)
> >>> +#define UHS2_DEV_CONFIG_LT_MINOR_MASK                0xF
> >>> +#define UHS2_DEV_CONFIG_LT_MAJOR_POS         4
> >>> +#define UHS2_DEV_CONFIG_LT_MAJOR_MASK                0x3
> >>> +#define UHS2_DEV_CONFIG_N_FCU_POS            8
> >>> +#define UHS2_DEV_CONFIG_N_FCU_MASK           0xFF
> >>> +#define UHS2_DEV_CONFIG_DEV_TYPE_POS         16
> >>> +#define UHS2_DEV_CONFIG_DEV_TYPE_MASK                0x7
> >>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_POS              20
> >>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK     0xFFF
> >>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS1              (UHS2_DEV_CONFIG_REG + 0x005)
> >>> +#define UHS2_DEV_CONFIG_N_DATA_GAP_MASK              0xFF
> >>> +
> >>> +#define UHS2_DEV_CONFIG_LINK_TRAN_SET                (UHS2_DEV_CONFIG_REG + 0x00C)
> >>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN   0x200
> >>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS 16
> >>> +
> >>> +/* Preset register */
> >>> +#define UHS2_DEV_CONFIG_PRESET       (UHS2_DEV_CONFIG_REG + 0x040)
> >>> +
> >>> +#define UHS2_DEV_INT_REG     0x100
> >>> +
> >>> +#define UHS2_DEV_STATUS_REG  0x180
> >>> +
> >>> +#define UHS2_DEV_CMD_REG             0x200
> >>> +#define UHS2_DEV_CMD_FULL_RESET              (UHS2_DEV_CMD_REG + 0x000)
> >>> +#define UHS2_DEV_CMD_GO_DORMANT_STATE        (UHS2_DEV_CMD_REG + 0x001)
> >>> +#define UHS2_DEV_CMD_DORMANT_HIBER   BIT(7)
> >>> +#define UHS2_DEV_CMD_DEVICE_INIT     (UHS2_DEV_CMD_REG + 0x002)
> >>> +#define UHS2_DEV_INIT_COMPLETE_FLAG  BIT(11)
> >>> +#define UHS2_DEV_CMD_ENUMERATE               (UHS2_DEV_CMD_REG + 0x003)
> >>> +#define UHS2_DEV_CMD_TRANS_ABORT     (UHS2_DEV_CMD_REG + 0x004)
> >>> +
> >>> +#define UHS2_RCLK_MAX        52000000
> >>> +#define UHS2_RCLK_MIN        26000000
> >>> +
> >>> +struct sd_uhs2_wait_active_state_data {
> >>> +     struct mmc_host *host;
> >>> +     struct mmc_command *cmd;
> >>> +};
> >>> +
> >>> +#endif /* LINUX_MMC_UHS2_H */
> >>
> >
> > Thanks, Victor Shih
>

Best regards,
Ben Chuang

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards
  2022-11-17  6:19         ` Ben Chuang
@ 2022-11-17 16:03           ` Adrian Hunter
  2022-11-18  1:19             ` Ben Chuang
  0 siblings, 1 reply; 72+ messages in thread
From: Adrian Hunter @ 2022-11-17 16:03 UTC (permalink / raw)
  To: Ben Chuang
  Cc: Victor Shih, ulf.hansson, linux-mmc, linux-kernel, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Jason Lai

On 17/11/22 08:19, Ben Chuang wrote:
> Hi,
> 
> On Wed, Nov 16, 2022 at 9:48 PM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> On 16/11/22 13:06, Victor Shih wrote:
>>> Hi, Adrian
>>>
>>> On Wed, Nov 2, 2022 at 1:12 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>
>>>> On 19/10/22 14:06, Victor Shih wrote:
>>>>> Add UHS-II specific data structures for commands and defines for
>>>>> registers, as described in Part 1 UHS-II Addendum Version 1.01.
>>>>>
>>>>> UHS-II related definitions are listed below:
>>>>>   1. UHS-II card capability: sd_uhs2_caps{}
>>>>>   2. UHS-II configuration: sd_uhs2_config{}
>>>>>   3. UHS-II Command structure: uhs2_command{}
>>>>>   4. UHS-II register I/O address and register field definitions: sd_uhs2.h
>>>>>
>>>>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>>>>> Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
>>>>> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
>>>>> ---
>>>>>
>>>>> Updates in V5:
>>>>>  - Added UHS2 interfaces in mmc_host_ops: host.h
>>>>>  - Added UHS2 VDD2 power supply in mmc_supply: host.h
>>>>>  - Added UHS2-specific OCR and UHS2 VDD2 max current in mmc_host: host.h
>>>>>  - Added definition of UHS2 VDD2 1.65v-1.95v in mmc_host: host.h
>>>>>  - Added flags/MMC_UHS2_SUPPORT/MMC_UHS2_2L_HD in mmc_host: host.h
>>>>> ---
>>>>>  include/linux/mmc/card.h    |  42 +++++-
>>>>>  include/linux/mmc/core.h    |  13 ++
>>>>>  include/linux/mmc/host.h    |  70 +++++++++-
>>>>>  include/linux/mmc/sd_uhs2.h | 263 ++++++++++++++++++++++++++++++++++++
>>>>>  4 files changed, 386 insertions(+), 2 deletions(-)
>>>>>  create mode 100644 include/linux/mmc/sd_uhs2.h
>>>>>
>>>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>>>> index 4a42f31b7bb0..d638a2c689cf 100644
>>>>> --- a/include/linux/mmc/card.h
>>>>> +++ b/include/linux/mmc/card.h
>>>>> @@ -190,6 +190,13 @@ struct sd_switch_caps {
>>>>>  #define SD_MAX_CURRENT_400   (1 << SD_SET_CURRENT_LIMIT_400)
>>>>>  #define SD_MAX_CURRENT_600   (1 << SD_SET_CURRENT_LIMIT_600)
>>>>>  #define SD_MAX_CURRENT_800   (1 << SD_SET_CURRENT_LIMIT_800)
>>>>> +     unsigned int            sd4_curr_limit;
>>>>> +#define SD4_SET_POWER_LIMIT_0_72W    0
>>>>> +#define SD4_SET_POWER_LIMIT_1_44W    1
>>>>> +#define SD4_SET_POWER_LIMIT_2_16W    2
>>>>> +#define SD4_SET_POWER_LIMIT_2_88W    3
>>>>> +#define SD4_SET_POWER_LIMIT_1_80W    4
>>>>> +#define SD4_SET_POWER_NO_CHANGE              (-1)
>>>>>  };
>>>>>
>>>>>  struct sd_ext_reg {
>>>>> @@ -213,7 +220,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 {
>>>>> @@ -323,6 +358,9 @@ struct mmc_card {
>>>>>       struct sd_ext_reg       ext_perf;       /* SD extension reg for PERF */
>>>>>
>>>>>       struct sd_uhs2_config   uhs2_config;    /* SD UHS-II config */
>>>>> +     u8                      uhs2_state;     /* SD UHS-II states */
>>>>> +#define MMC_UHS2_INITIALIZED BIT(1)
>>>>> +#define MMC_UHS2_SPEED_B     BIT(2)
>>>>>
>>>>>       unsigned int            sdio_funcs;     /* number of SDIO functions */
>>>>>       atomic_t                sdio_funcs_probed; /* number of probed SDIO funcs */
>>>>> @@ -364,4 +402,6 @@ bool mmc_card_is_blockaddr(struct mmc_card *card);
>>>>>  #define mmc_card_sdio(c)     ((c)->type == MMC_TYPE_SDIO)
>>>>>  #define mmc_card_sd_combo(c) ((c)->type == MMC_TYPE_SD_COMBO)
>>>>>
>>>>> +#define mmc_card_can_poweroff_notify(c)      ((c)->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY)
>>>>> +
>>>>>  #endif /* LINUX_MMC_CARD_H */
>>>>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
>>>>> index 6efec0b9820c..2a0581d87706 100644
>>>>> --- a/include/linux/mmc/core.h
>>>>> +++ b/include/linux/mmc/core.h
>>>>> @@ -23,6 +23,14 @@ enum mmc_blk_status {
>>>>>       MMC_BLK_NEW_REQUEST,
>>>>>  };
>>>>>
>>>>> +struct uhs2_command {
>>>>> +     u16     header;
>>>>> +     u16     arg;
>>>>> +     __be32  *payload;
>>>>> +     u32     payload_len;
>>>>> +     u32     packet_len;
>>>>> +};
>>>>> +
>>>>>  struct mmc_command {
>>>>>       u32                     opcode;
>>>>>       u32                     arg;
>>>>> @@ -109,6 +117,11 @@ struct mmc_command {
>>>>>       unsigned int            busy_timeout;   /* busy detect timeout in ms */
>>>>>       struct mmc_data         *data;          /* data segment associated with cmd */
>>>>>       struct mmc_request      *mrq;           /* associated request */
>>>>> +
>>>>> +     struct uhs2_command     *uhs2_cmd;      /* UHS2 command */
>>>>> +     u8                      *uhs2_resp;     /* UHS2 native cmd resp */
>>>>> +     u8                      uhs2_resp_len;  /* UHS2 native cmd resp len */
>>>>> +     u8                      uhs2_tmode0_flag; /* UHS2 transfer mode flag */
>>>>>  };
>>>>>
>>>>>  struct mmc_data {
>>>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>>>>> index 895bcf7f80b7..249a9414ad10 100644
>>>>> --- a/include/linux/mmc/host.h
>>>>> +++ b/include/linux/mmc/host.h
>>>>> @@ -16,6 +16,7 @@
>>>>>  #include <linux/mmc/pm.h>
>>>>>  #include <linux/dma-direction.h>
>>>>>  #include <linux/blk-crypto-profile.h>
>>>>> +#include <linux/mmc/sd_uhs2.h>
>>>>>
>>>>>  struct mmc_ios {
>>>>>       unsigned int    clock;                  /* clock rate */
>>>>> @@ -96,7 +97,48 @@ struct mmc_clk_phase_map {
>>>>>  };
>>>>>
>>>>>  struct sd_uhs2_caps {
>>>>> -     /* TODO: Add UHS-II capabilities for the host. */
>>>>> +     u32     dap;
>>>>> +     u32     gap;
>>>>> +     u32     group_desc;
>>>>> +     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 sd_uhs2_ios {
>>>>> +     bool            is_2L_HD_mode;
>>>>> +     bool            is_APP_CMD;
>>>>> +     unsigned int    power_delay_ms;         /* waiting for stable power */
>>>>> +};
>>>>> +
>>>>> +enum sd_uhs2_operation {
>>>>> +     UHS2_PHY_INIT = 0,
>>>>> +     UHS2_SET_CONFIG,
>>>>> +     UHS2_ENABLE_INT,
>>>>> +     UHS2_DISABLE_INT,
>>>>> +     UHS2_ENABLE_CLK,
>>>>> +     UHS2_DISABLE_CLK,
>>>>> +     UHS2_CHECK_DORMANT,
>>>>> +     UHS2_SET_SPEED_B,
>>>>> +     UHS2_POST_ATTACH_SD,
>>>>>  };
>>>>>
>>>>>  struct mmc_host;
>>>>> @@ -231,6 +273,20 @@ 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 */
>>>>> +     int     (*uhs2_detect_init)(struct mmc_host *host);
>>>>
>>>> Never called?
>>>
>>> Yes, I will delete it.
>>>
>>>>
>>>>> +     int     (*uhs2_set_reg)(struct mmc_host *host, enum sd_uhs2_operation act);
>>>>
>>>> Never called?
>>>
>>> Yes, I will delete it.
>>>
>>>>
>>>>> +     int (*uhs2_disable_clk)(struct mmc_host *host);
>>>>
>>>> Never called?
>>>
>>> Yes, I will delete it.
>>>
>>>>
>>>>> +     int (*uhs2_enable_clk)(struct mmc_host *host);
>>>>
>>>> Never called?
>>>
>>> Yes, I will delete it.
>>>
>>>>
>>>>> +
>>>>> +     /*
>>>>> +      * The uhs2_control callback is used to execute SD UHS-II specific
>>>>> +      * operations. It's mandatory to implement for hosts that supports the
>>>>> +      * SD UHS-II interface (MMC_CAP2_SD_UHS2). Expected return values are a
>>>>> +      * negative errno in case of a failure or zero for success.
>>>>> +      */
>>>>> +     int     (*uhs2_control)(struct mmc_host *host, enum sd_uhs2_operation op);
>>>>>  };
>>>>>
>>>>>  struct mmc_cqe_ops {
>>>>> @@ -323,6 +379,7 @@ struct mmc_pwrseq;
>>>>>
>>>>>  struct mmc_supply {
>>>>>       struct regulator *vmmc;         /* Card power supply */
>>>>> +     struct regulator *vmmc2;        /* UHS2 VDD2 power supply */
>>>>>       struct regulator *vqmmc;        /* Optional Vccq supply */
>>>>>       struct regulator *vqmmc2;       /* Optional supply for phy */
>>>>>  };
>>>>> @@ -344,10 +401,12 @@ struct mmc_host {
>>>>>       u32                     ocr_avail_sdio; /* SDIO-specific OCR */
>>>>>       u32                     ocr_avail_sd;   /* SD-specific OCR */
>>>>>       u32                     ocr_avail_mmc;  /* MMC-specific OCR */
>>>>> +     u32                     ocr_avail_uhs2; /* UHS2-specific OCR */
>>>>>       struct wakeup_source    *ws;            /* Enable consume of uevents */
>>>>>       u32                     max_current_330;
>>>>>       u32                     max_current_300;
>>>>>       u32                     max_current_180;
>>>>> +     u32                     max_current_180_vdd2; /* UHS2 vdd2 max curt. */
>>>>>
>>>>>  #define MMC_VDD_165_195              0x00000080      /* VDD voltage 1.65 - 1.95 */
>>>>>  #define MMC_VDD_20_21                0x00000100      /* VDD voltage 2.0 ~ 2.1 */
>>>>> @@ -366,6 +425,7 @@ struct mmc_host {
>>>>>  #define MMC_VDD_33_34                0x00200000      /* VDD voltage 3.3 ~ 3.4 */
>>>>>  #define MMC_VDD_34_35                0x00400000      /* VDD voltage 3.4 ~ 3.5 */
>>>>>  #define MMC_VDD_35_36                0x00800000      /* VDD voltage 3.5 ~ 3.6 */
>>>>> +#define MMC_VDD2_165_195     0x00000080      /* UHS2 VDD2 1.65 ~ 1.95 */
>>>>>
>>>>>       u32                     caps;           /* Host capabilities */
>>>>>
>>>>> @@ -443,7 +503,12 @@ struct mmc_host {
>>>>>  #endif
>>>>>  #define MMC_CAP2_ALT_GPT_TEGRA       (1 << 28)       /* Host with eMMC that has GPT entry at a non-standard location */
>>>>>
>>>>> +     int flags;
>>>>> +#define MMC_UHS2_SUPPORT     (1 << 0)
>>>>
>>>> MMC_UHS2_SUPPORT is getting mixed up with MMC_UHS2_INITIALIZED.
>>>> Both have the same value, but MMC_UHS2_SUPPORT is for
>>>> host->flags and MMC_UHS2_INITIALIZED is for card->uhs2_state
>>>>
>>>> Please use the correct flag with the correct variable.
>>>>
>>>
>>> The value of MMC_UHS2_SUPPORT is (1<<0) and the value of
>>> MMC_UHS2_INITIALIZED is BIT(1).
>>> Both have different values, therefore I'm not sure what you mean.
>>> May you give me some more advice? Thanks.
>>
>> I guess I got confused about the values, however it is not OK to
>> use MMC_UHS2_INITIALIZED for both mmc->flags and card->uhs2_state.
>> Please make a separate define with a different name for mmc->flags
>> version of MMC_UHS2_INITIALIZED.
> 
> MMC_UHS2_INITIALIZED here is used to judge that the UHS-II I/F has been
> initialized and can run in SD-TRAN. In this state,  some SD commands
> require a distinction. For example, ACMD (CMD55) should be set by the APP
> field in UHS-II packet.

OK, but SD commands cannot be sent in UHS-II mode without SD-TRAN
so is the distinction needed?

> 
>>
>> Also, I am confused about the purpose of mmc->flags and
>> card->uhs2_state.
> 
> It looks like the mmc->flags and card->uhs2_state have the same purpose.
> I think it is having trouble with card == NULL in mmc_app_cmd(*host, *card)
> in patch [V5, 06/26] so just add one more mmc->flags.
> Can wait for confirmation from Victor.
> 
>>
>> A host is UHS-II capable as represented by MMC_CAP2_SD_UHS2.
>> To initialize and use a UHS-II card in UHS-II mode, the host
>> must be in UHS-II mode.
>> To initialize and use a UHS-II card in SD mode, the host
>> must be in SD mode.
>> So the state of the card and host is always the same:
>> either UHS-II or not.  Note, that is a consequence of the
>> hardware I/F.  Whether SD I/F or UHS-II I/F is used is
>> decided before sending any UHS-II commands. SD I/F is
>> disabled during UHS-II PHY initialization, whereas
>> UHS-II I/F is disabled before execution of ACMD41 is
>> completed.
>>
>> So it seems like there would only be a need for one flag
>> to indicate UHS-II mode?
>>
>>>
>>>>> +#define MMC_UHS2_2L_HD               (1 << 2)
>>>>
>>>> MMC_UHS2_2L_HD does not seem to be used. Is it needed?
>>>
>>> I confirmed this, I don't use it, I will delete it.
>>>
>>>>
>>>>> +
>>>>>       struct sd_uhs2_caps     uhs2_caps;      /* Host UHS-II capabilities */
>>>>> +     struct sd_uhs2_ios      uhs2_ios;       /* Host UHS-II capabilities */
>>>>>
>>>>>       int                     fixed_drv_type; /* fixed driver type for non-removable media */
>>>>>
>>>>> @@ -695,4 +760,7 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
>>>>>  int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
>>>>>  int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
>>>>>
>>>>> +#define mmc_uhs2_2L_HD_mode(h)       ((h)->uhs2_ios.is_2L_HD_mode)
>>>>> +#define mmc_uhs2_APP_cmd(h)  ((h)->uhs2_ios.is_APP_CMD)
>>>>> +
>>>>>  #endif /* LINUX_MMC_HOST_H */
>>>>> diff --git a/include/linux/mmc/sd_uhs2.h b/include/linux/mmc/sd_uhs2.h
>>>>> new file mode 100644
>>>>> index 000000000000..8fcf702cf4a5
>>>>> --- /dev/null
>>>>> +++ b/include/linux/mmc/sd_uhs2.h
>>>>> @@ -0,0 +1,263 @@
>>>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>>>> +/*
>>>>> + * Header file for UHS-II packets, Host Controller registers and I/O
>>>>> + * accessors.
>>>>> + *
>>>>> + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
>>>>> + */
>>>>> +#ifndef LINUX_MMC_UHS2_H
>>>>> +#define LINUX_MMC_UHS2_H
>>>>> +
>>>>> +/* LINK Layer definition */
>>>>> +/*
>>>>> + * UHS2 Header:
>>>>> + * Refer to UHS-II Addendum Version 1.02 Figure 5-2, the format of CCMD Header is described below:
>>>>> + *      bit [3:0]  : DID(Destination ID = Node ID of UHS2 card)
>>>>> + *      bit [6:4]  : TYP(Packet Type)
>>>>> + *                   000b: CCMD(Control command packet)
>>>>> + *                   001b: DCMD(Data command packet)
>>>>> + *                   010b: RES(Response packet)
>>>>> + *                   011b: DATA(Data payload packet)
>>>>> + *                   111b: MSG(Message packet)
>>>>> + *                   Others: Reserved
>>>>> + *      bit [7]    : NP(Native Packet)
>>>>> + *      bit [10:8] : TID(Transaction ID)
>>>>> + *      bit [11]   : Reserved
>>>>> + *      bit [15:12]: SID(Source ID 0: Node ID of Host)
>>>>> + *
>>>>> + * Broadcast CCMD issued by Host is represented as DID=SID=0.
>>>>> + */
>>>>> +/*
>>>>> + * UHS2 Argument:
>>>>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-5, the format of CCMD Argument is described below:
>>>>> + *      bit [3:0]  : MSB of IOADR
>>>>> + *      bit [5:4]  : PLEN(Payload Length)
>>>>> + *                   00b: 0 byte
>>>>> + *                   01b: 4 bytes
>>>>> + *                   10b: 8 bytes
>>>>> + *                   11b: 16 bytes
>>>>> + *      bit [6]    : Reserved
>>>>> + *      bit [7]    : R/W(Read/Write)
>>>>> + *                   0: Control read command
>>>>> + *                   1: Control write command
>>>>> + *      bit [15:8] : LSB of IOADR
>>>>> + *
>>>>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
>>>>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
>>>>> + */
>>>>> +#define UHS2_NATIVE_PACKET_POS       7
>>>>> +#define UHS2_NATIVE_PACKET   (1 << UHS2_NATIVE_PACKET_POS)
>>>>> +
>>>>> +#define UHS2_PACKET_TYPE_POS 4
>>>>> +#define UHS2_PACKET_TYPE_CCMD        (0 << UHS2_PACKET_TYPE_POS)
>>>>> +#define UHS2_PACKET_TYPE_DCMD        (1 << UHS2_PACKET_TYPE_POS)
>>>>> +#define UHS2_PACKET_TYPE_RES (2 << UHS2_PACKET_TYPE_POS)
>>>>> +#define UHS2_PACKET_TYPE_DATA        (3 << UHS2_PACKET_TYPE_POS)
>>>>> +#define UHS2_PACKET_TYPE_MSG (7 << UHS2_PACKET_TYPE_POS)
>>>>> +
>>>>> +#define UHS2_DEST_ID_MASK    0x0F
>>>>> +#define UHS2_DEST_ID         0x1
>>>>> +
>>>>> +#define UHS2_SRC_ID_POS              12
>>>>> +#define UHS2_SRC_ID_MASK     0xF000
>>>>> +
>>>>> +#define UHS2_TRANS_ID_POS    8
>>>>> +#define UHS2_TRANS_ID_MASK   0x0700
>>>>> +
>>>>> +/* UHS2 MSG */
>>>>> +#define UHS2_MSG_CTG_POS     5
>>>>> +#define UHS2_MSG_CTG_LMSG    0x00
>>>>> +#define UHS2_MSG_CTG_INT     0x60
>>>>> +#define UHS2_MSG_CTG_AMSG    0x80
>>>>> +
>>>>> +#define UHS2_MSG_CTG_FCREQ   0x00
>>>>> +#define UHS2_MSG_CTG_FCRDY   0x01
>>>>> +#define UHS2_MSG_CTG_STAT    0x02
>>>>> +
>>>>> +#define UHS2_MSG_CODE_POS                    8
>>>>> +#define UHS2_MSG_CODE_FC_UNRECOVER_ERR               0x8
>>>>> +#define UHS2_MSG_CODE_STAT_UNRECOVER_ERR     0x8
>>>>> +#define UHS2_MSG_CODE_STAT_RECOVER_ERR               0x1
>>>>> +
>>>>> +/* TRANS Layer definition */
>>>>> +
>>>>> +/* Native packets*/
>>>>> +#define UHS2_NATIVE_CMD_RW_POS       7
>>>>> +#define UHS2_NATIVE_CMD_WRITE        (1 << UHS2_NATIVE_CMD_RW_POS)
>>>>> +#define UHS2_NATIVE_CMD_READ (0 << UHS2_NATIVE_CMD_RW_POS)
>>>>> +
>>>>> +#define UHS2_NATIVE_CMD_PLEN_POS     4
>>>>> +#define UHS2_NATIVE_CMD_PLEN_4B              (1 << UHS2_NATIVE_CMD_PLEN_POS)
>>>>> +#define UHS2_NATIVE_CMD_PLEN_8B              (2 << UHS2_NATIVE_CMD_PLEN_POS)
>>>>> +#define UHS2_NATIVE_CMD_PLEN_16B     (3 << UHS2_NATIVE_CMD_PLEN_POS)
>>>>> +
>>>>> +#define UHS2_NATIVE_CCMD_GET_MIOADR_MASK     0xF00
>>>>> +#define UHS2_NATIVE_CCMD_MIOADR_MASK         0x0F
>>>>> +
>>>>> +#define UHS2_NATIVE_CCMD_LIOADR_POS          8
>>>>> +#define UHS2_NATIVE_CCMD_GET_LIOADR_MASK     0x0FF
>>>>> +
>>>>> +#define UHS2_CCMD_DEV_INIT_COMPLETE_FLAG     BIT(11)
>>>>> +#define UHS2_DEV_INIT_PAYLOAD_LEN            1
>>>>> +#define UHS2_DEV_INIT_RESP_LEN                       6
>>>>> +#define UHS2_DEV_ENUM_PAYLOAD_LEN            1
>>>>> +#define UHS2_DEV_ENUM_RESP_LEN                       8
>>>>> +#define UHS2_CFG_WRITE_PAYLOAD_LEN           2
>>>>> +#define UHS2_CFG_WRITE_PHY_SET_RESP_LEN              4
>>>>> +#define UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN  5
>>>>> +#define UHS2_GO_DORMANT_PAYLOAD_LEN          1
>>>>> +
>>>>> +/*
>>>>> + * UHS2 Argument:
>>>>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-8, the format of DCMD Argument is described below:
>>>>> + *      bit [3:0]  : Reserved
>>>>> + *      bit [6:3]  : TMODE(Transfer Mode)
>>>>> + *                   bit 3: DAM(Data Access Mode)
>>>>> + *                   bit 4: TLUM(TLEN Unit Mode)
>>>>> + *                   bit 5: LM(Length Mode)
>>>>> + *                   bit 6: DM(Duplex Mode)
>>>>> + *      bit [7]    : R/W(Read/Write)
>>>>> + *                   0: Control read command
>>>>> + *                   1: Control write command
>>>>> + *      bit [15:8] : Reserved
>>>>> + *
>>>>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
>>>>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
>>>>> + */
>>>>> +#define UHS2_DCMD_DM_POS             6
>>>>> +#define UHS2_DCMD_2L_HD_MODE         (1 << UHS2_DCMD_DM_POS)
>>>>> +#define UHS2_DCMD_LM_POS             5
>>>>> +#define UHS2_DCMD_LM_TLEN_EXIST              (1 << UHS2_DCMD_LM_POS)
>>>>> +#define UHS2_DCMD_TLUM_POS           4
>>>>> +#define UHS2_DCMD_TLUM_BYTE_MODE     (1 << UHS2_DCMD_TLUM_POS)
>>>>> +#define UHS2_NATIVE_DCMD_DAM_POS     3
>>>>> +#define UHS2_NATIVE_DCMD_DAM_IO              (1 << UHS2_NATIVE_DCMD_DAM_POS)
>>>>> +
>>>>> +/*
>>>>> + * Per UHS2 spec, DCMD payload should be MSB first. There may be
>>>>> + * two types of data be assembled to MSB:
>>>>> + * 1. TLEN: Input block size for single read/write and number of blocks
>>>>> + * for multiple read/write to calculate TLEN as MSB first per spec.
>>>>> + * 2. SD command argument.
>>>>> + */
>>>>> +static inline __be32 uhs2_dcmd_convert_msb(u32 input)
>>>>> +{
>>>>> +     u32 ret = 0;
>>>>> +
>>>>> +     ret = ((input & 0xFF) << 24) |
>>>>> +             (((input >> 8) & 0xFF) << 16) |
>>>>> +             (((input >> 16) & 0xFF) << 8) |
>>>>> +             ((input >> 24) & 0xFF);
>>>>> +     return cpu_to_be32(ret);
>>>>> +}
>>>>> +
>>>>> +#define UHS2_RES_NACK_POS    7
>>>>> +#define UHS2_RES_NACK_MASK   (0x1 << UHS2_RES_NACK_POS)
>>>>> +
>>>>> +#define UHS2_RES_ECODE_POS   4
>>>>> +#define UHS2_RES_ECODE_MASK  0x7
>>>>> +#define UHS2_RES_ECODE_COND  1
>>>>> +#define UHS2_RES_ECODE_ARG   2
>>>>> +#define UHS2_RES_ECODE_GEN   3
>>>>> +
>>>>> +/* IOADR of device registers */
>>>>> +#define UHS2_IOADR_GENERIC_CAPS              0x00
>>>>> +#define UHS2_IOADR_PHY_CAPS          0x02
>>>>> +#define UHS2_IOADR_LINK_CAPS         0x04
>>>>> +#define UHS2_IOADR_RSV_CAPS          0x06
>>>>> +#define UHS2_IOADR_GENERIC_SETTINGS  0x08
>>>>> +#define UHS2_IOADR_PHY_SETTINGS              0x0A
>>>>> +#define UHS2_IOADR_LINK_SETTINGS     0x0C
>>>>> +#define UHS2_IOADR_PRESET            0x40
>>>>> +
>>>>> +/* SD application packets */
>>>>> +#define UHS2_SD_CMD_INDEX_POS        8
>>>>> +
>>>>> +#define UHS2_SD_CMD_APP_POS  14
>>>>> +#define UHS2_SD_CMD_APP              (1 << UHS2_SD_CMD_APP_POS)
>>>>> +
>>>>> +/* UHS-II Device Registers */
>>>>> +#define UHS2_DEV_CONFIG_REG  0x000
>>>>> +
>>>>> +/* General Caps and Settings registers */
>>>>> +#define UHS2_DEV_CONFIG_GEN_CAPS     (UHS2_DEV_CONFIG_REG + 0x000)
>>>>> +#define UHS2_DEV_CONFIG_N_LANES_POS  8
>>>>> +#define UHS2_DEV_CONFIG_N_LANES_MASK 0x3F
>>>>> +#define UHS2_DEV_CONFIG_2L_HD_FD     0x1
>>>>> +#define UHS2_DEV_CONFIG_2D1U_FD              0x2
>>>>> +#define UHS2_DEV_CONFIG_1D2U_FD              0x4
>>>>> +#define UHS2_DEV_CONFIG_2D2U_FD              0x8
>>>>> +#define UHS2_DEV_CONFIG_DADR_POS     14
>>>>> +#define UHS2_DEV_CONFIG_DADR_MASK    0x1
>>>>> +#define UHS2_DEV_CONFIG_APP_POS              16
>>>>> +#define UHS2_DEV_CONFIG_APP_MASK     0xFF
>>>>> +#define UHS2_DEV_CONFIG_APP_SD_MEM   0x1
>>>>> +
>>>>> +#define UHS2_DEV_CONFIG_GEN_SET                      (UHS2_DEV_CONFIG_REG + 0x008)
>>>>> +#define UHS2_DEV_CONFIG_GEN_SET_N_LANES_POS  8
>>>>> +#define UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD     0x0
>>>>> +#define UHS2_DEV_CONFIG_GEN_SET_2D1U_FD              0x2
>>>>> +#define UHS2_DEV_CONFIG_GEN_SET_1D2U_FD              0x3
>>>>> +#define UHS2_DEV_CONFIG_GEN_SET_2D2U_FD              0x4
>>>>> +#define UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE BIT(31)
>>>>> +
>>>>> +/* PHY Caps and Settings registers */
>>>>> +#define UHS2_DEV_CONFIG_PHY_CAPS     (UHS2_DEV_CONFIG_REG + 0x002)
>>>>> +#define UHS2_DEV_CONFIG_PHY_MINOR_MASK       0xF
>>>>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_POS        4
>>>>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_MASK       0x3
>>>>> +#define UHS2_DEV_CONFIG_CAN_HIBER_POS        15
>>>>> +#define UHS2_DEV_CONFIG_CAN_HIBER_MASK       0x1
>>>>> +#define UHS2_DEV_CONFIG_PHY_CAPS1    (UHS2_DEV_CONFIG_REG + 0x003)
>>>>> +#define UHS2_DEV_CONFIG_N_LSS_SYN_MASK       0xF
>>>>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_POS        4
>>>>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_MASK       0xF
>>>>> +
>>>>> +#define UHS2_DEV_CONFIG_PHY_SET                      (UHS2_DEV_CONFIG_REG + 0x00A)
>>>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_POS    6
>>>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_A              0x0
>>>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_B              0x1
>>>>> +
>>>>> +/* LINK-TRAN Caps and Settings registers */
>>>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS               (UHS2_DEV_CONFIG_REG + 0x004)
>>>>> +#define UHS2_DEV_CONFIG_LT_MINOR_MASK                0xF
>>>>> +#define UHS2_DEV_CONFIG_LT_MAJOR_POS         4
>>>>> +#define UHS2_DEV_CONFIG_LT_MAJOR_MASK                0x3
>>>>> +#define UHS2_DEV_CONFIG_N_FCU_POS            8
>>>>> +#define UHS2_DEV_CONFIG_N_FCU_MASK           0xFF
>>>>> +#define UHS2_DEV_CONFIG_DEV_TYPE_POS         16
>>>>> +#define UHS2_DEV_CONFIG_DEV_TYPE_MASK                0x7
>>>>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_POS              20
>>>>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK     0xFFF
>>>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS1              (UHS2_DEV_CONFIG_REG + 0x005)
>>>>> +#define UHS2_DEV_CONFIG_N_DATA_GAP_MASK              0xFF
>>>>> +
>>>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_SET                (UHS2_DEV_CONFIG_REG + 0x00C)
>>>>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN   0x200
>>>>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS 16
>>>>> +
>>>>> +/* Preset register */
>>>>> +#define UHS2_DEV_CONFIG_PRESET       (UHS2_DEV_CONFIG_REG + 0x040)
>>>>> +
>>>>> +#define UHS2_DEV_INT_REG     0x100
>>>>> +
>>>>> +#define UHS2_DEV_STATUS_REG  0x180
>>>>> +
>>>>> +#define UHS2_DEV_CMD_REG             0x200
>>>>> +#define UHS2_DEV_CMD_FULL_RESET              (UHS2_DEV_CMD_REG + 0x000)
>>>>> +#define UHS2_DEV_CMD_GO_DORMANT_STATE        (UHS2_DEV_CMD_REG + 0x001)
>>>>> +#define UHS2_DEV_CMD_DORMANT_HIBER   BIT(7)
>>>>> +#define UHS2_DEV_CMD_DEVICE_INIT     (UHS2_DEV_CMD_REG + 0x002)
>>>>> +#define UHS2_DEV_INIT_COMPLETE_FLAG  BIT(11)
>>>>> +#define UHS2_DEV_CMD_ENUMERATE               (UHS2_DEV_CMD_REG + 0x003)
>>>>> +#define UHS2_DEV_CMD_TRANS_ABORT     (UHS2_DEV_CMD_REG + 0x004)
>>>>> +
>>>>> +#define UHS2_RCLK_MAX        52000000
>>>>> +#define UHS2_RCLK_MIN        26000000
>>>>> +
>>>>> +struct sd_uhs2_wait_active_state_data {
>>>>> +     struct mmc_host *host;
>>>>> +     struct mmc_command *cmd;
>>>>> +};
>>>>> +
>>>>> +#endif /* LINUX_MMC_UHS2_H */
>>>>
>>>
>>> Thanks, Victor Shih
>>
> 
> Best regards,
> Ben Chuang


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards
  2022-11-17 16:03           ` Adrian Hunter
@ 2022-11-18  1:19             ` Ben Chuang
  2022-12-13  8:44               ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Ben Chuang @ 2022-11-18  1:19 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Victor Shih, ulf.hansson, linux-mmc, linux-kernel, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Jason Lai

On Fri, Nov 18, 2022 at 12:05 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 17/11/22 08:19, Ben Chuang wrote:
> > Hi,
> >
> > On Wed, Nov 16, 2022 at 9:48 PM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>
> >> On 16/11/22 13:06, Victor Shih wrote:
> >>> Hi, Adrian
> >>>
> >>> On Wed, Nov 2, 2022 at 1:12 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>>>
> >>>> On 19/10/22 14:06, Victor Shih wrote:
> >>>>> Add UHS-II specific data structures for commands and defines for
> >>>>> registers, as described in Part 1 UHS-II Addendum Version 1.01.
> >>>>>
> >>>>> UHS-II related definitions are listed below:
> >>>>>   1. UHS-II card capability: sd_uhs2_caps{}
> >>>>>   2. UHS-II configuration: sd_uhs2_config{}
> >>>>>   3. UHS-II Command structure: uhs2_command{}
> >>>>>   4. UHS-II register I/O address and register field definitions: sd_uhs2.h
> >>>>>
> >>>>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> >>>>> Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
> >>>>> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> >>>>> ---
> >>>>>
> >>>>> Updates in V5:
> >>>>>  - Added UHS2 interfaces in mmc_host_ops: host.h
> >>>>>  - Added UHS2 VDD2 power supply in mmc_supply: host.h
> >>>>>  - Added UHS2-specific OCR and UHS2 VDD2 max current in mmc_host: host.h
> >>>>>  - Added definition of UHS2 VDD2 1.65v-1.95v in mmc_host: host.h
> >>>>>  - Added flags/MMC_UHS2_SUPPORT/MMC_UHS2_2L_HD in mmc_host: host.h
> >>>>> ---
> >>>>>  include/linux/mmc/card.h    |  42 +++++-
> >>>>>  include/linux/mmc/core.h    |  13 ++
> >>>>>  include/linux/mmc/host.h    |  70 +++++++++-
> >>>>>  include/linux/mmc/sd_uhs2.h | 263 ++++++++++++++++++++++++++++++++++++
> >>>>>  4 files changed, 386 insertions(+), 2 deletions(-)
> >>>>>  create mode 100644 include/linux/mmc/sd_uhs2.h
> >>>>>
> >>>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> >>>>> index 4a42f31b7bb0..d638a2c689cf 100644
> >>>>> --- a/include/linux/mmc/card.h
> >>>>> +++ b/include/linux/mmc/card.h
> >>>>> @@ -190,6 +190,13 @@ struct sd_switch_caps {
> >>>>>  #define SD_MAX_CURRENT_400   (1 << SD_SET_CURRENT_LIMIT_400)
> >>>>>  #define SD_MAX_CURRENT_600   (1 << SD_SET_CURRENT_LIMIT_600)
> >>>>>  #define SD_MAX_CURRENT_800   (1 << SD_SET_CURRENT_LIMIT_800)
> >>>>> +     unsigned int            sd4_curr_limit;
> >>>>> +#define SD4_SET_POWER_LIMIT_0_72W    0
> >>>>> +#define SD4_SET_POWER_LIMIT_1_44W    1
> >>>>> +#define SD4_SET_POWER_LIMIT_2_16W    2
> >>>>> +#define SD4_SET_POWER_LIMIT_2_88W    3
> >>>>> +#define SD4_SET_POWER_LIMIT_1_80W    4
> >>>>> +#define SD4_SET_POWER_NO_CHANGE              (-1)
> >>>>>  };
> >>>>>
> >>>>>  struct sd_ext_reg {
> >>>>> @@ -213,7 +220,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 {
> >>>>> @@ -323,6 +358,9 @@ struct mmc_card {
> >>>>>       struct sd_ext_reg       ext_perf;       /* SD extension reg for PERF */
> >>>>>
> >>>>>       struct sd_uhs2_config   uhs2_config;    /* SD UHS-II config */
> >>>>> +     u8                      uhs2_state;     /* SD UHS-II states */
> >>>>> +#define MMC_UHS2_INITIALIZED BIT(1)
> >>>>> +#define MMC_UHS2_SPEED_B     BIT(2)
> >>>>>
> >>>>>       unsigned int            sdio_funcs;     /* number of SDIO functions */
> >>>>>       atomic_t                sdio_funcs_probed; /* number of probed SDIO funcs */
> >>>>> @@ -364,4 +402,6 @@ bool mmc_card_is_blockaddr(struct mmc_card *card);
> >>>>>  #define mmc_card_sdio(c)     ((c)->type == MMC_TYPE_SDIO)
> >>>>>  #define mmc_card_sd_combo(c) ((c)->type == MMC_TYPE_SD_COMBO)
> >>>>>
> >>>>> +#define mmc_card_can_poweroff_notify(c)      ((c)->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY)
> >>>>> +
> >>>>>  #endif /* LINUX_MMC_CARD_H */
> >>>>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> >>>>> index 6efec0b9820c..2a0581d87706 100644
> >>>>> --- a/include/linux/mmc/core.h
> >>>>> +++ b/include/linux/mmc/core.h
> >>>>> @@ -23,6 +23,14 @@ enum mmc_blk_status {
> >>>>>       MMC_BLK_NEW_REQUEST,
> >>>>>  };
> >>>>>
> >>>>> +struct uhs2_command {
> >>>>> +     u16     header;
> >>>>> +     u16     arg;
> >>>>> +     __be32  *payload;
> >>>>> +     u32     payload_len;
> >>>>> +     u32     packet_len;
> >>>>> +};
> >>>>> +
> >>>>>  struct mmc_command {
> >>>>>       u32                     opcode;
> >>>>>       u32                     arg;
> >>>>> @@ -109,6 +117,11 @@ struct mmc_command {
> >>>>>       unsigned int            busy_timeout;   /* busy detect timeout in ms */
> >>>>>       struct mmc_data         *data;          /* data segment associated with cmd */
> >>>>>       struct mmc_request      *mrq;           /* associated request */
> >>>>> +
> >>>>> +     struct uhs2_command     *uhs2_cmd;      /* UHS2 command */
> >>>>> +     u8                      *uhs2_resp;     /* UHS2 native cmd resp */
> >>>>> +     u8                      uhs2_resp_len;  /* UHS2 native cmd resp len */
> >>>>> +     u8                      uhs2_tmode0_flag; /* UHS2 transfer mode flag */
> >>>>>  };
> >>>>>
> >>>>>  struct mmc_data {
> >>>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> >>>>> index 895bcf7f80b7..249a9414ad10 100644
> >>>>> --- a/include/linux/mmc/host.h
> >>>>> +++ b/include/linux/mmc/host.h
> >>>>> @@ -16,6 +16,7 @@
> >>>>>  #include <linux/mmc/pm.h>
> >>>>>  #include <linux/dma-direction.h>
> >>>>>  #include <linux/blk-crypto-profile.h>
> >>>>> +#include <linux/mmc/sd_uhs2.h>
> >>>>>
> >>>>>  struct mmc_ios {
> >>>>>       unsigned int    clock;                  /* clock rate */
> >>>>> @@ -96,7 +97,48 @@ struct mmc_clk_phase_map {
> >>>>>  };
> >>>>>
> >>>>>  struct sd_uhs2_caps {
> >>>>> -     /* TODO: Add UHS-II capabilities for the host. */
> >>>>> +     u32     dap;
> >>>>> +     u32     gap;
> >>>>> +     u32     group_desc;
> >>>>> +     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 sd_uhs2_ios {
> >>>>> +     bool            is_2L_HD_mode;
> >>>>> +     bool            is_APP_CMD;
> >>>>> +     unsigned int    power_delay_ms;         /* waiting for stable power */
> >>>>> +};
> >>>>> +
> >>>>> +enum sd_uhs2_operation {
> >>>>> +     UHS2_PHY_INIT = 0,
> >>>>> +     UHS2_SET_CONFIG,
> >>>>> +     UHS2_ENABLE_INT,
> >>>>> +     UHS2_DISABLE_INT,
> >>>>> +     UHS2_ENABLE_CLK,
> >>>>> +     UHS2_DISABLE_CLK,
> >>>>> +     UHS2_CHECK_DORMANT,
> >>>>> +     UHS2_SET_SPEED_B,
> >>>>> +     UHS2_POST_ATTACH_SD,
> >>>>>  };
> >>>>>
> >>>>>  struct mmc_host;
> >>>>> @@ -231,6 +273,20 @@ 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 */
> >>>>> +     int     (*uhs2_detect_init)(struct mmc_host *host);
> >>>>
> >>>> Never called?
> >>>
> >>> Yes, I will delete it.
> >>>
> >>>>
> >>>>> +     int     (*uhs2_set_reg)(struct mmc_host *host, enum sd_uhs2_operation act);
> >>>>
> >>>> Never called?
> >>>
> >>> Yes, I will delete it.
> >>>
> >>>>
> >>>>> +     int (*uhs2_disable_clk)(struct mmc_host *host);
> >>>>
> >>>> Never called?
> >>>
> >>> Yes, I will delete it.
> >>>
> >>>>
> >>>>> +     int (*uhs2_enable_clk)(struct mmc_host *host);
> >>>>
> >>>> Never called?
> >>>
> >>> Yes, I will delete it.
> >>>
> >>>>
> >>>>> +
> >>>>> +     /*
> >>>>> +      * The uhs2_control callback is used to execute SD UHS-II specific
> >>>>> +      * operations. It's mandatory to implement for hosts that supports the
> >>>>> +      * SD UHS-II interface (MMC_CAP2_SD_UHS2). Expected return values are a
> >>>>> +      * negative errno in case of a failure or zero for success.
> >>>>> +      */
> >>>>> +     int     (*uhs2_control)(struct mmc_host *host, enum sd_uhs2_operation op);
> >>>>>  };
> >>>>>
> >>>>>  struct mmc_cqe_ops {
> >>>>> @@ -323,6 +379,7 @@ struct mmc_pwrseq;
> >>>>>
> >>>>>  struct mmc_supply {
> >>>>>       struct regulator *vmmc;         /* Card power supply */
> >>>>> +     struct regulator *vmmc2;        /* UHS2 VDD2 power supply */
> >>>>>       struct regulator *vqmmc;        /* Optional Vccq supply */
> >>>>>       struct regulator *vqmmc2;       /* Optional supply for phy */
> >>>>>  };
> >>>>> @@ -344,10 +401,12 @@ struct mmc_host {
> >>>>>       u32                     ocr_avail_sdio; /* SDIO-specific OCR */
> >>>>>       u32                     ocr_avail_sd;   /* SD-specific OCR */
> >>>>>       u32                     ocr_avail_mmc;  /* MMC-specific OCR */
> >>>>> +     u32                     ocr_avail_uhs2; /* UHS2-specific OCR */
> >>>>>       struct wakeup_source    *ws;            /* Enable consume of uevents */
> >>>>>       u32                     max_current_330;
> >>>>>       u32                     max_current_300;
> >>>>>       u32                     max_current_180;
> >>>>> +     u32                     max_current_180_vdd2; /* UHS2 vdd2 max curt. */
> >>>>>
> >>>>>  #define MMC_VDD_165_195              0x00000080      /* VDD voltage 1.65 - 1.95 */
> >>>>>  #define MMC_VDD_20_21                0x00000100      /* VDD voltage 2.0 ~ 2.1 */
> >>>>> @@ -366,6 +425,7 @@ struct mmc_host {
> >>>>>  #define MMC_VDD_33_34                0x00200000      /* VDD voltage 3.3 ~ 3.4 */
> >>>>>  #define MMC_VDD_34_35                0x00400000      /* VDD voltage 3.4 ~ 3.5 */
> >>>>>  #define MMC_VDD_35_36                0x00800000      /* VDD voltage 3.5 ~ 3.6 */
> >>>>> +#define MMC_VDD2_165_195     0x00000080      /* UHS2 VDD2 1.65 ~ 1.95 */
> >>>>>
> >>>>>       u32                     caps;           /* Host capabilities */
> >>>>>
> >>>>> @@ -443,7 +503,12 @@ struct mmc_host {
> >>>>>  #endif
> >>>>>  #define MMC_CAP2_ALT_GPT_TEGRA       (1 << 28)       /* Host with eMMC that has GPT entry at a non-standard location */
> >>>>>
> >>>>> +     int flags;
> >>>>> +#define MMC_UHS2_SUPPORT     (1 << 0)
> >>>>
> >>>> MMC_UHS2_SUPPORT is getting mixed up with MMC_UHS2_INITIALIZED.
> >>>> Both have the same value, but MMC_UHS2_SUPPORT is for
> >>>> host->flags and MMC_UHS2_INITIALIZED is for card->uhs2_state
> >>>>
> >>>> Please use the correct flag with the correct variable.
> >>>>
> >>>
> >>> The value of MMC_UHS2_SUPPORT is (1<<0) and the value of
> >>> MMC_UHS2_INITIALIZED is BIT(1).
> >>> Both have different values, therefore I'm not sure what you mean.
> >>> May you give me some more advice? Thanks.
> >>
> >> I guess I got confused about the values, however it is not OK to
> >> use MMC_UHS2_INITIALIZED for both mmc->flags and card->uhs2_state.
> >> Please make a separate define with a different name for mmc->flags
> >> version of MMC_UHS2_INITIALIZED.
> >
> > MMC_UHS2_INITIALIZED here is used to judge that the UHS-II I/F has been
> > initialized and can run in SD-TRAN. In this state,  some SD commands
> > require a distinction. For example, ACMD (CMD55) should be set by the APP
> > field in UHS-II packet.
>
> OK, but SD commands cannot be sent in UHS-II mode without SD-TRAN
> so is the distinction needed?

No need, if these SD commands are sent in SD_TRAN mode.

>
> >
> >>
> >> Also, I am confused about the purpose of mmc->flags and
> >> card->uhs2_state.
> >
> > It looks like the mmc->flags and card->uhs2_state have the same purpose.
> > I think it is having trouble with card == NULL in mmc_app_cmd(*host, *card)
> > in patch [V5, 06/26] so just add one more mmc->flags.
> > Can wait for confirmation from Victor.
> >
> >>
> >> A host is UHS-II capable as represented by MMC_CAP2_SD_UHS2.
> >> To initialize and use a UHS-II card in UHS-II mode, the host
> >> must be in UHS-II mode.
> >> To initialize and use a UHS-II card in SD mode, the host
> >> must be in SD mode.
> >> So the state of the card and host is always the same:
> >> either UHS-II or not.  Note, that is a consequence of the
> >> hardware I/F.  Whether SD I/F or UHS-II I/F is used is
> >> decided before sending any UHS-II commands. SD I/F is
> >> disabled during UHS-II PHY initialization, whereas
> >> UHS-II I/F is disabled before execution of ACMD41 is
> >> completed.
> >>
> >> So it seems like there would only be a need for one flag
> >> to indicate UHS-II mode?
> >>
> >>>
> >>>>> +#define MMC_UHS2_2L_HD               (1 << 2)
> >>>>
> >>>> MMC_UHS2_2L_HD does not seem to be used. Is it needed?
> >>>
> >>> I confirmed this, I don't use it, I will delete it.
> >>>
> >>>>
> >>>>> +
> >>>>>       struct sd_uhs2_caps     uhs2_caps;      /* Host UHS-II capabilities */
> >>>>> +     struct sd_uhs2_ios      uhs2_ios;       /* Host UHS-II capabilities */
> >>>>>
> >>>>>       int                     fixed_drv_type; /* fixed driver type for non-removable media */
> >>>>>
> >>>>> @@ -695,4 +760,7 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
> >>>>>  int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
> >>>>>  int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
> >>>>>
> >>>>> +#define mmc_uhs2_2L_HD_mode(h)       ((h)->uhs2_ios.is_2L_HD_mode)
> >>>>> +#define mmc_uhs2_APP_cmd(h)  ((h)->uhs2_ios.is_APP_CMD)
> >>>>> +
> >>>>>  #endif /* LINUX_MMC_HOST_H */
> >>>>> diff --git a/include/linux/mmc/sd_uhs2.h b/include/linux/mmc/sd_uhs2.h
> >>>>> new file mode 100644
> >>>>> index 000000000000..8fcf702cf4a5
> >>>>> --- /dev/null
> >>>>> +++ b/include/linux/mmc/sd_uhs2.h
> >>>>> @@ -0,0 +1,263 @@
> >>>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> >>>>> +/*
> >>>>> + * Header file for UHS-II packets, Host Controller registers and I/O
> >>>>> + * accessors.
> >>>>> + *
> >>>>> + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> >>>>> + */
> >>>>> +#ifndef LINUX_MMC_UHS2_H
> >>>>> +#define LINUX_MMC_UHS2_H
> >>>>> +
> >>>>> +/* LINK Layer definition */
> >>>>> +/*
> >>>>> + * UHS2 Header:
> >>>>> + * Refer to UHS-II Addendum Version 1.02 Figure 5-2, the format of CCMD Header is described below:
> >>>>> + *      bit [3:0]  : DID(Destination ID = Node ID of UHS2 card)
> >>>>> + *      bit [6:4]  : TYP(Packet Type)
> >>>>> + *                   000b: CCMD(Control command packet)
> >>>>> + *                   001b: DCMD(Data command packet)
> >>>>> + *                   010b: RES(Response packet)
> >>>>> + *                   011b: DATA(Data payload packet)
> >>>>> + *                   111b: MSG(Message packet)
> >>>>> + *                   Others: Reserved
> >>>>> + *      bit [7]    : NP(Native Packet)
> >>>>> + *      bit [10:8] : TID(Transaction ID)
> >>>>> + *      bit [11]   : Reserved
> >>>>> + *      bit [15:12]: SID(Source ID 0: Node ID of Host)
> >>>>> + *
> >>>>> + * Broadcast CCMD issued by Host is represented as DID=SID=0.
> >>>>> + */
> >>>>> +/*
> >>>>> + * UHS2 Argument:
> >>>>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-5, the format of CCMD Argument is described below:
> >>>>> + *      bit [3:0]  : MSB of IOADR
> >>>>> + *      bit [5:4]  : PLEN(Payload Length)
> >>>>> + *                   00b: 0 byte
> >>>>> + *                   01b: 4 bytes
> >>>>> + *                   10b: 8 bytes
> >>>>> + *                   11b: 16 bytes
> >>>>> + *      bit [6]    : Reserved
> >>>>> + *      bit [7]    : R/W(Read/Write)
> >>>>> + *                   0: Control read command
> >>>>> + *                   1: Control write command
> >>>>> + *      bit [15:8] : LSB of IOADR
> >>>>> + *
> >>>>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> >>>>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> >>>>> + */
> >>>>> +#define UHS2_NATIVE_PACKET_POS       7
> >>>>> +#define UHS2_NATIVE_PACKET   (1 << UHS2_NATIVE_PACKET_POS)
> >>>>> +
> >>>>> +#define UHS2_PACKET_TYPE_POS 4
> >>>>> +#define UHS2_PACKET_TYPE_CCMD        (0 << UHS2_PACKET_TYPE_POS)
> >>>>> +#define UHS2_PACKET_TYPE_DCMD        (1 << UHS2_PACKET_TYPE_POS)
> >>>>> +#define UHS2_PACKET_TYPE_RES (2 << UHS2_PACKET_TYPE_POS)
> >>>>> +#define UHS2_PACKET_TYPE_DATA        (3 << UHS2_PACKET_TYPE_POS)
> >>>>> +#define UHS2_PACKET_TYPE_MSG (7 << UHS2_PACKET_TYPE_POS)
> >>>>> +
> >>>>> +#define UHS2_DEST_ID_MASK    0x0F
> >>>>> +#define UHS2_DEST_ID         0x1
> >>>>> +
> >>>>> +#define UHS2_SRC_ID_POS              12
> >>>>> +#define UHS2_SRC_ID_MASK     0xF000
> >>>>> +
> >>>>> +#define UHS2_TRANS_ID_POS    8
> >>>>> +#define UHS2_TRANS_ID_MASK   0x0700
> >>>>> +
> >>>>> +/* UHS2 MSG */
> >>>>> +#define UHS2_MSG_CTG_POS     5
> >>>>> +#define UHS2_MSG_CTG_LMSG    0x00
> >>>>> +#define UHS2_MSG_CTG_INT     0x60
> >>>>> +#define UHS2_MSG_CTG_AMSG    0x80
> >>>>> +
> >>>>> +#define UHS2_MSG_CTG_FCREQ   0x00
> >>>>> +#define UHS2_MSG_CTG_FCRDY   0x01
> >>>>> +#define UHS2_MSG_CTG_STAT    0x02
> >>>>> +
> >>>>> +#define UHS2_MSG_CODE_POS                    8
> >>>>> +#define UHS2_MSG_CODE_FC_UNRECOVER_ERR               0x8
> >>>>> +#define UHS2_MSG_CODE_STAT_UNRECOVER_ERR     0x8
> >>>>> +#define UHS2_MSG_CODE_STAT_RECOVER_ERR               0x1
> >>>>> +
> >>>>> +/* TRANS Layer definition */
> >>>>> +
> >>>>> +/* Native packets*/
> >>>>> +#define UHS2_NATIVE_CMD_RW_POS       7
> >>>>> +#define UHS2_NATIVE_CMD_WRITE        (1 << UHS2_NATIVE_CMD_RW_POS)
> >>>>> +#define UHS2_NATIVE_CMD_READ (0 << UHS2_NATIVE_CMD_RW_POS)
> >>>>> +
> >>>>> +#define UHS2_NATIVE_CMD_PLEN_POS     4
> >>>>> +#define UHS2_NATIVE_CMD_PLEN_4B              (1 << UHS2_NATIVE_CMD_PLEN_POS)
> >>>>> +#define UHS2_NATIVE_CMD_PLEN_8B              (2 << UHS2_NATIVE_CMD_PLEN_POS)
> >>>>> +#define UHS2_NATIVE_CMD_PLEN_16B     (3 << UHS2_NATIVE_CMD_PLEN_POS)
> >>>>> +
> >>>>> +#define UHS2_NATIVE_CCMD_GET_MIOADR_MASK     0xF00
> >>>>> +#define UHS2_NATIVE_CCMD_MIOADR_MASK         0x0F
> >>>>> +
> >>>>> +#define UHS2_NATIVE_CCMD_LIOADR_POS          8
> >>>>> +#define UHS2_NATIVE_CCMD_GET_LIOADR_MASK     0x0FF
> >>>>> +
> >>>>> +#define UHS2_CCMD_DEV_INIT_COMPLETE_FLAG     BIT(11)
> >>>>> +#define UHS2_DEV_INIT_PAYLOAD_LEN            1
> >>>>> +#define UHS2_DEV_INIT_RESP_LEN                       6
> >>>>> +#define UHS2_DEV_ENUM_PAYLOAD_LEN            1
> >>>>> +#define UHS2_DEV_ENUM_RESP_LEN                       8
> >>>>> +#define UHS2_CFG_WRITE_PAYLOAD_LEN           2
> >>>>> +#define UHS2_CFG_WRITE_PHY_SET_RESP_LEN              4
> >>>>> +#define UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN  5
> >>>>> +#define UHS2_GO_DORMANT_PAYLOAD_LEN          1
> >>>>> +
> >>>>> +/*
> >>>>> + * UHS2 Argument:
> >>>>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-8, the format of DCMD Argument is described below:
> >>>>> + *      bit [3:0]  : Reserved
> >>>>> + *      bit [6:3]  : TMODE(Transfer Mode)
> >>>>> + *                   bit 3: DAM(Data Access Mode)
> >>>>> + *                   bit 4: TLUM(TLEN Unit Mode)
> >>>>> + *                   bit 5: LM(Length Mode)
> >>>>> + *                   bit 6: DM(Duplex Mode)
> >>>>> + *      bit [7]    : R/W(Read/Write)
> >>>>> + *                   0: Control read command
> >>>>> + *                   1: Control write command
> >>>>> + *      bit [15:8] : Reserved
> >>>>> + *
> >>>>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> >>>>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> >>>>> + */
> >>>>> +#define UHS2_DCMD_DM_POS             6
> >>>>> +#define UHS2_DCMD_2L_HD_MODE         (1 << UHS2_DCMD_DM_POS)
> >>>>> +#define UHS2_DCMD_LM_POS             5
> >>>>> +#define UHS2_DCMD_LM_TLEN_EXIST              (1 << UHS2_DCMD_LM_POS)
> >>>>> +#define UHS2_DCMD_TLUM_POS           4
> >>>>> +#define UHS2_DCMD_TLUM_BYTE_MODE     (1 << UHS2_DCMD_TLUM_POS)
> >>>>> +#define UHS2_NATIVE_DCMD_DAM_POS     3
> >>>>> +#define UHS2_NATIVE_DCMD_DAM_IO              (1 << UHS2_NATIVE_DCMD_DAM_POS)
> >>>>> +
> >>>>> +/*
> >>>>> + * Per UHS2 spec, DCMD payload should be MSB first. There may be
> >>>>> + * two types of data be assembled to MSB:
> >>>>> + * 1. TLEN: Input block size for single read/write and number of blocks
> >>>>> + * for multiple read/write to calculate TLEN as MSB first per spec.
> >>>>> + * 2. SD command argument.
> >>>>> + */
> >>>>> +static inline __be32 uhs2_dcmd_convert_msb(u32 input)
> >>>>> +{
> >>>>> +     u32 ret = 0;
> >>>>> +
> >>>>> +     ret = ((input & 0xFF) << 24) |
> >>>>> +             (((input >> 8) & 0xFF) << 16) |
> >>>>> +             (((input >> 16) & 0xFF) << 8) |
> >>>>> +             ((input >> 24) & 0xFF);
> >>>>> +     return cpu_to_be32(ret);
> >>>>> +}
> >>>>> +
> >>>>> +#define UHS2_RES_NACK_POS    7
> >>>>> +#define UHS2_RES_NACK_MASK   (0x1 << UHS2_RES_NACK_POS)
> >>>>> +
> >>>>> +#define UHS2_RES_ECODE_POS   4
> >>>>> +#define UHS2_RES_ECODE_MASK  0x7
> >>>>> +#define UHS2_RES_ECODE_COND  1
> >>>>> +#define UHS2_RES_ECODE_ARG   2
> >>>>> +#define UHS2_RES_ECODE_GEN   3
> >>>>> +
> >>>>> +/* IOADR of device registers */
> >>>>> +#define UHS2_IOADR_GENERIC_CAPS              0x00
> >>>>> +#define UHS2_IOADR_PHY_CAPS          0x02
> >>>>> +#define UHS2_IOADR_LINK_CAPS         0x04
> >>>>> +#define UHS2_IOADR_RSV_CAPS          0x06
> >>>>> +#define UHS2_IOADR_GENERIC_SETTINGS  0x08
> >>>>> +#define UHS2_IOADR_PHY_SETTINGS              0x0A
> >>>>> +#define UHS2_IOADR_LINK_SETTINGS     0x0C
> >>>>> +#define UHS2_IOADR_PRESET            0x40
> >>>>> +
> >>>>> +/* SD application packets */
> >>>>> +#define UHS2_SD_CMD_INDEX_POS        8
> >>>>> +
> >>>>> +#define UHS2_SD_CMD_APP_POS  14
> >>>>> +#define UHS2_SD_CMD_APP              (1 << UHS2_SD_CMD_APP_POS)
> >>>>> +
> >>>>> +/* UHS-II Device Registers */
> >>>>> +#define UHS2_DEV_CONFIG_REG  0x000
> >>>>> +
> >>>>> +/* General Caps and Settings registers */
> >>>>> +#define UHS2_DEV_CONFIG_GEN_CAPS     (UHS2_DEV_CONFIG_REG + 0x000)
> >>>>> +#define UHS2_DEV_CONFIG_N_LANES_POS  8
> >>>>> +#define UHS2_DEV_CONFIG_N_LANES_MASK 0x3F
> >>>>> +#define UHS2_DEV_CONFIG_2L_HD_FD     0x1
> >>>>> +#define UHS2_DEV_CONFIG_2D1U_FD              0x2
> >>>>> +#define UHS2_DEV_CONFIG_1D2U_FD              0x4
> >>>>> +#define UHS2_DEV_CONFIG_2D2U_FD              0x8
> >>>>> +#define UHS2_DEV_CONFIG_DADR_POS     14
> >>>>> +#define UHS2_DEV_CONFIG_DADR_MASK    0x1
> >>>>> +#define UHS2_DEV_CONFIG_APP_POS              16
> >>>>> +#define UHS2_DEV_CONFIG_APP_MASK     0xFF
> >>>>> +#define UHS2_DEV_CONFIG_APP_SD_MEM   0x1
> >>>>> +
> >>>>> +#define UHS2_DEV_CONFIG_GEN_SET                      (UHS2_DEV_CONFIG_REG + 0x008)
> >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_N_LANES_POS  8
> >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD     0x0
> >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_2D1U_FD              0x2
> >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_1D2U_FD              0x3
> >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_2D2U_FD              0x4
> >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE BIT(31)
> >>>>> +
> >>>>> +/* PHY Caps and Settings registers */
> >>>>> +#define UHS2_DEV_CONFIG_PHY_CAPS     (UHS2_DEV_CONFIG_REG + 0x002)
> >>>>> +#define UHS2_DEV_CONFIG_PHY_MINOR_MASK       0xF
> >>>>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_POS        4
> >>>>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_MASK       0x3
> >>>>> +#define UHS2_DEV_CONFIG_CAN_HIBER_POS        15
> >>>>> +#define UHS2_DEV_CONFIG_CAN_HIBER_MASK       0x1
> >>>>> +#define UHS2_DEV_CONFIG_PHY_CAPS1    (UHS2_DEV_CONFIG_REG + 0x003)
> >>>>> +#define UHS2_DEV_CONFIG_N_LSS_SYN_MASK       0xF
> >>>>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_POS        4
> >>>>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_MASK       0xF
> >>>>> +
> >>>>> +#define UHS2_DEV_CONFIG_PHY_SET                      (UHS2_DEV_CONFIG_REG + 0x00A)
> >>>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_POS    6
> >>>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_A              0x0
> >>>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_B              0x1
> >>>>> +
> >>>>> +/* LINK-TRAN Caps and Settings registers */
> >>>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS               (UHS2_DEV_CONFIG_REG + 0x004)
> >>>>> +#define UHS2_DEV_CONFIG_LT_MINOR_MASK                0xF
> >>>>> +#define UHS2_DEV_CONFIG_LT_MAJOR_POS         4
> >>>>> +#define UHS2_DEV_CONFIG_LT_MAJOR_MASK                0x3
> >>>>> +#define UHS2_DEV_CONFIG_N_FCU_POS            8
> >>>>> +#define UHS2_DEV_CONFIG_N_FCU_MASK           0xFF
> >>>>> +#define UHS2_DEV_CONFIG_DEV_TYPE_POS         16
> >>>>> +#define UHS2_DEV_CONFIG_DEV_TYPE_MASK                0x7
> >>>>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_POS              20
> >>>>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK     0xFFF
> >>>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS1              (UHS2_DEV_CONFIG_REG + 0x005)
> >>>>> +#define UHS2_DEV_CONFIG_N_DATA_GAP_MASK              0xFF
> >>>>> +
> >>>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_SET                (UHS2_DEV_CONFIG_REG + 0x00C)
> >>>>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN   0x200
> >>>>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS 16
> >>>>> +
> >>>>> +/* Preset register */
> >>>>> +#define UHS2_DEV_CONFIG_PRESET       (UHS2_DEV_CONFIG_REG + 0x040)
> >>>>> +
> >>>>> +#define UHS2_DEV_INT_REG     0x100
> >>>>> +
> >>>>> +#define UHS2_DEV_STATUS_REG  0x180
> >>>>> +
> >>>>> +#define UHS2_DEV_CMD_REG             0x200
> >>>>> +#define UHS2_DEV_CMD_FULL_RESET              (UHS2_DEV_CMD_REG + 0x000)
> >>>>> +#define UHS2_DEV_CMD_GO_DORMANT_STATE        (UHS2_DEV_CMD_REG + 0x001)
> >>>>> +#define UHS2_DEV_CMD_DORMANT_HIBER   BIT(7)
> >>>>> +#define UHS2_DEV_CMD_DEVICE_INIT     (UHS2_DEV_CMD_REG + 0x002)
> >>>>> +#define UHS2_DEV_INIT_COMPLETE_FLAG  BIT(11)
> >>>>> +#define UHS2_DEV_CMD_ENUMERATE               (UHS2_DEV_CMD_REG + 0x003)
> >>>>> +#define UHS2_DEV_CMD_TRANS_ABORT     (UHS2_DEV_CMD_REG + 0x004)
> >>>>> +
> >>>>> +#define UHS2_RCLK_MAX        52000000
> >>>>> +#define UHS2_RCLK_MIN        26000000
> >>>>> +
> >>>>> +struct sd_uhs2_wait_active_state_data {
> >>>>> +     struct mmc_host *host;
> >>>>> +     struct mmc_command *cmd;
> >>>>> +};
> >>>>> +
> >>>>> +#endif /* LINUX_MMC_UHS2_H */
> >>>>
> >>>
> >>> Thanks, Victor Shih
> >>
> >
> > Best regards,
> > Ben Chuang
>

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards
  2022-11-18  1:19             ` Ben Chuang
@ 2022-12-13  8:44               ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:44 UTC (permalink / raw)
  To: Ben Chuang
  Cc: Adrian Hunter, ulf.hansson, linux-mmc, linux-kernel, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Jason Lai

Hi, Adrian

On Fri, Nov 18, 2022 at 9:20 AM Ben Chuang <benchuanggli@gmail.com> wrote:
>
> On Fri, Nov 18, 2022 at 12:05 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >
> > On 17/11/22 08:19, Ben Chuang wrote:
> > > Hi,
> > >
> > > On Wed, Nov 16, 2022 at 9:48 PM Adrian Hunter <adrian.hunter@intel.com> wrote:
> > >>
> > >> On 16/11/22 13:06, Victor Shih wrote:
> > >>> Hi, Adrian
> > >>>
> > >>> On Wed, Nov 2, 2022 at 1:12 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> > >>>>
> > >>>> On 19/10/22 14:06, Victor Shih wrote:
> > >>>>> Add UHS-II specific data structures for commands and defines for
> > >>>>> registers, as described in Part 1 UHS-II Addendum Version 1.01.
> > >>>>>
> > >>>>> UHS-II related definitions are listed below:
> > >>>>>   1. UHS-II card capability: sd_uhs2_caps{}
> > >>>>>   2. UHS-II configuration: sd_uhs2_config{}
> > >>>>>   3. UHS-II Command structure: uhs2_command{}
> > >>>>>   4. UHS-II register I/O address and register field definitions: sd_uhs2.h
> > >>>>>
> > >>>>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> > >>>>> Signed-off-by: Jason Lai <jason.lai@genesyslogic.com.tw>
> > >>>>> Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > >>>>> ---
> > >>>>>
> > >>>>> Updates in V5:
> > >>>>>  - Added UHS2 interfaces in mmc_host_ops: host.h
> > >>>>>  - Added UHS2 VDD2 power supply in mmc_supply: host.h
> > >>>>>  - Added UHS2-specific OCR and UHS2 VDD2 max current in mmc_host: host.h
> > >>>>>  - Added definition of UHS2 VDD2 1.65v-1.95v in mmc_host: host.h
> > >>>>>  - Added flags/MMC_UHS2_SUPPORT/MMC_UHS2_2L_HD in mmc_host: host.h
> > >>>>> ---
> > >>>>>  include/linux/mmc/card.h    |  42 +++++-
> > >>>>>  include/linux/mmc/core.h    |  13 ++
> > >>>>>  include/linux/mmc/host.h    |  70 +++++++++-
> > >>>>>  include/linux/mmc/sd_uhs2.h | 263 ++++++++++++++++++++++++++++++++++++
> > >>>>>  4 files changed, 386 insertions(+), 2 deletions(-)
> > >>>>>  create mode 100644 include/linux/mmc/sd_uhs2.h
> > >>>>>
> > >>>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > >>>>> index 4a42f31b7bb0..d638a2c689cf 100644
> > >>>>> --- a/include/linux/mmc/card.h
> > >>>>> +++ b/include/linux/mmc/card.h
> > >>>>> @@ -190,6 +190,13 @@ struct sd_switch_caps {
> > >>>>>  #define SD_MAX_CURRENT_400   (1 << SD_SET_CURRENT_LIMIT_400)
> > >>>>>  #define SD_MAX_CURRENT_600   (1 << SD_SET_CURRENT_LIMIT_600)
> > >>>>>  #define SD_MAX_CURRENT_800   (1 << SD_SET_CURRENT_LIMIT_800)
> > >>>>> +     unsigned int            sd4_curr_limit;
> > >>>>> +#define SD4_SET_POWER_LIMIT_0_72W    0
> > >>>>> +#define SD4_SET_POWER_LIMIT_1_44W    1
> > >>>>> +#define SD4_SET_POWER_LIMIT_2_16W    2
> > >>>>> +#define SD4_SET_POWER_LIMIT_2_88W    3
> > >>>>> +#define SD4_SET_POWER_LIMIT_1_80W    4
> > >>>>> +#define SD4_SET_POWER_NO_CHANGE              (-1)
> > >>>>>  };
> > >>>>>
> > >>>>>  struct sd_ext_reg {
> > >>>>> @@ -213,7 +220,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 {
> > >>>>> @@ -323,6 +358,9 @@ struct mmc_card {
> > >>>>>       struct sd_ext_reg       ext_perf;       /* SD extension reg for PERF */
> > >>>>>
> > >>>>>       struct sd_uhs2_config   uhs2_config;    /* SD UHS-II config */
> > >>>>> +     u8                      uhs2_state;     /* SD UHS-II states */
> > >>>>> +#define MMC_UHS2_INITIALIZED BIT(1)
> > >>>>> +#define MMC_UHS2_SPEED_B     BIT(2)
> > >>>>>
> > >>>>>       unsigned int            sdio_funcs;     /* number of SDIO functions */
> > >>>>>       atomic_t                sdio_funcs_probed; /* number of probed SDIO funcs */
> > >>>>> @@ -364,4 +402,6 @@ bool mmc_card_is_blockaddr(struct mmc_card *card);
> > >>>>>  #define mmc_card_sdio(c)     ((c)->type == MMC_TYPE_SDIO)
> > >>>>>  #define mmc_card_sd_combo(c) ((c)->type == MMC_TYPE_SD_COMBO)
> > >>>>>
> > >>>>> +#define mmc_card_can_poweroff_notify(c)      ((c)->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY)
> > >>>>> +
> > >>>>>  #endif /* LINUX_MMC_CARD_H */
> > >>>>> diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
> > >>>>> index 6efec0b9820c..2a0581d87706 100644
> > >>>>> --- a/include/linux/mmc/core.h
> > >>>>> +++ b/include/linux/mmc/core.h
> > >>>>> @@ -23,6 +23,14 @@ enum mmc_blk_status {
> > >>>>>       MMC_BLK_NEW_REQUEST,
> > >>>>>  };
> > >>>>>
> > >>>>> +struct uhs2_command {
> > >>>>> +     u16     header;
> > >>>>> +     u16     arg;
> > >>>>> +     __be32  *payload;
> > >>>>> +     u32     payload_len;
> > >>>>> +     u32     packet_len;
> > >>>>> +};
> > >>>>> +
> > >>>>>  struct mmc_command {
> > >>>>>       u32                     opcode;
> > >>>>>       u32                     arg;
> > >>>>> @@ -109,6 +117,11 @@ struct mmc_command {
> > >>>>>       unsigned int            busy_timeout;   /* busy detect timeout in ms */
> > >>>>>       struct mmc_data         *data;          /* data segment associated with cmd */
> > >>>>>       struct mmc_request      *mrq;           /* associated request */
> > >>>>> +
> > >>>>> +     struct uhs2_command     *uhs2_cmd;      /* UHS2 command */
> > >>>>> +     u8                      *uhs2_resp;     /* UHS2 native cmd resp */
> > >>>>> +     u8                      uhs2_resp_len;  /* UHS2 native cmd resp len */
> > >>>>> +     u8                      uhs2_tmode0_flag; /* UHS2 transfer mode flag */
> > >>>>>  };
> > >>>>>
> > >>>>>  struct mmc_data {
> > >>>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> > >>>>> index 895bcf7f80b7..249a9414ad10 100644
> > >>>>> --- a/include/linux/mmc/host.h
> > >>>>> +++ b/include/linux/mmc/host.h
> > >>>>> @@ -16,6 +16,7 @@
> > >>>>>  #include <linux/mmc/pm.h>
> > >>>>>  #include <linux/dma-direction.h>
> > >>>>>  #include <linux/blk-crypto-profile.h>
> > >>>>> +#include <linux/mmc/sd_uhs2.h>
> > >>>>>
> > >>>>>  struct mmc_ios {
> > >>>>>       unsigned int    clock;                  /* clock rate */
> > >>>>> @@ -96,7 +97,48 @@ struct mmc_clk_phase_map {
> > >>>>>  };
> > >>>>>
> > >>>>>  struct sd_uhs2_caps {
> > >>>>> -     /* TODO: Add UHS-II capabilities for the host. */
> > >>>>> +     u32     dap;
> > >>>>> +     u32     gap;
> > >>>>> +     u32     group_desc;
> > >>>>> +     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 sd_uhs2_ios {
> > >>>>> +     bool            is_2L_HD_mode;
> > >>>>> +     bool            is_APP_CMD;
> > >>>>> +     unsigned int    power_delay_ms;         /* waiting for stable power */
> > >>>>> +};
> > >>>>> +
> > >>>>> +enum sd_uhs2_operation {
> > >>>>> +     UHS2_PHY_INIT = 0,
> > >>>>> +     UHS2_SET_CONFIG,
> > >>>>> +     UHS2_ENABLE_INT,
> > >>>>> +     UHS2_DISABLE_INT,
> > >>>>> +     UHS2_ENABLE_CLK,
> > >>>>> +     UHS2_DISABLE_CLK,
> > >>>>> +     UHS2_CHECK_DORMANT,
> > >>>>> +     UHS2_SET_SPEED_B,
> > >>>>> +     UHS2_POST_ATTACH_SD,
> > >>>>>  };
> > >>>>>
> > >>>>>  struct mmc_host;
> > >>>>> @@ -231,6 +273,20 @@ 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 */
> > >>>>> +     int     (*uhs2_detect_init)(struct mmc_host *host);
> > >>>>
> > >>>> Never called?
> > >>>
> > >>> Yes, I will delete it.
> > >>>

I will update it in the patch#5 of the new [PATCH V6].

> > >>>>
> > >>>>> +     int     (*uhs2_set_reg)(struct mmc_host *host, enum sd_uhs2_operation act);
> > >>>>
> > >>>> Never called?
> > >>>
> > >>> Yes, I will delete it.
> > >>>

I will update it in the patch#5 of the new [PATCH V6].

> > >>>>
> > >>>>> +     int (*uhs2_disable_clk)(struct mmc_host *host);
> > >>>>
> > >>>> Never called?
> > >>>
> > >>> Yes, I will delete it.
> > >>>

I will update it in the patch#5 of the new [PATCH V6].

> > >>>>
> > >>>>> +     int (*uhs2_enable_clk)(struct mmc_host *host);
> > >>>>
> > >>>> Never called?
> > >>>
> > >>> Yes, I will delete it.
> > >>>

I will update it in the patch#5 of the new [PATCH V6].

> > >>>>
> > >>>>> +
> > >>>>> +     /*
> > >>>>> +      * The uhs2_control callback is used to execute SD UHS-II specific
> > >>>>> +      * operations. It's mandatory to implement for hosts that supports the
> > >>>>> +      * SD UHS-II interface (MMC_CAP2_SD_UHS2). Expected return values are a
> > >>>>> +      * negative errno in case of a failure or zero for success.
> > >>>>> +      */
> > >>>>> +     int     (*uhs2_control)(struct mmc_host *host, enum sd_uhs2_operation op);
> > >>>>>  };
> > >>>>>
> > >>>>>  struct mmc_cqe_ops {
> > >>>>> @@ -323,6 +379,7 @@ struct mmc_pwrseq;
> > >>>>>
> > >>>>>  struct mmc_supply {
> > >>>>>       struct regulator *vmmc;         /* Card power supply */
> > >>>>> +     struct regulator *vmmc2;        /* UHS2 VDD2 power supply */
> > >>>>>       struct regulator *vqmmc;        /* Optional Vccq supply */
> > >>>>>       struct regulator *vqmmc2;       /* Optional supply for phy */
> > >>>>>  };
> > >>>>> @@ -344,10 +401,12 @@ struct mmc_host {
> > >>>>>       u32                     ocr_avail_sdio; /* SDIO-specific OCR */
> > >>>>>       u32                     ocr_avail_sd;   /* SD-specific OCR */
> > >>>>>       u32                     ocr_avail_mmc;  /* MMC-specific OCR */
> > >>>>> +     u32                     ocr_avail_uhs2; /* UHS2-specific OCR */
> > >>>>>       struct wakeup_source    *ws;            /* Enable consume of uevents */
> > >>>>>       u32                     max_current_330;
> > >>>>>       u32                     max_current_300;
> > >>>>>       u32                     max_current_180;
> > >>>>> +     u32                     max_current_180_vdd2; /* UHS2 vdd2 max curt. */
> > >>>>>
> > >>>>>  #define MMC_VDD_165_195              0x00000080      /* VDD voltage 1.65 - 1.95 */
> > >>>>>  #define MMC_VDD_20_21                0x00000100      /* VDD voltage 2.0 ~ 2.1 */
> > >>>>> @@ -366,6 +425,7 @@ struct mmc_host {
> > >>>>>  #define MMC_VDD_33_34                0x00200000      /* VDD voltage 3.3 ~ 3.4 */
> > >>>>>  #define MMC_VDD_34_35                0x00400000      /* VDD voltage 3.4 ~ 3.5 */
> > >>>>>  #define MMC_VDD_35_36                0x00800000      /* VDD voltage 3.5 ~ 3.6 */
> > >>>>> +#define MMC_VDD2_165_195     0x00000080      /* UHS2 VDD2 1.65 ~ 1.95 */
> > >>>>>
> > >>>>>       u32                     caps;           /* Host capabilities */
> > >>>>>
> > >>>>> @@ -443,7 +503,12 @@ struct mmc_host {
> > >>>>>  #endif
> > >>>>>  #define MMC_CAP2_ALT_GPT_TEGRA       (1 << 28)       /* Host with eMMC that has GPT entry at a non-standard location */
> > >>>>>
> > >>>>> +     int flags;
> > >>>>> +#define MMC_UHS2_SUPPORT     (1 << 0)
> > >>>>
> > >>>> MMC_UHS2_SUPPORT is getting mixed up with MMC_UHS2_INITIALIZED.
> > >>>> Both have the same value, but MMC_UHS2_SUPPORT is for
> > >>>> host->flags and MMC_UHS2_INITIALIZED is for card->uhs2_state
> > >>>>
> > >>>> Please use the correct flag with the correct variable.
> > >>>>
> > >>>
> > >>> The value of MMC_UHS2_SUPPORT is (1<<0) and the value of
> > >>> MMC_UHS2_INITIALIZED is BIT(1).
> > >>> Both have different values, therefore I'm not sure what you mean.
> > >>> May you give me some more advice? Thanks.
> > >>
> > >> I guess I got confused about the values, however it is not OK to
> > >> use MMC_UHS2_INITIALIZED for both mmc->flags and card->uhs2_state.
> > >> Please make a separate define with a different name for mmc->flags
> > >> version of MMC_UHS2_INITIALIZED.
> > >
> > > MMC_UHS2_INITIALIZED here is used to judge that the UHS-II I/F has been
> > > initialized and can run in SD-TRAN. In this state,  some SD commands
> > > require a distinction. For example, ACMD (CMD55) should be set by the APP
> > > field in UHS-II packet.
> >
> > OK, but SD commands cannot be sent in UHS-II mode without SD-TRAN
> > so is the distinction needed?
>
> No need, if these SD commands are sent in SD_TRAN mode.
>

I will update it in the the new [PATCH V6].

> >
> > >
> > >>
> > >> Also, I am confused about the purpose of mmc->flags and
> > >> card->uhs2_state.
> > >
> > > It looks like the mmc->flags and card->uhs2_state have the same purpose.
> > > I think it is having trouble with card == NULL in mmc_app_cmd(*host, *card)
> > > in patch [V5, 06/26] so just add one more mmc->flags.
> > > Can wait for confirmation from Victor.
> > >
> > >>
> > >> A host is UHS-II capable as represented by MMC_CAP2_SD_UHS2.
> > >> To initialize and use a UHS-II card in UHS-II mode, the host
> > >> must be in UHS-II mode.
> > >> To initialize and use a UHS-II card in SD mode, the host
> > >> must be in SD mode.
> > >> So the state of the card and host is always the same:
> > >> either UHS-II or not.  Note, that is a consequence of the
> > >> hardware I/F.  Whether SD I/F or UHS-II I/F is used is
> > >> decided before sending any UHS-II commands. SD I/F is
> > >> disabled during UHS-II PHY initialization, whereas
> > >> UHS-II I/F is disabled before execution of ACMD41 is
> > >> completed.
> > >>
> > >> So it seems like there would only be a need for one flag
> > >> to indicate UHS-II mode?
> > >>
> > >>>
> > >>>>> +#define MMC_UHS2_2L_HD               (1 << 2)
> > >>>>
> > >>>> MMC_UHS2_2L_HD does not seem to be used. Is it needed?
> > >>>
> > >>> I confirmed this, I don't use it, I will delete it.
> > >>>

I will update it in the patch#5 of the new [PATCH V6].

> > >>>>
> > >>>>> +
> > >>>>>       struct sd_uhs2_caps     uhs2_caps;      /* Host UHS-II capabilities */
> > >>>>> +     struct sd_uhs2_ios      uhs2_ios;       /* Host UHS-II capabilities */
> > >>>>>
> > >>>>>       int                     fixed_drv_type; /* fixed driver type for non-removable media */
> > >>>>>
> > >>>>> @@ -695,4 +760,7 @@ int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
> > >>>>>  int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
> > >>>>>  int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
> > >>>>>
> > >>>>> +#define mmc_uhs2_2L_HD_mode(h)       ((h)->uhs2_ios.is_2L_HD_mode)
> > >>>>> +#define mmc_uhs2_APP_cmd(h)  ((h)->uhs2_ios.is_APP_CMD)
> > >>>>> +
> > >>>>>  #endif /* LINUX_MMC_HOST_H */
> > >>>>> diff --git a/include/linux/mmc/sd_uhs2.h b/include/linux/mmc/sd_uhs2.h
> > >>>>> new file mode 100644
> > >>>>> index 000000000000..8fcf702cf4a5
> > >>>>> --- /dev/null
> > >>>>> +++ b/include/linux/mmc/sd_uhs2.h
> > >>>>> @@ -0,0 +1,263 @@
> > >>>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > >>>>> +/*
> > >>>>> + * Header file for UHS-II packets, Host Controller registers and I/O
> > >>>>> + * accessors.
> > >>>>> + *
> > >>>>> + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> > >>>>> + */
> > >>>>> +#ifndef LINUX_MMC_UHS2_H
> > >>>>> +#define LINUX_MMC_UHS2_H
> > >>>>> +
> > >>>>> +/* LINK Layer definition */
> > >>>>> +/*
> > >>>>> + * UHS2 Header:
> > >>>>> + * Refer to UHS-II Addendum Version 1.02 Figure 5-2, the format of CCMD Header is described below:
> > >>>>> + *      bit [3:0]  : DID(Destination ID = Node ID of UHS2 card)
> > >>>>> + *      bit [6:4]  : TYP(Packet Type)
> > >>>>> + *                   000b: CCMD(Control command packet)
> > >>>>> + *                   001b: DCMD(Data command packet)
> > >>>>> + *                   010b: RES(Response packet)
> > >>>>> + *                   011b: DATA(Data payload packet)
> > >>>>> + *                   111b: MSG(Message packet)
> > >>>>> + *                   Others: Reserved
> > >>>>> + *      bit [7]    : NP(Native Packet)
> > >>>>> + *      bit [10:8] : TID(Transaction ID)
> > >>>>> + *      bit [11]   : Reserved
> > >>>>> + *      bit [15:12]: SID(Source ID 0: Node ID of Host)
> > >>>>> + *
> > >>>>> + * Broadcast CCMD issued by Host is represented as DID=SID=0.
> > >>>>> + */
> > >>>>> +/*
> > >>>>> + * UHS2 Argument:
> > >>>>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-5, the format of CCMD Argument is described below:
> > >>>>> + *      bit [3:0]  : MSB of IOADR
> > >>>>> + *      bit [5:4]  : PLEN(Payload Length)
> > >>>>> + *                   00b: 0 byte
> > >>>>> + *                   01b: 4 bytes
> > >>>>> + *                   10b: 8 bytes
> > >>>>> + *                   11b: 16 bytes
> > >>>>> + *      bit [6]    : Reserved
> > >>>>> + *      bit [7]    : R/W(Read/Write)
> > >>>>> + *                   0: Control read command
> > >>>>> + *                   1: Control write command
> > >>>>> + *      bit [15:8] : LSB of IOADR
> > >>>>> + *
> > >>>>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> > >>>>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> > >>>>> + */
> > >>>>> +#define UHS2_NATIVE_PACKET_POS       7
> > >>>>> +#define UHS2_NATIVE_PACKET   (1 << UHS2_NATIVE_PACKET_POS)
> > >>>>> +
> > >>>>> +#define UHS2_PACKET_TYPE_POS 4
> > >>>>> +#define UHS2_PACKET_TYPE_CCMD        (0 << UHS2_PACKET_TYPE_POS)
> > >>>>> +#define UHS2_PACKET_TYPE_DCMD        (1 << UHS2_PACKET_TYPE_POS)
> > >>>>> +#define UHS2_PACKET_TYPE_RES (2 << UHS2_PACKET_TYPE_POS)
> > >>>>> +#define UHS2_PACKET_TYPE_DATA        (3 << UHS2_PACKET_TYPE_POS)
> > >>>>> +#define UHS2_PACKET_TYPE_MSG (7 << UHS2_PACKET_TYPE_POS)
> > >>>>> +
> > >>>>> +#define UHS2_DEST_ID_MASK    0x0F
> > >>>>> +#define UHS2_DEST_ID         0x1
> > >>>>> +
> > >>>>> +#define UHS2_SRC_ID_POS              12
> > >>>>> +#define UHS2_SRC_ID_MASK     0xF000
> > >>>>> +
> > >>>>> +#define UHS2_TRANS_ID_POS    8
> > >>>>> +#define UHS2_TRANS_ID_MASK   0x0700
> > >>>>> +
> > >>>>> +/* UHS2 MSG */
> > >>>>> +#define UHS2_MSG_CTG_POS     5
> > >>>>> +#define UHS2_MSG_CTG_LMSG    0x00
> > >>>>> +#define UHS2_MSG_CTG_INT     0x60
> > >>>>> +#define UHS2_MSG_CTG_AMSG    0x80
> > >>>>> +
> > >>>>> +#define UHS2_MSG_CTG_FCREQ   0x00
> > >>>>> +#define UHS2_MSG_CTG_FCRDY   0x01
> > >>>>> +#define UHS2_MSG_CTG_STAT    0x02
> > >>>>> +
> > >>>>> +#define UHS2_MSG_CODE_POS                    8
> > >>>>> +#define UHS2_MSG_CODE_FC_UNRECOVER_ERR               0x8
> > >>>>> +#define UHS2_MSG_CODE_STAT_UNRECOVER_ERR     0x8
> > >>>>> +#define UHS2_MSG_CODE_STAT_RECOVER_ERR               0x1
> > >>>>> +
> > >>>>> +/* TRANS Layer definition */
> > >>>>> +
> > >>>>> +/* Native packets*/
> > >>>>> +#define UHS2_NATIVE_CMD_RW_POS       7
> > >>>>> +#define UHS2_NATIVE_CMD_WRITE        (1 << UHS2_NATIVE_CMD_RW_POS)
> > >>>>> +#define UHS2_NATIVE_CMD_READ (0 << UHS2_NATIVE_CMD_RW_POS)
> > >>>>> +
> > >>>>> +#define UHS2_NATIVE_CMD_PLEN_POS     4
> > >>>>> +#define UHS2_NATIVE_CMD_PLEN_4B              (1 << UHS2_NATIVE_CMD_PLEN_POS)
> > >>>>> +#define UHS2_NATIVE_CMD_PLEN_8B              (2 << UHS2_NATIVE_CMD_PLEN_POS)
> > >>>>> +#define UHS2_NATIVE_CMD_PLEN_16B     (3 << UHS2_NATIVE_CMD_PLEN_POS)
> > >>>>> +
> > >>>>> +#define UHS2_NATIVE_CCMD_GET_MIOADR_MASK     0xF00
> > >>>>> +#define UHS2_NATIVE_CCMD_MIOADR_MASK         0x0F
> > >>>>> +
> > >>>>> +#define UHS2_NATIVE_CCMD_LIOADR_POS          8
> > >>>>> +#define UHS2_NATIVE_CCMD_GET_LIOADR_MASK     0x0FF
> > >>>>> +
> > >>>>> +#define UHS2_CCMD_DEV_INIT_COMPLETE_FLAG     BIT(11)
> > >>>>> +#define UHS2_DEV_INIT_PAYLOAD_LEN            1
> > >>>>> +#define UHS2_DEV_INIT_RESP_LEN                       6
> > >>>>> +#define UHS2_DEV_ENUM_PAYLOAD_LEN            1
> > >>>>> +#define UHS2_DEV_ENUM_RESP_LEN                       8
> > >>>>> +#define UHS2_CFG_WRITE_PAYLOAD_LEN           2
> > >>>>> +#define UHS2_CFG_WRITE_PHY_SET_RESP_LEN              4
> > >>>>> +#define UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN  5
> > >>>>> +#define UHS2_GO_DORMANT_PAYLOAD_LEN          1
> > >>>>> +
> > >>>>> +/*
> > >>>>> + * UHS2 Argument:
> > >>>>> + * Refer to UHS-II Addendum Version 1.02 Figure 6-8, the format of DCMD Argument is described below:
> > >>>>> + *      bit [3:0]  : Reserved
> > >>>>> + *      bit [6:3]  : TMODE(Transfer Mode)
> > >>>>> + *                   bit 3: DAM(Data Access Mode)
> > >>>>> + *                   bit 4: TLUM(TLEN Unit Mode)
> > >>>>> + *                   bit 5: LM(Length Mode)
> > >>>>> + *                   bit 6: DM(Duplex Mode)
> > >>>>> + *      bit [7]    : R/W(Read/Write)
> > >>>>> + *                   0: Control read command
> > >>>>> + *                   1: Control write command
> > >>>>> + *      bit [15:8] : Reserved
> > >>>>> + *
> > >>>>> + * I/O Address specifies the address of register in UHS-II I/O space accessed by CCMD.
> > >>>>> + * The unit of I/O Address is 4 Bytes. It is transmitted in MSB first, LSB last.
> > >>>>> + */
> > >>>>> +#define UHS2_DCMD_DM_POS             6
> > >>>>> +#define UHS2_DCMD_2L_HD_MODE         (1 << UHS2_DCMD_DM_POS)
> > >>>>> +#define UHS2_DCMD_LM_POS             5
> > >>>>> +#define UHS2_DCMD_LM_TLEN_EXIST              (1 << UHS2_DCMD_LM_POS)
> > >>>>> +#define UHS2_DCMD_TLUM_POS           4
> > >>>>> +#define UHS2_DCMD_TLUM_BYTE_MODE     (1 << UHS2_DCMD_TLUM_POS)
> > >>>>> +#define UHS2_NATIVE_DCMD_DAM_POS     3
> > >>>>> +#define UHS2_NATIVE_DCMD_DAM_IO              (1 << UHS2_NATIVE_DCMD_DAM_POS)
> > >>>>> +
> > >>>>> +/*
> > >>>>> + * Per UHS2 spec, DCMD payload should be MSB first. There may be
> > >>>>> + * two types of data be assembled to MSB:
> > >>>>> + * 1. TLEN: Input block size for single read/write and number of blocks
> > >>>>> + * for multiple read/write to calculate TLEN as MSB first per spec.
> > >>>>> + * 2. SD command argument.
> > >>>>> + */
> > >>>>> +static inline __be32 uhs2_dcmd_convert_msb(u32 input)
> > >>>>> +{
> > >>>>> +     u32 ret = 0;
> > >>>>> +
> > >>>>> +     ret = ((input & 0xFF) << 24) |
> > >>>>> +             (((input >> 8) & 0xFF) << 16) |
> > >>>>> +             (((input >> 16) & 0xFF) << 8) |
> > >>>>> +             ((input >> 24) & 0xFF);
> > >>>>> +     return cpu_to_be32(ret);
> > >>>>> +}
> > >>>>> +
> > >>>>> +#define UHS2_RES_NACK_POS    7
> > >>>>> +#define UHS2_RES_NACK_MASK   (0x1 << UHS2_RES_NACK_POS)
> > >>>>> +
> > >>>>> +#define UHS2_RES_ECODE_POS   4
> > >>>>> +#define UHS2_RES_ECODE_MASK  0x7
> > >>>>> +#define UHS2_RES_ECODE_COND  1
> > >>>>> +#define UHS2_RES_ECODE_ARG   2
> > >>>>> +#define UHS2_RES_ECODE_GEN   3
> > >>>>> +
> > >>>>> +/* IOADR of device registers */
> > >>>>> +#define UHS2_IOADR_GENERIC_CAPS              0x00
> > >>>>> +#define UHS2_IOADR_PHY_CAPS          0x02
> > >>>>> +#define UHS2_IOADR_LINK_CAPS         0x04
> > >>>>> +#define UHS2_IOADR_RSV_CAPS          0x06
> > >>>>> +#define UHS2_IOADR_GENERIC_SETTINGS  0x08
> > >>>>> +#define UHS2_IOADR_PHY_SETTINGS              0x0A
> > >>>>> +#define UHS2_IOADR_LINK_SETTINGS     0x0C
> > >>>>> +#define UHS2_IOADR_PRESET            0x40
> > >>>>> +
> > >>>>> +/* SD application packets */
> > >>>>> +#define UHS2_SD_CMD_INDEX_POS        8
> > >>>>> +
> > >>>>> +#define UHS2_SD_CMD_APP_POS  14
> > >>>>> +#define UHS2_SD_CMD_APP              (1 << UHS2_SD_CMD_APP_POS)
> > >>>>> +
> > >>>>> +/* UHS-II Device Registers */
> > >>>>> +#define UHS2_DEV_CONFIG_REG  0x000
> > >>>>> +
> > >>>>> +/* General Caps and Settings registers */
> > >>>>> +#define UHS2_DEV_CONFIG_GEN_CAPS     (UHS2_DEV_CONFIG_REG + 0x000)
> > >>>>> +#define UHS2_DEV_CONFIG_N_LANES_POS  8
> > >>>>> +#define UHS2_DEV_CONFIG_N_LANES_MASK 0x3F
> > >>>>> +#define UHS2_DEV_CONFIG_2L_HD_FD     0x1
> > >>>>> +#define UHS2_DEV_CONFIG_2D1U_FD              0x2
> > >>>>> +#define UHS2_DEV_CONFIG_1D2U_FD              0x4
> > >>>>> +#define UHS2_DEV_CONFIG_2D2U_FD              0x8
> > >>>>> +#define UHS2_DEV_CONFIG_DADR_POS     14
> > >>>>> +#define UHS2_DEV_CONFIG_DADR_MASK    0x1
> > >>>>> +#define UHS2_DEV_CONFIG_APP_POS              16
> > >>>>> +#define UHS2_DEV_CONFIG_APP_MASK     0xFF
> > >>>>> +#define UHS2_DEV_CONFIG_APP_SD_MEM   0x1
> > >>>>> +
> > >>>>> +#define UHS2_DEV_CONFIG_GEN_SET                      (UHS2_DEV_CONFIG_REG + 0x008)
> > >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_N_LANES_POS  8
> > >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD     0x0
> > >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_2D1U_FD              0x2
> > >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_1D2U_FD              0x3
> > >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_2D2U_FD              0x4
> > >>>>> +#define UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE BIT(31)
> > >>>>> +
> > >>>>> +/* PHY Caps and Settings registers */
> > >>>>> +#define UHS2_DEV_CONFIG_PHY_CAPS     (UHS2_DEV_CONFIG_REG + 0x002)
> > >>>>> +#define UHS2_DEV_CONFIG_PHY_MINOR_MASK       0xF
> > >>>>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_POS        4
> > >>>>> +#define UHS2_DEV_CONFIG_PHY_MAJOR_MASK       0x3
> > >>>>> +#define UHS2_DEV_CONFIG_CAN_HIBER_POS        15
> > >>>>> +#define UHS2_DEV_CONFIG_CAN_HIBER_MASK       0x1
> > >>>>> +#define UHS2_DEV_CONFIG_PHY_CAPS1    (UHS2_DEV_CONFIG_REG + 0x003)
> > >>>>> +#define UHS2_DEV_CONFIG_N_LSS_SYN_MASK       0xF
> > >>>>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_POS        4
> > >>>>> +#define UHS2_DEV_CONFIG_N_LSS_DIR_MASK       0xF
> > >>>>> +
> > >>>>> +#define UHS2_DEV_CONFIG_PHY_SET                      (UHS2_DEV_CONFIG_REG + 0x00A)
> > >>>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_POS    6
> > >>>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_A              0x0
> > >>>>> +#define UHS2_DEV_CONFIG_PHY_SET_SPEED_B              0x1
> > >>>>> +
> > >>>>> +/* LINK-TRAN Caps and Settings registers */
> > >>>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS               (UHS2_DEV_CONFIG_REG + 0x004)
> > >>>>> +#define UHS2_DEV_CONFIG_LT_MINOR_MASK                0xF
> > >>>>> +#define UHS2_DEV_CONFIG_LT_MAJOR_POS         4
> > >>>>> +#define UHS2_DEV_CONFIG_LT_MAJOR_MASK                0x3
> > >>>>> +#define UHS2_DEV_CONFIG_N_FCU_POS            8
> > >>>>> +#define UHS2_DEV_CONFIG_N_FCU_MASK           0xFF
> > >>>>> +#define UHS2_DEV_CONFIG_DEV_TYPE_POS         16
> > >>>>> +#define UHS2_DEV_CONFIG_DEV_TYPE_MASK                0x7
> > >>>>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_POS              20
> > >>>>> +#define UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK     0xFFF
> > >>>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_CAPS1              (UHS2_DEV_CONFIG_REG + 0x005)
> > >>>>> +#define UHS2_DEV_CONFIG_N_DATA_GAP_MASK              0xFF
> > >>>>> +
> > >>>>> +#define UHS2_DEV_CONFIG_LINK_TRAN_SET                (UHS2_DEV_CONFIG_REG + 0x00C)
> > >>>>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN   0x200
> > >>>>> +#define UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS 16
> > >>>>> +
> > >>>>> +/* Preset register */
> > >>>>> +#define UHS2_DEV_CONFIG_PRESET       (UHS2_DEV_CONFIG_REG + 0x040)
> > >>>>> +
> > >>>>> +#define UHS2_DEV_INT_REG     0x100
> > >>>>> +
> > >>>>> +#define UHS2_DEV_STATUS_REG  0x180
> > >>>>> +
> > >>>>> +#define UHS2_DEV_CMD_REG             0x200
> > >>>>> +#define UHS2_DEV_CMD_FULL_RESET              (UHS2_DEV_CMD_REG + 0x000)
> > >>>>> +#define UHS2_DEV_CMD_GO_DORMANT_STATE        (UHS2_DEV_CMD_REG + 0x001)
> > >>>>> +#define UHS2_DEV_CMD_DORMANT_HIBER   BIT(7)
> > >>>>> +#define UHS2_DEV_CMD_DEVICE_INIT     (UHS2_DEV_CMD_REG + 0x002)
> > >>>>> +#define UHS2_DEV_INIT_COMPLETE_FLAG  BIT(11)
> > >>>>> +#define UHS2_DEV_CMD_ENUMERATE               (UHS2_DEV_CMD_REG + 0x003)
> > >>>>> +#define UHS2_DEV_CMD_TRANS_ABORT     (UHS2_DEV_CMD_REG + 0x004)
> > >>>>> +
> > >>>>> +#define UHS2_RCLK_MAX        52000000
> > >>>>> +#define UHS2_RCLK_MIN        26000000
> > >>>>> +
> > >>>>> +struct sd_uhs2_wait_active_state_data {
> > >>>>> +     struct mmc_host *host;
> > >>>>> +     struct mmc_command *cmd;
> > >>>>> +};
> > >>>>> +
> > >>>>> +#endif /* LINUX_MMC_UHS2_H */
> > >>>>
> > >>>
> > >>> Thanks, Victor Shih
> > >>
> > >
> > > Best regards,
> > > Ben Chuang
> >

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 07/26] mmc: sdhci: add a kernel configuration for enabling UHS-II support
  2022-11-01 17:12   ` Adrian Hunter
@ 2022-12-13  8:45     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:45 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:12 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > From: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >
> > This kernel configuration, CONFIG_MMC_SDHCI_UHS2, will be used
> > in the following commits to indicate UHS-II specific code in sdhci
> > controllers.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
>
> Please merge this patch with:
>         [PATCH V5 09/26] mmc: sdhci: add UHS-II module
>

I will update it in the patch#8 of the new [PATCH V6].

> > ---
> >  drivers/mmc/host/Kconfig | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> >
> > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> > index f324daadaf70..7e53cca97934 100644
> > --- a/drivers/mmc/host/Kconfig
> > +++ b/drivers/mmc/host/Kconfig
> > @@ -89,6 +89,15 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
> >
> >         This is the case for the Nintendo Wii SDHCI.
> >
> > +config MMC_SDHCI_UHS2
> > +     tristate "UHS2 support on SDHCI controller"
> > +     depends on MMC_SDHCI
> > +     help
> > +       This option is selected by SDHCI controller drivers that want to
> > +       support UHS2-capable devices.
> > +
> > +       If you have a controller with this feature, say Y or M here.
> > +
> >  config MMC_SDHCI_PCI
> >       tristate "SDHCI support on PCI bus"
> >       depends on MMC_SDHCI && PCI
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 08/26] mmc: sdhci: add UHS-II related definitions in headers
  2022-11-01 17:12   ` Adrian Hunter
@ 2022-12-13  8:45     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:45 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:12 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > Add UHS-II related definitions in shdci.h and sdhci-uhs2.h.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
>
> I hope you don't mind, but some of the names seem a bit long,
> or could be more like regular SDHCI equivalents.  Also
> BIT() anf GENMASK() could be used more in some cases.  See
> comments below.
>
> >  drivers/mmc/host/sdhci-uhs2.h | 210 ++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci.h      |  73 +++++++++++-
> >  2 files changed, 282 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/mmc/host/sdhci-uhs2.h
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > new file mode 100644
> > index 000000000000..5610affebdf3
> > --- /dev/null
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -0,0 +1,210 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + *  linux/drivers/mmc/host/sdhci-uhs2.h - Secure Digital Host Controller
> > + *  Interface driver
> > + *
> > + * Header file for Host Controller UHS2 related registers and I/O accessors.
>
> I/O accessors?
>

I will update it in the patch#7 of the new [PATCH V6].

> > + *
> > + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> > + */
> > +#ifndef __SDHCI_UHS2_H
> > +#define __SDHCI_UHS2_H
> > +
> > +#include <linux/bits.h>
> > +
> > +/*
> > + * UHS-II Controller registers
> > + * 0x74 preset in sdhci.h
> > + * 0x80
> > + * 0x84-0xB4
> > + * 0xB8-0xCF
> > + * 0xE0-0xE7
> > + */
> > +/* UHS2 */
>
> Rather than above, let's just have one simple comment:
>
> /* SDHCI Category B registers : UHS2 only */
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define SDHCI_UHS2_BLOCK_SIZE        0x80
> > +#define  SDHCI_UHS2_MAKE_BLKSZ(dma, blksz) \
> > +     ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
>
> I would prefer to wrap only lines over 100 columns
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> > +#define SDHCI_UHS2_BLOCK_COUNT       0x84
> > +
> > +#define SDHCI_UHS2_CMD_PACKET        0x88
> > +#define  SDHCI_UHS2_CMD_PACK_MAX_LEN 20
> > +
> > +#define SDHCI_UHS2_TRANS_MODE        0x9C
> > +#define  SDHCI_UHS2_TRNS_DMA         BIT(0)
> > +#define  SDHCI_UHS2_TRNS_BLK_CNT_EN  BIT(1)
> > +#define  SDHCI_UHS2_TRNS_DATA_TRNS_WRT       BIT(4)
> > +#define  SDHCI_UHS2_TRNS_BLK_BYTE_MODE       BIT(5)
> > +#define  SDHCI_UHS2_TRNS_RES_R5              BIT(6)
> > +#define  SDHCI_UHS2_TRNS_RES_ERR_CHECK_EN    BIT(7)
> > +#define  SDHCI_UHS2_TRNS_RES_INT_DIS BIT(8)
> > +#define  SDHCI_UHS2_TRNS_WAIT_EBSY   BIT(14)
> > +#define  SDHCI_UHS2_TRNS_2L_HD               BIT(15)
> > +
> > +#define SDHCI_UHS2_COMMAND   0x9E
>
> Please line up all the values.  Also some names could be
> shortened.  There are suggestions in the comments below.
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define  SDHCI_UHS2_COMMAND_SUB_CMD  0x0004
>
> Please use BIT() and GENMASK() macros here and elsewhere.
>
> Also could keep the name "SDHCI_UHS2_COMMAND" for the
> register but abbreviate "COMMAND" to "CMD" for the fields.
> SDHCI_COMMAND register does it that way.
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define  SDHCI_UHS2_COMMAND_DATA     0x0020
> > +#define  SDHCI_UHS2_COMMAND_TRNS_ABORT       0x0040
> > +#define  SDHCI_UHS2_COMMAND_CMD12    0x0080
> > +#define  SDHCI_UHS2_COMMAND_DORMANT  0x00C0
> > +#define  SDHCI_UHS2_COMMAND_PACK_LEN_MASK    GENMASK(12, 8)
> > +#define  SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT   8
>
> If possible, please avoid macros for shift value.
> Instead use FIELD_GET() and FIELD_PREP(), or even
> __bf_shf() if FIELD_GET() and FIELD_PREP() don't
> work.
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> > +#define SDHCI_UHS2_RESPONSE  0xA0
> > +#define  SDHCI_UHS2_RESPONSE_MAX_LEN 20
> > +
> > +#define SDHCI_UHS2_MSG_SELECT        0xB4
> > +#define SDHCI_UHS2_MSG_SELECT_CURR   0x0
> > +#define SDHCI_UHS2_MSG_SELECT_ONE    0x1
> > +#define SDHCI_UHS2_MSG_SELECT_TWO    0x2
> > +#define SDHCI_UHS2_MSG_SELECT_THREE  0x3
> > +
> > +#define SDHCI_UHS2_MSG               0xB8
> > +
> > +#define SDHCI_UHS2_DEV_INT_STATUS    0xBC
> > +
> > +#define SDHCI_UHS2_DEV_SELECT        0xBE
> > +#define SDHCI_UHS2_DEV_SELECT_DEV_SEL_MASK   GENMASK(3, 0)
>
> Perhaps just SDHCI_UHS2_DEV_SEL_MASK
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define SDHCI_UHS2_DEV_SELECT_INT_MSG_EN     BIT(7)
>
> Perhaps just SDHCI_UHS2_DEV_SEL_INT_MSG_EN
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> > +#define SDHCI_UHS2_DEV_INT_CODE      0xBF
> > +
> > +#define SDHCI_UHS2_SW_RESET  0xC0
> > +#define SDHCI_UHS2_SW_RESET_FULL     0x0001
> > +#define SDHCI_UHS2_SW_RESET_SD               0x0002
>
> Please use BIT() macros
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> > +#define SDHCI_UHS2_TIMER_CTRL        0xC2
> > +#define SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT 4
>
> Please use GENMASK()
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> > +#define SDHCI_UHS2_ERR_INT_STATUS            0xC4
> > +#define SDHCI_UHS2_ERR_INT_STATUS_EN         0xC8
> > +#define SDHCI_UHS2_ERR_INT_SIG_EN            0xCC
>
> Let's make those 3 more like regular SDHCI names i.e.
>
> #define SDHCI_UHS2_INT_STATUS                   0xC4
> #define SDHCI_UHS2_INT_STATUS_ENABLE            0xC8
> #define SDHCI_UHS2_INT_SIGNAL_ENABLE            0xCC
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define SDHCI_UHS2_ERR_INT_STATUS_HEADER     BIT(0)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_RES                BIT(1)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP  BIT(2)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_CRC                BIT(3)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_FRAME              BIT(4)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_TID                BIT(5)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER  BIT(7)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_EBUSY              BIT(8)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_ADMA               BIT(15)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT        BIT(16)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT   BIT(17)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_VENDOR     BIT(27)
>
> Again, let's make the interrupt bits above more like regular SDHCI
> names i.e.
>
> #define SDHCI_UHS2_INT_HEADER_ERR       BIT(0)
> #define SDHCI_UHS2_INT_RES_ERR          BIT(1)
> #define SDHCI_UHS2_INT_RETRY_EXP        BIT(2)
> #define SDHCI_UHS2_INT_CRC              BIT(3)
> #define SDHCI_UHS2_INT_FRAME_ERR        BIT(4)
> #define SDHCI_UHS2_INT_TID_ERR          BIT(5)
> #define SDHCI_UHS2_INT_UNRECOVERABLE    BIT(7)
> #define SDHCI_UHS2_INT_EBUSY_ERR        BIT(8)
> #define SDHCI_UHS2_INT_ADMA_ERROR       BIT(15)
> #define SDHCI_UHS2_INT_CMD_TIMEOUT      BIT(16)
> #define SDHCI_UHS2_INT_DEADLOCK_TIMEOUT BIT(17)
> #define SDHCI_UHS2_INT_VENDOR_ERR       BIT(27)
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define SDHCI_UHS2_ERR_INT_STATUS_MASK       \
>
> More like regular SDHCI name
>
> #define SDHCI_UHS2_INT_ERROR_MASK
>

I will update it in the patch#7 of the new [PATCH V6].

> > +             (SDHCI_UHS2_ERR_INT_STATUS_HEADER |     \
> > +             SDHCI_UHS2_ERR_INT_STATUS_RES |         \
> > +             SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP |   \
> > +             SDHCI_UHS2_ERR_INT_STATUS_CRC |         \
> > +             SDHCI_UHS2_ERR_INT_STATUS_FRAME |       \
> > +             SDHCI_UHS2_ERR_INT_STATUS_TID |         \
> > +             SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER |   \
> > +             SDHCI_UHS2_ERR_INT_STATUS_EBUSY |       \
> > +             SDHCI_UHS2_ERR_INT_STATUS_ADMA |        \
> > +             SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT | \
> > +             SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_CMD_MASK   \
>
> SDHCI_UHS2_INT_CMD_ERR_MASK
>

I will update it in the patch#7 of the new [PATCH V6].

> > +             (SDHCI_UHS2_ERR_INT_STATUS_HEADER |     \
> > +             SDHCI_UHS2_ERR_INT_STATUS_RES |         \
> > +             SDHCI_UHS2_ERR_INT_STATUS_FRAME |       \
> > +             SDHCI_UHS2_ERR_INT_STATUS_TID |         \
> > +             SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT)
> > +/* CRC Error occurs during a packet receiving */
> > +#define SDHCI_UHS2_ERR_INT_STATUS_DATA_MASK  \
>
> SDHCI_UHS2_INT_DATA_ERR_MASK
>

I will update it in the patch#7 of the new [PATCH V6].

> > +             (SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP |  \
> > +             SDHCI_UHS2_ERR_INT_STATUS_CRC |         \
> > +             SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER |   \
> > +             SDHCI_UHS2_ERR_INT_STATUS_EBUSY |       \
> > +             SDHCI_UHS2_ERR_INT_STATUS_ADMA |        \
> > +             SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT)
> > +
> > +#define SDHCI_UHS2_SET_PTR   0xE0
>
> "SET" is not clear. "SETTINGS" would be better
>
> > +#define   SDHCI_UHS2_GEN_SET_POWER_LOW               0x0001
>
> Please use BIT() macros
>
> > +#define   SDHCI_UHS2_GEN_SET_N_LANES_POS     8
>
> Please use GENMASK()
>
> Also I would call this SDHCI_UHS2_LANES
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define   SDHCI_UHS2_GEN_SET_2L_FD_HD                0x0
> > +#define   SDHCI_UHS2_GEN_SET_2D1U_FD         0x2
> > +#define   SDHCI_UHS2_GEN_SET_1D2U_FD         0x3
> > +#define   SDHCI_UHS2_GEN_SET_2D2U_FD         0x4
>
> #define   SDHCI_UHS2_FD_OR_2L_HD                0 /* 2 lanes */
> #define   SDHCI_UHS2_2D1U_FD                    2 /* 3 lanes, 2 down, 1 up, full duplex */
> #define   SDHCI_UHS2_1D2U_FD                    3 /* 3 lanes, 1 down, 2 up, full duplex */
> #define   SDHCI_UHS2_2D2U_FD                    4 /* 4 lanes, 2 down, 2 up, full duplex */
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> > +#define   SDHCI_UHS2_PHY_SET_SPEED_POS               6
>
> Please use GENMASK()
>
> > +#define   SDHCI_UHS2_PHY_SET_HIBER_EN                BIT(12)
>
> HIBER -> HIBERNATE
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define   SDHCI_UHS2_PHY_SET_N_LSS_SYN_MASK  GENMASK(19, 16)
> > +#define   SDHCI_UHS2_PHY_SET_N_LSS_SYN_POS   16
> > +#define   SDHCI_UHS2_PHY_SET_N_LSS_DIR_MASK  GENMASK(23, 20)
> > +#define   SDHCI_UHS2_PHY_SET_N_LSS_DIR_POS   20
> > +
> > +#define   SDHCI_UHS2_TRAN_SET_N_FCU_MASK     GENMASK(15, 8)
> > +#define   SDHCI_UHS2_TRAN_SET_N_FCU_POS              8
> > +#define   SDHCI_UHS2_TRAN_SET_RETRY_CNT_MASK GENMASK(17, 16)
> > +#define   SDHCI_UHS2_TRAN_SET_RETRY_CNT_POS  16
> > +
> > +#define   SDHCI_UHS2_TRAN_SET_1_N_DAT_GAP_MASK       GENMASK(7, 0)
>
> "_SET_" in the names above is not needed
>
> Also please do not use *_POS macros - use FEILD_GET()
> and FIELD_PREP()
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> > +#define SDHCI_UHS2_HOST_CAPS_PTR     0xE2
>
> To make them shorter, let's change all "SDHCI_UHS2_HOST_CAPS_"
> to "SDHCI_UHS2_CAP_"
>
> Also _GEN_ is a bit meaningless in the field names, and no
> _SHIFT please
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define  SDHCI_UHS2_HOST_CAPS_GEN_OFFSET     0
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_DAP_MASK  GENMASK(3, 0)
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_GAP_MASK  GENMASK(7, 4)
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_GAP(gap)  ((gap) * 360)
> > +#define SDHCI_UHS2_HOST_CAPS_GEN_GAP_SHIFT 4
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_LANE_MASK GENMASK(13, 8)
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_LANE_SHIFT        8
> > +#define    SDHCI_UHS2_HOST_CAPS_GEN_2L_HD_FD 1
> > +#define    SDHCI_UHS2_HOST_CAPS_GEN_2D1U_FD  2
> > +#define    SDHCI_UHS2_HOST_CAPS_GEN_1D2U_FD  4
> > +#define    SDHCI_UHS2_HOST_CAPS_GEN_2D2U_FD  8
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_ADDR_64   BIT(14)
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_BOOT              BIT(15)
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_MASK     GENMASK(17, 16)
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_SHIFT    16
> > +#define    SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_RMV     0
> > +#define    SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_EMB     1
> > +#define    SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_EMB_RMV 2
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_NUM_DEV_MASK              GENMASK(21, 18)
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_NUM_DEV_SHIFT     18
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_MASK     GENMASK(23, 22)
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_SHIFT    22
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_P2P              0
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_RING     1
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_HUB              2
> > +#define   SDHCI_UHS2_HOST_CAPS_GEN_BUS_TOPO_HUB_RING 3
> > +
> > +#define  SDHCI_UHS2_HOST_CAPS_PHY_OFFSET     4
> > +#define   SDHCI_UHS2_HOST_CAPS_PHY_REV_MASK          GENMASK(5, 0)
> > +#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_MASK                GENMASK(7, 6)
> > +#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_SHIFT               6
> > +#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_A           0
> > +#define   SDHCI_UHS2_HOST_CAPS_PHY_RANGE_B           1
> > +#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_MASK    GENMASK(19, 16)
> > +#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_SHIFT   16
> > +#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_MASK    GENMASK(23, 20)
> > +#define   SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_SHIFT   20
> > +#define  SDHCI_UHS2_HOST_CAPS_TRAN_OFFSET    8
> > +#define   SDHCI_UHS2_HOST_CAPS_TRAN_LINK_REV_MASK    GENMASK(5, 0)
> > +#define   SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_MASK               GENMASK(15, 8)
> > +#define   SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_SHIFT              8
> > +#define   SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_MASK   GENMASK(18, 16)
> > +#define   SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_SHIFT  16
> > +#define   SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_MASK     GENMASK(31, 20)
> > +#define   SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_SHIFT    20
> > +
> > +#define  SDHCI_UHS2_HOST_CAPS_TRAN_1_OFFSET  12
> > +#define  SDHCI_UHS2_HOST_CAPS_TRAN_1_N_DATA_GAP_MASK GENMASK(7, 0)
> > +
> > +#define SDHCI_UHS2_TEST_PTR  0xE4
> > +#define  SDHCI_UHS2_TEST_ERR_HEADER  BIT(0)
> > +#define  SDHCI_UHS2_TEST_ERR_RES     BIT(1)
> > +#define  SDHCI_UHS2_TEST_ERR_RETRY_EXP       BIT(2)
> > +#define  SDHCI_UHS2_TEST_ERR_CRC     BIT(3)
> > +#define  SDHCI_UHS2_TEST_ERR_FRAME   BIT(4)
> > +#define  SDHCI_UHS2_TEST_ERR_TID     BIT(5)
> > +#define  SDHCI_UHS2_TEST_ERR_UNRECOVER       BIT(7)
> > +#define  SDHCI_UHS2_TEST_ERR_EBUSY   BIT(8)
> > +#define  SDHCI_UHS2_TEST_ERR_ADMA    BIT(15)
> > +#define  SDHCI_UHS2_TEST_ERR_RES_TIMEOUT     BIT(16)
> > +#define  SDHCI_UHS2_TEST_ERR_DEADLOCK_TIMEOUT        BIT(17)
> > +#define  SDHCI_UHS2_TEST_ERR_VENDOR  BIT(27)
>
> The Test register has the same bit fields as the interrupt
> registers, so we don't really need them do we?
>

I will delete it and update it in the patch#7 of the new [PATCH V6].

> > +
> > +#define SDHCI_UHS2_EMBED_CTRL        0xE6
> > +#define SDHCI_UHS2_VENDOR    0xE8
>
> For pointer registers like above 2, let's always name them *_PTR
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> > +#endif /* __SDHCI_UHS2_H */
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> > index d750c464bd1e..bbed850241d4 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -43,8 +43,27 @@
> >  #define  SDHCI_TRNS_READ     0x10
> >  #define  SDHCI_TRNS_MULTI    0x20
> >
> > +/*
> > + * Defined in Host Version 4.10.
>
> Spec says version 4.0 not version 4.1
>

I will update it in the patch#7 of the new [PATCH V6].

> > + * 1 - R5 (SDIO)
> > + * 0 - R1 (Memory)
>
> Without reading the spec, it is not obvious what the above
> means, so please just remove it.
>

I will update it in the patch#7 of the new [PATCH V6].

> > + */
> > +#define  SDHCI_TRNS_RES_TYPE         0x40
> > +#define  SDHCI_TRNS_RES_ERR_CHECK    0x80
> > +#define  SDHCI_TRNS_RES_INT_DIS              0x0100
> > +
> >  #define SDHCI_COMMAND                0x0E
> >  #define  SDHCI_CMD_RESP_MASK 0x03
> > +
> > +/*
> > + * Host Version 4.10 adds this bit to distinguish a main command or
> > + * sub command.
> > + * CMD53(SDIO) - main command
> > + * CMD52(SDIO) - sub command which doesn't have data block or doesn't
> > + * indicate busy.
>
> This isn't very clear.  How about just this instead:
>
> For example with SDIO, CMD52 (sub command) issued during CMD53 (main command)
>

I will update it in the patch#7 of the new [PATCH V6].

> > + */
> > +#define  SDHCI_CMD_SUB_CMD   0x04
> > +
> >  #define  SDHCI_CMD_CRC               0x08
> >  #define  SDHCI_CMD_INDEX     0x10
> >  #define  SDHCI_CMD_DATA              0x20
> > @@ -60,11 +79,19 @@
> >
> >  #define SDHCI_RESPONSE               0x10
> >
> > +#define  SDHCI_RESPONSE_CM_TRAN_ABORT_OFFSET 0x10
> > +#define  SDHCI_RESPONSE_CM_TRAN_ABORT_SIZE   4
> > +#define  SDHCI_RESPONSE_SD_TRAN_ABORT_OFFSET 0x18
> > +#define  SDHCI_RESPONSE_SD_TRAN_ABORT_SIZE   8
>
> These are UHS2 registers, so I would expect them in
> sdhci-uhs2.h.  We don't put register sizes, and for
> 8-byte registers we add "_1" for the upper 4-bytes.
> i.e.
>
> #define SDHCI_UHS2_CM_TRAN_RESP         0x10
> #define SDHCI_UHS2_SD_TRAN_RESP         0x18
> #define SDHCI_UHS2_SD_TRAN_RESP_1       0x1C
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> >  #define SDHCI_BUFFER         0x20
> >
> >  #define SDHCI_PRESENT_STATE  0x24
> >  #define  SDHCI_CMD_INHIBIT   0x00000001
> >  #define  SDHCI_DATA_INHIBIT  0x00000002
> > +
> > +#define  SDHCI_DATA_HIGH_LVL_MASK    0x000000F0
>
> "HIGH" is not that clear.  Instead, what about:
>
>         SDHCI_DAT_4_TO_7_LVL_MASK
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> >  #define  SDHCI_DOING_WRITE   0x00000100
> >  #define  SDHCI_DOING_READ    0x00000200
> >  #define  SDHCI_SPACE_AVAILABLE       0x00000400
> > @@ -80,6 +107,13 @@
> >  #define   SDHCI_DATA_0_LVL_MASK      0x00100000
> >  #define  SDHCI_CMD_LVL               0x01000000
> >
>
> /* Host Version 4.10 */
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define  SDHCI_HOST_REGULATOR_STABLE 0x02000000
> > +#define  SDHCI_CMD_NOT_ISSUE_ERR     0x08000000
>
> Please change:
>         ISSUE -> ISSUED
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define  SDHCI_SUB_CMD_STATUS                0x10000000
>
> > +#define  SDHCI_UHS2_IN_DORMANT_STATE 0x20000000
> > +#define  SDHCI_UHS2_LANE_SYNC                0x40000000
> > +#define  SDHCI_UHS2_IF_DETECT                0x80000000
> > +
> >  #define SDHCI_HOST_CONTROL   0x28
> >  #define  SDHCI_CTRL_LED              0x01
> >  #define  SDHCI_CTRL_4BITBUS  0x02
> > @@ -100,6 +134,11 @@
> >  #define  SDHCI_POWER_300     0x0C
> >  #define  SDHCI_POWER_330     0x0E
> >
> > +/* VDD2 - UHS2 */
>
> Please be more explicit here:
>
> /* VDD2 power on/off and voltage select (UHS2) */
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define  SDHCI_VDD2_POWER_ON         0x10
> > +#define  SDHCI_VDD2_POWER_180                0xA0
> > +#define  SDHCI_VDD2_POWER_120                0x80
>
> Last 3 values could be lined up with further above.
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> >  #define SDHCI_BLOCK_GAP_CONTROL      0x2A
> >
> >  #define SDHCI_WAKE_UP_CONTROL        0x2B
> > @@ -110,7 +149,7 @@
> >  #define SDHCI_CLOCK_CONTROL  0x2C
> >  #define  SDHCI_DIVIDER_SHIFT 8
> >  #define  SDHCI_DIVIDER_HI_SHIFT      6
> > -#define  SDHCI_DIV_MASK      0xFF
> > +#define  SDHCI_DIV_MASK              0xFF
> >  #define  SDHCI_DIV_MASK_LEN  8
> >  #define  SDHCI_DIV_HI_MASK   0x300
> >  #define  SDHCI_PROG_CLOCK_MODE       0x0020
> > @@ -139,6 +178,10 @@
> >  #define  SDHCI_INT_CARD_REMOVE       0x00000080
> >  #define  SDHCI_INT_CARD_INT  0x00000100
> >  #define  SDHCI_INT_RETUNE    0x00001000
> > +
> > +/* Host Version 4.10 */
> > +#define  SDHCI_INT_FX_EVENT  0x00002000
> > +
> >  #define  SDHCI_INT_CQE               0x00004000
> >  #define  SDHCI_INT_ERROR     0x00008000
> >  #define  SDHCI_INT_TIMEOUT   0x00010000
> > @@ -152,6 +195,9 @@
> >  #define  SDHCI_INT_AUTO_CMD_ERR      0x01000000
> >  #define  SDHCI_INT_ADMA_ERROR        0x02000000
> >
> > +/* Host Version 4.0 */
> > +#define  SDHCI_INT_RESPONSE_ERROR    0x08000000
>
> Could be shorter:
>
> SDHCI_INT_RESPONSE_ERROR -> SDHCI_INT_RESP_ERR
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> >  #define  SDHCI_INT_NORMAL_MASK       0x00007FFF
> >  #define  SDHCI_INT_ERROR_MASK        0xFFFF8000
> >
> > @@ -178,6 +224,9 @@
> >  #define  SDHCI_AUTO_CMD_END_BIT      0x00000008
> >  #define  SDHCI_AUTO_CMD_INDEX        0x00000010
> >
> > +/* Host Version 4.10 */
> > +#define  SDHCI_ACMD_RESPONSE_ERROR   0x0020
>
> Could be shorter:
>
> SDHCI_ACMD_RESPONSE_ERROR -> SDHCI_AUTO_CMD_RESP_ERR
>

I will update it in the patch#7 of the new [PATCH V6].

> > +
> >  #define SDHCI_HOST_CONTROL2          0x3E
> >  #define  SDHCI_CTRL_UHS_MASK         0x0007
> >  #define   SDHCI_CTRL_UHS_SDR12               0x0000
> > @@ -186,6 +235,7 @@
> >  #define   SDHCI_CTRL_UHS_SDR104              0x0003
> >  #define   SDHCI_CTRL_UHS_DDR50               0x0004
> >  #define   SDHCI_CTRL_HS400           0x0005 /* Non-standard */
> > +#define   SDHCI_CTRL_UHS_2           0x0007 /* UHS-2 */
>
> We are using UHS2 in other places, so do it here too:
>
> SDHCI_CTRL_UHS_2 -> SDHCI_CTRL_UHS2
>
> Also the comment /* UHS-2 */ is not needed
>

I will update it in the patch#7 of the new [PATCH V6].

> >  #define  SDHCI_CTRL_VDD_180          0x0008
> >  #define  SDHCI_CTRL_DRV_TYPE_MASK    0x0030
> >  #define   SDHCI_CTRL_DRV_TYPE_B              0x0000
> > @@ -194,9 +244,12 @@
> >  #define   SDHCI_CTRL_DRV_TYPE_D              0x0030
> >  #define  SDHCI_CTRL_EXEC_TUNING              0x0040
> >  #define  SDHCI_CTRL_TUNED_CLK                0x0080
> > +#define  SDHCI_CTRL_UHS2_INTERFACE_EN        0x0100 /* UHS-2 */
>
> Already have "SDHCI_CTRL_PRESET_VAL_ENABLE" so let's
> spell out ENABLE here too.
>
> SDHCI_CTRL_UHS2_INTERFACE_EN -> SDHCI_CTRL_UHS2_ENABLE
>
> Also the comment /* UHS-2 */ is not needed
>
> > +#define  SDHCI_CTRL_ADMA2_LEN_MODE   0x0400
> >  #define  SDHCI_CMD23_ENABLE          0x0800
> >  #define  SDHCI_CTRL_V4_MODE          0x1000
> >  #define  SDHCI_CTRL_64BIT_ADDR               0x2000
> > +#define  SDHCI_CTRL_ASYNC_INT_EN     0x4000
>
> Ditto
>
> SDHCI_CTRL_ASYNC_INT_EN -> SDHCI_CTRL_ASYNC_INT_ENABLE
>

I will update it in the patch#7 of the new [PATCH V6].

> >  #define  SDHCI_CTRL_PRESET_VAL_ENABLE        0x8000
> >
> >  #define SDHCI_CAPABILITIES   0x40
> > @@ -219,11 +272,13 @@
> >  #define  SDHCI_CAN_VDD_180   0x04000000
> >  #define  SDHCI_CAN_64BIT_V4  0x08000000
> >  #define  SDHCI_CAN_64BIT     0x10000000
> > +#define  SDHCI_CAN_ASYNC_INT 0x20000000
> >
> >  #define SDHCI_CAPABILITIES_1 0x44
> >  #define  SDHCI_SUPPORT_SDR50 0x00000001
> >  #define  SDHCI_SUPPORT_SDR104        0x00000002
> >  #define  SDHCI_SUPPORT_DDR50 0x00000004
> > +#define  SDHCI_SUPPORT_UHS2  0x00000008 /* UHS-2 support */
>
> Please remove the comment - the name says it all.
>

I will update it in the patch#7 of the new [PATCH V6].

> >  #define  SDHCI_DRIVER_TYPE_A 0x00000010
> >  #define  SDHCI_DRIVER_TYPE_C 0x00000020
> >  #define  SDHCI_DRIVER_TYPE_D 0x00000040
> > @@ -232,19 +287,28 @@
> >  #define  SDHCI_RETUNING_MODE_MASK            GENMASK(15, 14)
> >  #define  SDHCI_CLOCK_MUL_MASK                        GENMASK(23, 16)
> >  #define  SDHCI_CAN_DO_ADMA3  0x08000000
> > +#define  SDHCI_SUPPORT_VDD2_180      0x10000000 /* UHS-2 1.8V VDD2 */
>
> Better to be like VDD bit names i.e.
>
> SDHCI_SUPPORT_VDD2_180 -> SDHCI_CAN_VDD2_180
>
> > +#define  SDHCI_RSVD_FOR_VDD2    0x20000000 /* Rsvd for future VDD2 */
>
> Please drop SDHCI_RSVD_FOR_VDD2
>

I will update it in the patch#7 of the new [PATCH V6].

> >  #define  SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
> >
> >  #define SDHCI_MAX_CURRENT            0x48
> > +#define SDHCI_MAX_CURRENT_1          0x4C
>
> Let's put SDHCI_MAX_CURRENT_1 just above
> SDHCI_MAX_CURRENT_VDD2_180_MASK
>

I will update it in the patch#7 of the new [PATCH V6].

> >  #define  SDHCI_MAX_CURRENT_LIMIT     GENMASK(7, 0)
> >  #define  SDHCI_MAX_CURRENT_330_MASK  GENMASK(7, 0)
> >  #define  SDHCI_MAX_CURRENT_300_MASK  GENMASK(15, 8)
> >  #define  SDHCI_MAX_CURRENT_180_MASK  GENMASK(23, 16)
> > +#define  SDHCI_MAX_CURRENT_VDD2_180_MASK     GENMASK(7, 0) /* UHS2 */
> >  #define   SDHCI_MAX_CURRENT_MULTIPLIER       4
> >
> >  /* 4C-4F reserved for more max current */
> >
> >  #define SDHCI_SET_ACMD12_ERROR       0x50
> > +/* Host Version 4.10 */
> > +#define SDHCI_SET_ACMD_RESPONSE_ERROR        0x20
>
> This isn't being used is it?  Then let's leave it out.
>

I will update it in the patch#7 of the new [PATCH V6].

> >  #define SDHCI_SET_INT_ERROR  0x52
> > +/* Host Version 4.10 */
> > +#define SDHCI_SET_INT_TUNING_ERROR   0x0400
> > +#define SDHCI_SET_INT_RESPONSE_ERROR 0x0800
>
> These aren't being used are they?  Then let's leave them out.
>

I will update it in the patch#7 of the new [PATCH V6].

> >
> >  #define SDHCI_ADMA_ERROR     0x54
> >
> > @@ -262,10 +326,16 @@
> >  #define SDHCI_PRESET_FOR_SDR104        0x6C
> >  #define SDHCI_PRESET_FOR_DDR50 0x6E
> >  #define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
> > +
> > +/* TODO: 0x74 is used for UHS2 in 4.10. How about HS400? */
> > +/* UHS2 */
>
> A host controller cannot be using it for both at the same time.
> The drivers should be able to sort it out if needed. For now,
> just remove your comments.
>

I will update it in the patch#7 of the new [PATCH V6].

> > +#define SDHCI_PRESET_FOR_UHS2  0x74
> >  #define SDHCI_PRESET_DRV_MASK                GENMASK(15, 14)
> >  #define SDHCI_PRESET_CLKGEN_SEL              BIT(10)
> >  #define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0)
> >
> > +#define SDHCI_ADMA3_ADDRESS  0x78
> > +
> >  #define SDHCI_SLOT_INT_STATUS        0xFC
> >
> >  #define SDHCI_HOST_VERSION   0xFE
> > @@ -659,6 +729,7 @@ struct sdhci_ops {
> >       void    (*request_done)(struct sdhci_host *host,
> >                               struct mmc_request *mrq);
> >       void    (*dump_vendor_regs)(struct sdhci_host *host);
> > +     void    (*dump_uhs2_regs)(struct sdhci_host *host);
>
> Please move this to patch "mmc: sdhci-uhs2: dump UHS-II registers"
>

I will update it in the patch#7 of the new [PATCH V6].

> >  };
> >
> >  #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 09/26] mmc: sdhci: add UHS-II module
  2022-11-01 17:12   ` Adrian Hunter
@ 2022-12-13  8:45     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:45 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:12 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > From: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >
> > This patch adds sdhci-uhs2.c as a module for UHS-II support.
> > This is a skelton for further development in this patch series.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > ---
> >  drivers/mmc/host/Makefile     |  1 +
> >  drivers/mmc/host/sdhci-uhs2.c | 46 +++++++++++++++++++++++++++++++++++
> >  2 files changed, 47 insertions(+)
> >  create mode 100644 drivers/mmc/host/sdhci-uhs2.c
> >
> > diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> > index 4e4ceb32c4b4..c4ae7c6d9c04 100644
> > --- a/drivers/mmc/host/Makefile
> > +++ b/drivers/mmc/host/Makefile
> > @@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_PXA)               += pxamci.o
> >  obj-$(CONFIG_MMC_MXC)                += mxcmmc.o
> >  obj-$(CONFIG_MMC_MXS)                += mxs-mmc.o
> >  obj-$(CONFIG_MMC_SDHCI)              += sdhci.o
> > +obj-$(CONFIG_MMC_SDHCI_UHS2) += sdhci-uhs2.o
> >  obj-$(CONFIG_MMC_SDHCI_PCI)  += sdhci-pci.o
> >  sdhci-pci-y                  += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
> >                                  sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > new file mode 100644
> > index 000000000000..f29d3a4ed43c
> > --- /dev/null
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -0,0 +1,46 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + *  linux/drivers/mmc/host/sdhci_uhs2.c - Secure Digital Host Controller
> > + *  Interface driver
> > + *
> > + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> > + *  Copyright (C) 2020 Genesys Logic, Inc.
> > + *  Authors: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > + *  Copyright (C) 2020 Linaro Limited
> > + *  Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > + */
> > +
> > +#include <linux/module.h>
> > +
> > +#include "sdhci.h"
> > +#include "sdhci-uhs2.h"
> > +
> > +#define DRIVER_NAME "sdhci_uhs2"
> > +#define DBG(f, x...) \
> > +     pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
> > +
> > +/*****************************************************************************\
> > + *                                                                           *
> > + * Driver init/exit                                                          *
> > + *                                                                           *
> > +\*****************************************************************************/
> > +
> > +static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
> > +{
> > +     return 0;
> > +}
> > +
> > +static int __init sdhci_uhs2_mod_init(void)
> > +{
> > +     return 0;
> > +}
> > +module_init(sdhci_uhs2_mod_init);
> > +
> > +static void __exit sdhci_uhs2_exit(void)
>
> It would be better to match the form of the init name
> e.g. sdhci_uhs2_mod_exit
>

I will update it in the patch#8 of the new [PATCH V6].

> > +{
> > +}
> > +module_exit(sdhci_uhs2_exit);
> > +
> > +MODULE_AUTHOR("Intel, Genesys Logic, Linaro");
> > +MODULE_DESCRIPTION("MMC UHS-II Support");
> > +MODULE_LICENSE("GPL v2");
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 10/26] mmc: sdhci-uhs2: dump UHS-II registers
  2022-11-01 17:13   ` Adrian Hunter
@ 2022-12-13  8:45     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:45 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:13 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > From: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >
> > Dump UHS-II specific registers, if available, in sdhci_dumpregs()
> > for informative/debugging use.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 30 ++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci-uhs2.h |  4 ++++
> >  drivers/mmc/host/sdhci.c      |  3 +++
> >  3 files changed, 37 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index f29d3a4ed43c..08905ed081fb 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -18,6 +18,36 @@
> >  #define DRIVER_NAME "sdhci_uhs2"
> >  #define DBG(f, x...) \
> >       pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
> > +#define SDHCI_UHS2_DUMP(f, x...) \
> > +     pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
> > +
> > +void sdhci_uhs2_dump_regs(struct sdhci_host *host)
> > +{
> > +     if (!host->mmc || !(host->mmc->flags & MMC_UHS2_SUPPORT))
>
> !host->mmc is not possible
>

I will update it in the patch#9 of the new [PATCH V6].

> > +             return;
> > +
> > +     SDHCI_UHS2_DUMP("==================== UHS2 ==================\n");
> > +     SDHCI_UHS2_DUMP("Blk Size:  0x%08x | Blk Cnt:  0x%08x\n",
> > +                     sdhci_readw(host, SDHCI_UHS2_BLOCK_SIZE),
> > +                     sdhci_readl(host, SDHCI_UHS2_BLOCK_COUNT));
> > +     SDHCI_UHS2_DUMP("Cmd:       0x%08x | Trn mode: 0x%08x\n",
> > +                     sdhci_readw(host, SDHCI_UHS2_COMMAND),
> > +                     sdhci_readw(host, SDHCI_UHS2_TRANS_MODE));
> > +     SDHCI_UHS2_DUMP("Int Stat:  0x%08x | Dev Sel : 0x%08x\n",
> > +                     sdhci_readw(host, SDHCI_UHS2_DEV_INT_STATUS),
> > +                     sdhci_readb(host, SDHCI_UHS2_DEV_SELECT));
> > +     SDHCI_UHS2_DUMP("Dev Int Code:  0x%08x\n",
> > +                     sdhci_readb(host, SDHCI_UHS2_DEV_INT_CODE));
> > +     SDHCI_UHS2_DUMP("Reset:     0x%08x | Timer:    0x%08x\n",
> > +                     sdhci_readw(host, SDHCI_UHS2_SW_RESET),
> > +                     sdhci_readw(host, SDHCI_UHS2_TIMER_CTRL));
> > +     SDHCI_UHS2_DUMP("ErrInt:    0x%08x | ErrIntEn: 0x%08x\n",
> > +                     sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS),
> > +                     sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN));
> > +     SDHCI_UHS2_DUMP("ErrSigEn:  0x%08x\n",
> > +                     sdhci_readl(host, SDHCI_UHS2_ERR_INT_SIG_EN));
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
> >
> >  /*****************************************************************************\
> >   *                                                                           *
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > index 5610affebdf3..afdb05d6056b 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.h
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -207,4 +207,8 @@
> >  #define SDHCI_UHS2_EMBED_CTRL        0xE6
> >  #define SDHCI_UHS2_VENDOR    0xE8
> >
> > +struct sdhci_host;
> > +
> > +void sdhci_uhs2_dump_regs(struct sdhci_host *host);
> > +
> >  #endif /* __SDHCI_UHS2_H */
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index fef03de85b99..2cdd183c8ada 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -110,6 +110,9 @@ void sdhci_dumpregs(struct sdhci_host *host)
> >               }
> >       }
> >
> > +     if (host->ops->dump_uhs2_regs)
> > +             host->ops->dump_uhs2_regs(host);
> > +
> >       if (host->ops->dump_vendor_regs)
> >               host->ops->dump_vendor_regs(host);
> >
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 11/26] mmc: sdhci-uhs2: add reset function and uhs2_mode function
  2022-11-01 17:13   ` Adrian Hunter
@ 2022-12-13  8:45     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:45 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:13 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > Sdhci_uhs2_reset() does a UHS-II specific reset operation.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >  drivers/mmc/host/sdhci-pci-core.c |  1 +
> >  drivers/mmc/host/sdhci-pci-gli.c  |  1 +
> >  drivers/mmc/host/sdhci-uhs2.c     | 68 +++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci-uhs2.h     |  3 ++
> >  drivers/mmc/host/sdhci.c          |  3 +-
> >  drivers/mmc/host/sdhci.h          | 14 +++++++
> >  6 files changed, 89 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
> > index 34ea1acbb3cc..cba5bba994b8 100644
> > --- a/drivers/mmc/host/sdhci-pci-core.c
> > +++ b/drivers/mmc/host/sdhci-pci-core.c
> > @@ -1955,6 +1955,7 @@ static const struct sdhci_ops sdhci_pci_ops = {
> >       .reset          = sdhci_reset,
> >       .set_uhs_signaling = sdhci_set_uhs_signaling,
> >       .hw_reset               = sdhci_pci_hw_reset,
> > +     .uhs2_reset             = sdhci_uhs2_reset,
>
> AFAICT this isn't needed
>

I will update it in the patch#10 of the new [PATCH V6].

> >  };
> >
> >  /*****************************************************************************\
> > diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
> > index 4d509f656188..607cf69f45d0 100644
> > --- a/drivers/mmc/host/sdhci-pci-gli.c
> > +++ b/drivers/mmc/host/sdhci-pci-gli.c
> > @@ -1097,6 +1097,7 @@ static const struct sdhci_ops sdhci_gl9755_ops = {
> >       .reset                  = sdhci_reset,
> >       .set_uhs_signaling      = sdhci_set_uhs_signaling,
> >       .voltage_switch         = sdhci_gli_voltage_switch,
> > +     .uhs2_reset             = sdhci_uhs2_reset,
> >  };
> >
> >  const struct sdhci_pci_fixes sdhci_gl9755 = {
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 08905ed081fb..0e82f98d1967 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -10,6 +10,7 @@
> >   *  Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >   */
> >
> > +#include <linux/delay.h>
> >  #include <linux/module.h>
> >
> >  #include "sdhci.h"
> > @@ -49,6 +50,73 @@ void sdhci_uhs2_dump_regs(struct sdhci_host *host)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
> >
> > +/*****************************************************************************\
> > + *                                                                           *
> > + * Low level functions                                                       *
> > + *                                                                           *
> > +\*****************************************************************************/
> > +
> > +bool sdhci_uhs2_mode(struct sdhci_host *host)
> > +{
> > +     if ((host->mmc->caps2 & MMC_CAP2_SD_UHS2) &&
> > +         (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +             (host->version >= SDHCI_SPEC_400) &&
> > +             (host->mmc->flags & MMC_UHS2_SUPPORT)))
> > +             return true;
> > +     else
> > +             return false;
>
> For now, let's just make this:
>
>         return host->mmc->flags & MMC_UHS2_SUPPORT;
>

I will update it in the patch#10 of the new [PATCH V6].

> > +}
> > +
> > +/**
> > + * sdhci_uhs2_reset - invoke SW reset
> > + * @host: SDHCI host
> > + * @mask: Control mask
> > + *
> > + * Invoke SW reset, depending on a bit in @mask and wait for completion.
> > + */
> > +void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
> > +{
> > +     unsigned long timeout;
> > +     u32 val;
> > +
> > +     if (!(sdhci_uhs2_mode(host))) {
>
> That isn't possible.
>

I will update it in the patch#10 of the new [PATCH V6].

> > +             /**
> > +              * u8  mask for legacy.
> > +              * u16 mask for uhs-2.
> > +              */
> > +             u8 u8_mask;
> > +
> > +             u8_mask = (mask & 0xFF);
> > +             sdhci_reset(host, u8_mask);
>
> Probably should call host->ops->reset() but !sdhci_uhs2_mode(host)
> isn't possible
>

I will update it in the patch#10 of the new [PATCH V6].

> > +
> > +             return;
> > +     }
> > +
> > +     sdhci_writew(host, mask, SDHCI_UHS2_SW_RESET);
> > +
> > +     if (mask & SDHCI_UHS2_SW_RESET_FULL) {
> > +             host->clock = 0;
> > +             /* Reset-all turns off SD Bus Power */
> > +             if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
> > +                     sdhci_runtime_pm_bus_off(host);
>
> We don't know what other drivers will opt for UHS-II
> support, but I doubt this quirk will be used, so  let's
> not support SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON for UHS-II
>

I will update it in the patch#10 of the new [PATCH V6].

> > +     }
> > +
> > +     /* Wait max 100 ms */
> > +     timeout = 10000;
>
> Isn't that 10ms
>

I will update it in the patch#10 of the new [PATCH V6].

> > +
> > +     /* hw clears the bit when it's done */
> > +     if (read_poll_timeout_atomic(sdhci_readw, val, !(val & mask), 10,
> > +                                  timeout, true, host, SDHCI_UHS2_SW_RESET)) {
> > +             pr_err("%s: %s: Reset 0x%x never completed.\n",
> > +                                            __func__, mmc_hostname(host->mmc), (int)mask);
> > +             pr_err("%s: clean reset bit\n",
> > +                                            mmc_hostname(host->mmc));
> > +             sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET);
> > +             return;
> > +     }
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
> > +
> >  /*****************************************************************************\
> >   *                                                                           *
> >   * Driver init/exit                                                          *
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > index afdb05d6056b..31776dcca5cf 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.h
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -11,6 +11,7 @@
> >  #define __SDHCI_UHS2_H
> >
> >  #include <linux/bits.h>
> > +#include <linux/iopoll.h>
>
> Not needed in header.  Can just be in .c
>

I will update it in the patch#10 of the new [PATCH V6].

> >
> >  /*
> >   * UHS-II Controller registers
> > @@ -210,5 +211,7 @@
> >  struct sdhci_host;
> >
> >  void sdhci_uhs2_dump_regs(struct sdhci_host *host);
> > +bool sdhci_uhs2_mode(struct sdhci_host *host);
> > +void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
> >
> >  #endif /* __SDHCI_UHS2_H */
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index 2cdd183c8ada..bd017c59a020 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -194,13 +194,14 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
> >       pm_runtime_get_noresume(mmc_dev(host->mmc));
> >  }
> >
> > -static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
> > +void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
> >  {
> >       if (!host->bus_on)
> >               return;
> >       host->bus_on = false;
> >       pm_runtime_put_noidle(mmc_dev(host->mmc));
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_runtime_pm_bus_off);
>
> Let's not support SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON for UHS-II
>

I will update it in the patch#10 of the new [PATCH V6].

> >
> >  void sdhci_reset(struct sdhci_host *host, u8 mask)
> >  {
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> > index bbed850241d4..28716105da61 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -715,6 +715,19 @@ struct sdhci_ops {
> >                                            u8 power_mode);
> >       unsigned int    (*get_ro)(struct sdhci_host *host);
> >       void            (*reset)(struct sdhci_host *host, u8 mask);
> > +     /**
> > +      * The sdhci_uhs2_reset callback is to implement for reset
> > +      * @host: SDHCI host
> > +      * @mask: Control mask
> > +      *
> > +      * Invoke reset, depending on a bit in @mask and wait for completion.
> > +      * SD mode                              UHS-II mode
> > +      * SDHCI_RESET_ALL              SDHCI_UHS2_SW_RESET_FULL
> > +      * SDHCI_RESET_CMD              SDHCI_RESET_CMD
> > +      * SDHCI_RESET_DATA             SDHCI_UHS2_SW_RESET_SD
> > +      *
> > +      **/
> > +     void (*uhs2_reset)(struct sdhci_host *host, u16 mask);
>
> This is only being called from sdhci_uhs2.c so let's just call it
> directly for now, instead of using a callback.
>

I will update it in the patch#10 of the new [PATCH V6].

> >       int     (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
> >       void    (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
> >       void    (*hw_reset)(struct sdhci_host *host);
> > @@ -837,6 +850,7 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
> >       __sdhci_read_caps(host, NULL, NULL, NULL);
> >  }
> >
> > +void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
>
> Let's not support SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON for UHS-II
>

I will update it in the patch#10 of the new [PATCH V6].

> >  u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
> >                  unsigned int *actual_clock);
> >  void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 12/26] mmc: sdhci-uhs2: add set_power() to support vdd2
  2022-11-01 17:13   ` Adrian Hunter
@ 2022-12-13  8:46     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:46 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:13 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > This is a UHS-II version of sdhci's set_power operation.
> > VDD2, as well as VDD, is handled here.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 79 +++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci-uhs2.h |  2 +
> >  drivers/mmc/host/sdhci.c      | 66 ++++++++++++++++-------------
> >  drivers/mmc/host/sdhci.h      |  2 +
> >  4 files changed, 120 insertions(+), 29 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 0e82f98d1967..896a1c8e55cf 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -117,6 +117,85 @@ void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
> >
> > +void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
> > +                       unsigned short vdd)
> > +{
> > +     struct mmc_host *mmc = host->mmc;
> > +     u8 pwr;
> > +
> > +     /* FIXME: check if flags & MMC_UHS2_SUPPORT? */
> > +     if (!(sdhci_uhs2_mode(host))) {
> > +             sdhci_set_power(host, mode, vdd);
> > +             return;
> > +     }
>
> sdhci_uhs2_set_power() is called via ->uhs2_set_ios().  That should
> not be called if not in UHS2 mode, so no check should be needed here.
>
>

I will update it in the patch#11 of the new [PATCH V6].

> > +
> > +     if (mode != MMC_POWER_OFF) {
> > +             pwr = sdhci_get_vdd_value(vdd);
> > +             if (!pwr)
> > +                     WARN(1, "%s: Invalid vdd %#x\n",
> > +                          mmc_hostname(host->mmc), vdd);
> > +             pwr |= SDHCI_VDD2_POWER_180;
> > +     }
> > +
> > +     if (host->pwr == pwr)
> > +             return;
> > +     host->pwr = pwr;
> > +
> > +     if (pwr == 0) {
> > +             sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
> > +
> > +             if (!IS_ERR(host->mmc->supply.vmmc))
> > +                     mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
>
> Seems to be a common if-clause.  Looks like we could use a
> helper like:
>
> static inline int mmc_opt_regulator_set_ocr(struct mmc_host *mmc,
>                                             struct regulator *supply,
>                                             unsigned short vdd_bit)
> {
>         return IS_ERR_OR_NULL(supply) ? 0 : mmc_regulator_set_ocr(mmc, supply, vdd_bit);
> }
>
>

I will update it in the patch#11 of the new [PATCH V6].

> > +             if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
> > +                     mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
> > +
> > +             if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
> > +                     sdhci_runtime_pm_bus_off(host);
>
> Let's not support quirks that you don't need like
> SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON
>

I will update it in the patch#11 of the new [PATCH V6].

> > +     } else {
> > +             if (!IS_ERR(host->mmc->supply.vmmc))
> > +                     mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
> > +             if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
> > +                     /* support 1.8v only for now */
> > +                     mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2,
> > +                                           fls(MMC_VDD2_165_195) - 1);
> > +
> > +             /*
> > +              * Spec says that we should clear the power reg before setting
> > +              * a new value. Some controllers don't seem to like this though.
> > +              */
> > +             if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
>
> Let's not support quirks that you don't need like
> SDHCI_QUIRK_SINGLE_POWER_WRITE
> note this one is !
>

I will update it in the patch#11 of the new [PATCH V6].

> > +                     sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
> > +
> > +             /*
> > +              * At least the Marvell CaFe chip gets confused if we set the
> > +              * voltage and set turn on power at the same time, so set the
> > +              * voltage first.
> > +              */
> > +             if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
> > +                     sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
>
> Let's not support quirks that you don't need like
> SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER
>

I will update it in the patch#11 of the new [PATCH V6].

> > +
> > +             /* vdd first */
> > +             pwr |= SDHCI_POWER_ON;
> > +             sdhci_writeb(host, pwr & 0xf, SDHCI_POWER_CONTROL);
> > +             mdelay(5);
> > +
> > +             pwr |= SDHCI_VDD2_POWER_ON;
> > +             sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
> > +             mdelay(5);
> > +
> > +             if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
> > +                     sdhci_runtime_pm_bus_on(host);
>
> Let's not support quirks that you don't need like
> SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON
>

I will update it in the patch#11 of the new [PATCH V6].

> > +
> > +             /*
> > +              * Some controllers need an extra 10ms delay of 10ms before
> > +              * they can apply clock after applying power
> > +              */
> > +             if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
> > +                     mdelay(10);
>
> Let's not support quirks that you don't need like
> SDHCI_QUIRK_DELAY_AFTER_POWER
>

I will update it in the patch#11 of the new [PATCH V6].

> > +     }
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
>
> It is only used in this file, so let's not export it.
>
> > +
> >  /*****************************************************************************\
> >   *                                                                           *
> >   * Driver init/exit                                                          *
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > index 31776dcca5cf..3179915f7f79 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.h
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -213,5 +213,7 @@ struct sdhci_host;
> >  void sdhci_uhs2_dump_regs(struct sdhci_host *host);
> >  bool sdhci_uhs2_mode(struct sdhci_host *host);
> >  void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
> > +void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
> > +                       unsigned short vdd);
>
> Let's not export it for now.
>

I will update it in the patch#11 of the new [PATCH V6].

> >
> >  #endif /* __SDHCI_UHS2_H */
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index bd017c59a020..dfa0939a9058 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -23,7 +23,7 @@
> >  #include <linux/regulator/consumer.h>
> >  #include <linux/pm_runtime.h>
> >  #include <linux/of.h>
> > -
> > +#include <linux/bug.h>
> >  #include <linux/leds.h>
> >
> >  #include <linux/mmc/mmc.h>
> > @@ -186,13 +186,14 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
> >       sdhci_set_card_detection(host, false);
> >  }
> >
> > -static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
> > +void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
> >  {
> >       if (host->bus_on)
> >               return;
> >       host->bus_on = true;
> >       pm_runtime_get_noresume(mmc_dev(host->mmc));
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_runtime_pm_bus_on);
> >
> >  void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
> >  {
> > @@ -2071,41 +2072,48 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
> >               sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
> >  }
> >
> > +unsigned short sdhci_get_vdd_value(unsigned short vdd)
> > +{
> > +     u8 pwr;
> > +
> > +     switch (1 << vdd) {
> > +     case MMC_VDD_165_195:
> > +     /*
> > +      * Without a regulator, SDHCI does not support 2.0v
> > +      * so we only get here if the driver deliberately
> > +      * added the 2.0v range to ocr_avail. Map it to 1.8v
> > +      * for the purpose of turning on the power.
> > +      */
> > +     case MMC_VDD_20_21:
> > +             pwr = SDHCI_POWER_180;
> > +             break;
> > +     case MMC_VDD_29_30:
> > +     case MMC_VDD_30_31:
> > +             pwr = SDHCI_POWER_300;
> > +             break;
> > +     case MMC_VDD_32_33:
> > +     case MMC_VDD_33_34:
> > +             pwr = SDHCI_POWER_330;
> > +             break;
> > +     default:
> > +             pwr = 0;
> > +             break;
> > +     }
> > +
> > +     return pwr;
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_get_vdd_value);
> > +
> >  void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
> >                          unsigned short vdd)
> >  {
> >       u8 pwr = 0;
> >
> >       if (mode != MMC_POWER_OFF) {
> > -             switch (1 << vdd) {
> > -             case MMC_VDD_165_195:
> > -             /*
> > -              * Without a regulator, SDHCI does not support 2.0v
> > -              * so we only get here if the driver deliberately
> > -              * added the 2.0v range to ocr_avail. Map it to 1.8v
> > -              * for the purpose of turning on the power.
> > -              */
> > -             case MMC_VDD_20_21:
> > -                     pwr = SDHCI_POWER_180;
> > -                     break;
> > -             case MMC_VDD_29_30:
> > -             case MMC_VDD_30_31:
> > -                     pwr = SDHCI_POWER_300;
> > -                     break;
> > -             case MMC_VDD_32_33:
> > -             case MMC_VDD_33_34:
> > -             /*
> > -              * 3.4 ~ 3.6V are valid only for those platforms where it's
> > -              * known that the voltage range is supported by hardware.
> > -              */
> > -             case MMC_VDD_34_35:
> > -             case MMC_VDD_35_36:
> > -                     pwr = SDHCI_POWER_330;
> > -                     break;
> > -             default:
> > +             pwr = sdhci_get_vdd_value(vdd);
> > +             if (!pwr) {
> >                       WARN(1, "%s: Invalid vdd %#x\n",
> >                            mmc_hostname(host->mmc), vdd);
> > -                     break;
> >               }
> >       }
> >
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> > index 28716105da61..c34ca6ffbff6 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -850,6 +850,7 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
> >       __sdhci_read_caps(host, NULL, NULL, NULL);
> >  }
> >
> > +void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
> >  void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
> >  u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
> >                  unsigned int *actual_clock);
> > @@ -860,6 +861,7 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
> >  void sdhci_set_power_and_bus_voltage(struct sdhci_host *host,
> >                                    unsigned char mode,
> >                                    unsigned short vdd);
> > +unsigned short sdhci_get_vdd_value(unsigned short vdd);
> >  void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
> >                          unsigned short vdd);
> >  int sdhci_get_cd_nogpio(struct mmc_host *mmc);
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 14/26] mmc: sdhci-uhs2: add set_timeout()
  2022-11-01 17:14   ` Adrian Hunter
@ 2022-12-13  8:46     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:46 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:14 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > From: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >
> > This is a UHS-II version of sdhci's set_timeout() operation.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 85 +++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci-uhs2.h |  1 +
> >  2 files changed, 86 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 4dc3e904d7d2..2b90e5308764 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -196,6 +196,91 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
> >
> > +static u8 sdhci_calc_timeout_uhs2(struct sdhci_host *host, u8 *cmd_res,
> > +                               u8 *dead_lock)
> > +{
> > +     u8 count;
> > +     unsigned int cmd_res_timeout, dead_lock_timeout, current_timeout;
> > +
> > +     /*
> > +      * If the host controller provides us with an incorrect timeout
> > +      * value, just skip the check and use 0xE.  The hardware may take
> > +      * longer to time out, but that's much better than having a too-short
> > +      * timeout value.
> > +      */
> > +     if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) {
> > +             *cmd_res = 0xE;
> > +             *dead_lock = 0xE;
> > +             return 0xE;
> > +     }
>
> Let's skip quirks you don't need for now.
>

I will update it in the patch#13 of the new [PATCH V6].

> > +
> > +     /* timeout in us */
> > +     cmd_res_timeout = 5 * 1000;
> > +     dead_lock_timeout = 1 * 1000 * 1000;
> > +
> > +     /*
> > +      * Figure out needed cycles.
> > +      * We do this in steps in order to fit inside a 32 bit int.
> > +      * The first step is the minimum timeout, which will have a
> > +      * minimum resolution of 6 bits:
> > +      * (1) 2^13*1000 > 2^22,
> > +      * (2) host->timeout_clk < 2^16
> > +      *     =>
> > +      *     (1) / (2) > 2^6
> > +      */
> > +     count = 0;
> > +     current_timeout = (1 << 13) * 1000 / host->timeout_clk;
> > +     while (current_timeout < cmd_res_timeout) {
> > +             count++;
> > +             current_timeout <<= 1;
> > +             if (count >= 0xF)
> > +                     break;
> > +     }
> > +
> > +     if (count >= 0xF) {
> > +             DBG("%s: Too large timeout 0x%x requested for CMD_RES!\n",
> > +                 mmc_hostname(host->mmc), count);
> > +             count = 0xE;
> > +     }
> > +     *cmd_res = count;
> > +
> > +     count = 0;
> > +     current_timeout = (1 << 13) * 1000 / host->timeout_clk;
> > +     while (current_timeout < dead_lock_timeout) {
> > +             count++;
> > +             current_timeout <<= 1;
> > +             if (count >= 0xF)
> > +                     break;
> > +     }
> > +
> > +     if (count >= 0xF) {
> > +             DBG("%s: Too large timeout 0x%x requested for DEADLOCK!\n",
> > +                 mmc_hostname(host->mmc), count);
> > +             count = 0xE;
> > +     }
> > +     *dead_lock = count;
> > +
> > +     return count;
> > +}
> > +
> > +static void __sdhci_uhs2_set_timeout(struct sdhci_host *host)
> > +{
> > +     u8 cmd_res, dead_lock;
> > +
> > +     sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
> > +     cmd_res |= dead_lock << SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT;
>
> GENMASK() and FIELD_PREP() please
>
> > +     sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
> > +}
> > +
> > +void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
> > +{
> > +     __sdhci_set_timeout(host, cmd);
> > +
> > +     if (host->mmc->flags & MMC_UHS2_SUPPORT)
>
>         if (sdhci_uhs2_mode(host))
>

I will update it in the patch#13 of the new [PATCH V6].

> > +             __sdhci_uhs2_set_timeout(host);
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
> > +
> >  /*****************************************************************************\
> >   *                                                                           *
> >   * MMC callbacks                                                             *
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > index 3179915f7f79..5ea235b14108 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.h
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -215,5 +215,6 @@ bool sdhci_uhs2_mode(struct sdhci_host *host);
> >  void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
> >  void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
> >                         unsigned short vdd);
> > +void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
> >
> >  #endif /* __SDHCI_UHS2_H */
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 15/26] mmc: sdhci-uhs2: add set_ios()
  2022-11-01 17:14   ` Adrian Hunter
@ 2022-12-13  8:46     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:46 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:15 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > This is a sdhci version of mmc's set_ios operation.
> > It covers both UHS-I and UHS-II.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 102 ++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci-uhs2.h |   1 +
> >  drivers/mmc/host/sdhci.c      |  40 ++++++++-----
> >  drivers/mmc/host/sdhci.h      |   2 +
> >  4 files changed, 130 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 2b90e5308764..b535a47dc55a 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -281,6 +281,74 @@ void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
> >
> > +/**
> > + * sdhci_uhs2_clear_set_irqs - set Error Interrupt Status Enable register
> > + * @host:    SDHCI host
> > + * @clear:   bit-wise clear mask
> > + * @set:     bit-wise set mask
> > + *
> > + * Set/unset bits in UHS-II Error Interrupt Status Enable register
> > + */
> > +void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
> > +{
> > +     u32 ier;
> > +
> > +     ier = sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN);
> > +     ier &= ~clear;
> > +     ier |= set;
> > +     sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_STATUS_EN);
> > +     sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_SIG_EN);
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_clear_set_irqs);
> > +
> > +static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> > +{
> > +     struct sdhci_host *host = mmc_priv(mmc);
> > +     u8 cmd_res, dead_lock;
> > +     u16 ctrl_2;
> > +     unsigned long flags;
> > +
> > +     /* FIXME: why lock? */
> > +     spin_lock_irqsave(&host->lock, flags);
>
> ->uhs2_set_ios() should not be racing with anything, so the lock
> should not be needed.  Please remove for now.
>

I will update it in the patch#14 of the new [PATCH V6].

> > +
> > +     /* UHS2 Timeout Control */
> > +     sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
> > +
> > +     /* change to use calculate value */
> > +     cmd_res |= dead_lock << SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT;
> > +
> > +     sdhci_uhs2_clear_set_irqs(host,
> > +                               SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
> > +                               SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT,
> > +                               0);
> > +     sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
> > +     sdhci_uhs2_clear_set_irqs(host, 0,
> > +                               SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
> > +                               SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT);
> > +
> > +     /* UHS2 timing */
> > +     ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> > +     if (ios->timing == MMC_TIMING_SD_UHS2)
> > +             ctrl_2 |= SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN;
> > +     else
> > +             ctrl_2 &= ~(SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN);
> > +     sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
> > +
> > +     if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
> > +             sdhci_enable_preset_value(host, true);
> > +
> > +     if (host->ops->set_power)
> > +             host->ops->set_power(host, ios->power_mode, ios->vdd);
> > +     else
> > +             sdhci_uhs2_set_power(host, ios->power_mode, ios->vdd);
> > +     udelay(100);
> > +
> > +     host->timing = ios->timing;
> > +     sdhci_set_clock(host, host->clock);
> > +
> > +     spin_unlock_irqrestore(&host->lock, flags);
> > +}
> > +
> >  /*****************************************************************************\
> >   *                                                                           *
> >   * MMC callbacks                                                             *
> > @@ -302,6 +370,39 @@ static int sdhci_uhs2_start_signal_voltage_switch(struct mmc_host *mmc,
> >       return sdhci_start_signal_voltage_switch(mmc, ios);
> >  }
> >
> > +int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> > +{
> > +     struct sdhci_host *host = mmc_priv(mmc);
> > +
> > +     if (!(host->version >= SDHCI_SPEC_400) ||
> > +         !(host->mmc->flags & MMC_UHS2_SUPPORT &&
> > +           host->mmc->caps2 & MMC_CAP2_SD_UHS2)) {
> > +             sdhci_set_ios(mmc, ios);
> > +             return 0;
> > +     }
> > +
> > +     if (ios->power_mode == MMC_POWER_UNDEFINED)
> > +             return 1;
>
> ->uhs2_set_ios() expects 0 or a negative error code.
> This case is not an error.
>
>                 return 0;
>

I will update it in the patch#14 of the new [PATCH V6].

> > +
> > +     if (host->flags & SDHCI_DEVICE_DEAD) {
> > +             if (!IS_ERR(mmc->supply.vmmc) &&
> > +                 ios->power_mode == MMC_POWER_OFF)
> > +                     mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> > +             if (!IS_ERR_OR_NULL(mmc->supply.vmmc2) &&
> > +                 ios->power_mode == MMC_POWER_OFF)
> > +                     mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
> > +             return 1;
>
> This is an error, so a negative code is needed
>

I will update it in the patch#14 of the new [PATCH V6].

> > +     }
> > +
> > +     /* FIXME: host->timing = ios->timing */
>
> Yes, __sdhci_uhs2_set_ios() should do that when it sets the timing
>

I will update it in the patch#14 of the new [PATCH V6].

> > +
> > +     sdhci_set_ios_common(mmc, ios);
> > +
> > +     __sdhci_uhs2_set_ios(mmc, ios);
> > +
> > +     return 0;
> > +}
> > +
> >  /*****************************************************************************\
> >   *                                                                           *
> >   * Driver init/exit                                                          *
> > @@ -312,6 +413,7 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
> >  {
> >       host->mmc_host_ops.start_signal_voltage_switch =
> >               sdhci_uhs2_start_signal_voltage_switch;
> > +     host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
> >
> >       return 0;
> >  }
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > index 5ea235b14108..23368448ccd4 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.h
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -216,5 +216,6 @@ void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
> >  void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
> >                         unsigned short vdd);
> >  void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
> > +void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
> >
> >  #endif /* __SDHCI_UHS2_H */
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index dfa0939a9058..de47c71995fb 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -47,8 +47,6 @@
> >  static unsigned int debug_quirks = 0;
> >  static unsigned int debug_quirks2;
> >
> > -static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
> > -
> >  static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
> >
> >  void sdhci_dumpregs(struct sdhci_host *host)
> > @@ -1888,6 +1886,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
> >       case MMC_TIMING_MMC_HS400:
> >               preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
> >               break;
> > +     case MMC_TIMING_SD_UHS2:
> > +             preset = sdhci_readw(host, SDHCI_PRESET_FOR_UHS2);
> > +             break;
> >       default:
> >               pr_warn("%s: Invalid UHS-I mode selected\n",
> >                       mmc_hostname(host->mmc));
> > @@ -2305,20 +2306,9 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
> >
> > -void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> > +void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios)
> >  {
> >       struct sdhci_host *host = mmc_priv(mmc);
> > -     u8 ctrl;
> > -
> > -     if (ios->power_mode == MMC_POWER_UNDEFINED)
> > -             return;
> > -
> > -     if (host->flags & SDHCI_DEVICE_DEAD) {
> > -             if (!IS_ERR(mmc->supply.vmmc) &&
> > -                 ios->power_mode == MMC_POWER_OFF)
> > -                     mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> > -             return;
> > -     }
> >
> >       /*
> >        * Reset the chip on each power off.
> > @@ -2355,6 +2345,25 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> >               host->ops->set_power(host, ios->power_mode, ios->vdd);
> >       else
> >               sdhci_set_power(host, ios->power_mode, ios->vdd);
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_set_ios_common);
> > +
> > +void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> > +{
> > +     struct sdhci_host *host = mmc_priv(mmc);
> > +     u8 ctrl;
> > +
> > +     if (ios->power_mode == MMC_POWER_UNDEFINED)
> > +             return;
> > +
> > +     if (host->flags & SDHCI_DEVICE_DEAD) {
> > +             if (!IS_ERR(mmc->supply.vmmc) &&
> > +                 ios->power_mode == MMC_POWER_OFF)
> > +                     mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> > +             return;
> > +     }
> > +
> > +     sdhci_set_ios_common(mmc, ios);
> >
> >       if (host->ops->platform_send_init_74_clocks)
> >               host->ops->platform_send_init_74_clocks(host, ios->power_mode);
> > @@ -2935,7 +2944,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
> >
> > -static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
> > +void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
> >  {
> >       /* Host Controller v3.00 defines preset value registers */
> >       if (host->version < SDHCI_SPEC_300)
> > @@ -2963,6 +2972,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
> >               host->preset_enabled = enable;
> >       }
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_enable_preset_value);
> >
> >  static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
> >                               int err)
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> > index c34ca6ffbff6..22d7f47862ae 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -871,6 +871,8 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width);
> >  void sdhci_reset(struct sdhci_host *host, u8 mask);
> >  void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
> >  int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
> > +void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
> > +void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios);
> >  void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
> >  int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
> >                                     struct mmc_ios *ios);
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 16/26] mmc: sdhci-uhs2: add detect_init() to detect the interface
  2022-11-01 17:14   ` Adrian Hunter
@ 2022-12-13  8:47     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:47 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:14 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > Sdhci_uhs2_do_detect_init() is a sdhci version of mmc's uhs2_detect_init
> > operation. After detected, the host's UHS-II capabilities will be set up
> > here and interrupts will also be enabled.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 146 ++++++++++++++++++++++++++++++++++
> >  1 file changed, 146 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index b535a47dc55a..9ceae552c323 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -409,12 +409,158 @@ int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> >   *                                                                           *
> >  \*****************************************************************************/
> >
> > +static int sdhci_uhs2_interface_detect(struct sdhci_host *host)
> > +{
> > +     /* 100ms */
> > +     int timeout = 100000;
> > +     u32 val;
> > +
> > +     udelay(200); /* wait for 200us before check */
> > +
> > +     if (read_poll_timeout_atomic(sdhci_readl, val, (val & SDHCI_UHS2_IF_DETECT),
> > +                                  100, timeout, true, host, SDHCI_PRESENT_STATE)) {
> > +             pr_warn("%s: not detect UHS2 interface in 200us.\n", mmc_hostname(host->mmc));
> > +             sdhci_dumpregs(host);
> > +             return -EIO;
> > +     }
> > +
> > +     /* Enable UHS2 error interrupts */
> > +     sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
> > +                               SDHCI_UHS2_ERR_INT_STATUS_MASK);
> > +
> > +     /* 150ms */
> > +     timeout = 150000;
> > +     if (read_poll_timeout_atomic(sdhci_readl, val, (val & SDHCI_UHS2_LANE_SYNC),
> > +                                  100, timeout, true, host, SDHCI_PRESENT_STATE)) {
> > +             pr_warn("%s: UHS2 Lane sync fail in 150ms.\n", mmc_hostname(host->mmc));
> > +             sdhci_dumpregs(host);
> > +             return -EIO;
> > +     }
> > +
> > +     DBG("%s: UHS2 Lane synchronized in UHS2 mode, PHY is initialized.\n",
> > +         mmc_hostname(host->mmc));
> > +     return 0;
> > +}
> > +
> > +static int sdhci_uhs2_init(struct sdhci_host *host)
> > +{
> > +     u16 caps_ptr = 0;
> > +     u32 caps_gen = 0;
> > +     u32 caps_phy = 0;
> > +     u32 caps_tran[2] = {0, 0};
> > +     struct mmc_host *mmc = host->mmc;
> > +
> > +     caps_ptr = sdhci_readw(host, SDHCI_UHS2_HOST_CAPS_PTR);
> > +     if (caps_ptr < 0x100 || caps_ptr > 0x1FF) {
> > +             pr_err("%s: SDHCI_UHS2_HOST_CAPS_PTR(%d) is wrong.\n",
> > +                    mmc_hostname(mmc), caps_ptr);
> > +             return -ENODEV;
> > +     }
> > +     caps_gen = sdhci_readl(host,
> > +                            caps_ptr + SDHCI_UHS2_HOST_CAPS_GEN_OFFSET);
>
> Please wrap at 100 columns not 80, here and elsewhere.
>

I will update it in the patch#15 of the new [PATCH V6].

> > +     caps_phy = sdhci_readl(host,
> > +                            caps_ptr + SDHCI_UHS2_HOST_CAPS_PHY_OFFSET);
> > +     caps_tran[0] = sdhci_readl(host,
> > +                                caps_ptr + SDHCI_UHS2_HOST_CAPS_TRAN_OFFSET);
> > +     caps_tran[1] = sdhci_readl(host,
> > +                                caps_ptr
> > +                                     + SDHCI_UHS2_HOST_CAPS_TRAN_1_OFFSET);
> > +
> > +     /* General Caps */
> > +     mmc->uhs2_caps.dap = caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_DAP_MASK;
> > +     mmc->uhs2_caps.gap = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_GAP_MASK) >>
> > +                          SDHCI_UHS2_HOST_CAPS_GEN_GAP_SHIFT;
> > +     mmc->uhs2_caps.n_lanes = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_LANE_MASK)
> > +                     >> SDHCI_UHS2_HOST_CAPS_GEN_LANE_SHIFT;
> > +     mmc->uhs2_caps.addr64 =
> > +             (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_ADDR_64) ? 1 : 0;
> > +     mmc->uhs2_caps.card_type =
> > +             (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_MASK) >>
> > +             SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_SHIFT;
> > +
> > +     /* PHY Caps */
> > +     mmc->uhs2_caps.phy_rev = caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_REV_MASK;
> > +     mmc->uhs2_caps.speed_range =
> > +             (caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_RANGE_MASK)
> > +             >> SDHCI_UHS2_HOST_CAPS_PHY_RANGE_SHIFT;
> > +     mmc->uhs2_caps.n_lss_sync =
> > +             (caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_MASK)
> > +             >> SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_SHIFT;
> > +     mmc->uhs2_caps.n_lss_dir =
> > +             (caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_MASK)
> > +             >> SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_SHIFT;
> > +     if (mmc->uhs2_caps.n_lss_sync == 0)
> > +             mmc->uhs2_caps.n_lss_sync = 16 << 2;
> > +     else
> > +             mmc->uhs2_caps.n_lss_sync <<= 2;
> > +     if (mmc->uhs2_caps.n_lss_dir == 0)
> > +             mmc->uhs2_caps.n_lss_dir = 16 << 3;
> > +     else
> > +             mmc->uhs2_caps.n_lss_dir <<= 3;
> > +
> > +     /* LINK/TRAN Caps */
> > +     mmc->uhs2_caps.link_rev =
> > +             caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_LINK_REV_MASK;
> > +     mmc->uhs2_caps.n_fcu =
> > +             (caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_MASK)
> > +             >> SDHCI_UHS2_HOST_CAPS_TRAN_N_FCU_SHIFT;
> > +     if (mmc->uhs2_caps.n_fcu == 0)
> > +             mmc->uhs2_caps.n_fcu = 256;
> > +     mmc->uhs2_caps.host_type =
> > +             (caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_MASK)
> > +             >> SDHCI_UHS2_HOST_CAPS_TRAN_HOST_TYPE_SHIFT;
> > +     mmc->uhs2_caps.maxblk_len =
> > +             (caps_tran[0] & SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_MASK)
> > +             >> SDHCI_UHS2_HOST_CAPS_TRAN_BLK_LEN_SHIFT;
> > +     mmc->uhs2_caps.n_data_gap =
> > +             caps_tran[1] & SDHCI_UHS2_HOST_CAPS_TRAN_1_N_DATA_GAP_MASK;
> > +
> > +     return 0;
> > +}
> > +
> > +static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc)
> > +{
> > +     struct sdhci_host *host = mmc_priv(mmc);
> > +     int ret = -EIO;
> > +
> > +     DBG("%s: begin UHS2 init.\n", __func__);
> > +
> > +     if (sdhci_uhs2_interface_detect(host)) {
> > +             pr_warn("%s: cannot detect UHS2 interface.\n",
> > +                     mmc_hostname(host->mmc));
> > +             goto out;
> > +     }
> > +
> > +     if (sdhci_uhs2_init(host)) {
> > +             pr_warn("%s: UHS2 init fail.\n", mmc_hostname(host->mmc));
> > +             goto out;
> > +     }
> > +
> > +     /* Init complete, do soft reset and enable UHS2 error irqs. */
> > +     host->ops->uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD);
> > +     sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
> > +                               SDHCI_UHS2_ERR_INT_STATUS_MASK);
> > +     /*
> > +      * !!! SDHCI_INT_ENABLE and SDHCI_SIGNAL_ENABLE was cleared
>
> !!! is a little dramatic, what about just N.B.
>

I will update it in the patch#15 of the new [PATCH V6].

> > +      * by SDHCI_UHS2_SW_RESET_SD
> > +      */
> > +     sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> > +     sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
> > +
> > +     ret = 0;
> > +out:
> > +     return ret;
> > +}
> > +
> >  static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
> >  {
> >       host->mmc_host_ops.start_signal_voltage_switch =
> >               sdhci_uhs2_start_signal_voltage_switch;
> >       host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
> >
> > +     if (!host->mmc_host_ops.uhs2_detect_init)
> > +             host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
>
> As mentioned before ->uhs2_detect_init() is never called.
>
> > +
> >       return 0;
> >  }
> >
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 17/26] mmc: sdhci-uhs2: add clock operations
  2022-11-01 17:14   ` Adrian Hunter
@ 2022-12-13  8:47     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:47 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:14 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > This is a sdhci version of mmc's uhs2_[enable|disable]_clk operations.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 36 +++++++++++++++++++++++++++++++++++
> >  1 file changed, 36 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 9ceae552c323..afaca5d96938 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -11,6 +11,7 @@
> >   */
> >
> >  #include <linux/delay.h>
> > +#include <linux/ktime.h>
> >  #include <linux/module.h>
> >
> >  #include "sdhci.h"
> > @@ -403,6 +404,37 @@ int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> >       return 0;
> >  }
> >
> > +static int sdhci_uhs2_disable_clk(struct mmc_host *mmc)
> > +{
> > +     struct sdhci_host *host = mmc_priv(mmc);
> > +     u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> > +
> > +     clk &= ~SDHCI_CLOCK_CARD_EN;
> > +     sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> > +
> > +     return 0;
> > +}
> > +
> > +static int sdhci_uhs2_enable_clk(struct mmc_host *mmc)
> > +{
> > +     struct sdhci_host *host = mmc_priv(mmc);
> > +     u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> > +     u32 val;
> > +     /* 20ms */
> > +     int timeout_us = 20000;
> > +
> > +     clk |= SDHCI_CLOCK_CARD_EN;
> > +     sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> > +
> > +     if (read_poll_timeout_atomic(sdhci_readw, val, (val & SDHCI_CLOCK_INT_STABLE),
> > +                                  10, timeout_us, true, host, SDHCI_CLOCK_CONTROL)) {
> > +             pr_err("%s: Internal clock never stabilised.\n", mmc_hostname(host->mmc));
> > +             sdhci_dumpregs(host);
> > +             return 1;
> > +     }
> > +     return 0;
> > +}
> > +
> >  /*****************************************************************************\
> >   *                                                                           *
> >   * Driver init/exit                                                          *
> > @@ -560,6 +592,10 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
> >
> >       if (!host->mmc_host_ops.uhs2_detect_init)
> >               host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
> > +     if (!host->mmc_host_ops.uhs2_disable_clk)
> > +             host->mmc_host_ops.uhs2_disable_clk = sdhci_uhs2_disable_clk;
> > +     if (!host->mmc_host_ops.uhs2_enable_clk)
> > +             host->mmc_host_ops.uhs2_enable_clk = sdhci_uhs2_enable_clk;
>
> As mentioned before ->uhs2_disable_clk() and ->uhs2_enable_clk()
> are never called.
>

I will update it in the patch#16 of the new [PATCH V6].

> >
> >       return 0;
> >  }
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 18/26] mmc: sdhci-uhs2: add uhs2_control() to initialise the interface
  2022-11-01 17:15   ` Adrian Hunter
@ 2022-12-13  8:47     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:47 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:15 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > This is a sdhci version of mmc's uhs2_set_reg operation.
> > UHS-II interface (related registers) will be initialised here.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 103 ++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci.c      |  12 ++++
> >  drivers/mmc/host/sdhci.h      |   1 +
> >  3 files changed, 116 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index afaca5d96938..c9d59b8ac37f 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -350,6 +350,53 @@ static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> >       spin_unlock_irqrestore(&host->lock, flags);
> >  }
> >
> > +static void sdhci_uhs2_set_config(struct sdhci_host *host)
> > +{
> > +     u32 value;
> > +     u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
> > +     u16 sdhci_uhs2_gen_set_reg = (sdhci_uhs2_set_ptr + 0);
> > +     u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
> > +     u16 sdhci_uhs2_tran_set_reg = (sdhci_uhs2_set_ptr + 8);
> > +     u16 sdhci_uhs2_tran_set_1_reg = (sdhci_uhs2_set_ptr + 12);
> > +
> > +     /* Set Gen Settings */
> > +     sdhci_writel(host, host->mmc->uhs2_caps.n_lanes_set <<
> > +             SDHCI_UHS2_GEN_SET_N_LANES_POS, sdhci_uhs2_gen_set_reg);
> > +
> > +     /* Set PHY Settings */
> > +     value = (host->mmc->uhs2_caps.n_lss_dir_set <<
> > +                     SDHCI_UHS2_PHY_SET_N_LSS_DIR_POS) |
> > +             (host->mmc->uhs2_caps.n_lss_sync_set <<
> > +                     SDHCI_UHS2_PHY_SET_N_LSS_SYN_POS);
> > +     if (host->mmc->flags & MMC_UHS2_SPEED_B)
> > +             value |= 1 << SDHCI_UHS2_PHY_SET_SPEED_POS;
> > +     sdhci_writel(host, value, sdhci_uhs2_phy_set_reg);
> > +
> > +     /* Set LINK-TRAN Settings */
> > +     value = (host->mmc->uhs2_caps.max_retry_set <<
> > +                     SDHCI_UHS2_TRAN_SET_RETRY_CNT_POS) |
> > +             (host->mmc->uhs2_caps.n_fcu_set <<
> > +                     SDHCI_UHS2_TRAN_SET_N_FCU_POS);
> > +     sdhci_writel(host, value, sdhci_uhs2_tran_set_reg);
> > +     sdhci_writel(host, host->mmc->uhs2_caps.n_data_gap_set,
> > +                  sdhci_uhs2_tran_set_1_reg);
> > +}
> > +
> > +static int sdhci_uhs2_check_dormant(struct sdhci_host *host)
> > +{
> > +     u32 val;
> > +     /* 100ms */
> > +     int timeout = 100000;
> > +
> > +     if (read_poll_timeout_atomic(sdhci_readl, val, (val & SDHCI_UHS2_IN_DORMANT_STATE),
> > +                                  100, timeout, true, host, SDHCI_PRESENT_STATE)) {
> > +             pr_warn("%s: UHS2 IN_DORMANT fail in 100ms.\n", mmc_hostname(host->mmc));
> > +             sdhci_dumpregs(host);
> > +             return -EIO;
> > +     }
> > +     return 0;
> > +}
> > +
> >  /*****************************************************************************\
> >   *                                                                           *
> >   * MMC callbacks                                                             *
> > @@ -435,6 +482,61 @@ static int sdhci_uhs2_enable_clk(struct mmc_host *mmc)
> >       return 0;
> >  }
> >
> > +static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc);
> > +
> > +static int sdhci_uhs2_control(struct mmc_host *mmc, enum sd_uhs2_operation op)
> > +{
> > +     struct sdhci_host *host = mmc_priv(mmc);
> > +     unsigned long flags;
> > +     int err = 0;
> > +     u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
> > +     u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
> > +
> > +     DBG("Begin %s, act %d.\n", __func__, op);
>
> DBG already has __func__.  Please also check other DBG that
> have duplicate __func__
>

I will update it in the patch#17 of the new [PATCH V6].

> > +
> > +     spin_lock_irqsave(&host->lock, flags);
>
> This all relates to initialization or reinitialization, so I suspect
> the spinlock is not needed here.  What could it be racing with?
>

I will delete it and update it in the patch#17 of the new [PATCH V6].

> > +
> > +     switch (op) {
> > +     case UHS2_PHY_INIT:
> > +             err = sdhci_uhs2_do_detect_init(mmc);
> > +             break;
> > +     case UHS2_SET_CONFIG:
> > +             sdhci_uhs2_set_config(host);
> > +             break;
> > +     case UHS2_ENABLE_INT:
> > +             sdhci_clear_set_irqs(host, 0, SDHCI_INT_CARD_INT);
> > +             break;
> > +     case UHS2_DISABLE_INT:
> > +             sdhci_clear_set_irqs(host, SDHCI_INT_CARD_INT, 0);
> > +             break;
> > +     case UHS2_SET_SPEED_B:
> > +             sdhci_writeb(host, 1 << SDHCI_UHS2_PHY_SET_SPEED_POS,
> > +                          sdhci_uhs2_phy_set_reg);
> > +             break;
> > +     case UHS2_CHECK_DORMANT:
> > +             err = sdhci_uhs2_check_dormant(host);
> > +             break;
> > +     case UHS2_DISABLE_CLK:
> > +             err = sdhci_uhs2_disable_clk(mmc);
> > +             break;
> > +     case UHS2_ENABLE_CLK:
> > +             err = sdhci_uhs2_enable_clk(mmc);
> > +             break;
> > +     case UHS2_POST_ATTACH_SD:
> > +             host->ops->uhs2_post_attach_sd(host);
> > +             break;
> > +     default:
> > +             pr_err("%s: input sd uhs2 operation %d is wrong!\n",
> > +                    mmc_hostname(host->mmc), op);
> > +             err = -EIO;
> > +             break;
> > +     }
> > +
> > +     spin_unlock_irqrestore(&host->lock, flags);
> > +
> > +     return err;
> > +}
> > +
> >  /*****************************************************************************\
> >   *                                                                           *
> >   * Driver init/exit                                                          *
> > @@ -589,6 +691,7 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
> >       host->mmc_host_ops.start_signal_voltage_switch =
> >               sdhci_uhs2_start_signal_voltage_switch;
> >       host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
> > +     host->mmc_host_ops.uhs2_control = sdhci_uhs2_control;
> >
> >       if (!host->mmc_host_ops.uhs2_detect_init)
> >               host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index de47c71995fb..b9db2e976010 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -236,6 +236,18 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_reset);
> >
> > +void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
> > +{
> > +     u32 ier;
> > +
> > +     ier = sdhci_readl(host, SDHCI_INT_ENABLE);
> > +     ier &= ~clear;
> > +     ier |= set;
> > +     sdhci_writel(host, ier, SDHCI_INT_ENABLE);
> > +     sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_clear_set_irqs);
>
> This might as well be in sdhci-uhs2.c since that is the only
> place that calls it.  Then there is no need to export it.
>

I will update it in the patch#17 of the new [PATCH V6].

> > +
> >  static bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
> >  {
> >       if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> > index 22d7f47862ae..f049331bd0bc 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -869,6 +869,7 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq);
> >  int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
> >  void sdhci_set_bus_width(struct sdhci_host *host, int width);
> >  void sdhci_reset(struct sdhci_host *host, u8 mask);
> > +void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
> >  void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
> >  int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
> >  void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 19/26] mmc: sdhci-uhs2: add request() and others
  2022-11-01 17:15   ` Adrian Hunter
@ 2022-12-13  8:47     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:47 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:15 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > This is a sdhci version of mmc's request operation.
> > It covers both UHS-I and UHS-II.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 475 ++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci.c      |  91 ++++---
> >  drivers/mmc/host/sdhci.h      |  17 ++
> >  3 files changed, 550 insertions(+), 33 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index c9d59b8ac37f..41b089ccc200 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -13,6 +13,7 @@
> >  #include <linux/delay.h>
> >  #include <linux/ktime.h>
> >  #include <linux/module.h>
> > +#include <linux/mmc/mmc.h>
> >
> >  #include "sdhci.h"
> >  #include "sdhci-uhs2.h"
> > @@ -537,6 +538,479 @@ static int sdhci_uhs2_control(struct mmc_host *mmc, enum sd_uhs2_operation op)
> >       return err;
> >  }
> >
> > +/*****************************************************************************\
> > + *                                                                           *
> > + * Core functions                                                            *
> > + *                                                                           *
> > +\*****************************************************************************/
> > +
> > +static void sdhci_uhs2_prepare_data(struct sdhci_host *host,
> > +                                 struct mmc_command *cmd)
> > +{
> > +     struct mmc_data *data = cmd->data;
> > +
> > +     sdhci_initialize_data(host, data);
> > +
> > +     sdhci_prepare_dma(host, data);
> > +
> > +     sdhci_writew(host, data->blksz, SDHCI_UHS2_BLOCK_SIZE);
> > +     sdhci_writew(host, data->blocks, SDHCI_UHS2_BLOCK_COUNT);
> > +}
> > +
> > +#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
> > +static void sdhci_uhs2_external_dma_prepare_data(struct sdhci_host *host,
> > +                                              struct mmc_command *cmd)
> > +{
> > +     if (!sdhci_external_dma_setup(host, cmd)) {
> > +             __sdhci_external_dma_prepare_data(host, cmd);
> > +     } else {
> > +             sdhci_external_dma_release(host);
> > +             pr_err("%s: Cannot use external DMA, switch to the DMA/PIO which standard SDHCI provides.\n",
> > +                    mmc_hostname(host->mmc));
> > +             sdhci_uhs2_prepare_data(host, cmd);
> > +     }
> > +}
> > +#else
> > +static inline void sdhci_uhs2_external_dma_prepare_data(struct sdhci_host *host,
> > +                                                     struct mmc_command *cmd)
> > +{
> > +     /* This should never happen */
> > +     WARN_ON_ONCE(1);
> > +}
> > +
> > +static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
> > +                                                struct mmc_command *cmd)
> > +{
> > +}
> > +#endif /* CONFIG_MMC_SDHCI_EXTERNAL_DMA */
>
> Let's skip external DMA support to start with.
>

I will update it in the patch#18 of the new [PATCH V6].

> > +
> > +static void sdhci_uhs2_finish_data(struct sdhci_host *host)
> > +{
> > +     struct mmc_data *data = host->data;
> > +
> > +     __sdhci_finish_data_common(host);
> > +
> > +     /*
> > +      *  FIXME: Is this condition needed?
> > +         if (host->mmc->flags & MMC_UHS2_INITIALIZED)
> > +      */
>
> No
>

I will update it in the patch#18 of the new [PATCH V6].

> > +     __sdhci_finish_mrq(host, data->mrq);
> > +}
> > +
> > +static void sdhci_uhs2_set_transfer_mode(struct sdhci_host *host,
> > +                                      struct mmc_command *cmd)
> > +{
> > +     u16 mode;
> > +     struct mmc_data *data = cmd->data;
> > +     u16 arg;
> > +
> > +     if (!data) {
> > +             /* clear Auto CMD settings for no data CMDs */
> > +             arg = cmd->uhs2_cmd->arg;
> > +             if ((((arg & 0xF) << 8) | ((arg >> 8) & 0xFF)) ==
>
> Please don't open code byte-swapping
>
> This should be an inline function so it can be used again
> further below:
>
> #define UHS2_ARG_IOADR_MASK 0xfff
>
> static inline u16 uhs2_dev_cmd(struct mmc_command *cmd)
> {
>         return be16_to_cpu((__be16)cmd->uhs2_cmd->arg) & UHS2_ARG_IOADR_MASK;
> }
>
>

I will update it in the patch#18 of the new [PATCH V6].

> > +                    UHS2_DEV_CMD_TRANS_ABORT) {
>
> Please wrap at 100 columns instead of 80, here and elsewhere.
>

I will update it in the patch#18 of the new [PATCH V6].

> > +                     mode =  0;
> > +             } else {
> > +                     mode = sdhci_readw(host, SDHCI_UHS2_TRANS_MODE);
> > +                     if (cmd->opcode == MMC_STOP_TRANSMISSION ||
> > +                         cmd->opcode == MMC_ERASE)
> > +                             mode |= SDHCI_UHS2_TRNS_WAIT_EBSY;
> > +                     else
> > +                             /* send status mode */
> > +                             if (cmd->opcode == MMC_SEND_STATUS)
> > +                                     mode = 0;
> > +             }
> > +
> > +             if (IS_ENABLED(CONFIG_MMC_DEBUG))
>
> Please don't use CONFIG_MMC_DEBUG
>

I will update it in the patch#18 of the new [PATCH V6].

> > +                     DBG("UHS2 no data trans mode is 0x%x.\n", mode);
> > +
> > +             sdhci_writew(host, mode, SDHCI_UHS2_TRANS_MODE);
> > +             return;
> > +     }
> > +
> > +     WARN_ON(!host->data);
> > +
> > +     mode = SDHCI_UHS2_TRNS_BLK_CNT_EN | SDHCI_UHS2_TRNS_WAIT_EBSY;
> > +     if (data->flags & MMC_DATA_WRITE)
> > +             mode |= SDHCI_UHS2_TRNS_DATA_TRNS_WRT;
> > +
> > +     if (data->blocks == 1 &&
> > +         data->blksz != 512 &&
> > +         cmd->opcode != MMC_READ_SINGLE_BLOCK &&
> > +         cmd->opcode != MMC_WRITE_BLOCK) {
> > +             mode &= ~SDHCI_UHS2_TRNS_BLK_CNT_EN;
> > +             mode |= SDHCI_UHS2_TRNS_BLK_BYTE_MODE;
> > +     }
> > +
> > +     if (host->flags & SDHCI_REQ_USE_DMA)
> > +             mode |= SDHCI_UHS2_TRNS_DMA;
> > +
> > +     if ((host->mmc->uhs2_ios.is_2L_HD_mode) && !cmd->uhs2_tmode0_flag)
> > +             mode |= SDHCI_UHS2_TRNS_2L_HD;
> > +
> > +     sdhci_writew(host, mode, SDHCI_UHS2_TRANS_MODE);
> > +
> > +     if (IS_ENABLED(CONFIG_MMC_DEBUG))
>
> Please don't use CONFIG_MMC_DEBUG
>

I will update it in the patch#18 of the new [PATCH V6].

> > +             DBG("UHS2 trans mode is 0x%x.\n", mode);
> > +}
> > +
> > +static void __sdhci_uhs2_send_command(struct sdhci_host *host,
> > +                                   struct mmc_command *cmd)
> > +{
> > +     int i, j;
> > +     int cmd_reg;
> > +
> > +     if (host->mmc->flags & MMC_UHS2_INITIALIZED) {
>
> Not necessary to check MMC_UHS2_INITIALIZED here
>

I will update it in the patch#18 of the new [PATCH V6].

> > +             if (!cmd->uhs2_cmd) {
> > +                     pr_err("%s: fatal error, no uhs2_cmd!\n",
> > +                            mmc_hostname(host->mmc));
> > +                     return;
> > +             }
> > +     }
> > +
> > +     i = 0;
> > +     sdhci_writel(host,
> > +                  ((u32)cmd->uhs2_cmd->arg << 16) |
> > +                             (u32)cmd->uhs2_cmd->header,
> > +                  SDHCI_UHS2_CMD_PACKET + i);
> > +     i += 4;
> > +
> > +     /*
> > +      * Per spec, playload (config) should be MSB before sending out.
> > +      * But we don't need convert here because had set payload as
> > +      * MSB when preparing config read/write commands.
> > +      */
> > +     for (j = 0; j < cmd->uhs2_cmd->payload_len / sizeof(u32); j++) {
> > +             sdhci_writel(host, *(cmd->uhs2_cmd->payload + j),
> > +                          SDHCI_UHS2_CMD_PACKET + i);
> > +             i += 4;
> > +     }
> > +
> > +     for ( ; i < SDHCI_UHS2_CMD_PACK_MAX_LEN; i += 4)
> > +             sdhci_writel(host, 0, SDHCI_UHS2_CMD_PACKET + i);
> > +
> > +     if (IS_ENABLED(CONFIG_MMC_DEBUG)) {
>
> Please don't use CONFIG_MMC_DEBUG
>

I will update it in the patch#18 of the new [PATCH V6].

> > +             DBG("UHS2 CMD packet_len = %d.\n", cmd->uhs2_cmd->packet_len);
> > +             for (i = 0; i < cmd->uhs2_cmd->packet_len; i++)
> > +                     DBG("UHS2 CMD_PACKET[%d] = 0x%x.\n", i,
> > +                         sdhci_readb(host, SDHCI_UHS2_CMD_PACKET + i));
> > +     }
> > +
> > +     cmd_reg = cmd->uhs2_cmd->packet_len <<
> > +             SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT;
> > +     if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC)
> > +             cmd_reg |= SDHCI_UHS2_COMMAND_DATA;
> > +     if (cmd->opcode == MMC_STOP_TRANSMISSION)
> > +             cmd_reg |= SDHCI_UHS2_COMMAND_CMD12;
> > +
> > +     /* UHS2 Native ABORT */
> > +     if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) &&
> > +         ((((cmd->uhs2_cmd->arg & 0xF) << 8) |
> > +         ((cmd->uhs2_cmd->arg >> 8) & 0xFF)) == UHS2_DEV_CMD_TRANS_ABORT))
>
>  From above, can use (uhs2_dev_cmd(cmd) == UHS2_DEV_CMD_TRANS_ABORT)
>

I will update it in the patch#18 of the new [PATCH V6].

> > +             cmd_reg |= SDHCI_UHS2_COMMAND_TRNS_ABORT;
> > +
> > +     /* UHS2 Native DORMANT */
> > +     if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) &&
> > +         ((((cmd->uhs2_cmd->arg & 0xF) << 8) |
> > +          ((cmd->uhs2_cmd->arg >> 8) & 0xFF)) ==
> > +                             UHS2_DEV_CMD_GO_DORMANT_STATE))
>
>  From above, can use (uhs2_dev_cmd(cmd) == UHS2_DEV_CMD_GO_DORMANT_STATE)
>

I will update it in the patch#18 of the new [PATCH V6].

> > +             cmd_reg |= SDHCI_UHS2_COMMAND_DORMANT;
> > +
> > +     DBG("0x%x is set to UHS2 CMD register.\n", cmd_reg);
> > +
> > +     sdhci_writew(host, cmd_reg, SDHCI_UHS2_COMMAND);
> > +}
> > +
> > +static bool sdhci_uhs2_send_command(struct sdhci_host *host,
> > +                                 struct mmc_command *cmd)
> > +{
> > +     int flags;
> > +     u32 mask;
> > +     unsigned long timeout;
> > +
> > +     WARN_ON(host->cmd);
> > +
> > +     /* Initially, a command has no error */
> > +     cmd->error = 0;
> > +
> > +     if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
> > +             return sdhci_send_command(host, cmd);
>
> No check necessary, can remove, and please do not export
> sdhci_send_command().
>

I will update it in the patch#18 of the new [PATCH V6].

> > +
> > +     if (cmd->opcode == MMC_STOP_TRANSMISSION)
> > +             cmd->flags |= MMC_RSP_BUSY;
> > +
> > +     mask = SDHCI_CMD_INHIBIT;
> > +
> > +     if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)
> > +             return false;
> > +
> > +     host->cmd = cmd;
> > +     host->data_timeout = 0;
> > +     if (sdhci_data_line_cmd(cmd)) {
> > +             WARN_ON(host->data_cmd);
> > +             host->data_cmd = cmd;
> > +             __sdhci_uhs2_set_timeout(host);
> > +     }
> > +
> > +     if (cmd->data) {
> > +             if (host->use_external_dma)
>
> Let's skip external DMA support for now
>

I will update it in the patch#18 of the new [PATCH V6].

> > +                     sdhci_uhs2_external_dma_prepare_data(host, cmd);
> > +             else
> > +                     sdhci_uhs2_prepare_data(host, cmd);
> > +     }
> > +
> > +     sdhci_uhs2_set_transfer_mode(host, cmd);
> > +
> > +     if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
> > +             WARN_ONCE(1, "Unsupported response type!\n");
> > +             /*
> > +              * This does not happen in practice because 136-bit response
> > +              * commands never have busy waiting, so rather than complicate
> > +              * the error path, just remove busy waiting and continue.
> > +              */
> > +             cmd->flags &= ~MMC_RSP_BUSY;
> > +     }
> > +
> > +     if (!(cmd->flags & MMC_RSP_PRESENT))
> > +             flags = SDHCI_CMD_RESP_NONE;
> > +     else if (cmd->flags & MMC_RSP_136)
> > +             flags = SDHCI_CMD_RESP_LONG;
> > +     else if (cmd->flags & MMC_RSP_BUSY)
> > +             flags = SDHCI_CMD_RESP_SHORT_BUSY;
> > +     else
> > +             flags = SDHCI_CMD_RESP_SHORT;
> > +
> > +     if (cmd->flags & MMC_RSP_CRC)
> > +             flags |= SDHCI_CMD_CRC;
> > +     if (cmd->flags & MMC_RSP_OPCODE)
> > +             flags |= SDHCI_CMD_INDEX;
> > +
> > +     timeout = jiffies;
> > +     if (host->data_timeout)
> > +             timeout += nsecs_to_jiffies(host->data_timeout);
> > +     else if (!cmd->data && cmd->busy_timeout > 9000)
> > +             timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
> > +     else
> > +             timeout += 10 * HZ;
> > +     sdhci_mod_timer(host, cmd->mrq, timeout);
> > +
> > +     if (host->use_external_dma)
> > +             sdhci_external_dma_pre_transfer(host, cmd);
> > +
> > +     __sdhci_uhs2_send_command(host, cmd);
> > +
> > +     return true;
> > +}
> > +
> > +static bool sdhci_uhs2_send_command_retry(struct sdhci_host *host,
> > +                                  struct mmc_command *cmd,
> > +                                  unsigned long flags)
> > +     __releases(host->lock)
> > +     __acquires(host->lock)
> > +{
> > +     struct mmc_command *deferred_cmd = host->deferred_cmd;
> > +     int timeout = 10; /* Approx. 10 ms */
> > +     bool present;
> > +
> > +     while (!sdhci_uhs2_send_command(host, cmd)) {
> > +             if (!timeout--) {
> > +                     pr_err("%s: Controller never released inhibit bit(s).\n",
> > +                            mmc_hostname(host->mmc));
> > +                     sdhci_dumpregs(host);
> > +                     cmd->error = -EIO;
> > +                     return false;
> > +             }
> > +
> > +             spin_unlock_irqrestore(&host->lock, flags);
> > +
> > +             usleep_range(1000, 1250);
> > +
> > +             present = host->mmc->ops->get_cd(host->mmc);
> > +
> > +             spin_lock_irqsave(&host->lock, flags);
> > +
> > +             /* A deferred command might disappear, handle that */
> > +             if (cmd == deferred_cmd && cmd != host->deferred_cmd)
> > +                     return true;
> > +
> > +             if (sdhci_present_error(host, cmd, present))
> > +                     return false;
> > +     }
> > +
> > +     if (cmd == host->deferred_cmd)
> > +             host->deferred_cmd = NULL;
> > +
> > +     return true;
> > +}
> > +
> > +static void __sdhci_uhs2_finish_command(struct sdhci_host *host)
> > +{
> > +     struct mmc_command *cmd = host->cmd;
> > +     u8 resp;
> > +     u8 ecode;
> > +     bool bReadA0 = 0;
> > +     int i;
> > +
> > +     if (host->mmc->flags & MMC_UHS2_INITIALIZED) {
> > +             resp = sdhci_readb(host, SDHCI_UHS2_RESPONSE + 2);
> > +             if (resp & UHS2_RES_NACK_MASK) {
> > +                     ecode = (resp >> UHS2_RES_ECODE_POS) &
> > +                             UHS2_RES_ECODE_MASK;
> > +                     pr_err("%s: NACK is got, ECODE=0x%x.\n",
> > +                            mmc_hostname(host->mmc), ecode);
> > +             }
> > +             bReadA0 = 1;
> > +     }
> > +
> > +     if (cmd->uhs2_resp &&
> > +         cmd->uhs2_resp_len && cmd->uhs2_resp_len <= 20) {
> > +             /* Get whole response of some native CCMD, like
> > +              * DEVICE_INIT, ENUMERATE.
> > +              */
> > +             for (i = 0; i < cmd->uhs2_resp_len; i++)
> > +                     cmd->uhs2_resp[i] =
> > +                             sdhci_readb(host, SDHCI_UHS2_RESPONSE + i);
> > +     } else {
> > +             /* Get SD CMD response and Payload for some read
> > +              * CCMD, like INQUIRY_CFG.
> > +              */
> > +             /* Per spec (p136), payload field is divided into
> > +              * a unit of DWORD and transmission order within
> > +              * a DWORD is big endian.
> > +              */
> > +             if (!bReadA0)
> > +                     sdhci_readl(host, SDHCI_UHS2_RESPONSE);
> > +             for (i = 4; i < 20; i += 4) {
> > +                     cmd->resp[i / 4 - 1] =
> > +                             (sdhci_readb(host,
> > +                                          SDHCI_UHS2_RESPONSE + i) << 24) |
> > +                             (sdhci_readb(host,
> > +                                          SDHCI_UHS2_RESPONSE + i + 1)
> > +                                     << 16) |
> > +                             (sdhci_readb(host,
> > +                                          SDHCI_UHS2_RESPONSE + i + 2)
> > +                                     << 8) |
> > +                             sdhci_readb(host, SDHCI_UHS2_RESPONSE + i + 3);
> > +             }
> > +     }
> > +}
> > +
> > +static void sdhci_uhs2_finish_command(struct sdhci_host *host)
> > +{
> > +     struct mmc_command *cmd = host->cmd;
> > +
> > +     /* FIXME: Is this check necessary? */
>
> No
>

I will update it in the patch#18 of the new [PATCH V6].

> > +     if (!(host->mmc->flags & MMC_UHS2_SUPPORT)) {
> > +             sdhci_finish_command(host);
>
> Please do not export sdhci_finish_command()
>

I will update it in the patch#18 of the new [PATCH V6].

> > +             return;
> > +     }
> > +
> > +     __sdhci_uhs2_finish_command(host);
> > +
> > +     host->cmd = NULL;
> > +
> > +     if (cmd->mrq->cap_cmd_during_tfr && cmd == cmd->mrq->cmd)
> > +             mmc_command_done(host->mmc, cmd->mrq);
> > +
> > +     /*
> > +      * The host can send and interrupt when the busy state has
> > +      * ended, allowing us to wait without wasting CPU cycles.
> > +      * The busy signal uses DAT0 so this is similar to waiting
> > +      * for data to complete.
> > +      *
> > +      * Note: The 1.0 specification is a bit ambiguous about this
> > +      *       feature so there might be some problems with older
> > +      *       controllers.
> > +      */
> > +     if (cmd->flags & MMC_RSP_BUSY) {
> > +             if (cmd->data) {
> > +                     DBG("Cannot wait for busy signal when also doing a data transfer");
> > +             } else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) &&
> > +                        cmd == host->data_cmd) {
> > +                     /* Command complete before busy is ended */
> > +                     return;
> > +             }
> > +     }
> > +
> > +     /* Processed actual command. */
> > +     if (host->data && host->data_early)
> > +             sdhci_uhs2_finish_data(host);
> > +
> > +     if (!cmd->data)
> > +             __sdhci_finish_mrq(host, cmd->mrq);
> > +}
> > +
> > +void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
> > +{
> > +     struct sdhci_host *host = mmc_priv(mmc);
> > +     struct mmc_command *cmd;
> > +     unsigned long flags;
> > +     bool present;
> > +
> > +     /* FIXME: check more flags? */
>
> No, it's fine.
>

I will update it in the patch#18 of the new [PATCH V6].

> > +     if (!(sdhci_uhs2_mode(host))) {
> > +             sdhci_request(mmc, mrq);
> > +             return;
> > +     }
>
> We need to clear the stop cmd and sbc to prevent the
> driver using them.
>
>         mrq->stop = NULL;
>         mrq->sbc = NULL;
>         if (mrq->data)
>                 mrq->data->stop = NULL;
>

I will update it in the patch#18 of the new [PATCH V6].

> > +
> > +     /* Firstly check card presence */
> > +     present = mmc->ops->get_cd(mmc);
> > +
> > +     spin_lock_irqsave(&host->lock, flags);
> > +
> > +     if (sdhci_present_error(host, mrq->cmd, present))
> > +             goto out_finish;
> > +
> > +     cmd = mrq->cmd;
> > +
> > +     if (!sdhci_uhs2_send_command(host, cmd))
> > +             goto out_finish;
> > +
> > +     spin_unlock_irqrestore(&host->lock, flags);
> > +
> > +     return;
> > +
> > +out_finish:
> > +     sdhci_finish_mrq(host, mrq);
> > +     spin_unlock_irqrestore(&host->lock, flags);
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_request);
> > +
> > +int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq)
> > +{
> > +     struct sdhci_host *host = mmc_priv(mmc);
> > +     struct mmc_command *cmd;
> > +     unsigned long flags;
> > +     int ret = 0;
> > +
> > +     if (!host->mmc->flags & MMC_UHS2_SUPPORT)
> > +             return sdhci_request_atomic(mmc, mrq);
> > +
> > +     spin_lock_irqsave(&host->lock, flags);
> > +
> > +     if (sdhci_present_error(host, mrq->cmd, true)) {
> > +             sdhci_finish_mrq(host, mrq);
> > +             goto out_finish;
> > +     }
> > +
> > +     cmd = mrq->cmd;
> > +
> > +     /*
> > +      * The HSQ may send a command in interrupt context without polling
> > +      * the busy signaling, which means we should return BUSY if controller
> > +      * has not released inhibit bits to allow HSQ trying to send request
> > +      * again in non-atomic context. So we should not finish this request
> > +      * here.
> > +      */
> > +     if (!sdhci_uhs2_send_command(host, cmd))
> > +             ret = -EBUSY;
> > +
> > +out_finish:
> > +     spin_unlock_irqrestore(&host->lock, flags);
> > +     return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_request_atomic);
> > +
> >  /*****************************************************************************\
> >   *                                                                           *
> >   * Driver init/exit                                                          *
> > @@ -692,6 +1166,7 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
> >               sdhci_uhs2_start_signal_voltage_switch;
> >       host->mmc_host_ops.uhs2_set_ios = sdhci_uhs2_set_ios;
> >       host->mmc_host_ops.uhs2_control = sdhci_uhs2_control;
> > +     host->mmc_host_ops.request = sdhci_uhs2_request;
> >
> >       if (!host->mmc_host_ops.uhs2_detect_init)
> >               host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index b9db2e976010..407169468927 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -47,8 +47,6 @@
> >  static unsigned int debug_quirks = 0;
> >  static unsigned int debug_quirks2;
> >
> > -static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
> > -
> >  void sdhci_dumpregs(struct sdhci_host *host)
> >  {
> >       SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n");
> > @@ -147,10 +145,11 @@ void sdhci_enable_v4_mode(struct sdhci_host *host)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode);
> >
> > -static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
> > +bool sdhci_data_line_cmd(struct mmc_command *cmd)
> >  {
> >       return cmd->data || cmd->flags & MMC_RSP_BUSY;
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_data_line_cmd);
> >
> >  static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
> >  {
> > @@ -409,7 +408,7 @@ static void sdhci_reinit(struct sdhci_host *host)
> >               mmc_detect_change(host->mmc, msecs_to_jiffies(200));
> >  }
> >
> > -static void __sdhci_led_activate(struct sdhci_host *host)
> > +void __sdhci_led_activate(struct sdhci_host *host)
> >  {
> >       u8 ctrl;
> >
> > @@ -420,8 +419,9 @@ static void __sdhci_led_activate(struct sdhci_host *host)
> >       ctrl |= SDHCI_CTRL_LED;
> >       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
> >  }
> > +EXPORT_SYMBOL_GPL(__sdhci_led_activate);
>
> The LED functions like __sdhci_led_activate() are not being used
> and don't need to be exported.
>

I will update it in the patch#18 of the new [PATCH V6].

> >
> > -static void __sdhci_led_deactivate(struct sdhci_host *host)
> > +void __sdhci_led_deactivate(struct sdhci_host *host)
> >  {
> >       u8 ctrl;
> >
> > @@ -432,6 +432,7 @@ static void __sdhci_led_deactivate(struct sdhci_host *host)
> >       ctrl &= ~SDHCI_CTRL_LED;
> >       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
> >  }
> > +EXPORT_SYMBOL_GPL(__sdhci_led_deactivate);
> >
> >  #if IS_REACHABLE(CONFIG_LEDS_CLASS)
> >  static void sdhci_led_control(struct led_classdev *led,
> > @@ -510,14 +511,15 @@ static inline void sdhci_led_deactivate(struct sdhci_host *host)
> >
> >  #endif
> >
> > -static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
> > -                         unsigned long timeout)
> > +void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
> > +                  unsigned long timeout)
> >  {
> >       if (sdhci_data_line_cmd(mrq->cmd))
> >               mod_timer(&host->data_timer, timeout);
> >       else
> >               mod_timer(&host->timer, timeout);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_mod_timer);
> >
> >  static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
> >  {
> > @@ -1098,8 +1100,7 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
> >               __sdhci_set_timeout(host, cmd);
> >  }
> >
> > -static void sdhci_initialize_data(struct sdhci_host *host,
> > -                               struct mmc_data *data)
> > +void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data)
> >  {
> >       WARN_ON(host->data);
> >
> > @@ -1112,6 +1113,7 @@ static void sdhci_initialize_data(struct sdhci_host *host,
> >       host->data_early = 0;
> >       host->data->bytes_xfered = 0;
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_initialize_data);
> >
> >  static inline void sdhci_set_block_info(struct sdhci_host *host,
> >                                       struct mmc_data *data)
> > @@ -1134,12 +1136,8 @@ static inline void sdhci_set_block_info(struct sdhci_host *host,
> >       }
> >  }
> >
> > -static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
> > +void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data)
> >  {
> > -     struct mmc_data *data = cmd->data;
> > -
> > -     sdhci_initialize_data(host, data);
> > -
> >       if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
> >               struct scatterlist *sg;
> >               unsigned int length_mask, offset_mask;
> > @@ -1224,6 +1222,16 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
> >       }
> >
> >       sdhci_set_transfer_irqs(host);
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_prepare_dma);
> > +
> > +static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
> > +{
> > +     struct mmc_data *data = cmd->data;
> > +
> > +     sdhci_initialize_data(host, data);
> > +
> > +     sdhci_prepare_dma(host, data);
> >
> >       sdhci_set_block_info(host, data);
> >  }
> > @@ -1266,8 +1274,7 @@ static struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
> >       return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
> >  }
> >
> > -static int sdhci_external_dma_setup(struct sdhci_host *host,
> > -                                 struct mmc_command *cmd)
> > +int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd)
> >  {
> >       int ret, i;
> >       enum dma_transfer_direction dir;
> > @@ -1320,8 +1327,9 @@ static int sdhci_external_dma_setup(struct sdhci_host *host,
> >
> >       return ret;
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_external_dma_setup);
> >
> > -static void sdhci_external_dma_release(struct sdhci_host *host)
> > +void sdhci_external_dma_release(struct sdhci_host *host)
> >  {
> >       if (host->tx_chan) {
> >               dma_release_channel(host->tx_chan);
> > @@ -1335,9 +1343,10 @@ static void sdhci_external_dma_release(struct sdhci_host *host)
> >
> >       sdhci_switch_external_dma(host, false);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_external_dma_release);
> >
> > -static void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
> > -                                           struct mmc_command *cmd)
> > +void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
> > +                                    struct mmc_command *cmd)
> >  {
> >       struct mmc_data *data = cmd->data;
> >
> > @@ -1348,6 +1357,7 @@ static void __sdhci_external_dma_prepare_data(struct sdhci_host *host,
> >
> >       sdhci_set_block_info(host, data);
> >  }
> > +EXPORT_SYMBOL(__sdhci_external_dma_prepare_data);
> >
> >  static void sdhci_external_dma_prepare_data(struct sdhci_host *host,
> >                                           struct mmc_command *cmd)
> > @@ -1362,8 +1372,8 @@ static void sdhci_external_dma_prepare_data(struct sdhci_host *host,
> >       }
> >  }
> >
> > -static void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
> > -                                         struct mmc_command *cmd)
> > +void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
> > +                                  struct mmc_command *cmd)
> >  {
> >       struct dma_chan *chan;
> >
> > @@ -1374,6 +1384,7 @@ static void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
> >       if (chan)
> >               dma_async_issue_pending(chan);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_external_dma_pre_transfer);
> >
> >  #else
> >
> > @@ -1425,11 +1436,11 @@ static inline bool sdhci_auto_cmd23(struct sdhci_host *host,
> >       return mrq->sbc && (host->flags & SDHCI_AUTO_CMD23);
> >  }
> >
> > -static inline bool sdhci_manual_cmd23(struct sdhci_host *host,
> > -                                   struct mmc_request *mrq)
> > +bool sdhci_manual_cmd23(struct sdhci_host *host, struct mmc_request *mrq)
> >  {
> >       return mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_manual_cmd23);
>
> Also don't see sdhci_manual_cmd23() being used.
> Please check what is being exported.
>

I will update it in the patch#18 of the new [PATCH V6].

> >
> >  static inline void sdhci_auto_cmd_select(struct sdhci_host *host,
> >                                        struct mmc_command *cmd,
> > @@ -1541,7 +1552,7 @@ static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
> >       WARN_ON(i >= SDHCI_MAX_MRQS);
> >  }
> >
> > -static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
> > +void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
> >  {
> >       if (host->cmd && host->cmd->mrq == mrq)
> >               host->cmd = NULL;
> > @@ -1565,15 +1576,17 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
> >       if (!sdhci_has_requests(host))
> >               sdhci_led_deactivate(host);
> >  }
> > +EXPORT_SYMBOL_GPL(__sdhci_finish_mrq);
> >
> > -static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
> > +void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
> >  {
> >       __sdhci_finish_mrq(host, mrq);
> >
> >       queue_work(host->complete_wq, &host->complete_work);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_finish_mrq);
> >
> > -static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
> > +void __sdhci_finish_data_common(struct sdhci_host *host)
> >  {
> >       struct mmc_command *data_cmd = host->data_cmd;
> >       struct mmc_data *data = host->data;
> > @@ -1607,6 +1620,14 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
> >               data->bytes_xfered = 0;
> >       else
> >               data->bytes_xfered = data->blksz * data->blocks;
> > +}
> > +EXPORT_SYMBOL_GPL(__sdhci_finish_data_common);
> > +
> > +static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
> > +{
> > +     struct mmc_data *data = host->data;
> > +
> > +     __sdhci_finish_data_common(host);
> >
> >       /*
> >        * Need to send CMD12 if -
> > @@ -1645,12 +1666,13 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
> >       }
> >  }
> >
> > -static void sdhci_finish_data(struct sdhci_host *host)
> > +void sdhci_finish_data(struct sdhci_host *host)
> >  {
> >       __sdhci_finish_data(host, false);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_finish_data);
>
> Also don't see sdhci_finish_data() being used.
> Please check what is being exported.
>

I will update it in the patch#18 of the new [PATCH V6].

> >
> > -static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
> > +bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
> >  {
> >       int flags;
> >       u32 mask;
> > @@ -1692,8 +1714,6 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
> >                       sdhci_prepare_data(host, cmd);
> >       }
> >
> > -     sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
> > -
> >       sdhci_set_transfer_mode(host, cmd);
> >
> >       if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
> > @@ -1737,13 +1757,16 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
> >       if (host->use_external_dma)
> >               sdhci_external_dma_pre_transfer(host, cmd);
> >
> > +     sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
>
> If this move of "sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT)"
> is intentional, it should be a separate patch.
>
> > +
> >       sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
> >
> >       return true;
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_send_command);
>
> It is not necessary to export sdhci_send_command()
>

I will update it in the patch#18 of the new [PATCH V6].

> >
> > -static bool sdhci_present_error(struct sdhci_host *host,
> > -                             struct mmc_command *cmd, bool present)
> > +bool sdhci_present_error(struct sdhci_host *host,
> > +                      struct mmc_command *cmd, bool present)
> >  {
> >       if (!present || host->flags & SDHCI_DEVICE_DEAD) {
> >               cmd->error = -ENOMEDIUM;
> > @@ -1752,6 +1775,7 @@ static bool sdhci_present_error(struct sdhci_host *host,
> >
> >       return false;
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_present_error);
> >
> >  static bool sdhci_send_command_retry(struct sdhci_host *host,
> >                                    struct mmc_command *cmd,
> > @@ -1815,7 +1839,7 @@ static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd)
> >       }
> >  }
> >
> > -static void sdhci_finish_command(struct sdhci_host *host)
> > +void sdhci_finish_command(struct sdhci_host *host)
> >  {
> >       struct mmc_command *cmd = host->cmd;
> >
> > @@ -1868,6 +1892,7 @@ static void sdhci_finish_command(struct sdhci_host *host)
> >                       __sdhci_finish_mrq(host, cmd->mrq);
> >       }
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_finish_command);
>
> It is not necessary to export sdhci_finish_command()
>

I will update it in the patch#18 of the new [PATCH V6].

> >
> >  static u16 sdhci_get_preset_value(struct sdhci_host *host)
> >  {
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> > index f049331bd0bc..1a9924e7972d 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -850,8 +850,25 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
> >       __sdhci_read_caps(host, NULL, NULL, NULL);
> >  }
> >
> > +bool sdhci_data_line_cmd(struct mmc_command *cmd);
> >  void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
> >  void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
> > +void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, unsigned long timeout);
> > +void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data);
> > +void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data);
> > +#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
> > +int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd);
> > +void sdhci_external_dma_release(struct sdhci_host *host);
> > +void __sdhci_external_dma_prepare_data(struct sdhci_host *host, struct mmc_command *cmd);
> > +void sdhci_external_dma_pre_transfer(struct sdhci_host *host, struct mmc_command *cmd);
> > +#endif
> > +bool sdhci_manual_cmd23(struct sdhci_host *host, struct mmc_request *mrq);
> > +void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
> > +void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
> > +void __sdhci_finish_data_common(struct sdhci_host *host);
> > +bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
> > +void sdhci_finish_command(struct sdhci_host *host);
> > +bool sdhci_present_error(struct sdhci_host *host, struct mmc_command *cmd, bool present);
> >  u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
> >                  unsigned int *actual_clock);
> >  void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 20/26] mmc: sdhci-uhs2: add irq() and others
  2022-11-01 17:15   ` Adrian Hunter
@ 2022-12-13  8:48     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:48 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:15 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > This is a UHS-II version of sdhci's request() operation.
> > It handles UHS-II related command interrupts and errors.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 237 ++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci-uhs2.h |   3 +
> >  drivers/mmc/host/sdhci.c      | 106 ++++++++-------
> >  drivers/mmc/host/sdhci.h      |   5 +
> >  4 files changed, 304 insertions(+), 47 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 41b089ccc200..883e18d849ad 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -11,6 +11,7 @@
> >   */
> >
> >  #include <linux/delay.h>
> > +#include <linux/dmaengine.h>
> >  #include <linux/ktime.h>
> >  #include <linux/module.h>
> >  #include <linux/mmc/mmc.h>
> > @@ -582,6 +583,12 @@ static inline void sdhci_external_dma_pre_transfer(struct sdhci_host *host,
> >                                                  struct mmc_command *cmd)
> >  {
> >  }
> > +
> > +static inline struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
> > +                                                       struct mmc_data *data)
> > +{
> > +     return NULL;
> > +}
> >  #endif /* CONFIG_MMC_SDHCI_EXTERNAL_DMA */
> >
> >  static void sdhci_uhs2_finish_data(struct sdhci_host *host)
> > @@ -940,6 +947,236 @@ static void sdhci_uhs2_finish_command(struct sdhci_host *host)
> >               __sdhci_finish_mrq(host, cmd->mrq);
> >  }
> >
> > +/*****************************************************************************\
> > + *                                                                           *
> > + * Request done                                                              *
> > + *                                                                           *
> > +\*****************************************************************************/
> > +
> > +static bool sdhci_uhs2_request_done(struct sdhci_host *host)
> > +{
> > +     unsigned long flags;
> > +     struct mmc_request *mrq;
> > +     int i;
> > +
> > +     /* FIXME: UHS2_INITIALIZED, instead? */
> > +     if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
> > +             return sdhci_request_done(host);
>
> Please do not put this check here, and sdhci_request_done()
> does not need to be exported.
>

I will update it in the patch#19 of the new [PATCH V6].

> > +
> > +     spin_lock_irqsave(&host->lock, flags);
> > +
> > +     for (i = 0; i < SDHCI_MAX_MRQS; i++) {
> > +             mrq = host->mrqs_done[i];
> > +             if (mrq)
> > +                     break;
> > +     }
> > +
> > +     if (!mrq) {
> > +             spin_unlock_irqrestore(&host->lock, flags);
> > +             return true;
> > +     }
> > +
> > +     /*
> > +      * Always unmap the data buffers if they were mapped by
> > +      * sdhci_prepare_data() whenever we finish with a request.
> > +      * This avoids leaking DMA mappings on error.
> > +      */
> > +     if (host->flags & SDHCI_REQ_USE_DMA) {
> > +             struct mmc_data *data = mrq->data;
> > +
> > +             if (host->use_external_dma && data &&
> > +                 (mrq->cmd->error || data->error)) {
> > +                     struct dma_chan *chan = sdhci_external_dma_channel(host, data);
> > +
> > +                     host->mrqs_done[i] = NULL;
> > +                     spin_unlock_irqrestore(&host->lock, flags);
> > +                     dmaengine_terminate_sync(chan);
> > +                     spin_lock_irqsave(&host->lock, flags);
> > +                     sdhci_set_mrq_done(host, mrq);
> > +             }
> > +
> > +             sdhci_request_done_dma(host, mrq);
> > +     }
> > +
> > +     /*
> > +      * The controller needs a reset of internal state machines
> > +      * upon error conditions.
> > +      */
> > +     if (sdhci_needs_reset(host, mrq)) {
> > +             /*
> > +              * Do not finish until command and data lines are available for
> > +              * reset. Note there can only be one other mrq, so it cannot
> > +              * also be in mrqs_done, otherwise host->cmd and host->data_cmd
> > +              * would both be null.
> > +              */
> > +             if (host->cmd || host->data_cmd) {
> > +                     spin_unlock_irqrestore(&host->lock, flags);
> > +                     return true;
> > +             }
> > +
> > +             /* Some controllers need this kick or reset won't work here */
> > +             if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
> > +                     /* This is to force an update */
> > +                     host->ops->set_clock(host, host->clock);
> > +
> > +             host->ops->uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD);
> > +             host->pending_reset = false;
> > +     }
> > +
> > +     host->mrqs_done[i] = NULL;
> > +
> > +     spin_unlock_irqrestore(&host->lock, flags);
> > +
> > +     if (host->ops->request_done)
> > +             host->ops->request_done(host, mrq);
> > +     else
> > +             mmc_request_done(host->mmc, mrq);
> > +
> > +     return false;
> > +}
> > +
> > +static void sdhci_uhs2_complete_work(struct work_struct *work)
> > +{
> > +     struct sdhci_host *host = container_of(work, struct sdhci_host,
> > +                                            complete_work);
>
> Put a check for UHS2 mode here:
>
>         if (sdhci_uhs2_mode(host)) {
>                 sdhci_complete_work(work);
>                 return;
>         }
>

I will update it in the patch#19 of the new [PATCH V6].

> > +
> > +     while (!sdhci_uhs2_request_done(host))
> > +             ;
> > +}
> > +
> > +/*****************************************************************************\
> > + *                                                                           *
> > + * Interrupt handling                                                        *
> > + *                                                                           *
> > +\*****************************************************************************/
> > +
> > +static void __sdhci_uhs2_irq(struct sdhci_host *host, u32 uhs2mask)
> > +{
> > +     struct mmc_command *cmd = host->cmd;
> > +
> > +     DBG("*** %s got UHS2 error interrupt: 0x%08x\n",
> > +         mmc_hostname(host->mmc), uhs2mask);
> > +
> > +     if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_CMD_MASK) {
> > +             if (!host->cmd) {
> > +                     pr_err("%s: Got cmd interrupt 0x%08x but no cmd.\n",
> > +                            mmc_hostname(host->mmc),
> > +                            (unsigned int)uhs2mask);
> > +                     sdhci_dumpregs(host);
> > +                     return;
> > +             }
> > +             host->cmd->error = -EILSEQ;
> > +             if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT)
> > +                     host->cmd->error = -ETIMEDOUT;
> > +     }
> > +
> > +     if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_DATA_MASK) {
> > +             if (!host->data) {
> > +                     pr_err("%s: Got data interrupt 0x%08x but no data.\n",
> > +                            mmc_hostname(host->mmc),
> > +                            (unsigned int)uhs2mask);
> > +                     sdhci_dumpregs(host);
> > +                     return;
> > +             }
> > +
> > +             if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT) {
> > +                     pr_err("%s: Got deadlock timeout interrupt 0x%08x\n",
> > +                            mmc_hostname(host->mmc),
> > +                            (unsigned int)uhs2mask);
> > +                     host->data->error = -ETIMEDOUT;
> > +             } else if (uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_ADMA) {
> > +                     pr_err("%s: ADMA error = 0x %x\n",
> > +                            mmc_hostname(host->mmc),
> > +                            sdhci_readb(host, SDHCI_ADMA_ERROR));
> > +                     host->data->error = -EIO;
> > +             } else {
> > +                     host->data->error = -EILSEQ;
> > +             }
> > +     }
> > +
> > +     if (host->data && host->data->error)
> > +             sdhci_uhs2_finish_data(host);
> > +     else
> > +             sdhci_finish_mrq(host, cmd->mrq);
> > +}
> > +
> > +u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask)
> > +{
> > +     u32 mask = intmask, uhs2mask;
> > +
> > +     if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
> > +             goto out;
> > +
> > +     if (intmask & SDHCI_INT_ERROR) {
> > +             uhs2mask = sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS);
> > +             if (!(uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_MASK))
> > +                     goto cmd_irq;
> > +
> > +             /* Clear error interrupts */
> > +             sdhci_writel(host, uhs2mask & SDHCI_UHS2_ERR_INT_STATUS_MASK,
> > +                          SDHCI_UHS2_ERR_INT_STATUS);
> > +
> > +             /* Handle error interrupts */
> > +             __sdhci_uhs2_irq(host, uhs2mask);
> > +
> > +             /* Caller, shdci_irq(), doesn't have to care UHS-2 errors */
> > +             intmask &= ~SDHCI_INT_ERROR;
> > +             mask &= SDHCI_INT_ERROR;
> > +     }
> > +
> > +cmd_irq:
> > +     if (intmask & SDHCI_INT_CMD_MASK) {
> > +             /* Clear command interrupt */
> > +             sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, SDHCI_INT_STATUS);
> > +
> > +             /* Handle command interrupt */
> > +             if (intmask & SDHCI_INT_RESPONSE)
> > +                     sdhci_uhs2_finish_command(host);
> > +
> > +             /* Caller, shdci_irq(), doesn't have to care UHS-2 command */
> > +             intmask &= ~SDHCI_INT_CMD_MASK;
> > +             mask &= SDHCI_INT_CMD_MASK;
> > +     }
> > +
> > +     /* Clear already-handled interrupts. */
> > +     sdhci_writel(host, mask, SDHCI_INT_STATUS);
> > +
> > +out:
> > +     return intmask;
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_irq);
> > +
> > +static irqreturn_t sdhci_uhs2_thread_irq(int irq, void *dev_id)
> > +{
> > +     struct sdhci_host *host = dev_id;
> > +     struct mmc_command *cmd;
> > +     unsigned long flags;
> > +     u32 isr;
>
> Put a check for UHS2 mode here:
>
>         if (sdhci_uhs2_mode(host))
>                 return sdhci_uhs2_thread_irq(irq, dev_id);
>

I will update it in the patch#19 of the new [PATCH V6].

> > +
> > +     while (!sdhci_uhs2_request_done(host))
> > +             ;
> > +
> > +     spin_lock_irqsave(&host->lock, flags);
> > +
> > +     isr = host->thread_isr;
> > +     host->thread_isr = 0;
> > +
> > +     cmd = host->deferred_cmd;
> > +     if (cmd && !sdhci_uhs2_send_command_retry(host, cmd, flags))
> > +             sdhci_finish_mrq(host, cmd->mrq);
> > +
> > +     spin_unlock_irqrestore(&host->lock, flags);
> > +
> > +     if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
> > +             struct mmc_host *mmc = host->mmc;
> > +
> > +             mmc->ops->card_event(mmc);
> > +             mmc_detect_change(mmc, msecs_to_jiffies(200));
> > +     }
> > +
> > +     return IRQ_HANDLED;
> > +}
> > +
> >  void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
> >  {
> >       struct sdhci_host *host = mmc_priv(mmc);
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > index 23368448ccd4..d32a8602d045 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.h
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -217,5 +217,8 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
> >                         unsigned short vdd);
> >  void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
> >  void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
> > +void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq);
> > +int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
> > +u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask);
> >
> >  #endif /* __SDHCI_UHS2_H */
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index 407169468927..e44ede049559 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -1268,11 +1268,12 @@ static int sdhci_external_dma_init(struct sdhci_host *host)
> >       return ret;
> >  }
> >
> > -static struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
> > -                                                struct mmc_data *data)
> > +struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host,
> > +                                         struct mmc_data *data)
> >  {
> >       return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan;
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_external_dma_channel);
> >
> >  int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd)
> >  {
> > @@ -1522,7 +1523,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
> >       sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
> >  }
> >
> > -static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
> > +bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
> >  {
> >       return (!(host->flags & SDHCI_DEVICE_DEAD) &&
> >               ((mrq->cmd && mrq->cmd->error) ||
> > @@ -1530,8 +1531,9 @@ static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
> >                (mrq->data && mrq->data->stop && mrq->data->stop->error) ||
> >                (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_needs_reset);
> >
> > -static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
> > +void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
> >  {
> >       int i;
> >
> > @@ -1551,6 +1553,7 @@ static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
> >
> >       WARN_ON(i >= SDHCI_MAX_MRQS);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_set_mrq_done);
> >
> >  void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
> >  {
> > @@ -3103,7 +3106,56 @@ static const struct mmc_host_ops sdhci_ops = {
> >   *                                                                           *
> >  \*****************************************************************************/
> >
> > -static bool sdhci_request_done(struct sdhci_host *host)
> > +void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq)
> > +{
> > +     struct mmc_data *data = mrq->data;
> > +
> > +     if (data && data->host_cookie == COOKIE_MAPPED) {
> > +             if (host->bounce_buffer) {
> > +                     /*
> > +                      * On reads, copy the bounced data into the
> > +                      * sglist
> > +                      */
> > +                     if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
> > +                             unsigned int length = data->bytes_xfered;
> > +
> > +                             if (length > host->bounce_buffer_size) {
> > +                                     pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
> > +                                            mmc_hostname(host->mmc),
> > +                                            host->bounce_buffer_size,
> > +                                            data->bytes_xfered);
> > +                                     /* Cap it down and continue */
> > +                                     length = host->bounce_buffer_size;
> > +                             }
> > +                             dma_sync_single_for_cpu(
> > +                                     host->mmc->parent,
> > +                                     host->bounce_addr,
> > +                                     host->bounce_buffer_size,
> > +                                     DMA_FROM_DEVICE);
> > +                             sg_copy_from_buffer(data->sg,
> > +                                     data->sg_len,
> > +                                     host->bounce_buffer,
> > +                                     length);
> > +                     } else {
> > +                             /* No copying, just switch ownership */
> > +                             dma_sync_single_for_cpu(
> > +                                     host->mmc->parent,
> > +                                     host->bounce_addr,
> > +                                     host->bounce_buffer_size,
> > +                                     mmc_get_dma_dir(data));
> > +                     }
> > +             } else {
> > +                     /* Unmap the raw data */
> > +                     dma_unmap_sg(mmc_dev(host->mmc), data->sg,
> > +                                  data->sg_len,
> > +                                  mmc_get_dma_dir(data));
> > +             }
> > +             data->host_cookie = COOKIE_UNMAPPED;
> > +     }
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_request_done_dma);
> > +
> > +bool sdhci_request_done(struct sdhci_host *host)
> >  {
> >       unsigned long flags;
> >       struct mmc_request *mrq;
> > @@ -3167,48 +3219,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
> >                       sdhci_set_mrq_done(host, mrq);
> >               }
> >
> > -             if (data && data->host_cookie == COOKIE_MAPPED) {
> > -                     if (host->bounce_buffer) {
> > -                             /*
> > -                              * On reads, copy the bounced data into the
> > -                              * sglist
> > -                              */
> > -                             if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
> > -                                     unsigned int length = data->bytes_xfered;
> > -
> > -                                     if (length > host->bounce_buffer_size) {
> > -                                             pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
> > -                                                    mmc_hostname(host->mmc),
> > -                                                    host->bounce_buffer_size,
> > -                                                    data->bytes_xfered);
> > -                                             /* Cap it down and continue */
> > -                                             length = host->bounce_buffer_size;
> > -                                     }
> > -                                     dma_sync_single_for_cpu(
> > -                                             mmc_dev(host->mmc),
> > -                                             host->bounce_addr,
> > -                                             host->bounce_buffer_size,
> > -                                             DMA_FROM_DEVICE);
> > -                                     sg_copy_from_buffer(data->sg,
> > -                                             data->sg_len,
> > -                                             host->bounce_buffer,
> > -                                             length);
> > -                             } else {
> > -                                     /* No copying, just switch ownership */
> > -                                     dma_sync_single_for_cpu(
> > -                                             mmc_dev(host->mmc),
> > -                                             host->bounce_addr,
> > -                                             host->bounce_buffer_size,
> > -                                             mmc_get_dma_dir(data));
> > -                             }
> > -                     } else {
> > -                             /* Unmap the raw data */
> > -                             dma_unmap_sg(mmc_dev(host->mmc), data->sg,
> > -                                          data->sg_len,
> > -                                          mmc_get_dma_dir(data));
> > -                     }
> > -                     data->host_cookie = COOKIE_UNMAPPED;
> > -             }
> > +             sdhci_request_done_dma(host, mrq);
> >       }
> >
> >       host->mrqs_done[i] = NULL;
> > @@ -3222,6 +3233,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
> >
> >       return false;
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_request_done);
> >
> >  static void sdhci_complete_work(struct work_struct *work)
> >  {
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> > index 1a9924e7972d..49de8fdbd7a3 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -861,8 +861,11 @@ int sdhci_external_dma_setup(struct sdhci_host *host, struct mmc_command *cmd);
> >  void sdhci_external_dma_release(struct sdhci_host *host);
> >  void __sdhci_external_dma_prepare_data(struct sdhci_host *host, struct mmc_command *cmd);
> >  void sdhci_external_dma_pre_transfer(struct sdhci_host *host, struct mmc_command *cmd);
> > +struct dma_chan *sdhci_external_dma_channel(struct sdhci_host *host, struct mmc_data *data);
> >  #endif
> >  bool sdhci_manual_cmd23(struct sdhci_host *host, struct mmc_request *mrq);
> > +bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq);
> > +void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq);
> >  void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
> >  void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq);
> >  void __sdhci_finish_data_common(struct sdhci_host *host);
> > @@ -895,6 +898,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
> >  int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
> >                                     struct mmc_ios *ios);
> >  void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
> > +void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq);
> > +bool sdhci_request_done(struct sdhci_host *host);
> >  void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
> >                          dma_addr_t addr, int len, unsigned int cmd);
> >
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 21/26] mmc: sdhci-uhs2: add add_host() and others to set up the driver
  2022-11-01 17:15   ` Adrian Hunter
@ 2022-12-13  8:48     ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-12-13  8:48 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: ulf.hansson, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih, Ben Chuang

Hi, Adrian

On Wed, Nov 2, 2022 at 1:15 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 19/10/22 14:06, Victor Shih wrote:
> > This is a UHS-II version of sdhci's add_host/remove_host operation.
> > Any sdhci drivers which are capable of handling UHS-II cards must
> > call those functions instead of the corresponding sdhci's.
> >
> > Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> > Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 172 ++++++++++++++++++++++++++++++++++
> >  drivers/mmc/host/sdhci-uhs2.h |   2 +
> >  drivers/mmc/host/sdhci.c      |  21 +++--
> >  drivers/mmc/host/sdhci.h      |   9 ++
> >  4 files changed, 197 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 883e18d849ad..eb3241bf95a2 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -15,6 +15,7 @@
> >  #include <linux/ktime.h>
> >  #include <linux/module.h>
> >  #include <linux/mmc/mmc.h>
> > +#include <linux/regulator/consumer.h>
> >
> >  #include "sdhci.h"
> >  #include "sdhci-uhs2.h"
> > @@ -1177,6 +1178,177 @@ static irqreturn_t sdhci_uhs2_thread_irq(int irq, void *dev_id)
> >       return IRQ_HANDLED;
> >  }
> >
> > +/*****************************************************************************\
> > + *
> > + * Device allocation/registration                                            *
> > + *                                                                           *
> > +\*****************************************************************************/
> > +
> > +static int __sdhci_uhs2_add_host_v4(struct sdhci_host *host, u32 caps1)
> > +{
> > +     struct mmc_host *mmc;
> > +     u32 max_current_caps2;
> > +
> > +     if (host->version < SDHCI_SPEC_400)
> > +             return 0;
> > +
> > +     mmc = host->mmc;
> > +
> > +     /* Support UHS2 */
> > +     if (caps1 & SDHCI_SUPPORT_UHS2)
> > +             mmc->caps2 |= MMC_CAP2_SD_UHS2;
> > +
> > +     max_current_caps2 = sdhci_readl(host, SDHCI_MAX_CURRENT_1);
> > +
> > +     if ((caps1 & SDHCI_SUPPORT_VDD2_180) &&
> > +         !max_current_caps2 &&
> > +         !IS_ERR(mmc->supply.vmmc2)) {
> > +             /* UHS2 - VDD2 */
> > +             int curr = regulator_get_current_limit(mmc->supply.vmmc2);
> > +
> > +             if (curr > 0) {
> > +                     /* convert to SDHCI_MAX_CURRENT format */
> > +                     curr = curr / 1000;  /* convert to mA */
> > +                     curr = curr / SDHCI_MAX_CURRENT_MULTIPLIER;
> > +                     curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
> > +                     max_current_caps2 = curr;
> > +             }
> > +     }
> > +
> > +     if (caps1 & SDHCI_SUPPORT_VDD2_180) {
> > +             mmc->ocr_avail_uhs2 |= MMC_VDD2_165_195;
> > +             /*
> > +              * UHS2 doesn't require this. Only UHS-I bus needs to set
> > +              * max current.
> > +              */
> > +             mmc->max_current_180_vdd2 = (max_current_caps2 &
> > +                                     SDHCI_MAX_CURRENT_VDD2_180_MASK) *
> > +                                     SDHCI_MAX_CURRENT_MULTIPLIER;
> > +     } else {
> > +             mmc->caps2 &= ~MMC_CAP2_SD_UHS2;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int sdhci_uhs2_host_ops_init(struct sdhci_host *host);
> > +
> > +static int __sdhci_uhs2_add_host(struct sdhci_host *host)
>
> The only thing this does differently is to use
> sdhci_uhs2_complete_work() and sdhci_uhs2_thread_irq().
> Better to add variables in struct sdhci_host, set them in
> sdhci_alloc_host:
>
>         host->complete_work_fn = sdhci_complete_work;
>         host->thread_irq_fn = sdhci_thread_irq;
>
> override them in sdhci_uhs2_add_host():
>
>         host->complete_work_fn = sdhci_uhs2_complete_work;
>         host->thread_irq_fn = sdhci_uhs2_thread_irq;
>
> and use them in __sdhci_add_host().
>

I will update it in the patch#20 of the new [PATCH V6].

> > +{
> > +     unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI;
> > +     struct mmc_host *mmc = host->mmc;
> > +     int ret;
> > +
> > +     if ((mmc->caps2 & MMC_CAP2_CQE) &&
> > +         (host->quirks & SDHCI_QUIRK_BROKEN_CQE)) {
> > +             mmc->caps2 &= ~MMC_CAP2_CQE;
> > +             mmc->cqe_ops = NULL;
> > +     }
> > +
> > +     /* overwrite ops */
> > +     if (mmc->caps2 & MMC_CAP2_SD_UHS2)
> > +             sdhci_uhs2_host_ops_init(host);
>
> Do in sdhci_uhs2_add_host() instead of here
>

I will update it in the patch#20 of the new [PATCH V6].

> > +
> > +     host->complete_wq = alloc_workqueue("sdhci", flags, 0);
> > +     if (!host->complete_wq)
> > +             return -ENOMEM;
> > +
> > +     INIT_WORK(&host->complete_work, sdhci_uhs2_complete_work);
> > +
> > +     timer_setup(&host->timer, sdhci_timeout_timer, 0);
> > +     timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
> > +
> > +     init_waitqueue_head(&host->buf_ready_int);
> > +
> > +     sdhci_init(host, 0);
> > +
> > +     ret = request_threaded_irq(host->irq, sdhci_irq,
> > +                                sdhci_uhs2_thread_irq,
> > +                                IRQF_SHARED, mmc_hostname(mmc), host);
> > +     if (ret) {
> > +             pr_err("%s: Failed to request IRQ %d: %d\n",
> > +                    mmc_hostname(mmc), host->irq, ret);
> > +             goto unwq;
> > +     }
> > +
> > +     ret = mmc_add_host(mmc);
> > +             if (ret)
> > +                     return 1;
> > +
> > +     pr_info("%s: SDHCI controller on %s [%s] using %s\n",
> > +             mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
> > +             host->use_external_dma ? "External DMA" :
> > +             (host->flags & SDHCI_USE_ADMA) ?
> > +             (host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" :
> > +             (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
> > +
> > +     sdhci_enable_card_detection(host);
> > +
> > +     return 0;
> > +
> > +unwq:
> > +     destroy_workqueue(host->complete_wq);
> > +
> > +     return ret;
> > +}
> > +
> > +static void __sdhci_uhs2_remove_host(struct sdhci_host *host, int dead)
> > +{
> > +     if (!(host->mmc) || !(host->mmc->flags & MMC_UHS2_SUPPORT))
> > +             return;
>
> Just use sdhci_uhs2_mode() i.e
>
>         if (!sdhci_uhs2_mode(host))
>                 return;
>

I will update it in the patch#20 of the new [PATCH V6].

> > +
> > +     if (!dead)
> > +             host->ops->uhs2_reset(host, SDHCI_UHS2_SW_RESET_FULL);
> > +
> > +     sdhci_writel(host, 0, SDHCI_UHS2_ERR_INT_STATUS_EN);
> > +     sdhci_writel(host, 0, SDHCI_UHS2_ERR_INT_SIG_EN);
>
> Do not write registers if it is dead.
>

I will update it in the patch#20 of the new [PATCH V6].

> > +     host->mmc->flags &= ~MMC_UHS2_INITIALIZED;
>
> Not the drivers job to change host->mmc->flags
>

I will update it in the patch#20 of the new [PATCH V6].

> > +}
> > +
> > +int sdhci_uhs2_add_host(struct sdhci_host *host)
> > +{
> > +     struct mmc_host *mmc = host->mmc;
> > +     int ret;
> > +
> > +     ret = sdhci_setup_host(host);
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (host->version >= SDHCI_SPEC_400) {
> > +             ret = __sdhci_uhs2_add_host_v4(host, host->caps1);
> > +             if (ret)
> > +                     goto cleanup;
> > +     }
> > +
> > +     if ((mmc->caps2 & MMC_CAP2_SD_UHS2) && !host->v4_mode)
> > +             /* host doesn't want to enable UHS2 support */
> > +             /* FIXME: Do we have to do some cleanup here? */
> > +             mmc->caps2 &= ~MMC_CAP2_SD_UHS2;
> > +
> > +     ret = __sdhci_uhs2_add_host(host);
> > +     if (ret)
> > +             goto cleanup2;
> > +
> > +     return 0;
> > +
> > +cleanup2:
> > +     if (host->version >= SDHCI_SPEC_400)
> > +             __sdhci_uhs2_remove_host(host, 0);
> > +cleanup:
> > +     sdhci_cleanup_host(host);
> > +
> > +     return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_add_host);
> > +
> > +void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead)
> > +{
> > +     __sdhci_uhs2_remove_host(host, dead);
> > +
> > +     sdhci_remove_host(host, dead);
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_remove_host);
> > +
> >  void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
> >  {
> >       struct sdhci_host *host = mmc_priv(mmc);
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > index d32a8602d045..54241a7adfca 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.h
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -220,5 +220,7 @@ void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
> >  void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq);
> >  int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
> >  u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask);
> > +int sdhci_uhs2_add_host(struct sdhci_host *host);
> > +void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead);
> >
> >  #endif /* __SDHCI_UHS2_H */
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index e44ede049559..df433ad0ba66 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -173,10 +173,11 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
> >       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
> >  }
> >
> > -static void sdhci_enable_card_detection(struct sdhci_host *host)
> > +void sdhci_enable_card_detection(struct sdhci_host *host)
> >  {
> >       sdhci_set_card_detection(host, true);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_enable_card_detection);
> >
> >  static void sdhci_disable_card_detection(struct sdhci_host *host)
> >  {
> > @@ -365,7 +366,7 @@ static void sdhci_config_dma(struct sdhci_host *host)
> >       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
> >  }
> >
> > -static void sdhci_init(struct sdhci_host *host, int soft)
> > +void sdhci_init(struct sdhci_host *host, int soft)
> >  {
> >       struct mmc_host *mmc = host->mmc;
> >       unsigned long flags;
> > @@ -390,6 +391,7 @@ static void sdhci_init(struct sdhci_host *host, int soft)
> >               mmc->ops->set_ios(mmc, &mmc->ios);
> >       }
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_init);
> >
> >  static void sdhci_reinit(struct sdhci_host *host)
> >  {
> > @@ -454,7 +456,7 @@ static void sdhci_led_control(struct led_classdev *led,
> >       spin_unlock_irqrestore(&host->lock, flags);
> >  }
> >
> > -static int sdhci_led_register(struct sdhci_host *host)
> > +int sdhci_led_register(struct sdhci_host *host)
> >  {
> >       struct mmc_host *mmc = host->mmc;
> >
> > @@ -471,14 +473,16 @@ static int sdhci_led_register(struct sdhci_host *host)
> >
> >       return led_classdev_register(mmc_dev(mmc), &host->led);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_led_register);
> >
> > -static void sdhci_led_unregister(struct sdhci_host *host)
> > +void sdhci_led_unregister(struct sdhci_host *host)
> >  {
> >       if (host->quirks & SDHCI_QUIRK_NO_LED)
> >               return;
> >
> >       led_classdev_unregister(&host->led);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_led_unregister);
> >
> >  static inline void sdhci_led_activate(struct sdhci_host *host)
> >  {
> > @@ -3244,7 +3248,7 @@ static void sdhci_complete_work(struct work_struct *work)
> >               ;
> >  }
> >
> > -static void sdhci_timeout_timer(struct timer_list *t)
> > +void sdhci_timeout_timer(struct timer_list *t)
> >  {
> >       struct sdhci_host *host;
> >       unsigned long flags;
> > @@ -3265,8 +3269,9 @@ static void sdhci_timeout_timer(struct timer_list *t)
> >
> >       spin_unlock_irqrestore(&host->lock, flags);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_timeout_timer);
> >
> > -static void sdhci_timeout_data_timer(struct timer_list *t)
> > +void sdhci_timeout_data_timer(struct timer_list *t)
> >  {
> >       struct sdhci_host *host;
> >       unsigned long flags;
> > @@ -3297,6 +3302,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t)
> >
> >       spin_unlock_irqrestore(&host->lock, flags);
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_timeout_data_timer);
> >
> >  /*****************************************************************************\
> >   *                                                                           *
> > @@ -3560,7 +3566,7 @@ static inline bool sdhci_defer_done(struct sdhci_host *host,
> >               data->host_cookie == COOKIE_MAPPED);
> >  }
> >
> > -static irqreturn_t sdhci_irq(int irq, void *dev_id)
> > +irqreturn_t sdhci_irq(int irq, void *dev_id)
> >  {
> >       struct mmc_request *mrqs_done[SDHCI_MAX_MRQS] = {0};
> >       irqreturn_t result = IRQ_NONE;
> > @@ -3701,6 +3707,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
> >
> >       return result;
> >  }
> > +EXPORT_SYMBOL_GPL(sdhci_irq);
>
> This doesn't need to be exported when __sdhci_uhs2_add_host()
> isn't needed.
>

I will update it in the patch#20 of the new [PATCH V6].

> >
> >  static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
> >  {
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> > index 49de8fdbd7a3..0970fe392d49 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -851,8 +851,14 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
> >  }
> >
> >  bool sdhci_data_line_cmd(struct mmc_command *cmd);
> > +void sdhci_enable_card_detection(struct sdhci_host *host);
> >  void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
> >  void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
> > +void sdhci_init(struct sdhci_host *host, int soft);
> > +#if IS_REACHABLE(CONFIG_LEDS_CLASS)
> > +int sdhci_led_register(struct sdhci_host *host);
> > +void sdhci_led_unregister(struct sdhci_host *host);
> > +#endif
>
> Don't support LEDs.  Just set:
>
>         /* LED support not implemented for UHS2 */
>         host->quirks |= SDHCI_QUIRK_NO_LED;
>

I will update it in the patch#20 of the new [PATCH V6].

> >  void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, unsigned long timeout);
> >  void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data);
> >  void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data);
> > @@ -900,6 +906,9 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
> >  void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
> >  void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq);
> >  bool sdhci_request_done(struct sdhci_host *host);
> > +void sdhci_timeout_timer(struct timer_list *t);
> > +void sdhci_timeout_data_timer(struct timer_list *t);
> > +irqreturn_t sdhci_irq(int irq, void *dev_id);
> >  void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
> >                          dma_addr_t addr, int len, unsigned int cmd);
> >
>

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 00/26] Add support UHS-II for GL9755
  2022-10-17 11:31 ` Ulf Hansson
@ 2022-10-19 11:02   ` Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-19 11:02 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: adrian.hunter, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih

Hi, Ulf

Ulf Hansson <ulf.hansson@linaro.org> 於 2022年10月17日 週一 晚上7:32寫道:

>
> Hi Victor,
>
> On Fri, 14 Oct 2022 at 13:47, Victor Shih <victorshihgli@gmail.com> wrote:
> >
> > Summary
> > =======
> > These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
> >
> > About UHS-II, roughly deal with the following three parts:
> > 1) A UHS-II detection and initialization:
> > - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
> >   [2]).
> > - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> > - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
> >   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
> >   Setup Sequence.
> >
> > 2) Send Legacy SD command through SD-TRAN
> > - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
> >   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
> >   Types and Format Overview[3]).
> > - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
> >   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
> >
> > 3) UHS-II Interrupt
> > - Except for UHS-II error interrupts, most interrupts share the original
> >   interrupt registers.
> >
> > Patch structure
> > ===============
> > patch#1-#6:  for core
> > patch#7-#25: for sdhci
> > patch#26:    for GL9755
> >
> > Changes in v5 (Oct. 14, 2022)
> > * rebased to linux-v6.0.
>
> You sent a v5 on Oct 14 and then this one (v5 again) today. Why? What
> is the difference?

I left out two files in the October 14th edition, so I added it back
in the October 17th edition, but I forgot to change the date of the
cover-letter.

>
> Moreover, as v6.1-rc1 is now available, my next branch will be based
> on that. Can you please rebase the series on top of my next branch -
> or at least use the latest available "rc", when you test and submit?

Ok, I will follow your advice.
I will rebase to the linux-v6.1-rc1 in your next branch.

>
> > * according to the guidance and overall architecture provided
> >   by Ulf Hansson, Ben Chuang and Jason Lai to implement the
> >   UHS-2 Core function based on the patches of the [V4,0/6]
> >   Preparations to support SD UHS-II cards[5].
> > * according to the guidance and comments provided by
> >   Adrian Hunter, Ben Chuang and AKASHI Takahiro to implement
> >   the UHS-2 Host function based on the patches of the
> >   [RFC,v3.1,00/27] Add support UHS-II for GL9755[4].
> > * implement the necessary function to let the UHS-2 Core/Host
> >   work properly.
> > * fix most of checkpatch warnings/errors
> >
> > Reference
> > =========
> > [1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
> > [2] SD Host Controller Simplified Specification 4.20
> > [3] UHS-II Simplified Addendum 1.02
> > [4] https://patchwork.kernel.org/project/linux-mmc/cover/20201106022726.19831-1-takahiro.akashi@linaro.org/
> > [5] https://patchwork.kernel.org/project/linux-mmc/cover/20220418115833.10738-1-jasonlai.genesyslogic@gmail.com/
>
> Another general question, I assume you intend to move this forward
> instead of Jason Lai, right?

Yes. Please let me know if I have any mistakes.

>
> Kind regards
> Uffe

Thanks, Victor Shih

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH V5 00/26] Add support UHS-II for GL9755
  2022-10-14 11:45 Victor Shih
@ 2022-10-17 11:31 ` Ulf Hansson
  2022-10-19 11:02   ` Victor Shih
  0 siblings, 1 reply; 72+ messages in thread
From: Ulf Hansson @ 2022-10-17 11:31 UTC (permalink / raw)
  To: Victor Shih
  Cc: adrian.hunter, linux-mmc, linux-kernel, benchuanggli, HL.Liu,
	Greg.tu, takahiro.akashi, dlunev, Victor Shih

Hi Victor,

On Fri, 14 Oct 2022 at 13:47, Victor Shih <victorshihgli@gmail.com> wrote:
>
> Summary
> =======
> These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
>
> About UHS-II, roughly deal with the following three parts:
> 1) A UHS-II detection and initialization:
> - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
>   [2]).
> - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
>   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
>   Setup Sequence.
>
> 2) Send Legacy SD command through SD-TRAN
> - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
>   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
>   Types and Format Overview[3]).
> - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
>   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
>
> 3) UHS-II Interrupt
> - Except for UHS-II error interrupts, most interrupts share the original
>   interrupt registers.
>
> Patch structure
> ===============
> patch#1-#6:  for core
> patch#7-#25: for sdhci
> patch#26:    for GL9755
>
> Changes in v5 (Oct. 14, 2022)
> * rebased to linux-v6.0.

You sent a v5 on Oct 14 and then this one (v5 again) today. Why? What
is the difference?

Moreover, as v6.1-rc1 is now available, my next branch will be based
on that. Can you please rebase the series on top of my next branch -
or at least use the latest available "rc", when you test and submit?

> * according to the guidance and overall architecture provided
>   by Ulf Hansson, Ben Chuang and Jason Lai to implement the
>   UHS-2 Core function based on the patches of the [V4,0/6]
>   Preparations to support SD UHS-II cards[5].
> * according to the guidance and comments provided by
>   Adrian Hunter, Ben Chuang and AKASHI Takahiro to implement
>   the UHS-2 Host function based on the patches of the
>   [RFC,v3.1,00/27] Add support UHS-II for GL9755[4].
> * implement the necessary function to let the UHS-2 Core/Host
>   work properly.
> * fix most of checkpatch warnings/errors
>
> Reference
> =========
> [1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
> [2] SD Host Controller Simplified Specification 4.20
> [3] UHS-II Simplified Addendum 1.02
> [4] https://patchwork.kernel.org/project/linux-mmc/cover/20201106022726.19831-1-takahiro.akashi@linaro.org/
> [5] https://patchwork.kernel.org/project/linux-mmc/cover/20220418115833.10738-1-jasonlai.genesyslogic@gmail.com/

Another general question, I assume you intend to move this forward
instead of Jason Lai, right?

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH V5 00/26] Add support UHS-II for GL9755
@ 2022-10-17  9:11 Victor Shih
  0 siblings, 0 replies; 72+ messages in thread
From: Victor Shih @ 2022-10-17  9:11 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih

Summary
=======
These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.

About UHS-II, roughly deal with the following three parts:
1) A UHS-II detection and initialization:
- Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
  [2]).
- Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
- In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
  3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
  Setup Sequence.

2) Send Legacy SD command through SD-TRAN
- Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
  compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
  Types and Format Overview[3]).
- Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
  CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).

3) UHS-II Interrupt
- Except for UHS-II error interrupts, most interrupts share the original
  interrupt registers.

Patch structure
===============
patch#1-#6:  for core
patch#7-#25: for sdhci
patch#26:    for GL9755

Changes in v5 (Oct. 14, 2022)
* rebased to linux-v6.0.
* according to the guidance and overall architecture provided 
  by Ulf Hansson, Ben Chuang and Jason Lai to implement the
  UHS-2 Core function based on the patches of the [V4,0/6] 
  Preparations to support SD UHS-II cards[5].
* according to the guidance and comments provided by 
  Adrian Hunter, Ben Chuang and AKASHI Takahiro to implement 
  the UHS-2 Host function based on the patches of the 
  [RFC,v3.1,00/27] Add support UHS-II for GL9755[4].
* implement the necessary function to let the UHS-2 Core/Host
  work properly.
* fix most of checkpatch warnings/errors

Reference
=========
[1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
[2] SD Host Controller Simplified Specification 4.20
[3] UHS-II Simplified Addendum 1.02
[4] https://patchwork.kernel.org/project/linux-mmc/cover/20201106022726.19831-1-takahiro.akashi@linaro.org/
[5] https://patchwork.kernel.org/project/linux-mmc/cover/20220418115833.10738-1-jasonlai.genesyslogic@gmail.com/
 
----------------- original cover letter from v3.1 -----------------
This is an interim snapshot of our next version, v4, for enabling
UHS-II on MMC/SD.

It is focused on 'sdhci' side to address Adrian's comments regarding
"modularising" sdhci-uhs2.c.
The whole aim of this version is to get early feedback from Adrian (and
others) on this issue. Without any consensus about the code structure,
it would make little sense to go further ahead on sdhci side.
(Actually, Adrian has made no comments other than "modularising" so far.)

I heavily reworked/refactored sdhci-uhs2.c and re-organised the patch
set to meet what I believe Adrian expects; no UHS-II related code in
Legacy (UHS-I) code or sdhci.c.

Nevertheless, almost of all changes I made are trivial and straightforward
in this direction, and I believe that there is no logic changed since v3
except sdhci_uhs2_irq(), as ops->irq hook, where we must deal with UHS-II
command sequences in addition to UHS-II errors. So I added extra handlings.

I admit that there is plenty of room for improvements (for example,
handling host->flags), but again the focal point here is how sdhci-uhs2.c
should be built as a module.

Please review this series (particularly Patch#8-#26 and #27) from this
viewpoint in the first place.
(Ben is working on 'host' side but there is no change on 'host' side
in this submission except a minor tweak.)

Thanks,
-Takahiro Akashi

------ original cover letter from v3 ------
Summary
=======
These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.

About UHS-II, roughly deal with the following three parts:
1) A UHS-II detection and initialization:
- Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
  [2]).
- Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
- In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
  3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
  Setup Sequence.

2) Send Legacy SD command through SD-TRAN
- Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
  compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
  Types and Format Overview[3]).
- Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
  CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).

3) UHS-II Interrupt
- Except for UHS-II error interrupts, most interrupts share the original
  interrupt registers.

Patch structure
===============
patch#1-#7: for core
patch#8-#17: for sdhci
patch#18-#21: for GL9755

Tests
=====
Ran 'dd' command to evaluate the performance:
(SanDisk UHS-II card on GL9755 controller)
                             Read    Write
UHS-II disabled (UHS-I): 88.3MB/s 60.7MB/s
UHS-II enabled         :  206MB/s   80MB/s

TODO
====
- replace some define with BIT macro

Reference
=========
[1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
[2] SD Host Controller Simplified Specification 4.20
[3] UHS-II Simplified Addendum 1.02

Changes in v3 (Jul. 10, 2020)
* rebased to v5.8-rc4
* add copyright notice
* reorganize the patch set and split some commits into smaller ones
* separate uhs-2 headers from others
* correct wrong spellings
* fix most of checkpatch warnings/errors
* remove all k[cz]alloc() from the code
* guard sdhci-uhs2 specific code with
      'if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))'
* make sdhci-uhs2.c as a module
* trivial changes, including
  - rename back sdhci-core.c to sdhci.c
  - allow vendor code to disable uhs2 if v4_mode == 0
      in __sdhci_add_host()
  - merge uhs2_power_up() into mmc_power_up()
  - remove flag_uhs2 from mmc_attach_sd()
  - add function descriptions to EXPORT'ed functions
  - other minor code optimization

Changes in v2 (Jan. 9, 2020)
* rebased to v5.5-rc5

AKASHI Takahiro (6):
  mmc: sdhci: add a kernel configuration for enabling UHS-II support
  mmc: sdhci: add UHS-II module
  mmc: sdhci-uhs2: dump UHS-II registers
  mmc: sdhci-uhs2: add set_timeout()
  mmc: core: add post-mmc_attach_sd hook
  mmc: sdhci-pci: add UHS-II support framework

Ben Chuang (1):
  mmc: sdhci-uhs2: add post-mmc_attach_sd hook

Ulf Hansson (4):
  mmc: core: Cleanup printing of speed mode at card insertion
  mmc: core: Prepare to support SD UHS-II cards
  mmc: core: Announce successful insertion of an SD UHS-II card
  mmc: core: Extend support for mmc regulators with a vqmmc2

Victor Shih (15):
  mmc: core: Add definitions for SD UHS-II cards
  mmc: core: Support UHS-II card control and access
  mmc: sdhci: add UHS-II related definitions in headers
  mmc: sdhci-uhs2: add reset function and uhs2_mode function
  mmc: sdhci-uhs2: add set_power() to support vdd2
  mmc: sdhci-uhs2: skip signal_voltage_switch()
  mmc: sdhci-uhs2: add set_ios()
  mmc: sdhci-uhs2: add detect_init() to detect the interface
  mmc: sdhci-uhs2: add clock operations
  mmc: sdhci-uhs2: add uhs2_control() to initialise the interface
  mmc: sdhci-uhs2: add request() and others
  mmc: sdhci-uhs2: add irq() and others
  mmc: sdhci-uhs2: add add_host() and others to set up the driver
  mmc: sdhci-uhs2: add pre-detect_init hook
  mmc: sdhci-pci-gli: enable UHS-II mode for GL9755

 drivers/mmc/core/Makefile         |    2 +-
 drivers/mmc/core/block.c          |    6 +-
 drivers/mmc/core/bus.c            |   38 +-
 drivers/mmc/core/core.c           |   49 +-
 drivers/mmc/core/core.h           |    1 +
 drivers/mmc/core/host.h           |    4 +
 drivers/mmc/core/mmc_ops.c        |   25 +-
 drivers/mmc/core/mmc_ops.h        |    1 +
 drivers/mmc/core/regulator.c      |   34 +
 drivers/mmc/core/sd.c             |   17 +-
 drivers/mmc/core/sd.h             |    3 +
 drivers/mmc/core/sd_ops.c         |   18 +
 drivers/mmc/core/sd_ops.h         |    3 +
 drivers/mmc/core/sd_uhs2.c        | 1394 ++++++++++++++++++++++++
 drivers/mmc/host/Kconfig          |   10 +
 drivers/mmc/host/Makefile         |    1 +
 drivers/mmc/host/sdhci-pci-core.c |   17 +-
 drivers/mmc/host/sdhci-pci-gli.c  |  310 +++++-
 drivers/mmc/host/sdhci-pci.h      |    3 +
 drivers/mmc/host/sdhci-uhs2.c     | 1634 +++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h     |  226 ++++
 drivers/mmc/host/sdhci.c          |  335 +++---
 drivers/mmc/host/sdhci.h          |  125 ++-
 include/linux/mmc/card.h          |   47 +
 include/linux/mmc/core.h          |   13 +
 include/linux/mmc/host.h          |   99 ++
 include/linux/mmc/sd_uhs2.h       |  263 +++++
 27 files changed, 4507 insertions(+), 171 deletions(-)
 create mode 100644 drivers/mmc/core/sd_uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h
 create mode 100644 include/linux/mmc/sd_uhs2.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH V5 00/26] Add support UHS-II for GL9755
@ 2022-10-14 11:45 Victor Shih
  2022-10-17 11:31 ` Ulf Hansson
  0 siblings, 1 reply; 72+ messages in thread
From: Victor Shih @ 2022-10-14 11:45 UTC (permalink / raw)
  To: ulf.hansson, adrian.hunter
  Cc: linux-mmc, linux-kernel, benchuanggli, HL.Liu, Greg.tu,
	takahiro.akashi, dlunev, Victor Shih

Summary
=======
These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.

About UHS-II, roughly deal with the following three parts:
1) A UHS-II detection and initialization:
- Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
  [2]).
- Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
- In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
  3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
  Setup Sequence.

2) Send Legacy SD command through SD-TRAN
- Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
  compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
  Types and Format Overview[3]).
- Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
  CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).

3) UHS-II Interrupt
- Except for UHS-II error interrupts, most interrupts share the original
  interrupt registers.

Patch structure
===============
patch#1-#6:  for core
patch#7-#25: for sdhci
patch#26:    for GL9755

Changes in v5 (Oct. 14, 2022)
* rebased to linux-v6.0.
* according to the guidance and overall architecture provided 
  by Ulf Hansson, Ben Chuang and Jason Lai to implement the
  UHS-2 Core function based on the patches of the [V4,0/6] 
  Preparations to support SD UHS-II cards[5].
* according to the guidance and comments provided by 
  Adrian Hunter, Ben Chuang and AKASHI Takahiro to implement 
  the UHS-2 Host function based on the patches of the 
  [RFC,v3.1,00/27] Add support UHS-II for GL9755[4].
* implement the necessary function to let the UHS-2 Core/Host
  work properly.
* fix most of checkpatch warnings/errors

Reference
=========
[1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
[2] SD Host Controller Simplified Specification 4.20
[3] UHS-II Simplified Addendum 1.02
[4] https://patchwork.kernel.org/project/linux-mmc/cover/20201106022726.19831-1-takahiro.akashi@linaro.org/
[5] https://patchwork.kernel.org/project/linux-mmc/cover/20220418115833.10738-1-jasonlai.genesyslogic@gmail.com/
 
----------------- original cover letter from v3.1 -----------------
This is an interim snapshot of our next version, v4, for enabling
UHS-II on MMC/SD.

It is focused on 'sdhci' side to address Adrian's comments regarding
"modularising" sdhci-uhs2.c.
The whole aim of this version is to get early feedback from Adrian (and
others) on this issue. Without any consensus about the code structure,
it would make little sense to go further ahead on sdhci side.
(Actually, Adrian has made no comments other than "modularising" so far.)

I heavily reworked/refactored sdhci-uhs2.c and re-organised the patch
set to meet what I believe Adrian expects; no UHS-II related code in
Legacy (UHS-I) code or sdhci.c.

Nevertheless, almost of all changes I made are trivial and straightforward
in this direction, and I believe that there is no logic changed since v3
except sdhci_uhs2_irq(), as ops->irq hook, where we must deal with UHS-II
command sequences in addition to UHS-II errors. So I added extra handlings.

I admit that there is plenty of room for improvements (for example,
handling host->flags), but again the focal point here is how sdhci-uhs2.c
should be built as a module.

Please review this series (particularly Patch#8-#26 and #27) from this
viewpoint in the first place.
(Ben is working on 'host' side but there is no change on 'host' side
in this submission except a minor tweak.)

Thanks,
-Takahiro Akashi

------ original cover letter from v3 ------
Summary
=======
These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.

About UHS-II, roughly deal with the following three parts:
1) A UHS-II detection and initialization:
- Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
  [2]).
- Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
- In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
  3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
  Setup Sequence.

2) Send Legacy SD command through SD-TRAN
- Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
  compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
  Types and Format Overview[3]).
- Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
  CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).

3) UHS-II Interrupt
- Except for UHS-II error interrupts, most interrupts share the original
  interrupt registers.

Patch structure
===============
patch#1-#7: for core
patch#8-#17: for sdhci
patch#18-#21: for GL9755

Tests
=====
Ran 'dd' command to evaluate the performance:
(SanDisk UHS-II card on GL9755 controller)
                             Read    Write
UHS-II disabled (UHS-I): 88.3MB/s 60.7MB/s
UHS-II enabled         :  206MB/s   80MB/s

TODO
====
- replace some define with BIT macro

Reference
=========
[1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
[2] SD Host Controller Simplified Specification 4.20
[3] UHS-II Simplified Addendum 1.02

Changes in v3 (Jul. 10, 2020)
* rebased to v5.8-rc4
* add copyright notice
* reorganize the patch set and split some commits into smaller ones
* separate uhs-2 headers from others
* correct wrong spellings
* fix most of checkpatch warnings/errors
* remove all k[cz]alloc() from the code
* guard sdhci-uhs2 specific code with
      'if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))'
* make sdhci-uhs2.c as a module
* trivial changes, including
  - rename back sdhci-core.c to sdhci.c
  - allow vendor code to disable uhs2 if v4_mode == 0
      in __sdhci_add_host()
  - merge uhs2_power_up() into mmc_power_up()
  - remove flag_uhs2 from mmc_attach_sd()
  - add function descriptions to EXPORT'ed functions
  - other minor code optimization

Changes in v2 (Jan. 9, 2020)
* rebased to v5.5-rc5

AKASHI Takahiro (6):
  mmc: sdhci: add a kernel configuration for enabling UHS-II support
  mmc: sdhci: add UHS-II module
  mmc: sdhci-uhs2: dump UHS-II registers
  mmc: sdhci-uhs2: add set_timeout()
  mmc: core: add post-mmc_attach_sd hook
  mmc: sdhci-pci: add UHS-II support framework

Ben Chuang (1):
  mmc: sdhci-uhs2: add post-mmc_attach_sd hook

Ulf Hansson (4):
  mmc: core: Cleanup printing of speed mode at card insertion
  mmc: core: Prepare to support SD UHS-II cards
  mmc: core: Announce successful insertion of an SD UHS-II card
  mmc: core: Extend support for mmc regulators with a vqmmc2

Victor Shih (15):
  mmc: core: Add definitions for SD UHS-II cards
  mmc: core: Support UHS-II card control and access
  mmc: sdhci: add UHS-II related definitions in headers
  mmc: sdhci-uhs2: add reset function and uhs2_mode function
  mmc: sdhci-uhs2: add set_power() to support vdd2
  mmc: sdhci-uhs2: skip signal_voltage_switch()
  mmc: sdhci-uhs2: add set_ios()
  mmc: sdhci-uhs2: add detect_init() to detect the interface
  mmc: sdhci-uhs2: add clock operations
  mmc: sdhci-uhs2: add uhs2_control() to initialise the interface
  mmc: sdhci-uhs2: add request() and others
  mmc: sdhci-uhs2: add irq() and others
  mmc: sdhci-uhs2: add add_host() and others to set up the driver
  mmc: sdhci-uhs2: add pre-detect_init hook
  mmc: sdhci-pci-gli: enable UHS-II mode for GL9755

 drivers/mmc/Kconfig               |   22 -
 drivers/mmc/Makefile              |    7 -
 drivers/mmc/core/Makefile         |    2 +-
 drivers/mmc/core/block.c          |    6 +-
 drivers/mmc/core/bus.c            |   38 +-
 drivers/mmc/core/core.c           |   49 +-
 drivers/mmc/core/core.h           |    1 +
 drivers/mmc/core/host.h           |    4 +
 drivers/mmc/core/mmc_ops.c        |   25 +-
 drivers/mmc/core/mmc_ops.h        |    1 +
 drivers/mmc/core/regulator.c      |   34 +
 drivers/mmc/core/sd.c             |   17 +-
 drivers/mmc/core/sd.h             |    3 +
 drivers/mmc/core/sd_ops.c         |   18 +
 drivers/mmc/core/sd_ops.h         |    3 +
 drivers/mmc/core/sd_uhs2.c        | 1394 ++++++++++++++++++++++++
 drivers/mmc/host/Kconfig          |   10 +
 drivers/mmc/host/Makefile         |    1 +
 drivers/mmc/host/sdhci-pci-core.c |   17 +-
 drivers/mmc/host/sdhci-pci-gli.c  |  319 +++++-
 drivers/mmc/host/sdhci-pci.h      |    3 +
 drivers/mmc/host/sdhci-uhs2.c     | 1634 +++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h     |  226 ++++
 drivers/mmc/host/sdhci.c          |  335 +++---
 drivers/mmc/host/sdhci.h          |  125 ++-
 include/linux/mmc/card.h          |   47 +
 include/linux/mmc/core.h          |   13 +
 include/linux/mmc/host.h          |   99 ++
 include/linux/mmc/sd_uhs2.h       |  263 +++++
 29 files changed, 4516 insertions(+), 200 deletions(-)
 delete mode 100644 drivers/mmc/Kconfig
 delete mode 100644 drivers/mmc/Makefile
 create mode 100644 drivers/mmc/core/sd_uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h
 create mode 100644 include/linux/mmc/sd_uhs2.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 72+ messages in thread

end of thread, other threads:[~2022-12-13  8:49 UTC | newest]

Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-19 11:06 [PATCH V5 00/26] Add support UHS-II for GL9755 Victor Shih
2022-10-19 11:06 ` [PATCH V5 01/26] mmc: core: Cleanup printing of speed mode at card insertion Victor Shih
2022-10-19 11:06 ` [PATCH V5 02/26] mmc: core: Prepare to support SD UHS-II cards Victor Shih
2022-11-04 12:16   ` Christophe JAILLET
2022-11-04 15:09     ` Ulf Hansson
2022-10-19 11:06 ` [PATCH V5 03/26] mmc: core: Announce successful insertion of an SD UHS-II card Victor Shih
2022-10-19 11:06 ` [PATCH V5 04/26] mmc: core: Extend support for mmc regulators with a vqmmc2 Victor Shih
2022-10-19 11:06 ` [PATCH V5 05/26] mmc: core: Add definitions for SD UHS-II cards Victor Shih
2022-11-01 17:12   ` Adrian Hunter
2022-11-16 11:06     ` Victor Shih
2022-11-16 13:48       ` Adrian Hunter
2022-11-17  6:19         ` Ben Chuang
2022-11-17 16:03           ` Adrian Hunter
2022-11-18  1:19             ` Ben Chuang
2022-12-13  8:44               ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 06/26] mmc: core: Support UHS-II card control and access Victor Shih
2022-10-19 11:06 ` [PATCH V5 07/26] mmc: sdhci: add a kernel configuration for enabling UHS-II support Victor Shih
2022-11-01 17:12   ` Adrian Hunter
2022-12-13  8:45     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 08/26] mmc: sdhci: add UHS-II related definitions in headers Victor Shih
2022-11-01 17:12   ` Adrian Hunter
2022-12-13  8:45     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 09/26] mmc: sdhci: add UHS-II module Victor Shih
2022-11-01 17:12   ` Adrian Hunter
2022-12-13  8:45     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 10/26] mmc: sdhci-uhs2: dump UHS-II registers Victor Shih
2022-11-01 17:13   ` Adrian Hunter
2022-12-13  8:45     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 11/26] mmc: sdhci-uhs2: add reset function and uhs2_mode function Victor Shih
2022-11-01 17:13   ` Adrian Hunter
2022-12-13  8:45     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 12/26] mmc: sdhci-uhs2: add set_power() to support vdd2 Victor Shih
2022-11-01 17:13   ` Adrian Hunter
2022-12-13  8:46     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 13/26] mmc: sdhci-uhs2: skip signal_voltage_switch() Victor Shih
2022-10-19 11:06 ` [PATCH V5 14/26] mmc: sdhci-uhs2: add set_timeout() Victor Shih
2022-11-01 17:14   ` Adrian Hunter
2022-12-13  8:46     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 15/26] mmc: sdhci-uhs2: add set_ios() Victor Shih
2022-11-01 17:14   ` Adrian Hunter
2022-12-13  8:46     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 16/26] mmc: sdhci-uhs2: add detect_init() to detect the interface Victor Shih
2022-11-01 17:14   ` Adrian Hunter
2022-12-13  8:47     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 17/26] mmc: sdhci-uhs2: add clock operations Victor Shih
2022-11-01 17:14   ` Adrian Hunter
2022-12-13  8:47     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 18/26] mmc: sdhci-uhs2: add uhs2_control() to initialise the interface Victor Shih
2022-11-01 17:15   ` Adrian Hunter
2022-12-13  8:47     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 19/26] mmc: sdhci-uhs2: add request() and others Victor Shih
2022-11-01 17:15   ` Adrian Hunter
2022-12-13  8:47     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 20/26] mmc: sdhci-uhs2: add irq() " Victor Shih
2022-11-01 17:15   ` Adrian Hunter
2022-12-13  8:48     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 21/26] mmc: sdhci-uhs2: add add_host() and others to set up the driver Victor Shih
2022-11-01 17:15   ` Adrian Hunter
2022-12-13  8:48     ` Victor Shih
2022-10-19 11:06 ` [PATCH V5 22/26] mmc: sdhci-uhs2: add pre-detect_init hook Victor Shih
2022-10-19 11:06 ` [PATCH V5 23/26] mmc: core: add post-mmc_attach_sd hook Victor Shih
2022-10-19 11:06 ` [PATCH V5 24/26] mmc: sdhci-uhs2: " Victor Shih
2022-10-19 11:06 ` [PATCH V5 25/26] mmc: sdhci-pci: add UHS-II support framework Victor Shih
2022-10-19 11:06 ` [PATCH V5 26/26] mmc: sdhci-pci-gli: enable UHS-II mode for GL9755 Victor Shih
2022-10-19 11:29 ` [PATCH V5 00/26] Add support UHS-II " Ulf Hansson
2022-11-01  2:24   ` Victor Shih
2022-11-01 17:28 ` Adrian Hunter
2022-11-04 10:43   ` Victor Shih
  -- strict thread matches above, loose matches on Subject: below --
2022-10-17  9:11 Victor Shih
2022-10-14 11:45 Victor Shih
2022-10-17 11:31 ` Ulf Hansson
2022-10-19 11:02   ` Victor Shih

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.