mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 00/12] SDHCI updates
@ 2021-06-07 10:43 Sascha Hauer
  2021-06-07 10:44 ` [PATCH 01/12] mci: sdhci: straighten capabilities register Sascha Hauer
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:43 UTC (permalink / raw)
  To: Barebox List

This series has some updates for the common SDHCI support and finally
support for the eMMC controller found on Rockchip RK3568 SoCs.

Sascha Hauer (12):
  mci: sdhci: straighten capabilities register
  mci: sdhci: Add and use SDHCI_CAPABILITIES_1 defines
  mci: sdhci: Use SDHCI_MAX_DIV_SPEC_200 define
  mci: sdhci: port over some common functions from Linux
  mci: sdhci: imx: Use sdhci_setup_host()
  mci: sdhci: Use Linux defines for SDHCI_HOST_CONTROL register
  mci: sdhci: arasan: Use sdhci_setup_host()
  mci: sdhci: arasan: Use sdhci_set_bus_width()
  mci: sdhci: Use Linux defines for SDHCI_CLOCK_CONTROL register
  mci: sdhci: arasan: Use sdhci_set_clock()
  mci: sdhci: Get rid of many register ops
  mci: Add support for Rockchip variant of the dwcmshc

 drivers/mci/Kconfig                  |   7 +
 drivers/mci/Makefile                 |   1 +
 drivers/mci/arasan-sdhci.c           | 143 +---------
 drivers/mci/atmel-sdhci-common.c     |  72 ++---
 drivers/mci/dove-sdhci.c             |  84 ++----
 drivers/mci/imx-esdhc-common.c       |  21 +-
 drivers/mci/imx-esdhc-pbl.c          |  20 +-
 drivers/mci/imx-esdhc.c              |  20 +-
 drivers/mci/imx-esdhc.h              |   8 -
 drivers/mci/rockchip-dwcmshc-sdhci.c | 382 +++++++++++++++++++++++++++
 drivers/mci/sdhci.c                  | 281 ++++++++++++++++++++
 drivers/mci/sdhci.h                  | 159 +++++++++--
 include/mci.h                        |   2 +
 13 files changed, 879 insertions(+), 321 deletions(-)
 create mode 100644 drivers/mci/rockchip-dwcmshc-sdhci.c

-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 01/12] mci: sdhci: straighten capabilities register
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 02/12] mci: sdhci: Add and use SDHCI_CAPABILITIES_1 defines Sascha Hauer
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

So far we read the host capabilites register as two 16bit registers
SDHCI_CAPABILITIES (0x40) and SDHCI_CAPABILITIES_1 (0x42). Read them
as one 32bit register like Linux does. While at it switch to the
register defines Linux uses.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/arasan-sdhci.c       | 12 ++++++------
 drivers/mci/atmel-sdhci-common.c |  8 ++++----
 drivers/mci/dove-sdhci.c         | 15 +++++++--------
 drivers/mci/imx-esdhc.c          |  8 ++++----
 drivers/mci/imx-esdhc.h          |  7 -------
 drivers/mci/sdhci.h              | 23 +++++++++++++++++------
 6 files changed, 38 insertions(+), 35 deletions(-)

diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 520bf30ff9..53492e10d4 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -316,17 +316,17 @@ error:
 
 static void arasan_sdhci_set_mci_caps(struct arasan_sdhci_host *host)
 {
-	u16 caps = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
+	u32 caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
 
-	if ((caps & SDHCI_HOSTCAP_VOLTAGE_180) &&
+	if ((caps & SDHCI_CAN_VDD_180) &&
 	    !(host->quirks & SDHCI_ARASAN_QUIRK_NO_1_8_V))
 		host->mci.voltages |= MMC_VDD_165_195;
-	if (caps & SDHCI_HOSTCAP_VOLTAGE_300)
+	if (caps & SDHCI_CAN_VDD_300)
 		host->mci.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
-	if (caps & SDHCI_HOSTCAP_VOLTAGE_330)
+	if (caps & SDHCI_CAN_VDD_330)
 		host->mci.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
 
-	if (caps & SDHCI_HOSTCAP_HIGHSPEED)
+	if (caps & SDHCI_CAN_DO_HISPD)
 		host->mci.host_caps |= (MMC_CAP_MMC_HIGHSPEED_52MHZ |
 					MMC_CAP_MMC_HIGHSPEED |
 					MMC_CAP_SD_HIGHSPEED);
@@ -335,7 +335,7 @@ static void arasan_sdhci_set_mci_caps(struct arasan_sdhci_host *host)
 	mci_of_parse(&host->mci);
 
 	/* limit bus widths to controller capabilities */
-	if (!(caps & SDHCI_HOSTCAP_8BIT))
+	if (!(caps & SDHCI_CAN_DO_8BIT))
 		host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA;
 }
 
diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index a83610c3d0..92013feb95 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -42,13 +42,13 @@ void at91_sdhci_host_capability(struct at91_sdhci *host,
 {
 	u16 caps;
 
-	caps = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
+	caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
 
-	if (caps & SDHCI_HOSTCAP_VOLTAGE_330)
+	if (caps & SDHCI_CAN_VDD_330)
 		*voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
-	if (caps & SDHCI_HOSTCAP_VOLTAGE_300)
+	if (caps & SDHCI_CAN_VDD_300)
 		*voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
-	if (caps & SDHCI_HOSTCAP_VOLTAGE_180)
+	if (caps & SDHCI_CAN_VDD_180)
 		*voltages |= MMC_VDD_165_195;
 }
 
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
index c734a6e0dd..945c4bb4b1 100644
--- a/drivers/mci/dove-sdhci.c
+++ b/drivers/mci/dove-sdhci.c
@@ -290,19 +290,18 @@ static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev)
 
 static void dove_sdhci_set_mci_caps(struct dove_sdhci *host)
 {
-	u16 caps[2];
+	u32 caps;
 
-	caps[0] = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES);
-	caps[1] = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
+	caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
 
-	if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_180)
+	if (caps & SDHCI_CAN_VDD_180)
 		host->mci.voltages |= MMC_VDD_165_195;
-	if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_300)
+	if (caps & SDHCI_CAN_VDD_300)
 		host->mci.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
-	if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_330)
+	if (caps & SDHCI_CAN_VDD_330)
 		host->mci.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
 
-	if (caps[1] & SDHCI_HOSTCAP_HIGHSPEED)
+	if (caps & SDHCI_CAN_DO_HISPD)
 		host->mci.host_caps |= (MMC_CAP_MMC_HIGHSPEED_52MHZ |
 					MMC_CAP_MMC_HIGHSPEED |
 					MMC_CAP_SD_HIGHSPEED);
@@ -311,7 +310,7 @@ static void dove_sdhci_set_mci_caps(struct dove_sdhci *host)
 	mci_of_parse(&host->mci);
 
 	/* limit bus widths to controller capabilities */
-	if ((caps[1] & SDHCI_HOSTCAP_8BIT) == 0)
+	if ((caps & SDHCI_CAN_DO_8BIT) == 0)
 		host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA;
 }
 
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 93f3c57d4e..fa858a9853 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -271,11 +271,11 @@ static int fsl_esdhc_probe(struct device_d *dev)
 
 	caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
 
-	if (caps & ESDHC_HOSTCAPBLT_VS18)
+	if (caps & SDHCI_CAN_VDD_180)
 		mci->voltages |= MMC_VDD_165_195;
-	if (caps & ESDHC_HOSTCAPBLT_VS30)
+	if (caps & SDHCI_CAN_VDD_300)
 		mci->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
-	if (caps & ESDHC_HOSTCAPBLT_VS33)
+	if (caps & SDHCI_CAN_VDD_330)
 		mci->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
 
 	if (pdata) {
@@ -284,7 +284,7 @@ static int fsl_esdhc_probe(struct device_d *dev)
 			mci->devname = pdata->devname;
 	}
 
-	if (caps & ESDHC_HOSTCAPBLT_HSS)
+	if (caps & SDHCI_CAN_DO_HISPD)
 		mci->host_caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
 	host->mci.send_cmd = esdhc_send_cmd;
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index 8abe1207d7..0de1e72e7b 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -37,13 +37,6 @@
 #define BLKATTR_SIZE(x)	(x & 0x1fff)
 #define MAX_BLK_CNT	0x7fff	/* so malloc will have enough room with 32M */
 
-#define ESDHC_HOSTCAPBLT_VS18	0x04000000
-#define ESDHC_HOSTCAPBLT_VS30	0x02000000
-#define ESDHC_HOSTCAPBLT_VS33	0x01000000
-#define ESDHC_HOSTCAPBLT_SRS	0x00800000
-#define ESDHC_HOSTCAPBLT_DMAS	0x00400000
-#define ESDHC_HOSTCAPBLT_HSS	0x00200000
-
 #define PIO_TIMEOUT		100000
 
 #define IMX_SDHCI_WML		0x44
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 7b3f64486f..9bd9749dd6 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -105,12 +105,23 @@
 #define SDHCI_SIGNAL_ENABLE					0x38
 #define SDHCI_ACMD12_ERR__HOST_CONTROL2				0x3C
 #define SDHCI_CAPABILITIES					0x40
-#define SDHCI_CAPABILITIES_1					0x42
-#define  SDHCI_HOSTCAP_VOLTAGE_180		BIT(10)
-#define  SDHCI_HOSTCAP_VOLTAGE_300		BIT(9)
-#define  SDHCI_HOSTCAP_VOLTAGE_330		BIT(8)
-#define  SDHCI_HOSTCAP_HIGHSPEED		BIT(5)
-#define  SDHCI_HOSTCAP_8BIT			BIT(2)
+#define  SDHCI_TIMEOUT_CLK_MASK			GENMASK(5, 0)
+#define  SDHCI_TIMEOUT_CLK_UNIT			0x00000080
+#define  SDHCI_CLOCK_BASE_MASK			GENMASK(13, 8)
+#define  SDHCI_CLOCK_V3_BASE_MASK		GENMASK(15, 8)
+#define  SDHCI_MAX_BLOCK_MASK			0x00030000
+#define  SDHCI_MAX_BLOCK_SHIFT			16
+#define  SDHCI_CAN_DO_8BIT			0x00040000
+#define  SDHCI_CAN_DO_ADMA2			0x00080000
+#define  SDHCI_CAN_DO_ADMA1			0x00100000
+#define  SDHCI_CAN_DO_HISPD			0x00200000
+#define  SDHCI_CAN_DO_SDMA			0x00400000
+#define  SDHCI_CAN_DO_SUSPEND			0x00800000
+#define  SDHCI_CAN_VDD_330			0x01000000
+#define  SDHCI_CAN_VDD_300			0x02000000
+#define  SDHCI_CAN_VDD_180			0x04000000
+#define  SDHCI_CAN_64BIT_V4			0x08000000
+#define  SDHCI_CAN_64BIT			0x10000000
 
 #define  SDHCI_CLOCK_MUL_MASK	0x00FF0000
 #define  SDHCI_CLOCK_MUL_SHIFT	16
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 02/12] mci: sdhci: Add and use SDHCI_CAPABILITIES_1 defines
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
  2021-06-07 10:44 ` [PATCH 01/12] mci: sdhci: straighten capabilities register Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 03/12] mci: sdhci: Use SDHCI_MAX_DIV_SPEC_200 define Sascha Hauer
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

