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