1/*	$NetBSD: rk3399_pcie_phy.c,v 1.4 2021/01/27 03:10:19 thorpej 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.4 2021/01/27 03:10:19 thorpej 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
37struct 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
44static int rkpciephy_match(device_t, cfdata_t, void *);
45static void rkpciephy_attach(device_t, device_t, void *);
46
47CFATTACH_DECL_NEW(rkpciephy, sizeof(struct rkpciephy_softc),
48        rkpciephy_match, rkpciephy_attach, NULL, NULL);
49
50static const struct device_compatible_entry compat_data[] = {
51	{ .compat = "rockchip,rk3399-pcie-phy" },
52	DEVICE_COMPAT_EOL
53};
54
55static int
56rkpciephy_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
63static void rkpcie_phy_poweron(struct rkpciephy_softc *, u_int);
64
65static inline void
66clock_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
75static void
76reset_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
85static void
86reset_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
95static void *
96rkpciephy_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
116static int
117rkpciephy_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
136const struct fdtbus_phy_controller_func rkpciephy_phy_funcs = {
137 	.acquire = rkpciephy_phy_acquire,
138 	.release = (void *)voidop,
139 	.enable = rkpciephy_phy_enable,
140};
141
142static void
143rkpciephy_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
184static void
185rkpcie_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
201static void
202rkpcie_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