1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2017-2020,2022 NXP 4 */ 5 6 #include <linux/bitfield.h> 7 #include <linux/bits.h> 8 #include <linux/clk.h> 9 #include <linux/mfd/syscon.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/phy/phy.h> 13 #include <linux/platform_device.h> 14 #include <linux/pm_runtime.h> 15 #include <linux/regmap.h> 16 #include <linux/units.h> 17 18 #define REG_SET 0x4 19 #define REG_CLR 0x8 20 21 #define PHY_CTRL 0x0 22 #define M_MASK GENMASK(18, 17) 23 #define M(n) FIELD_PREP(M_MASK, (n)) 24 #define CCM_MASK GENMASK(16, 14) 25 #define CCM(n) FIELD_PREP(CCM_MASK, (n)) 26 #define CA_MASK GENMASK(13, 11) 27 #define CA(n) FIELD_PREP(CA_MASK, (n)) 28 #define TST_MASK GENMASK(10, 5) 29 #define TST(n) FIELD_PREP(TST_MASK, (n)) 30 #define CH_EN(id) BIT(3 + (id)) 31 #define NB BIT(2) 32 #define RFB BIT(1) 33 #define PD BIT(0) 34 35 /* Power On Reset(POR) value */ 36 #define CTRL_RESET_VAL (M(0x0) | CCM(0x4) | CA(0x4) | TST(0x25)) 37 38 /* PHY initialization value and mask */ 39 #define CTRL_INIT_MASK (M_MASK | CCM_MASK | CA_MASK | TST_MASK | NB | RFB) 40 #define CTRL_INIT_VAL (M(0x0) | CCM(0x5) | CA(0x4) | TST(0x25) | RFB) 41 42 #define PHY_STATUS 0x10 43 #define LOCK BIT(0) 44 45 #define PHY_NUM 2 46 47 #define MIN_CLKIN_FREQ (25 * MEGA) 48 #define MAX_CLKIN_FREQ (165 * MEGA) 49 50 #define PLL_LOCK_SLEEP 10 51 #define PLL_LOCK_TIMEOUT 1000 52 53 struct mixel_lvds_phy { 54 struct phy *phy; 55 struct phy_configure_opts_lvds cfg; 56 unsigned int id; 57 }; 58 59 struct mixel_lvds_phy_priv { 60 struct regmap *regmap; 61 struct mutex lock; /* protect remap access and cfg of our own */ 62 struct clk *phy_ref_clk; 63 struct mixel_lvds_phy *phys[PHY_NUM]; 64 }; 65 66 static int mixel_lvds_phy_init(struct phy *phy) 67 { 68 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); 69 70 mutex_lock(&priv->lock); 71 regmap_update_bits(priv->regmap, 72 PHY_CTRL, CTRL_INIT_MASK, CTRL_INIT_VAL); 73 mutex_unlock(&priv->lock); 74 75 return 0; 76 } 77 78 static int mixel_lvds_phy_power_on(struct phy *phy) 79 { 80 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); 81 struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy); 82 struct mixel_lvds_phy *companion = priv->phys[lvds_phy->id ^ 1]; 83 struct phy_configure_opts_lvds *cfg = &lvds_phy->cfg; 84 u32 val = 0; 85 u32 locked; 86 int ret; 87 88 /* The master PHY would power on the slave PHY. */ 89 if (cfg->is_slave) 90 return 0; 91 92 ret = clk_prepare_enable(priv->phy_ref_clk); 93 if (ret < 0) { 94 dev_err(&phy->dev, 95 "failed to enable PHY reference clock: %d\n", ret); 96 return ret; 97 } 98 99 mutex_lock(&priv->lock); 100 if (cfg->bits_per_lane_and_dclk_cycle == 7) { 101 if (cfg->differential_clk_rate < 44000000) 102 val |= M(0x2); 103 else if (cfg->differential_clk_rate < 90000000) 104 val |= M(0x1); 105 else 106 val |= M(0x0); 107 } else { 108 val = NB; 109 110 if (cfg->differential_clk_rate < 32000000) 111 val |= M(0x2); 112 else if (cfg->differential_clk_rate < 63000000) 113 val |= M(0x1); 114 else 115 val |= M(0x0); 116 } 117 regmap_update_bits(priv->regmap, PHY_CTRL, M_MASK | NB, val); 118 119 /* 120 * Enable two channels synchronously, 121 * if the companion PHY is a slave PHY. 122 */ 123 if (companion->cfg.is_slave) 124 val = CH_EN(0) | CH_EN(1); 125 else 126 val = CH_EN(lvds_phy->id); 127 regmap_write(priv->regmap, PHY_CTRL + REG_SET, val); 128 129 ret = regmap_read_poll_timeout(priv->regmap, PHY_STATUS, locked, 130 locked, PLL_LOCK_SLEEP, 131 PLL_LOCK_TIMEOUT); 132 if (ret < 0) { 133 dev_err(&phy->dev, "failed to get PHY lock: %d\n", ret); 134 clk_disable_unprepare(priv->phy_ref_clk); 135 } 136 mutex_unlock(&priv->lock); 137 138 return ret; 139 } 140 141 static int mixel_lvds_phy_power_off(struct phy *phy) 142 { 143 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); 144 struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy); 145 struct mixel_lvds_phy *companion = priv->phys[lvds_phy->id ^ 1]; 146 struct phy_configure_opts_lvds *cfg = &lvds_phy->cfg; 147 148 /* The master PHY would power off the slave PHY. */ 149 if (cfg->is_slave) 150 return 0; 151 152 mutex_lock(&priv->lock); 153 if (companion->cfg.is_slave) 154 regmap_write(priv->regmap, PHY_CTRL + REG_CLR, 155 CH_EN(0) | CH_EN(1)); 156 else 157 regmap_write(priv->regmap, PHY_CTRL + REG_CLR, 158 CH_EN(lvds_phy->id)); 159 mutex_unlock(&priv->lock); 160 161 clk_disable_unprepare(priv->phy_ref_clk); 162 163 return 0; 164 } 165 166 static int mixel_lvds_phy_configure(struct phy *phy, 167 union phy_configure_opts *opts) 168 { 169 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); 170 struct phy_configure_opts_lvds *cfg = &opts->lvds; 171 int ret; 172 173 ret = clk_set_rate(priv->phy_ref_clk, cfg->differential_clk_rate); 174 if (ret) 175 dev_err(&phy->dev, "failed to set PHY reference clock rate(%lu): %d\n", 176 cfg->differential_clk_rate, ret); 177 178 return ret; 179 } 180 181 /* Assume the master PHY's configuration set is cached first. */ 182 static int mixel_lvds_phy_check_slave(struct phy *slave_phy) 183 { 184 struct device *dev = &slave_phy->dev; 185 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(dev->parent); 186 struct mixel_lvds_phy *slv = phy_get_drvdata(slave_phy); 187 struct mixel_lvds_phy *mst = priv->phys[slv->id ^ 1]; 188 struct phy_configure_opts_lvds *mst_cfg = &mst->cfg; 189 struct phy_configure_opts_lvds *slv_cfg = &slv->cfg; 190 191 if (mst_cfg->bits_per_lane_and_dclk_cycle != 192 slv_cfg->bits_per_lane_and_dclk_cycle) { 193 dev_err(dev, "number bits mismatch(mst: %u vs slv: %u)\n", 194 mst_cfg->bits_per_lane_and_dclk_cycle, 195 slv_cfg->bits_per_lane_and_dclk_cycle); 196 return -EINVAL; 197 } 198 199 if (mst_cfg->differential_clk_rate != 200 slv_cfg->differential_clk_rate) { 201 dev_err(dev, "dclk rate mismatch(mst: %lu vs slv: %lu)\n", 202 mst_cfg->differential_clk_rate, 203 slv_cfg->differential_clk_rate); 204 return -EINVAL; 205 } 206 207 if (mst_cfg->lanes != slv_cfg->lanes) { 208 dev_err(dev, "lanes mismatch(mst: %u vs slv: %u)\n", 209 mst_cfg->lanes, slv_cfg->lanes); 210 return -EINVAL; 211 } 212 213 if (mst_cfg->is_slave == slv_cfg->is_slave) { 214 dev_err(dev, "master PHY is not found\n"); 215 return -EINVAL; 216 } 217 218 return 0; 219 } 220 221 static int mixel_lvds_phy_validate(struct phy *phy, enum phy_mode mode, 222 int submode, union phy_configure_opts *opts) 223 { 224 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); 225 struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy); 226 struct phy_configure_opts_lvds *cfg = &opts->lvds; 227 int ret = 0; 228 229 if (mode != PHY_MODE_LVDS) { 230 dev_err(&phy->dev, "invalid PHY mode(%d)\n", mode); 231 return -EINVAL; 232 } 233 234 if (cfg->bits_per_lane_and_dclk_cycle != 7 && 235 cfg->bits_per_lane_and_dclk_cycle != 10) { 236 dev_err(&phy->dev, "invalid bits per data lane(%u)\n", 237 cfg->bits_per_lane_and_dclk_cycle); 238 return -EINVAL; 239 } 240 241 if (cfg->lanes != 4 && cfg->lanes != 3) { 242 dev_err(&phy->dev, "invalid data lanes(%u)\n", cfg->lanes); 243 return -EINVAL; 244 } 245 246 if (cfg->differential_clk_rate < MIN_CLKIN_FREQ || 247 cfg->differential_clk_rate > MAX_CLKIN_FREQ) { 248 dev_err(&phy->dev, "invalid differential clock rate(%lu)\n", 249 cfg->differential_clk_rate); 250 return -EINVAL; 251 } 252 253 mutex_lock(&priv->lock); 254 /* cache configuration set of our own for check */ 255 memcpy(&lvds_phy->cfg, cfg, sizeof(*cfg)); 256 257 if (cfg->is_slave) { 258 ret = mixel_lvds_phy_check_slave(phy); 259 if (ret) 260 dev_err(&phy->dev, "failed to check slave PHY: %d\n", ret); 261 } 262 mutex_unlock(&priv->lock); 263 264 return ret; 265 } 266 267 static const struct phy_ops mixel_lvds_phy_ops = { 268 .init = mixel_lvds_phy_init, 269 .power_on = mixel_lvds_phy_power_on, 270 .power_off = mixel_lvds_phy_power_off, 271 .configure = mixel_lvds_phy_configure, 272 .validate = mixel_lvds_phy_validate, 273 .owner = THIS_MODULE, 274 }; 275 276 static int mixel_lvds_phy_reset(struct device *dev) 277 { 278 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(dev); 279 int ret; 280 281 ret = pm_runtime_resume_and_get(dev); 282 if (ret < 0) { 283 dev_err(dev, "failed to get PM runtime: %d\n", ret); 284 return ret; 285 } 286 287 regmap_write(priv->regmap, PHY_CTRL, CTRL_RESET_VAL); 288 289 ret = pm_runtime_put(dev); 290 if (ret < 0) 291 dev_err(dev, "failed to put PM runtime: %d\n", ret); 292 293 return ret; 294 } 295 296 static struct phy *mixel_lvds_phy_xlate(struct device *dev, 297 const struct of_phandle_args *args) 298 { 299 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(dev); 300 unsigned int phy_id; 301 302 if (args->args_count != 1) { 303 dev_err(dev, 304 "invalid argument number(%d) for 'phys' property\n", 305 args->args_count); 306 return ERR_PTR(-EINVAL); 307 } 308 309 phy_id = args->args[0]; 310 311 if (phy_id >= PHY_NUM) { 312 dev_err(dev, "invalid PHY index(%d)\n", phy_id); 313 return ERR_PTR(-ENODEV); 314 } 315 316 return priv->phys[phy_id]->phy; 317 } 318 319 static int mixel_lvds_phy_probe(struct platform_device *pdev) 320 { 321 struct device *dev = &pdev->dev; 322 struct phy_provider *phy_provider; 323 struct mixel_lvds_phy_priv *priv; 324 struct mixel_lvds_phy *lvds_phy; 325 struct phy *phy; 326 int i; 327 int ret; 328 329 if (!dev->of_node) 330 return -ENODEV; 331 332 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 333 if (!priv) 334 return -ENOMEM; 335 336 priv->regmap = syscon_node_to_regmap(dev->of_node->parent); 337 if (IS_ERR(priv->regmap)) 338 return dev_err_probe(dev, PTR_ERR(priv->regmap), 339 "failed to get regmap\n"); 340 341 priv->phy_ref_clk = devm_clk_get(dev, NULL); 342 if (IS_ERR(priv->phy_ref_clk)) 343 return dev_err_probe(dev, PTR_ERR(priv->phy_ref_clk), 344 "failed to get PHY reference clock\n"); 345 346 mutex_init(&priv->lock); 347 348 dev_set_drvdata(dev, priv); 349 350 pm_runtime_enable(dev); 351 352 ret = mixel_lvds_phy_reset(dev); 353 if (ret) { 354 dev_err(dev, "failed to do POR reset: %d\n", ret); 355 return ret; 356 } 357 358 for (i = 0; i < PHY_NUM; i++) { 359 lvds_phy = devm_kzalloc(dev, sizeof(*lvds_phy), GFP_KERNEL); 360 if (!lvds_phy) { 361 ret = -ENOMEM; 362 goto err; 363 } 364 365 phy = devm_phy_create(dev, NULL, &mixel_lvds_phy_ops); 366 if (IS_ERR(phy)) { 367 ret = PTR_ERR(phy); 368 dev_err(dev, "failed to create PHY for channel%d: %d\n", 369 i, ret); 370 goto err; 371 } 372 373 lvds_phy->phy = phy; 374 lvds_phy->id = i; 375 priv->phys[i] = lvds_phy; 376 377 phy_set_drvdata(phy, lvds_phy); 378 } 379 380 phy_provider = devm_of_phy_provider_register(dev, mixel_lvds_phy_xlate); 381 if (IS_ERR(phy_provider)) { 382 ret = PTR_ERR(phy_provider); 383 dev_err(dev, "failed to register PHY provider: %d\n", ret); 384 goto err; 385 } 386 387 return 0; 388 err: 389 pm_runtime_disable(dev); 390 391 return ret; 392 } 393 394 static void mixel_lvds_phy_remove(struct platform_device *pdev) 395 { 396 pm_runtime_disable(&pdev->dev); 397 } 398 399 static int __maybe_unused mixel_lvds_phy_runtime_suspend(struct device *dev) 400 { 401 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(dev); 402 403 /* power down */ 404 mutex_lock(&priv->lock); 405 regmap_write(priv->regmap, PHY_CTRL + REG_SET, PD); 406 mutex_unlock(&priv->lock); 407 408 return 0; 409 } 410 411 static int __maybe_unused mixel_lvds_phy_runtime_resume(struct device *dev) 412 { 413 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(dev); 414 415 /* power up + control initialization */ 416 mutex_lock(&priv->lock); 417 regmap_update_bits(priv->regmap, PHY_CTRL, 418 CTRL_INIT_MASK | PD, CTRL_INIT_VAL); 419 mutex_unlock(&priv->lock); 420 421 return 0; 422 } 423 424 static const struct dev_pm_ops mixel_lvds_phy_pm_ops = { 425 SET_RUNTIME_PM_OPS(mixel_lvds_phy_runtime_suspend, 426 mixel_lvds_phy_runtime_resume, NULL) 427 }; 428 429 static const struct of_device_id mixel_lvds_phy_of_match[] = { 430 { .compatible = "fsl,imx8qm-lvds-phy" }, 431 { /* sentinel */ } 432 }; 433 MODULE_DEVICE_TABLE(of, mixel_lvds_phy_of_match); 434 435 static struct platform_driver mixel_lvds_phy_driver = { 436 .probe = mixel_lvds_phy_probe, 437 .remove_new = mixel_lvds_phy_remove, 438 .driver = { 439 .pm = &mixel_lvds_phy_pm_ops, 440 .name = "mixel-lvds-phy", 441 .of_match_table = mixel_lvds_phy_of_match, 442 } 443 }; 444 module_platform_driver(mixel_lvds_phy_driver); 445 446 MODULE_DESCRIPTION("Mixel LVDS PHY driver"); 447 MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); 448 MODULE_LICENSE("GPL"); 449