aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-07-31 21:36:58 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-31 21:36:58 -0400
commit07f00f06ba9a5533d6650d46d3e938f6cbeee97e (patch)
tree854142fbef263efe8c5b3e9d7450cb44b7fb84c6 /drivers/phy
parent27acbec338113a75b9d72aeb53149a3538031dda (diff)
parent6ea6257945188ff7f5d1670d5adc964ac78c590c (diff)
Merge tag 'mmc-v4.8' of git://git.linaro.org/people/ulf.hansson/mmc
Pull MMC updates from Ulf Hansson: "MMC core: - A couple of changes to improve the support for erase/discard/trim cmds - Add eMMC HS400 enhanced strobe support - Show OCR and DSR registers in SYSFS for MMC/SD cards - Correct and improve busy detection logic for MMC switch (CMD6) cmds - Disable HPI cmds for certain broken Hynix eMMC cards - Allow MMC hosts to specify non-support for SD and MMC cmds - Some minor additional fixes MMC host: - sdhci: Re-works, fixes and clean-ups - sdhci: Add HW auto re-tuning support - sdhci: Re-factor code to prepare for adding support for eMMC CMDQ - sdhci-esdhc-imx: Fixes and clean-ups - sdhci-esdhc-imx: Update system PM support - sdhci-esdhc-imx: Enable HW auto re-tuning - sdhci-bcm2835: Remove driver as sdhci-iproc is used instead - sdhci-brcmstb: Add new driver for Broadcom BRCMSTB SoCs - sdhci-msm: Add support for UHS cards - sdhci-tegra: Improve support for UHS cards - sdhci-of-arasan: Update phy support for Rockchip SoCs - sdhci-of-arasan: Deploy enhanced strobe support - dw_mmc: Some fixes and clean-ups - dw_mmc: Enable support for erase/discard/trim cmds - dw_mmc: Enable CMD23 support - mediatek: Some fixes related to the eMMC HS400 support - sh_mmcif: Improve support for HW busy detection - rtsx_pci: Enable support for erase/discard/trim cmds" * tag 'mmc-v4.8' of git://git.linaro.org/people/ulf.hansson/mmc: (135 commits) mmc: rtsx_pci: Remove deprecated create_singlethread_workqueue mmc: rtsx_pci: Enable MMC_CAP_ERASE to allow erase/discard/trim requests mmc: rtsx_pci: Use the provided busy timeout from the mmc core mmc: sdhci-pltfm: Drop define for SDHCI_PLTFM_PMOPS mmc: sdhci-pltfm: Convert to use the SET_SYSTEM_SLEEP_PM_OPS mmc: sdhci-pltfm: Make sdhci_pltfm_suspend|resume() static mmc: sdhci-esdhc-imx: Use common sdhci_suspend|resume_host() mmc: sdhci-esdhc-imx: Assign system PM ops within #ifdef CONFIG_PM_SLEEP mmc: sdhci-sirf: Remove non needed #ifdef CONFIG_PM* for dev_pm_ops mmc: sdhci-s3c: Remove non needed #ifdef CONFIG_PM for dev_pm_ops mmc: sdhci-pxav3: Remove non needed #ifdef CONFIG_PM for dev_pm_ops mmc: sdhci-of-esdhc: Simplify code by using SIMPLE_DEV_PM_OPS mmc: sdhci-acpi: Simplify code by using SET_SYSTEM_SLEEP_PM_OPS mmc: sdhci-pci-core: Simplify code by using SET_SYSTEM_SLEEP_PM_OPS mmc: Change the max discard sectors and erase response when HW busy detect phy: rockchip-emmc: Wait even longer for the DLL to lock phy: rockchip-emmc: Be tolerant to card clock of 0 in power on mmc: sdhci-of-arasan: Revert: Always power the PHY off/on when clock changes mmc: sdhci-msm: Add support for UHS cards mmc: sdhci-msm: Add set_uhs_signaling() implementation ...
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/phy-rockchip-emmc.c241
1 files changed, 196 insertions, 45 deletions
diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
index 6ebcf3e41c46..fd57345ffed2 100644
--- a/drivers/phy/phy-rockchip-emmc.c
+++ b/drivers/phy/phy-rockchip-emmc.c
@@ -14,6 +14,7 @@
14 * GNU General Public License for more details. 14 * GNU General Public License for more details.
15 */ 15 */
16 16
17#include <linux/clk.h>
17#include <linux/delay.h> 18#include <linux/delay.h>
18#include <linux/mfd/syscon.h> 19#include <linux/mfd/syscon.h>
19#include <linux/module.h> 20#include <linux/module.h>
@@ -31,42 +32,64 @@
31 ((val) << (shift) | (mask) << ((shift) + 16)) 32 ((val) << (shift) | (mask) << ((shift) + 16))
32 33
33/* Register definition */ 34/* Register definition */
34#define GRF_EMMCPHY_CON0 0x0 35#define GRF_EMMCPHY_CON0 0x0
35#define GRF_EMMCPHY_CON1 0x4 36#define GRF_EMMCPHY_CON1 0x4
36#define GRF_EMMCPHY_CON2 0x8 37#define GRF_EMMCPHY_CON2 0x8
37#define GRF_EMMCPHY_CON3 0xc 38#define GRF_EMMCPHY_CON3 0xc
38#define GRF_EMMCPHY_CON4 0x10 39#define GRF_EMMCPHY_CON4 0x10
39#define GRF_EMMCPHY_CON5 0x14 40#define GRF_EMMCPHY_CON5 0x14
40#define GRF_EMMCPHY_CON6 0x18 41#define GRF_EMMCPHY_CON6 0x18
41#define GRF_EMMCPHY_STATUS 0x20 42#define GRF_EMMCPHY_STATUS 0x20
42 43
43#define PHYCTRL_PDB_MASK 0x1 44#define PHYCTRL_PDB_MASK 0x1
44#define PHYCTRL_PDB_SHIFT 0x0 45#define PHYCTRL_PDB_SHIFT 0x0
45#define PHYCTRL_PDB_PWR_ON 0x1 46#define PHYCTRL_PDB_PWR_ON 0x1
46#define PHYCTRL_PDB_PWR_OFF 0x0 47#define PHYCTRL_PDB_PWR_OFF 0x0
47#define PHYCTRL_ENDLL_MASK 0x1 48#define PHYCTRL_ENDLL_MASK 0x1
48#define PHYCTRL_ENDLL_SHIFT 0x1 49#define PHYCTRL_ENDLL_SHIFT 0x1
49#define PHYCTRL_ENDLL_ENABLE 0x1 50#define PHYCTRL_ENDLL_ENABLE 0x1
50#define PHYCTRL_ENDLL_DISABLE 0x0 51#define PHYCTRL_ENDLL_DISABLE 0x0
51#define PHYCTRL_CALDONE_MASK 0x1 52#define PHYCTRL_CALDONE_MASK 0x1
52#define PHYCTRL_CALDONE_SHIFT 0x6 53#define PHYCTRL_CALDONE_SHIFT 0x6
53#define PHYCTRL_CALDONE_DONE 0x1 54#define PHYCTRL_CALDONE_DONE 0x1
54#define PHYCTRL_CALDONE_GOING 0x0 55#define PHYCTRL_CALDONE_GOING 0x0
55#define PHYCTRL_DLLRDY_MASK 0x1 56#define PHYCTRL_DLLRDY_MASK 0x1
56#define PHYCTRL_DLLRDY_SHIFT 0x5 57#define PHYCTRL_DLLRDY_SHIFT 0x5
57#define PHYCTRL_DLLRDY_DONE 0x1 58#define PHYCTRL_DLLRDY_DONE 0x1
58#define PHYCTRL_DLLRDY_GOING 0x0 59#define PHYCTRL_DLLRDY_GOING 0x0
60#define PHYCTRL_FREQSEL_200M 0x0
61#define PHYCTRL_FREQSEL_50M 0x1
62#define PHYCTRL_FREQSEL_100M 0x2
63#define PHYCTRL_FREQSEL_150M 0x3
64#define PHYCTRL_FREQSEL_MASK 0x3
65#define PHYCTRL_FREQSEL_SHIFT 0xc
66#define PHYCTRL_DR_MASK 0x7
67#define PHYCTRL_DR_SHIFT 0x4
68#define PHYCTRL_DR_50OHM 0x0
69#define PHYCTRL_DR_33OHM 0x1
70#define PHYCTRL_DR_66OHM 0x2
71#define PHYCTRL_DR_100OHM 0x3
72#define PHYCTRL_DR_40OHM 0x4
73#define PHYCTRL_OTAPDLYENA 0x1
74#define PHYCTRL_OTAPDLYENA_MASK 0x1
75#define PHYCTRL_OTAPDLYENA_SHIFT 0xb
76#define PHYCTRL_OTAPDLYSEL_MASK 0xf
77#define PHYCTRL_OTAPDLYSEL_SHIFT 0x7
59 78
60struct rockchip_emmc_phy { 79struct rockchip_emmc_phy {
61 unsigned int reg_offset; 80 unsigned int reg_offset;
62 struct regmap *reg_base; 81 struct regmap *reg_base;
82 struct clk *emmcclk;
63}; 83};
64 84
65static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy, 85static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
66 bool on_off)
67{ 86{
87 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
68 unsigned int caldone; 88 unsigned int caldone;
69 unsigned int dllrdy; 89 unsigned int dllrdy;
90 unsigned int freqsel = PHYCTRL_FREQSEL_200M;
91 unsigned long rate;
92 unsigned long timeout;
70 93
71 /* 94 /*
72 * Keep phyctrl_pdb and phyctrl_endll low to allow 95 * Keep phyctrl_pdb and phyctrl_endll low to allow
@@ -87,6 +110,43 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
87 if (on_off == PHYCTRL_PDB_PWR_OFF) 110 if (on_off == PHYCTRL_PDB_PWR_OFF)
88 return 0; 111 return 0;
89 112
113 rate = clk_get_rate(rk_phy->emmcclk);
114
115 if (rate != 0) {
116 unsigned long ideal_rate;
117 unsigned long diff;
118
119 switch (rate) {
120 case 1 ... 74999999:
121 ideal_rate = 50000000;
122 freqsel = PHYCTRL_FREQSEL_50M;
123 break;
124 case 75000000 ... 124999999:
125 ideal_rate = 100000000;
126 freqsel = PHYCTRL_FREQSEL_100M;
127 break;
128 case 125000000 ... 174999999:
129 ideal_rate = 150000000;
130 freqsel = PHYCTRL_FREQSEL_150M;
131 break;
132 default:
133 ideal_rate = 200000000;
134 break;
135 };
136
137 diff = (rate > ideal_rate) ?
138 rate - ideal_rate : ideal_rate - rate;
139
140 /*
141 * In order for tuning delays to be accurate we need to be
142 * pretty spot on for the DLL range, so warn if we're too
143 * far off. Also warn if we're above the 200 MHz max. Don't
144 * warn for really slow rates since we won't be tuning then.
145 */
146 if ((rate > 50000000 && diff > 15000000) || (rate > 200000000))
147 dev_warn(&phy->dev, "Unsupported rate: %lu\n", rate);
148 }
149
90 /* 150 /*
91 * According to the user manual, calpad calibration 151 * According to the user manual, calpad calibration
92 * cycle takes more than 2us without the minimal recommended 152 * cycle takes more than 2us without the minimal recommended
@@ -113,20 +173,62 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
113 return -ETIMEDOUT; 173 return -ETIMEDOUT;
114 } 174 }
115 175
176 /* Set the frequency of the DLL operation */
177 regmap_write(rk_phy->reg_base,
178 rk_phy->reg_offset + GRF_EMMCPHY_CON0,
179 HIWORD_UPDATE(freqsel, PHYCTRL_FREQSEL_MASK,
180 PHYCTRL_FREQSEL_SHIFT));
181
182 /* Turn on the DLL */
116 regmap_write(rk_phy->reg_base, 183 regmap_write(rk_phy->reg_base,
117 rk_phy->reg_offset + GRF_EMMCPHY_CON6, 184 rk_phy->reg_offset + GRF_EMMCPHY_CON6,
118 HIWORD_UPDATE(PHYCTRL_ENDLL_ENABLE, 185 HIWORD_UPDATE(PHYCTRL_ENDLL_ENABLE,
119 PHYCTRL_ENDLL_MASK, 186 PHYCTRL_ENDLL_MASK,
120 PHYCTRL_ENDLL_SHIFT)); 187 PHYCTRL_ENDLL_SHIFT));
188
121 /* 189 /*
122 * After enable analog DLL circuits, we need extra 10.2us 190 * We turned on the DLL even though the rate was 0 because we the
123 * for dll to be ready for work. 191 * clock might be turned on later. ...but we can't wait for the DLL
192 * to lock when the rate is 0 because it will never lock with no
193 * input clock.
194 *
195 * Technically we should be checking the lock later when the clock
196 * is turned on, but for now we won't.
124 */ 197 */
125 udelay(11); 198 if (rate == 0)
126 regmap_read(rk_phy->reg_base, 199 return 0;
127 rk_phy->reg_offset + GRF_EMMCPHY_STATUS, 200
128 &dllrdy); 201 /*
129 dllrdy = (dllrdy >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK; 202 * After enabling analog DLL circuits docs say that we need 10.2 us if
203 * our source clock is at 50 MHz and that lock time scales linearly
204 * with clock speed. If we are powering on the PHY and the card clock
205 * is super slow (like 100 kHZ) this could take as long as 5.1 ms as
206 * per the math: 10.2 us * (50000000 Hz / 100000 Hz) => 5.1 ms
207 * Hopefully we won't be running at 100 kHz, but we should still make
208 * sure we wait long enough.
209 *
210 * NOTE: There appear to be corner cases where the DLL seems to take
211 * extra long to lock for reasons that aren't understood. In some
212 * extreme cases we've seen it take up to over 10ms (!). We'll be
213 * generous and give it 50ms. We still busy wait here because:
214 * - In most cases it should be super fast.
215 * - This is not called lots during normal operation so it shouldn't
216 * be a power or performance problem to busy wait. We expect it
217 * only at boot / resume. In both cases, eMMC is probably on the
218 * critical path so busy waiting a little extra time should be OK.
219 */
220 timeout = jiffies + msecs_to_jiffies(50);
221 do {
222 udelay(1);
223
224 regmap_read(rk_phy->reg_base,
225 rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
226 &dllrdy);
227 dllrdy = (dllrdy >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK;
228 if (dllrdy == PHYCTRL_DLLRDY_DONE)
229 break;
230 } while (!time_after(jiffies, timeout));
231
130 if (dllrdy != PHYCTRL_DLLRDY_DONE) { 232 if (dllrdy != PHYCTRL_DLLRDY_DONE) {
131 pr_err("rockchip_emmc_phy_power: dllrdy timeout.\n"); 233 pr_err("rockchip_emmc_phy_power: dllrdy timeout.\n");
132 return -ETIMEDOUT; 234 return -ETIMEDOUT;
@@ -135,33 +237,82 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
135 return 0; 237 return 0;
136} 238}
137 239
138static int rockchip_emmc_phy_power_off(struct phy *phy) 240static int rockchip_emmc_phy_init(struct phy *phy)
139{ 241{
140 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy); 242 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
141 int ret = 0; 243 int ret = 0;
142 244
143 /* Power down emmc phy analog blocks */ 245 /*
144 ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_OFF); 246 * We purposely get the clock here and not in probe to avoid the
145 if (ret) 247 * circular dependency problem. We expect:
146 return ret; 248 * - PHY driver to probe
249 * - SDHCI driver to start probe
250 * - SDHCI driver to register it's clock
251 * - SDHCI driver to get the PHY
252 * - SDHCI driver to init the PHY
253 *
254 * The clock is optional, so upon any error we just set to NULL.
255 *
256 * NOTE: we don't do anything special for EPROBE_DEFER here. Given the
257 * above expected use case, EPROBE_DEFER isn't sensible to expect, so
258 * it's just like any other error.
259 */
260 rk_phy->emmcclk = clk_get(&phy->dev, "emmcclk");
261 if (IS_ERR(rk_phy->emmcclk)) {
262 dev_dbg(&phy->dev, "Error getting emmcclk: %d\n", ret);
263 rk_phy->emmcclk = NULL;
264 }
265
266 return ret;
267}
268
269static int rockchip_emmc_phy_exit(struct phy *phy)
270{
271 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
272
273 clk_put(rk_phy->emmcclk);
147 274
148 return 0; 275 return 0;
149} 276}
150 277
278static int rockchip_emmc_phy_power_off(struct phy *phy)
279{
280 /* Power down emmc phy analog blocks */
281 return rockchip_emmc_phy_power(phy, PHYCTRL_PDB_PWR_OFF);
282}
283
151static int rockchip_emmc_phy_power_on(struct phy *phy) 284static int rockchip_emmc_phy_power_on(struct phy *phy)
152{ 285{
153 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy); 286 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
154 int ret = 0;
155 287
156 /* Power up emmc phy analog blocks */ 288 /* Drive impedance: 50 Ohm */
157 ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_ON); 289 regmap_write(rk_phy->reg_base,
158 if (ret) 290 rk_phy->reg_offset + GRF_EMMCPHY_CON6,
159 return ret; 291 HIWORD_UPDATE(PHYCTRL_DR_50OHM,
292 PHYCTRL_DR_MASK,
293 PHYCTRL_DR_SHIFT));
160 294
161 return 0; 295 /* Output tap delay: enable */
296 regmap_write(rk_phy->reg_base,
297 rk_phy->reg_offset + GRF_EMMCPHY_CON0,
298 HIWORD_UPDATE(PHYCTRL_OTAPDLYENA,
299 PHYCTRL_OTAPDLYENA_MASK,
300 PHYCTRL_OTAPDLYENA_SHIFT));
301
302 /* Output tap delay */
303 regmap_write(rk_phy->reg_base,
304 rk_phy->reg_offset + GRF_EMMCPHY_CON0,
305 HIWORD_UPDATE(4,
306 PHYCTRL_OTAPDLYSEL_MASK,
307 PHYCTRL_OTAPDLYSEL_SHIFT));
308
309 /* Power up emmc phy analog blocks */
310 return rockchip_emmc_phy_power(phy, PHYCTRL_PDB_PWR_ON);
162} 311}
163 312
164static const struct phy_ops ops = { 313static const struct phy_ops ops = {
314 .init = rockchip_emmc_phy_init,
315 .exit = rockchip_emmc_phy_exit,
165 .power_on = rockchip_emmc_phy_power_on, 316 .power_on = rockchip_emmc_phy_power_on,
166 .power_off = rockchip_emmc_phy_power_off, 317 .power_off = rockchip_emmc_phy_power_off,
167 .owner = THIS_MODULE, 318 .owner = THIS_MODULE,