• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * SDHCI support for SiRF primaII and marco SoCs
4  *
5  * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
6  */
7 
8 #include <linux/delay.h>
9 #include <linux/device.h>
10 #include <linux/mmc/host.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/mmc/slot-gpio.h>
14 #include "sdhci-pltfm.h"
15 
16 #define SDHCI_CLK_DELAY_SETTING 0x4C
17 #define SDHCI_SIRF_8BITBUS BIT(3)
18 #define SIRF_TUNING_COUNT 16384
19 
sdhci_sirf_set_bus_width(struct sdhci_host * host,int width)20 static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
21 {
22 	u8 ctrl;
23 
24 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
25 	ctrl &= ~(SDHCI_CTRL_4BITBUS | SDHCI_SIRF_8BITBUS);
26 
27 	/*
28 	 * CSR atlas7 and prima2 SD host version is not 3.0
29 	 * 8bit-width enable bit of CSR SD hosts is 3,
30 	 * while stardard hosts use bit 5
31 	 */
32 	if (width == MMC_BUS_WIDTH_8)
33 		ctrl |= SDHCI_SIRF_8BITBUS;
34 	else if (width == MMC_BUS_WIDTH_4)
35 		ctrl |= SDHCI_CTRL_4BITBUS;
36 
37 	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
38 }
39 
sdhci_sirf_readl_le(struct sdhci_host * host,int reg)40 static u32 sdhci_sirf_readl_le(struct sdhci_host *host, int reg)
41 {
42 	u32 val = readl(host->ioaddr + reg);
43 
44 	if (unlikely((reg == SDHCI_CAPABILITIES_1) &&
45 			(host->mmc->caps & MMC_CAP_UHS_SDR50))) {
46 		/* fake CAP_1 register */
47 		val = SDHCI_SUPPORT_DDR50 |
48 			SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING;
49 	}
50 
51 	if (unlikely(reg == SDHCI_SLOT_INT_STATUS)) {
52 		u32 prss = val;
53 		/* fake chips as V3.0 host conreoller */
54 		prss &= ~(0xFF << 16);
55 		val = prss | (SDHCI_SPEC_300 << 16);
56 	}
57 	return val;
58 }
59 
sdhci_sirf_readw_le(struct sdhci_host * host,int reg)60 static u16 sdhci_sirf_readw_le(struct sdhci_host *host, int reg)
61 {
62 	u16 ret = 0;
63 
64 	ret = readw(host->ioaddr + reg);
65 
66 	if (unlikely(reg == SDHCI_HOST_VERSION)) {
67 		ret = readw(host->ioaddr + SDHCI_HOST_VERSION);
68 		ret |= SDHCI_SPEC_300;
69 	}
70 
71 	return ret;
72 }
73 
sdhci_sirf_execute_tuning(struct sdhci_host * host,u32 opcode)74 static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
75 {
76 	int tuning_seq_cnt = 3;
77 	int phase;
78 	u8 tuned_phase_cnt = 0;
79 	int rc = 0, longest_range = 0;
80 	int start = -1, end = 0, tuning_value = -1, range = 0;
81 	u16 clock_setting;
82 	struct mmc_host *mmc = host->mmc;
83 
84 	clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING);
85 	clock_setting &= ~0x3fff;
86 
87 retry:
88 	phase = 0;
89 	tuned_phase_cnt = 0;
90 	do {
91 		sdhci_writel(host,
92 			clock_setting | phase,
93 			SDHCI_CLK_DELAY_SETTING);
94 
95 		if (!mmc_send_tuning(mmc, opcode, NULL)) {
96 			/* Tuning is successful at this tuning point */
97 			tuned_phase_cnt++;
98 			dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
99 				 mmc_hostname(mmc), phase);
100 			if (start == -1)
101 				start = phase;
102 			end = phase;
103 			range++;
104 			if (phase == (SIRF_TUNING_COUNT - 1)
105 				&& range > longest_range)
106 				tuning_value = (start + end) / 2;
107 		} else {
108 			dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n",
109 				 mmc_hostname(mmc), phase);
110 			if (range > longest_range) {
111 				tuning_value = (start + end) / 2;
112 				longest_range = range;
113 			}
114 			start = -1;
115 			end = range = 0;
116 		}
117 	} while (++phase < SIRF_TUNING_COUNT);
118 
119 	if (tuned_phase_cnt && tuning_value > 0) {
120 		/*
121 		 * Finally set the selected phase in delay
122 		 * line hw block.
123 		 */
124 		phase = tuning_value;
125 		sdhci_writel(host,
126 			clock_setting | phase,
127 			SDHCI_CLK_DELAY_SETTING);
128 
129 		dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
130 			 mmc_hostname(mmc), phase);
131 	} else {
132 		if (--tuning_seq_cnt)
133 			goto retry;
134 		/* Tuning failed */
135 		dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
136 		       mmc_hostname(mmc));
137 		rc = -EIO;
138 	}
139 
140 	return rc;
141 }
142 
143 static const struct sdhci_ops sdhci_sirf_ops = {
144 	.read_l = sdhci_sirf_readl_le,
145 	.read_w = sdhci_sirf_readw_le,
146 	.platform_execute_tuning = sdhci_sirf_execute_tuning,
147 	.set_clock = sdhci_set_clock,
148 	.get_max_clock	= sdhci_pltfm_clk_get_max_clock,
149 	.set_bus_width = sdhci_sirf_set_bus_width,
150 	.reset = sdhci_reset,
151 	.set_uhs_signaling = sdhci_set_uhs_signaling,
152 };
153 
154 static const struct sdhci_pltfm_data sdhci_sirf_pdata = {
155 	.ops = &sdhci_sirf_ops,
156 	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
157 		SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
158 		SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
159 		SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
160 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
161 };
162 
sdhci_sirf_probe(struct platform_device * pdev)163 static int sdhci_sirf_probe(struct platform_device *pdev)
164 {
165 	struct sdhci_host *host;
166 	struct sdhci_pltfm_host *pltfm_host;
167 	struct clk *clk;
168 	int ret;
169 
170 	clk = devm_clk_get(&pdev->dev, NULL);
171 	if (IS_ERR(clk)) {
172 		dev_err(&pdev->dev, "unable to get clock");
173 		return PTR_ERR(clk);
174 	}
175 
176 	host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, 0);
177 	if (IS_ERR(host))
178 		return PTR_ERR(host);
179 
180 	pltfm_host = sdhci_priv(host);
181 	pltfm_host->clk = clk;
182 
183 	sdhci_get_of_property(pdev);
184 
185 	ret = clk_prepare_enable(pltfm_host->clk);
186 	if (ret)
187 		goto err_clk_prepare;
188 
189 	ret = sdhci_add_host(host);
190 	if (ret)
191 		goto err_sdhci_add;
192 
193 	/*
194 	 * We must request the IRQ after sdhci_add_host(), as the tasklet only
195 	 * gets setup in sdhci_add_host() and we oops.
196 	 */
197 	ret = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0, NULL);
198 	if (ret == -EPROBE_DEFER)
199 		goto err_request_cd;
200 	if (!ret)
201 		mmc_gpiod_request_cd_irq(host->mmc);
202 
203 	return 0;
204 
205 err_request_cd:
206 	sdhci_remove_host(host, 0);
207 err_sdhci_add:
208 	clk_disable_unprepare(pltfm_host->clk);
209 err_clk_prepare:
210 	sdhci_pltfm_free(pdev);
211 	return ret;
212 }
213 
214 static const struct of_device_id sdhci_sirf_of_match[] = {
215 	{ .compatible = "sirf,prima2-sdhc" },
216 	{ }
217 };
218 MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match);
219 
220 static struct platform_driver sdhci_sirf_driver = {
221 	.driver		= {
222 		.name	= "sdhci-sirf",
223 		.of_match_table = sdhci_sirf_of_match,
224 		.pm	= &sdhci_pltfm_pmops,
225 	},
226 	.probe		= sdhci_sirf_probe,
227 	.remove		= sdhci_pltfm_unregister,
228 };
229 
230 module_platform_driver(sdhci_sirf_driver);
231 
232 MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco");
233 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
234 MODULE_LICENSE("GPL v2");
235