xref: /netbsd-src/sys/arch/arm/amlogic/mesong12_usb3pciephy.c (revision 90313c06e62e910bf0d1bb24faa9d17dcefd0ab6)
1 /* $NetBSD: mesong12_usb3pciephy.c,v 1.3 2024/02/07 04:20:26 msaitoh Exp $ */
2 
3 /*
4  * Copyright (c) 2021 Ryo Shimizu
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: mesong12_usb3pciephy.c,v 1.3 2024/02/07 04:20:26 msaitoh Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/bus.h>
35 #include <sys/device.h>
36 
37 #include <dev/fdt/fdtvar.h>
38 
39 #define USB3PCIEPHY_R0_REG				0x00
40 #define  USB3PCIEPHY_R0_PCIE_USB3_SWITCH		__BITS(6,5)
41 #define  USB3PCIEPHY_R0_PCIE_POWER_STATE		__BITS(4,0)
42 #define USB3PCIEPHY_R1_REG				0x04
43 #define  USB3PCIEPHY_R1_PHY_MPLL_MULTIPLIER		__BITS(31,25)
44 #define  USB3PCIEPHY_R1_PHY_REF_CLKDIV2			__BIT(24)
45 #define  USB3PCIEPHY_R1_PHY_LOS_BIAS			__BITS(23,21)
46 #define  USB3PCIEPHY_R1_PHY_LOS_LEVEL			__BITS(20,16)
47 #define  USB3PCIEPHY_R1_PHY_RX0_EQ			__BITS(15,13)
48 #define  USB3PCIEPHY_R1_PHY_RX1_EQ			__BITS(12,10)
49 #define  USB3PCIEPHY_R1_PHY_TX0_TERM_OFFSET		__BITS(9,5)
50 #define  USB3PCIEPHY_R1_PHY_TX1_TERM_OFFSET		__BITS(4,0)
51 #define USB3PCIEPHY_R2_REG				0x08
52 #define  USB3PCIEPHY_R2_PHY_TX_VBOOST_LVL		__BITS(20,18)
53 #define  USB3PCIEPHY_R2_PCS_TX_DEEMPH_GEN1		__BITS(17,12)
54 #define  USB3PCIEPHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB	__BITS(11,6)
55 #define  USB3PCIEPHY_R2_PCS_TX_DEEMPH_GEN2_6DB		__BITS(5,0)
56 #define USB3PCIEPHY_R4_REG				0x10
57 #define  USB3PCIEPHY_R4_PHY_CR_CAP_ADDR			__BIT(19)
58 #define  USB3PCIEPHY_R4_PHY_CR_CAP_DATA			__BIT(18)
59 #define  USB3PCIEPHY_R4_PHY_CR_DATA_IN			__BITS(17,2)
60 #define  USB3PCIEPHY_R4_PHY_CR_READ			__BIT(1)
61 #define  USB3PCIEPHY_R4_PHY_CR_WRITE			__BIT(0)
62 #define USB3PCIEPHY_R5_REG				0x14
63 #define  USB3PCIEPHY_R5_PHY_BS_OUT			__BIT(17)
64 #define  USB3PCIEPHY_R5_PHY_CR_ACK			__BIT(16)
65 #define  USB3PCIEPHY_R5_PHY_CR_DATA_OUT			__BITS(15,0)
66 
67 #define PHY_READ_REG(sc, reg)	\
68 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
69 #define PHY_WRITE_REG(sc, reg, val)	\
70 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
71 
72 
73 /* The values must be matched to those in dt-bindings/phy/phy.h */
74 #define PHY_NONE	0
75 #define PHY_TYPE_PCIE	2
76 #define PHY_TYPE_USB3	4
77 
78 struct mesong12_usb3pciephy_softc {
79 	device_t sc_dev;
80 	bus_space_tag_t sc_bst;
81 	bus_space_handle_t sc_bsh;
82 	struct clk *sc_clk;
83 	struct fdtbus_reset *sc_reset;
84 	struct fdtbus_regulator *sc_supply;
85 	int sc_phandle;
86 	int sc_phy_type;
87 };
88 
89 static void *
mesong12_usb3pciephy_acquire(device_t dev,const void * data,size_t len)90 mesong12_usb3pciephy_acquire(device_t dev, const void *data, size_t len)
91 {
92 	struct mesong12_usb3pciephy_softc * const sc = device_private(dev);
93 	const uint32_t *p = data;
94 
95 	/* already acquired? */
96 	if (sc->sc_phy_type != PHY_NONE)
97 		return NULL;
98 
99 	if (len != sizeof(uint32_t))
100 		return NULL;
101 
102 	switch (be32toh(p[0])) {
103 	case PHY_TYPE_USB3:
104 		sc->sc_phy_type = PHY_TYPE_USB3;
105 		break;
106 	case PHY_TYPE_PCIE:
107 		return NULL;	/* PCIe mode is not supported */
108 	default:
109 		return NULL;
110 	}
111 
112 	return sc;
113 }
114 
115 static void
mesong12_usb3pciephy_release(device_t dev,void * priv)116 mesong12_usb3pciephy_release(device_t dev, void *priv)
117 {
118 	struct mesong12_usb3pciephy_softc * const sc = device_private(dev);
119 
120 	sc->sc_phy_type = PHY_NONE;
121 }
122 
123 static inline int
mesong12_usb3pciephy_ack(struct mesong12_usb3pciephy_softc * sc,bool ack,const char * str)124 mesong12_usb3pciephy_ack(struct mesong12_usb3pciephy_softc *sc, bool ack,
125     const char *str)
126 {
127 	int timeout;
128 	uint32_t val;
129 
130 	for (timeout = 1000; timeout > 0; timeout--) {
131 		val = PHY_READ_REG(sc, USB3PCIEPHY_R5_REG);
132 		if (!(val & USB3PCIEPHY_R5_PHY_CR_ACK) == !ack)
133 			return 0;
134 		delay(5);
135 	}
136 	device_printf(sc->sc_dev, "phy %s %s timeout\n",
137 	    str, ack ? "ack" : "nack");
138 	return ETIMEDOUT;
139 }
140 
141 static void
mesong12_usb3pciephy_addr(struct mesong12_usb3pciephy_softc * sc,bus_addr_t addr)142 mesong12_usb3pciephy_addr(struct mesong12_usb3pciephy_softc *sc,
143     bus_addr_t addr)
144 {
145 	uint32_t val;
146 
147 	val = __SHIFTIN(addr, USB3PCIEPHY_R4_PHY_CR_DATA_IN);
148 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
149 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
150 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val |
151 	    USB3PCIEPHY_R4_PHY_CR_CAP_ADDR);
152 	if (mesong12_usb3pciephy_ack(sc, true, "addr") != 0)
153 		return;
154 
155 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
156 	mesong12_usb3pciephy_ack(sc, false, "addr");
157 }
158 
159 static uint16_t
mesong12_usb3pciephy_read(struct mesong12_usb3pciephy_softc * sc,bus_addr_t addr)160 mesong12_usb3pciephy_read(struct mesong12_usb3pciephy_softc *sc,
161     bus_addr_t addr)
162 {
163 	uint32_t val;
164 
165 	mesong12_usb3pciephy_addr(sc, addr);
166 
167 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, 0);
168 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, USB3PCIEPHY_R4_PHY_CR_READ);
169 	if (mesong12_usb3pciephy_ack(sc, true, "read data") != 0)
170 		return 0;
171 
172 	val = PHY_READ_REG(sc, USB3PCIEPHY_R5_REG);
173 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, 0);
174 	if (mesong12_usb3pciephy_ack(sc, false, "read data") != 0)
175 		return 0;
176 
177 	return __SHIFTOUT(val, USB3PCIEPHY_R5_PHY_CR_DATA_OUT);
178 }
179 
180 static void
mesong12_usb3pciephy_write(struct mesong12_usb3pciephy_softc * sc,bus_addr_t addr,uint16_t data)181 mesong12_usb3pciephy_write(struct mesong12_usb3pciephy_softc *sc,
182     bus_addr_t addr, uint16_t data)
183 {
184 	uint32_t val;
185 
186 	mesong12_usb3pciephy_addr(sc, addr);
187 
188 	val = __SHIFTIN(addr, USB3PCIEPHY_R4_PHY_CR_DATA_IN);
189 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
190 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
191 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val |
192 	    USB3PCIEPHY_R4_PHY_CR_CAP_DATA);
193 	if (mesong12_usb3pciephy_ack(sc, true, "write addr") != 0)
194 		return;
195 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
196 	if (mesong12_usb3pciephy_ack(sc, false, "write addr") != 0)
197 		return;
198 
199 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
200 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val |
201 	    USB3PCIEPHY_R4_PHY_CR_WRITE);
202 	if (mesong12_usb3pciephy_ack(sc, true, "write data") != 0)
203 		return;
204 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
205 	if (mesong12_usb3pciephy_ack(sc, false, "write data") != 0)
206 		return;
207 }
208 
209 static int
mesong12_usb3pciephy_enable(device_t dev,void * priv,bool enable)210 mesong12_usb3pciephy_enable(device_t dev, void *priv, bool enable)
211 {
212 	struct mesong12_usb3pciephy_softc * const sc = device_private(dev);
213 	uint32_t val;
214 
215 	fdtbus_clock_assign(sc->sc_phandle);
216 	if (sc->sc_reset != NULL) {
217 		fdtbus_reset_assert(sc->sc_reset);
218 		delay(10);
219 		fdtbus_reset_deassert(sc->sc_reset);
220 	}
221 
222 	if (!enable)
223 		return 0;
224 
225 	/* switch to USB3.0 */
226 	val = PHY_READ_REG(sc, USB3PCIEPHY_R0_REG);
227 	val &= ~USB3PCIEPHY_R0_PCIE_USB3_SWITCH;
228 	val |= __SHIFTIN(3, USB3PCIEPHY_R0_PCIE_USB3_SWITCH);
229 	PHY_WRITE_REG(sc, USB3PCIEPHY_R0_REG, val);
230 	delay(10);
231 
232 #if 0 /* XXX: doesn't work? */
233 	/* workaround for SSPHY(SuperSpeedPHY) suspend bug */
234 	val = mesong12_usb3pciephy_read(sc, 0x102d);
235 	val |= __BIT(7);
236 	mesong12_usb3pciephy_write(sc, 0x102d, val);
237 #endif
238 
239 	val = mesong12_usb3pciephy_read(sc, 0x1010);
240 	val &= ~__BITS(11,4);
241 	val |= __SHIFTIN(2, __BITS(11,4));
242 	mesong12_usb3pciephy_write(sc, 0x1010, val);
243 
244 #if 0 /* XXX: doesn't work? */
245 	/* Rx equalization magic */
246 	val = mesong12_usb3pciephy_read(sc, 0x1006);
247 	val &= ~__BITS(7,6);
248 	val |= __SHIFTIN(2, __BITS(7,6));
249 	val &= ~__BITS(10,8);
250 	val |= __SHIFTIN(3, __BITS(10,8));
251 	val |= __BIT(11);
252 	mesong12_usb3pciephy_write(sc, 0x1006, val);
253 #endif
254 
255 	/* Tx equalization magic */
256 	val = mesong12_usb3pciephy_read(sc, 0x1002);
257 	val &= ~__BITS(13,7);
258 	val |= __SHIFTIN(0x16, __BITS(13,7));
259 	val &= ~__BITS(6,0);
260 	val |= __SHIFTIN(0x7f, __BITS(6,0));
261 	val |= __BIT(14);
262 	mesong12_usb3pciephy_write(sc, 0x1002, val);
263 
264 	/* MPLL loop magic */
265 	val = mesong12_usb3pciephy_read(sc, 0x30);
266 	val &= ~__BITS(7,4);
267 	val |= __SHIFTIN(8, __BITS(7,4));
268 	mesong12_usb3pciephy_write(sc, 0x30, val);
269 
270 
271 	val = PHY_READ_REG(sc, USB3PCIEPHY_R2_REG);
272 	val &= ~USB3PCIEPHY_R2_PHY_TX_VBOOST_LVL;
273 	val |= __SHIFTIN(4, USB3PCIEPHY_R2_PHY_TX_VBOOST_LVL);
274 	PHY_WRITE_REG(sc, USB3PCIEPHY_R2_REG, val);
275 
276 	val = PHY_READ_REG(sc, USB3PCIEPHY_R1_REG);
277 	val &= ~USB3PCIEPHY_R1_PHY_LOS_BIAS;
278 	val |= __SHIFTIN(4, USB3PCIEPHY_R1_PHY_LOS_BIAS);
279 	val &= ~USB3PCIEPHY_R1_PHY_LOS_LEVEL;
280 	val |= __SHIFTIN(9, USB3PCIEPHY_R1_PHY_LOS_LEVEL);
281 	PHY_WRITE_REG(sc, USB3PCIEPHY_R1_REG, val);
282 
283 	return 0;
284 }
285 
286 static const struct device_compatible_entry compat_data[] = {
287 	{ .compat = "amlogic,g12a-usb3-pcie-phy" },
288 	DEVICE_COMPAT_EOL
289 };
290 
291 static int
mesong12_usb3pciephy_match(device_t parent,cfdata_t cf,void * aux)292 mesong12_usb3pciephy_match(device_t parent, cfdata_t cf, void *aux)
293 {
294 	struct fdt_attach_args * const faa = aux;
295 
296 	return of_compatible_match(faa->faa_phandle, compat_data);
297 }
298 
299 static const struct fdtbus_phy_controller_func mesong12_usb3pciephy_funcs = {
300 	.acquire = mesong12_usb3pciephy_acquire,
301 	.release = mesong12_usb3pciephy_release,
302 	.enable = mesong12_usb3pciephy_enable
303 };
304 
305 static void
mesong12_usb3pciephy_attach(device_t parent,device_t self,void * aux)306 mesong12_usb3pciephy_attach(device_t parent, device_t self, void *aux)
307 {
308 	struct mesong12_usb3pciephy_softc * const sc = device_private(self);
309 	struct fdt_attach_args * const faa = aux;
310 	const int phandle = faa->faa_phandle;
311 	bus_addr_t addr;
312 	bus_size_t size;
313 
314 	sc->sc_dev = self;
315 	sc->sc_bst = faa->faa_bst;
316 	sc->sc_phandle = phandle;
317 
318 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
319 		aprint_error(": couldn't get registers\n");
320 		return;
321 	}
322 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
323 		aprint_error(": couldn't map registers\n");
324 		return;
325 	}
326 
327 	sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
328 	if (sc->sc_clk == NULL) {
329 		aprint_error(": couldn't get clock\n");
330 		goto attach_failure;
331 	}
332 	if (clk_enable(sc->sc_clk) != 0) {
333 		aprint_error(": couldn't enable clock\n");
334 		goto attach_failure;
335 	}
336 
337 	sc->sc_reset = fdtbus_reset_get_index(phandle, 0);
338 	sc->sc_supply = fdtbus_regulator_acquire(phandle, "phy-supply");
339 	if (sc->sc_supply != NULL)
340 		fdtbus_regulator_enable(sc->sc_supply);
341 
342 	aprint_naive("\n");
343 	aprint_normal(": USB3 PCIe PHY\n");
344 
345 	fdtbus_register_phy_controller(self, phandle,
346 	    &mesong12_usb3pciephy_funcs);
347 	return;
348 
349  attach_failure:
350 	bus_space_unmap(sc->sc_bst, sc->sc_bsh, size);
351 	return;
352 }
353 
354 CFATTACH_DECL_NEW(mesong12_usb3pciephy,
355     sizeof(struct mesong12_usb3pciephy_softc),
356     mesong12_usb3pciephy_match, mesong12_usb3pciephy_attach, NULL, NULL);
357