exynos_usbdrdphy.c revision 1.2.6.2 1 1.2.6.2 christos /* $NetBSD: exynos_usbdrdphy.c,v 1.2.6.2 2019/06/10 22:05:56 christos Exp $ */
2 1.2.6.2 christos
3 1.2.6.2 christos /*-
4 1.2.6.2 christos * Copyright (c) 2018 Jared McNeill <jmcneill (at) invisible.ca>
5 1.2.6.2 christos * All rights reserved.
6 1.2.6.2 christos *
7 1.2.6.2 christos * Redistribution and use in source and binary forms, with or without
8 1.2.6.2 christos * modification, are permitted provided that the following conditions
9 1.2.6.2 christos * are met:
10 1.2.6.2 christos * 1. Redistributions of source code must retain the above copyright
11 1.2.6.2 christos * notice, this list of conditions and the following disclaimer.
12 1.2.6.2 christos * 2. Redistributions in binary form must reproduce the above copyright
13 1.2.6.2 christos * notice, this list of conditions and the following disclaimer in the
14 1.2.6.2 christos * documentation and/or other materials provided with the distribution.
15 1.2.6.2 christos *
16 1.2.6.2 christos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.2.6.2 christos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.2.6.2 christos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.2.6.2 christos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.2.6.2 christos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.2.6.2 christos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.2.6.2 christos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.2.6.2 christos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.2.6.2 christos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.2.6.2 christos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.2.6.2 christos * POSSIBILITY OF SUCH DAMAGE.
27 1.2.6.2 christos */
28 1.2.6.2 christos
29 1.2.6.2 christos #include <sys/cdefs.h>
30 1.2.6.2 christos
31 1.2.6.2 christos __KERNEL_RCSID(0, "$NetBSD: exynos_usbdrdphy.c,v 1.2.6.2 2019/06/10 22:05:56 christos Exp $");
32 1.2.6.2 christos
33 1.2.6.2 christos #include <sys/param.h>
34 1.2.6.2 christos #include <sys/bus.h>
35 1.2.6.2 christos #include <sys/device.h>
36 1.2.6.2 christos #include <sys/intr.h>
37 1.2.6.2 christos #include <sys/systm.h>
38 1.2.6.2 christos #include <sys/kmem.h>
39 1.2.6.2 christos
40 1.2.6.2 christos #include <dev/fdt/fdtvar.h>
41 1.2.6.2 christos #include <dev/fdt/syscon.h>
42 1.2.6.2 christos
43 1.2.6.2 christos /*
44 1.2.6.2 christos * PHY Registers
45 1.2.6.2 christos */
46 1.2.6.2 christos #define PHY_LINK_SYSTEM 0x04
47 1.2.6.2 christos #define PHY_LINK_SYSTEM_XHCI_VERCTL __BIT(27)
48 1.2.6.2 christos #define PHY_LINK_SYSTEM_FLADJ __BITS(6,1)
49 1.2.6.2 christos #define PHY_UTMI 0x08
50 1.2.6.2 christos #define PHY_UTMI_OTGDISABLE __BIT(6)
51 1.2.6.2 christos #define PHY_CLK_RST 0x10
52 1.2.6.2 christos #define PHY_CLK_RST_SSC_REFCLKSEL __BITS(30,23)
53 1.2.6.2 christos #define PHY_CLK_RST_SSC_EN __BIT(20)
54 1.2.6.2 christos #define PHY_CLK_RST_REF_SSP_EN __BIT(19)
55 1.2.6.2 christos #define PHY_CLK_RST_MPLL_MULT __BITS(17,11)
56 1.2.6.2 christos #define PHY_CLK_RST_MPLL_MULT_24M 0x68
57 1.2.6.2 christos #define PHY_CLK_RST_FSEL __BITS(10,5)
58 1.2.6.2 christos #define PHY_CLK_RST_FSEL_24M 0x5
59 1.2.6.2 christos #define PHY_CLK_RST_RETENABLEN __BIT(4)
60 1.2.6.2 christos #define PHY_CLK_RST_REFCLKSEL __BITS(3,2)
61 1.2.6.2 christos #define PHY_CLK_RST_REFCLKSEL_EXT 3
62 1.2.6.2 christos #define PHY_CLK_RST_PORTRESET __BIT(1)
63 1.2.6.2 christos #define PHY_CLK_RST_COMMONONN __BIT(0)
64 1.2.6.2 christos #define PHY_REG0 0x14
65 1.2.6.2 christos #define PHY_PARAM0 0x1c
66 1.2.6.2 christos #define PHY_PARAM0_REF_USE_PAD __BIT(31)
67 1.2.6.2 christos #define PHY_PARAM0_REF_LOSLEVEL __BITS(30,26)
68 1.2.6.2 christos #define PHY_PARAM1 0x20
69 1.2.6.2 christos #define PHY_PARAM1_TXDEEMPH __BITS(4,0)
70 1.2.6.2 christos #define PHY_TEST 0x28
71 1.2.6.2 christos #define PHY_TEST_POWERDOWN_SSP __BIT(3)
72 1.2.6.2 christos #define PHY_TEST_POWERDOWN_HSP __BIT(2)
73 1.2.6.2 christos #define PHY_BATCHG 0x30
74 1.2.6.2 christos #define PHY_BATCHG_UTMI_CLKSEL __BIT(2)
75 1.2.6.2 christos #define PHY_RESUME 0x34
76 1.2.6.2 christos
77 1.2.6.2 christos /*
78 1.2.6.2 christos * PMU Registers
79 1.2.6.2 christos */
80 1.2.6.2 christos #define USBDRD_PHY_CTRL(n) (0x704 + (n) * 4)
81 1.2.6.2 christos #define USBDRD_PHY_CTRL_EN __BIT(0)
82 1.2.6.2 christos
83 1.2.6.2 christos static int exynos_usbdrdphy_match(device_t, cfdata_t, void *);
84 1.2.6.2 christos static void exynos_usbdrdphy_attach(device_t, device_t, void *);
85 1.2.6.2 christos
86 1.2.6.2 christos enum {
87 1.2.6.2 christos PHY_ID_UTMI_PLUS = 0,
88 1.2.6.2 christos PHY_ID_PIPE3,
89 1.2.6.2 christos NPHY_ID
90 1.2.6.2 christos };
91 1.2.6.2 christos
92 1.2.6.2 christos static const struct of_compat_data compat_data[] = {
93 1.2.6.2 christos { "samsung,exynos5420-usbdrd-phy", 0 },
94 1.2.6.2 christos { NULL }
95 1.2.6.2 christos };
96 1.2.6.2 christos
97 1.2.6.2 christos struct exynos_usbdrdphy_softc;
98 1.2.6.2 christos
99 1.2.6.2 christos struct exynos_usbdrdphy {
100 1.2.6.2 christos struct exynos_usbdrdphy_softc *phy_sc;
101 1.2.6.2 christos u_int phy_index;
102 1.2.6.2 christos };
103 1.2.6.2 christos
104 1.2.6.2 christos struct exynos_usbdrdphy_softc {
105 1.2.6.2 christos device_t sc_dev;
106 1.2.6.2 christos bus_space_tag_t sc_bst;
107 1.2.6.2 christos bus_space_handle_t sc_bsh;
108 1.2.6.2 christos int sc_phandle;
109 1.2.6.2 christos struct syscon *sc_pmureg;
110 1.2.6.2 christos
111 1.2.6.2 christos struct exynos_usbdrdphy *sc_phy;
112 1.2.6.2 christos u_int sc_nphy;
113 1.2.6.2 christos
114 1.2.6.2 christos struct fdtbus_gpio_pin *sc_gpio_id_det;
115 1.2.6.2 christos struct fdtbus_gpio_pin *sc_gpio_vbus_det;
116 1.2.6.2 christos };
117 1.2.6.2 christos
118 1.2.6.2 christos #define PHY_READ(sc, reg) \
119 1.2.6.2 christos bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
120 1.2.6.2 christos #define PHY_WRITE(sc, reg, val) \
121 1.2.6.2 christos bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
122 1.2.6.2 christos
123 1.2.6.2 christos CFATTACH_DECL_NEW(exynos_usbdrdphy, sizeof(struct exynos_usbdrdphy_softc),
124 1.2.6.2 christos exynos_usbdrdphy_match, exynos_usbdrdphy_attach, NULL, NULL);
125 1.2.6.2 christos
126 1.2.6.2 christos static void *
127 1.2.6.2 christos exynos_usbdrdphy_acquire(device_t dev, const void *data, size_t len)
128 1.2.6.2 christos {
129 1.2.6.2 christos struct exynos_usbdrdphy_softc * const sc = device_private(dev);
130 1.2.6.2 christos
131 1.2.6.2 christos if (len != 4)
132 1.2.6.2 christos return NULL;
133 1.2.6.2 christos
134 1.2.6.2 christos const u_int index = be32dec(data);
135 1.2.6.2 christos if (index >= sc->sc_nphy)
136 1.2.6.2 christos return NULL;
137 1.2.6.2 christos
138 1.2.6.2 christos return &sc->sc_phy[index];
139 1.2.6.2 christos }
140 1.2.6.2 christos
141 1.2.6.2 christos static void
142 1.2.6.2 christos exynos_usbdrdphy_release(device_t dev, void *priv)
143 1.2.6.2 christos {
144 1.2.6.2 christos }
145 1.2.6.2 christos
146 1.2.6.2 christos static int
147 1.2.6.2 christos exynos_usbdrdphy_enable(device_t dev, void *priv, bool enable)
148 1.2.6.2 christos {
149 1.2.6.2 christos struct exynos_usbdrdphy * const phy = priv;
150 1.2.6.2 christos struct exynos_usbdrdphy_softc * const sc = phy->phy_sc;
151 1.2.6.2 christos uint32_t val;
152 1.2.6.2 christos
153 1.2.6.2 christos syscon_lock(sc->sc_pmureg);
154 1.2.6.2 christos val = syscon_read_4(sc->sc_pmureg, USBDRD_PHY_CTRL(phy->phy_index));
155 1.2.6.2 christos if (enable)
156 1.2.6.2 christos val |= USBDRD_PHY_CTRL_EN;
157 1.2.6.2 christos else
158 1.2.6.2 christos val &= ~USBDRD_PHY_CTRL_EN;
159 1.2.6.2 christos syscon_write_4(sc->sc_pmureg, USBDRD_PHY_CTRL(phy->phy_index), val);
160 1.2.6.2 christos syscon_unlock(sc->sc_pmureg);
161 1.2.6.2 christos
162 1.2.6.2 christos return 0;
163 1.2.6.2 christos }
164 1.2.6.2 christos
165 1.2.6.2 christos const struct fdtbus_phy_controller_func exynos_usbdrdphy_funcs = {
166 1.2.6.2 christos .acquire = exynos_usbdrdphy_acquire,
167 1.2.6.2 christos .release = exynos_usbdrdphy_release,
168 1.2.6.2 christos .enable = exynos_usbdrdphy_enable,
169 1.2.6.2 christos };
170 1.2.6.2 christos
171 1.2.6.2 christos static void
172 1.2.6.2 christos exynos_usbdrdphy_init(struct exynos_usbdrdphy_softc *sc)
173 1.2.6.2 christos {
174 1.2.6.2 christos uint32_t val;
175 1.2.6.2 christos
176 1.2.6.2 christos PHY_WRITE(sc, PHY_REG0, 0);
177 1.2.6.2 christos
178 1.2.6.2 christos val = PHY_READ(sc, PHY_PARAM0);
179 1.2.6.2 christos val &= ~PHY_PARAM0_REF_USE_PAD;
180 1.2.6.2 christos val &= ~PHY_PARAM0_REF_LOSLEVEL;
181 1.2.6.2 christos val |= __SHIFTIN(9, PHY_PARAM0_REF_LOSLEVEL);
182 1.2.6.2 christos PHY_WRITE(sc, PHY_PARAM0, val);
183 1.2.6.2 christos
184 1.2.6.2 christos PHY_WRITE(sc, PHY_RESUME, 0);
185 1.2.6.2 christos
186 1.2.6.2 christos val = PHY_READ(sc, PHY_LINK_SYSTEM);
187 1.2.6.2 christos val |= PHY_LINK_SYSTEM_XHCI_VERCTL;
188 1.2.6.2 christos val &= ~PHY_LINK_SYSTEM_FLADJ;
189 1.2.6.2 christos val |= __SHIFTIN(0x20, PHY_LINK_SYSTEM_FLADJ);
190 1.2.6.2 christos PHY_WRITE(sc, PHY_LINK_SYSTEM, val);
191 1.2.6.2 christos
192 1.2.6.2 christos val = PHY_READ(sc, PHY_PARAM1);
193 1.2.6.2 christos val &= ~PHY_PARAM1_TXDEEMPH;
194 1.2.6.2 christos val |= __SHIFTIN(0x1c, PHY_PARAM1_TXDEEMPH);
195 1.2.6.2 christos PHY_WRITE(sc, PHY_PARAM1, val);
196 1.2.6.2 christos
197 1.2.6.2 christos val = PHY_READ(sc, PHY_BATCHG);
198 1.2.6.2 christos val |= PHY_BATCHG_UTMI_CLKSEL;
199 1.2.6.2 christos PHY_WRITE(sc, PHY_BATCHG, val);
200 1.2.6.2 christos
201 1.2.6.2 christos val = PHY_READ(sc, PHY_TEST);
202 1.2.6.2 christos val &= ~PHY_TEST_POWERDOWN_SSP;
203 1.2.6.2 christos val &= ~PHY_TEST_POWERDOWN_HSP;
204 1.2.6.2 christos PHY_WRITE(sc, PHY_TEST, val);
205 1.2.6.2 christos
206 1.2.6.2 christos PHY_WRITE(sc, PHY_UTMI, PHY_UTMI_OTGDISABLE);
207 1.2.6.2 christos
208 1.2.6.2 christos val = __SHIFTIN(PHY_CLK_RST_REFCLKSEL_EXT, PHY_CLK_RST_REFCLKSEL);
209 1.2.6.2 christos val |= __SHIFTIN(PHY_CLK_RST_FSEL_24M, PHY_CLK_RST_FSEL);
210 1.2.6.2 christos val |= __SHIFTIN(PHY_CLK_RST_MPLL_MULT_24M, PHY_CLK_RST_MPLL_MULT);
211 1.2.6.2 christos val |= __SHIFTIN(0x88, PHY_CLK_RST_SSC_REFCLKSEL);
212 1.2.6.2 christos val |= PHY_CLK_RST_PORTRESET;
213 1.2.6.2 christos val |= PHY_CLK_RST_RETENABLEN;
214 1.2.6.2 christos val |= PHY_CLK_RST_REF_SSP_EN;
215 1.2.6.2 christos val |= PHY_CLK_RST_SSC_EN;
216 1.2.6.2 christos val |= PHY_CLK_RST_COMMONONN;
217 1.2.6.2 christos PHY_WRITE(sc, PHY_CLK_RST, val);
218 1.2.6.2 christos
219 1.2.6.2 christos delay(50000);
220 1.2.6.2 christos
221 1.2.6.2 christos val &= ~PHY_CLK_RST_PORTRESET;
222 1.2.6.2 christos PHY_WRITE(sc, PHY_CLK_RST, val);
223 1.2.6.2 christos }
224 1.2.6.2 christos
225 1.2.6.2 christos static int
226 1.2.6.2 christos exynos_usbdrdphy_match(device_t parent, cfdata_t cf, void *aux)
227 1.2.6.2 christos {
228 1.2.6.2 christos struct fdt_attach_args * const faa = aux;
229 1.2.6.2 christos
230 1.2.6.2 christos return of_match_compat_data(faa->faa_phandle, compat_data);
231 1.2.6.2 christos }
232 1.2.6.2 christos
233 1.2.6.2 christos static void
234 1.2.6.2 christos exynos_usbdrdphy_attach(device_t parent, device_t self, void *aux)
235 1.2.6.2 christos {
236 1.2.6.2 christos struct exynos_usbdrdphy_softc * const sc = device_private(self);
237 1.2.6.2 christos struct fdt_attach_args * const faa = aux;
238 1.2.6.2 christos const int phandle = faa->faa_phandle;
239 1.2.6.2 christos struct clk *clk;
240 1.2.6.2 christos bus_addr_t addr;
241 1.2.6.2 christos bus_size_t size;
242 1.2.6.2 christos u_int n;
243 1.2.6.2 christos
244 1.2.6.2 christos if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
245 1.2.6.2 christos aprint_error(": couldn't get phy registers\n");
246 1.2.6.2 christos return;
247 1.2.6.2 christos }
248 1.2.6.2 christos
249 1.2.6.2 christos sc->sc_dev = self;
250 1.2.6.2 christos sc->sc_phandle = phandle;
251 1.2.6.2 christos sc->sc_bst = faa->faa_bst;
252 1.2.6.2 christos if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
253 1.2.6.2 christos aprint_error(": couldn't map phy registers\n");
254 1.2.6.2 christos return;
255 1.2.6.2 christos }
256 1.2.6.2 christos
257 1.2.6.2 christos sc->sc_nphy = NPHY_ID;
258 1.2.6.2 christos sc->sc_phy = kmem_alloc(sizeof(*sc->sc_phy) * sc->sc_nphy, KM_SLEEP);
259 1.2.6.2 christos for (n = 0; n < sc->sc_nphy; n++) {
260 1.2.6.2 christos sc->sc_phy[n].phy_sc = sc;
261 1.2.6.2 christos sc->sc_phy[n].phy_index = n;
262 1.2.6.2 christos }
263 1.2.6.2 christos
264 1.2.6.2 christos sc->sc_pmureg = fdtbus_syscon_acquire(phandle, "samsung,pmu-syscon");
265 1.2.6.2 christos if (sc->sc_pmureg == NULL) {
266 1.2.6.2 christos aprint_error(": couldn't acquire pmureg syscon\n");
267 1.2.6.2 christos return;
268 1.2.6.2 christos }
269 1.2.6.2 christos
270 1.2.6.2 christos /* Enable clocks */
271 1.2.6.2 christos clk = fdtbus_clock_get(phandle, "phy");
272 1.2.6.2 christos if (clk == NULL || clk_enable(clk) != 0) {
273 1.2.6.2 christos aprint_error(": couldn't enable phy clock\n");
274 1.2.6.2 christos return;
275 1.2.6.2 christos }
276 1.2.6.2 christos clk = fdtbus_clock_get(phandle, "ref");
277 1.2.6.2 christos if (clk == NULL || clk_enable(clk) != 0) {
278 1.2.6.2 christos aprint_error(": couldn't enable ref clock\n");
279 1.2.6.2 christos return;
280 1.2.6.2 christos }
281 1.2.6.2 christos
282 1.2.6.2 christos aprint_naive("\n");
283 1.2.6.2 christos aprint_normal(": USB DRD PHY\n");
284 1.2.6.2 christos
285 1.2.6.2 christos exynos_usbdrdphy_init(sc);
286 1.2.6.2 christos
287 1.2.6.2 christos fdtbus_register_phy_controller(self, phandle, &exynos_usbdrdphy_funcs);
288 1.2.6.2 christos }
289