Linux has defines for the SDHCI_CAPABILITIES_1 register at offset 0x44.
Add these and convert the only user so far to use the defines.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/atmel-sdhci-common.c |  6 ++----
 drivers/mci/sdhci.h              | 15 ++++++++++++++-
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index 92013feb95..b391775b00 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -24,8 +24,6 @@
 
 #include "atmel-sdhci.h"
 
-#define AT91_SDHCI_CA1R		0x44	/* Capabilities 1 Register */
-
 #define AT91_SDHCI_MC1R		0x204
 #define		AT91_SDHCI_MC1_FCD		BIT(7)
 #define AT91_SDHCI_CALCR	0x240
@@ -237,9 +235,9 @@ static int at91_sdhci_set_clock(struct at91_sdhci *host, unsigned clock)
 	if (clock == 0)
 		return 0;
 
-	caps = sdhci_read32(sdhci, AT91_SDHCI_CA1R);
+	caps = sdhci_read32(sdhci, SDHCI_CAPABILITIES_1);
 
-	caps_clk_mult = (caps & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT;
+	caps_clk_mult = FIELD_GET(SDHCI_CLOCK_MUL_MASK, caps);
 
 	if (caps_clk_mult) {
 		for (clk_div = 1; clk_div <= 1024; clk_div++) {
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 9bd9749dd6..fd63cd84de 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -123,7 +123,20 @@
 #define  SDHCI_CAN_64BIT_V4			0x08000000
 #define  SDHCI_CAN_64BIT			0x10000000
 
-#define  SDHCI_CLOCK_MUL_MASK	0x00FF0000
+#define SDHCI_CAPABILITIES_1			0x44
+#define  SDHCI_SUPPORT_SDR50			0x00000001
+#define  SDHCI_SUPPORT_SDR104			0x00000002
+#define  SDHCI_SUPPORT_DDR50			0x00000004
+#define  SDHCI_DRIVER_TYPE_A			0x00000010
+#define  SDHCI_DRIVER_TYPE_C			0x00000020
+#define  SDHCI_DRIVER_TYPE_D			0x00000040
+#define  SDHCI_RETUNING_TIMER_COUNT_MASK	GENMASK(11, 8)
+#define  SDHCI_USE_SDR50_TUNING			0x00002000
+#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_HS400			0x80000000 /* Non-standard */
+
 #define  SDHCI_CLOCK_MUL_SHIFT	16
 
 #define SDHCI_SPEC_200_MAX_CLK_DIVIDER	256
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 03/12] mci: sdhci: Use SDHCI_MAX_DIV_SPEC_200 define
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
  2021-06-07 10:44 ` [PATCH 01/12] mci: sdhci: straighten capabilities register Sascha Hauer
  2021-06-07 10:44 ` [PATCH 02/12] mci: sdhci: Add and use SDHCI_CAPABILITIES_1 defines Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 04/12] mci: sdhci: port over some common functions from Linux Sascha Hauer
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

Linux uses SDHCI_MAX_DIV_SPEC_200 for what we have
SDHCI_SPEC_200_MAX_CLK_DIVIDER. Also we have SDHCI_MAX_DIV_SPEC_300
defined in the arasan driver. Use the Linux defines and add them
both to the header file.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/arasan-sdhci.c | 2 --
 drivers/mci/dove-sdhci.c   | 2 +-
 drivers/mci/sdhci.h        | 4 +++-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 53492e10d4..e22db4cfa3 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -152,8 +152,6 @@ static int arasan_sdhci_init(struct mci_host *mci, struct device_d *dev)
 	return 0;
 }
 
-#define SDHCI_MAX_DIV_SPEC_300		2046
-
 static u16 arasan_sdhci_get_clock_divider(struct arasan_sdhci_host *host,
 					  unsigned int reqclk)
 {
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
index 945c4bb4b1..9c10e67eb8 100644
--- a/drivers/mci/dove-sdhci.c
+++ b/drivers/mci/dove-sdhci.c
@@ -197,7 +197,7 @@ static u16 dove_sdhci_get_clock_divider(struct dove_sdhci *host, u32 reqclk)
 {
 	u16 div;
 
-	for (div = 1; div < SDHCI_SPEC_200_MAX_CLK_DIVIDER; div *= 2)
+	for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2)
 		if ((host->mci.f_max / div) <= reqclk)
 			break;
 	div /= 2;
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index fd63cd84de..aa6dd9824e 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -139,9 +139,11 @@
 
 #define  SDHCI_CLOCK_MUL_SHIFT	16
 
-#define SDHCI_SPEC_200_MAX_CLK_DIVIDER	256
 #define SDHCI_MMC_BOOT						0xC4
 
+#define SDHCI_MAX_DIV_SPEC_200	256
+#define SDHCI_MAX_DIV_SPEC_300	2046
+
 struct sdhci {
 	u32 (*read32)(struct sdhci *host, int reg);
 	u16 (*read16)(struct sdhci *host, int reg);
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 04/12] mci: sdhci: port over some common functions from Linux
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
                   ` (2 preceding siblings ...)
  2021-06-07 10:44 ` [PATCH 03/12] mci: sdhci: Use SDHCI_MAX_DIV_SPEC_200 define Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 05/12] mci: sdhci: imx: Use sdhci_setup_host() Sascha Hauer
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

This adds some functions useful for SDHCI drivers from Linux:

sdhci_calc_clk()
sdhci_set_clock()
sdhci_enable_clk()
sdhci_read_caps()
sdhci_set_bus_width()

These functions can be used to further unify our different SDHCI
drivers. All the new functions assume the also newly introduced
sdhci_setup_host() has been called before using them.

The functions are moslty the same as their Linux pendants, only
sdhci_calc_clk() takes an addional clock rate argument where Linux
uses host->max_clk. This is not suitable for the upcoming Rockchip
driver which needs to adjust the input clock using clk_set_rate(),
so fixed host->max_clk is not accurate for this driver.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/sdhci.c | 281 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/mci/sdhci.h |  53 +++++++++
 include/mci.h       |   2 +
 3 files changed, 336 insertions(+)

diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index dba26b2665..0783f6d420 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -4,6 +4,7 @@
 #include <driver.h>
 #include <mci.h>
 #include <io.h>
+#include <linux/bitfield.h>
 
 #include "sdhci.h"
 
@@ -88,6 +89,27 @@ static void sdhci_tx_pio(struct sdhci *sdhci, struct mci_data *data,
 		sdhci_write32(sdhci, SDHCI_BUFFER, buf[i]);
 }
 
