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