brintos

brintos / linux-shallow public Read only

0
0
Text · 15.3 KiB · 40d3cf1 Raw
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, &reg);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, &reg);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, &reg);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, &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, &reg)) {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