1*0f9e9ec2Sjsg /* $OpenBSD: amlusbphy.c,v 1.4 2024/05/13 01:15:50 jsg Exp $ */
2ac37a22fSkettenis /*
3ac37a22fSkettenis * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org>
4ac37a22fSkettenis *
5ac37a22fSkettenis * Permission to use, copy, modify, and distribute this software for any
6ac37a22fSkettenis * purpose with or without fee is hereby granted, provided that the above
7ac37a22fSkettenis * copyright notice and this permission notice appear in all copies.
8ac37a22fSkettenis *
9ac37a22fSkettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10ac37a22fSkettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ac37a22fSkettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ac37a22fSkettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ac37a22fSkettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ac37a22fSkettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15ac37a22fSkettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ac37a22fSkettenis */
17ac37a22fSkettenis
18ac37a22fSkettenis #include <sys/param.h>
19ac37a22fSkettenis #include <sys/systm.h>
20ac37a22fSkettenis #include <sys/device.h>
21ac37a22fSkettenis
22ac37a22fSkettenis #include <machine/intr.h>
23ac37a22fSkettenis #include <machine/bus.h>
24ac37a22fSkettenis #include <machine/fdt.h>
25ac37a22fSkettenis
26ac37a22fSkettenis #include <dev/ofw/openfirm.h>
27ac37a22fSkettenis #include <dev/ofw/ofw_clock.h>
28ac37a22fSkettenis #include <dev/ofw/ofw_misc.h>
29ac37a22fSkettenis #include <dev/ofw/ofw_regulator.h>
30ac37a22fSkettenis #include <dev/ofw/fdt.h>
31ac37a22fSkettenis
32ac37a22fSkettenis /* Registers */
33ac37a22fSkettenis #define PHY_R3 0x0c
34ac37a22fSkettenis #define PHY_R3_SQUELCH_REF_SHIFT 0
35ac37a22fSkettenis #define PHY_R3_HDISC_REF_SHIFT 2
36ac37a22fSkettenis #define PHY_R3_DISC_THRESH_SHIFT 4
37ac37a22fSkettenis #define PHY_R4 0x10
38ac37a22fSkettenis #define PHY_R4_CALIB_CODE_SHIFT 0
39ac37a22fSkettenis #define PHY_R4_TEST_BYPASS_MODE_EN (1 << 27)
40ac37a22fSkettenis #define PHY_R4_I_C2L_BIAS_TRIM_SHIFT 28
41ac37a22fSkettenis #define PHY_R13 0x34
42ac37a22fSkettenis #define PHY_R13_UPDATE_PMA_SIGNALS (1 << 15)
43ac37a22fSkettenis #define PHY_R13_MIN_COUNT_FOR_SYNC_DET_SHIFT 16
44ac37a22fSkettenis #define PHY_R14 0x38
45ac37a22fSkettenis #define PHY_R16 0x40
46ac37a22fSkettenis #define PHY_R16_MPLL_M_SHIFT 0
47ac37a22fSkettenis #define PHY_R16_MPLL_N_SHIFT 10
48ac37a22fSkettenis #define PHY_R16_MPLL_LOAD (1 << 22)
49ac37a22fSkettenis #define PHY_R16_MPLL_LOCK_LONG_SHIFT 24
50ac37a22fSkettenis #define PHY_R16_MPLL_FAST_LOCK (1 << 27)
51ac37a22fSkettenis #define PHY_R16_MPLL_EN (1 << 28)
52ac37a22fSkettenis #define PHY_R16_MPLL_RESET (1 << 29)
53ac37a22fSkettenis #define PHY_R17 0x44
54ac37a22fSkettenis #define PHY_R17_MPLL_FRAC_IN_SHIFT 0
55ac37a22fSkettenis #define PHY_R17_MPLL_LAMBDA1_SHIFT 17
56ac37a22fSkettenis #define PHY_R17_MPLL_LAMBDA0_SHIFT 20
57ac37a22fSkettenis #define PHY_R17_MPLL_FILTER_PVT2_SHIFT 24
58ac37a22fSkettenis #define PHY_R17_MPLL_FILTER_PVT1_SHIFT 28
59ac37a22fSkettenis #define PHY_R18 0x48
60ac37a22fSkettenis #define PHY_R18_MPLL_LKW_SEL_SHIFT 0
61ac37a22fSkettenis #define PHY_R18_MPLL_LK_W_SHIFT 2
62ac37a22fSkettenis #define PHY_R18_MPLL_LK_S_SHIFT 6
63ac37a22fSkettenis #define PHY_R18_MPLL_PFD_GAIN_SHIFT 14
64ac37a22fSkettenis #define PHY_R18_MPLL_ROU_SHIFT 16
65ac37a22fSkettenis #define PHY_R18_MPLL_DATA_SEL_SHIFT 19
66ac37a22fSkettenis #define PHY_R18_MPLL_BIAS_ADJ_SHIFT 22
67ac37a22fSkettenis #define PHY_R18_MPLL_BB_MODE_SHIFT 24
68ac37a22fSkettenis #define PHY_R18_MPLL_ALPHA_SHIFT 26
69ac37a22fSkettenis #define PHY_R18_MPLL_ADJ_LDO_SHIFT 29
70ac37a22fSkettenis #define PHY_R18_MPLL_ACG_RANGE (1U << 31)
71ac37a22fSkettenis #define PHY_R20 0x50
72ac37a22fSkettenis #define PHY_R20_USB2_ITG_VBUS_TRIM_SHIFT 1
73ac37a22fSkettenis #define PHY_R20_USB2_OTG_VBUSDET_EN (1 << 4)
74ac37a22fSkettenis #define PHY_R20_USB2_DMON_SEL_SHIFT 9
75ac37a22fSkettenis #define PHY_R20_USB2_EDGE_DRV_EN (1 << 13)
76ac37a22fSkettenis #define PHY_R20_USB2_EDGE_DRV_TRIM_SHIFT 14
77ac37a22fSkettenis #define PHY_R20_USB2_BGR_ADJ_SHIFT 16
78ac37a22fSkettenis #define PHY_R20_USB2_BGR_VREF_SHIFT 24
79ac37a22fSkettenis #define PHY_R20_USB2_BGR_DBG_SHIFT 29
80ac37a22fSkettenis #define PHY_R21 0x54
81ac37a22fSkettenis #define PHY_R21_USB2_OTG_ACA_EN (1 << 2)
82ac37a22fSkettenis
83ac37a22fSkettenis #define HREAD4(sc, reg) \
84ac37a22fSkettenis (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
85ac37a22fSkettenis #define HWRITE4(sc, reg, val) \
86ac37a22fSkettenis bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
87ac37a22fSkettenis #define HSET4(sc, reg, bits) \
88ac37a22fSkettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
89ac37a22fSkettenis #define HCLR4(sc, reg, bits) \
90ac37a22fSkettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
91ac37a22fSkettenis
92ac37a22fSkettenis struct amlusbphy_softc {
93ac37a22fSkettenis struct device sc_dev;
94ac37a22fSkettenis bus_space_tag_t sc_iot;
95ac37a22fSkettenis bus_space_handle_t sc_ioh;
96ac37a22fSkettenis
97ac37a22fSkettenis struct phy_device sc_pd;
98ac37a22fSkettenis };
99ac37a22fSkettenis
100ac37a22fSkettenis int amlusbphy_match(struct device *, void *, void *);
101ac37a22fSkettenis void amlusbphy_attach(struct device *, struct device *, void *);
102ac37a22fSkettenis
1039fdf0c62Smpi const struct cfattach amlusbphy_ca = {
104ac37a22fSkettenis sizeof (struct amlusbphy_softc), amlusbphy_match, amlusbphy_attach
105ac37a22fSkettenis };
106ac37a22fSkettenis
107ac37a22fSkettenis struct cfdriver amlusbphy_cd = {
108ac37a22fSkettenis NULL, "amlusbphy", DV_DULL
109ac37a22fSkettenis };
110ac37a22fSkettenis
111ac37a22fSkettenis int amlusbphy_enable(void *, uint32_t *);
112ac37a22fSkettenis
113ac37a22fSkettenis int
amlusbphy_match(struct device * parent,void * match,void * aux)114ac37a22fSkettenis amlusbphy_match(struct device *parent, void *match, void *aux)
115ac37a22fSkettenis {
116ac37a22fSkettenis struct fdt_attach_args *faa = aux;
117ac37a22fSkettenis
118ac37a22fSkettenis return OF_is_compatible(faa->fa_node, "amlogic,g12a-usb2-phy");
119ac37a22fSkettenis }
120ac37a22fSkettenis
121ac37a22fSkettenis void
amlusbphy_attach(struct device * parent,struct device * self,void * aux)122ac37a22fSkettenis amlusbphy_attach(struct device *parent, struct device *self, void *aux)
123ac37a22fSkettenis {
124ac37a22fSkettenis struct amlusbphy_softc *sc = (struct amlusbphy_softc *)self;
125ac37a22fSkettenis struct fdt_attach_args *faa = aux;
126ac37a22fSkettenis
127ac37a22fSkettenis if (faa->fa_nreg < 1) {
128ac37a22fSkettenis printf(": no registers\n");
129ac37a22fSkettenis return;
130ac37a22fSkettenis }
131ac37a22fSkettenis
132ac37a22fSkettenis sc->sc_iot = faa->fa_iot;
133ac37a22fSkettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
134ac37a22fSkettenis faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
135ac37a22fSkettenis printf(": can't map registers\n");
136ac37a22fSkettenis return;
137ac37a22fSkettenis }
138ac37a22fSkettenis
139ac37a22fSkettenis printf("\n");
140ac37a22fSkettenis
141ac37a22fSkettenis sc->sc_pd.pd_node = faa->fa_node;
142ac37a22fSkettenis sc->sc_pd.pd_cookie = sc;
143ac37a22fSkettenis sc->sc_pd.pd_enable = amlusbphy_enable;
144ac37a22fSkettenis phy_register(&sc->sc_pd);
145ac37a22fSkettenis }
146ac37a22fSkettenis
147ac37a22fSkettenis int
amlusbphy_enable(void * cookie,uint32_t * cells)148ac37a22fSkettenis amlusbphy_enable(void *cookie, uint32_t *cells)
149ac37a22fSkettenis {
150ac37a22fSkettenis struct amlusbphy_softc *sc = cookie;
151ac37a22fSkettenis int node = sc->sc_pd.pd_node;
152ac37a22fSkettenis uint32_t phy_supply;
153ac37a22fSkettenis
154ac37a22fSkettenis clock_enable_all(node);
155ac37a22fSkettenis
156ac37a22fSkettenis reset_assert_all(node);
157ac37a22fSkettenis delay(10);
158ac37a22fSkettenis reset_deassert_all(node);
159ac37a22fSkettenis delay(1000);
160ac37a22fSkettenis
161ac37a22fSkettenis phy_supply = OF_getpropint(node, "phy-supply", 0);
162ac37a22fSkettenis if (phy_supply)
163ac37a22fSkettenis regulator_enable(phy_supply);
164ac37a22fSkettenis
165ac37a22fSkettenis HCLR4(sc, PHY_R21, PHY_R21_USB2_OTG_ACA_EN);
166ac37a22fSkettenis
167ac37a22fSkettenis /* Set PLL to 480 MHz. */
168ac37a22fSkettenis HWRITE4(sc, PHY_R16, (20 << PHY_R16_MPLL_M_SHIFT) |
169ac37a22fSkettenis (1 << PHY_R16_MPLL_N_SHIFT) | PHY_R16_MPLL_LOAD |
170ac37a22fSkettenis (1 << PHY_R16_MPLL_LOCK_LONG_SHIFT) | PHY_R16_MPLL_FAST_LOCK |
171ac37a22fSkettenis PHY_R16_MPLL_EN | PHY_R16_MPLL_RESET);
172ac37a22fSkettenis HWRITE4(sc, PHY_R17, (0 << PHY_R17_MPLL_FRAC_IN_SHIFT) |
173ac37a22fSkettenis (7 << PHY_R17_MPLL_LAMBDA0_SHIFT) |
174ac37a22fSkettenis (7 << PHY_R17_MPLL_LAMBDA1_SHIFT) |
175ac37a22fSkettenis (9 << PHY_R17_MPLL_FILTER_PVT1_SHIFT) |
176ac37a22fSkettenis (2 << PHY_R17_MPLL_FILTER_PVT2_SHIFT));
177ac37a22fSkettenis HWRITE4(sc, PHY_R18, (1 << PHY_R18_MPLL_LKW_SEL_SHIFT) |
178ac37a22fSkettenis (9 << PHY_R18_MPLL_LK_W_SHIFT) | (39 << PHY_R18_MPLL_LK_S_SHIFT) |
179ac37a22fSkettenis (1 << PHY_R18_MPLL_PFD_GAIN_SHIFT) |
180ac37a22fSkettenis (7 << PHY_R18_MPLL_ROU_SHIFT) |
181ac37a22fSkettenis (3 << PHY_R18_MPLL_DATA_SEL_SHIFT) |
182ac37a22fSkettenis (1 << PHY_R18_MPLL_BIAS_ADJ_SHIFT) |
183ac37a22fSkettenis (0 << PHY_R18_MPLL_BB_MODE_SHIFT) |
184ac37a22fSkettenis (3 << PHY_R18_MPLL_ALPHA_SHIFT) |
185ac37a22fSkettenis (1 << PHY_R18_MPLL_ADJ_LDO_SHIFT) |
186ac37a22fSkettenis PHY_R18_MPLL_ACG_RANGE);
187ac37a22fSkettenis delay(100);
188ac37a22fSkettenis HWRITE4(sc, PHY_R16, (20 << PHY_R16_MPLL_M_SHIFT) |
189ac37a22fSkettenis (1 << PHY_R16_MPLL_N_SHIFT) | PHY_R16_MPLL_LOAD |
190ac37a22fSkettenis (1 << PHY_R16_MPLL_LOCK_LONG_SHIFT) | PHY_R16_MPLL_FAST_LOCK |
191ac37a22fSkettenis PHY_R16_MPLL_EN);
192ac37a22fSkettenis
193ac37a22fSkettenis /* Tune PHY. */
194ac37a22fSkettenis HWRITE4(sc, PHY_R20, (4 << PHY_R20_USB2_ITG_VBUS_TRIM_SHIFT) |
195ac37a22fSkettenis PHY_R20_USB2_OTG_VBUSDET_EN | (15 << PHY_R20_USB2_DMON_SEL_SHIFT) |
196ac37a22fSkettenis PHY_R20_USB2_EDGE_DRV_EN |
197ac37a22fSkettenis (3 << PHY_R20_USB2_EDGE_DRV_TRIM_SHIFT) |
198ac37a22fSkettenis (0 << PHY_R20_USB2_BGR_ADJ_SHIFT) |
199ac37a22fSkettenis (0 << PHY_R20_USB2_BGR_VREF_SHIFT) |
200ac37a22fSkettenis (0 << PHY_R20_USB2_BGR_DBG_SHIFT));
201ac37a22fSkettenis HWRITE4(sc, PHY_R4, (0xfff << PHY_R4_CALIB_CODE_SHIFT) |
202ac37a22fSkettenis PHY_R4_TEST_BYPASS_MODE_EN |
203ac37a22fSkettenis (0 << PHY_R4_I_C2L_BIAS_TRIM_SHIFT));
204ac37a22fSkettenis
205ac37a22fSkettenis /* Tune disconnect threshold. */
206ac37a22fSkettenis HWRITE4(sc, PHY_R3, (0 << PHY_R3_SQUELCH_REF_SHIFT) |
207ac37a22fSkettenis (1 << PHY_R3_HDISC_REF_SHIFT) | (3 << PHY_R3_DISC_THRESH_SHIFT));
208ac37a22fSkettenis
2094b1a56afSjsg /* Analog settings. */
210ac37a22fSkettenis HWRITE4(sc, PHY_R14, 0);
211ac37a22fSkettenis HWRITE4(sc, PHY_R13, PHY_R13_UPDATE_PMA_SIGNALS |
212ac37a22fSkettenis (7 << PHY_R13_MIN_COUNT_FOR_SYNC_DET_SHIFT));
213ac37a22fSkettenis
214ac37a22fSkettenis return 0;
215ac37a22fSkettenis }
216