xref: /openbsd/sys/dev/fdt/amlusbphy.c (revision 274d7c50)
1 /*	$OpenBSD: amlusbphy.c,v 1.1 2019/08/29 17:20:03 kettenis 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 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 uint16_t amlusbphy_read(struct amlusbphy_softc *, bus_addr_t);
113 void	amlusbphy_write(struct amlusbphy_softc *, bus_addr_t, uint16_t);
114 
115 int
116 amlusbphy_match(struct device *parent, void *match, void *aux)
117 {
118 	struct fdt_attach_args *faa = aux;
119 
120 	return OF_is_compatible(faa->fa_node, "amlogic,g12a-usb2-phy");
121 }
122 
123 void
124 amlusbphy_attach(struct device *parent, struct device *self, void *aux)
125 {
126 	struct amlusbphy_softc *sc = (struct amlusbphy_softc *)self;
127 	struct fdt_attach_args *faa = aux;
128 
129 	if (faa->fa_nreg < 1) {
130 		printf(": no registers\n");
131 		return;
132 	}
133 
134 	sc->sc_iot = faa->fa_iot;
135 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
136 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
137 		printf(": can't map registers\n");
138 		return;
139 	}
140 
141 	printf("\n");
142 
143 	sc->sc_pd.pd_node = faa->fa_node;
144 	sc->sc_pd.pd_cookie = sc;
145 	sc->sc_pd.pd_enable = amlusbphy_enable;
146 	phy_register(&sc->sc_pd);
147 }
148 
149 int
150 amlusbphy_enable(void *cookie, uint32_t *cells)
151 {
152 	struct amlusbphy_softc *sc = cookie;
153 	int node = sc->sc_pd.pd_node;
154 	uint32_t phy_supply;
155 
156 	clock_enable_all(node);
157 
158 	reset_assert_all(node);
159 	delay(10);
160 	reset_deassert_all(node);
161 	delay(1000);
162 
163 	phy_supply = OF_getpropint(node, "phy-supply", 0);
164 	if (phy_supply)
165 		regulator_enable(phy_supply);
166 
167 	HCLR4(sc, PHY_R21, PHY_R21_USB2_OTG_ACA_EN);
168 
169 	/* Set PLL to 480 MHz. */
170 	HWRITE4(sc, PHY_R16, (20 << PHY_R16_MPLL_M_SHIFT) |
171 	    (1 << PHY_R16_MPLL_N_SHIFT) | PHY_R16_MPLL_LOAD |
172 	    (1 << PHY_R16_MPLL_LOCK_LONG_SHIFT) | PHY_R16_MPLL_FAST_LOCK |
173 	    PHY_R16_MPLL_EN | PHY_R16_MPLL_RESET);
174 	HWRITE4(sc, PHY_R17, (0 << PHY_R17_MPLL_FRAC_IN_SHIFT) |
175 	    (7 << PHY_R17_MPLL_LAMBDA0_SHIFT) |
176 	    (7 << PHY_R17_MPLL_LAMBDA1_SHIFT) |
177 	    (9 << PHY_R17_MPLL_FILTER_PVT1_SHIFT) |
178 	    (2 << PHY_R17_MPLL_FILTER_PVT2_SHIFT));
179 	HWRITE4(sc, PHY_R18, (1 << PHY_R18_MPLL_LKW_SEL_SHIFT) |
180 	    (9 << PHY_R18_MPLL_LK_W_SHIFT) | (39 << PHY_R18_MPLL_LK_S_SHIFT) |
181 	    (1 << PHY_R18_MPLL_PFD_GAIN_SHIFT) |
182 	    (7 << PHY_R18_MPLL_ROU_SHIFT) |
183 	    (3 << PHY_R18_MPLL_DATA_SEL_SHIFT) |
184 	    (1 << PHY_R18_MPLL_BIAS_ADJ_SHIFT) |
185 	    (0 << PHY_R18_MPLL_BB_MODE_SHIFT) |
186 	    (3 << PHY_R18_MPLL_ALPHA_SHIFT) |
187 	    (1 << PHY_R18_MPLL_ADJ_LDO_SHIFT) |
188 	    PHY_R18_MPLL_ACG_RANGE);
189 	delay(100);
190 	HWRITE4(sc, PHY_R16, (20 << PHY_R16_MPLL_M_SHIFT) |
191 	    (1 << PHY_R16_MPLL_N_SHIFT) | PHY_R16_MPLL_LOAD |
192 	    (1 << PHY_R16_MPLL_LOCK_LONG_SHIFT) |  PHY_R16_MPLL_FAST_LOCK |
193 	    PHY_R16_MPLL_EN);
194 
195 	/* Tune PHY. */
196 	HWRITE4(sc, PHY_R20, (4 << PHY_R20_USB2_ITG_VBUS_TRIM_SHIFT) |
197 	    PHY_R20_USB2_OTG_VBUSDET_EN | (15 << PHY_R20_USB2_DMON_SEL_SHIFT) |
198 	    PHY_R20_USB2_EDGE_DRV_EN |
199 	    (3 << PHY_R20_USB2_EDGE_DRV_TRIM_SHIFT) |
200 	    (0 << PHY_R20_USB2_BGR_ADJ_SHIFT) |
201 	    (0 << PHY_R20_USB2_BGR_VREF_SHIFT) |
202 	    (0 << PHY_R20_USB2_BGR_DBG_SHIFT));
203 	HWRITE4(sc, PHY_R4, (0xfff << PHY_R4_CALIB_CODE_SHIFT) |
204 	    PHY_R4_TEST_BYPASS_MODE_EN |
205 	    (0 << PHY_R4_I_C2L_BIAS_TRIM_SHIFT));
206 
207 	/* Tune disconnect threshold. */
208 	HWRITE4(sc, PHY_R3, (0 << PHY_R3_SQUELCH_REF_SHIFT) |
209 	    (1 << PHY_R3_HDISC_REF_SHIFT) | (3 << PHY_R3_DISC_THRESH_SHIFT));
210 
211 	/* Analogg settings. */
212 	HWRITE4(sc, PHY_R14, 0);
213 	HWRITE4(sc, PHY_R13, PHY_R13_UPDATE_PMA_SIGNALS |
214 	    (7 << PHY_R13_MIN_COUNT_FOR_SYNC_DET_SHIFT));
215 
216 	return 0;
217 }
218