hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
kernel/drivers/mmc/host/sdhci-omap.c
....@@ -1,23 +1,13 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /**
23 * SDHCI Controller driver for TI's OMAP SoCs
34 *
45 * Copyright (C) 2017 Texas Instruments
56 * Author: Kishon Vijay Abraham I <kishon@ti.com>
6
- *
7
- * This program is free software: you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License version 2 of
9
- * the License as published by the Free Software Foundation.
10
- *
11
- * This program is distributed in the hope that it will be useful,
12
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- * GNU General Public License for more details.
15
- *
16
- * You should have received a copy of the GNU General Public License
17
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
187 */
198
209 #include <linux/delay.h>
10
+#include <linux/mmc/mmc.h>
2111 #include <linux/mmc/slot-gpio.h>
2212 #include <linux/module.h>
2313 #include <linux/of.h>
....@@ -72,6 +62,8 @@
7262 #define SDHCI_OMAP_IE 0x234
7363 #define INT_CC_EN BIT(0)
7464
65
+#define SDHCI_OMAP_ISE 0x238
66
+
7567 #define SDHCI_OMAP_AC12 0x23c
7668 #define AC12_V1V8_SIGEN BIT(19)
7769 #define AC12_SCLK_SEL BIT(23)
....@@ -96,6 +88,7 @@
9688
9789 /* sdhci-omap controller flags */
9890 #define SDHCI_OMAP_REQUIRE_IODELAY BIT(0)
91
+#define SDHCI_OMAP_SPECIAL_RESET BIT(1)
9992
10093 struct sdhci_omap_data {
10194 u32 offset;
....@@ -117,6 +110,13 @@
117110 struct pinctrl *pinctrl;
118111 struct pinctrl_state **pinctrl_state;
119112 bool is_tuning;
113
+ /* Omap specific context save */
114
+ u32 con;
115
+ u32 hctl;
116
+ u32 sysctl;
117
+ u32 capa;
118
+ u32 ie;
119
+ u32 ise;
120120 };
121121
122122 static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host);
....@@ -304,10 +304,6 @@
304304 int ret = 0;
305305 u32 reg;
306306 int i;
307
-
308
- pltfm_host = sdhci_priv(host);
309
- omap_host = sdhci_pltfm_priv(pltfm_host);
310
- dev = omap_host->dev;
311307
312308 /* clock tuning is not needed for upto 52MHz */
313309 if (ios->clock <= 52000000)
....@@ -701,7 +697,11 @@
701697 struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
702698
703699 reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
704
- reg |= CON_DMA_MASTER;
700
+ reg &= ~CON_DMA_MASTER;
701
+ /* Switch to DMA slave mode when using external DMA */
702
+ if (!host->use_external_dma)
703
+ reg |= CON_DMA_MASTER;
704
+
705705 sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
706706
707707 return 0;
....@@ -790,14 +790,34 @@
790790 sdhci_omap_start_clock(omap_host);
791791 }
792792
793
-void sdhci_omap_reset(struct sdhci_host *host, u8 mask)
793
+#define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */
794
+static void sdhci_omap_reset(struct sdhci_host *host, u8 mask)
794795 {
795796 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
796797 struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
798
+ unsigned long limit = MMC_TIMEOUT_US;
799
+ unsigned long i = 0;
797800
798801 /* Don't reset data lines during tuning operation */
799802 if (omap_host->is_tuning)
800803 mask &= ~SDHCI_RESET_DATA;
804
+
805
+ if (omap_host->flags & SDHCI_OMAP_SPECIAL_RESET) {
806
+ sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
807
+ while ((!(sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask)) &&
808
+ (i++ < limit))
809
+ udelay(1);
810
+ i = 0;
811
+ while ((sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) &&
812
+ (i++ < limit))
813
+ udelay(1);
814
+
815
+ if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask)
816
+ dev_err(mmc_dev(host->mmc),
817
+ "Timeout waiting on controller reset in %s\n",
818
+ __func__);
819
+ return;
820
+ }
801821
802822 sdhci_reset(host, mask);
803823 }
....@@ -839,6 +859,15 @@
839859 return intmask;
840860 }
841861
862
+static void sdhci_omap_set_timeout(struct sdhci_host *host,
863
+ struct mmc_command *cmd)
864
+{
865
+ if (cmd->opcode == MMC_ERASE)
866
+ sdhci_set_data_timeout_irq(host, false);
867
+
868
+ __sdhci_set_timeout(host, cmd);
869
+}
870
+
842871 static struct sdhci_ops sdhci_omap_ops = {
843872 .set_clock = sdhci_omap_set_clock,
844873 .set_power = sdhci_omap_set_power,
....@@ -850,6 +879,7 @@
850879 .reset = sdhci_omap_reset,
851880 .set_uhs_signaling = sdhci_omap_set_uhs_signaling,
852881 .irq = sdhci_omap_irq,
882
+ .set_timeout = sdhci_omap_set_timeout,
853883 };
854884
855885 static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host)
....@@ -899,6 +929,16 @@
899929 .offset = 0x200,
900930 };
901931
932
+static const struct sdhci_omap_data am335_data = {
933
+ .offset = 0x200,
934
+ .flags = SDHCI_OMAP_SPECIAL_RESET,
935
+};
936
+
937
+static const struct sdhci_omap_data am437_data = {
938
+ .offset = 0x200,
939
+ .flags = SDHCI_OMAP_SPECIAL_RESET,
940
+};
941
+
902942 static const struct sdhci_omap_data dra7_data = {
903943 .offset = 0x200,
904944 .flags = SDHCI_OMAP_REQUIRE_IODELAY,
....@@ -907,6 +947,8 @@
907947 static const struct of_device_id omap_sdhci_match[] = {
908948 { .compatible = "ti,dra7-sdhci", .data = &dra7_data },
909949 { .compatible = "ti,k2g-sdhci", .data = &k2g_data },
950
+ { .compatible = "ti,am335-sdhci", .data = &am335_data },
951
+ { .compatible = "ti,am437-sdhci", .data = &am437_data },
910952 {},
911953 };
912954 MODULE_DEVICE_TABLE(of, omap_sdhci_match);
....@@ -1053,6 +1095,7 @@
10531095 const struct of_device_id *match;
10541096 struct sdhci_omap_data *data;
10551097 const struct soc_device_attribute *soc;
1098
+ struct resource *regs;
10561099
10571100 match = of_match_device(omap_sdhci_match, dev);
10581101 if (!match)
....@@ -1064,6 +1107,10 @@
10641107 return -EINVAL;
10651108 }
10661109 offset = data->offset;
1110
+
1111
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1112
+ if (!regs)
1113
+ return -ENXIO;
10671114
10681115 host = sdhci_pltfm_init(pdev, &sdhci_omap_pdata,
10691116 sizeof(*omap_host));
....@@ -1081,6 +1128,7 @@
10811128 omap_host->timing = MMC_TIMING_LEGACY;
10821129 omap_host->flags = data->flags;
10831130 host->ioaddr += offset;
1131
+ host->mapbase = regs->start + offset;
10841132
10851133 mmc = host->mmc;
10861134 sdhci_get_of_property(pdev);
....@@ -1098,6 +1146,9 @@
10981146 if (!strcmp(dev_name(dev), "480ad000.mmc"))
10991147 mmc->f_max = 48000000;
11001148 }
1149
+
1150
+ if (!mmc_can_gpio_ro(mmc))
1151
+ mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
11011152
11021153 pltfm_host->clk = devm_clk_get(dev, "fck");
11031154 if (IS_ERR(pltfm_host->clk)) {
....@@ -1140,13 +1191,16 @@
11401191 goto err_put_sync;
11411192 }
11421193
1143
- host->mmc_host_ops.get_ro = mmc_gpio_get_ro;
11441194 host->mmc_host_ops.start_signal_voltage_switch =
11451195 sdhci_omap_start_signal_voltage_switch;
11461196 host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
11471197 host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
11481198 host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
11491199 host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq;
1200
+
1201
+ /* Switch to external DMA only if there is the "dmas" property */
1202
+ if (of_find_property(dev->of_node, "dmas", NULL))
1203
+ sdhci_switch_external_dma(host, true);
11501204
11511205 /* R1B responses is required to properly manage HW busy detection. */
11521206 mmc->caps |= MMC_CAP_NEED_RSP_BUSY;
....@@ -1191,12 +1245,74 @@
11911245
11921246 return 0;
11931247 }
1248
+#ifdef CONFIG_PM_SLEEP
1249
+static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host)
1250
+{
1251
+ omap_host->con = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
1252
+ omap_host->hctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL);
1253
+ omap_host->sysctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCTL);
1254
+ omap_host->capa = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA);
1255
+ omap_host->ie = sdhci_omap_readl(omap_host, SDHCI_OMAP_IE);
1256
+ omap_host->ise = sdhci_omap_readl(omap_host, SDHCI_OMAP_ISE);
1257
+}
1258
+
1259
+/* Order matters here, HCTL must be restored in two phases */
1260
+static void sdhci_omap_context_restore(struct sdhci_omap_host *omap_host)
1261
+{
1262
+ sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl);
1263
+ sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, omap_host->capa);
1264
+ sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl);
1265
+
1266
+ sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCTL, omap_host->sysctl);
1267
+ sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, omap_host->con);
1268
+ sdhci_omap_writel(omap_host, SDHCI_OMAP_IE, omap_host->ie);
1269
+ sdhci_omap_writel(omap_host, SDHCI_OMAP_ISE, omap_host->ise);
1270
+}
1271
+
1272
+static int __maybe_unused sdhci_omap_suspend(struct device *dev)
1273
+{
1274
+ struct sdhci_host *host = dev_get_drvdata(dev);
1275
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1276
+ struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
1277
+
1278
+ sdhci_suspend_host(host);
1279
+
1280
+ sdhci_omap_context_save(omap_host);
1281
+
1282
+ pinctrl_pm_select_idle_state(dev);
1283
+
1284
+ pm_runtime_force_suspend(dev);
1285
+
1286
+ return 0;
1287
+}
1288
+
1289
+static int __maybe_unused sdhci_omap_resume(struct device *dev)
1290
+{
1291
+ struct sdhci_host *host = dev_get_drvdata(dev);
1292
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1293
+ struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
1294
+
1295
+ pm_runtime_force_resume(dev);
1296
+
1297
+ pinctrl_pm_select_default_state(dev);
1298
+
1299
+ sdhci_omap_context_restore(omap_host);
1300
+
1301
+ sdhci_resume_host(host);
1302
+
1303
+ return 0;
1304
+}
1305
+#endif
1306
+static SIMPLE_DEV_PM_OPS(sdhci_omap_dev_pm_ops, sdhci_omap_suspend,
1307
+ sdhci_omap_resume);
11941308
11951309 static struct platform_driver sdhci_omap_driver = {
11961310 .probe = sdhci_omap_probe,
11971311 .remove = sdhci_omap_remove,
11981312 .driver = {
11991313 .name = "sdhci-omap",
1314
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
1315
+ .pm = &sdhci_omap_dev_pm_ops,
12001316 .of_match_table = omap_sdhci_match,
12011317 },
12021318 };