Skip to contentSkip to conversation

Add support UHS-II for GL9755

RFC PATCH Superseded Ben Chuang 3 participants 12 messages Jan 9, 2020 – Mar 18, 2020

Subsystems (9)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Ben Chuang

author
#0 lore raw

v2 cover Add support UHS-II for GL9755

Hi Uffe and Adrian,

These patches support UHS-II and fix GL9755 UHS-II compatibility.

The parts of UHS-II are based on [1][2] and porting to Linux 5.5-rc5. I have seen that Uffe comment that splitting the UHS-II parts into smaller patches. Other than splitting into small patches, could you give me some suggestions for refactoring/splitting files?

Best regards,
Ben

References:
1. [RFC,1/2] mmc: core: support UHS-II in core stack.
(https://patchwork.kernel.org/patch/5544441/)
2. [RFC,2/2] mmc: sdhci: support UHS-II in SDHCI host.
(https://patchwork.kernel.org/patch/5544451/)

v2:
- base on Linux v5.5-rc5

Ben Chuang (6):
mmc: Add UHS-II support in public headers
mmc: core: Add UHS-II support in core layer
mmc: host: Add UHS-II support in host layer
mmc: uhs2: Introduce a uhs2_post_attach_sd function
mmc: sdhci-uhs2: Introduce a uhs2_pre_detect_init function
mmc: sdhci-pci-gli: Fix power/reset/ZC/timeout for GL9755 UHS-II mode

 drivers/mmc/core/Makefile                  |   3 +-
 drivers/mmc/core/block.c                   |   7 +-
 drivers/mmc/core/bus.c                     |   5 +-
 drivers/mmc/core/core.c                    |  65 +-
 drivers/mmc/core/core.h                    |   3 +-
 drivers/mmc/core/regulator.c               |  14 +
 drivers/mmc/core/sd.c                      |  27 +-
 drivers/mmc/core/sd_ops.c                  |  12 +
 drivers/mmc/core/uhs2.c                    | 995 +++++++++++++++++++++
 drivers/mmc/core/uhs2.h                    |  23 +
 drivers/mmc/host/Makefile                  |   1 +
 drivers/mmc/host/{sdhci.c => sdhci-core.c} | 285 +++++-
 drivers/mmc/host/sdhci-milbeaut.c          |   4 +-
 drivers/mmc/host/sdhci-of-arasan.c         |   4 +-
 drivers/mmc/host/sdhci-of-at91.c           |   4 +-
 drivers/mmc/host/sdhci-omap.c              |   2 +-
 drivers/mmc/host/sdhci-pci-core.c          |   4 +-
 drivers/mmc/host/sdhci-pci-gli.c           | 361 +++++++-
 drivers/mmc/host/sdhci-pxav3.c             |   4 +-
 drivers/mmc/host/sdhci-uhs2.c              | 754 ++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h              |  34 +
 drivers/mmc/host/sdhci-xenon.c             |   4 +-
 drivers/mmc/host/sdhci.h                   | 286 +++++-
 drivers/mmc/host/sdhci_am654.c             |   4 +-
 include/linux/mmc/card.h                   |   1 +
 include/linux/mmc/core.h                   |   6 +
 include/linux/mmc/host.h                   |  31 +
 include/linux/mmc/uhs2.h                   | 270 ++++++
 28 files changed, 3137 insertions(+), 76 deletions(-)
 create mode 100644 drivers/mmc/core/uhs2.c
 create mode 100644 drivers/mmc/core/uhs2.h
 rename drivers/mmc/host/{sdhci.c => sdhci-core.c} (94%)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h
 create mode 100644 include/linux/mmc/uhs2.h

base-commit: c79f46a282390e0f5b306007bf7b11a46d529538

Signature · 1 line
2.24.1
author
#1 lore raw

RFC PATCH v2 1/6 mmc: Add UHS-II support in public headers

From: Ben Chuang <[email protected]>

Add UHS-II support in public headers

---
 include/linux/mmc/card.h |  1 +
 include/linux/mmc/core.h |  6 ++++++
 include/linux/mmc/host.h | 30 ++++++++++++++++++++++++++++++
 3 files changed, 37 insertions(+)
include/linux/mmc/card.h +1 -0
index cf3780a6ccc4..988f46638317 100644
@@ -180,6 +180,7 @@ struct sd_switch_caps {
 #define SD_SET_CURRENT_LIMIT_400	1
 #define SD_SET_CURRENT_LIMIT_600	2
 #define SD_SET_CURRENT_LIMIT_800	3
+#define SD_SET_CURRENT_LIMIT_1000       4
 #define SD_SET_CURRENT_NO_CHANGE	(-1)
 
 #define SD_MAX_CURRENT_200	(1 << SD_SET_CURRENT_LIMIT_200)
include/linux/mmc/core.h +6 -0
index b7ba8810a3b5..cd294a1c31c6 100644
@@ -7,6 +7,7 @@
 
 #include <linux/completion.h>
 #include <linux/types.h>
+#include <linux/mmc/uhs2.h>
 
 struct mmc_data;
 struct mmc_request;
@@ -112,6 +113,11 @@ struct mmc_command {
 
 	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 {
include/linux/mmc/host.h +30 -0
index ba703384bea0..3d6a7c9b534f 100644
@@ -15,10 +15,12 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/pm.h>
 #include <linux/dma-direction.h>
+#include <linux/mmc/uhs2.h>
 
 struct mmc_ios {
 	unsigned int	clock;			/* clock rate */
 	unsigned short	vdd;
+	unsigned short	vdd2;			/* UHS2 VDD2 power supply */
 	unsigned int	power_delay_ms;		/* waiting for stable power */
 
 /* vdd stores the bit number of the selected voltage range from below. */
@@ -60,6 +62,7 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52	8
 #define MMC_TIMING_MMC_HS200	9
 #define MMC_TIMING_MMC_HS400	10
+#define MMC_TIMING_UHS2		11
 
 	unsigned char	signal_voltage;		/* signalling voltage (1.8V or 3.3V) */
 
@@ -169,6 +172,11 @@ struct mmc_host_ops {
 	 */
 	int	(*multi_io_quirk)(struct mmc_card *card,
 				  unsigned int direction, int blk_size);
+	/* UHS2 interfaces */
+	int	(*uhs2_detect_init)(struct mmc_host *host);
+	int	(*uhs2_set_reg)(struct mmc_host *host, enum uhs2_act act);
+	void    (*uhs2_disable_clk)(struct mmc_host *host);
+	void    (*uhs2_enable_clk)(struct mmc_host *host);
 };
 
 struct mmc_cqe_ops {
@@ -261,6 +269,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 */
 };
 
@@ -281,12 +290,14 @@ 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 */
 #ifdef CONFIG_PM_SLEEP
 	struct notifier_block	pm_notify;
 #endif
 	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 */
@@ -305,6 +316,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 */
 
@@ -336,6 +348,7 @@ struct mmc_host {
 #define MMC_CAP_DRIVER_TYPE_A	(1 << 23)	/* Host supports Driver Type A */
 #define MMC_CAP_DRIVER_TYPE_C	(1 << 24)	/* Host supports Driver Type C */
 #define MMC_CAP_DRIVER_TYPE_D	(1 << 25)	/* Host supports Driver Type D */
+#define MMC_CAP_UHS2		(1 << 26)	/* Host supports UHS2 mode */
 #define MMC_CAP_DONE_COMPLETE	(1 << 27)	/* RW reqs can be completed within mmc_request_done() */
 #define MMC_CAP_CD_WAKE		(1 << 28)	/* Enable card detect wake */
 #define MMC_CAP_CMD_DURING_TFR	(1 << 29)	/* Commands during data transfer */
@@ -374,6 +387,17 @@ struct mmc_host {
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
+	struct uhs2_host_caps	uhs2_caps;	/* UHS2 host capabilities */
+	struct uhs2_card_prop	uhs2_dev_prop;	/* UHS2 device properties */
+	u32			group_desc;	/* UHS2 property */
+	int			flags;
+#define MMC_UHS2_SUPPORT	(1 << 0)
+#define MMC_UHS2_INITIALIZED	(1 << 1)
+#define MMC_UHS2_2L_HD		(1 << 2)
+#define MMC_UHS2_APP_CMD	(1 << 3)
+#define MMC_UHS2_SPEED_B	(1 << 4)
+#define MMC_SUPPORT_ADMA3	(1 << 5)
+
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
 	unsigned short		max_segs;	/* see blk_queue_max_segments */
@@ -566,6 +590,12 @@ static inline int mmc_card_uhs(struct mmc_card *card)
 		card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
 }
 
+static inline bool mmc_card_uhs2(struct mmc_card *card)
+{
+	return (card->host->flags & MMC_UHS2_SUPPORT) &&
+		(card->host->flags & MMC_UHS2_INITIALIZED);
+}
+
 void mmc_retune_timer_stop(struct mmc_host *host);
 
 static inline void mmc_retune_needed(struct mmc_host *host)
Signature · 1 line
2.24.1
author
#2 lore raw

RFC PATCH v2 2/6 mmc: core: Add UHS-II support in core layer

In reply to Ben Chuang

From: Ben Chuang <[email protected]>

Add UHS-II support in core layer

---
 drivers/mmc/core/Makefile    |   3 +-
 drivers/mmc/core/block.c     |   7 +-
 drivers/mmc/core/bus.c       |   5 +-
 drivers/mmc/core/core.c      |  65 ++-
 drivers/mmc/core/core.h      |   3 +-
 drivers/mmc/core/regulator.c |  14 +
 drivers/mmc/core/sd.c        |  27 +-
 drivers/mmc/core/sd_ops.c    |  12 +
 drivers/mmc/core/uhs2.c      | 992 +++++++++++++++++++++++++++++++++++
 drivers/mmc/core/uhs2.h      |  23 +
 10 files changed, 1139 insertions(+), 12 deletions(-)
 create mode 100644 drivers/mmc/core/uhs2.c
 create mode 100644 drivers/mmc/core/uhs2.h
drivers/mmc/core/Makefile +2 -1
index 95ffe008ebdf..ddfda7a234cb 100644
@@ -8,7 +8,8 @@ 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 \
-				   slot-gpio.o regulator.o
+				   slot-gpio.o regulator.o \
+				   uhs2.o
 mmc_core-$(CONFIG_OF)		+= pwrseq.o
 obj-$(CONFIG_PWRSEQ_SIMPLE)	+= pwrseq_simple.o
 obj-$(CONFIG_PWRSEQ_SD8787)	+= pwrseq_sd8787.o
drivers/mmc/core/block.c +6 -1
index 95b41c0891d0..c5f6bfd05d49 100644
@@ -56,6 +56,7 @@
 #include "mmc_ops.h"
 #include "quirks.h"
 #include "sd_ops.h"
+#include "uhs2.h"
 
 MODULE_ALIAS("mmc:block");
 #ifdef MODULE_PARAM_PREFIX
@@ -1551,6 +1552,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->host->flags & MMC_UHS2_INITIALIZED) ? true : false;
 
 	mmc_blk_data_prep(mq, mqrq, disable_multi, &do_rel_wr, &do_data_tag);
 
@@ -1561,7 +1565,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.
 		 */
@@ -1574,6 +1578,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;
 
drivers/mmc/core/bus.c +3 -2
index 74de3f2dda38..c1cd1079c186 100644
@@ -336,8 +336,9 @@ int mmc_add_card(struct mmc_card *card)
 	} 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_uhs2(card) ? "ultra high speed 2 " :
+			(mmc_card_uhs(card) ? "ultra high speed 1 " :
+			(mmc_card_hs(card) ? "high speed " : "")),
 			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
drivers/mmc/core/core.c +59 -6

144 lines not on this page · raw message

drivers/mmc/core/core.h +2 -1
index 575ac0257af2..1fb10c341b43 100644
@@ -76,7 +76,7 @@ int _mmc_detect_card_removed(struct mmc_host *host);
 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_sd(struct mmc_host *host, bool flag_uhs2);
 int mmc_attach_sdio(struct mmc_host *host);
 
 /* Module parameters */
@@ -124,6 +124,7 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
 void mmc_release_host(struct mmc_host *host);
 void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx);
 void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx);
+void mmc_set_ios(struct mmc_host *host);
 
 /**
  *	mmc_claim_host - exclusively claim a host
drivers/mmc/core/regulator.c +14 -0
index b6febbcf8978..f9a643f653fe 100644
@@ -236,6 +236,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.vmmc2 = devm_regulator_get_optional(dev, "vmmc2");
 
 	if (IS_ERR(mmc->supply.vmmc)) {
 		if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
@@ -255,6 +256,19 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
 		dev_dbg(dev, "No vqmmc regulator found\n");
 	}
 
+	if (IS_ERR(mmc->supply.vmmc2)) {
+		if (PTR_ERR(mmc->supply.vmmc2) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		dev_dbg(dev, "No vmmc2 regulator found\n");
+	} else {
+		ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc2);
+		if (ret > 0)
+			mmc->ocr_avail_uhs2 = ret;
+		else
+			dev_warn(dev, "Failed getting UHS2 OCR mask: %d\n",
+				 ret);
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
drivers/mmc/core/sd.c +26 -1
index fe914ff5f5d6..b079f3f164fe 100644
@@ -877,6 +877,19 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
 		err = mmc_read_switch(card);
 		if (err)
 			return err;
+		if (host->flags & MMC_UHS2_INITIALIZED) {
+			u8 status[64];
+			/*
+			 * send CMD6 to set Maximum Power Consumption
+			 * to get better performance
+			 */
+			err = mmc_sd_switch(card, 0, 3,
+					SD_SET_CURRENT_LIMIT_1000, status);
+			if (!err) {
+				err = mmc_sd_switch(card, 1, 3,
+					SD_SET_CURRENT_LIMIT_1000, status);
+			}
+		}
 	}
 
 	/*
@@ -1019,6 +1032,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 	if (err)
 		goto free_card;
 
+	/* For UHS2, skip the UHS-I initialization. */
+	if ((host->flags & MMC_UHS2_SUPPORT) &&
+	    (host->flags & MMC_UHS2_INITIALIZED))
+		goto done;
+
 	/*
 	 * If the card has not been power cycled, it may still be using 1.8V
 	 * signaling. Detect that situation and try to initialize a UHS-I (1.8V)
@@ -1266,7 +1284,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
 /*
  * Starting point for SD card init.
  */
-int mmc_attach_sd(struct mmc_host *host)
+int mmc_attach_sd(struct mmc_host *host, bool flag_uhs2)
 {
 	int err;
 	u32 ocr, rocr;
@@ -1300,6 +1318,13 @@ int mmc_attach_sd(struct mmc_host *host)
 
 	rocr = mmc_select_voltage(host, ocr);
 
+	/*
+	 * Some cards have zero value of rocr in UHS-II mode. Assign host's ocr
+	 * value to rocr.
+	 */
+	if (flag_uhs2 && !rocr)
+		rocr = host->ocr_avail;
+
 	/*
 	 * Can we support the voltage(s) of the card(s)?
 	 */
drivers/mmc/core/sd_ops.c +12 -0
index 22bf528294b9..9dc296356928 100644
@@ -26,6 +26,15 @@ 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 (host->flags &  MMC_UHS2_SUPPORT &&
+	    host->flags & MMC_UHS2_INITIALIZED) {
+		host->flags |= MMC_UHS2_APP_CMD;
+		return 0;
+	}
+
 	cmd.opcode = MMC_APP_CMD;
 
 	if (card) {
@@ -235,6 +244,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;
@@ -282,6 +292,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 	cmd.arg &= ~(0xF << (group * 4));
 	cmd.arg |= value << (group * 4);
 	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.uhs2_tmode0_flag = 1;
 
 	data.blksz = 64;
 	data.blocks = 1;
@@ -323,6 +334,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;
drivers/mmc/core/uhs2.c new file +992 -0

992 lines not on this page · raw message

drivers/mmc/core/uhs2.h new file +23 -0
new file mode 100644
index 000000000000..60fecf25db0a
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *  driver/mmc/core/uhs2.h - UHS-II driver
+ *
+ * Header file for UHS-II packets, Host Controller registers and I/O
+ * accessors.
+ *
+ *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ */
+#ifndef MMC_UHS2_H
+#define MMC_UHS2_H
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+
+#define UHS2_PHY_INIT_ERR	1
+
+extern int uhs2_prepare_sd_cmd(struct mmc_host *host, struct mmc_request *mrq);
+extern void uhs2_power_up(struct mmc_host *host);
+extern int mmc_uhs2_try_frequency(struct mmc_host *host, unsigned int freq);
+extern int uhs2_abort_trans(struct mmc_host *host);
+
+#endif /* MMC_UHS2_H */
Signature · 1 line
2.24.1
author
#3 lore raw

RFC PATCH v2 3/6 mmc: host: Add UHS-II support in host layer

In reply to Ben Chuang

From: Ben Chuang <[email protected]>

Add UHS-II support in host layer

---
 drivers/mmc/host/Makefile                  |   1 +
 drivers/mmc/host/{sdhci.c => sdhci-core.c} | 276 ++++++--
 drivers/mmc/host/sdhci-milbeaut.c          |   4 +-
 drivers/mmc/host/sdhci-of-arasan.c         |   4 +-
 drivers/mmc/host/sdhci-of-at91.c           |   4 +-
 drivers/mmc/host/sdhci-omap.c              |   2 +-
 drivers/mmc/host/sdhci-pci-core.c          |   4 +-
 drivers/mmc/host/sdhci-pxav3.c             |   4 +-
 drivers/mmc/host/sdhci-uhs2.c              | 751 +++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h              |  34 +
 drivers/mmc/host/sdhci-xenon.c             |   4 +-
 drivers/mmc/host/sdhci.h                   | 284 +++++++-
 drivers/mmc/host/sdhci_am654.c             |   4 +-
 include/linux/mmc/uhs2.h                   | 270 ++++++++
 14 files changed, 1583 insertions(+), 63 deletions(-)
 rename drivers/mmc/host/{sdhci.c => sdhci-core.c} (94%)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h
 create mode 100644 include/linux/mmc/uhs2.h
drivers/mmc/host/Makefile +1 -0
index 21d9089e5eda..6880d0a1ef16 100644
@@ -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
+sdhci-y				+= sdhci-core.o 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
drivers/mmc/host/sdhci-core.c renamed from drivers/mmc/host/sdhci.c +235 -41

532 lines not on this page · raw message

drivers/mmc/host/sdhci-milbeaut.c +2 -2
index a1aa21b9ae1c..1c076f885670 100644
@@ -122,14 +122,14 @@ static void sdhci_milbeaut_reset(struct sdhci_host *host, u8 mask)
 }
 
 static void sdhci_milbeaut_set_power(struct sdhci_host *host,
-			unsigned char mode, unsigned short vdd)
+		unsigned char mode, unsigned short vdd, unsigned short vdd2)
 {
 	if (!IS_ERR(host->mmc->supply.vmmc)) {
 		struct mmc_host *mmc = host->mmc;
 
 		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
 	}
-	sdhci_set_power_noreg(host, mode, vdd);
+	sdhci_set_power_noreg(host, mode, vdd, -1);
 }
 
 static const struct sdhci_ops sdhci_milbeaut_ops = {
drivers/mmc/host/sdhci-of-arasan.c +2 -2
index e49b44b4d82e..7bc5c60544f1 100644
@@ -326,14 +326,14 @@ static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
 }
 
 static void sdhci_arasan_set_power(struct sdhci_host *host, unsigned char mode,
-		     unsigned short vdd)
+		     unsigned short vdd, unsigned short vdd2)
 {
 	if (!IS_ERR(host->mmc->supply.vmmc)) {
 		struct mmc_host *mmc = host->mmc;
 
 		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
 	}
-	sdhci_set_power_noreg(host, mode, vdd);
+	sdhci_set_power_noreg(host, mode, vdd, -1);
 }
 
 static const struct sdhci_ops sdhci_arasan_ops = {
drivers/mmc/host/sdhci-of-at91.c +2 -2
index 5959e394b416..59237568fdc3 100644
@@ -100,14 +100,14 @@ static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
  * an external regulator.
  */
 static void sdhci_at91_set_power(struct sdhci_host *host, unsigned char mode,
-		     unsigned short vdd)
+		     unsigned short vdd, unsigned short vdd2)
 {
 	if (!IS_ERR(host->mmc->supply.vmmc)) {
 		struct mmc_host *mmc = host->mmc;
 
 		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
 	}
-	sdhci_set_power_noreg(host, mode, vdd);
+	sdhci_set_power_noreg(host, mode, vdd, -1);
 }
 
 static void sdhci_at91_set_uhs_signaling(struct sdhci_host *host,
drivers/mmc/host/sdhci-omap.c +1 -1
index 083e7e053c95..3b59c20e5f58 100644
@@ -671,7 +671,7 @@ static void sdhci_omap_set_clock(struct sdhci_host *host, unsigned int clock)
 }
 
 static void sdhci_omap_set_power(struct sdhci_host *host, unsigned char mode,
-			  unsigned short vdd)
+			  unsigned short vdd, unsigned short vdd2)
 {
 	struct mmc_host *mmc = host->mmc;
 
drivers/mmc/host/sdhci-pci-core.c +2 -2
index 5091e2c1c0e5..1cfb22276047 100644
@@ -630,12 +630,12 @@ static int bxt_get_cd(struct mmc_host *mmc)
 #define SDHCI_INTEL_PWR_TIMEOUT_UDELAY	100
 
 static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode,
-				  unsigned short vdd)
+				  unsigned short vdd, unsigned short vdd2)
 {
 	int cntr;
 	u8 reg;
 
-	sdhci_set_power(host, mode, vdd);
+	sdhci_set_power(host, mode, vdd, -1);
 
 	if (mode == MMC_POWER_OFF)
 		return;
drivers/mmc/host/sdhci-pxav3.c +2 -2
index e55037ceda73..457e9425339a 100644
@@ -298,12 +298,12 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
 }
 
 static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
