brintos

brintos / linux-shallow public Read only

0
0
Text · 14.1 KiB · f8e3054 Raw
618 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Intel Combo-PHY driver4 *5 * Copyright (C) 2019-2020 Intel Corporation.6 */7 8#include <linux/bitfield.h>9#include <linux/clk.h>10#include <linux/iopoll.h>11#include <linux/mfd/syscon.h>12#include <linux/module.h>13#include <linux/mutex.h>14#include <linux/of.h>15#include <linux/phy/phy.h>16#include <linux/platform_device.h>17#include <linux/regmap.h>18#include <linux/reset.h>19 20#include <dt-bindings/phy/phy.h>21 22#define PCIE_PHY_GEN_CTRL	0x0023#define PCIE_PHY_CLK_PAD	BIT(17)24 25#define PAD_DIS_CFG		0x17426 27#define PCS_XF_ATE_OVRD_IN_2	0x300828#define ADAPT_REQ_MSK		GENMASK(5, 4)29 30#define PCS_XF_RX_ADAPT_ACK	0x301031#define RX_ADAPT_ACK_BIT	BIT(0)32 33#define CR_ADDR(addr, lane)	(((addr) + (lane) * 0x100) << 2)34#define REG_COMBO_MODE(x)	((x) * 0x200)35#define REG_CLK_DISABLE(x)	((x) * 0x200 + 0x124)36 37#define COMBO_PHY_ID(x)		((x)->parent->id)38#define PHY_ID(x)		((x)->id)39 40#define CLK_100MHZ		10000000041#define CLK_156_25MHZ		15625000042 43static const unsigned long intel_iphy_clk_rates[] = {44	CLK_100MHZ, CLK_156_25MHZ, CLK_100MHZ,45};46 47enum {48	PHY_0,49	PHY_1,50	PHY_MAX_NUM51};52 53/*54 * Clock Register bit fields to enable clocks55 * for ComboPhy according to the mode.56 */57enum intel_phy_mode {58	PHY_PCIE_MODE = 0,59	PHY_XPCS_MODE,60	PHY_SATA_MODE,61};62 63/* ComboPhy mode Register values */64enum intel_combo_mode {65	PCIE0_PCIE1_MODE = 0,66	PCIE_DL_MODE,67	RXAUI_MODE,68	XPCS0_XPCS1_MODE,69	SATA0_SATA1_MODE,70};71 72enum aggregated_mode {73	PHY_SL_MODE,74	PHY_DL_MODE,75};76 77struct intel_combo_phy;78 79struct intel_cbphy_iphy {80	struct phy		*phy;81	struct intel_combo_phy	*parent;82	struct reset_control	*app_rst;83	u32			id;84};85 86struct intel_combo_phy {87	struct device		*dev;88	struct clk		*core_clk;89	unsigned long		clk_rate;90	void __iomem		*app_base;91	void __iomem		*cr_base;92	struct regmap		*syscfg;93	struct regmap		*hsiocfg;94	u32			id;95	u32			bid;96	struct reset_control	*phy_rst;97	struct reset_control	*core_rst;98	struct intel_cbphy_iphy	iphy[PHY_MAX_NUM];99	enum intel_phy_mode	phy_mode;100	enum aggregated_mode	aggr_mode;101	u32			init_cnt;102	struct mutex		lock;103};104 105static int intel_cbphy_iphy_enable(struct intel_cbphy_iphy *iphy, bool set)106{107	struct intel_combo_phy *cbphy = iphy->parent;108	u32 mask = BIT(cbphy->phy_mode * 2 + iphy->id);109	u32 val;110 111	/* Register: 0 is enable, 1 is disable */112	val = set ? 0 : mask;113 114	return regmap_update_bits(cbphy->hsiocfg, REG_CLK_DISABLE(cbphy->bid),115				  mask, val);116}117 118static int intel_cbphy_pcie_refclk_cfg(struct intel_cbphy_iphy *iphy, bool set)119{120	struct intel_combo_phy *cbphy = iphy->parent;121	u32 mask = BIT(cbphy->id * 2 + iphy->id);122	u32 val;123 124	/* Register: 0 is enable, 1 is disable */125	val = set ? 0 : mask;126 127	return regmap_update_bits(cbphy->syscfg, PAD_DIS_CFG, mask, val);128}129 130static inline void combo_phy_w32_off_mask(void __iomem *base, unsigned int reg,131					  u32 mask, u32 val)132{133	u32 reg_val;134 135	reg_val = readl(base + reg);136	reg_val &= ~mask;137	reg_val |= val;138	writel(reg_val, base + reg);139}140 141static int intel_cbphy_iphy_cfg(struct intel_cbphy_iphy *iphy,142				int (*phy_cfg)(struct intel_cbphy_iphy *))143{144	struct intel_combo_phy *cbphy = iphy->parent;145	int ret;146 147	ret = phy_cfg(iphy);148	if (ret)149		return ret;150 151	if (cbphy->aggr_mode != PHY_DL_MODE)152		return 0;153 154	return phy_cfg(&cbphy->iphy[PHY_1]);155}156 157static int intel_cbphy_pcie_en_pad_refclk(struct intel_cbphy_iphy *iphy)158{159	struct intel_combo_phy *cbphy = iphy->parent;160	int ret;161 162	ret = intel_cbphy_pcie_refclk_cfg(iphy, true);163	if (ret) {164		dev_err(cbphy->dev, "Failed to enable PCIe pad refclk\n");165		return ret;166	}167 168	if (cbphy->init_cnt)169		return 0;170 171	combo_phy_w32_off_mask(cbphy->app_base, PCIE_PHY_GEN_CTRL,172			       PCIE_PHY_CLK_PAD, FIELD_PREP(PCIE_PHY_CLK_PAD, 0));173 174	/* Delay for stable clock PLL */175	usleep_range(50, 100);176 177	return 0;178}179 180static int intel_cbphy_pcie_dis_pad_refclk(struct intel_cbphy_iphy *iphy)181{182	struct intel_combo_phy *cbphy = iphy->parent;183	int ret;184 185	ret = intel_cbphy_pcie_refclk_cfg(iphy, false);186	if (ret) {187		dev_err(cbphy->dev, "Failed to disable PCIe pad refclk\n");188		return ret;189	}190 191	if (cbphy->init_cnt)192		return 0;193 194	combo_phy_w32_off_mask(cbphy->app_base, PCIE_PHY_GEN_CTRL,195			       PCIE_PHY_CLK_PAD, FIELD_PREP(PCIE_PHY_CLK_PAD, 1));196 197	return 0;198}199 200static int intel_cbphy_set_mode(struct intel_combo_phy *cbphy)201{202	enum intel_combo_mode cb_mode;203	enum aggregated_mode aggr = cbphy->aggr_mode;204	struct device *dev = cbphy->dev;205	enum intel_phy_mode mode;206	int ret;207 208	mode = cbphy->phy_mode;209 210	switch (mode) {211	case PHY_PCIE_MODE:212		cb_mode = (aggr == PHY_DL_MODE) ? PCIE_DL_MODE : PCIE0_PCIE1_MODE;213		break;214 215	case PHY_XPCS_MODE:216		cb_mode = (aggr == PHY_DL_MODE) ? RXAUI_MODE : XPCS0_XPCS1_MODE;217		break;218 219	case PHY_SATA_MODE:220		if (aggr == PHY_DL_MODE) {221			dev_err(dev, "Mode:%u not support dual lane!\n", mode);222			return -EINVAL;223		}224 225		cb_mode = SATA0_SATA1_MODE;226		break;227	default:228		return -EINVAL;229	}230 231	ret = regmap_write(cbphy->hsiocfg, REG_COMBO_MODE(cbphy->bid), cb_mode);232	if (ret)233		dev_err(dev, "Failed to set ComboPhy mode: %d\n", ret);234 235	return ret;236}237 238static void intel_cbphy_rst_assert(struct intel_combo_phy *cbphy)239{240	reset_control_assert(cbphy->core_rst);241	reset_control_assert(cbphy->phy_rst);242}243 244static void intel_cbphy_rst_deassert(struct intel_combo_phy *cbphy)245{246	reset_control_deassert(cbphy->core_rst);247	reset_control_deassert(cbphy->phy_rst);248	/* Delay to ensure reset process is done */249	usleep_range(10, 20);250}251 252static int intel_cbphy_iphy_power_on(struct intel_cbphy_iphy *iphy)253{254	struct intel_combo_phy *cbphy = iphy->parent;255	int ret;256 257	if (!cbphy->init_cnt) {258		ret = clk_prepare_enable(cbphy->core_clk);259		if (ret) {260			dev_err(cbphy->dev, "Clock enable failed!\n");261			return ret;262		}263 264		ret = clk_set_rate(cbphy->core_clk, cbphy->clk_rate);265		if (ret) {266			dev_err(cbphy->dev, "Clock freq set to %lu failed!\n",267				cbphy->clk_rate);268			goto clk_err;269		}270 271		intel_cbphy_rst_assert(cbphy);272		intel_cbphy_rst_deassert(cbphy);273		ret = intel_cbphy_set_mode(cbphy);274		if (ret)275			goto clk_err;276	}277 278	ret = intel_cbphy_iphy_enable(iphy, true);279	if (ret) {280		dev_err(cbphy->dev, "Failed enabling PHY core\n");281		goto clk_err;282	}283 284	ret = reset_control_deassert(iphy->app_rst);285	if (ret) {286		dev_err(cbphy->dev, "PHY(%u:%u) reset deassert failed!\n",287			COMBO_PHY_ID(iphy), PHY_ID(iphy));288		goto clk_err;289	}290 291	/* Delay to ensure reset process is done */292	udelay(1);293 294	return 0;295 296clk_err:297	clk_disable_unprepare(cbphy->core_clk);298 299	return ret;300}301 302static int intel_cbphy_iphy_power_off(struct intel_cbphy_iphy *iphy)303{304	struct intel_combo_phy *cbphy = iphy->parent;305	int ret;306 307	ret = reset_control_assert(iphy->app_rst);308	if (ret) {309		dev_err(cbphy->dev, "PHY(%u:%u) reset assert failed!\n",310			COMBO_PHY_ID(iphy), PHY_ID(iphy));311		return ret;312	}313 314	ret = intel_cbphy_iphy_enable(iphy, false);315	if (ret) {316		dev_err(cbphy->dev, "Failed disabling PHY core\n");317		return ret;318	}319 320	if (cbphy->init_cnt)321		return 0;322 323	clk_disable_unprepare(cbphy->core_clk);324	intel_cbphy_rst_assert(cbphy);325 326	return 0;327}328 329static int intel_cbphy_init(struct phy *phy)330{331	struct intel_cbphy_iphy *iphy = phy_get_drvdata(phy);332	struct intel_combo_phy *cbphy = iphy->parent;333	int ret;334 335	mutex_lock(&cbphy->lock);336	ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_iphy_power_on);337	if (ret)338		goto err;339 340	if (cbphy->phy_mode == PHY_PCIE_MODE) {341		ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_pcie_en_pad_refclk);342		if (ret)343			goto err;344	}345 346	cbphy->init_cnt++;347 348err:349	mutex_unlock(&cbphy->lock);350 351	return ret;352}353 354static int intel_cbphy_exit(struct phy *phy)355{356	struct intel_cbphy_iphy *iphy = phy_get_drvdata(phy);357	struct intel_combo_phy *cbphy = iphy->parent;358	int ret;359 360	mutex_lock(&cbphy->lock);361	cbphy->init_cnt--;362	if (cbphy->phy_mode == PHY_PCIE_MODE) {363		ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_pcie_dis_pad_refclk);364		if (ret)365			goto err;366	}367 368	ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_iphy_power_off);369 370err:371	mutex_unlock(&cbphy->lock);372 373	return ret;374}375 376static int intel_cbphy_calibrate(struct phy *phy)377{378	struct intel_cbphy_iphy *iphy = phy_get_drvdata(phy);379	struct intel_combo_phy *cbphy = iphy->parent;380	void __iomem *cr_base = cbphy->cr_base;381	int val, ret, id;382 383	if (cbphy->phy_mode != PHY_XPCS_MODE)384		return 0;385 386	id = PHY_ID(iphy);387 388	/* trigger auto RX adaptation */389	combo_phy_w32_off_mask(cr_base, CR_ADDR(PCS_XF_ATE_OVRD_IN_2, id),390			       ADAPT_REQ_MSK, FIELD_PREP(ADAPT_REQ_MSK, 3));391	/* Wait RX adaptation to finish */392	ret = readl_poll_timeout(cr_base + CR_ADDR(PCS_XF_RX_ADAPT_ACK, id),393				 val, val & RX_ADAPT_ACK_BIT, 10, 5000);394	if (ret)395		dev_err(cbphy->dev, "RX Adaptation failed!\n");396	else397		dev_dbg(cbphy->dev, "RX Adaptation success!\n");398 399	/* Stop RX adaptation */400	combo_phy_w32_off_mask(cr_base, CR_ADDR(PCS_XF_ATE_OVRD_IN_2, id),401			       ADAPT_REQ_MSK, FIELD_PREP(ADAPT_REQ_MSK, 0));402 403	return ret;404}405 406static int intel_cbphy_fwnode_parse(struct intel_combo_phy *cbphy)407{408	struct device *dev = cbphy->dev;409	struct platform_device *pdev = to_platform_device(dev);410	struct fwnode_handle *fwnode = dev_fwnode(dev);411	struct fwnode_reference_args ref;412	int ret;413	u32 val;414 415	cbphy->core_clk = devm_clk_get(dev, NULL);416	if (IS_ERR(cbphy->core_clk))417		return dev_err_probe(dev, PTR_ERR(cbphy->core_clk),418				     "Get clk failed!\n");419 420	cbphy->core_rst = devm_reset_control_get_optional(dev, "core");421	if (IS_ERR(cbphy->core_rst))422		return dev_err_probe(dev, PTR_ERR(cbphy->core_rst),423				     "Get core reset control err!\n");424 425	cbphy->phy_rst = devm_reset_control_get_optional(dev, "phy");426	if (IS_ERR(cbphy->phy_rst))427		return dev_err_probe(dev, PTR_ERR(cbphy->phy_rst),428				     "Get PHY reset control err!\n");429 430	cbphy->iphy[0].app_rst = devm_reset_control_get_optional(dev, "iphy0");431	if (IS_ERR(cbphy->iphy[0].app_rst))432		return dev_err_probe(dev, PTR_ERR(cbphy->iphy[0].app_rst),433				     "Get phy0 reset control err!\n");434 435	cbphy->iphy[1].app_rst = devm_reset_control_get_optional(dev, "iphy1");436	if (IS_ERR(cbphy->iphy[1].app_rst))437		return dev_err_probe(dev, PTR_ERR(cbphy->iphy[1].app_rst),438				     "Get phy1 reset control err!\n");439 440	cbphy->app_base = devm_platform_ioremap_resource_byname(pdev, "app");441	if (IS_ERR(cbphy->app_base))442		return PTR_ERR(cbphy->app_base);443 444	cbphy->cr_base = devm_platform_ioremap_resource_byname(pdev, "core");445	if (IS_ERR(cbphy->cr_base))446		return PTR_ERR(cbphy->cr_base);447 448	/*449	 * syscfg and hsiocfg variables stores the handle of the registers set450	 * in which ComboPhy subsystem specific registers are subset. Using451	 * Register map framework to access the registers set.452	 */453	ret = fwnode_property_get_reference_args(fwnode, "intel,syscfg", NULL,454						 1, 0, &ref);455	if (ret < 0)456		return ret;457 458	cbphy->id = ref.args[0];459	cbphy->syscfg = device_node_to_regmap(to_of_node(ref.fwnode));460	fwnode_handle_put(ref.fwnode);461 462	ret = fwnode_property_get_reference_args(fwnode, "intel,hsio", NULL, 1,463						 0, &ref);464	if (ret < 0)465		return ret;466 467	cbphy->bid = ref.args[0];468	cbphy->hsiocfg = device_node_to_regmap(to_of_node(ref.fwnode));469	fwnode_handle_put(ref.fwnode);470 471	ret = fwnode_property_read_u32_array(fwnode, "intel,phy-mode", &val, 1);472	if (ret)473		return ret;474 475	switch (val) {476	case PHY_TYPE_PCIE:477		cbphy->phy_mode = PHY_PCIE_MODE;478		break;479 480	case PHY_TYPE_SATA:481		cbphy->phy_mode = PHY_SATA_MODE;482		break;483 484	case PHY_TYPE_XPCS:485		cbphy->phy_mode = PHY_XPCS_MODE;486		break;487 488	default:489		dev_err(dev, "Invalid PHY mode: %u\n", val);490		return -EINVAL;491	}492 493	cbphy->clk_rate = intel_iphy_clk_rates[cbphy->phy_mode];494 495	if (fwnode_property_present(fwnode, "intel,aggregation"))496		cbphy->aggr_mode = PHY_DL_MODE;497	else498		cbphy->aggr_mode = PHY_SL_MODE;499 500	return 0;501}502 503static const struct phy_ops intel_cbphy_ops = {504	.init		= intel_cbphy_init,505	.exit		= intel_cbphy_exit,506	.calibrate	= intel_cbphy_calibrate,507	.owner		= THIS_MODULE,508};509 510static struct phy *intel_cbphy_xlate(struct device *dev,511				     const struct of_phandle_args *args)512{513	struct intel_combo_phy *cbphy = dev_get_drvdata(dev);514	u32 iphy_id;515 516	if (args->args_count < 1) {517		dev_err(dev, "Invalid number of arguments\n");518		return ERR_PTR(-EINVAL);519	}520 521	iphy_id = args->args[0];522	if (iphy_id >= PHY_MAX_NUM) {523		dev_err(dev, "Invalid phy instance %d\n", iphy_id);524		return ERR_PTR(-EINVAL);525	}526 527	if (cbphy->aggr_mode == PHY_DL_MODE && iphy_id == PHY_1) {528		dev_err(dev, "Invalid. ComboPhy is in Dual lane mode %d\n", iphy_id);529		return ERR_PTR(-EINVAL);530	}531 532	return cbphy->iphy[iphy_id].phy;533}534 535static int intel_cbphy_create(struct intel_combo_phy *cbphy)536{537	struct phy_provider *phy_provider;538	struct device *dev = cbphy->dev;539	struct intel_cbphy_iphy *iphy;540	int i;541 542	for (i = 0; i < PHY_MAX_NUM; i++) {543		iphy = &cbphy->iphy[i];544		iphy->parent = cbphy;545		iphy->id = i;546 547		/* In dual lane mode skip phy creation for the second phy */548		if (cbphy->aggr_mode == PHY_DL_MODE && iphy->id == PHY_1)549			continue;550 551		iphy->phy = devm_phy_create(dev, NULL, &intel_cbphy_ops);552		if (IS_ERR(iphy->phy)) {553			dev_err(dev, "PHY[%u:%u]: create PHY instance failed!\n",554				COMBO_PHY_ID(iphy), PHY_ID(iphy));555 556			return PTR_ERR(iphy->phy);557		}558 559		phy_set_drvdata(iphy->phy, iphy);560	}561 562	dev_set_drvdata(dev, cbphy);563	phy_provider = devm_of_phy_provider_register(dev, intel_cbphy_xlate);564	if (IS_ERR(phy_provider))565		dev_err(dev, "Register PHY provider failed!\n");566 567	return PTR_ERR_OR_ZERO(phy_provider);568}569 570static int intel_cbphy_probe(struct platform_device *pdev)571{572	struct device *dev = &pdev->dev;573	struct intel_combo_phy *cbphy;574	int ret;575 576	cbphy = devm_kzalloc(dev, sizeof(*cbphy), GFP_KERNEL);577	if (!cbphy)578		return -ENOMEM;579 580	cbphy->dev = dev;581	cbphy->init_cnt = 0;582	mutex_init(&cbphy->lock);583	ret = intel_cbphy_fwnode_parse(cbphy);584	if (ret)585		return ret;586 587	platform_set_drvdata(pdev, cbphy);588 589	return intel_cbphy_create(cbphy);590}591 592static void intel_cbphy_remove(struct platform_device *pdev)593{594	struct intel_combo_phy *cbphy = platform_get_drvdata(pdev);595 596	intel_cbphy_rst_assert(cbphy);597	clk_disable_unprepare(cbphy->core_clk);598}599 600static const struct of_device_id of_intel_cbphy_match[] = {601	{ .compatible = "intel,combo-phy" },602	{ .compatible = "intel,combophy-lgm" },603	{}604};605 606static struct platform_driver intel_cbphy_driver = {607	.probe = intel_cbphy_probe,608	.remove_new = intel_cbphy_remove,609	.driver = {610		.name = "intel-combo-phy",611		.of_match_table = of_intel_cbphy_match,612	}613};614 615module_platform_driver(intel_cbphy_driver);616 617MODULE_DESCRIPTION("Intel Combo-phy driver");618