+void sdhci_set_bus_width(struct sdhci *host, int width)
+{
+	u8 ctrl;
+
+	BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+	ctrl = sdhci_read8(host, SDHCI_HOST_CONTROL);
+	if (width == MMC_BUS_WIDTH_8) {
+		ctrl &= ~SDHCI_CTRL_4BITBUS;
+		ctrl |= SDHCI_CTRL_8BITBUS;
+	} else {
+		if (host->mci->host_caps & MMC_CAP_8_BIT_DATA)
+			ctrl &= ~SDHCI_CTRL_8BITBUS;
+		if (width == MMC_BUS_WIDTH_4)
+			ctrl |= SDHCI_CTRL_4BITBUS;
+		else
+			ctrl &= ~SDHCI_CTRL_4BITBUS;
+	}
+	sdhci_write8(host, SDHCI_HOST_CONTROL, ctrl);
+}
+
 #ifdef __PBL__
 /*
  * Stubs to make timeout logic below work in PBL
@@ -149,3 +171,262 @@ int sdhci_reset(struct sdhci *sdhci, u8 mask)
 					val, !(val & mask),
 					100 * USEC_PER_MSEC);
 }
+
+static u16 sdhci_get_preset_value(struct sdhci *host)
+{
+	u16 preset = 0;
+
+	BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+	switch (host->timing) {
+	case MMC_TIMING_UHS_SDR12:
+		preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR12);
+		break;
+	case MMC_TIMING_UHS_SDR25:
+		preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR25);
+		break;
+	case MMC_TIMING_UHS_SDR50:
+		preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR50);
+		break;
+	case MMC_TIMING_UHS_SDR104:
+	case MMC_TIMING_MMC_HS200:
+		preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR104);
+		break;
+	case MMC_TIMING_UHS_DDR50:
+	case MMC_TIMING_MMC_DDR52:
+		preset = sdhci_read16(host, SDHCI_PRESET_FOR_DDR50);
+		break;
+	case MMC_TIMING_MMC_HS400:
+		preset = sdhci_read16(host, SDHCI_PRESET_FOR_HS400);
+		break;
+	default:
+		dev_warn(host->mci->hw_dev, "Invalid UHS-I mode selected\n");
+		preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR12);
+		break;
+	}
+	return preset;
+}
+
+u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock,
+		   unsigned int *actual_clock, unsigned int input_clock)
+{
+	int div = 0; /* Initialized for compiler warning */
+	int real_div = div, clk_mul = 1;
+	u16 clk = 0;
+	bool switch_base_clk = false;
+
+	BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+	if (host->version >= SDHCI_SPEC_300) {
+		if (host->preset_enabled) {
+			u16 pre_val;
+
+			clk = sdhci_read16(host, SDHCI_CLOCK_CONTROL);
+			pre_val = sdhci_get_preset_value(host);
+			div = FIELD_GET(SDHCI_PRESET_SDCLK_FREQ_MASK, pre_val);
+			if (host->clk_mul &&
+				(pre_val & SDHCI_PRESET_CLKGEN_SEL)) {
+				clk = SDHCI_PROG_CLOCK_MODE;
+				real_div = div + 1;
+				clk_mul = host->clk_mul;
+			} else {
+				real_div = max_t(int, 1, div << 1);
+			}
+			goto clock_set;
+		}
+
+		/*
+		 * Check if the Host Controller supports Programmable Clock
+		 * Mode.
+		 */
+		if (host->clk_mul) {
+			for (div = 1; div <= 1024; div++) {
+				if ((input_clock * host->clk_mul / div)
+					<= clock)
+					break;
+			}
+			if ((input_clock * host->clk_mul / div) <= clock) {
+				/*
+				 * Set Programmable Clock Mode in the Clock
+				 * Control register.
+				 */
+				clk = SDHCI_PROG_CLOCK_MODE;
+				real_div = div;
+				clk_mul = host->clk_mul;
+				div--;
+			} else {
+				/*
+				 * Divisor can be too small to reach clock
+				 * speed requirement. Then use the base clock.
+				 */
+				switch_base_clk = true;
+			}
+		}
+
+		if (!host->clk_mul || switch_base_clk) {
+			/* Version 3.00 divisors must be a multiple of 2. */
+			if (input_clock <= clock)
+				div = 1;
+			else {
+				for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
+				     div += 2) {
+					if ((input_clock / div) <= clock)
+						break;
+				}
+			}
+			real_div = div;
+			div >>= 1;
+			if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN)
+				&& !div && input_clock <= 25000000)
+				div = 1;
+		}
+	} else {
+		/* Version 2.00 divisors must be a power of 2. */
+		for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
+			if ((input_clock / div) <= clock)
+				break;
+		}
+		real_div = div;
+		div >>= 1;
+	}
+
+clock_set:
+	if (real_div)
+		*actual_clock = (input_clock * clk_mul) / real_div;
+	clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+	clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
+		<< SDHCI_DIVIDER_HI_SHIFT;
+
+	return clk;
+}
+
+void sdhci_enable_clk(struct sdhci *host, u16 clk)
+{
+	u64 start;
+
+	BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+	clk |= SDHCI_CLOCK_INT_EN;
+	sdhci_write16(host, SDHCI_CLOCK_CONTROL, clk);
+
+	start = get_time_ns();
+	while (!(sdhci_read16(host, SDHCI_CLOCK_CONTROL) &
+		SDHCI_CLOCK_INT_STABLE)) {
+		if (is_timeout(start, 150 * MSECOND)) {
+			dev_err(host->mci->hw_dev,
+					"SDHCI clock stable timeout\n");
+			return;
+		}
+	}
+
+	clk |= SDHCI_CLOCK_CARD_EN;
+	sdhci_write16(host, SDHCI_CLOCK_CONTROL, clk);
+}
+
+void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_clock)
+{
+	u16 clk;
+
+	BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+	host->mci->clock = 0;
+
+	sdhci_write16(host, SDHCI_CLOCK_CONTROL, 0);
+
+	if (clock == 0)
+		return;
+
+	clk = sdhci_calc_clk(host, clock, &host->mci->clock, input_clock);
+	sdhci_enable_clk(host, clk);
+}
+
+void __sdhci_read_caps(struct sdhci *host, const u16 *ver,
+			const u32 *caps, const u32 *caps1)
+{
+	u16 v;
+	u64 dt_caps_mask = 0;
+	u64 dt_caps = 0;
+	struct device_node *np = host->mci->hw_dev->device_node;
+
+	BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+	if (host->read_caps)
+		return;
+
+	host->read_caps = true;
+
+	sdhci_reset(host, SDHCI_RESET_ALL);
+
+	of_property_read_u64(np, "sdhci-caps-mask", &dt_caps_mask);
+	of_property_read_u64(np, "sdhci-caps", &dt_caps);
+
+	v = ver ? *ver : sdhci_read16(host, SDHCI_HOST_VERSION);
+	host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
+
+	if (host->quirks & SDHCI_QUIRK_MISSING_CAPS)
+		return;
+
+	if (caps) {
+		host->caps = *caps;
+	} else {
+		host->caps = sdhci_read32(host, SDHCI_CAPABILITIES);
+		host->caps &= ~lower_32_bits(dt_caps_mask);
+		host->caps |= lower_32_bits(dt_caps);
+	}
+
+	if (host->version < SDHCI_SPEC_300)
+		return;
+
+	if (caps1) {
+		host->caps1 = *caps1;
+	} else {
+		host->caps1 = sdhci_read32(host, SDHCI_CAPABILITIES_1);
+		host->caps1 &= ~upper_32_bits(dt_caps_mask);
+		host->caps1 |= upper_32_bits(dt_caps);
+	}
+}
+
+int sdhci_setup_host(struct sdhci *host)
+{
+	struct mci_host *mci = host->mci;
+
+	BUG_ON(!mci);
+
+	sdhci_read_caps(host);
+
+	if (!host->max_clk) {
+		if (host->version >= SDHCI_SPEC_300)
+			host->max_clk = FIELD_GET(SDHCI_CLOCK_V3_BASE_MASK, host->caps);
+		else
+			host->max_clk = FIELD_GET(SDHCI_CLOCK_BASE_MASK, host->caps);
+
+		host->max_clk *= 1000000;
+	}
+
+	/*
+	 * In case of Host Controller v3.00, find out whether clock
+	 * multiplier is supported.
+	 */
+	host->clk_mul = FIELD_GET(SDHCI_CLOCK_MUL_MASK, host->caps1);
+
+	/*
+	 * In case the value in Clock Multiplier is 0, then programmable
+	 * clock mode is not supported, otherwise the actual clock
+	 * multiplier is one more than the value of Clock Multiplier
+	 * in the Capabilities Register.
+	 */
+	if (host->clk_mul)
+		host->clk_mul += 1;
+
+	if (host->caps & SDHCI_CAN_VDD_180)
+		mci->voltages |= MMC_VDD_165_195;
+	if (host->caps & SDHCI_CAN_VDD_300)
+		mci->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
+	if (host->caps & SDHCI_CAN_VDD_330)
+		mci->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
+
+	if (host->caps & SDHCI_CAN_DO_HISPD)
+		mci->host_caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
+
+	return 0;
+}
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index aa6dd9824e..872caabde5 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -69,7 +69,9 @@
 #define  SDHCI_BUS_POWER_EN			BIT(0)
 #define SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET	0x2c
 #define SDHCI_CLOCK_CONTROL					0x2c
+#define  SDHCI_DIVIDER_SHIFT			8
 #define  SDHCI_DIVIDER_HI_SHIFT			6
+#define  SDHCI_DIV_MASK				0xFF
 #define  SDHCI_DIV_HI_MASK			0x300
 #define  SDHCI_DIV_MASK_LEN			8
 #define  SDHCI_FREQ_SEL(x)			(((x) & 0xff) << 8)
@@ -137,6 +139,27 @@
 #define  SDHCI_CAN_DO_ADMA3			0x08000000
 #define  SDHCI_SUPPORT_HS400			0x80000000 /* Non-standard */
 
+#define SDHCI_PRESET_FOR_SDR12	0x66
+#define SDHCI_PRESET_FOR_SDR25	0x68
+#define SDHCI_PRESET_FOR_SDR50	0x6A
+#define SDHCI_PRESET_FOR_SDR104	0x6C
+#define SDHCI_PRESET_FOR_DDR50	0x6E
+#define SDHCI_PRESET_FOR_HS400	0x74 /* Non-standard */
+#define SDHCI_PRESET_CLKGEN_SEL		BIT(10)
+#define SDHCI_PRESET_SDCLK_FREQ_MASK	GENMASK(9, 0)
+
+#define SDHCI_HOST_VERSION	0xFE
+#define  SDHCI_VENDOR_VER_MASK	0xFF00
+#define  SDHCI_VENDOR_VER_SHIFT	8
+#define  SDHCI_SPEC_VER_MASK	0x00FF
+#define  SDHCI_SPEC_VER_SHIFT	0
+#define   SDHCI_SPEC_100	0
+#define   SDHCI_SPEC_200	1
+#define   SDHCI_SPEC_300	2
+#define   SDHCI_SPEC_400	3
+#define   SDHCI_SPEC_410	4
+#define   SDHCI_SPEC_420	5
+
 #define  SDHCI_CLOCK_MUL_SHIFT	16
 
 #define SDHCI_MMC_BOOT						0xC4
@@ -151,6 +174,24 @@ struct sdhci {
 	void (*write32)(struct sdhci *host, int reg, u32 val);
 	void (*write16)(struct sdhci *host, int reg, u16 val);
 	void (*write8)(struct sdhci *host, int reg, u8 val);
+
+	int max_clk; /* Max possible freq (Hz) */
+	int clk_mul; /* Clock Muliplier value */
+
+	unsigned int version; /* SDHCI spec. version */
+
+	enum mci_timing timing;
+	bool preset_enabled; /* Preset is enabled */
+
+	unsigned int quirks;
+#define SDHCI_QUIRK_MISSING_CAPS		BIT(27)
+	unsigned int quirks2;
+#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN	BIT(15)
+	u32 caps;	/* CAPABILITY_0 */
+	u32 caps1;	/* CAPABILITY_1 */
+	bool read_caps;	/* Capability flags have been read */
+
+	struct mci_host	*mci;
 };
 
 static inline u32 sdhci_read32(struct sdhci *host, int reg)
@@ -189,6 +230,18 @@ void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd,
 			     u32 *xfer);
 int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data);
 int sdhci_reset(struct sdhci *sdhci, u8 mask);
+u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock,
+		   unsigned int *actual_clock, unsigned int input_clock);
+void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_clock);
+void sdhci_enable_clk(struct sdhci *host, u16 clk);
+int sdhci_setup_host(struct sdhci *host);
+void __sdhci_read_caps(struct sdhci *host, const u16 *ver,
+			const u32 *caps, const u32 *caps1);
+static inline void sdhci_read_caps(struct sdhci *host)
+{
+	__sdhci_read_caps(host, NULL, NULL, NULL);
+}
+void sdhci_set_bus_width(struct sdhci *host, int width);
 
 #define sdhci_read8_poll_timeout(sdhci, reg, val, cond, timeout_us) \
 	read_poll_timeout(sdhci_read8, val, cond, timeout_us, sdhci, reg)
diff --git a/include/mci.h b/include/mci.h
index 5e6805e8dc..df2437f618 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -365,6 +365,8 @@ enum mci_timing {
 	MMC_TIMING_UHS_SDR104	= 4,
 	MMC_TIMING_UHS_DDR50	= 5,
 	MMC_TIMING_MMC_HS200	= 6,
+	MMC_TIMING_MMC_DDR52	= 7,
+	MMC_TIMING_MMC_HS400	= 8,
 };
 
 struct mci_ios {
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 05/12] mci: sdhci: imx: Use sdhci_setup_host()
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
                   ` (3 preceding siblings ...)
  2021-06-07 10:44 ` [PATCH 04/12] mci: sdhci: port over some common functions from Linux Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 06/12] mci: sdhci: Use Linux defines for SDHCI_HOST_CONTROL register Sascha Hauer
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