-			    unsigned short vdd)
+			    unsigned short vdd, unsigned short vdd2)
 {
 	struct mmc_host *mmc = host->mmc;
 	u8 pwr = host->pwr;
 
-	sdhci_set_power_noreg(host, mode, vdd);
+	sdhci_set_power_noreg(host, mode, vdd, -1);
 
 	if (host->pwr == pwr)
 		return;
drivers/mmc/host/sdhci-uhs2.c new file +751 -0

751 lines not on this page · raw message

drivers/mmc/host/sdhci-uhs2.h new file +34 -0
new file mode 100644
index 000000000000..1a17c81a3533
@@ -0,0 +1,34 @@
+/* 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/mmc/host.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/uhs2.h>
+
+extern void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
+extern void sdhci_uhs2_set_transfer_mode(struct sdhci_host *host,
+					struct mmc_command *cmd);
+extern void sdhci_uhs2_send_command(struct sdhci_host *host,
+					struct mmc_command *cmd);
+extern void sdhci_uhs2_finish_command(struct sdhci_host *host);
+extern void sdhci_uhs2_do_set_ios(struct sdhci_host *host,
+					struct mmc_ios *ios);
+extern int sdhci_uhs2_do_detect_init(struct sdhci_host *host);
+extern int sdhci_uhs2_do_set_reg(struct sdhci_host *host, enum uhs2_act act);
+extern void sdhci_uhs2_irq(struct sdhci_host *host);
+extern int sdhci_uhs2_add_host(struct sdhci_host *host, u32 caps1);
+extern void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead);
+extern void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear,
+					u32 set);
+extern void sdhci_uhs2_set_timeout(struct sdhci_host *host);
+
+#endif /* __SDHCI_UHS2_H */
drivers/mmc/host/sdhci-xenon.c +2 -2
index 1dea1ba66f7b..328860cf2bc3 100644
@@ -214,12 +214,12 @@ static void xenon_set_uhs_signaling(struct sdhci_host *host,
 }
 
 static void xenon_set_power(struct sdhci_host *host, unsigned char mode,
-		unsigned short vdd)
+		unsigned short vdd, unsigned short vdd2)
 {
 	struct mmc_host *mmc = host->mmc;
 	u8 pwr = host->pwr;
 
-	sdhci_set_power_noreg(host, mode, vdd);
+	sdhci_set_power_noreg(host, mode, vdd, -1);
 
 	if (host->pwr == pwr)
 		return;
drivers/mmc/host/sdhci.h +277 -7

422 lines not on this page · raw message

drivers/mmc/host/sdhci_am654.c +2 -2
index b8e897e31e2e..524a342ae3cd 100644
@@ -209,14 +209,14 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
 }
 
 static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode,
