aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy
diff options
context:
space:
mode:
authorDouglas Anderson <dianders@chromium.org>2016-06-20 13:56:53 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2016-07-25 04:34:20 -0400
commit52c0624a10cce0cdc8be2d15462b9c8d76b7700d (patch)
tree8ed54283ef28d43540b2ed3eff82e9f360ab849f /drivers/phy
parent352051ef1ff5efa8ba050bc3a581dbf136a1f97b (diff)
phy: rockchip-emmc: Set phyctrl_frqsel based on card clock
The "phyctrl_frqsel" is described in the Arasan datasheet [1] as "the frequency range of DLL operation". Although the Rockchip variant of this PHY has different ranges than the reference Arasan PHY it appears as if the functionality is similar. We should set this phyctrl field properly. Note: as per Rockchip engineers, apparently the "phyctrl_frqsel" is actually only useful in HS200 / HS400 modes even though the DLL itself it used for some purposes in all modes. See the discussion in the earlier change in this series: ("mmc: sdhci-of-arasan: Always power the PHY off/on when clock changes"). In any case, it shouldn't hurt to set this always. Note that this change should allow boards to run at HS200 / HS400 speed modes while running at 100 MHz or 150 MHz. In fact, running HS400 at 150 MHz (giving 300 MB/s) is the main motivation of this series, since performance is still good but signal integrity problems are less prevelant at 150 MHz. [1]: https://arasan.com/wp-content/media/eMMC-5-1-Total-Solution_Rev-1-3.pdf Signed-off-by: Douglas Anderson <dianders@chromium.org> Acked-by: Kishon Vijay Abraham I <kishon@ti.com> Reviewed-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/phy-rockchip-emmc.c101
1 files changed, 89 insertions, 12 deletions
diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
index 23fe50864526..9dce958233a0 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>
@@ -78,15 +79,53 @@
78struct rockchip_emmc_phy { 79struct rockchip_emmc_phy {
79 unsigned int reg_offset; 80 unsigned int reg_offset;
80 struct regmap *reg_base; 81 struct regmap *reg_base;
82 struct clk *emmcclk;
81}; 83};
82 84
83static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy, 85static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
84 bool on_off)
85{ 86{
87 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
86 unsigned int caldone; 88 unsigned int caldone;
87 unsigned int dllrdy; 89 unsigned int dllrdy;
90 unsigned int freqsel = PHYCTRL_FREQSEL_200M;
88 unsigned long timeout; 91 unsigned long timeout;
89 92
93 if (rk_phy->emmcclk != NULL) {
94 unsigned long rate = clk_get_rate(rk_phy->emmcclk);
95 unsigned long ideal_rate;
96 unsigned long diff;
97
98 switch (rate) {
99 case 0 ... 74999999:
100 ideal_rate = 50000000;
101 freqsel = PHYCTRL_FREQSEL_50M;
102 break;
103 case 75000000 ... 124999999:
104 ideal_rate = 100000000;
105 freqsel = PHYCTRL_FREQSEL_100M;
106 break;
107 case 125000000 ... 174999999:
108 ideal_rate = 150000000;
109 freqsel = PHYCTRL_FREQSEL_150M;
110 break;
111 default:
112 ideal_rate = 200000000;
113 break;
114 };
115
116 diff = (rate > ideal_rate) ?
117 rate - ideal_rate : ideal_rate - rate;
118
119 /*
120 * In order for tuning delays to be accurate we need to be
121 * pretty spot on for the DLL range, so warn if we're too
122 * far off. Also warn if we're above the 200 MHz max. Don't
123 * warn for really slow rates since we won't be tuning then.
124 */
125 if ((rate > 50000000 && diff > 15000000) || (rate > 200000000))
126 dev_warn(&phy->dev, "Unsupported rate: %lu\n", rate);
127 }
128
90 /* 129 /*
91 * Keep phyctrl_pdb and phyctrl_endll low to allow 130 * Keep phyctrl_pdb and phyctrl_endll low to allow
92 * initialization of CALIO state M/C DFFs 131 * initialization of CALIO state M/C DFFs
@@ -132,6 +171,13 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
132 return -ETIMEDOUT; 171 return -ETIMEDOUT;
133 } 172 }
134 173
174 /* Set the frequency of the DLL operation */
175 regmap_write(rk_phy->reg_base,
176 rk_phy->reg_offset + GRF_EMMCPHY_CON0,
177 HIWORD_UPDATE(freqsel, PHYCTRL_FREQSEL_MASK,
178 PHYCTRL_FREQSEL_SHIFT));
179
180 /* Turn on the DLL */
135 regmap_write(rk_phy->reg_base, 181 regmap_write(rk_phy->reg_base,
136 rk_phy->reg_offset + GRF_EMMCPHY_CON6, 182 rk_phy->reg_offset + GRF_EMMCPHY_CON6,
137 HIWORD_UPDATE(PHYCTRL_ENDLL_ENABLE, 183 HIWORD_UPDATE(PHYCTRL_ENDLL_ENABLE,
@@ -166,25 +212,54 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
166 return 0; 212 return 0;
167} 213}
168 214
169static int rockchip_emmc_phy_power_off(struct phy *phy) 215static int rockchip_emmc_phy_init(struct phy *phy)
216{
217 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
218 int ret = 0;
219
220 /*
221 * We purposely get the clock here and not in probe to avoid the
222 * circular dependency problem. We expect:
223 * - PHY driver to probe
224 * - SDHCI driver to start probe
225 * - SDHCI driver to register it's clock
226 * - SDHCI driver to get the PHY
227 * - SDHCI driver to init the PHY
228 *
229 * The clock is optional, so upon any error we just set to NULL.
230 *
231 * NOTE: we don't do anything special for EPROBE_DEFER here. Given the
232 * above expected use case, EPROBE_DEFER isn't sensible to expect, so
233 * it's just like any other error.
234 */
235 rk_phy->emmcclk = clk_get(&phy->dev, "emmcclk");
236 if (IS_ERR(rk_phy->emmcclk)) {
237 dev_dbg(&phy->dev, "Error getting emmcclk: %d\n", ret);
238 rk_phy->emmcclk = NULL;
239 }
240
241 return ret;
242}
243
244static int rockchip_emmc_phy_exit(struct phy *phy)
170{ 245{
171 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy); 246 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
172 247
248 clk_put(rk_phy->emmcclk);
249
250 return 0;
251}
252
253static int rockchip_emmc_phy_power_off(struct phy *phy)
254{
173 /* Power down emmc phy analog blocks */ 255 /* Power down emmc phy analog blocks */
174 return rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_OFF); 256 return rockchip_emmc_phy_power(phy, PHYCTRL_PDB_PWR_OFF);
175} 257}
176 258
177static int rockchip_emmc_phy_power_on(struct phy *phy) 259static int rockchip_emmc_phy_power_on(struct phy *phy)
178{ 260{
179 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy); 261 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
180 262
181 /* DLL operation: 200 MHz */
182 regmap_write(rk_phy->reg_base,
183 rk_phy->reg_offset + GRF_EMMCPHY_CON0,
184 HIWORD_UPDATE(PHYCTRL_FREQSEL_200M,
185 PHYCTRL_FREQSEL_MASK,
186 PHYCTRL_FREQSEL_SHIFT));
187
188 /* Drive impedance: 50 Ohm */ 263 /* Drive impedance: 50 Ohm */
189 regmap_write(rk_phy->reg_base, 264 regmap_write(rk_phy->reg_base,
190 rk_phy->reg_offset + GRF_EMMCPHY_CON6, 265 rk_phy->reg_offset + GRF_EMMCPHY_CON6,
@@ -207,10 +282,12 @@ static int rockchip_emmc_phy_power_on(struct phy *phy)
207 PHYCTRL_OTAPDLYSEL_SHIFT)); 282 PHYCTRL_OTAPDLYSEL_SHIFT));
208 283
209 /* Power up emmc phy analog blocks */ 284 /* Power up emmc phy analog blocks */
210 return rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_ON); 285 return rockchip_emmc_phy_power(phy, PHYCTRL_PDB_PWR_ON);
211} 286}
212 287
213static const struct phy_ops ops = { 288static const struct phy_ops ops = {
289 .init = rockchip_emmc_phy_init,
290 .exit = rockchip_emmc_phy_exit,
214 .power_on = rockchip_emmc_phy_power_on, 291 .power_on = rockchip_emmc_phy_power_on,
215 .power_off = rockchip_emmc_phy_power_off, 292 .power_off = rockchip_emmc_phy_power_off,
216 .owner = THIS_MODULE, 293 .owner = THIS_MODULE,