mmc: sdhci: Distinguish between base clock and maximum peripheral frequency

The sdhci controller assumes that the base clock frequency is fully supported by
the peripheral and doesn't support hardware limitations. The Linux kernel
distinguishes between base clock (max_clk) of the host controller and maximum
frequency (f_max) of the card interface. Use the same differentiation and allow
the platform to constrain the peripheral interface.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c
index 6654b54..62cb242 100644
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -35,8 +35,9 @@
 		free(host);
 		return -ENODEV;
 	}
+	host->max_clk = max_clk;
 
-	add_sdhci(host, max_clk, min_clk);
+	add_sdhci(host, 0, min_clk);
 
 	return 0;
 }
@@ -95,7 +96,9 @@
 	if (!max_clk)
 		return -EINVAL;
 
-	ret = sdhci_setup_cfg(&plat->cfg, host, max_clk, ATMEL_SDHC_MIN_FREQ);
+	host->max_clk = max_clk;
+
+	ret = sdhci_setup_cfg(&plat->cfg, host, 0, ATMEL_SDHC_MIN_FREQ);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c
index cb2bd40..29c2a85 100644
--- a/drivers/mmc/bcm2835_sdhci.c
+++ b/drivers/mmc/bcm2835_sdhci.c
@@ -181,10 +181,11 @@
 	host->ioaddr = (void *)(unsigned long)regbase;
 	host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B |
 		SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_NO_HISPD_BIT;
+	host->max_clk = emmc_freq;
 	host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
 	host->ops = &bcm2835_ops;
 
-	add_sdhci(host, emmc_freq, MIN_FREQ);
+	add_sdhci(host, 0, MIN_FREQ);
 
 	return 0;
 }
diff --git a/drivers/mmc/ftsdc021_sdhci.c b/drivers/mmc/ftsdc021_sdhci.c
index 6e9fefa..4940ccb 100644
--- a/drivers/mmc/ftsdc021_sdhci.c
+++ b/drivers/mmc/ftsdc021_sdhci.c
@@ -27,7 +27,8 @@
 	host->name = "FTSDC021";
 	host->ioaddr = (void __iomem *)regbase;
 	host->quirks = 0;
-	add_sdhci(host, freq, 0);
+	host->max_clk = freq;
+	add_sdhci(host, 0, 0);
 
 	return 0;
 }
diff --git a/drivers/mmc/kona_sdhci.c b/drivers/mmc/kona_sdhci.c
index 549f6bc..ddd821b 100644
--- a/drivers/mmc/kona_sdhci.c
+++ b/drivers/mmc/kona_sdhci.c
@@ -121,12 +121,13 @@
 	host->name = "kona-sdhci";
 	host->ioaddr = reg_base;
 	host->quirks = quirks;
+	host->max_clk = max_clk;
 
 	if (init_kona_mmc_core(host)) {
 		free(host);
 		return -EINVAL;
 	}
 
-	add_sdhci(host, max_clk, min_clk);
+	add_sdhci(host, 0, min_clk);
 	return ret;
 }
diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c
index f33714b..1db683d 100644
--- a/drivers/mmc/msm_sdhci.c
+++ b/drivers/mmc/msm_sdhci.c
@@ -96,6 +96,8 @@
 
 	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B;
 
+	host->max_clk = 0;
+
 	/* Init clocks */
 	ret = msm_sdc_clk_init(dev);
 	if (ret)
diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c
index e388ad1..69aa87b 100644
--- a/drivers/mmc/mv_sdhci.c
+++ b/drivers/mmc/mv_sdhci.c
@@ -77,6 +77,7 @@
 	host->name = MVSDH_NAME;
 	host->ioaddr = (void *)regbase;
 	host->quirks = quirks;
+	host->max_clk = max_clk;
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
 	memset(&mv_ops, 0, sizeof(struct sdhci_ops));
 	mv_ops.write_b = mv_sdhci_writeb;
@@ -88,5 +89,5 @@
 		sdhci_mvebu_mbus_config((void __iomem *)regbase);
 	}
 
-	return add_sdhci(host, max_clk, min_clk);
+	return add_sdhci(host, 0, min_clk);
 }
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index 3d587cc..e39b476 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -32,6 +32,7 @@
 		dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase);
 		mmc_host->ioaddr = (void *)(ulong)iobase;
 		mmc_host->quirks = 0;
+		mmc_host->max_clk = 0;
 		ret = add_sdhci(mmc_host, 0, 0);
 		if (ret)
 			return ret;
diff --git a/drivers/mmc/pic32_sdhci.c b/drivers/mmc/pic32_sdhci.c
index c06364c..1e14fa1 100644
--- a/drivers/mmc/pic32_sdhci.c
+++ b/drivers/mmc/pic32_sdhci.c
@@ -56,7 +56,9 @@
 		return ret;
 	}
 
-	ret = add_sdhci(host, f_min_max[1], f_min_max[0]);
+	host->max_clk   = f_min_max[1];
+
+	ret = add_sdhci(host, 0, f_min_max[0]);
 	if (ret)
 		return ret;
 	host->mmc->dev = dev;
diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c
index e33e35e..1358864 100644
--- a/drivers/mmc/rockchip_sdhci.c
+++ b/drivers/mmc/rockchip_sdhci.c
@@ -50,9 +50,9 @@
 	}
 
 	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
+	host->max_clk = max_frequency;
 
-	ret = sdhci_setup_cfg(&plat->cfg, host, max_frequency,
-			EMMC_MIN_FREQ);
+	ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
 
 	host->mmc = &plat->mmc;
 	if (ret)
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index 1f1d2ed..28327d5 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -91,6 +91,7 @@
 	host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE |
 		SDHCI_QUIRK_32BIT_DMA_ADDR |
 		SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_USE_WIDE8;
+	host->max_clk = 52000000;
 	host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
 	host->ops = &s5p_sdhci_ops;
 
@@ -98,7 +99,7 @@
 		host->host_caps |= MMC_MODE_8BIT;
 
 #ifndef CONFIG_BLK
-	return add_sdhci(host, 52000000, 400000);
+	return add_sdhci(host, 0, 400000);
 #else
 	return 0;
 #endif
@@ -254,7 +255,7 @@
 	if (ret)
 		return ret;
 
-	ret = sdhci_setup_cfg(&plat->cfg, host, 52000000, 400000);
+	ret = sdhci_setup_cfg(&plat->cfg, host, 0, 400000);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 5b404ff..84e0581 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -325,7 +325,7 @@
 		 */
 		if (host->clk_mul) {
 			for (div = 1; div <= 1024; div++) {
-				if ((mmc->cfg->f_max * host->clk_mul / div)
+				if ((host->max_clk * host->clk_mul / div)
 					<= clock)
 					break;
 			}
@@ -338,13 +338,13 @@
 			div--;
 		} else {
 			/* Version 3.00 divisors must be a multiple of 2. */
-			if (mmc->cfg->f_max <= clock) {
+			if (host->max_clk <= clock) {
 				div = 1;
 			} else {
 				for (div = 2;
 				     div < SDHCI_MAX_DIV_SPEC_300;
 				     div += 2) {
-					if ((mmc->cfg->f_max / div) <= clock)
+					if ((host->max_clk / div) <= clock)
 						break;
 				}
 			}
@@ -353,7 +353,7 @@
 	} else {
 		/* Version 2.00 divisors must be a power of 2. */
 		for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
-			if ((mmc->cfg->f_max / div) <= clock)
+			if ((host->max_clk / div) <= clock)
 				break;
 		}
 		div >>= 1;
@@ -513,7 +513,7 @@
 #endif
 
 int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
-		u32 max_clk, u32 min_clk)
+		u32 f_max, u32 f_min)
 {
 	u32 caps, caps_1;
 
@@ -536,24 +536,26 @@
 #ifndef CONFIG_DM_MMC_OPS
 	cfg->ops = &sdhci_ops;
 #endif
-	if (max_clk)
-		cfg->f_max = max_clk;
-	else {
+	if (host->max_clk == 0) {
 		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
-			cfg->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) >>
+			host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK) >>
 				SDHCI_CLOCK_BASE_SHIFT;
 		else
-			cfg->f_max = (caps & SDHCI_CLOCK_BASE_MASK) >>
+			host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK) >>
 				SDHCI_CLOCK_BASE_SHIFT;
-		cfg->f_max *= 1000000;
+		host->max_clk *= 1000000;
 	}
-	if (cfg->f_max == 0) {
+	if (host->max_clk == 0) {
 		printf("%s: Hardware doesn't specify base clock frequency\n",
 		       __func__);
 		return -EINVAL;
 	}
-	if (min_clk)
-		cfg->f_min = min_clk;
+	if (f_max && (f_max < host->max_clk))
+		cfg->f_max = f_max;
+	else
+		cfg->f_max = host->max_clk;
+	if (f_min)
+		cfg->f_min = f_min;
 	else {
 		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
 			cfg->f_min = cfg->f_max / SDHCI_MAX_DIV_SPEC_300;
@@ -598,11 +600,11 @@
 	return mmc_bind(dev, mmc, cfg);
 }
 #else
-int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
+int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min)
 {
 	int ret;
 
-	ret = sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk);
+	ret = sdhci_setup_cfg(&host->cfg, host, f_max, f_min);
 	if (ret)
 		return ret;
 
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index 3da1385..69efa38 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -36,7 +36,9 @@
 	host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
 #endif
 
-	ret = sdhci_setup_cfg(&plat->cfg, host, CONFIG_ZYNQ_SDHCI_MAX_FREQ,
+	host->max_clk = CONFIG_ZYNQ_SDHCI_MAX_FREQ;
+
+	ret = sdhci_setup_cfg(&plat->cfg, host, 0,
 			      CONFIG_ZYNQ_SDHCI_MIN_FREQ);
 	host->mmc = &plat->mmc;
 	if (ret)