-				  unsigned short vdd)
+				  unsigned short vdd, unsigned short vdd2)
 {
 	if (!IS_ERR(host->mmc->supply.vmmc)) {
 		struct mmc_host *mmc = host->mmc;
 
 		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
 	}
-	sdhci_set_power_noreg(host, mode, vdd);
+	sdhci_set_power_noreg(host, mode, vdd, -1);
 }
 
 static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg)
include/linux/mmc/uhs2.h new file +270 -0

270 lines not on this page · raw message

Signature · 1 line
2.24.1
maintainer
#4 lore raw

Re: [RFC PATCH v2 3/6] mmc: host: Add UHS-II support in host layer

Quoted 3 lines · Ben Chuang

From: Ben Chuang <[email protected]>

Add UHS-II support in host layer

Split host layer changes from sdhci changes.

Quoted 2 lines

Drop "Reported-by: kbuild test robot <[email protected]>"

Quoted 13 lines
---
 drivers/mmc/host/Makefile                  |   1 +
 drivers/mmc/host/{sdhci.c => sdhci-core.c} | 276 ++++++--
 drivers/mmc/host/sdhci-milbeaut.c          |   4 +-
 drivers/mmc/host/sdhci-of-arasan.c         |   4 +-
 drivers/mmc/host/sdhci-of-at91.c           |   4 +-
 drivers/mmc/host/sdhci-omap.c              |   2 +-
 drivers/mmc/host/sdhci-pci-core.c          |   4 +-
 drivers/mmc/host/sdhci-pxav3.c             |   4 +-
 drivers/mmc/host/sdhci-uhs2.c              | 751 +++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h              |  34 +
 drivers/mmc/host/sdhci-xenon.c             |   4 +-
