xref: /netbsd-src/sys/arch/arm/rockchip/rk3399_pcie_phy.c (revision ca5860d9ee8ae57e39e516ea0653e09e16fb2bdf)
1 /*	$NetBSD: rk3399_pcie_phy.c,v 1.5 2024/11/19 08:24:47 skrll Exp $	*/
2 /*	$OpenBSD: rkpcie.c,v 1.6 2018/08/28 09:33:18 jsg Exp $	*/
3 /*
4  * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/cdefs.h>
20 
21 __KERNEL_RCSID(1, "$NetBSD: rk3399_pcie_phy.c,v 1.5 2024/11/19 08:24:47 skrll Exp $");
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/kmem.h>
27 
28 #include <machine/intr.h>
29 #include <sys/bus.h>
30 #include <dev/fdt/fdtvar.h>
31 #include <dev/fdt/syscon.h>
32 
33 #include <sys/gpio.h>
34 
35 #define RKPCIEPHY_MAXPHY 4
36 
37 struct rkpciephy_softc {
38 	device_t		sc_dev;
39 	int			sc_phy_node;
40 	uint8_t			sc_phys[RKPCIEPHY_MAXPHY];
41 	u_int			sc_phys_on;
42 };
43 
44 static int rkpciephy_match(device_t, cfdata_t, void *);
45 static void rkpciephy_attach(device_t, device_t, void *);
46 
47 CFATTACH_DECL_NEW(rkpciephy, sizeof(struct rkpciephy_softc),
48         rkpciephy_match, rkpciephy_attach, NULL, NULL);
49 
50 static const struct device_compatible_entry compat_data[] = {
51 	{ .compat = "rockchip,rk3399-pcie-phy" },
52 	DEVICE_COMPAT_EOL
53 };
54 
55 static int
56 rkpciephy_match(device_t parent, cfdata_t cf, void *aux)
57 {
58 	struct fdt_attach_args *faa = aux;
59 
60 	return of_compatible_match(faa->faa_phandle, compat_data);
61 }
62 
63 static void rkpcie_phy_poweron(struct rkpciephy_softc *, u_int);
64 
65 static inline void
66 clock_enable(int phandle, const char *name)
67 {
68 	struct clk * clk = fdtbus_clock_get(phandle, name);
69 	if (clk == NULL)
70 		return;
71 	if (clk_enable(clk) != 0)
72 		return;
73 }
74 
75 static void
76 reset_assert(int phandle, const char *name)
77 {
78 	struct fdtbus_reset *rst;
79 
80 	rst = fdtbus_reset_get(phandle, name);
81 	fdtbus_reset_assert(rst);
82 	fdtbus_reset_put(rst);
83 }
84 
85 static void
86 reset_deassert(int phandle, const char *name)
87 {
88         struct fdtbus_reset *rst;
89 
90 	rst = fdtbus_reset_get(phandle, name);
91 	fdtbus_reset_deassert(rst);
92 	fdtbus_reset_put(rst);
93 }
94 
95 static void *
96 rkpciephy_phy_acquire(device_t dev, const void *data, size_t len)
97 {
98 	struct rkpciephy_softc * const sc = device_private(dev);
99 
100 	if (len != 4)
101 		return NULL;
102 
103 	const int phy_id = be32dec(data);
104 	if (phy_id >= RKPCIEPHY_MAXPHY)
105 		return NULL;
106 //	device_printf(dev, "%s phy_id %d %d\n", __func__, phy_id, sc->sc_phys[phy_id]);
107 
108 	if (true /*XXX*/ || sc->sc_phys_on == 0) {
109 		clock_enable(sc->sc_phy_node, "refclk");
110 		reset_assert(sc->sc_phy_node, "phy");
111 	}
112 
113 	return &sc->sc_phys[phy_id];
114 }
115 
116 static int
117 rkpciephy_phy_enable(device_t dev, void *priv, bool enable)
118 {
119 	struct rkpciephy_softc * const sc = device_private(dev);
120 	uint8_t * const lane = priv;
121 
122 //	device_printf(dev, "%s %u %u\n", __func__, *lane, enable);
123 
124 	if (enable) {
125 		rkpcie_phy_poweron(sc, *lane);
126 		sc->sc_phys_on |= 1U << *lane;
127 	} else {
128 #if notyet
129 		sc->sc_phys_on &= ~(1U << *lane);
130 #endif
131 	}
132 
133 	return 0;
134 }
135 
136 const struct fdtbus_phy_controller_func rkpciephy_phy_funcs = {
137  	.acquire = rkpciephy_phy_acquire,
138  	.release = (void *)voidop,
139  	.enable = rkpciephy_phy_enable,
140 };
141 
142 static void
143 rkpciephy_attach(device_t parent, device_t self, void *aux)
144 {
145 	struct rkpciephy_softc *sc = device_private(self);
146 	struct fdt_attach_args *faa = aux;
147 
148 	sc->sc_dev = self;
149 	sc->sc_phy_node = faa->faa_phandle;
150 
151 	aprint_naive("\n");
152 	aprint_normal(": RK3399 PCIe PHY\n");
153 
154 	for (size_t i = 0; i < RKPCIEPHY_MAXPHY; i++)
155 		sc->sc_phys[i] = i;
156 
157 	fdtbus_register_phy_controller(self, faa->faa_phandle, &rkpciephy_phy_funcs);
158 }
159 
160 /*
161  * PHY Support.
162  */
163 
164 #define RK3399_GRF_SOC_CON5_PCIE	0xe214
165 #define  RK3399_TX_ELEC_IDLE_OFF_MASK	((1 << 3) << 16)
166 #define  RK3399_TX_ELEC_IDLE_OFF	(1 << 3)
167 #define RK3399_GRF_SOC_CON8		0xe220
168 #define  RK3399_PCIE_TEST_DATA_MASK	((0xf << 7) << 16)
169 #define  RK3399_PCIE_TEST_DATA_SHIFT	7
170 #define  RK3399_PCIE_TEST_ADDR_MASK	((0x3f << 1) << 16)
171 #define  RK3399_PCIE_TEST_ADDR_SHIFT	1
172 #define  RK3399_PCIE_TEST_WRITE_ENABLE	(((1 << 0) << 16) | (1 << 0))
173 #define  RK3399_PCIE_TEST_WRITE_DISABLE	(((1 << 0) << 16) | (0 << 0))
174 #define RK3399_GRF_SOC_STATUS1		0xe2a4
175 #define  RK3399_PCIE_PHY_PLL_LOCKED	(1 << 9)
176 #define  RK3399_PCIE_PHY_PLL_OUTPUT	(1 << 10)
177 
178 #define RK3399_PCIE_PHY_CFG_PLL_LOCK	0x10
179 #define RK3399_PCIE_PHY_CFG_CLK_TEST	0x10
180 #define  RK3399_PCIE_PHY_CFG_SEPE_RATE	(1 << 3)
181 #define RK3399_PCIE_PHY_CFG_CLK_SCC	0x12
182 #define  RK3399_PCIE_PHY_CFG_PLL_100M	(1 << 3)
183 
184 static void
185 rkpcie_phy_write_conf(struct syscon *rm, uint8_t addr, uint8_t data)
186 {
187 	syscon_write_4(rm, RK3399_GRF_SOC_CON8,
188 	    RK3399_PCIE_TEST_ADDR_MASK |
189 	    (addr << RK3399_PCIE_TEST_ADDR_SHIFT) |
190 	    RK3399_PCIE_TEST_DATA_MASK |
191 	    (data << RK3399_PCIE_TEST_DATA_SHIFT) |
192 	    RK3399_PCIE_TEST_WRITE_DISABLE);
193 	delay(1);
194 	syscon_write_4(rm, RK3399_GRF_SOC_CON8,
195 	    RK3399_PCIE_TEST_WRITE_ENABLE);
196 	delay(1);
197 	syscon_write_4(rm, RK3399_GRF_SOC_CON8,
198 	    RK3399_PCIE_TEST_WRITE_DISABLE);
199 }
200 
201 static void
202 rkpcie_phy_poweron(struct rkpciephy_softc *sc, u_int lane)
203 {
204 	struct syscon *rm;
205 	uint32_t status;
206 	int timo;
207 
208 	reset_deassert(sc->sc_phy_node, "phy");
209 
210 	rm = fdtbus_syscon_lookup(OF_parent(sc->sc_phy_node));
211 	if (rm == NULL)
212 		return;
213 
214 	syscon_lock(rm);
215 	syscon_write_4(rm, RK3399_GRF_SOC_CON8,
216 	    RK3399_PCIE_TEST_ADDR_MASK |
217 	    RK3399_PCIE_PHY_CFG_PLL_LOCK << RK3399_PCIE_TEST_ADDR_SHIFT);
218 	syscon_write_4(rm, RK3399_GRF_SOC_CON5_PCIE,
219 	    RK3399_TX_ELEC_IDLE_OFF_MASK << lane | 0);
220 	//printf("%s %x\n", __func__, syscon_read_4(rm, RK3399_GRF_SOC_CON5_PCIE));
221 
222 	for (timo = 50; timo > 0; timo--) {
223 		status = syscon_read_4(rm, RK3399_GRF_SOC_STATUS1);
224 		if (status & RK3399_PCIE_PHY_PLL_LOCKED)
225 			break;
226 		delay(20000);
227 	}
228 	if (timo == 0) {
229 		device_printf(sc->sc_dev, "PHY PLL lock timeout\n");
230 		syscon_unlock(rm);
231 		return;
232 	}
233 
234 	rkpcie_phy_write_conf(rm, RK3399_PCIE_PHY_CFG_CLK_TEST,
235 	    RK3399_PCIE_PHY_CFG_SEPE_RATE);
236 	rkpcie_phy_write_conf(rm, RK3399_PCIE_PHY_CFG_CLK_SCC,
237 	    RK3399_PCIE_PHY_CFG_PLL_100M);
238 
239 	for (timo = 50; timo > 0; timo--) {
240 		status = syscon_read_4(rm, RK3399_GRF_SOC_STATUS1);
241 		if ((status & RK3399_PCIE_PHY_PLL_OUTPUT) == 0)
242 			break;
243 		delay(20000);
244 	}
245 	if (timo == 0) {
246 		device_printf(sc->sc_dev, "PHY PLL output enable timeout\n");
247 		syscon_unlock(rm);
248 		return;
249 	}
250 
251 	syscon_write_4(rm, RK3399_GRF_SOC_CON8,
252 	    RK3399_PCIE_TEST_ADDR_MASK |
253 	    RK3399_PCIE_PHY_CFG_PLL_LOCK << RK3399_PCIE_TEST_ADDR_SHIFT);
254 
255 	for (timo = 50; timo > 0; timo--) {
256 		status = syscon_read_4(rm, RK3399_GRF_SOC_STATUS1);
257 		if (status & RK3399_PCIE_PHY_PLL_LOCKED)
258 			break;
259 		delay(20000);
260 	}
261 	if (timo == 0) {
262 		device_printf(sc->sc_dev, "PHY PLL relock timeout\n");
263 		syscon_unlock(rm);
264 		return;
265 	}
266 	syscon_unlock(rm);
267 }
268