0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/clk.h>
0010 #include <linux/delay.h>
0011 #include <linux/mfd/syscon.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/of_address.h>
0015 #include <linux/phy/phy.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/regmap.h>
0018
0019
0020
0021
0022
0023 #define HIWORD_UPDATE(val, mask, shift) \
0024 ((val) << (shift) | (mask) << ((shift) + 16))
0025
0026
0027 #define GRF_EMMCPHY_CON0 0x0
0028 #define GRF_EMMCPHY_CON1 0x4
0029 #define GRF_EMMCPHY_CON2 0x8
0030 #define GRF_EMMCPHY_CON3 0xc
0031 #define GRF_EMMCPHY_CON4 0x10
0032 #define GRF_EMMCPHY_CON5 0x14
0033 #define GRF_EMMCPHY_CON6 0x18
0034 #define GRF_EMMCPHY_STATUS 0x20
0035
0036 #define PHYCTRL_PDB_MASK 0x1
0037 #define PHYCTRL_PDB_SHIFT 0x0
0038 #define PHYCTRL_PDB_PWR_ON 0x1
0039 #define PHYCTRL_PDB_PWR_OFF 0x0
0040 #define PHYCTRL_ENDLL_MASK 0x1
0041 #define PHYCTRL_ENDLL_SHIFT 0x1
0042 #define PHYCTRL_ENDLL_ENABLE 0x1
0043 #define PHYCTRL_ENDLL_DISABLE 0x0
0044 #define PHYCTRL_CALDONE_MASK 0x1
0045 #define PHYCTRL_CALDONE_SHIFT 0x6
0046 #define PHYCTRL_CALDONE_DONE 0x1
0047 #define PHYCTRL_CALDONE_GOING 0x0
0048 #define PHYCTRL_DLLRDY_MASK 0x1
0049 #define PHYCTRL_DLLRDY_SHIFT 0x5
0050 #define PHYCTRL_DLLRDY_DONE 0x1
0051 #define PHYCTRL_DLLRDY_GOING 0x0
0052 #define PHYCTRL_FREQSEL_200M 0x0
0053 #define PHYCTRL_FREQSEL_50M 0x1
0054 #define PHYCTRL_FREQSEL_100M 0x2
0055 #define PHYCTRL_FREQSEL_150M 0x3
0056 #define PHYCTRL_FREQSEL_MASK 0x3
0057 #define PHYCTRL_FREQSEL_SHIFT 0xc
0058 #define PHYCTRL_DR_MASK 0x7
0059 #define PHYCTRL_DR_SHIFT 0x4
0060 #define PHYCTRL_DR_50OHM 0x0
0061 #define PHYCTRL_DR_33OHM 0x1
0062 #define PHYCTRL_DR_66OHM 0x2
0063 #define PHYCTRL_DR_100OHM 0x3
0064 #define PHYCTRL_DR_40OHM 0x4
0065 #define PHYCTRL_OTAPDLYENA 0x1
0066 #define PHYCTRL_OTAPDLYENA_MASK 0x1
0067 #define PHYCTRL_OTAPDLYENA_SHIFT 0xb
0068 #define PHYCTRL_OTAPDLYSEL_DEFAULT 0x4
0069 #define PHYCTRL_OTAPDLYSEL_MAXVALUE 0xf
0070 #define PHYCTRL_OTAPDLYSEL_MASK 0xf
0071 #define PHYCTRL_OTAPDLYSEL_SHIFT 0x7
0072 #define PHYCTRL_REN_STRB_DISABLE 0x0
0073 #define PHYCTRL_REN_STRB_ENABLE 0x1
0074 #define PHYCTRL_REN_STRB_MASK 0x1
0075 #define PHYCTRL_REN_STRB_SHIFT 0x9
0076
0077 #define PHYCTRL_IS_CALDONE(x) \
0078 ((((x) >> PHYCTRL_CALDONE_SHIFT) & \
0079 PHYCTRL_CALDONE_MASK) == PHYCTRL_CALDONE_DONE)
0080 #define PHYCTRL_IS_DLLRDY(x) \
0081 ((((x) >> PHYCTRL_DLLRDY_SHIFT) & \
0082 PHYCTRL_DLLRDY_MASK) == PHYCTRL_DLLRDY_DONE)
0083
0084 struct rockchip_emmc_phy {
0085 unsigned int reg_offset;
0086 struct regmap *reg_base;
0087 struct clk *emmcclk;
0088 unsigned int drive_impedance;
0089 unsigned int enable_strobe_pulldown;
0090 unsigned int output_tapdelay_select;
0091 };
0092
0093 static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
0094 {
0095 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
0096 unsigned int caldone;
0097 unsigned int dllrdy;
0098 unsigned int freqsel = PHYCTRL_FREQSEL_200M;
0099 unsigned long rate;
0100 int ret;
0101
0102
0103
0104
0105
0106 regmap_write(rk_phy->reg_base,
0107 rk_phy->reg_offset + GRF_EMMCPHY_CON6,
0108 HIWORD_UPDATE(PHYCTRL_PDB_PWR_OFF,
0109 PHYCTRL_PDB_MASK,
0110 PHYCTRL_PDB_SHIFT));
0111 regmap_write(rk_phy->reg_base,
0112 rk_phy->reg_offset + GRF_EMMCPHY_CON6,
0113 HIWORD_UPDATE(PHYCTRL_ENDLL_DISABLE,
0114 PHYCTRL_ENDLL_MASK,
0115 PHYCTRL_ENDLL_SHIFT));
0116
0117
0118 if (on_off == PHYCTRL_PDB_PWR_OFF)
0119 return 0;
0120
0121 rate = clk_get_rate(rk_phy->emmcclk);
0122
0123 if (rate != 0) {
0124 unsigned long ideal_rate;
0125 unsigned long diff;
0126
0127 switch (rate) {
0128 case 1 ... 74999999:
0129 ideal_rate = 50000000;
0130 freqsel = PHYCTRL_FREQSEL_50M;
0131 break;
0132 case 75000000 ... 124999999:
0133 ideal_rate = 100000000;
0134 freqsel = PHYCTRL_FREQSEL_100M;
0135 break;
0136 case 125000000 ... 174999999:
0137 ideal_rate = 150000000;
0138 freqsel = PHYCTRL_FREQSEL_150M;
0139 break;
0140 default:
0141 ideal_rate = 200000000;
0142 break;
0143 }
0144
0145 diff = (rate > ideal_rate) ?
0146 rate - ideal_rate : ideal_rate - rate;
0147
0148
0149
0150
0151
0152
0153
0154 if ((rate > 50000000 && diff > 15000000) || (rate > 200000000))
0155 dev_warn(&phy->dev, "Unsupported rate: %lu\n", rate);
0156 }
0157
0158
0159
0160
0161
0162
0163 udelay(3);
0164 regmap_write(rk_phy->reg_base,
0165 rk_phy->reg_offset + GRF_EMMCPHY_CON6,
0166 HIWORD_UPDATE(PHYCTRL_PDB_PWR_ON,
0167 PHYCTRL_PDB_MASK,
0168 PHYCTRL_PDB_SHIFT));
0169
0170
0171
0172
0173
0174
0175
0176
0177 ret = regmap_read_poll_timeout(rk_phy->reg_base,
0178 rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
0179 caldone, PHYCTRL_IS_CALDONE(caldone),
0180 0, 50);
0181 if (ret) {
0182 pr_err("%s: caldone failed, ret=%d\n", __func__, ret);
0183 return ret;
0184 }
0185
0186
0187 regmap_write(rk_phy->reg_base,
0188 rk_phy->reg_offset + GRF_EMMCPHY_CON0,
0189 HIWORD_UPDATE(freqsel, PHYCTRL_FREQSEL_MASK,
0190 PHYCTRL_FREQSEL_SHIFT));
0191
0192
0193 regmap_write(rk_phy->reg_base,
0194 rk_phy->reg_offset + GRF_EMMCPHY_CON6,
0195 HIWORD_UPDATE(PHYCTRL_ENDLL_ENABLE,
0196 PHYCTRL_ENDLL_MASK,
0197 PHYCTRL_ENDLL_SHIFT));
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208 if (rate == 0)
0209 return 0;
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225 ret = regmap_read_poll_timeout(rk_phy->reg_base,
0226 rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
0227 dllrdy, PHYCTRL_IS_DLLRDY(dllrdy),
0228 0, 50 * USEC_PER_MSEC);
0229 if (ret) {
0230 pr_err("%s: dllrdy failed. ret=%d\n", __func__, ret);
0231 return ret;
0232 }
0233
0234 return 0;
0235 }
0236
0237 static int rockchip_emmc_phy_init(struct phy *phy)
0238 {
0239 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
0240 int ret = 0;
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258 rk_phy->emmcclk = clk_get_optional(&phy->dev, "emmcclk");
0259 if (IS_ERR(rk_phy->emmcclk)) {
0260 ret = PTR_ERR(rk_phy->emmcclk);
0261 dev_err(&phy->dev, "Error getting emmcclk: %d\n", ret);
0262 rk_phy->emmcclk = NULL;
0263 }
0264
0265 return ret;
0266 }
0267
0268 static int rockchip_emmc_phy_exit(struct phy *phy)
0269 {
0270 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
0271
0272 clk_put(rk_phy->emmcclk);
0273
0274 return 0;
0275 }
0276
0277 static int rockchip_emmc_phy_power_off(struct phy *phy)
0278 {
0279
0280 return rockchip_emmc_phy_power(phy, PHYCTRL_PDB_PWR_OFF);
0281 }
0282
0283 static int rockchip_emmc_phy_power_on(struct phy *phy)
0284 {
0285 struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
0286
0287
0288 regmap_write(rk_phy->reg_base,
0289 rk_phy->reg_offset + GRF_EMMCPHY_CON6,
0290 HIWORD_UPDATE(rk_phy->drive_impedance,
0291 PHYCTRL_DR_MASK,
0292 PHYCTRL_DR_SHIFT));
0293
0294
0295 regmap_write(rk_phy->reg_base,
0296 rk_phy->reg_offset + GRF_EMMCPHY_CON0,
0297 HIWORD_UPDATE(PHYCTRL_OTAPDLYENA,
0298 PHYCTRL_OTAPDLYENA_MASK,
0299 PHYCTRL_OTAPDLYENA_SHIFT));
0300
0301
0302 regmap_write(rk_phy->reg_base,
0303 rk_phy->reg_offset + GRF_EMMCPHY_CON0,
0304 HIWORD_UPDATE(rk_phy->output_tapdelay_select,
0305 PHYCTRL_OTAPDLYSEL_MASK,
0306 PHYCTRL_OTAPDLYSEL_SHIFT));
0307
0308
0309 regmap_write(rk_phy->reg_base,
0310 rk_phy->reg_offset + GRF_EMMCPHY_CON2,
0311 HIWORD_UPDATE(rk_phy->enable_strobe_pulldown,
0312 PHYCTRL_REN_STRB_MASK,
0313 PHYCTRL_REN_STRB_SHIFT));
0314
0315
0316 return rockchip_emmc_phy_power(phy, PHYCTRL_PDB_PWR_ON);
0317 }
0318
0319 static const struct phy_ops ops = {
0320 .init = rockchip_emmc_phy_init,
0321 .exit = rockchip_emmc_phy_exit,
0322 .power_on = rockchip_emmc_phy_power_on,
0323 .power_off = rockchip_emmc_phy_power_off,
0324 .owner = THIS_MODULE,
0325 };
0326
0327 static u32 convert_drive_impedance_ohm(struct platform_device *pdev, u32 dr_ohm)
0328 {
0329 switch (dr_ohm) {
0330 case 100:
0331 return PHYCTRL_DR_100OHM;
0332 case 66:
0333 return PHYCTRL_DR_66OHM;
0334 case 50:
0335 return PHYCTRL_DR_50OHM;
0336 case 40:
0337 return PHYCTRL_DR_40OHM;
0338 case 33:
0339 return PHYCTRL_DR_33OHM;
0340 }
0341
0342 dev_warn(&pdev->dev, "Invalid value %u for drive-impedance-ohm.\n",
0343 dr_ohm);
0344 return PHYCTRL_DR_50OHM;
0345 }
0346
0347 static int rockchip_emmc_phy_probe(struct platform_device *pdev)
0348 {
0349 struct device *dev = &pdev->dev;
0350 struct rockchip_emmc_phy *rk_phy;
0351 struct phy *generic_phy;
0352 struct phy_provider *phy_provider;
0353 struct regmap *grf;
0354 unsigned int reg_offset;
0355 u32 val;
0356
0357 if (!dev->parent || !dev->parent->of_node)
0358 return -ENODEV;
0359
0360 grf = syscon_node_to_regmap(dev->parent->of_node);
0361 if (IS_ERR(grf)) {
0362 dev_err(dev, "Missing rockchip,grf property\n");
0363 return PTR_ERR(grf);
0364 }
0365
0366 rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
0367 if (!rk_phy)
0368 return -ENOMEM;
0369
0370 if (of_property_read_u32(dev->of_node, "reg", ®_offset)) {
0371 dev_err(dev, "missing reg property in node %pOFn\n",
0372 dev->of_node);
0373 return -EINVAL;
0374 }
0375
0376 rk_phy->reg_offset = reg_offset;
0377 rk_phy->reg_base = grf;
0378 rk_phy->drive_impedance = PHYCTRL_DR_50OHM;
0379 rk_phy->enable_strobe_pulldown = PHYCTRL_REN_STRB_DISABLE;
0380 rk_phy->output_tapdelay_select = PHYCTRL_OTAPDLYSEL_DEFAULT;
0381
0382 if (!of_property_read_u32(dev->of_node, "drive-impedance-ohm", &val))
0383 rk_phy->drive_impedance = convert_drive_impedance_ohm(pdev, val);
0384
0385 if (of_property_read_bool(dev->of_node, "rockchip,enable-strobe-pulldown"))
0386 rk_phy->enable_strobe_pulldown = PHYCTRL_REN_STRB_ENABLE;
0387
0388 if (!of_property_read_u32(dev->of_node, "rockchip,output-tapdelay-select", &val)) {
0389 if (val <= PHYCTRL_OTAPDLYSEL_MAXVALUE)
0390 rk_phy->output_tapdelay_select = val;
0391 else
0392 dev_err(dev, "output-tapdelay-select exceeds limit, apply default\n");
0393 }
0394
0395 generic_phy = devm_phy_create(dev, dev->of_node, &ops);
0396 if (IS_ERR(generic_phy)) {
0397 dev_err(dev, "failed to create PHY\n");
0398 return PTR_ERR(generic_phy);
0399 }
0400
0401 phy_set_drvdata(generic_phy, rk_phy);
0402 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
0403
0404 return PTR_ERR_OR_ZERO(phy_provider);
0405 }
0406
0407 static const struct of_device_id rockchip_emmc_phy_dt_ids[] = {
0408 { .compatible = "rockchip,rk3399-emmc-phy" },
0409 {}
0410 };
0411
0412 MODULE_DEVICE_TABLE(of, rockchip_emmc_phy_dt_ids);
0413
0414 static struct platform_driver rockchip_emmc_driver = {
0415 .probe = rockchip_emmc_phy_probe,
0416 .driver = {
0417 .name = "rockchip-emmc-phy",
0418 .of_match_table = rockchip_emmc_phy_dt_ids,
0419 },
0420 };
0421
0422 module_platform_driver(rockchip_emmc_driver);
0423
0424 MODULE_AUTHOR("Shawn Lin <shawn.lin@rock-chips.com>");
0425 MODULE_DESCRIPTION("Rockchip EMMC PHY driver");
0426 MODULE_LICENSE("GPL v2");