Quoted 8 lines
 drivers/mmc/host/sdhci.h                   | 284 +++++++-
 drivers/mmc/host/sdhci_am654.c             |   4 +-
 include/linux/mmc/uhs2.h                   | 270 ++++++++
 14 files changed, 1583 insertions(+), 63 deletions(-)
 rename drivers/mmc/host/{sdhci.c => sdhci-core.c} (94%)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h
 create mode 100644 include/linux/mmc/uhs2.h

Please make sdhci-uhs2 a module and do not rename sdhci.c.

References in sdhci.c to sdhci-uhs2.c will need to be enclosed by #if IS_REACHABLE(CONFIG_SDHCI_UHS2)

Move all UHS-II definitions into sdhci-uhs2.h. Things that are for V4 but not necessarily UHS-II can be in sdhci.h

Make the set_power parameter change into a separate patch

Fix all spelling mistakes

Make comment style correct.

Review all checkpatch warnings and checks (i.e. --strict option)

If possible provide a link to a tree that contains the patches.

Re-base on Ulf's next branch

The patch set could use an overview of how UHS-II is different from regular SD.

In other patches there are a bunch of memory allocations on the I/O path. That is a problem. Memory needed should be allocated in advance.

author
#5 lore raw

Re: [RFC PATCH v2 3/6] mmc: host: Add UHS-II support in host layer

