1 /* $OpenBSD: amlusbphy.c,v 1.4 2024/05/13 01:15:50 jsg Exp $ */
2 /*
3 * Copyright (c) 2019 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/ofw_regulator.h>
30 #include <dev/ofw/fdt.h>
31
32 /* Registers */
33 #define PHY_R3 0x0c
34 #define PHY_R3_SQUELCH_REF_SHIFT 0
35 #define PHY_R3_HDISC_REF_SHIFT 2
36 #define PHY_R3_DISC_THRESH_SHIFT 4
37 #define PHY_R4 0x10
38 #define PHY_R4_CALIB_CODE_SHIFT 0
39 #define PHY_R4_TEST_BYPASS_MODE_EN (1 << 27)
40 #define PHY_R4_I_C2L_BIAS_TRIM_SHIFT 28
41 #define PHY_R13 0x34
42 #define PHY_R13_UPDATE_PMA_SIGNALS (1 << 15)
43 #define PHY_R13_MIN_COUNT_FOR_SYNC_DET_SHIFT 16
44 #define PHY_R14 0x38
45 #define PHY_R16 0x40
46 #define PHY_R16_MPLL_M_SHIFT 0
47 #define PHY_R16_MPLL_N_SHIFT 10
48 #define PHY_R16_MPLL_LOAD (1 << 22)
49 #define PHY_R16_MPLL_LOCK_LONG_SHIFT 24
50 #define PHY_R16_MPLL_FAST_LOCK (1 << 27)
51 #define PHY_R16_MPLL_EN (1 << 28)
52 #define PHY_R16_MPLL_RESET (1 << 29)
53 #define PHY_R17 0x44
54 #define PHY_R17_MPLL_FRAC_IN_SHIFT 0
55 #define PHY_R17_MPLL_LAMBDA1_SHIFT 17
56 #define PHY_R17_MPLL_LAMBDA0_SHIFT 20
57 #define PHY_R17_MPLL_FILTER_PVT2_SHIFT 24
58 #define PHY_R17_MPLL_FILTER_PVT1_SHIFT 28
59 #define PHY_R18 0x48
60 #define PHY_R18_MPLL_LKW_SEL_SHIFT 0
61 #define PHY_R18_MPLL_LK_W_SHIFT 2
62 #define PHY_R18_MPLL_LK_S_SHIFT 6
63 #define PHY_R18_MPLL_PFD_GAIN_SHIFT 14
64 #define PHY_R18_MPLL_ROU_SHIFT 16
65 #define PHY_R18_MPLL_DATA_SEL_SHIFT 19
66 #define PHY_R18_MPLL_BIAS_ADJ_SHIFT 22
67 #define PHY_R18_MPLL_BB_MODE_SHIFT 24
68 #define PHY_R18_MPLL_ALPHA_SHIFT 26
69 #define PHY_R18_MPLL_ADJ_LDO_SHIFT 29
70 #define PHY_R18_MPLL_ACG_RANGE (1U << 31)
71 #define PHY_R20 0x50
72 #define PHY_R20_USB2_ITG_VBUS_TRIM_SHIFT 1
73 #define PHY_R20_USB2_OTG_VBUSDET_EN (1 << 4)
74 #define PHY_R20_USB2_DMON_SEL_SHIFT 9
75 #define PHY_R20_USB2_EDGE_DRV_EN (1 << 13)
76 #define PHY_R20_USB2_EDGE_DRV_TRIM_SHIFT 14
77 #define PHY_R20_USB2_BGR_ADJ_SHIFT 16
78 #define PHY_R20_USB2_BGR_VREF_SHIFT 24
79 #define PHY_R20_USB2_BGR_DBG_SHIFT 29
80 #define PHY_R21 0x54
81 #define PHY_R21_USB2_OTG_ACA_EN (1 << 2)
82
83 #define HREAD4(sc, reg) \
84 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
85 #define HWRITE4(sc, reg, val) \
86 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
87 #define HSET4(sc, reg, bits) \
88 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
89 #define HCLR4(sc, reg, bits) \
90 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
91
92 struct amlusbphy_softc {
93 struct device sc_dev;
94 bus_space_tag_t sc_iot;
95 bus_space_handle_t sc_ioh;
96
97 struct phy_device sc_pd;
98 };
99
100 int amlusbphy_match(struct device *, void *, void *);
101 void amlusbphy_attach(struct device *, struct device *, void *);
102
103 const struct cfattach amlusbphy_ca = {
104 sizeof (struct amlusbphy_softc), amlusbphy_match, amlusbphy_attach
105 };
106
107 struct cfdriver amlusbphy_cd = {
108 NULL, "amlusbphy", DV_DULL
109 };
110
111 int amlusbphy_enable(void *, uint32_t *);
112
113 int
amlusbphy_match(struct device * parent,void * match,void * aux)114 amlusbphy_match(struct device *parent, void *match, void *aux)
115 {
116 struct fdt_attach_args *faa = aux;
117
118 return OF_is_compatible(faa->fa_node, "amlogic,g12a-usb2-phy");
119 }
120
121 void
amlusbphy_attach(struct device * parent,struct device * self,void * aux)122 amlusbphy_attach(struct device *parent, struct device *self, void *aux)
123 {
124 struct amlusbphy_softc *sc = (struct amlusbphy_softc *)self;
125 struct fdt_attach_args *faa = aux;
126
127 if (faa->fa_nreg < 1) {
128 printf(": no registers\n");
129 return;
130 }
131
132 sc->sc_iot = faa->fa_iot;
133 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
134 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
135 printf(": can't map registers\n");
136 return;
137 }
138
139 printf("\n");
140
141 sc->sc_pd.pd_node = faa->fa_node;
142 sc->sc_pd.pd_cookie = sc;
143 sc->sc_pd.pd_enable = amlusbphy_enable;
144 phy_register(&sc->sc_pd);
145 }
146
147 int
amlusbphy_enable(void * cookie,uint32_t * cells)148 amlusbphy_enable(void *cookie, uint32_t *cells)
149 {
150 struct amlusbphy_softc *sc = cookie;
151 int node = sc->sc_pd.pd_node;
152 uint32_t phy_supply;
153
154 clock_enable_all(node);
155
156 reset_assert_all(node);
157 delay(10);
158 reset_deassert_all(node);
159 delay(1000);
160
161 phy_supply = OF_getpropint(node, "phy-supply", 0);
162 if (phy_supply)
163 regulator_enable(phy_supply);
164
165 HCLR4(sc, PHY_R21, PHY_R21_USB2_OTG_ACA_EN);
166
167 /* Set PLL to 480 MHz. */
168 HWRITE4(sc, PHY_R16, (20 << PHY_R16_MPLL_M_SHIFT) |
169 (1 << PHY_R16_MPLL_N_SHIFT) | PHY_R16_MPLL_LOAD |
170 (1 << PHY_R16_MPLL_LOCK_LONG_SHIFT) | PHY_R16_MPLL_FAST_LOCK |
171 PHY_R16_MPLL_EN | PHY_R16_MPLL_RESET);
172 HWRITE4(sc, PHY_R17, (0 << PHY_R17_MPLL_FRAC_IN_SHIFT) |
173 (7 << PHY_R17_MPLL_LAMBDA0_SHIFT) |
174 (7 << PHY_R17_MPLL_LAMBDA1_SHIFT) |
175 (9 << PHY_R17_MPLL_FILTER_PVT1_SHIFT) |
176 (2 << PHY_R17_MPLL_FILTER_PVT2_SHIFT));
177 HWRITE4(sc, PHY_R18, (1 << PHY_R18_MPLL_LKW_SEL_SHIFT) |
178 (9 << PHY_R18_MPLL_LK_W_SHIFT) | (39 << PHY_R18_MPLL_LK_S_SHIFT) |
179 (1 << PHY_R18_MPLL_PFD_GAIN_SHIFT) |
180 (7 << PHY_R18_MPLL_ROU_SHIFT) |
181 (3 << PHY_R18_MPLL_DATA_SEL_SHIFT) |
182 (1 << PHY_R18_MPLL_BIAS_ADJ_SHIFT) |
183 (0 << PHY_R18_MPLL_BB_MODE_SHIFT) |
184 (3 << PHY_R18_MPLL_ALPHA_SHIFT) |
185 (1 << PHY_R18_MPLL_ADJ_LDO_SHIFT) |
186 PHY_R18_MPLL_ACG_RANGE);
187 delay(100);
188 HWRITE4(sc, PHY_R16, (20 << PHY_R16_MPLL_M_SHIFT) |
189 (1 << PHY_R16_MPLL_N_SHIFT) | PHY_R16_MPLL_LOAD |
190 (1 << PHY_R16_MPLL_LOCK_LONG_SHIFT) | PHY_R16_MPLL_FAST_LOCK |
191 PHY_R16_MPLL_EN);
192
193 /* Tune PHY. */
194 HWRITE4(sc, PHY_R20, (4 << PHY_R20_USB2_ITG_VBUS_TRIM_SHIFT) |
195 PHY_R20_USB2_OTG_VBUSDET_EN | (15 << PHY_R20_USB2_DMON_SEL_SHIFT) |
196 PHY_R20_USB2_EDGE_DRV_EN |
197 (3 << PHY_R20_USB2_EDGE_DRV_TRIM_SHIFT) |
198 (0 << PHY_R20_USB2_BGR_ADJ_SHIFT) |
199 (0 << PHY_R20_USB2_BGR_VREF_SHIFT) |
200 (0 << PHY_R20_USB2_BGR_DBG_SHIFT));
201 HWRITE4(sc, PHY_R4, (0xfff << PHY_R4_CALIB_CODE_SHIFT) |
202 PHY_R4_TEST_BYPASS_MODE_EN |
203 (0 << PHY_R4_I_C2L_BIAS_TRIM_SHIFT));
204
205 /* Tune disconnect threshold. */
206 HWRITE4(sc, PHY_R3, (0 << PHY_R3_SQUELCH_REF_SHIFT) |
207 (1 << PHY_R3_HDISC_REF_SHIFT) | (3 << PHY_R3_DISC_THRESH_SHIFT));
208
209 /* Analog settings. */
210 HWRITE4(sc, PHY_R14, 0);
211 HWRITE4(sc, PHY_R13, PHY_R13_UPDATE_PMA_SIGNALS |
212 (7 << PHY_R13_MIN_COUNT_FOR_SYNC_DET_SHIFT));
213
214 return 0;
215 }
216