1fe924cbdSEmmanuel Vadot /* $NetBSD: sunxi_usb3phy.c,v 1.1 2018/05/01 23:59:42 jmcneill Exp $ */
2fe924cbdSEmmanuel Vadot
3fe924cbdSEmmanuel Vadot /*-
4fe924cbdSEmmanuel Vadot * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca>
5fe924cbdSEmmanuel Vadot * All rights reserved.
6fe924cbdSEmmanuel Vadot *
7fe924cbdSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without
8fe924cbdSEmmanuel Vadot * modification, are permitted provided that the following conditions
9fe924cbdSEmmanuel Vadot * are met:
10fe924cbdSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright
11fe924cbdSEmmanuel Vadot * notice, this list of conditions and the following disclaimer.
12fe924cbdSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright
13fe924cbdSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the
14fe924cbdSEmmanuel Vadot * documentation and/or other materials provided with the distribution.
15fe924cbdSEmmanuel Vadot *
16fe924cbdSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17fe924cbdSEmmanuel Vadot * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18fe924cbdSEmmanuel Vadot * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19fe924cbdSEmmanuel Vadot * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20fe924cbdSEmmanuel Vadot * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21fe924cbdSEmmanuel Vadot * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22fe924cbdSEmmanuel Vadot * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23fe924cbdSEmmanuel Vadot * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24fe924cbdSEmmanuel Vadot * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25fe924cbdSEmmanuel Vadot * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26fe924cbdSEmmanuel Vadot * POSSIBILITY OF SUCH DAMAGE.
27fe924cbdSEmmanuel Vadot */
28fe924cbdSEmmanuel Vadot
29fe924cbdSEmmanuel Vadot /*
30fe924cbdSEmmanuel Vadot * Allwinner USB3PHY
31fe924cbdSEmmanuel Vadot */
32fe924cbdSEmmanuel Vadot
33fe924cbdSEmmanuel Vadot #include <sys/param.h>
34fe924cbdSEmmanuel Vadot #include <sys/systm.h>
35fe924cbdSEmmanuel Vadot #include <sys/bus.h>
36fe924cbdSEmmanuel Vadot #include <sys/rman.h>
37fe924cbdSEmmanuel Vadot #include <sys/kernel.h>
38fe924cbdSEmmanuel Vadot #include <sys/module.h>
39fe924cbdSEmmanuel Vadot #include <sys/gpio.h>
40fe924cbdSEmmanuel Vadot #include <machine/bus.h>
41fe924cbdSEmmanuel Vadot
42fe924cbdSEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
43fe924cbdSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
44fe924cbdSEmmanuel Vadot
45be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
461f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h>
47b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator.h>
48*950a6087SEmmanuel Vadot #include <dev/phy/phy_usb.h>
49fe924cbdSEmmanuel Vadot
50fe924cbdSEmmanuel Vadot #include "phynode_if.h"
51fe924cbdSEmmanuel Vadot
52fe924cbdSEmmanuel Vadot #define USB3PHY_APP 0x00
53fe924cbdSEmmanuel Vadot #define APP_FORCE_VBUS (0x3 << 12)
54fe924cbdSEmmanuel Vadot
55fe924cbdSEmmanuel Vadot #define USB3PHY_PIPE_CLOCK_CONTROL 0x14
56fe924cbdSEmmanuel Vadot #define PCC_PIPE_CLK_OPEN (1 << 6)
57fe924cbdSEmmanuel Vadot
58fe924cbdSEmmanuel Vadot #define USB3PHY_PHY_TUNE_LOW 0x18
59fe924cbdSEmmanuel Vadot #define PTL_MAGIC 0x0047fc87
60fe924cbdSEmmanuel Vadot
61fe924cbdSEmmanuel Vadot #define USB3PHY_PHY_TUNE_HIGH 0x1c
62fe924cbdSEmmanuel Vadot #define PTH_TX_DEEMPH_3P5DB (0x1F << 19)
63fe924cbdSEmmanuel Vadot #define PTH_TX_DEEMPH_6DB (0x3F << 13)
64fe924cbdSEmmanuel Vadot #define PTH_TX_SWING_FULL (0x7F << 6)
65fe924cbdSEmmanuel Vadot #define PTH_LOS_BIAS (0x7 << 3)
66fe924cbdSEmmanuel Vadot #define PTH_TX_BOOST_LVL (0x7 << 0)
67fe924cbdSEmmanuel Vadot
68fe924cbdSEmmanuel Vadot #define USB3PHY_PHY_EXTERNAL_CONTROL 0x20
69fe924cbdSEmmanuel Vadot #define PEC_REF_SSP_EN (1 << 26)
70fe924cbdSEmmanuel Vadot #define PEC_SSC_EN (1 << 24)
71fe924cbdSEmmanuel Vadot #define PEC_EXTERN_VBUS (0x3 << 1)
72fe924cbdSEmmanuel Vadot
73fe924cbdSEmmanuel Vadot #define __LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask))
74fe924cbdSEmmanuel Vadot #define __SHIFTIN(__x, __mask) ((__x) * __LOWEST_SET_BIT(__mask))
75fe924cbdSEmmanuel Vadot
76fe924cbdSEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
77fe924cbdSEmmanuel Vadot { "allwinner,sun50i-h6-usb3-phy", 1 },
78fe924cbdSEmmanuel Vadot { NULL, 0 }
79fe924cbdSEmmanuel Vadot };
80fe924cbdSEmmanuel Vadot
81fe924cbdSEmmanuel Vadot static struct resource_spec aw_usb3phy_spec[] = {
82fe924cbdSEmmanuel Vadot { SYS_RES_MEMORY, 0, RF_ACTIVE },
83fe924cbdSEmmanuel Vadot { -1, 0 }
84fe924cbdSEmmanuel Vadot };
85fe924cbdSEmmanuel Vadot
86fe924cbdSEmmanuel Vadot struct awusb3phy_softc {
87fe924cbdSEmmanuel Vadot struct resource * res;
88fe924cbdSEmmanuel Vadot regulator_t reg;
89fe924cbdSEmmanuel Vadot int mode;
90fe924cbdSEmmanuel Vadot };
91fe924cbdSEmmanuel Vadot
92fe924cbdSEmmanuel Vadot /* Phy class and methods. */
93fe924cbdSEmmanuel Vadot static int awusb3phy_phy_enable(struct phynode *phy, bool enable);
94fe924cbdSEmmanuel Vadot static int awusb3phy_get_mode(struct phynode *phy, int *mode);
95fe924cbdSEmmanuel Vadot static int awusb3phy_set_mode(struct phynode *phy, int mode);
96fe924cbdSEmmanuel Vadot static phynode_usb_method_t awusb3phy_phynode_methods[] = {
97fe924cbdSEmmanuel Vadot PHYNODEMETHOD(phynode_enable, awusb3phy_phy_enable),
98fe924cbdSEmmanuel Vadot PHYNODEMETHOD(phynode_usb_get_mode, awusb3phy_get_mode),
99fe924cbdSEmmanuel Vadot PHYNODEMETHOD(phynode_usb_set_mode, awusb3phy_set_mode),
100fe924cbdSEmmanuel Vadot
101fe924cbdSEmmanuel Vadot PHYNODEMETHOD_END
102fe924cbdSEmmanuel Vadot };
103fe924cbdSEmmanuel Vadot DEFINE_CLASS_1(awusb3phy_phynode, awusb3phy_phynode_class, awusb3phy_phynode_methods,
104fe924cbdSEmmanuel Vadot sizeof(struct phynode_usb_sc), phynode_usb_class);
105fe924cbdSEmmanuel Vadot
106fe924cbdSEmmanuel Vadot #define RD4(res, o) bus_read_4(res, (o))
107fe924cbdSEmmanuel Vadot #define WR4(res, o, v) bus_write_4(res, (o), (v))
108fe924cbdSEmmanuel Vadot
109fe924cbdSEmmanuel Vadot static int
awusb3phy_phy_enable(struct phynode * phynode,bool enable)110fe924cbdSEmmanuel Vadot awusb3phy_phy_enable(struct phynode *phynode, bool enable)
111fe924cbdSEmmanuel Vadot {
112fe924cbdSEmmanuel Vadot struct awusb3phy_softc *sc;
113fe924cbdSEmmanuel Vadot device_t dev;
114fe924cbdSEmmanuel Vadot uint32_t val;
115fe924cbdSEmmanuel Vadot int error = 0;
116fe924cbdSEmmanuel Vadot
117fe924cbdSEmmanuel Vadot dev = phynode_get_device(phynode);
118fe924cbdSEmmanuel Vadot sc = device_get_softc(dev);
119fe924cbdSEmmanuel Vadot
120fe924cbdSEmmanuel Vadot device_printf(dev, "%s: called\n", __func__);
121fe924cbdSEmmanuel Vadot
122fe924cbdSEmmanuel Vadot if (enable) {
123fe924cbdSEmmanuel Vadot val = RD4(sc->res, USB3PHY_PHY_EXTERNAL_CONTROL);
124fe924cbdSEmmanuel Vadot device_printf(dev, "EXTERNAL_CONTROL: %x\n", val);
125fe924cbdSEmmanuel Vadot val |= PEC_EXTERN_VBUS;
126fe924cbdSEmmanuel Vadot val |= PEC_SSC_EN;
127fe924cbdSEmmanuel Vadot val |= PEC_REF_SSP_EN;
128fe924cbdSEmmanuel Vadot device_printf(dev, "EXTERNAL_CONTROL: %x\n", val);
129fe924cbdSEmmanuel Vadot WR4(sc->res, USB3PHY_PHY_EXTERNAL_CONTROL, val);
130fe924cbdSEmmanuel Vadot
131fe924cbdSEmmanuel Vadot val = RD4(sc->res, USB3PHY_PIPE_CLOCK_CONTROL);
132fe924cbdSEmmanuel Vadot device_printf(dev, "PIPE_CONTROL: %x\n", val);
133fe924cbdSEmmanuel Vadot val |= PCC_PIPE_CLK_OPEN;
134fe924cbdSEmmanuel Vadot device_printf(dev, "PIPE_CONTROL: %x\n", val);
135fe924cbdSEmmanuel Vadot WR4(sc->res, USB3PHY_PIPE_CLOCK_CONTROL, val);
136fe924cbdSEmmanuel Vadot
137fe924cbdSEmmanuel Vadot val = RD4(sc->res, USB3PHY_APP);
138fe924cbdSEmmanuel Vadot device_printf(dev, "APP: %x\n", val);
139fe924cbdSEmmanuel Vadot val |= APP_FORCE_VBUS;
140fe924cbdSEmmanuel Vadot device_printf(dev, "APP: %x\n", val);
141fe924cbdSEmmanuel Vadot WR4(sc->res, USB3PHY_APP, val);
142fe924cbdSEmmanuel Vadot
143fe924cbdSEmmanuel Vadot WR4(sc->res, USB3PHY_PHY_TUNE_LOW, PTL_MAGIC);
144fe924cbdSEmmanuel Vadot
145fe924cbdSEmmanuel Vadot val = RD4(sc->res, USB3PHY_PHY_TUNE_HIGH);
146fe924cbdSEmmanuel Vadot device_printf(dev, "PHY_TUNE_HIGH: %x\n", val);
147fe924cbdSEmmanuel Vadot val |= PTH_TX_BOOST_LVL;
148fe924cbdSEmmanuel Vadot val |= PTH_LOS_BIAS;
149fe924cbdSEmmanuel Vadot val &= ~PTH_TX_SWING_FULL;
150fe924cbdSEmmanuel Vadot val |= __SHIFTIN(0x55, PTH_TX_SWING_FULL);
151fe924cbdSEmmanuel Vadot val &= ~PTH_TX_DEEMPH_6DB;
152fe924cbdSEmmanuel Vadot val |= __SHIFTIN(0x20, PTH_TX_DEEMPH_6DB);
153fe924cbdSEmmanuel Vadot val &= ~PTH_TX_DEEMPH_3P5DB;
154fe924cbdSEmmanuel Vadot val |= __SHIFTIN(0x15, PTH_TX_DEEMPH_3P5DB);
155fe924cbdSEmmanuel Vadot device_printf(dev, "PHY_TUNE_HIGH: %x\n", val);
156fe924cbdSEmmanuel Vadot WR4(sc->res, USB3PHY_PHY_TUNE_HIGH, val);
157fe924cbdSEmmanuel Vadot
158fe924cbdSEmmanuel Vadot if (sc->reg)
159fe924cbdSEmmanuel Vadot error = regulator_enable(sc->reg);
160fe924cbdSEmmanuel Vadot } else {
161fe924cbdSEmmanuel Vadot if (sc->reg)
162fe924cbdSEmmanuel Vadot error = regulator_disable(sc->reg);
163fe924cbdSEmmanuel Vadot }
164fe924cbdSEmmanuel Vadot
165fe924cbdSEmmanuel Vadot if (error != 0) {
166fe924cbdSEmmanuel Vadot device_printf(dev,
167fe924cbdSEmmanuel Vadot "couldn't %s regulator for phy\n",
168fe924cbdSEmmanuel Vadot enable ? "enable" : "disable");
169fe924cbdSEmmanuel Vadot return (error);
170fe924cbdSEmmanuel Vadot }
171fe924cbdSEmmanuel Vadot
172fe924cbdSEmmanuel Vadot return (0);
173fe924cbdSEmmanuel Vadot }
174fe924cbdSEmmanuel Vadot
175fe924cbdSEmmanuel Vadot static int
awusb3phy_get_mode(struct phynode * phynode,int * mode)176fe924cbdSEmmanuel Vadot awusb3phy_get_mode(struct phynode *phynode, int *mode)
177fe924cbdSEmmanuel Vadot {
178fe924cbdSEmmanuel Vadot struct awusb3phy_softc *sc;
179fe924cbdSEmmanuel Vadot device_t dev;
180fe924cbdSEmmanuel Vadot
181fe924cbdSEmmanuel Vadot dev = phynode_get_device(phynode);
182fe924cbdSEmmanuel Vadot sc = device_get_softc(dev);
183fe924cbdSEmmanuel Vadot
184fe924cbdSEmmanuel Vadot *mode = sc->mode;
185fe924cbdSEmmanuel Vadot
186fe924cbdSEmmanuel Vadot return (0);
187fe924cbdSEmmanuel Vadot }
188fe924cbdSEmmanuel Vadot
189fe924cbdSEmmanuel Vadot static int
awusb3phy_set_mode(struct phynode * phynode,int mode)190fe924cbdSEmmanuel Vadot awusb3phy_set_mode(struct phynode *phynode, int mode)
191fe924cbdSEmmanuel Vadot {
192fe924cbdSEmmanuel Vadot device_t dev;
193fe924cbdSEmmanuel Vadot struct awusb3phy_softc *sc;
194fe924cbdSEmmanuel Vadot
195fe924cbdSEmmanuel Vadot dev = phynode_get_device(phynode);
196fe924cbdSEmmanuel Vadot sc = device_get_softc(dev);
197fe924cbdSEmmanuel Vadot
198fe924cbdSEmmanuel Vadot if (mode != PHY_USB_MODE_HOST)
199fe924cbdSEmmanuel Vadot return (EINVAL);
200fe924cbdSEmmanuel Vadot
201fe924cbdSEmmanuel Vadot sc->mode = mode;
202fe924cbdSEmmanuel Vadot
203fe924cbdSEmmanuel Vadot return (0);
204fe924cbdSEmmanuel Vadot }
205fe924cbdSEmmanuel Vadot
206fe924cbdSEmmanuel Vadot static int
awusb3phy_probe(device_t dev)207fe924cbdSEmmanuel Vadot awusb3phy_probe(device_t dev)
208fe924cbdSEmmanuel Vadot {
209fe924cbdSEmmanuel Vadot if (!ofw_bus_status_okay(dev))
210fe924cbdSEmmanuel Vadot return (ENXIO);
211fe924cbdSEmmanuel Vadot
212fe924cbdSEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
213fe924cbdSEmmanuel Vadot return (ENXIO);
214fe924cbdSEmmanuel Vadot
215fe924cbdSEmmanuel Vadot device_set_desc(dev, "Allwinner USB3PHY");
216fe924cbdSEmmanuel Vadot return (BUS_PROBE_DEFAULT);
217fe924cbdSEmmanuel Vadot }
218fe924cbdSEmmanuel Vadot
219fe924cbdSEmmanuel Vadot static int
awusb3phy_attach(device_t dev)220fe924cbdSEmmanuel Vadot awusb3phy_attach(device_t dev)
221fe924cbdSEmmanuel Vadot {
222fe924cbdSEmmanuel Vadot struct phynode *phynode;
223fe924cbdSEmmanuel Vadot struct phynode_init_def phy_init;
224fe924cbdSEmmanuel Vadot struct awusb3phy_softc *sc;
225fe924cbdSEmmanuel Vadot clk_t clk;
226fe924cbdSEmmanuel Vadot hwreset_t rst;
227fe924cbdSEmmanuel Vadot phandle_t node;
228fe924cbdSEmmanuel Vadot int error, i;
229fe924cbdSEmmanuel Vadot
230fe924cbdSEmmanuel Vadot sc = device_get_softc(dev);
231fe924cbdSEmmanuel Vadot node = ofw_bus_get_node(dev);
232fe924cbdSEmmanuel Vadot
233fe924cbdSEmmanuel Vadot if (bus_alloc_resources(dev, aw_usb3phy_spec, &sc->res) != 0) {
234fe924cbdSEmmanuel Vadot device_printf(dev, "cannot allocate resources for device\n");
235fe924cbdSEmmanuel Vadot return (ENXIO);
236fe924cbdSEmmanuel Vadot }
237fe924cbdSEmmanuel Vadot
238fe924cbdSEmmanuel Vadot /* Enable clocks */
239fe924cbdSEmmanuel Vadot for (i = 0; clk_get_by_ofw_index(dev, 0, i, &clk) == 0; i++) {
240fe924cbdSEmmanuel Vadot error = clk_enable(clk);
241fe924cbdSEmmanuel Vadot if (error != 0) {
242fe924cbdSEmmanuel Vadot device_printf(dev, "couldn't enable clock %s\n",
243fe924cbdSEmmanuel Vadot clk_get_name(clk));
244fe924cbdSEmmanuel Vadot return (error);
245fe924cbdSEmmanuel Vadot }
246fe924cbdSEmmanuel Vadot }
247fe924cbdSEmmanuel Vadot
248fe924cbdSEmmanuel Vadot /* De-assert resets */
249fe924cbdSEmmanuel Vadot for (i = 0; hwreset_get_by_ofw_idx(dev, 0, i, &rst) == 0; i++) {
250fe924cbdSEmmanuel Vadot error = hwreset_deassert(rst);
251fe924cbdSEmmanuel Vadot if (error != 0) {
252fe924cbdSEmmanuel Vadot device_printf(dev, "couldn't de-assert reset %d\n",
253fe924cbdSEmmanuel Vadot i);
254fe924cbdSEmmanuel Vadot return (error);
255fe924cbdSEmmanuel Vadot }
256fe924cbdSEmmanuel Vadot }
257fe924cbdSEmmanuel Vadot
258fe924cbdSEmmanuel Vadot /* Get regulators */
259fe924cbdSEmmanuel Vadot regulator_get_by_ofw_property(dev, node, "phy-supply", &sc->reg);
260fe924cbdSEmmanuel Vadot
261fe924cbdSEmmanuel Vadot /* Create the phy */
262fe924cbdSEmmanuel Vadot phy_init.ofw_node = ofw_bus_get_node(dev);
263fe924cbdSEmmanuel Vadot phynode = phynode_create(dev, &awusb3phy_phynode_class,
264fe924cbdSEmmanuel Vadot &phy_init);
265fe924cbdSEmmanuel Vadot if (phynode == NULL) {
266fe924cbdSEmmanuel Vadot device_printf(dev, "failed to create USB PHY\n");
267fe924cbdSEmmanuel Vadot return (ENXIO);
268fe924cbdSEmmanuel Vadot }
269fe924cbdSEmmanuel Vadot if (phynode_register(phynode) == NULL) {
270fe924cbdSEmmanuel Vadot device_printf(dev, "failed to create USB PHY\n");
271fe924cbdSEmmanuel Vadot return (ENXIO);
272fe924cbdSEmmanuel Vadot }
273fe924cbdSEmmanuel Vadot
274fe924cbdSEmmanuel Vadot return (error);
275fe924cbdSEmmanuel Vadot }
276fe924cbdSEmmanuel Vadot
277fe924cbdSEmmanuel Vadot static device_method_t awusb3phy_methods[] = {
278fe924cbdSEmmanuel Vadot /* Device interface */
279fe924cbdSEmmanuel Vadot DEVMETHOD(device_probe, awusb3phy_probe),
280fe924cbdSEmmanuel Vadot DEVMETHOD(device_attach, awusb3phy_attach),
281fe924cbdSEmmanuel Vadot
282fe924cbdSEmmanuel Vadot DEVMETHOD_END
283fe924cbdSEmmanuel Vadot };
284fe924cbdSEmmanuel Vadot
285fe924cbdSEmmanuel Vadot static driver_t awusb3phy_driver = {
286fe924cbdSEmmanuel Vadot "awusb3phy",
287fe924cbdSEmmanuel Vadot awusb3phy_methods,
288fe924cbdSEmmanuel Vadot sizeof(struct awusb3phy_softc)
289fe924cbdSEmmanuel Vadot };
290fe924cbdSEmmanuel Vadot
291fe924cbdSEmmanuel Vadot /* aw_usb3phy needs to come up after regulators/gpio/etc, but before ehci/ohci */
2927e1e2ba1SJohn Baldwin EARLY_DRIVER_MODULE(awusb3phy, simplebus, awusb3phy_driver, 0, 0,
2937e1e2ba1SJohn Baldwin BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);
294fe924cbdSEmmanuel Vadot MODULE_VERSION(awusb3phy, 1);
295