mesong12_usb3pciephy.c revision 1.1
1/* $NetBSD: mesong12_usb3pciephy.c,v 1.1 2021/01/01 07:21:58 ryo Exp $ */
2
3/*
4 * Copyright (c) 2021 Ryo Shimizu <ryo@nerv.org>
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.1 2021/01/01 07:21:58 ryo 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
78struct 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
89static void *
90mesong12_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
115static void
116mesong12_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
123static inline int
124mesong12_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
141static void
142mesong12_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
159static uint16_t
160mesong12_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
180static void
181mesong12_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
209static int
210mesong12_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
286static const char *compatible[] = {
287	"amlogic,g12a-usb3-pcie-phy",
288	NULL
289};
290
291static int
292mesong12_usb3pciephy_match(device_t parent, cfdata_t cf, void *aux)
293{
294	struct fdt_attach_args * const faa = aux;
295
296	return of_match_compatible(faa->faa_phandle, compatible);
297}
298
299static 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
305static void
306mesong12_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
354CFATTACH_DECL_NEW(mesong12_usb3pciephy,
355    sizeof(struct mesong12_usb3pciephy_softc),
356    mesong12_usb3pciephy_match, mesong12_usb3pciephy_attach, NULL, NULL);
357