Quoted 51 lines · Adrian Hunter
Quoted 3 lines · Ben Chuang

From: Ben Chuang <[email protected]>

Add UHS-II support in host layer

Split host layer changes from sdhci changes.

Quoted 2 lines

Drop "Reported-by: kbuild test robot <[email protected]>"

Quoted 13 lines
---
 drivers/mmc/host/Makefile                  |   1 +
 drivers/mmc/host/{sdhci.c => sdhci-core.c} | 276 ++++++--
 drivers/mmc/host/sdhci-milbeaut.c          |   4 +-
 drivers/mmc/host/sdhci-of-arasan.c         |   4 +-
 drivers/mmc/host/sdhci-of-at91.c           |   4 +-
 drivers/mmc/host/sdhci-omap.c              |   2 +-
 drivers/mmc/host/sdhci-pci-core.c          |   4 +-
 drivers/mmc/host/sdhci-pxav3.c             |   4 +-
 drivers/mmc/host/sdhci-uhs2.c              | 751 +++++++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h              |  34 +
 drivers/mmc/host/sdhci-xenon.c             |   4 +-
Quoted 8 lines
 drivers/mmc/host/sdhci.h                   | 284 +++++++-
 drivers/mmc/host/sdhci_am654.c             |   4 +-
 include/linux/mmc/uhs2.h                   | 270 ++++++++
 14 files changed, 1583 insertions(+), 63 deletions(-)
 rename drivers/mmc/host/{sdhci.c => sdhci-core.c} (94%)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h
 create mode 100644 include/linux/mmc/uhs2.h

