1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Samsung Exynos SoC series PCIe PHY driver
4 *
5 * Phy provider for PCIe controller on Exynos SoC series
6 *
7 * Copyright (C) 2017 Samsung Electronics Co., Ltd.
8 * Jaehoon Chung <jh80.chung@samsung.com>
9 */
10
11#include <linux/delay.h>
12#include <linux/io.h>
13#include <linux/iopoll.h>
14#include <linux/init.h>
15#include <linux/mfd/syscon.h>
16#include <linux/of.h>
17#include <linux/of_address.h>
18#include <linux/of_platform.h>
19#include <linux/platform_device.h>
20#include <linux/phy/phy.h>
21#include <linux/regmap.h>
22
23/* PCIe Purple registers */
24#define PCIE_PHY_GLOBAL_RESET		0x000
25#define PCIE_PHY_COMMON_RESET		0x004
26#define PCIE_PHY_CMN_REG		0x008
27#define PCIE_PHY_MAC_RESET		0x00c
28#define PCIE_PHY_PLL_LOCKED		0x010
29#define PCIE_PHY_TRSVREG_RESET		0x020
30#define PCIE_PHY_TRSV_RESET		0x024
31
32/* PCIe PHY registers */
33#define PCIE_PHY_IMPEDANCE		0x004
34#define PCIE_PHY_PLL_DIV_0		0x008
35#define PCIE_PHY_PLL_BIAS		0x00c
36#define PCIE_PHY_DCC_FEEDBACK		0x014
37#define PCIE_PHY_PLL_DIV_1		0x05c
38#define PCIE_PHY_COMMON_POWER		0x064
39#define PCIE_PHY_COMMON_PD_CMN		BIT(3)
40#define PCIE_PHY_TRSV0_EMP_LVL		0x084
41#define PCIE_PHY_TRSV0_DRV_LVL		0x088
42#define PCIE_PHY_TRSV0_RXCDR		0x0ac
43#define PCIE_PHY_TRSV0_POWER		0x0c4
44#define PCIE_PHY_TRSV0_PD_TSV		BIT(7)
45#define PCIE_PHY_TRSV0_LVCC		0x0dc
46#define PCIE_PHY_TRSV1_EMP_LVL		0x144
47#define PCIE_PHY_TRSV1_RXCDR		0x16c
48#define PCIE_PHY_TRSV1_POWER		0x184
49#define PCIE_PHY_TRSV1_PD_TSV		BIT(7)
50#define PCIE_PHY_TRSV1_LVCC		0x19c
51#define PCIE_PHY_TRSV2_EMP_LVL		0x204
52#define PCIE_PHY_TRSV2_RXCDR		0x22c
53#define PCIE_PHY_TRSV2_POWER		0x244
54#define PCIE_PHY_TRSV2_PD_TSV		BIT(7)
55#define PCIE_PHY_TRSV2_LVCC		0x25c
56#define PCIE_PHY_TRSV3_EMP_LVL		0x2c4
57#define PCIE_PHY_TRSV3_RXCDR		0x2ec
58#define PCIE_PHY_TRSV3_POWER		0x304
59#define PCIE_PHY_TRSV3_PD_TSV		BIT(7)
60#define PCIE_PHY_TRSV3_LVCC		0x31c
61
62struct exynos_pcie_phy_data {
63	const struct phy_ops	*ops;
64};
65
66/* For Exynos pcie phy */
67struct exynos_pcie_phy {
68	const struct exynos_pcie_phy_data *drv_data;
69	void __iomem *phy_base;
70	void __iomem *blk_base; /* For exynos5440 */
71};
72
73static void exynos_pcie_phy_writel(void __iomem *base, u32 val, u32 offset)
74{
75	writel(val, base + offset);
76}
77
78static u32 exynos_pcie_phy_readl(void __iomem *base, u32 offset)
79{
80	return readl(base + offset);
81}
82
83/* For Exynos5440 specific functions */
84static int exynos5440_pcie_phy_init(struct phy *phy)
85{
86	struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
87
88	/* DCC feedback control off */
89	exynos_pcie_phy_writel(ep->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
90
91	/* set TX/RX impedance */
92	exynos_pcie_phy_writel(ep->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
93
94	/* set 50Mhz PHY clock */
95	exynos_pcie_phy_writel(ep->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
96	exynos_pcie_phy_writel(ep->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
97
98	/* set TX Differential output for lane 0 */
99	exynos_pcie_phy_writel(ep->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
100
101	/* set TX Pre-emphasis Level Control for lane 0 to minimum */
102	exynos_pcie_phy_writel(ep->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
103
104	/* set RX clock and data recovery bandwidth */
105	exynos_pcie_phy_writel(ep->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
106	exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
107	exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
108	exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
109	exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
110
111	/* change TX Pre-emphasis Level Control for lanes */
112	exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
113	exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
114	exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
115	exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
116
117	/* set LVCC */
118	exynos_pcie_phy_writel(ep->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
119	exynos_pcie_phy_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
120	exynos_pcie_phy_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
121	exynos_pcie_phy_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
122
123	/* pulse for common reset */
124	exynos_pcie_phy_writel(ep->blk_base, 1, PCIE_PHY_COMMON_RESET);
125	udelay(500);
126	exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_COMMON_RESET);
127
128	return 0;
129}
130
131static int exynos5440_pcie_phy_power_on(struct phy *phy)
132{
133	struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
134	u32 val;
135
136	exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_COMMON_RESET);
137	exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_CMN_REG);
138	exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_TRSVREG_RESET);
139	exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_TRSV_RESET);
140
141	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
142	val &= ~PCIE_PHY_COMMON_PD_CMN;
143	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
144
145	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
146	val &= ~PCIE_PHY_TRSV0_PD_TSV;
147	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
148
149	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
150	val &= ~PCIE_PHY_TRSV1_PD_TSV;
151	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
152
153	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
154	val &= ~PCIE_PHY_TRSV2_PD_TSV;
155	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
156
157	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
158	val &= ~PCIE_PHY_TRSV3_PD_TSV;
159	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
160
161	return 0;
162}
163
164static int exynos5440_pcie_phy_power_off(struct phy *phy)
165{
166	struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
167	u32 val;
168
169	if (readl_poll_timeout(ep->phy_base + PCIE_PHY_PLL_LOCKED, val,
170				(val != 0), 1, 500)) {
171		dev_err(&phy->dev, "PLL Locked: 0x%x\n", val);
172		return -ETIMEDOUT;
173	}
174
175	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_COMMON_POWER);
176	val |= PCIE_PHY_COMMON_PD_CMN;
177	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER);
178
179	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER);
180	val |= PCIE_PHY_TRSV0_PD_TSV;
181	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER);
182
183	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER);
184	val |= PCIE_PHY_TRSV1_PD_TSV;
185	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER);
186
187	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER);
188	val |= PCIE_PHY_TRSV2_PD_TSV;
189	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER);
190
191	val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER);
192	val |= PCIE_PHY_TRSV3_PD_TSV;
193	exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER);
194
195	return 0;
196}
197
198static int exynos5440_pcie_phy_reset(struct phy *phy)
199{
200	struct exynos_pcie_phy *ep = phy_get_drvdata(phy);
201
202	exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_MAC_RESET);
203	exynos_pcie_phy_writel(ep->blk_base, 1, PCIE_PHY_GLOBAL_RESET);
204	exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_GLOBAL_RESET);
205
206	return 0;
207}
208
209static const struct phy_ops exynos5440_phy_ops = {
210	.init		= exynos5440_pcie_phy_init,
211	.power_on	= exynos5440_pcie_phy_power_on,
212	.power_off	= exynos5440_pcie_phy_power_off,
213	.reset		= exynos5440_pcie_phy_reset,
214	.owner		= THIS_MODULE,
215};
216
217static const struct exynos_pcie_phy_data exynos5440_pcie_phy_data = {
218	.ops		= &exynos5440_phy_ops,
219};
220
221static const struct of_device_id exynos_pcie_phy_match[] = {
222	{
223		.compatible = "samsung,exynos5440-pcie-phy",
224		.data = &exynos5440_pcie_phy_data,
225	},
226	{},
227};
228
229static int exynos_pcie_phy_probe(struct platform_device *pdev)
230{
231	struct device *dev = &pdev->dev;
232	struct exynos_pcie_phy *exynos_phy;
233	struct phy *generic_phy;
234	struct phy_provider *phy_provider;
235	struct resource *res;
236	const struct exynos_pcie_phy_data *drv_data;
237
238	drv_data = of_device_get_match_data(dev);
239	if (!drv_data)
240		return -ENODEV;
241
242	exynos_phy = devm_kzalloc(dev, sizeof(*exynos_phy), GFP_KERNEL);
243	if (!exynos_phy)
244		return -ENOMEM;
245
246	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
247	exynos_phy->phy_base = devm_ioremap_resource(dev, res);
248	if (IS_ERR(exynos_phy->phy_base))
249		return PTR_ERR(exynos_phy->phy_base);
250
251	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
252	exynos_phy->blk_base = devm_ioremap_resource(dev, res);
253	if (IS_ERR(exynos_phy->blk_base))
254		return PTR_ERR(exynos_phy->blk_base);
255
256	exynos_phy->drv_data = drv_data;
257
258	generic_phy = devm_phy_create(dev, dev->of_node, drv_data->ops);
259	if (IS_ERR(generic_phy)) {
260		dev_err(dev, "failed to create PHY\n");
261		return PTR_ERR(generic_phy);
262	}
263
264	phy_set_drvdata(generic_phy, exynos_phy);
265	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
266
267	return PTR_ERR_OR_ZERO(phy_provider);
268}
269
270static struct platform_driver exynos_pcie_phy_driver = {
271	.probe	= exynos_pcie_phy_probe,
272	.driver = {
273		.of_match_table	= exynos_pcie_phy_match,
274		.name		= "exynos_pcie_phy",
275		.suppress_bind_attrs = true,
276	}
277};
278
279builtin_platform_driver(exynos_pcie_phy_driver);
280