sdhci_setup_host() handles reading the caps. Call it instead of doing it
in the driver.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/imx-esdhc.c | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index fa858a9853..12e98ce26a 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -230,7 +230,6 @@ static int fsl_esdhc_probe(struct device_d *dev)
 	struct resource *iores;
 	struct fsl_esdhc_host *host;
 	struct mci_host *mci;
-	u32 caps;
 	int ret;
 	unsigned long rate;
 	struct esdhc_platform_data *pdata = dev->platform_data;
@@ -269,29 +268,22 @@ static int fsl_esdhc_probe(struct device_d *dev)
 
 	esdhc_populate_sdhci(host);
 
-	caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
-
-	if (caps & SDHCI_CAN_VDD_180)
-		mci->voltages |= MMC_VDD_165_195;
-	if (caps & SDHCI_CAN_VDD_300)
-		mci->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
-	if (caps & SDHCI_CAN_VDD_330)
-		mci->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
-
 	if (pdata) {
 		mci->host_caps = pdata->caps;
 		if (pdata->devname)
 			mci->devname = pdata->devname;
 	}
 
-	if (caps & SDHCI_CAN_DO_HISPD)
-		mci->host_caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
-
 	host->mci.send_cmd = esdhc_send_cmd;
 	host->mci.set_ios = esdhc_set_ios;
 	host->mci.init = esdhc_init;
 	host->mci.card_present = esdhc_card_present;
 	host->mci.hw_dev = dev;
+	host->sdhci.mci = &host->mci;
+
+	ret = sdhci_setup_host(&host->sdhci);
+	if (ret)
+		goto err_clk_disable;
 
 	rate = clk_get_rate(host->clk);
 	host->mci.f_min = rate >> 12;
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 06/12] mci: sdhci: Use Linux defines for SDHCI_HOST_CONTROL register
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
                   ` (4 preceding siblings ...)
  2021-06-07 10:44 ` [PATCH 05/12] mci: sdhci: imx: Use sdhci_setup_host() Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 07/12] mci: sdhci: arasan: Use sdhci_setup_host() Sascha Hauer
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

To ease porting and comparing of Linux code.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/arasan-sdhci.c       | 12 ++++++------
 drivers/mci/atmel-sdhci-common.c | 14 +++++++-------
 drivers/mci/dove-sdhci.c         | 10 +++++-----
 drivers/mci/sdhci.h              | 17 ++++++++++++-----
 4 files changed, 30 insertions(+), 23 deletions(-)

diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index e22db4cfa3..e02f222345 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -124,7 +124,7 @@ static int arasan_sdhci_reset(struct arasan_sdhci_host *host, u8 mask)
 		u8 ctrl;
 
 		ctrl = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
-		ctrl |= SDHCI_CARD_DETECT_TEST_LEVEL | SDHCI_CARD_DETECT_SIGNAL_SELECTION;
+		ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_INS;
 		sdhci_write8(&host->sdhci, ctrl, SDHCI_HOST_CONTROL);
 	}
 
@@ -200,21 +200,21 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 	}
 
 	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
-			~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
+			~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);
 
 	switch (ios->bus_width) {
 	case MMC_BUS_WIDTH_8:
-		val |= SDHCI_DATA_WIDTH_8BIT;
+		val |= SDHCI_CTRL_8BITBUS;
 		break;
 	case MMC_BUS_WIDTH_4:
-		val |= SDHCI_DATA_WIDTH_4BIT;
+		val |= SDHCI_CTRL_8BITBUS;
 		break;
 	}
 
 	if (ios->clock > 26000000)
-		val |= SDHCI_HIGHSPEED_EN;
+		val |= SDHCI_CTRL_HISPD;
 	else
-		val &= ~SDHCI_HIGHSPEED_EN;
+		val &= ~SDHCI_CTRL_HISPD;
 
 	sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
 }
diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index b391775b00..d2b777a93c 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -279,9 +279,9 @@ static int at91_sdhci_set_clock(struct at91_sdhci *host, unsigned clock)
 
 	reg = sdhci_read8(sdhci, SDHCI_HOST_CONTROL);
 	if (clock > 26000000)
-		reg |= SDHCI_HIGHSPEED_EN;
+		reg |= SDHCI_CTRL_HISPD;
 	else
-		reg &= ~SDHCI_HIGHSPEED_EN;
+		reg &= ~SDHCI_CTRL_HISPD;
 
 	sdhci_write8(sdhci, SDHCI_HOST_CONTROL, reg);
 
@@ -297,15 +297,15 @@ static int at91_sdhci_set_bus_width(struct at91_sdhci *host, unsigned bus_width)
 
 	switch(bus_width) {
 	case MMC_BUS_WIDTH_8:
-		reg |= SDHCI_DATA_WIDTH_8BIT;
+		reg |= SDHCI_CTRL_8BITBUS;
 		break;
 	case MMC_BUS_WIDTH_4:
-		reg &= ~SDHCI_DATA_WIDTH_8BIT;
-		reg |= SDHCI_DATA_WIDTH_4BIT;
+		reg &= ~SDHCI_CTRL_8BITBUS;
+		reg |= SDHCI_CTRL_8BITBUS;
 		break;
 	default:
-		reg &= ~SDHCI_DATA_WIDTH_8BIT;
-		reg &= ~SDHCI_DATA_WIDTH_4BIT;
+		reg &= ~SDHCI_CTRL_8BITBUS;
+		reg &= ~SDHCI_CTRL_8BITBUS;
 	}
 
 	sdhci_write8(sdhci, SDHCI_HOST_CONTROL, reg);
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
index 9c10e67eb8..cafc9dc579 100644
--- a/drivers/mci/dove-sdhci.c
+++ b/drivers/mci/dove-sdhci.c
@@ -224,20 +224,20 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 
 	/* set bus width */
 	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
-		~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
+		~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);
 	switch (ios->bus_width) {
 	case MMC_BUS_WIDTH_8:
-		val |= SDHCI_DATA_WIDTH_8BIT;
+		val |= SDHCI_CTRL_8BITBUS;
 		break;
 	case MMC_BUS_WIDTH_4:
-		val |= SDHCI_DATA_WIDTH_4BIT;
+		val |= SDHCI_CTRL_8BITBUS;
 		break;
 	}
 
 	if (ios->clock > 26000000)
-		val |= SDHCI_HIGHSPEED_EN;
+		val |= SDHCI_CTRL_HISPD;
 	else
-		val &= ~SDHCI_HIGHSPEED_EN;
+		val &= ~SDHCI_CTRL_HISPD;
 
 	sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
 
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 872caabde5..0b436d3aa2 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -54,11 +54,18 @@
 #define SDHCI_PRESENT_STATE1					0x26
 #define SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL	0x28
 #define SDHCI_HOST_CONTROL					0x28
-#define  SDHCI_CARD_DETECT_SIGNAL_SELECTION	BIT(7)
-#define  SDHCI_CARD_DETECT_TEST_LEVEL		BIT(6)
-#define  SDHCI_DATA_WIDTH_8BIT			BIT(5)
-#define  SDHCI_HIGHSPEED_EN			BIT(2)
-#define  SDHCI_DATA_WIDTH_4BIT			BIT(1)
+#define  SDHCI_CTRL_LED         BIT(0)
+#define  SDHCI_CTRL_4BITBUS     BIT(1)
+#define  SDHCI_CTRL_HISPD       BIT(2)
+#define  SDHCI_CTRL_DMA_MASK    0x18
+#define   SDHCI_CTRL_SDMA       0x00
+#define   SDHCI_CTRL_ADMA1      0x08
+#define   SDHCI_CTRL_ADMA32     0x10
+#define   SDHCI_CTRL_ADMA64     0x18
+#define   SDHCI_CTRL_ADMA3      0x18
+#define  SDHCI_CTRL_8BITBUS     BIT(5)
+#define  SDHCI_CTRL_CDTEST_INS  BIT(6)
+#define  SDHCI_CTRL_CDTEST_EN   BIT(7)
 #define SDHCI_POWER_CONTROL					0x29
 #define  SDHCI_POWER_ON				0x01
 #define  SDHCI_POWER_180			0x0A
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 07/12] mci: sdhci: arasan: Use sdhci_setup_host()
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
                   ` (5 preceding siblings ...)
  2021-06-07 10:44 ` [PATCH 06/12] mci: sdhci: Use Linux defines for SDHCI_HOST_CONTROL register Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 08/12] mci: sdhci: arasan: Use sdhci_set_bus_width() Sascha Hauer
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

Use common code instead of duplicating it in the driver.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/arasan-sdhci.c | 32 +++++---------------------------
 1 file changed, 5 insertions(+), 27 deletions(-)

diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index e02f222345..acc2827f1d 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -311,32 +311,6 @@ error:
 	return ret;
 }
 
-
-static void arasan_sdhci_set_mci_caps(struct arasan_sdhci_host *host)
-{
-	u32 caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
-
-	if ((caps & SDHCI_CAN_VDD_180) &&
-	    !(host->quirks & SDHCI_ARASAN_QUIRK_NO_1_8_V))
-		host->mci.voltages |= MMC_VDD_165_195;
-	if (caps & SDHCI_CAN_VDD_300)
-		host->mci.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
-	if (caps & SDHCI_CAN_VDD_330)
-		host->mci.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
-
-	if (caps & SDHCI_CAN_DO_HISPD)
-		host->mci.host_caps |= (MMC_CAP_MMC_HIGHSPEED_52MHZ |
-					MMC_CAP_MMC_HIGHSPEED |
-					MMC_CAP_SD_HIGHSPEED);
-
-	/* parse board supported bus width capabilities */
-	mci_of_parse(&host->mci);
-
-	/* limit bus widths to controller capabilities */
-	if (!(caps & SDHCI_CAN_DO_8BIT))
-		host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA;
-}
-
 static int arasan_sdhci_probe(struct device_d *dev)
 {
 	struct device_node *np = dev->device_node;
@@ -391,6 +365,7 @@ static int arasan_sdhci_probe(struct device_d *dev)
 	arasan_sdhci->sdhci.write32 = arasan_sdhci_writel;
 	arasan_sdhci->sdhci.write16 = arasan_sdhci_writew;
 	arasan_sdhci->sdhci.write8 = arasan_sdhci_writeb;
+	arasan_sdhci->sdhci.mci = mci;
 	mci->send_cmd = arasan_sdhci_send_cmd;
 	mci->set_ios = arasan_sdhci_set_ios;
 	mci->init = arasan_sdhci_init;
@@ -401,7 +376,10 @@ static int arasan_sdhci_probe(struct device_d *dev)
 	mci->f_max = clk_get_rate(clk_xin);
 	mci->f_min = 50000000 / 256;
 
-	arasan_sdhci_set_mci_caps(arasan_sdhci);
+	/* parse board supported bus width capabilities */
+	mci_of_parse(&arasan_sdhci->mci);
+
+	sdhci_setup_host(&arasan_sdhci->sdhci);
 
 	dev->priv = arasan_sdhci;
 
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 08/12] mci: sdhci: arasan: Use sdhci_set_bus_width()
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
                   ` (6 preceding siblings ...)
  2021-06-07 10:44 ` [PATCH 07/12] mci: sdhci: arasan: Use sdhci_setup_host() Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 09/12] mci: sdhci: Use Linux defines for SDHCI_CLOCK_CONTROL register Sascha Hauer
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