Please make sdhci-uhs2 a module and do not rename sdhci.c.

References in sdhci.c to sdhci-uhs2.c will need to be enclosed by #if IS_REACHABLE(CONFIG_SDHCI_UHS2)

Move all UHS-II definitions into sdhci-uhs2.h. Things that are for V4 but not necessarily UHS-II can be in sdhci.h

Make the set_power parameter change into a separate patch

Fix all spelling mistakes

Make comment style correct.

Review all checkpatch warnings and checks (i.e. --strict option)

Quoted 8 lines

If possible provide a link to a tree that contains the patches.

Re-base on Ulf's next branch

The patch set could use an overview of how UHS-II is different from regular SD.

In other patches there are a bunch of memory allocations on the I/O path. That is a problem. Memory needed should be allocated in advance.

Thanks for your comments and guidance.
There seems to be a lot of work to do. I will do my best to meet these.

author
#6 lore raw

RFC PATCH v2 4/6 mmc: uhs2: Introduce a uhs2_post_attach_sd function

In reply to Ben Chuang

From: Ben Chuang <[email protected]>

Introduce a uhs2_post_attach_sd function after attach_sd on UHS-II mode.

---
 drivers/mmc/core/uhs2.c       | 5 ++++-
 drivers/mmc/host/sdhci-core.c | 9 +++++++++
 drivers/mmc/host/sdhci.h      | 1 +
 include/linux/mmc/host.h      | 1 +
 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/mmc/core/uhs2.c +4 -1
index 43ea155ccc59..99aeeccd88e5 100644
@@ -935,8 +935,11 @@ int mmc_uhs2_try_frequency(struct mmc_host *host, unsigned int freq)
 	 */
 	err = mmc_attach_sd(host, true);
 
-	if (!err)
+	if (!err) {
+		if (host->ops->uhs2_post_attach_sd)
+			host->ops->uhs2_post_attach_sd(host);
 		return 0;
+	}
 
 init_fail:
 	mmc_power_off(host);
drivers/mmc/host/sdhci-core.c +9 -0
index 82184684f963..d7b2535a847a 100644
@@ -2778,6 +2778,14 @@ void sdhci_uhs2_enable_clk(struct mmc_host *mmc)
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_enable_clk);
 
