1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * PCIe host controller driver for Rockchip SoCs.
4  *
5  * Copyright (C) 2021 Rockchip Electronics Co., Ltd.
6  *		http://www.rock-chips.com
7  *
8  * Author: Simon Xue <xxm@rock-chips.com>
9  */
10 
11 #include <linux/clk.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/mfd/syscon.h>
14 #include <linux/module.h>
15 #include <linux/of_device.h>
16 #include <linux/phy/phy.h>
17 #include <linux/platform_device.h>
18 #include <linux/regmap.h>
19 #include <linux/reset.h>
20 
21 #include "pcie-designware.h"
22 
23 /*
24  * The upper 16 bits of PCIE_CLIENT_CONFIG are a write
25  * mask for the lower 16 bits.
26  */
27 #define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))
28 #define HIWORD_UPDATE_BIT(val)	HIWORD_UPDATE(val, val)
29 
30 #define to_rockchip_pcie(x) dev_get_drvdata((x)->dev)
31 
32 #define PCIE_CLIENT_RC_MODE		HIWORD_UPDATE_BIT(0x40)
33 #define PCIE_CLIENT_ENABLE_LTSSM	HIWORD_UPDATE_BIT(0xc)
34 #define PCIE_SMLH_LINKUP		BIT(16)
35 #define PCIE_RDLH_LINKUP		BIT(17)
36 #define PCIE_LINKUP			(PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP)
37 #define PCIE_L0S_ENTRY			0x11
38 #define PCIE_CLIENT_GENERAL_CONTROL	0x0
39 #define PCIE_CLIENT_GENERAL_DEBUG	0x104
40 #define PCIE_CLIENT_HOT_RESET_CTRL      0x180
41 #define PCIE_CLIENT_LTSSM_STATUS	0x300
42 #define PCIE_LTSSM_ENABLE_ENHANCE       BIT(4)
43 #define PCIE_LTSSM_STATUS_MASK		GENMASK(5, 0)
44 
45 struct rockchip_pcie {
46 	struct dw_pcie			pci;
47 	void __iomem			*apb_base;
48 	struct phy			*phy;
49 	struct clk_bulk_data		*clks;
50 	unsigned int			clk_cnt;
51 	struct reset_control		*rst;
52 	struct gpio_desc		*rst_gpio;
53 	struct regulator                *vpcie3v3;
54 };
55 
56 static int rockchip_pcie_readl_apb(struct rockchip_pcie *rockchip,
57 					     u32 reg)
58 {
59 	return readl_relaxed(rockchip->apb_base + reg);
60 }
61 
62 static void rockchip_pcie_writel_apb(struct rockchip_pcie *rockchip,
63 						u32 val, u32 reg)
64 {
65 	writel_relaxed(val, rockchip->apb_base + reg);
66 }
67 
68 static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip)
69 {
70 	rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM,
71 				 PCIE_CLIENT_GENERAL_CONTROL);
72 }
73 
74 static int rockchip_pcie_link_up(struct dw_pcie *pci)
75 {
76 	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
77 	u32 val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS);
78 
79 	if ((val & PCIE_LINKUP) == PCIE_LINKUP &&
80 	    (val & PCIE_LTSSM_STATUS_MASK) == PCIE_L0S_ENTRY)
81 		return 1;
82 
83 	return 0;
84 }
85 
86 static int rockchip_pcie_start_link(struct dw_pcie *pci)
87 {
88 	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
89 
90 	/* Reset device */
91 	gpiod_set_value_cansleep(rockchip->rst_gpio, 0);
92 
93 	rockchip_pcie_enable_ltssm(rockchip);
94 
95 	/*
96 	 * PCIe requires the refclk to be stable for 100µs prior to releasing
97 	 * PERST. See table 2-4 in section 2.6.2 AC Specifications of the PCI
98 	 * Express Card Electromechanical Specification, 1.1. However, we don't
99 	 * know if the refclk is coming from RC's PHY or external OSC. If it's
100 	 * from RC, so enabling LTSSM is the just right place to release #PERST.
101 	 * We need more extra time as before, rather than setting just
102 	 * 100us as we don't know how long should the device need to reset.
103 	 */
104 	msleep(100);
105 	gpiod_set_value_cansleep(rockchip->rst_gpio, 1);
106 
107 	return 0;
108 }
109 
110 static int rockchip_pcie_host_init(struct pcie_port *pp)
111 {
112 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
113 	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
114 	u32 val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE);
115 
116 	/* LTSSM enable control mode */
117 	rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL);
118 
119 	rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_RC_MODE,
120 				 PCIE_CLIENT_GENERAL_CONTROL);
121 
122 	return 0;
123 }
124 
125 static const struct dw_pcie_host_ops rockchip_pcie_host_ops = {
126 	.host_init = rockchip_pcie_host_init,
127 };
128 
129 static int rockchip_pcie_clk_init(struct rockchip_pcie *rockchip)
130 {
131 	struct device *dev = rockchip->pci.dev;
132 	int ret;
133 
134 	ret = devm_clk_bulk_get_all(dev, &rockchip->clks);
135 	if (ret < 0)
136 		return ret;
137 
138 	rockchip->clk_cnt = ret;
139 
140 	return clk_bulk_prepare_enable(rockchip->clk_cnt, rockchip->clks);
141 }
142 
143 static int rockchip_pcie_resource_get(struct platform_device *pdev,
144 				      struct rockchip_pcie *rockchip)
145 {
146 	rockchip->apb_base = devm_platform_ioremap_resource_byname(pdev, "apb");
147 	if (IS_ERR(rockchip->apb_base))
148 		return PTR_ERR(rockchip->apb_base);
149 
150 	rockchip->rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
151 						     GPIOD_OUT_HIGH);
152 	if (IS_ERR(rockchip->rst_gpio))
153 		return PTR_ERR(rockchip->rst_gpio);
154 
155 	return 0;
156 }
157 
158 static int rockchip_pcie_phy_init(struct rockchip_pcie *rockchip)
159 {
160 	struct device *dev = rockchip->pci.dev;
161 	int ret;
162 
163 	rockchip->phy = devm_phy_get(dev, "pcie-phy");
164 	if (IS_ERR(rockchip->phy))
165 		return dev_err_probe(dev, PTR_ERR(rockchip->phy),
166 				     "missing PHY\n");
167 
168 	ret = phy_init(rockchip->phy);
169 	if (ret < 0)
170 		return ret;
171 
172 	ret = phy_power_on(rockchip->phy);
173 	if (ret)
174 		phy_exit(rockchip->phy);
175 
176 	return ret;
177 }
178 
179 static void rockchip_pcie_phy_deinit(struct rockchip_pcie *rockchip)
180 {
181 	phy_exit(rockchip->phy);
182 	phy_power_off(rockchip->phy);
183 }
184 
185 static int rockchip_pcie_reset_control_release(struct rockchip_pcie *rockchip)
186 {
187 	struct device *dev = rockchip->pci.dev;
188 
189 	rockchip->rst = devm_reset_control_array_get_exclusive(dev);
190 	if (IS_ERR(rockchip->rst))
191 		return dev_err_probe(dev, PTR_ERR(rockchip->rst),
192 				     "failed to get reset lines\n");
193 
194 	return reset_control_deassert(rockchip->rst);
195 }
196 
197 static const struct dw_pcie_ops dw_pcie_ops = {
198 	.link_up = rockchip_pcie_link_up,
199 	.start_link = rockchip_pcie_start_link,
200 };
201 
202 static int rockchip_pcie_probe(struct platform_device *pdev)
203 {
204 	struct device *dev = &pdev->dev;
205 	struct rockchip_pcie *rockchip;
206 	struct pcie_port *pp;
207 	int ret;
208 
209 	rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL);
210 	if (!rockchip)
211 		return -ENOMEM;
212 
213 	platform_set_drvdata(pdev, rockchip);
214 
215 	rockchip->pci.dev = dev;
216 	rockchip->pci.ops = &dw_pcie_ops;
217 
218 	pp = &rockchip->pci.pp;
219 	pp->ops = &rockchip_pcie_host_ops;
220 
221 	ret = rockchip_pcie_resource_get(pdev, rockchip);
222 	if (ret)
223 		return ret;
224 
225 	/* DON'T MOVE ME: must be enable before PHY init */
226 	rockchip->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3");
227 	if (IS_ERR(rockchip->vpcie3v3)) {
228 		if (PTR_ERR(rockchip->vpcie3v3) != -ENODEV)
229 			return dev_err_probe(dev, PTR_ERR(rockchip->vpcie3v3),
230 					"failed to get vpcie3v3 regulator\n");
231 		rockchip->vpcie3v3 = NULL;
232 	} else {
233 		ret = regulator_enable(rockchip->vpcie3v3);
234 		if (ret) {
235 			dev_err(dev, "failed to enable vpcie3v3 regulator\n");
236 			return ret;
237 		}
238 	}
239 
240 	ret = rockchip_pcie_phy_init(rockchip);
241 	if (ret)
242 		goto disable_regulator;
243 
244 	ret = rockchip_pcie_reset_control_release(rockchip);
245 	if (ret)
246 		goto deinit_phy;
247 
248 	ret = rockchip_pcie_clk_init(rockchip);
249 	if (ret)
250 		goto deinit_phy;
251 
252 	ret = dw_pcie_host_init(pp);
253 	if (!ret)
254 		return 0;
255 
256 	clk_bulk_disable_unprepare(rockchip->clk_cnt, rockchip->clks);
257 deinit_phy:
258 	rockchip_pcie_phy_deinit(rockchip);
259 disable_regulator:
260 	if (rockchip->vpcie3v3)
261 		regulator_disable(rockchip->vpcie3v3);
262 
263 	return ret;
264 }
265 
266 static const struct of_device_id rockchip_pcie_of_match[] = {
267 	{ .compatible = "rockchip,rk3568-pcie", },
268 	{},
269 };
270 
271 static struct platform_driver rockchip_pcie_driver = {
272 	.driver = {
273 		.name	= "rockchip-dw-pcie",
274 		.of_match_table = rockchip_pcie_of_match,
275 		.suppress_bind_attrs = true,
276 	},
277 	.probe = rockchip_pcie_probe,
278 };
279 builtin_platform_driver(rockchip_pcie_driver);
280