Use common code rather than duplicating it in the driver.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/arasan-sdhci.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index acc2827f1d..7bd98c0a96 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -199,17 +199,9 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 				    val | SDHCI_SDCLOCK_EN);
 	}
 
-	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
-			~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);
-
-	switch (ios->bus_width) {
-	case MMC_BUS_WIDTH_8:
-		val |= SDHCI_CTRL_8BITBUS;
-		break;
-	case MMC_BUS_WIDTH_4:
-		val |= SDHCI_CTRL_8BITBUS;
-		break;
-	}
+	sdhci_set_bus_width(&host->sdhci, ios->bus_width);
+
+	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
 
 	if (ios->clock > 26000000)
 		val |= SDHCI_CTRL_HISPD;
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 09/12] mci: sdhci: Use Linux defines for SDHCI_CLOCK_CONTROL register
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
                   ` (7 preceding siblings ...)
  2021-06-07 10:44 ` [PATCH 08/12] mci: sdhci: arasan: Use sdhci_set_bus_width() Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 10/12] mci: sdhci: arasan: Use sdhci_set_clock() Sascha Hauer
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

Convert another register to use the Linux defines.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/arasan-sdhci.c       |  6 +++---
 drivers/mci/atmel-sdhci-common.c |  6 +++---
 drivers/mci/dove-sdhci.c         |  6 +++---
 drivers/mci/sdhci.h              | 13 +++++++------
 4 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 7bd98c0a96..180f0042bf 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -182,12 +182,12 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 		val = arasan_sdhci_get_clock_divider(host, ios->clock);
 		/* Bit 6 & 7 are upperbits of 10bit divider */
 		val = SDHCI_FREQ_SEL(val) | SDHCI_FREQ_SEL_10_BIT(val);
-		val |= SDHCI_INTCLOCK_EN;
+		val |= SDHCI_CLOCK_INT_EN;
 		sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val);
 
 		start = get_time_ns();
 		while (!(sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL) &
-			SDHCI_INTCLOCK_STABLE)) {
+			SDHCI_CLOCK_INT_STABLE)) {
 			if (is_timeout(start, 20 * MSECOND)) {
 				dev_err(host->mci.hw_dev,
 						"SDHCI clock stable timeout\n");
@@ -196,7 +196,7 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 		}
 		/* enable bus clock */
 		sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL,
-				    val | SDHCI_SDCLOCK_EN);
+				    val | SDHCI_CLOCK_CARD_EN);
 	}
 
 	sdhci_set_bus_width(&host->sdhci, ios->bus_width);
diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index d2b777a93c..5a734d0d47 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -262,19 +262,19 @@ static int at91_sdhci_set_clock(struct at91_sdhci *host, unsigned clock)
 	clk |= SDHCI_FREQ_SEL(clk_div);
 	clk |= ((clk_div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
 		<< SDHCI_DIVIDER_HI_SHIFT;
-	clk |= SDHCI_INTCLOCK_EN;
+	clk |= SDHCI_CLOCK_INT_EN;
 
 	sdhci_write16(sdhci, SDHCI_CLOCK_CONTROL, clk);
 
 	ret = sdhci_read32_poll_timeout(sdhci, SDHCI_CLOCK_CONTROL, clk,
-					clk & SDHCI_INTCLOCK_STABLE,
+					clk & SDHCI_CLOCK_INT_STABLE,
 					20 * USEC_PER_MSEC);
 	if (ret) {
 		dev_warn(host->dev, "Timeout waiting for clock stable\n");
 		return ret;
 	}
 
-	clk |= SDHCI_SDCLOCK_EN;
+	clk |= SDHCI_CLOCK_CARD_EN;
 	sdhci_write16(sdhci, SDHCI_CLOCK_CONTROL, clk);
 
 	reg = sdhci_read8(sdhci, SDHCI_HOST_CONTROL);
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
index cafc9dc579..f4f8dabba1 100644
--- a/drivers/mci/dove-sdhci.c
+++ b/drivers/mci/dove-sdhci.c
@@ -244,13 +244,13 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 	/* set bus clock */
 	sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
 	val = dove_sdhci_get_clock_divider(host, ios->clock);
-	val = SDHCI_INTCLOCK_EN | SDHCI_FREQ_SEL(val);
+	val = SDHCI_CLOCK_INT_EN | SDHCI_FREQ_SEL(val);
 	sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val);
 
 	/* wait for internal clock stable */
 	start = get_time_ns();
 	while (!(sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL) &
-			SDHCI_INTCLOCK_STABLE)) {
+			SDHCI_CLOCK_INT_STABLE)) {
 		if (is_timeout(start, 20 * MSECOND)) {
 			dev_err(host->mci.hw_dev, "SDHCI clock stable timeout\n");
 			return;
@@ -258,7 +258,7 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 	}
 
 	/* enable bus clock */
-	sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val | SDHCI_SDCLOCK_EN);
+	sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val | SDHCI_CLOCK_CARD_EN);
 }
 
 static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev)
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 0b436d3aa2..2605ecb535 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -75,17 +75,18 @@
 #define  SDHCI_BUS_VOLTAGE(v)			((v) << 1)
 #define  SDHCI_BUS_POWER_EN			BIT(0)
 #define SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET	0x2c
-#define SDHCI_CLOCK_CONTROL					0x2c
+#define SDHCI_CLOCK_CONTROL					0x2C
 #define  SDHCI_DIVIDER_SHIFT			8
 #define  SDHCI_DIVIDER_HI_SHIFT			6
 #define  SDHCI_DIV_MASK				0xFF
-#define  SDHCI_DIV_HI_MASK			0x300
 #define  SDHCI_DIV_MASK_LEN			8
-#define  SDHCI_FREQ_SEL(x)			(((x) & 0xff) << 8)
+#define  SDHCI_FREQ_SEL(x)                     (((x) & 0xff) << 8)
+#define  SDHCI_DIV_HI_MASK			0x300
 #define  SDHCI_PROG_CLOCK_MODE			BIT(5)
-#define  SDHCI_SDCLOCK_EN			BIT(2)
-#define  SDHCI_INTCLOCK_STABLE			BIT(1)
-#define  SDHCI_INTCLOCK_EN			BIT(0)
+#define  SDHCI_CLOCK_CARD_EN			BIT(2)
+#define  SDHCI_CLOCK_PLL_EN			BIT(3)
+#define  SDHCI_CLOCK_INT_STABLE			BIT(1)
+#define  SDHCI_CLOCK_INT_EN     		BIT(0)
 #define SDHCI_TIMEOUT_CONTROL					0x2e
 #define SDHCI_SOFTWARE_RESET					0x2f
 #define  SDHCI_RESET_ALL			BIT(0)
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 10/12] mci: sdhci: arasan: Use sdhci_set_clock()
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
                   ` (8 preceding siblings ...)
  2021-06-07 10:44 ` [PATCH 09/12] mci: sdhci: Use Linux defines for SDHCI_CLOCK_CONTROL register Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 11/12] mci: sdhci: Get rid of many register ops Sascha Hauer
  2021-06-07 10:44 ` [PATCH 12/12] mci: Add support for Rockchip variant of the dwcmshc Sascha Hauer
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

We now have a function to calculate the clock divider. Use it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/arasan-sdhci.c | 40 ++------------------------------------
 1 file changed, 2 insertions(+), 38 deletions(-)

diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 180f0042bf..8a5e85109c 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -152,21 +152,6 @@ static int arasan_sdhci_init(struct mci_host *mci, struct device_d *dev)
 	return 0;
 }
 
-static u16 arasan_sdhci_get_clock_divider(struct arasan_sdhci_host *host,
-					  unsigned int reqclk)
-{
-	u16 div;
-
-	for (div = 1; div < SDHCI_MAX_DIV_SPEC_300; div += 2)
-		if ((host->mci.f_max / div) <= reqclk)
-			break;
-	div /= 2;
-
-	return div;
-}
-
-#define SDHCI_FREQ_SEL_10_BIT(x)	(((x) & 0x300) >> 2)
-
 static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 {
 	struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
@@ -175,29 +160,8 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
 	/* stop clock */
 	sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
 
-	if (ios->clock) {
-		u64 start;
-
-		/* set & start clock */
-		val = arasan_sdhci_get_clock_divider(host, ios->clock);
-		/* Bit 6 & 7 are upperbits of 10bit divider */
-		val = SDHCI_FREQ_SEL(val) | SDHCI_FREQ_SEL_10_BIT(val);
-		val |= SDHCI_CLOCK_INT_EN;
-		sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val);
-
-		start = get_time_ns();
-		while (!(sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL) &
-			SDHCI_CLOCK_INT_STABLE)) {
-			if (is_timeout(start, 20 * MSECOND)) {
-				dev_err(host->mci.hw_dev,
-						"SDHCI clock stable timeout\n");
-				return;
-			}
-		}
-		/* enable bus clock */
-		sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL,
-				    val | SDHCI_CLOCK_CARD_EN);
-	}
+	if (ios->clock)
+		sdhci_set_clock(&host->sdhci, ios->clock, host->sdhci.max_clk);
 
 	sdhci_set_bus_width(&host->sdhci, ios->bus_width);
 
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 11/12] mci: sdhci: Get rid of many register ops
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
                   ` (9 preceding siblings ...)
  2021-06-07 10:44 ` [PATCH 10/12] mci: sdhci: arasan: Use sdhci_set_clock() Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  2021-06-07 10:44 ` [PATCH 12/12] mci: Add support for Rockchip variant of the dwcmshc Sascha Hauer
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

Most SDHCI drivers use standard readl/writel to access registers.
Implement these in the common register accessor functions so that
drivers only to overwrite them when they want to do something different.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/arasan-sdhci.c       | 51 +-------------------------------
 drivers/mci/atmel-sdhci-common.c | 38 +-----------------------
 drivers/mci/dove-sdhci.c         | 51 +-------------------------------
 drivers/mci/imx-esdhc-common.c   | 21 +++++++------
 drivers/mci/imx-esdhc-pbl.c      | 20 ++++++-------
 drivers/mci/imx-esdhc.c          |  2 +-
 drivers/mci/imx-esdhc.h          |  1 -
 drivers/mci/sdhci.h              | 32 ++++++++++++++++----
 8 files changed, 50 insertions(+), 166 deletions(-)

diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 8a5e85109c..c19e1022c5 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -33,7 +33,6 @@
 struct arasan_sdhci_host {
 	struct mci_host		mci;
 	struct sdhci		sdhci;
-	void __iomem		*ioaddr;
 	unsigned int		quirks; /* Arasan deviations from spec */
 /* Controller does not have CD wired and will not function normally without */
 #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST		BIT(0)
@@ -53,48 +52,6 @@ struct arasan_sdhci_host *sdhci_to_arasan(struct sdhci *sdhci)
 	return container_of(sdhci, struct arasan_sdhci_host, sdhci);
 }
 
-static void arasan_sdhci_writel(struct sdhci *sdhci, int reg, u32 val)
-{
-	struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
-	writel(val, p->ioaddr + reg);
-}
-
-static void arasan_sdhci_writew(struct sdhci *sdhci, int reg, u16 val)
-{
-	struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
-	writew(val, p->ioaddr + reg);
-}
-
-static void arasan_sdhci_writeb(struct sdhci *sdhci, int reg, u8 val)
-{
-	struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
-	writeb(val, p->ioaddr + reg);
-}
-
-static u32 arasan_sdhci_readl(struct sdhci *sdhci, int reg)
-{
-	struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
-	return readl(p->ioaddr + reg);
-}
-
-static u16 arasan_sdhci_readw(struct sdhci *sdhci, int reg)
-{
-	struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
-	return readw(p->ioaddr + reg);
-}
-
-static u8 arasan_sdhci_readb(struct sdhci *sdhci, int reg)
-{
-	struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
-	return readb(p->ioaddr + reg);
-}
-
 static int arasan_sdhci_card_present(struct mci_host *mci)
 {
 	struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
@@ -283,7 +240,6 @@ static int arasan_sdhci_probe(struct device_d *dev)
 	iores = dev_request_mem_resource(dev, 0);
 	if (IS_ERR(iores))
 		return PTR_ERR(iores);
-	arasan_sdhci->ioaddr = IOMEM(iores->start);
 
 	clk_ahb = clk_get(dev, "clk_ahb");
 	if (IS_ERR(clk_ahb)) {
@@ -315,12 +271,7 @@ static int arasan_sdhci_probe(struct device_d *dev)
 	if (of_property_read_bool(np, "no-1-8-v"))
 		arasan_sdhci->quirks |= SDHCI_ARASAN_QUIRK_NO_1_8_V;
 
-	arasan_sdhci->sdhci.read32 = arasan_sdhci_readl;
-	arasan_sdhci->sdhci.read16 = arasan_sdhci_readw;
-	arasan_sdhci->sdhci.read8 = arasan_sdhci_readb;
-	arasan_sdhci->sdhci.write32 = arasan_sdhci_writel;
-	arasan_sdhci->sdhci.write16 = arasan_sdhci_writew;
-	arasan_sdhci->sdhci.write8 = arasan_sdhci_writeb;
+	arasan_sdhci->sdhci.base = IOMEM(iores->start);
 	arasan_sdhci->sdhci.mci = mci;
 	mci->send_cmd = arasan_sdhci_send_cmd;
 	mci->set_ios = arasan_sdhci_set_ios;
diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index 5a734d0d47..be8b6b38c3 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -377,43 +377,7 @@ int at91_sdhci_init(struct at91_sdhci *host, u32 maxclk,
 	return 0;
 }
 
-static u32 at91_sdhci_read32(struct sdhci *sdhci, int reg)
-{
-	return readl(to_priv(sdhci)->base + reg);
-}
-
-static void at91_sdhci_write32(struct sdhci *sdhci, int reg, u32 value)
-{
-	writel(value, to_priv(sdhci)->base + reg);
-}
-
-static u16 at91_sdhci_read16(struct sdhci *sdhci, int reg)
-{
-	return readw(to_priv(sdhci)->base + reg);
-}
-
-static void at91_sdhci_write16(struct sdhci *sdhci, int reg, u16 value)
-{
-	writew(value, to_priv(sdhci)->base + reg);
-}
-
-static u8 at91_sdhci_read8(struct sdhci *sdhci, int reg)
-{
-	return readb(to_priv(sdhci)->base + reg);
-}
-
-static void at91_sdhci_write8(struct sdhci *sdhci, int reg, u8 value)
-{
-	writeb(value, to_priv(sdhci)->base + reg);
-}
-
 void at91_sdhci_mmio_init(struct at91_sdhci *host, void __iomem *base)
 {
-	host->base = base;
-	host->sdhci.read8 = at91_sdhci_read8;
-	host->sdhci.read16 = at91_sdhci_read16;
-	host->sdhci.read32 = at91_sdhci_read32;
-	host->sdhci.write8 = at91_sdhci_write8;
-	host->sdhci.write16 = at91_sdhci_write16;
-	host->sdhci.write32 = at91_sdhci_write32;
+	host->sdhci.base = base;
 }
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
index f4f8dabba1..e6ac769bde 100644
--- a/drivers/mci/dove-sdhci.c
+++ b/drivers/mci/dove-sdhci.c
@@ -20,55 +20,12 @@
 
 struct dove_sdhci {
 	struct mci_host mci;
-	void __iomem *base;
 	struct sdhci sdhci;
 };
 
 #define priv_from_mci_host(h)	\
 	container_of(h, struct dove_sdhci, mci);
 
-static void dove_sdhci_writel(struct sdhci *sdhci, int reg, u32 val)
-{
-	struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
-	writel(val, p->base + reg);
-}
-
-static void dove_sdhci_writew(struct sdhci *sdhci, int reg, u16 val)
-{
-	struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
-	writew(val, p->base + reg);
-}
-
-static void dove_sdhci_writeb(struct sdhci *sdhci, int reg, u8 val)
-{
-	struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
-	writeb(val, p->base + reg);
-}
-
-static u32 dove_sdhci_readl(struct sdhci *sdhci, int reg)
-{
-	struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
-	return readl(p->base + reg);
-}
-
-static u16 dove_sdhci_readw(struct sdhci *sdhci, int reg)
-{
-	struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
-	return readw(p->base + reg);
-}
-
-static u8 dove_sdhci_readb(struct sdhci *sdhci, int reg)
-{
-	struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
-	return readb(p->base + reg);
-}
-
 static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask)
 {
 	u16 status;
@@ -320,7 +277,7 @@ static int dove_sdhci_probe(struct device_d *dev)
 	int ret;
 
 	host = xzalloc(sizeof(*host));
-	host->base = dev_request_mem_region(dev, 0);
+	host->sdhci.base = dev_request_mem_region(dev, 0);
 	host->mci.max_req_size = 0x8000;
 	host->mci.hw_dev = dev;
 	host->mci.send_cmd = dove_sdhci_mci_send_cmd;
@@ -328,12 +285,6 @@ static int dove_sdhci_probe(struct device_d *dev)
 	host->mci.init = dove_sdhci_mci_init;
 	host->mci.f_max = 50000000;
 	host->mci.f_min = host->mci.f_max / 256;
-	host->sdhci.read32 = dove_sdhci_readl;
-	host->sdhci.read16 = dove_sdhci_readw;
-	host->sdhci.read8 = dove_sdhci_readb;
-	host->sdhci.write32 = dove_sdhci_writel;
-	host->sdhci.write16 = dove_sdhci_writew;
-	host->sdhci.write8 = dove_sdhci_writeb;
 
 	dove_sdhci_set_mci_caps(host);
 
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index c9d589468f..7980278801 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -16,42 +16,41 @@ struct fsl_esdhc_dma_transfer {
 	enum dma_data_direction dir;
 };
 
-static u32 esdhc_op_read32_le(struct sdhci *sdhci, int reg)
+static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
 {
 	struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
 
-	return readl(host->regs + reg);
+	return in_be32(host->sdhci.base + reg);
 }
 
-static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
+static void esdhc_op_write32_be(struct sdhci *sdhci, int reg, u32 val)
 {
 	struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
 
-	return in_be32(host->regs + reg);
+	out_be32(host->sdhci.base + reg, val);
 }
 
-static void esdhc_op_write32_le(struct sdhci *sdhci, int reg, u32 val)
+static u16 esdhc_op_read16_be(struct sdhci *sdhci, int reg)
 {
 	struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
 
-	writel(val, host->regs + reg);
+	return in_be16(host->sdhci.base + reg);
 }
 
-static void esdhc_op_write32_be(struct sdhci *sdhci, int reg, u32 val)
+static void esdhc_op_write16_be(struct sdhci *sdhci, int reg, u16 val)
 {
 	struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
 
-	out_be32(host->regs + reg, val);
+	out_be16(host->sdhci.base + reg, val);
 }
 
 void esdhc_populate_sdhci(struct fsl_esdhc_host *host)
 {
 	if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN) {
+		host->sdhci.read16 = esdhc_op_read16_be;
+		host->sdhci.write16 = esdhc_op_write16_be;
 		host->sdhci.read32 = esdhc_op_read32_be;
 		host->sdhci.write32 = esdhc_op_write32_be;
-	} else {
-		host->sdhci.read32 = esdhc_op_read32_le;
-		host->sdhci.write32 = esdhc_op_write32_le;
 	}
 }
 
diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c
index c3a8b377e2..cf469eff44 100644
--- a/drivers/mci/imx-esdhc-pbl.c
+++ b/drivers/mci/imx-esdhc-pbl.c
@@ -200,14 +200,14 @@ static int imx8m_esdhc_init(struct fsl_esdhc_host *host,
 {
 	switch (instance) {
 	case 0:
-		host->regs = IOMEM(MX8M_USDHC1_BASE_ADDR);
+		host->sdhci.base = IOMEM(MX8M_USDHC1_BASE_ADDR);
 		break;
 	case 1:
-		host->regs = IOMEM(MX8M_USDHC2_BASE_ADDR);
+		host->sdhci.base = IOMEM(MX8M_USDHC2_BASE_ADDR);
 		break;
 	case 2:
 		/* Only exists on i.MX8MM, not on i.MX8MQ */
-		host->regs = IOMEM(MX8MM_USDHC3_BASE_ADDR);
+		host->sdhci.base = IOMEM(MX8MM_USDHC3_BASE_ADDR);
 		break;
 	default:
 		return -EINVAL;
@@ -237,16 +237,16 @@ int imx6_esdhc_start_image(int instance)
 
 	switch (instance) {
 	case 0:
-		host.regs = IOMEM(MX6_USDHC1_BASE_ADDR);
+		host.sdhci.base = IOMEM(MX6_USDHC1_BASE_ADDR);
 		break;
 	case 1:
-		host.regs = IOMEM(MX6_USDHC2_BASE_ADDR);
+		host.sdhci.base = IOMEM(MX6_USDHC2_BASE_ADDR);
 		break;
 	case 2:
-		host.regs = IOMEM(MX6_USDHC3_BASE_ADDR);
+		host.sdhci.base = IOMEM(MX6_USDHC3_BASE_ADDR);
 		break;
 	case 3:
-		host.regs = IOMEM(MX6_USDHC4_BASE_ADDR);
+		host.sdhci.base = IOMEM(MX6_USDHC4_BASE_ADDR);
 		break;
 	default:
 		return -EINVAL;
@@ -276,13 +276,13 @@ int imx7_esdhc_start_image(int instance)
 
 	switch (instance) {
 	case 0:
-		host.regs = IOMEM(MX7_USDHC1_BASE_ADDR);
+		host.sdhci.base = IOMEM(MX7_USDHC1_BASE_ADDR);
 		break;
 	case 1:
-		host.regs = IOMEM(MX7_USDHC2_BASE_ADDR);
+		host.sdhci.base = IOMEM(MX7_USDHC2_BASE_ADDR);
 		break;
 	case 2:
-		host.regs = IOMEM(MX7_USDHC3_BASE_ADDR);
+		host.sdhci.base = IOMEM(MX7_USDHC3_BASE_ADDR);
 		break;
 	default:
 		return -EINVAL;
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 12e98ce26a..5a664ce4c3 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -264,7 +264,7 @@ static int fsl_esdhc_probe(struct device_d *dev)
 		ret = PTR_ERR(iores);
 		goto err_clk_disable;
 	}
-	host->regs = IOMEM(iores->start);
+	host->sdhci.base = IOMEM(iores->start);
 
 	esdhc_populate_sdhci(host);
 
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index 0de1e72e7b..f1685eac06 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -101,7 +101,6 @@ struct fsl_esdhc_host {
 	struct mci_host		mci;
 	struct clk		*clk;
 	struct device_d		*dev;
-	void __iomem		*regs;
 	const struct esdhc_soc_data *socdata;
 	struct sdhci	sdhci;
 };
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 2605ecb535..e07f4a3fb2 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -183,6 +183,8 @@ struct sdhci {
 	void (*write16)(struct sdhci *host, int reg, u16 val);
 	void (*write8)(struct sdhci *host, int reg, u8 val);
 
+	void __iomem *base;
+
 	int max_clk; /* Max possible freq (Hz) */
 	int clk_mul; /* Clock Muliplier value */
 
@@ -204,32 +206,50 @@ struct sdhci {
 
 static inline u32 sdhci_read32(struct sdhci *host, int reg)
 {
-	return host->read32(host, reg);
+	if (host->read32)
+		return host->read32(host, reg);
+	else
+		return readl(host->base + reg);
 }
 
 static inline u32 sdhci_read16(struct sdhci *host, int reg)
 {
-	return host->read16(host, reg);
+	if (host->read16)
+		return host->read16(host, reg);
+	else
+		return readw(host->base + reg);
 }
 
 static inline u32 sdhci_read8(struct sdhci *host, int reg)
 {
-	return host->read8(host, reg);
+	if (host->read8)
+		return host->read8(host, reg);
+	else
+		return readb(host->base + reg);
 }
 
 static inline void sdhci_write32(struct sdhci *host, int reg, u32 val)
 {
-	host->write32(host, reg, val);
+	if (host->write32)
+		host->write32(host, reg, val);
+	else
+		writel(val, host->base + reg);
 }
 
 static inline void sdhci_write16(struct sdhci *host, int reg, u32 val)
 {
-	host->write16(host, reg, val);
+	if (host->write16)
+		host->write16(host, reg, val);
+	else
+		writew(val, host->base + reg);
 }
 
 static inline void sdhci_write8(struct sdhci *host, int reg, u32 val)
 {
-	host->write8(host, reg, val);
+	if (host->write8)
+		host->write8(host, reg, val);
+	else
+		writeb(val, host->base + reg);
 }
 
 void sdhci_read_response(struct sdhci *host, struct mci_cmd *cmd);
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

* [PATCH 12/12] mci: Add support for Rockchip variant of the dwcmshc
  2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
                   ` (10 preceding siblings ...)
  2021-06-07 10:44 ` [PATCH 11/12] mci: sdhci: Get rid of many register ops Sascha Hauer
@ 2021-06-07 10:44 ` Sascha Hauer
  11 siblings, 0 replies; 13+ messages in thread
From: Sascha Hauer @ 2021-06-07 10:44 UTC (permalink / raw)
  To: Barebox List

This adds support for a Rockchip derivation of the DWCMSHC controller
which itself is a SDHCI controller found on some Rockchip SoCs like the
RK3568.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mci/Kconfig                  |   7 +
 drivers/mci/Makefile                 |   1 +
 drivers/mci/rockchip-dwcmshc-sdhci.c | 382 +++++++++++++++++++++++++++
 3 files changed, 390 insertions(+)
 create mode 100644 drivers/mci/rockchip-dwcmshc-sdhci.c

diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 7d4e72138d..e1fcd41271 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -79,6 +79,13 @@ config MCI_MXS
 	  Enable this entry to add support to read and write SD cards on a
 	  i.MX23/i.MX28 based system.
 
+config MCI_ROCKCHIP_DWCMSHC
+	bool "MCI sdhc support for Rockchip SoCs"
+	select MCI_SDHCI
+	help
+	  Enable this entry to add support for a Rockchip derivation of the
+	  DWCMSHC controller found on some Rockchip SoCs like the RK3568.
+
 config MCI_S3C
 	bool "S3C"
 	depends on ARCH_S3C24xx
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index 60dc100c37..b113b1c732 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_MCI_MXS)		+= mxs.o
 obj-$(CONFIG_MCI_OMAP_HSMMC)	+= omap_hsmmc.o
 obj-$(CONFIG_MCI_PXA)		+= pxamci.o
 obj-$(CONFIG_MCI_S3C)		+= s3c.o
+obj-$(CONFIG_MCI_ROCKCHIP_DWCMSHC)	+= rockchip-dwcmshc-sdhci.o
 obj-$(CONFIG_MCI_TEGRA)		+= tegra-sdmmc.o
 obj-$(CONFIG_MCI_SPI)		+= mci_spi.o
 obj-$(CONFIG_MCI_DW)		+= dw_mmc.o
diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c
new file mode 100644
index 0000000000..e44fc16c39
--- /dev/null
+++ b/drivers/mci/rockchip-dwcmshc-sdhci.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <clock.h>
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <mci.h>
+#include <linux/iopoll.h>
+
+#include "sdhci.h"
+
+/* DWCMSHC specific Mode Select value */
+#define DWCMSHC_CTRL_HS400		0x7
+
+#define DWCMSHC_VER_ID			0x500
+#define DWCMSHC_VER_TYPE		0x504
+#define DWCMSHC_HOST_CTRL3		0x508
+#define DWCMSHC_EMMC_CONTROL		0x52c
+#define DWCMSHC_EMMC_ATCTRL		0x540
+
+/* Rockchip specific Registers */
+#define DWCMSHC_EMMC_DLL_CTRL		0x800
+#define DWCMSHC_EMMC_DLL_RXCLK		0x804
+#define DWCMSHC_EMMC_DLL_TXCLK		0x808
+#define DWCMSHC_EMMC_DLL_STRBIN		0x80c
+#define DWCMSHC_EMMC_DLL_STATUS0	0x840
+#define DWCMSHC_EMMC_DLL_START		BIT(0)
+#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL	29
+#define DWCMSHC_EMMC_DLL_START_POINT	16
+#define DWCMSHC_EMMC_DLL_INC		8
+#define DWCMSHC_EMMC_DLL_DLYENA		BIT(27)
+#define DLL_TXCLK_TAPNUM_DEFAULT	0x8
+#define DLL_STRBIN_TAPNUM_DEFAULT	0x8
+#define DLL_TXCLK_TAPNUM_FROM_SW	BIT(24)
+#define DLL_STRBIN_TAPNUM_FROM_SW	BIT(24)
+#define DWCMSHC_EMMC_DLL_LOCKED		BIT(8)
+#define DWCMSHC_EMMC_DLL_TIMEOUT	BIT(9)
+#define DLL_RXCLK_NO_INVERTER		1
+#define DLL_RXCLK_INVERTER		0
+#define DWCMSHC_ENHANCED_STROBE		BIT(8)
+#define DLL_LOCK_WO_TMOUT(x) \
+	((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
+	(((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
+
+#define SDHCI_DWCMSHC_INT_DATA_MASK		SDHCI_INT_XFER_COMPLETE | \
+						SDHCI_INT_DMA | \
+						SDHCI_INT_SPACE_AVAIL | \
+						SDHCI_INT_DATA_AVAIL | \
+						SDHCI_INT_DATA_TIMEOUT | \
+						SDHCI_INT_DATA_CRC | \
+						SDHCI_INT_DATA_END_BIT
+
+#define SDHCI_DWCMSHC_INT_CMD_MASK		SDHCI_INT_CMD_COMPLETE | \
+						SDHCI_INT_TIMEOUT | \
+						SDHCI_INT_CRC | \
+						SDHCI_INT_END_BIT | \
+						SDHCI_INT_INDEX
+
+enum {
+	CLK_CORE,
+	CLK_BUS,
+	CLK_AXI,
+	CLK_BLOCK,
+	CLK_TIMER,
+	CLK_MAX,
+};
+
+struct rk_sdhci_host {
+	struct mci_host		mci;
+	struct sdhci		sdhci;
+	struct clk_bulk_data	clks[CLK_MAX];
+};
+
+
+static inline
+struct rk_sdhci_host *to_rk_sdhci_host(struct mci_host *mci)
+{
+	return container_of(mci, struct rk_sdhci_host, mci);
+}
+
+static int rk_sdhci_card_present(struct mci_host *mci)
+{
+	struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+
+	return !!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_CARD_DETECT);
+}
+
+static int rk_sdhci_reset(struct rk_sdhci_host *host, u8 mask)
+{
+	sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, mask);
+
+	/* wait for reset completion */
+	if (wait_on_timeout(100 * MSECOND,
+			!(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))){
+		dev_err(host->mci.hw_dev, "SDHCI reset timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int rk_sdhci_init(struct mci_host *mci, struct device_d *dev)
+{
+	struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+	int ret;
+
+	ret = rk_sdhci_reset(host, SDHCI_RESET_ALL);
+	if (ret)
+		return ret;
+
+	sdhci_write8(&host->sdhci, SDHCI_POWER_CONTROL,
+			    SDHCI_BUS_VOLTAGE_330 | SDHCI_BUS_POWER_EN);
+	udelay(400);
+
+	sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE,
+			    SDHCI_DWCMSHC_INT_DATA_MASK |
+			    SDHCI_DWCMSHC_INT_CMD_MASK);
+	sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, 0x00);
+
+	/* Disable cmd conflict check */
+	sdhci_write32(&host->sdhci, DWCMSHC_HOST_CTRL3, 0x0);
+	/* Reset previous settings */
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_TXCLK, 0);
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_STRBIN, 0);
+
+	return 0;
+}
+
+static void rk_sdhci_set_clock(struct rk_sdhci_host *host, unsigned int clock)
+{
+	u32 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, extra;
+	int err;
+
+	host->mci.clock = 0;
+
+	/* DO NOT TOUCH THIS SETTING */
+	extra = DWCMSHC_EMMC_DLL_DLYENA |
+		DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_RXCLK, extra);
+
+	if (clock == 0)
+		return;
+
+	/* Rockchip platform only support 375KHz for identify mode */
+	if (clock <= 400000)
+		clock = 375000;
+
+	clk_set_rate(host->clks[CLK_CORE].clk, clock);
+
+	sdhci_set_clock(&host->sdhci, clock, clk_get_rate(host->clks[CLK_CORE].clk));
+
+	if (clock <= 400000)
+		return;
+
+	/* Reset DLL */
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, BIT(1));
+	udelay(1);
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, 0x0);
+
+	/* Init DLL settings */
+	extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
+		0x2 << DWCMSHC_EMMC_DLL_INC |
+		DWCMSHC_EMMC_DLL_START;
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, extra);
+	err = readl_poll_timeout(host->sdhci.base + DWCMSHC_EMMC_DLL_STATUS0,
+				 extra, DLL_LOCK_WO_TMOUT(extra),
+				 500 * USEC_PER_MSEC);
+	if (err) {
+		dev_err(host->mci.hw_dev, "DLL lock timeout!\n");
+		return;
+	}
+
+	/* Disable cmd conflict check */
+	extra = sdhci_read32(&host->sdhci, DWCMSHC_HOST_CTRL3);
+	extra &= ~BIT(0);
+	sdhci_write32(&host->sdhci, DWCMSHC_HOST_CTRL3, extra);
+
+	extra = 0x1 << 16 | /* tune clock stop en */
+		0x2 << 17 | /* pre-change delay */
+		0x3 << 19;  /* post-change delay */
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_ATCTRL, extra);
+
+	extra = DWCMSHC_EMMC_DLL_DLYENA |
+		DLL_TXCLK_TAPNUM_FROM_SW |
+		txclk_tapnum;
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_TXCLK, extra);
+
+	extra = DWCMSHC_EMMC_DLL_DLYENA |
+		DLL_STRBIN_TAPNUM_DEFAULT |
+		DLL_STRBIN_TAPNUM_FROM_SW;
+	sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_STRBIN, extra);
+}
+
+static void rk_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
+{
+	struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+	u16 val;
+
+	/* stop clock */
+	sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
+
+	if (ios->clock)
+		rk_sdhci_set_clock(host, ios->clock);
+
+	sdhci_set_bus_width(&host->sdhci, ios->bus_width);
+
+	val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
+
+	if (ios->clock > 26000000)
+		val |= SDHCI_CTRL_HISPD;
+	else
+		val &= ~SDHCI_CTRL_HISPD;
+
+	sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
+}
+
+static int rk_sdhci_wait_for_done(struct rk_sdhci_host *host, u32 mask)
+{
+	u64 start = get_time_ns();
+	u16 stat;
+
+	do {
+		stat = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS);
+		if (stat & SDHCI_INT_ERROR) {
+			dev_err(host->mci.hw_dev, "SDHCI_INT_ERROR: 0x%08x\n",
+				sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS));
+			return -EPERM;
+		}
+
+		if (is_timeout(start, 1000 * MSECOND)) {
+			dev_err(host->mci.hw_dev,
+					"SDHCI timeout while waiting for done\n");
+			return -ETIMEDOUT;
+		}
+	} while ((stat & mask) != mask);
+
+	return 0;
+}
+
+static void print_error(struct rk_sdhci_host *host, int cmdidx)
+{
+	dev_err(host->mci.hw_dev,
+		"error while transfering data for command %d\n", cmdidx);
+	dev_err(host->mci.hw_dev, "state = 0x%08x , interrupt = 0x%08x\n",
+		sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE),
+		sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS));
+}
+
+static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
+				 struct mci_data *data)
+{
+	struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+	u32 mask, command, xfer;
+	int ret;
+
+	/* Wait for idle before next command */
+	mask = SDHCI_CMD_INHIBIT_CMD;
+	if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION)
+		mask |= SDHCI_CMD_INHIBIT_DATA;
+
+	ret = wait_on_timeout(10 * MSECOND,
+			!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & mask));
+
+	if (ret) {
+		dev_err(host->mci.hw_dev,
+				"SDHCI timeout while waiting for idle\n");
+		return ret;
+	}
+
+	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+
+	mask = SDHCI_INT_CMD_COMPLETE;
+	if (data)
+		mask |= SDHCI_INT_DATA_AVAIL;
+
+	sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, false, &command, &xfer);
+
+	sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe);
+
+	sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer);
+
+	if (data) {
+		sdhci_write16(&host->sdhci, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K |
+			    SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
+		sdhci_write16(&host->sdhci, SDHCI_BLOCK_COUNT, data->blocks);
+	}
+
+	sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
+	sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
+
+	ret = rk_sdhci_wait_for_done(host, mask);
+	if (ret == -EPERM)
+		goto error;
+	else if (ret)
+		return ret;
+
+	sdhci_read_response(&host->sdhci, cmd);
+	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, mask);
+
+	if (data)
+		ret = sdhci_transfer_data(&host->sdhci, data);
+
+error:
+	if (ret) {
+		print_error(host, cmd->cmdidx);
+		rk_sdhci_reset(host, BIT(1)); /* SDHCI_RESET_CMD */
+		rk_sdhci_reset(host, BIT(2)); /* SDHCI_RESET_DATA */
+	}
+
+	sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+	return ret;
+}
+
+static int rk_sdhci_probe(struct device_d *dev)
+{
+	struct rk_sdhci_host *host;
+	struct resource *iores;
+	struct mci_host *mci;
+	int ret;
+
+	host = xzalloc(sizeof(*host));
+
+	mci = &host->mci;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	host->sdhci.base = IOMEM(iores->start);
+	host->sdhci.mci = mci;
+	mci->send_cmd = rk_sdhci_send_cmd;
+	mci->set_ios = rk_sdhci_set_ios;
+	mci->init = rk_sdhci_init;
+	mci->card_present = rk_sdhci_card_present;
+	mci->hw_dev = dev;
+
+	host->clks[CLK_CORE].id = "core";
+	host->clks[CLK_BUS].id = "bus";
+	host->clks[CLK_AXI].id = "axi";
+	host->clks[CLK_BLOCK].id = "block";
+	host->clks[CLK_TIMER].id = "timer";
+
+	ret = clk_bulk_get(host->mci.hw_dev, CLK_MAX, host->clks);
+	if (ret) {
+		dev_err(host->mci.hw_dev, "failed to get clocks: %s\n",
+			strerror(-ret));
+		return ret;
+	}
+
+	ret = clk_bulk_enable(CLK_MAX, host->clks);
+	if (ret) {
+		dev_err(host->mci.hw_dev, "failed to enable clocks: %s\n",
+			strerror(-ret));
+		return ret;
+	}
+
+	host->sdhci.max_clk = clk_get_rate(host->clks[CLK_CORE].clk);
+
+	mci_of_parse(&host->mci);
+
+	sdhci_setup_host(&host->sdhci);
+
+	dev->priv = host;
+
+	return mci_register(&host->mci);
+}
+
+static __maybe_unused struct of_device_id rk_sdhci_compatible[] = {
+	{
+		.compatible = "rockchip,rk3568-dwcmshc"
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct driver_d rk_sdhci_driver = {
+	.name = "rk3568-dwcmshc-sdhci",
+	.probe = rk_sdhci_probe,
+	.of_compatible = DRV_OF_COMPAT(rk_sdhci_compatible),
+};
+device_platform_driver(rk_sdhci_driver);
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


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

end of thread, other threads:[~2021-06-07 10:55 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-07 10:43 [PATCH 00/12] SDHCI updates Sascha Hauer
2021-06-07 10:44 ` [PATCH 01/12] mci: sdhci: straighten capabilities register Sascha Hauer
2021-06-07 10:44 ` [PATCH 02/12] mci: sdhci: Add and use SDHCI_CAPABILITIES_1 defines Sascha Hauer
2021-06-07 10:44 ` [PATCH 03/12] mci: sdhci: Use SDHCI_MAX_DIV_SPEC_200 define Sascha Hauer
2021-06-07 10:44 ` [PATCH 04/12] mci: sdhci: port over some common functions from Linux Sascha Hauer
2021-06-07 10:44 ` [PATCH 05/12] mci: sdhci: imx: Use sdhci_setup_host() Sascha Hauer
2021-06-07 10:44 ` [PATCH 06/12] mci: sdhci: Use Linux defines for SDHCI_HOST_CONTROL register Sascha Hauer
2021-06-07 10:44 ` [PATCH 07/12] mci: sdhci: arasan: Use sdhci_setup_host() Sascha Hauer
2021-06-07 10:44 ` [PATCH 08/12] mci: sdhci: arasan: Use sdhci_set_bus_width() Sascha Hauer
2021-06-07 10:44 ` [PATCH 09/12] mci: sdhci: Use Linux defines for SDHCI_CLOCK_CONTROL register Sascha Hauer
2021-06-07 10:44 ` [PATCH 10/12] mci: sdhci: arasan: Use sdhci_set_clock() Sascha Hauer
2021-06-07 10:44 ` [PATCH 11/12] mci: sdhci: Get rid of many register ops Sascha Hauer
2021-06-07 10:44 ` [PATCH 12/12] mci: Add support for Rockchip variant of the dwcmshc Sascha Hauer

mail archive of the barebox mailing list

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://lore.barebox.org/barebox/0 barebox/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 barebox barebox/ https://lore.barebox.org/barebox \
		barebox@lists.infradead.org
	public-inbox-index barebox

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git