+static void sdhci_uhs2_post_attach_sd(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+
+	if (host->ops && host->ops->uhs2_post_attach_sd)
+		host->ops->uhs2_post_attach_sd(host);
+}
+
 static const struct mmc_host_ops sdhci_ops = {
 	.request	= sdhci_request,
 	.post_req	= sdhci_post_req,
@@ -2797,6 +2805,7 @@ static const struct mmc_host_ops sdhci_ops = {
 	.uhs2_set_reg		= sdhci_uhs2_set_reg,
 	.uhs2_disable_clk	= sdhci_uhs2_disable_clk,
 	.uhs2_enable_clk	= sdhci_uhs2_enable_clk,
+	.uhs2_post_attach_sd    = sdhci_uhs2_post_attach_sd,
 };
 
 /*****************************************************************************\
drivers/mmc/host/sdhci.h +1 -0
index 2f7732f4bb75..7f779ac81931 100644
@@ -906,6 +906,7 @@ struct sdhci_ops {
 	void	(*voltage_switch)(struct sdhci_host *host);
 	void	(*adma_write_desc)(struct sdhci_host *host, void **desc,
 				   dma_addr_t addr, int len, unsigned int cmd);
+	void    (*uhs2_post_attach_sd)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
include/linux/mmc/host.h +1 -0
index 3d6a7c9b534f..ed4ebe6bf68a 100644
@@ -177,6 +177,7 @@ struct mmc_host_ops {
 	int	(*uhs2_set_reg)(struct mmc_host *host, enum uhs2_act act);
 	void    (*uhs2_disable_clk)(struct mmc_host *host);
 	void    (*uhs2_enable_clk)(struct mmc_host *host);
+	void    (*uhs2_post_attach_sd)(struct mmc_host *host);
 };
 
 struct mmc_cqe_ops {
Signature · 1 line
2.24.1
author
#7 lore raw

RFC PATCH v2 5/6 mmc: sdhci-uhs2: Introduce a uhs2_pre_detect_init function

In reply to Ben Chuang

From: Ben Chuang <[email protected]>

Introduce a uhs2_pre_detect_init function before detect uhs2 interface.

---
 drivers/mmc/host/sdhci-uhs2.c | 3 +++
 drivers/mmc/host/sdhci.h      | 1 +
 2 files changed, 4 insertions(+)
drivers/mmc/host/sdhci-uhs2.c +3 -0
index e9c42894185a..9f53b7b938b9 100644
@@ -506,6 +506,9 @@ int sdhci_uhs2_do_detect_init(struct sdhci_host *host)
 	DBG("%s: begin UHS2 init.\n", __func__);
 	spin_lock_irqsave(&host->lock, flags);
 
+	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));
drivers/mmc/host/sdhci.h +1 -0
index 7f779ac81931..08ee4c805474 100644
@@ -906,6 +906,7 @@ struct sdhci_ops {
 	void	(*voltage_switch)(struct sdhci_host *host);
 	void	(*adma_write_desc)(struct sdhci_host *host, void **desc,
 				   dma_addr_t addr, int len, unsigned int cmd);
+	void    (*uhs2_pre_detect_init)(struct sdhci_host *host);
 	void    (*uhs2_post_attach_sd)(struct sdhci_host *host);
 };
 
Signature · 1 line
2.24.1
author
#8 lore raw

RFC PATCH v2 6/6 mmc: sdhci-pci-gli: Fix power/reset/ZC/timeout for GL9755 UHS-II mode

In reply to Ben Chuang

From: Ben Chuang <[email protected]>

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.

---
 drivers/mmc/host/sdhci-pci-gli.c | 361 ++++++++++++++++++++++++++++++-
 1 file changed, 360 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci-pci-gli.c +360 -1
index 5eea8d70a85d..1be78a609dc3 100644
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include "sdhci.h"
 #include "sdhci-pci.h"
+#include "sdhci-uhs2.h"
 
 /*  Genesys Logic extra registers */
 #define SDHCI_GLI_9750_WT         0x800
@@ -60,6 +61,42 @@
 #define   SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY    GENMASK(2, 0)
 #define   GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE    0x1
 
+#define PCI_GLI_9755_WT       0x800
+#define   PCI_GLI_9755_WT_EN    BIT(0)
+#define   GLI_9755_WT_EN_ON	0x1
+#define   GLI_9755_WT_EN_OFF    0x0
+
+#define PCI_GLI_9755_PLLSSC                 0x68
+#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_UHS2_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_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 GLI_MAX_TUNING_LOOP 40
 
 /* Genesys Logic chipset */
@@ -262,6 +299,324 @@ static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode)
 	return 0;
 }
 
+static inline void gl9755_wt_on(struct pci_dev *pdev)
+{
+	u32 wt_value;
+	u32 wt_enable;
+
+	pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value);
+	wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value);
+
+	if (wt_enable == GLI_9755_WT_EN_ON)
+		return;
+
+	wt_value &= ~PCI_GLI_9755_WT_EN;
+	wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_ON);
+
+	pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value);
+}
+
+static inline void gl9755_wt_off(struct pci_dev *pdev)
+{
+	u32 wt_value;
+	u32 wt_enable;
+
+	pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value);
+	wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value);
+
+	if (wt_enable == GLI_9755_WT_EN_OFF)
+		return;
+
+	wt_value &= ~PCI_GLI_9755_WT_EN;
+	wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_OFF);
+
+	pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value);
+}
+
+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_UHS2_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_UHS2_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_UHS2_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_UHS2_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, unsigned short vdd2)
+{
+	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;
+		}
+	}
+
+	if (mode != MMC_POWER_OFF) {
+		if (vdd2 != (unsigned short)-1) {
+			switch (1 << vdd2) {
+			case MMC_VDD2_165_195:
+				pwr |= SDHCI_VDD2_POWER_180;
+				break;
+			default:
+				WARN(1, "%s: Invalid vdd2 %#x\n",
+				     mmc_hostname(host->mmc), vdd2);
+				break;
+			}
+		}
+	}
+
+	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;
+		if (vdd2 != (unsigned short)-1)
+			pwr |= 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;
@@ -278,6 +633,7 @@ static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
 
 	slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
 	sdhci_enable_v4_mode(host);
+	gl9755_vendor_init(host);
 
 	return 0;
 }
