663 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform4 *5 * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd.6 * http://www.huawei.com7 *8 * Authors: Yu Chen <chenyu56@huawei.com>9 */10 11#include <linux/bitfield.h>12#include <linux/clk.h>13#include <linux/kernel.h>14#include <linux/mfd/syscon.h>15#include <linux/module.h>16#include <linux/of.h>17#include <linux/phy/phy.h>18#include <linux/platform_device.h>19#include <linux/regmap.h>20 21#define SCTRL_SCDEEPSLEEPED (0x0)22#define USB_CLK_SELECTED BIT(20)23 24#define PERI_CRG_PEREN0 (0x00)25#define PERI_CRG_PERDIS0 (0x04)26#define PERI_CRG_PEREN4 (0x40)27#define PERI_CRG_PERDIS4 (0x44)28#define PERI_CRG_PERRSTEN4 (0x90)29#define PERI_CRG_PERRSTDIS4 (0x94)30#define PERI_CRG_ISODIS (0x148)31#define PERI_CRG_PEREN6 (0x410)32#define PERI_CRG_PERDIS6 (0x414)33 34#define USB_REFCLK_ISO_EN BIT(25)35 36#define GT_CLK_USB2PHY_REF BIT(19)37 38#define PCTRL_PERI_CTRL3 (0x10)39#define PCTRL_PERI_CTRL3_MSK_START (16)40#define USB_TCXO_EN BIT(1)41 42#define PCTRL_PERI_CTRL24 (0x64)43#define SC_CLK_USB3PHY_3MUX1_SEL BIT(25)44 45#define USB3OTG_CTRL0 (0x00)46#define USB3OTG_CTRL3 (0x0c)47#define USB3OTG_CTRL4 (0x10)48#define USB3OTG_CTRL5 (0x14)49#define USB3OTG_CTRL7 (0x1c)50#define USB_MISC_CFG50 (0x50)51#define USB_MISC_CFG54 (0x54)52#define USB_MISC_CFG58 (0x58)53#define USB_MISC_CFG5C (0x5c)54#define USB_MISC_CFGA0 (0xa0)55#define TCA_CLK_RST (0x200)56#define TCA_INTR_EN (0x204)57#define TCA_INTR_STS (0x208)58#define TCA_GCFG (0x210)59#define TCA_TCPC (0x214)60#define TCA_SYSMODE_CFG (0x218)61#define TCA_VBUS_CTRL (0x240)62 63#define CTRL0_USB3_VBUSVLD BIT(7)64#define CTRL0_USB3_VBUSVLD_SEL BIT(6)65 66#define CTRL3_USB2_VBUSVLDEXT0 BIT(6)67#define CTRL3_USB2_VBUSVLDEXTSEL0 BIT(5)68 69#define CTRL5_USB2_SIDDQ BIT(0)70 71#define CTRL7_USB2_REFCLKSEL_MASK GENMASK(4, 3)72#define CTRL7_USB2_REFCLKSEL_ABB (BIT(4) | BIT(3))73#define CTRL7_USB2_REFCLKSEL_PAD BIT(4)74 75#define CFG50_USB3_PHY_TEST_POWERDOWN BIT(23)76 77#define CFG54_USB31PHY_CR_ADDR_MASK GENMASK(31, 16)78 79#define CFG54_USB3PHY_REF_USE_PAD BIT(12)80#define CFG54_PHY0_PMA_PWR_STABLE BIT(11)81#define CFG54_PHY0_PCS_PWR_STABLE BIT(9)82#define CFG54_USB31PHY_CR_ACK BIT(7)83#define CFG54_USB31PHY_CR_WR_EN BIT(5)84#define CFG54_USB31PHY_CR_SEL BIT(4)85#define CFG54_USB31PHY_CR_RD_EN BIT(3)86#define CFG54_USB31PHY_CR_CLK BIT(2)87#define CFG54_USB3_PHY0_ANA_PWR_EN BIT(1)88 89#define CFG58_USB31PHY_CR_DATA_MASK GENMASK(31, 16)90 91#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN BIT(1)92 93#define CFGA0_VAUX_RESET BIT(9)94#define CFGA0_USB31C_RESET BIT(8)95#define CFGA0_USB2PHY_REFCLK_SELECT BIT(4)96#define CFGA0_USB3PHY_RESET BIT(1)97#define CFGA0_USB2PHY_POR BIT(0)98 99#define INTR_EN_XA_TIMEOUT_EVT_EN BIT(1)100#define INTR_EN_XA_ACK_EVT_EN BIT(0)101 102#define CLK_RST_TCA_REF_CLK_EN BIT(1)103#define CLK_RST_SUSPEND_CLK_EN BIT(0)104 105#define GCFG_ROLE_HSTDEV BIT(4)106#define GCFG_OP_MODE GENMASK(1, 0)107#define GCFG_OP_MODE_CTRL_SYNC_MODE BIT(0)108 109#define TCPC_VALID BIT(4)110#define TCPC_LOW_POWER_EN BIT(3)111#define TCPC_MUX_CONTROL_MASK GENMASK(1, 0)112#define TCPC_MUX_CONTROL_USB31 BIT(0)113 114#define SYSMODE_CFG_TYPEC_DISABLE BIT(3)115 116#define VBUS_CTRL_POWERPRESENT_OVERRD GENMASK(3, 2)117#define VBUS_CTRL_VBUSVALID_OVERRD GENMASK(1, 0)118 119#define KIRIN970_USB_DEFAULT_PHY_PARAM (0xfdfee4)120#define KIRIN970_USB_DEFAULT_PHY_VBOOST (0x5)121 122#define TX_VBOOST_LVL_REG (0xf)123#define TX_VBOOST_LVL_START (6)124#define TX_VBOOST_LVL_ENABLE BIT(9)125 126struct hi3670_priv {127 struct device *dev;128 struct regmap *peri_crg;129 struct regmap *pctrl;130 struct regmap *sctrl;131 struct regmap *usb31misc;132 133 u32 eye_diagram_param;134 u32 tx_vboost_lvl;135 136 u32 peri_crg_offset;137 u32 pctrl_offset;138 u32 usb31misc_offset;139};140 141static int hi3670_phy_cr_clk(struct regmap *usb31misc)142{143 int ret;144 145 /* Clock up */146 ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,147 CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK);148 if (ret)149 return ret;150 151 /* Clock down */152 return regmap_update_bits(usb31misc, USB_MISC_CFG54,153 CFG54_USB31PHY_CR_CLK, 0);154}155 156static int hi3670_phy_cr_set_sel(struct regmap *usb31misc)157{158 return regmap_update_bits(usb31misc, USB_MISC_CFG54,159 CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL);160}161 162static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction)163{164 int ret, reg;165 166 if (direction)167 reg = CFG54_USB31PHY_CR_WR_EN;168 else169 reg = CFG54_USB31PHY_CR_RD_EN;170 171 ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, reg, reg);172 173 if (ret)174 return ret;175 176 ret = hi3670_phy_cr_clk(usb31misc);177 if (ret)178 return ret;179 180 return regmap_update_bits(usb31misc, USB_MISC_CFG54,181 CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0);182}183 184static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc)185{186 u32 reg;187 int retry = 10;188 int ret;189 190 while (retry-- > 0) {191 ret = regmap_read(usb31misc, USB_MISC_CFG54, ®);192 if (ret)193 return ret;194 if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK)195 return 0;196 197 ret = hi3670_phy_cr_clk(usb31misc);198 if (ret)199 return ret;200 201 usleep_range(10, 20);202 }203 204 return -ETIMEDOUT;205}206 207static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)208{209 u32 reg;210 int ret;211 212 ret = regmap_read(usb31misc, USB_MISC_CFG54, ®);213 if (ret)214 return ret;215 216 reg = FIELD_PREP(CFG54_USB31PHY_CR_ADDR_MASK, addr);217 218 return regmap_update_bits(usb31misc, USB_MISC_CFG54,219 CFG54_USB31PHY_CR_ADDR_MASK, reg);220}221 222static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val)223{224 int reg, i, ret;225 226 for (i = 0; i < 100; i++) {227 ret = hi3670_phy_cr_clk(usb31misc);228 if (ret)229 return ret;230 }231 232 ret = hi3670_phy_cr_set_sel(usb31misc);233 if (ret)234 return ret;235 236 ret = hi3670_phy_cr_set_addr(usb31misc, addr);237 if (ret)238 return ret;239 240 ret = hi3670_phy_cr_start(usb31misc, 0);241 if (ret)242 return ret;243 244 ret = hi3670_phy_cr_wait_ack(usb31misc);245 if (ret)246 return ret;247 248 ret = regmap_read(usb31misc, USB_MISC_CFG58, ®);249 if (ret)250 return ret;251 252 *val = FIELD_GET(CFG58_USB31PHY_CR_DATA_MASK, reg);253 254 return 0;255}256 257static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val)258{259 int i;260 int ret;261 262 for (i = 0; i < 100; i++) {263 ret = hi3670_phy_cr_clk(usb31misc);264 if (ret)265 return ret;266 }267 268 ret = hi3670_phy_cr_set_sel(usb31misc);269 if (ret)270 return ret;271 272 ret = hi3670_phy_cr_set_addr(usb31misc, addr);273 if (ret)274 return ret;275 276 ret = regmap_write(usb31misc, USB_MISC_CFG58,277 FIELD_PREP(CFG58_USB31PHY_CR_DATA_MASK, val));278 if (ret)279 return ret;280 281 ret = hi3670_phy_cr_start(usb31misc, 1);282 if (ret)283 return ret;284 285 return hi3670_phy_cr_wait_ack(usb31misc);286}287 288static int hi3670_phy_set_params(struct hi3670_priv *priv)289{290 u32 reg;291 int ret;292 int retry = 3;293 294 ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4,295 priv->eye_diagram_param);296 if (ret) {297 dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n");298 return ret;299 }300 301 while (retry-- > 0) {302 ret = hi3670_phy_cr_read(priv->usb31misc,303 TX_VBOOST_LVL_REG, ®);304 if (!ret)305 break;306 307 if (ret != -ETIMEDOUT) {308 dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n");309 return ret;310 }311 }312 if (ret)313 return ret;314 315 reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START));316 ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg);317 if (ret)318 dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n");319 320 return ret;321}322 323static bool hi3670_is_abbclk_selected(struct hi3670_priv *priv)324{325 u32 reg;326 327 if (!priv->sctrl) {328 dev_err(priv->dev, "priv->sctrl is null!\n");329 return false;330 }331 332 if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, ®)) {333 dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n");334 return false;335 }336 337 if ((reg & USB_CLK_SELECTED) == 0)338 return false;339 340 return true;341}342 343static int hi3670_config_phy_clock(struct hi3670_priv *priv)344{345 u32 val, mask;346 int ret;347 348 if (!hi3670_is_abbclk_selected(priv)) {349 /* usb refclk iso disable */350 ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS,351 USB_REFCLK_ISO_EN);352 if (ret)353 goto out;354 355 /* enable usb_tcxo_en */356 ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,357 USB_TCXO_EN |358 (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START));359 360 /* select usbphy clk from abb */361 mask = SC_CLK_USB3PHY_3MUX1_SEL;362 ret = regmap_update_bits(priv->pctrl,363 PCTRL_PERI_CTRL24, mask, 0);364 if (ret)365 goto out;366 367 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,368 CFGA0_USB2PHY_REFCLK_SELECT, 0);369 if (ret)370 goto out;371 372 ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);373 if (ret)374 goto out;375 val &= ~CTRL7_USB2_REFCLKSEL_MASK;376 val |= CTRL7_USB2_REFCLKSEL_ABB;377 ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);378 if (ret)379 goto out;380 381 return 0;382 }383 384 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,385 CFG54_USB3PHY_REF_USE_PAD,386 CFG54_USB3PHY_REF_USE_PAD);387 if (ret)388 goto out;389 390 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,391 CFGA0_USB2PHY_REFCLK_SELECT,392 CFGA0_USB2PHY_REFCLK_SELECT);393 if (ret)394 goto out;395 396 ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);397 if (ret)398 goto out;399 val &= ~CTRL7_USB2_REFCLKSEL_MASK;400 val |= CTRL7_USB2_REFCLKSEL_PAD;401 ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);402 if (ret)403 goto out;404 405 ret = regmap_write(priv->peri_crg,406 PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF);407 if (ret)408 goto out;409 410 return 0;411out:412 dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);413 return ret;414}415 416static int hi3670_config_tca(struct hi3670_priv *priv)417{418 u32 val, mask;419 int ret;420 421 ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff);422 if (ret)423 goto out;424 425 ret = regmap_write(priv->usb31misc, TCA_INTR_EN,426 INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN);427 if (ret)428 goto out;429 430 mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN;431 ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0);432 if (ret)433 goto out;434 435 ret = regmap_update_bits(priv->usb31misc, TCA_GCFG,436 GCFG_ROLE_HSTDEV | GCFG_OP_MODE,437 GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE);438 if (ret)439 goto out;440 441 ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG,442 SYSMODE_CFG_TYPEC_DISABLE, 0);443 if (ret)444 goto out;445 446 ret = regmap_read(priv->usb31misc, TCA_TCPC, &val);447 if (ret)448 goto out;449 val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK);450 val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31);451 ret = regmap_write(priv->usb31misc, TCA_TCPC, val);452 if (ret)453 goto out;454 455 ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL,456 VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD);457 if (ret)458 goto out;459 460 return 0;461out:462 dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);463 return ret;464}465 466static int hi3670_phy_init(struct phy *phy)467{468 struct hi3670_priv *priv = phy_get_drvdata(phy);469 u32 val;470 int ret;471 472 /* assert controller */473 val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET |474 CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;475 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0);476 if (ret)477 goto out;478 479 ret = hi3670_config_phy_clock(priv);480 if (ret)481 goto out;482 483 /* Exit from IDDQ mode */484 ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5,485 CTRL5_USB2_SIDDQ, 0);486 if (ret)487 goto out;488 489 /* Release USB31 PHY out of TestPowerDown mode */490 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50,491 CFG50_USB3_PHY_TEST_POWERDOWN, 0);492 if (ret)493 goto out;494 495 /* Deassert phy */496 val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;497 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);498 if (ret)499 goto out;500 501 usleep_range(100, 120);502 503 /* Tell the PHY power is stable */504 val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE |505 CFG54_PHY0_PMA_PWR_STABLE;506 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,507 val, val);508 if (ret)509 goto out;510 511 ret = hi3670_config_tca(priv);512 if (ret)513 goto out;514 515 /* Enable SSC */516 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C,517 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN,518 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN);519 if (ret)520 goto out;521 522 /* Deassert controller */523 val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET;524 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);525 if (ret)526 goto out;527 528 usleep_range(100, 120);529 530 /* Set fake vbus valid signal */531 val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL;532 ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val);533 if (ret)534 goto out;535 536 val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0;537 ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val);538 if (ret)539 goto out;540 541 usleep_range(100, 120);542 543 ret = hi3670_phy_set_params(priv);544 if (ret)545 goto out;546 547 return 0;548out:549 dev_err(priv->dev, "failed to init phy ret: %d\n", ret);550 return ret;551}552 553static int hi3670_phy_exit(struct phy *phy)554{555 struct hi3670_priv *priv = phy_get_drvdata(phy);556 u32 mask;557 int ret;558 559 /* Assert phy */560 mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;561 ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0);562 if (ret)563 goto out;564 565 if (!hi3670_is_abbclk_selected(priv)) {566 /* disable usb_tcxo_en */567 ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,568 USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);569 } else {570 ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6,571 GT_CLK_USB2PHY_REF);572 if (ret)573 goto out;574 }575 576 return 0;577out:578 dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);579 return ret;580}581 582static const struct phy_ops hi3670_phy_ops = {583 .init = hi3670_phy_init,584 .exit = hi3670_phy_exit,585 .owner = THIS_MODULE,586};587 588static int hi3670_phy_probe(struct platform_device *pdev)589{590 struct phy_provider *phy_provider;591 struct device *dev = &pdev->dev;592 struct phy *phy;593 struct hi3670_priv *priv;594 595 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);596 if (!priv)597 return -ENOMEM;598 599 priv->dev = dev;600 priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node,601 "hisilicon,pericrg-syscon");602 if (IS_ERR(priv->peri_crg)) {603 dev_err(dev, "no hisilicon,pericrg-syscon\n");604 return PTR_ERR(priv->peri_crg);605 }606 607 priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node,608 "hisilicon,pctrl-syscon");609 if (IS_ERR(priv->pctrl)) {610 dev_err(dev, "no hisilicon,pctrl-syscon\n");611 return PTR_ERR(priv->pctrl);612 }613 614 priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node,615 "hisilicon,sctrl-syscon");616 if (IS_ERR(priv->sctrl)) {617 dev_err(dev, "no hisilicon,sctrl-syscon\n");618 return PTR_ERR(priv->sctrl);619 }620 621 /* node of hi3670 phy is a sub-node of usb3_otg_bc */622 priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node);623 if (IS_ERR(priv->usb31misc)) {624 dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");625 return PTR_ERR(priv->usb31misc);626 }627 628 if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param",629 &priv->eye_diagram_param))630 priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM;631 632 if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl",633 &priv->tx_vboost_lvl))634 priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST;635 636 phy = devm_phy_create(dev, NULL, &hi3670_phy_ops);637 if (IS_ERR(phy))638 return PTR_ERR(phy);639 640 phy_set_drvdata(phy, priv);641 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);642 return PTR_ERR_OR_ZERO(phy_provider);643}644 645static const struct of_device_id hi3670_phy_of_match[] = {646 { .compatible = "hisilicon,hi3670-usb-phy" },647 { },648};649MODULE_DEVICE_TABLE(of, hi3670_phy_of_match);650 651static struct platform_driver hi3670_phy_driver = {652 .probe = hi3670_phy_probe,653 .driver = {654 .name = "hi3670-usb-phy",655 .of_match_table = hi3670_phy_of_match,656 }657};658module_platform_driver(hi3670_phy_driver);659 660MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");661MODULE_LICENSE("GPL v2");662MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver");663