brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 11a2bb9 Raw
333 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.4 * Copyright (c) 2019, Linaro Ltd.5 */6 7#include <linux/clk-provider.h>8#include <linux/clk.h>9#include <linux/iopoll.h>10#include <linux/module.h>11#include <linux/phy/phy.h>12#include <linux/platform_device.h>13#include <linux/reset.h>14#include <linux/slab.h>15 16#include <dt-bindings/phy/phy.h>17 18#define PCIE20_PARF_PHY_STTS         0x3c19#define PCIE2_PHY_RESET_CTRL         0x4420#define PCIE20_PARF_PHY_REFCLK_CTRL2 0xa021#define PCIE20_PARF_PHY_REFCLK_CTRL3 0xa422#define PCIE20_PARF_PCS_SWING_CTRL1  0x8823#define PCIE20_PARF_PCS_SWING_CTRL2  0x8c24#define PCIE20_PARF_PCS_DEEMPH1      0x7425#define PCIE20_PARF_PCS_DEEMPH2      0x7826#define PCIE20_PARF_PCS_DEEMPH3      0x7c27#define PCIE20_PARF_CONFIGBITS       0x8428#define PCIE20_PARF_PHY_CTRL3        0x9429#define PCIE20_PARF_PCS_CTRL         0x8030 31#define TX_AMP_VAL                   12032#define PHY_RX0_EQ_GEN1_VAL          033#define PHY_RX0_EQ_GEN2_VAL          434#define TX_DEEMPH_GEN1_VAL           2435#define TX_DEEMPH_GEN2_3_5DB_VAL     2636#define TX_DEEMPH_GEN2_6DB_VAL       3637#define PHY_TX0_TERM_OFFST_VAL       038 39struct qcom_phy {40	struct device *dev;41	void __iomem *base;42 43	struct regulator_bulk_data vregs[2];44 45	struct reset_control *phy_reset;46	struct reset_control *pipe_reset;47	struct clk *pipe_clk;48};49 50static int qcom_pcie2_phy_init(struct phy *phy)51{52	struct qcom_phy *qphy = phy_get_drvdata(phy);53	int ret;54 55	ret = reset_control_deassert(qphy->phy_reset);56	if (ret) {57		dev_err(qphy->dev, "cannot deassert pipe reset\n");58		return ret;59	}60 61	ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);62	if (ret)63		reset_control_assert(qphy->phy_reset);64 65	return ret;66}67 68static int qcom_pcie2_phy_power_on(struct phy *phy)69{70	struct qcom_phy *qphy = phy_get_drvdata(phy);71	int ret;72	u32 val;73 74	/* Program REF_CLK source */75	val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);76	val &= ~BIT(1);77	writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);78 79	usleep_range(1000, 2000);80 81	/* Don't use PAD for refclock */82	val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);83	val &= ~BIT(0);84	writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2);85 86	/* Program SSP ENABLE */87	val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);88	val |= BIT(0);89	writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3);90 91	usleep_range(1000, 2000);92 93	/* Assert Phy SW Reset */94	val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);95	val |= BIT(0);96	writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);97 98	/* Program Tx Amplitude */99	val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);100	val &= ~0x7f;101	val |= TX_AMP_VAL;102	writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL1);103 104	val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);105	val &= ~0x7f;106	val |= TX_AMP_VAL;107	writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL2);108 109	/* Program De-Emphasis */110	val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH1);111	val &= ~0x3f;112	val |= TX_DEEMPH_GEN2_6DB_VAL;113	writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH1);114 115	val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH2);116	val &= ~0x3f;117	val |= TX_DEEMPH_GEN2_3_5DB_VAL;118	writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH2);119 120	val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH3);121	val &= ~0x3f;122	val |= TX_DEEMPH_GEN1_VAL;123	writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH3);124 125	/* Program Rx_Eq */126	val = readl(qphy->base + PCIE20_PARF_CONFIGBITS);127	val &= ~0x7;128	val |= PHY_RX0_EQ_GEN2_VAL;129	writel(val, qphy->base + PCIE20_PARF_CONFIGBITS);130 131	/* Program Tx0_term_offset */132	val = readl(qphy->base + PCIE20_PARF_PHY_CTRL3);133	val &= ~0x1f;134	val |= PHY_TX0_TERM_OFFST_VAL;135	writel(val, qphy->base + PCIE20_PARF_PHY_CTRL3);136 137	/* disable Tx2Rx Loopback */138	val = readl(qphy->base + PCIE20_PARF_PCS_CTRL);139	val &= ~BIT(1);140	writel(val, qphy->base + PCIE20_PARF_PCS_CTRL);141 142	/* De-assert Phy SW Reset */143	val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);144	val &= ~BIT(0);145	writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);146 147	usleep_range(1000, 2000);148 149	ret = reset_control_deassert(qphy->pipe_reset);150	if (ret) {151		dev_err(qphy->dev, "cannot deassert pipe reset\n");152		goto out;153	}154 155	clk_set_rate(qphy->pipe_clk, 250000000);156 157	ret = clk_prepare_enable(qphy->pipe_clk);158	if (ret) {159		dev_err(qphy->dev, "failed to enable pipe clock\n");160		goto out;161	}162 163	ret = readl_poll_timeout(qphy->base + PCIE20_PARF_PHY_STTS, val,164				 !(val & BIT(0)), 1000, 10);165	if (ret)166		dev_err(qphy->dev, "phy initialization failed\n");167 168out:169	return ret;170}171 172static int qcom_pcie2_phy_power_off(struct phy *phy)173{174	struct qcom_phy *qphy = phy_get_drvdata(phy);175	u32 val;176 177	val = readl(qphy->base + PCIE2_PHY_RESET_CTRL);178	val |= BIT(0);179	writel(val, qphy->base + PCIE2_PHY_RESET_CTRL);180 181	clk_disable_unprepare(qphy->pipe_clk);182	reset_control_assert(qphy->pipe_reset);183 184	return 0;185}186 187static int qcom_pcie2_phy_exit(struct phy *phy)188{189	struct qcom_phy *qphy = phy_get_drvdata(phy);190 191	regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);192	reset_control_assert(qphy->phy_reset);193 194	return 0;195}196 197static const struct phy_ops qcom_pcie2_ops = {198	.init = qcom_pcie2_phy_init,199	.power_on = qcom_pcie2_phy_power_on,200	.power_off = qcom_pcie2_phy_power_off,201	.exit = qcom_pcie2_phy_exit,202	.owner = THIS_MODULE,203};204 205/*206 * Register a fixed rate pipe clock.207 *208 * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate209 * controls it. The <s>_pipe_clk coming out of the GCC is requested210 * by the PHY driver for its operations.211 * We register the <s>_pipe_clksrc here. The gcc driver takes care212 * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.213 * Below picture shows this relationship.214 *215 *         +---------------+216 *         |   PHY block   |<<---------------------------------------+217 *         |               |                                         |218 *         |   +-------+   |                   +-----+               |219 *   I/P---^-->|  PLL  |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+220 *    clk  |   +-------+   |                   +-----+221 *         +---------------+222 */223static int phy_pipe_clksrc_register(struct qcom_phy *qphy)224{225	struct device_node *np = qphy->dev->of_node;226	struct clk_fixed_rate *fixed;227	struct clk_init_data init = { };228	int ret;229 230	ret = of_property_read_string(np, "clock-output-names", &init.name);231	if (ret) {232		dev_err(qphy->dev, "%s: No clock-output-names\n", np->name);233		return ret;234	}235 236	fixed = devm_kzalloc(qphy->dev, sizeof(*fixed), GFP_KERNEL);237	if (!fixed)238		return -ENOMEM;239 240	init.ops = &clk_fixed_rate_ops;241 242	/* controllers using QMP phys use 250MHz pipe clock interface */243	fixed->fixed_rate = 250000000;244	fixed->hw.init = &init;245 246	ret = devm_clk_hw_register(qphy->dev, &fixed->hw);247	if (ret < 0)248		return ret;249 250	return devm_of_clk_add_hw_provider(qphy->dev, of_clk_hw_simple_get, &fixed->hw);251}252 253static int qcom_pcie2_phy_probe(struct platform_device *pdev)254{255	struct phy_provider *phy_provider;256	struct qcom_phy *qphy;257	struct device *dev = &pdev->dev;258	struct phy *phy;259	int ret;260 261	qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);262	if (!qphy)263		return -ENOMEM;264 265	qphy->dev = dev;266	qphy->base = devm_platform_ioremap_resource(pdev, 0);267	if (IS_ERR(qphy->base))268		return PTR_ERR(qphy->base);269 270	ret = phy_pipe_clksrc_register(qphy);271	if (ret) {272		dev_err(dev, "failed to register pipe_clk\n");273		return ret;274	}275 276	qphy->vregs[0].supply = "vdda-vp";277	qphy->vregs[1].supply = "vdda-vph";278	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(qphy->vregs), qphy->vregs);279	if (ret < 0)280		return ret;281 282	qphy->pipe_clk = devm_clk_get(dev, NULL);283	if (IS_ERR(qphy->pipe_clk)) {284		dev_err(dev, "failed to acquire pipe clock\n");285		return PTR_ERR(qphy->pipe_clk);286	}287 288	qphy->phy_reset = devm_reset_control_get_exclusive(dev, "phy");289	if (IS_ERR(qphy->phy_reset)) {290		dev_err(dev, "failed to acquire phy reset\n");291		return PTR_ERR(qphy->phy_reset);292	}293 294	qphy->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");295	if (IS_ERR(qphy->pipe_reset)) {296		dev_err(dev, "failed to acquire pipe reset\n");297		return PTR_ERR(qphy->pipe_reset);298	}299 300	phy = devm_phy_create(dev, dev->of_node, &qcom_pcie2_ops);301	if (IS_ERR(phy)) {302		dev_err(dev, "failed to create phy\n");303		return PTR_ERR(phy);304	}305 306	phy_set_drvdata(phy, qphy);307 308	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);309	if (IS_ERR(phy_provider))310		dev_err(dev, "failed to register phy provider\n");311 312	return PTR_ERR_OR_ZERO(phy_provider);313}314 315static const struct of_device_id qcom_pcie2_phy_match_table[] = {316	{ .compatible = "qcom,pcie2-phy" },317	{}318};319MODULE_DEVICE_TABLE(of, qcom_pcie2_phy_match_table);320 321static struct platform_driver qcom_pcie2_phy_driver = {322	.probe = qcom_pcie2_phy_probe,323	.driver = {324		.name = "phy-qcom-pcie2",325		.of_match_table = qcom_pcie2_phy_match_table,326	},327};328 329module_platform_driver(qcom_pcie2_phy_driver);330 331MODULE_DESCRIPTION("Qualcomm PCIe PHY driver");332MODULE_LICENSE("GPL v2");333