@@ -319,11 +675,14 @@ static u32 sdhci_gl9750_readl(struct sdhci_host *host, int reg)
 
 static const struct sdhci_ops sdhci_gl9755_ops = {
 	.set_clock		= sdhci_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_pre_detect_init    = gl9755_pre_detect_init,
+	.uhs2_post_attach_sd    = gl9755_post_attach_sd,
 };
 
 const struct sdhci_pci_fixes sdhci_gl9755 = {
Signature · 1 line
2.24.1
author
#9 lore raw
In reply to Ben Chuang

Hi Uffe and Adrian,

Quoted 5 lines · Ben Chuang

Hi Uffe and Adrian,

These patches support UHS-II and fix GL9755 UHS-II compatibility.

Quoted 7 lines

The parts of UHS-II are based on [1][2] and porting to Linux 5.5-rc5. I have seen that Uffe comment that splitting the UHS-II parts into smaller patches. Other than splitting into small patches, could you give me some suggestions for refactoring/splitting files?

Best regards,
Ben

Gentle Ping, Any comments?

Best regards,
Ben

Quoted 59 lines

References:
1. [RFC,1/2] mmc: core: support UHS-II in core stack.
(https://patchwork.kernel.org/patch/5544441/)
2. [RFC,2/2] mmc: sdhci: support UHS-II in SDHCI host.
(https://patchwork.kernel.org/patch/5544451/)

v2:
- base on Linux v5.5-rc5

Ben Chuang (6):
mmc: Add UHS-II support in public headers
mmc: core: Add UHS-II support in core layer
mmc: host: Add UHS-II support in host layer
mmc: uhs2: Introduce a uhs2_post_attach_sd function
mmc: sdhci-uhs2: Introduce a uhs2_pre_detect_init function
mmc: sdhci-pci-gli: Fix power/reset/ZC/timeout for GL9755 UHS-II mode

 drivers/mmc/core/Makefile                  |   3 +-
 drivers/mmc/core/block.c                   |   7 +-
 drivers/mmc/core/bus.c                     |   5 +-
 drivers/mmc/core/core.c                    |  65 +-
 drivers/mmc/core/core.h                    |   3 +-
 drivers/mmc/core/regulator.c               |  14 +
 drivers/mmc/core/sd.c                      |  27 +-
 drivers/mmc/core/sd_ops.c                  |  12 +
 drivers/mmc/core/uhs2.c                    | 995 +++++++++++++++++++++
 drivers/mmc/core/uhs2.h                    |  23 +
 drivers/mmc/host/Makefile                  |   1 +
 drivers/mmc/host/{sdhci.c => sdhci-core.c} | 285 +++++-
 drivers/mmc/host/sdhci-milbeaut.c          |   4 +-
 drivers/mmc/host/sdhci-of-arasan.c         |   4 +-
 drivers/mmc/host/sdhci-of-at91.c           |   4 +-
 drivers/mmc/host/sdhci-omap.c              |   2 +-
 drivers/mmc/host/sdhci-pci-core.c          |   4 +-
 drivers/mmc/host/sdhci-pci-gli.c           | 361 +++++++-
 drivers/mmc/host/sdhci-pxav3.c             |   4 +-
 drivers/mmc/host/sdhci-uhs2.c              | 754 ++++++++++++++++
 drivers/mmc/host/sdhci-uhs2.h              |  34 +
 drivers/mmc/host/sdhci-xenon.c             |   4 +-
 drivers/mmc/host/sdhci.h                   | 286 +++++-
 drivers/mmc/host/sdhci_am654.c             |   4 +-
 include/linux/mmc/card.h                   |   1 +
 include/linux/mmc/core.h                   |   6 +
 include/linux/mmc/host.h                   |  31 +
 include/linux/mmc/uhs2.h                   | 270 ++++++
 28 files changed, 3137 insertions(+), 76 deletions(-)
 create mode 100644 drivers/mmc/core/uhs2.c
 create mode 100644 drivers/mmc/core/uhs2.h
 rename drivers/mmc/host/{sdhci.c => sdhci-core.c} (94%)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h
 create mode 100644 include/linux/mmc/uhs2.h

base-commit: c79f46a282390e0f5b306007bf7b11a46d529538 --
2.24.1

#10 lore raw
Quoted 14 lines · Ben Chuang

Hi Uffe and Adrian,

Quoted 10 lines · Ben Chuang

Hi Uffe and Adrian,

These patches support UHS-II and fix GL9755 UHS-II compatibility.

The parts of UHS-II are based on [1][2] and porting to Linux 5.5-rc5. I have seen that Uffe comment that splitting the UHS-II parts into smaller patches. Other than splitting into small patches, could you give me some suggestions for refactoring/splitting files?

Quoted 4 lines
Quoted 2 lines

Best regards,
Ben

Gentle Ping, Any comments?

I coming to this, but I need some additional time. In any case, thanks for posting this and for pinging!

[...]

Kind regards
Uffe

author
#11 lore raw
Quoted 16 lines · Ulf Hansson
Quoted 14 lines · Ben Chuang

Hi Uffe and Adrian,

Quoted 10 lines · Ben Chuang

Hi Uffe and Adrian,

These patches support UHS-II and fix GL9755 UHS-II compatibility.

The parts of UHS-II are based on [1][2] and porting to Linux 5.5-rc5. I have seen that Uffe comment that splitting the UHS-II parts into smaller patches. Other than splitting into small patches, could you give me some suggestions for refactoring/splitting files?

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Best regards,
Ben

Gentle Ping, Any comments?

I coming to this, but I need some additional time. In any case, thanks for posting this and for pinging!

Thank you for taking the time and pinging back quickly. :-) I will wait patiently for the next reply.

Quoted 4 lines

[...]

Kind regards
Uffe

Best regards,
Ben