xref: /openbsd/sys/dev/fdt/rkcomphy.c (revision 4448ddba)
1*4448ddbaSkettenis /*	$OpenBSD: rkcomphy.c,v 1.2 2023/04/27 08:56:39 kettenis Exp $	*/
2e1414c50Skettenis /*
3e1414c50Skettenis  * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org>
4e1414c50Skettenis  *
5e1414c50Skettenis  * Permission to use, copy, modify, and distribute this software for any
6e1414c50Skettenis  * purpose with or without fee is hereby granted, provided that the above
7e1414c50Skettenis  * copyright notice and this permission notice appear in all copies.
8e1414c50Skettenis  *
9e1414c50Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10e1414c50Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11e1414c50Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12e1414c50Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13e1414c50Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14e1414c50Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15e1414c50Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16e1414c50Skettenis  */
17e1414c50Skettenis 
18e1414c50Skettenis #include <sys/param.h>
19e1414c50Skettenis #include <sys/systm.h>
20e1414c50Skettenis #include <sys/device.h>
21e1414c50Skettenis 
22e1414c50Skettenis #include <machine/intr.h>
23e1414c50Skettenis #include <machine/bus.h>
24e1414c50Skettenis #include <machine/fdt.h>
25e1414c50Skettenis 
26e1414c50Skettenis #include <dev/ofw/openfirm.h>
27e1414c50Skettenis #include <dev/ofw/ofw_clock.h>
28e1414c50Skettenis #include <dev/ofw/ofw_misc.h>
29e1414c50Skettenis #include <dev/ofw/fdt.h>
30e1414c50Skettenis 
31*4448ddbaSkettenis /*
32*4448ddbaSkettenis  * WARNING: Most (but not all!) of the register numbers in the Linux
33*4448ddbaSkettenis  * driver are off-by-one!  This driver uses 0-based register numbers
34*4448ddbaSkettenis  * like in the TRM.
35*4448ddbaSkettenis  */
36*4448ddbaSkettenis 
37e1414c50Skettenis /* Combo PHY registers */
38e1414c50Skettenis #define COMBO_PIPE_PHY_REG(idx)			((idx) * 4)
39e1414c50Skettenis /* REG_005 */
40e1414c50Skettenis #define  COMBO_PIPE_PHY_PLL_DIV_MASK		(0x3 << 6)
41e1414c50Skettenis #define  COMBO_PIPE_PHY_PLL_DIV_2		(0x1 << 6)
42e1414c50Skettenis /* REG_006 */
43e1414c50Skettenis #define  COMBO_PIPE_PHY_TX_RTERM_50OHM		(0x8 << 4)
44e1414c50Skettenis #define  COMBO_PIPE_PHY_RX_RTERM_44OHM		(0xf << 4)
45e1414c50Skettenis /* REG_010 */
46e1414c50Skettenis #define  COMBO_PIPE_PHY_SU_TRIM_0_7		0xf0
47e1414c50Skettenis /* REG_011 */
48e1414c50Skettenis #define  COMBO_PIPE_PHY_PLL_LPF_ADJ_VALUE	4
49e1414c50Skettenis /* REG_014 */
50e1414c50Skettenis #define  COMBO_PIPE_PHY_SSC_CNT_LO_MASK		(0x3 << 6)
51e1414c50Skettenis #define  COMBO_PIPE_PHY_SSC_CNT_LO_VALUE	(0x1 << 6)
52e1414c50Skettenis #define  COMBO_PIPE_PHY_CTLE_EN			(1 << 0)
53e1414c50Skettenis /* REG_015 */
54e1414c50Skettenis #define  COMBO_PIPE_PHY_SSC_CNT_HI_MASK		(0xff << 0)
55e1414c50Skettenis #define  COMBO_PIPE_PHY_SSC_CNT_HI_VALUE	(0x5f << 0)
56e1414c50Skettenis /* REG_017 */
57e1414c50Skettenis #define  COMBO_PIPE_PHY_PLL_LOOP		0x32
58*4448ddbaSkettenis /* REG_027 */
59*4448ddbaSkettenis #define  COMBO_PIPE_PHY_RX_TRIM_RK3588		0x4c
60e1414c50Skettenis /* REG_031 */
61e1414c50Skettenis #define  COMBO_PIPE_PHY_SSC_DIR_MASK		(0x3 << 4)
62e1414c50Skettenis #define  COMBO_PIPE_PHY_SSC_DIR_DOWN		(0x1 << 4)
63e1414c50Skettenis #define  COMBO_PIPE_PHY_SSC_OFFSET_MASK		(0x3 << 6)
64e1414c50Skettenis #define  COMBO_PIPE_PHY_SSC_OFFSET_500PPM	(0x1 << 6)
65e1414c50Skettenis /* REG_032 */
66e1414c50Skettenis #define  COMBO_PIPE_PHY_PLL_KVCO_MASK		(0x7 << 2)
67e1414c50Skettenis #define  COMBO_PIPE_PHY_PLL_KVCO_VALUE		(0x2 << 2)
68*4448ddbaSkettenis #define  COMBO_PIPE_PHY_PLL_KVCO_VALUE_RK3588	(0x4 << 2)
69e1414c50Skettenis 
70e1414c50Skettenis /* GRF registers */
71e1414c50Skettenis #define PIPE_GRF_PIPE_CON0			0x0000
72e1414c50Skettenis 
73*4448ddbaSkettenis /* PHP GRF registers (for RK3588) */
74*4448ddbaSkettenis #define PHP_GRF_PCIESEL_CON			0x0100
75*4448ddbaSkettenis 
76e1414c50Skettenis /* PHY GRF registers */
77e1414c50Skettenis #define PIPE_PHY_GRF_PIPE_CON(idx)		((idx) * 4)
78e1414c50Skettenis /* CON0 */
79e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_MODE_PCIE		0x003f0000
80e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_MODE_USB		0x003f0004
81e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_MODE_SATA		0x003f0019
82e1414c50Skettenis /* CON1 */
83e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_CLK_24M		0x60000000
84e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_CLK_25M		0x60002000
85e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_CLK_100M		0x60004000
86e1414c50Skettenis /* CON2 */
87e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_TXCOMP_SEL_CTRL	0x80000000
88e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_TXCOMP_SEL_GRF	0x80008000
89e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_TXELEC_SEL_CTRL	0x10000000
90e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_TXELEC_SEL_GRF	0x10001000
91e1414c50Skettenis /* CON3 */
92e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_SEL_PCIE		0x60000000
93e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_SEL_USB		0x60002000
94e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_SEL_SATA		0x60004000
95e1414c50Skettenis /* STATUS1 */
96e1414c50Skettenis #define PIPE_PHY_GRF_PIPE_STATUS1		0x34
97e1414c50Skettenis #define  PIPE_PHY_GRF_PIPE_PHYSTATUS		(1 << 6)
98e1414c50Skettenis 
99e1414c50Skettenis #define HREAD4(sc, reg)							\
100e1414c50Skettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
101e1414c50Skettenis #define HWRITE4(sc, reg, val)						\
102e1414c50Skettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
103e1414c50Skettenis #define HSET4(sc, reg, bits)						\
104e1414c50Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
105e1414c50Skettenis #define HCLR4(sc, reg, bits)						\
106e1414c50Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
107e1414c50Skettenis 
108e1414c50Skettenis struct rkcomphy_softc {
109e1414c50Skettenis 	struct device		sc_dev;
110e1414c50Skettenis 	bus_space_tag_t		sc_iot;
111e1414c50Skettenis 	bus_space_handle_t	sc_ioh;
112e1414c50Skettenis 
113e1414c50Skettenis 	struct phy_device	sc_pd;
114e1414c50Skettenis };
115e1414c50Skettenis 
116e1414c50Skettenis int	rkcomphy_match(struct device *, void *, void *);
117e1414c50Skettenis void	rkcomphy_attach(struct device *, struct device *, void *);
118e1414c50Skettenis 
119e1414c50Skettenis const struct cfattach rkcomphy_ca = {
120e1414c50Skettenis 	sizeof (struct rkcomphy_softc), rkcomphy_match, rkcomphy_attach
121e1414c50Skettenis };
122e1414c50Skettenis 
123e1414c50Skettenis struct cfdriver rkcomphy_cd = {
124e1414c50Skettenis 	NULL, "rkcomphy", DV_DULL
125e1414c50Skettenis };
126e1414c50Skettenis 
127*4448ddbaSkettenis int	rkcomphy_rk3568_enable(void *, uint32_t *);
128*4448ddbaSkettenis int	rkcomphy_rk3588_enable(void *, uint32_t *);
129e1414c50Skettenis 
130e1414c50Skettenis int
rkcomphy_match(struct device * parent,void * match,void * aux)131e1414c50Skettenis rkcomphy_match(struct device *parent, void *match, void *aux)
132e1414c50Skettenis {
133e1414c50Skettenis 	struct fdt_attach_args *faa = aux;
134*4448ddbaSkettenis 	int node = faa->fa_node;
135e1414c50Skettenis 
136*4448ddbaSkettenis 	return OF_is_compatible(node, "rockchip,rk3568-naneng-combphy") ||
137*4448ddbaSkettenis 	    OF_is_compatible(node, "rockchip,rk3588-naneng-combphy");
138e1414c50Skettenis }
139e1414c50Skettenis 
140e1414c50Skettenis void
rkcomphy_attach(struct device * parent,struct device * self,void * aux)141e1414c50Skettenis rkcomphy_attach(struct device *parent, struct device *self, void *aux)
142e1414c50Skettenis {
143e1414c50Skettenis 	struct rkcomphy_softc *sc = (struct rkcomphy_softc *)self;
144e1414c50Skettenis 	struct fdt_attach_args *faa = aux;
145e1414c50Skettenis 
146e1414c50Skettenis 	if (faa->fa_nreg < 1) {
147e1414c50Skettenis 		printf(": no registers\n");
148e1414c50Skettenis 		return;
149e1414c50Skettenis 	}
150e1414c50Skettenis 
151e1414c50Skettenis 	sc->sc_iot = faa->fa_iot;
152e1414c50Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
153e1414c50Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
154e1414c50Skettenis 		printf(": can't map registers\n");
155e1414c50Skettenis 		return;
156e1414c50Skettenis 	}
157e1414c50Skettenis 
158e1414c50Skettenis 	reset_assert_all(faa->fa_node);
159e1414c50Skettenis 
160e1414c50Skettenis 	printf("\n");
161e1414c50Skettenis 
162e1414c50Skettenis 	sc->sc_pd.pd_node = faa->fa_node;
163e1414c50Skettenis 	sc->sc_pd.pd_cookie = sc;
164*4448ddbaSkettenis 	if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-naneng-combphy"))
165*4448ddbaSkettenis 	    sc->sc_pd.pd_enable = rkcomphy_rk3568_enable;
166*4448ddbaSkettenis 	else
167*4448ddbaSkettenis 	    sc->sc_pd.pd_enable = rkcomphy_rk3588_enable;
168e1414c50Skettenis 	phy_register(&sc->sc_pd);
169e1414c50Skettenis }
170e1414c50Skettenis 
171e1414c50Skettenis void
rkcomphy_rk3568_pll_tune(struct rkcomphy_softc * sc)172*4448ddbaSkettenis rkcomphy_rk3568_pll_tune(struct rkcomphy_softc *sc)
173e1414c50Skettenis {
174e1414c50Skettenis 	uint32_t reg;
175e1414c50Skettenis 
176e1414c50Skettenis 	reg = HREAD4(sc, COMBO_PIPE_PHY_REG(32));
177e1414c50Skettenis 	reg &= ~COMBO_PIPE_PHY_PLL_KVCO_MASK;
178e1414c50Skettenis 	reg |= COMBO_PIPE_PHY_PLL_KVCO_VALUE;
179e1414c50Skettenis 	HWRITE4(sc, COMBO_PIPE_PHY_REG(32), reg);
180e1414c50Skettenis 
181e1414c50Skettenis 	HWRITE4(sc, COMBO_PIPE_PHY_REG(11), COMBO_PIPE_PHY_PLL_LPF_ADJ_VALUE);
182e1414c50Skettenis 
183e1414c50Skettenis 	reg = HREAD4(sc, COMBO_PIPE_PHY_REG(5));
184e1414c50Skettenis 	reg &= ~COMBO_PIPE_PHY_PLL_DIV_MASK;
185e1414c50Skettenis 	reg |= COMBO_PIPE_PHY_PLL_DIV_2;
186e1414c50Skettenis 	HWRITE4(sc, COMBO_PIPE_PHY_REG(5), reg);
187e1414c50Skettenis 
188e1414c50Skettenis 	HWRITE4(sc, COMBO_PIPE_PHY_REG(17), COMBO_PIPE_PHY_PLL_LOOP);
189e1414c50Skettenis 	HWRITE4(sc, COMBO_PIPE_PHY_REG(10), COMBO_PIPE_PHY_SU_TRIM_0_7);
190e1414c50Skettenis }
191e1414c50Skettenis 
192e1414c50Skettenis int
rkcomphy_rk3568_enable(void * cookie,uint32_t * cells)193*4448ddbaSkettenis rkcomphy_rk3568_enable(void *cookie, uint32_t *cells)
194e1414c50Skettenis {
195e1414c50Skettenis 	struct rkcomphy_softc *sc = cookie;
196e1414c50Skettenis 	struct regmap *rm, *phy_rm;
197e1414c50Skettenis 	int node = sc->sc_pd.pd_node;
198e1414c50Skettenis 	uint32_t type = cells[0];
199e1414c50Skettenis 	uint32_t freq, grf, phy_grf, reg;
200e1414c50Skettenis 	int stat, timo;
201e1414c50Skettenis 
202e1414c50Skettenis 	/* We only support PCIe, SATA and USB 3 for now. */
203e1414c50Skettenis 	switch (type) {
204e1414c50Skettenis 	case PHY_TYPE_PCIE:
205e1414c50Skettenis 	case PHY_TYPE_SATA:
206e1414c50Skettenis 	case PHY_TYPE_USB3:
207e1414c50Skettenis 		break;
208e1414c50Skettenis 	default:
209e1414c50Skettenis 		return EINVAL;
210e1414c50Skettenis 	}
211e1414c50Skettenis 
212e1414c50Skettenis 	grf = OF_getpropint(node, "rockchip,pipe-grf", 0);
213e1414c50Skettenis 	rm = regmap_byphandle(grf);
214e1414c50Skettenis 	if (rm == NULL)
215e1414c50Skettenis 		return ENXIO;
216e1414c50Skettenis 
217e1414c50Skettenis 	phy_grf = OF_getpropint(node, "rockchip,pipe-phy-grf", 0);
218e1414c50Skettenis 	phy_rm = regmap_byphandle(phy_grf);
219e1414c50Skettenis 	if (phy_rm == NULL)
220e1414c50Skettenis 		return ENXIO;
221e1414c50Skettenis 
222e1414c50Skettenis 	clock_set_assigned(node);
223e1414c50Skettenis 	clock_enable_all(node);
224e1414c50Skettenis 
225e1414c50Skettenis 	if (type == PHY_TYPE_PCIE || type == PHY_TYPE_USB3) {
226e1414c50Skettenis 		reg = HREAD4(sc, COMBO_PIPE_PHY_REG(31));
227e1414c50Skettenis 		reg &= ~COMBO_PIPE_PHY_SSC_OFFSET_MASK;
228e1414c50Skettenis 		reg &= ~COMBO_PIPE_PHY_SSC_DIR_MASK;
229e1414c50Skettenis 		reg |= COMBO_PIPE_PHY_SSC_DIR_DOWN;
230e1414c50Skettenis 		HWRITE4(sc, COMBO_PIPE_PHY_REG(31), reg);
231e1414c50Skettenis 	}
232e1414c50Skettenis 
233e1414c50Skettenis 	if (type == PHY_TYPE_SATA || type == PHY_TYPE_USB3) {
234e1414c50Skettenis 		reg = HREAD4(sc, COMBO_PIPE_PHY_REG(14));
235e1414c50Skettenis 		reg |= COMBO_PIPE_PHY_CTLE_EN;
236e1414c50Skettenis 		HWRITE4(sc, COMBO_PIPE_PHY_REG(14), reg);
237e1414c50Skettenis 	}
238e1414c50Skettenis 
239e1414c50Skettenis 	switch (type) {
240e1414c50Skettenis 	case PHY_TYPE_PCIE:
241e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(0), 0xffff1000);
242e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1), 0xffff0000);
243e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(2), 0xffff0101);
244e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(3), 0xffff0200);
245e1414c50Skettenis 		break;
246e1414c50Skettenis 	case PHY_TYPE_SATA:
247e1414c50Skettenis 		HWRITE4(sc, COMBO_PIPE_PHY_REG(6),
248e1414c50Skettenis 		    COMBO_PIPE_PHY_TX_RTERM_50OHM |
249e1414c50Skettenis 		    COMBO_PIPE_PHY_RX_RTERM_44OHM);
250e1414c50Skettenis 
251e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(0), 0xffff0119);
252e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1), 0xffff0040);
253e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(2), 0xffff80c3);
254e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(3), 0xffff4407);
255e1414c50Skettenis 		regmap_write_4(rm, PIPE_GRF_PIPE_CON0, 0xffff2220);
256e1414c50Skettenis 		break;
257e1414c50Skettenis 	case PHY_TYPE_USB3:
258*4448ddbaSkettenis 		rkcomphy_rk3568_pll_tune(sc);
259e1414c50Skettenis 
260e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(0),
261e1414c50Skettenis 		    PIPE_PHY_GRF_PIPE_MODE_USB);
262e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(2),
263e1414c50Skettenis 		    PIPE_PHY_GRF_PIPE_TXCOMP_SEL_CTRL);
264e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(2),
265e1414c50Skettenis 		    PIPE_PHY_GRF_PIPE_TXELEC_SEL_CTRL);
266e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(3),
267e1414c50Skettenis 		    PIPE_PHY_GRF_PIPE_SEL_USB);
268e1414c50Skettenis 		break;
269e1414c50Skettenis 	}
270e1414c50Skettenis 
271e1414c50Skettenis 	freq = clock_get_frequency(node, "ref");
272e1414c50Skettenis 	switch (freq) {
273e1414c50Skettenis 	case 24000000:
274e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1),
275e1414c50Skettenis 		    PIPE_PHY_GRF_PIPE_CLK_24M);
276e1414c50Skettenis 		if (type == PHY_TYPE_SATA || type == PHY_TYPE_USB3) {
277e1414c50Skettenis 			reg = HREAD4(sc, COMBO_PIPE_PHY_REG(14));
278e1414c50Skettenis 			reg &= ~COMBO_PIPE_PHY_SSC_CNT_LO_MASK;
279e1414c50Skettenis 			reg |= COMBO_PIPE_PHY_SSC_CNT_LO_VALUE;
280e1414c50Skettenis 			HWRITE4(sc, COMBO_PIPE_PHY_REG(14), reg);
281e1414c50Skettenis 			reg = HREAD4(sc, COMBO_PIPE_PHY_REG(15));
282e1414c50Skettenis 			reg &= ~COMBO_PIPE_PHY_SSC_CNT_HI_MASK;
283e1414c50Skettenis 			reg |= COMBO_PIPE_PHY_SSC_CNT_HI_VALUE;
284e1414c50Skettenis 			HWRITE4(sc, COMBO_PIPE_PHY_REG(15), reg);
285e1414c50Skettenis 		}
286e1414c50Skettenis 		break;
287e1414c50Skettenis 	case 25000000:
288e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1),
289e1414c50Skettenis 		    PIPE_PHY_GRF_PIPE_CLK_25M);
290e1414c50Skettenis 		break;
291e1414c50Skettenis 	case 100000000:
292e1414c50Skettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1),
293e1414c50Skettenis 		    PIPE_PHY_GRF_PIPE_CLK_100M);
294e1414c50Skettenis 		switch (type) {
295e1414c50Skettenis 		case PHY_TYPE_PCIE:
296*4448ddbaSkettenis 			rkcomphy_rk3568_pll_tune(sc);
297e1414c50Skettenis 			break;
298e1414c50Skettenis 		case PHY_TYPE_SATA:
299e1414c50Skettenis 			reg = HREAD4(sc, COMBO_PIPE_PHY_REG(31));
300e1414c50Skettenis 			reg &= ~COMBO_PIPE_PHY_SSC_OFFSET_MASK;
301e1414c50Skettenis 			reg |= COMBO_PIPE_PHY_SSC_OFFSET_500PPM;
302e1414c50Skettenis 			reg &= ~COMBO_PIPE_PHY_SSC_DIR_MASK;
303e1414c50Skettenis 			reg |= COMBO_PIPE_PHY_SSC_DIR_DOWN;
304e1414c50Skettenis 			HWRITE4(sc, COMBO_PIPE_PHY_REG(31), reg);
305e1414c50Skettenis 			break;
306e1414c50Skettenis 		}
307e1414c50Skettenis 		break;
308e1414c50Skettenis 	}
309e1414c50Skettenis 
310e1414c50Skettenis 	reset_deassert_all(node);
311e1414c50Skettenis 
312e1414c50Skettenis 	if (type == PHY_TYPE_USB3) {
313e1414c50Skettenis 		for (timo = 100; timo > 0; timo--) {
314e1414c50Skettenis 			stat = regmap_read_4(phy_rm,
315e1414c50Skettenis 			    PIPE_PHY_GRF_PIPE_STATUS1);
316e1414c50Skettenis 			if ((stat & PIPE_PHY_GRF_PIPE_PHYSTATUS) == 0)
317e1414c50Skettenis 				break;
318e1414c50Skettenis 			delay(10);
319e1414c50Skettenis 		}
320e1414c50Skettenis 		if (timo == 0) {
321e1414c50Skettenis 			printf("%s: timeout\n", sc->sc_dev.dv_xname);
322e1414c50Skettenis 			return ETIMEDOUT;
323e1414c50Skettenis 		}
324e1414c50Skettenis 	}
325e1414c50Skettenis 
326e1414c50Skettenis 	return 0;
327e1414c50Skettenis }
328*4448ddbaSkettenis 
329*4448ddbaSkettenis void
rkcomphy_rk3588_pll_tune(struct rkcomphy_softc * sc)330*4448ddbaSkettenis rkcomphy_rk3588_pll_tune(struct rkcomphy_softc *sc)
331*4448ddbaSkettenis {
332*4448ddbaSkettenis 	uint32_t reg;
333*4448ddbaSkettenis 
334*4448ddbaSkettenis 	reg = HREAD4(sc, COMBO_PIPE_PHY_REG(32));
335*4448ddbaSkettenis 	reg &= ~COMBO_PIPE_PHY_PLL_KVCO_MASK;
336*4448ddbaSkettenis 	reg |= COMBO_PIPE_PHY_PLL_KVCO_VALUE_RK3588;
337*4448ddbaSkettenis 	HWRITE4(sc, COMBO_PIPE_PHY_REG(32), reg);
338*4448ddbaSkettenis 
339*4448ddbaSkettenis 	HWRITE4(sc, COMBO_PIPE_PHY_REG(11), COMBO_PIPE_PHY_PLL_LPF_ADJ_VALUE);
340*4448ddbaSkettenis 
341*4448ddbaSkettenis 	HWRITE4(sc, COMBO_PIPE_PHY_REG(27), COMBO_PIPE_PHY_RX_TRIM_RK3588);
342*4448ddbaSkettenis 	HWRITE4(sc, COMBO_PIPE_PHY_REG(10), COMBO_PIPE_PHY_SU_TRIM_0_7);
343*4448ddbaSkettenis }
344*4448ddbaSkettenis 
345*4448ddbaSkettenis int
rkcomphy_rk3588_enable(void * cookie,uint32_t * cells)346*4448ddbaSkettenis rkcomphy_rk3588_enable(void *cookie, uint32_t *cells)
347*4448ddbaSkettenis {
348*4448ddbaSkettenis 	struct rkcomphy_softc *sc = cookie;
349*4448ddbaSkettenis 	struct regmap *rm, *phy_rm;
350*4448ddbaSkettenis 	int node = sc->sc_pd.pd_node;
351*4448ddbaSkettenis 	uint32_t type = cells[0];
352*4448ddbaSkettenis 	uint32_t freq, grf, phy_grf;
353*4448ddbaSkettenis 
354*4448ddbaSkettenis 	/* We only support PCIe for now. */
355*4448ddbaSkettenis 	switch (type) {
356*4448ddbaSkettenis 	case PHY_TYPE_PCIE:
357*4448ddbaSkettenis 		break;
358*4448ddbaSkettenis 	default:
359*4448ddbaSkettenis 		return EINVAL;
360*4448ddbaSkettenis 	}
361*4448ddbaSkettenis 
362*4448ddbaSkettenis 	grf = OF_getpropint(node, "rockchip,pipe-grf", 0);
363*4448ddbaSkettenis 	rm = regmap_byphandle(grf);
364*4448ddbaSkettenis 	if (rm == NULL)
365*4448ddbaSkettenis 		return ENXIO;
366*4448ddbaSkettenis 
367*4448ddbaSkettenis 	phy_grf = OF_getpropint(node, "rockchip,pipe-phy-grf", 0);
368*4448ddbaSkettenis 	phy_rm = regmap_byphandle(phy_grf);
369*4448ddbaSkettenis 	if (phy_rm == NULL)
370*4448ddbaSkettenis 		return ENXIO;
371*4448ddbaSkettenis 
372*4448ddbaSkettenis 	clock_set_assigned(node);
373*4448ddbaSkettenis 	clock_enable_all(node);
374*4448ddbaSkettenis 
375*4448ddbaSkettenis 	switch (type) {
376*4448ddbaSkettenis 	case PHY_TYPE_PCIE:
377*4448ddbaSkettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(0), 0xffff1000);
378*4448ddbaSkettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1), 0xffff0000);
379*4448ddbaSkettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(2), 0xffff0101);
380*4448ddbaSkettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(3), 0xffff0200);
381*4448ddbaSkettenis 		regmap_write_4(rm, PHP_GRF_PCIESEL_CON, 0x00010000);
382*4448ddbaSkettenis 		regmap_write_4(rm, PHP_GRF_PCIESEL_CON, 0x00020000);
383*4448ddbaSkettenis 		break;
384*4448ddbaSkettenis 	}
385*4448ddbaSkettenis 
386*4448ddbaSkettenis 	freq = clock_get_frequency(node, "ref");
387*4448ddbaSkettenis 	switch (freq) {
388*4448ddbaSkettenis 	case 25000000:
389*4448ddbaSkettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1),
390*4448ddbaSkettenis 		    PIPE_PHY_GRF_PIPE_CLK_25M);
391*4448ddbaSkettenis 		break;
392*4448ddbaSkettenis 	case 100000000:
393*4448ddbaSkettenis 		regmap_write_4(phy_rm, PIPE_PHY_GRF_PIPE_CON(1),
394*4448ddbaSkettenis 		    PIPE_PHY_GRF_PIPE_CLK_100M);
395*4448ddbaSkettenis 		switch (type) {
396*4448ddbaSkettenis 		case PHY_TYPE_PCIE:
397*4448ddbaSkettenis 			rkcomphy_rk3588_pll_tune(sc);
398*4448ddbaSkettenis 			break;
399*4448ddbaSkettenis 		}
400*4448ddbaSkettenis 	}
401*4448ddbaSkettenis 
402*4448ddbaSkettenis 	reset_deassert_all(node);
403*4448ddbaSkettenis 
404*4448ddbaSkettenis 	return 0;
405*4448ddbaSkettenis }
406