xref: /openbmc/linux/drivers/phy/samsung/phy-exynos-pcie.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20b56e9a7SVivek Gautam /*
3c233a2edSKrzysztof Kozlowski  * Samsung Exynos SoC series PCIe PHY driver
40b56e9a7SVivek Gautam  *
50b56e9a7SVivek Gautam  * Phy provider for PCIe controller on Exynos SoC series
60b56e9a7SVivek Gautam  *
7496db029SJaehoon Chung  * Copyright (C) 2017-2020 Samsung Electronics Co., Ltd.
80b56e9a7SVivek Gautam  * Jaehoon Chung <jh80.chung@samsung.com>
90b56e9a7SVivek Gautam  */
100b56e9a7SVivek Gautam 
110b56e9a7SVivek Gautam #include <linux/io.h>
120b56e9a7SVivek Gautam #include <linux/mfd/syscon.h>
130b56e9a7SVivek Gautam #include <linux/of_platform.h>
140b56e9a7SVivek Gautam #include <linux/platform_device.h>
150b56e9a7SVivek Gautam #include <linux/phy/phy.h>
160b56e9a7SVivek Gautam #include <linux/regmap.h>
170b56e9a7SVivek Gautam 
18496db029SJaehoon Chung #define PCIE_PHY_OFFSET(x)		((x) * 0x4)
190b56e9a7SVivek Gautam 
20496db029SJaehoon Chung /* Sysreg FSYS register offsets and bits for Exynos5433 */
21496db029SJaehoon Chung #define PCIE_EXYNOS5433_PHY_MAC_RESET		0x0208
22496db029SJaehoon Chung #define PCIE_MAC_RESET_MASK			0xFF
23496db029SJaehoon Chung #define PCIE_MAC_RESET				BIT(4)
24496db029SJaehoon Chung #define PCIE_EXYNOS5433_PHY_L1SUB_CM_CON	0x1010
25496db029SJaehoon Chung #define PCIE_REFCLK_GATING_EN			BIT(0)
26496db029SJaehoon Chung #define PCIE_EXYNOS5433_PHY_COMMON_RESET	0x1020
27496db029SJaehoon Chung #define PCIE_PHY_RESET				BIT(0)
28496db029SJaehoon Chung #define PCIE_EXYNOS5433_PHY_GLOBAL_RESET	0x1040
29496db029SJaehoon Chung #define PCIE_GLOBAL_RESET			BIT(0)
30496db029SJaehoon Chung #define PCIE_REFCLK				BIT(1)
31496db029SJaehoon Chung #define PCIE_REFCLK_MASK			0x16
32496db029SJaehoon Chung #define PCIE_APP_REQ_EXIT_L1_MODE		BIT(5)
330b56e9a7SVivek Gautam 
34496db029SJaehoon Chung /* PMU PCIE PHY isolation control */
35496db029SJaehoon Chung #define EXYNOS5433_PMU_PCIE_PHY_OFFSET		0x730
360b56e9a7SVivek Gautam 
370b56e9a7SVivek Gautam /* For Exynos pcie phy */
380b56e9a7SVivek Gautam struct exynos_pcie_phy {
39496db029SJaehoon Chung 	void __iomem *base;
40496db029SJaehoon Chung 	struct regmap *pmureg;
41496db029SJaehoon Chung 	struct regmap *fsysreg;
420b56e9a7SVivek Gautam };
430b56e9a7SVivek Gautam 
exynos_pcie_phy_writel(void __iomem * base,u32 val,u32 offset)440b56e9a7SVivek Gautam static void exynos_pcie_phy_writel(void __iomem *base, u32 val, u32 offset)
450b56e9a7SVivek Gautam {
460b56e9a7SVivek Gautam 	writel(val, base + offset);
470b56e9a7SVivek Gautam }
480b56e9a7SVivek Gautam 
49496db029SJaehoon Chung /* Exynos5433 specific functions */
exynos5433_pcie_phy_init(struct phy * phy)50496db029SJaehoon Chung static int exynos5433_pcie_phy_init(struct phy *phy)
510b56e9a7SVivek Gautam {
520b56e9a7SVivek Gautam 	struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
530b56e9a7SVivek Gautam 
54*f2812227SMarek Szyprowski 	regmap_update_bits(ep->pmureg, EXYNOS5433_PMU_PCIE_PHY_OFFSET,
55*f2812227SMarek Szyprowski 			   BIT(0), 1);
56*f2812227SMarek Szyprowski 	regmap_update_bits(ep->fsysreg, PCIE_EXYNOS5433_PHY_GLOBAL_RESET,
57*f2812227SMarek Szyprowski 			   PCIE_APP_REQ_EXIT_L1_MODE, 0);
58*f2812227SMarek Szyprowski 	regmap_update_bits(ep->fsysreg, PCIE_EXYNOS5433_PHY_L1SUB_CM_CON,
59*f2812227SMarek Szyprowski 			   PCIE_REFCLK_GATING_EN, 0);
60*f2812227SMarek Szyprowski 
61496db029SJaehoon Chung 	regmap_update_bits(ep->fsysreg,	PCIE_EXYNOS5433_PHY_COMMON_RESET,
62496db029SJaehoon Chung 			   PCIE_PHY_RESET, 1);
63496db029SJaehoon Chung 	regmap_update_bits(ep->fsysreg, PCIE_EXYNOS5433_PHY_MAC_RESET,
64496db029SJaehoon Chung 			   PCIE_MAC_RESET, 0);
650b56e9a7SVivek Gautam 
66496db029SJaehoon Chung 	/* PHY refclk 24MHz */
67496db029SJaehoon Chung 	regmap_update_bits(ep->fsysreg, PCIE_EXYNOS5433_PHY_GLOBAL_RESET,
68496db029SJaehoon Chung 			   PCIE_REFCLK_MASK, PCIE_REFCLK);
69496db029SJaehoon Chung 	regmap_update_bits(ep->fsysreg, PCIE_EXYNOS5433_PHY_GLOBAL_RESET,
70496db029SJaehoon Chung 			   PCIE_GLOBAL_RESET, 0);
710b56e9a7SVivek Gautam 
720b56e9a7SVivek Gautam 
73496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x11, PCIE_PHY_OFFSET(0x3));
740b56e9a7SVivek Gautam 
75496db029SJaehoon Chung 	/* band gap reference on */
76496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0, PCIE_PHY_OFFSET(0x20));
77496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0, PCIE_PHY_OFFSET(0x4b));
780b56e9a7SVivek Gautam 
79768a711eSVinod Koul 	/* jitter tuning */
80496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x34, PCIE_PHY_OFFSET(0x4));
81496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x02, PCIE_PHY_OFFSET(0x7));
82496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x41, PCIE_PHY_OFFSET(0x21));
83496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x7F, PCIE_PHY_OFFSET(0x14));
84496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0xC0, PCIE_PHY_OFFSET(0x15));
85496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x61, PCIE_PHY_OFFSET(0x36));
860b56e9a7SVivek Gautam 
87496db029SJaehoon Chung 	/* D0 uninit.. */
88496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x44, PCIE_PHY_OFFSET(0x3D));
890b56e9a7SVivek Gautam 
90496db029SJaehoon Chung 	/* 24MHz */
91496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x94, PCIE_PHY_OFFSET(0x8));
92496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0xA7, PCIE_PHY_OFFSET(0x9));
93496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x93, PCIE_PHY_OFFSET(0xA));
94496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x6B, PCIE_PHY_OFFSET(0xC));
95496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0xA5, PCIE_PHY_OFFSET(0xF));
96496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x34, PCIE_PHY_OFFSET(0x16));
97496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0xA3, PCIE_PHY_OFFSET(0x17));
98496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0xA7, PCIE_PHY_OFFSET(0x1A));
99496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x71, PCIE_PHY_OFFSET(0x23));
100496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x4C, PCIE_PHY_OFFSET(0x24));
1010b56e9a7SVivek Gautam 
102496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x0E, PCIE_PHY_OFFSET(0x26));
103496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x14, PCIE_PHY_OFFSET(0x7));
104496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x48, PCIE_PHY_OFFSET(0x43));
105496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x44, PCIE_PHY_OFFSET(0x44));
106496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x03, PCIE_PHY_OFFSET(0x45));
107496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0xA7, PCIE_PHY_OFFSET(0x48));
108496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x13, PCIE_PHY_OFFSET(0x54));
109496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0x04, PCIE_PHY_OFFSET(0x31));
110496db029SJaehoon Chung 	exynos_pcie_phy_writel(ep->base, 0, PCIE_PHY_OFFSET(0x32));
1110b56e9a7SVivek Gautam 
112496db029SJaehoon Chung 	regmap_update_bits(ep->fsysreg, PCIE_EXYNOS5433_PHY_COMMON_RESET,
113496db029SJaehoon Chung 			   PCIE_PHY_RESET, 0);
114496db029SJaehoon Chung 	regmap_update_bits(ep->fsysreg, PCIE_EXYNOS5433_PHY_MAC_RESET,
115496db029SJaehoon Chung 			   PCIE_MAC_RESET_MASK, PCIE_MAC_RESET);
1160b56e9a7SVivek Gautam 	return 0;
1170b56e9a7SVivek Gautam }
1180b56e9a7SVivek Gautam 
exynos5433_pcie_phy_exit(struct phy * phy)119*f2812227SMarek Szyprowski static int exynos5433_pcie_phy_exit(struct phy *phy)
120496db029SJaehoon Chung {
121496db029SJaehoon Chung 	struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
122496db029SJaehoon Chung 
123496db029SJaehoon Chung 	regmap_update_bits(ep->fsysreg, PCIE_EXYNOS5433_PHY_L1SUB_CM_CON,
124496db029SJaehoon Chung 			   PCIE_REFCLK_GATING_EN, PCIE_REFCLK_GATING_EN);
125496db029SJaehoon Chung 	regmap_update_bits(ep->pmureg, EXYNOS5433_PMU_PCIE_PHY_OFFSET,
126496db029SJaehoon Chung 			   BIT(0), 0);
127496db029SJaehoon Chung 	return 0;
128496db029SJaehoon Chung }
129496db029SJaehoon Chung 
130496db029SJaehoon Chung static const struct phy_ops exynos5433_phy_ops = {
131496db029SJaehoon Chung 	.init		= exynos5433_pcie_phy_init,
132*f2812227SMarek Szyprowski 	.exit		= exynos5433_pcie_phy_exit,
1330b56e9a7SVivek Gautam 	.owner		= THIS_MODULE,
1340b56e9a7SVivek Gautam };
1350b56e9a7SVivek Gautam 
1360b56e9a7SVivek Gautam static const struct of_device_id exynos_pcie_phy_match[] = {
1370b56e9a7SVivek Gautam 	{
138496db029SJaehoon Chung 		.compatible = "samsung,exynos5433-pcie-phy",
1390b56e9a7SVivek Gautam 	},
1400b56e9a7SVivek Gautam 	{},
1410b56e9a7SVivek Gautam };
1420b56e9a7SVivek Gautam 
exynos_pcie_phy_probe(struct platform_device * pdev)1430b56e9a7SVivek Gautam static int exynos_pcie_phy_probe(struct platform_device *pdev)
1440b56e9a7SVivek Gautam {
1450b56e9a7SVivek Gautam 	struct device *dev = &pdev->dev;
1460b56e9a7SVivek Gautam 	struct exynos_pcie_phy *exynos_phy;
1470b56e9a7SVivek Gautam 	struct phy *generic_phy;
1480b56e9a7SVivek Gautam 	struct phy_provider *phy_provider;
1490b56e9a7SVivek Gautam 
1500b56e9a7SVivek Gautam 	exynos_phy = devm_kzalloc(dev, sizeof(*exynos_phy), GFP_KERNEL);
1510b56e9a7SVivek Gautam 	if (!exynos_phy)
1520b56e9a7SVivek Gautam 		return -ENOMEM;
1530b56e9a7SVivek Gautam 
154496db029SJaehoon Chung 	exynos_phy->base = devm_platform_ioremap_resource(pdev, 0);
155496db029SJaehoon Chung 	if (IS_ERR(exynos_phy->base))
156496db029SJaehoon Chung 		return PTR_ERR(exynos_phy->base);
1570b56e9a7SVivek Gautam 
158496db029SJaehoon Chung 	exynos_phy->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
159496db029SJaehoon Chung 							"samsung,pmu-syscon");
160496db029SJaehoon Chung 	if (IS_ERR(exynos_phy->pmureg)) {
161496db029SJaehoon Chung 		dev_err(&pdev->dev, "PMU regmap lookup failed.\n");
162496db029SJaehoon Chung 		return PTR_ERR(exynos_phy->pmureg);
163496db029SJaehoon Chung 	}
1640b56e9a7SVivek Gautam 
165496db029SJaehoon Chung 	exynos_phy->fsysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
166496db029SJaehoon Chung 							 "samsung,fsys-sysreg");
167496db029SJaehoon Chung 	if (IS_ERR(exynos_phy->fsysreg)) {
168496db029SJaehoon Chung 		dev_err(&pdev->dev, "FSYS sysreg regmap lookup failed.\n");
169496db029SJaehoon Chung 		return PTR_ERR(exynos_phy->fsysreg);
170496db029SJaehoon Chung 	}
1710b56e9a7SVivek Gautam 
172496db029SJaehoon Chung 	generic_phy = devm_phy_create(dev, dev->of_node, &exynos5433_phy_ops);
1730b56e9a7SVivek Gautam 	if (IS_ERR(generic_phy)) {
1740b56e9a7SVivek Gautam 		dev_err(dev, "failed to create PHY\n");
1750b56e9a7SVivek Gautam 		return PTR_ERR(generic_phy);
1760b56e9a7SVivek Gautam 	}
1770b56e9a7SVivek Gautam 
1780b56e9a7SVivek Gautam 	phy_set_drvdata(generic_phy, exynos_phy);
1790b56e9a7SVivek Gautam 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
1800b56e9a7SVivek Gautam 
1810b56e9a7SVivek Gautam 	return PTR_ERR_OR_ZERO(phy_provider);
1820b56e9a7SVivek Gautam }
1830b56e9a7SVivek Gautam 
1840b56e9a7SVivek Gautam static struct platform_driver exynos_pcie_phy_driver = {
1850b56e9a7SVivek Gautam 	.probe	= exynos_pcie_phy_probe,
1860b56e9a7SVivek Gautam 	.driver = {
1870b56e9a7SVivek Gautam 		.of_match_table	= exynos_pcie_phy_match,
1880b56e9a7SVivek Gautam 		.name		= "exynos_pcie_phy",
1896aeec986SMarek Szyprowski 		.suppress_bind_attrs = true,
1900b56e9a7SVivek Gautam 	}
1910b56e9a7SVivek Gautam };
1920b56e9a7SVivek Gautam builtin_platform_driver(exynos_pcie_phy_driver);
193