1/* $NetBSD: jh71x0_usb.c,v 1.1 2024/01/18 07:48:57 skrll Exp $ */ 2 3/*- 4 * Copyright (c) 2023 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nick Hudson 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: jh71x0_usb.c,v 1.1 2024/01/18 07:48:57 skrll Exp $"); 34 35#include <sys/param.h> 36 37 38#include <dev/fdt/fdtvar.h> 39#include <dev/fdt/syscon.h> 40 41struct jh71x0_usb_softc { 42 device_t sc_dev; 43 bus_space_tag_t sc_bst; 44 bus_space_handle_t sc_bsh; 45 int sc_phandle; 46 47 int sc_syscon_phandle; 48 const struct syscon *sc_syscon; 49}; 50 51 52#define RD4(sc, reg) \ 53 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 54#define WR4(sc, reg, val) \ 55 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 56 57 58/* Register definitions */ 59 60#define JH7100_USB0 0x20 61#define JH7100_USB0_MODE_STRAP_MASK __BITS(2, 0) 62#define JH7100_USB0_MODE_STRAP_HOST 2 63 64#define JH7100_USB3 0x2c 65#define JH7100_USB3_UTMI_IDDIG __BIT(21) 66 67#define JH7100_USB7 0x3c 68#define JH7100_USB7_SSRX_SEL __BIT(18) 69#define JH7100_USB7_SSTX_SEL __BIT(19) 70#define JH7100_USB7_PLL_EN __BIT(23) 71#define JH7100_USB7_EQ_EN __BIT(25) 72 73#define JH7110_STRAP_HOST __BIT(17) 74#define JH7110_STRAP_DEVICE __BIT(18) 75#define JH7110_STRAP_MASK __BITS(18, 16) 76 77#define JH7110_SUSPENDM_HOST __BIT(19) 78#define JH7110_SUSPENDM_MASK __BIT(19) 79 80#define JH7110_MISC_CFG_MASK __BITS(23, 20) 81#define JH7110_SUSPENDM_BYPS __BIT(20) 82#define JH7110_PLL_EN __BIT(22) 83#define JH7110_REFCLK_MODE __BIT(23) 84 85 86 87enum usb_dr_mode { 88 USB_DR_MODE_UNKNOWN, 89 USB_DR_MODE_HOST, 90 USB_DR_MODE_PERIPHERAL, 91 USB_DR_MODE_OTG, 92}; 93 94static inline void 95jh71x0_syscon_update(struct jh71x0_usb_softc *sc, bus_size_t off, 96 uint32_t clr, uint32_t set) 97{ 98 syscon_lock(sc->sc_syscon); 99 const uint32_t old = syscon_read_4(sc->sc_syscon, off); 100 const uint32_t new = (old & ~clr) | set; 101 if (old != new) { 102 syscon_write_4(sc->sc_syscon, off, new); 103 } 104 syscon_unlock(sc->sc_syscon); 105} 106 107static int 108jh7100_usb_init(struct jh71x0_usb_softc *sc, const u_int *syscon_data ) 109{ 110 enum usb_dr_mode mode = USB_DR_MODE_HOST; 111 112 switch (mode) { 113 case USB_DR_MODE_HOST: 114 jh71x0_syscon_update(sc, JH7100_USB0, 115 JH7100_USB0_MODE_STRAP_MASK, JH7100_USB0_MODE_STRAP_HOST); 116 jh71x0_syscon_update(sc, JH7100_USB7, 117 JH7100_USB7_PLL_EN, JH7100_USB7_PLL_EN); 118 jh71x0_syscon_update(sc, JH7100_USB7, 119 JH7100_USB7_EQ_EN, JH7100_USB7_EQ_EN); 120 jh71x0_syscon_update(sc, JH7100_USB7, 121 JH7100_USB7_SSRX_SEL, JH7100_USB7_SSRX_SEL); 122 jh71x0_syscon_update(sc, JH7100_USB7, 123 JH7100_USB7_SSTX_SEL, JH7100_USB7_SSTX_SEL); 124 jh71x0_syscon_update(sc, JH7100_USB3, 125 JH7100_USB3_UTMI_IDDIG, JH7100_USB3_UTMI_IDDIG); 126 break; 127 default: 128 break; 129 } 130 131 return 0; 132} 133 134static int 135jh7110_usb_init(struct jh71x0_usb_softc *sc, const u_int *syscon_data) 136{ 137 enum usb_dr_mode mode = USB_DR_MODE_HOST; 138 bus_size_t usb_mode = be32dec(&syscon_data[1]); 139 140 jh71x0_syscon_update(sc, usb_mode, JH7110_MISC_CFG_MASK, 141 JH7110_SUSPENDM_BYPS | JH7110_PLL_EN | JH7110_REFCLK_MODE); 142 143 switch (mode) { 144 case USB_DR_MODE_HOST: 145 jh71x0_syscon_update(sc, usb_mode, JH7110_STRAP_MASK, JH7110_STRAP_HOST); 146 jh71x0_syscon_update(sc, usb_mode, JH7110_SUSPENDM_MASK, JH7110_SUSPENDM_HOST); 147 break; 148 149 case USB_DR_MODE_PERIPHERAL: 150 jh71x0_syscon_update(sc, usb_mode, JH7110_STRAP_MASK, JH7110_STRAP_DEVICE); 151 jh71x0_syscon_update(sc, usb_mode, JH7110_SUSPENDM_MASK, 0); 152 break; 153 default: 154 break; 155 } 156 157 return 0; 158} 159 160struct jh71x0_usb_config { 161 int (*jhuc_init)(struct jh71x0_usb_softc *, const u_int *); 162 const char *jhuc_syscon; 163 size_t jhuc_sclen; 164}; 165 166struct jh71x0_usb_config jh7100_usb_data = { 167 .jhuc_init = jh7100_usb_init, 168 .jhuc_syscon = "starfive,syscon", 169 .jhuc_sclen = 1 * sizeof(uint32_t), 170}; 171 172struct jh71x0_usb_config jh7110_usb_data = { 173 .jhuc_init = jh7110_usb_init, 174 .jhuc_syscon = "starfive,stg-syscon", 175 .jhuc_sclen = 2 * sizeof(uint32_t), 176}; 177 178/* Compat string(s) */ 179static const struct device_compatible_entry compat_data[] = { 180 { .compat = "starfive,jh7100-usb", .data = &jh7100_usb_data }, 181 { .compat = "starfive,jh7110-usb", .data = &jh7110_usb_data }, 182 DEVICE_COMPAT_EOL 183}; 184 185static int 186jh71x0_usb_match(device_t parent, cfdata_t cf, void *aux) 187{ 188 struct fdt_attach_args * const faa = aux; 189 190 return of_compatible_match(faa->faa_phandle, compat_data); 191} 192 193static void 194jh71x0_usb_attach(device_t parent, device_t self, void *aux) 195{ 196 struct jh71x0_usb_softc *sc = device_private(self); 197 struct fdt_attach_args * const faa = aux; 198 const int phandle = faa->faa_phandle; 199 200 sc->sc_dev = self; 201 sc->sc_phandle = phandle; 202 sc->sc_bst = faa->faa_bst; 203 204 const struct jh71x0_usb_config *jhuc = 205 of_compatible_lookup(sc->sc_phandle, compat_data)->data; 206 207 int len; 208 const u_int *syscon_data = 209 fdtbus_get_prop(phandle, jhuc->jhuc_syscon, &len); 210 if (syscon_data == NULL) { 211 aprint_error(": couldn't get '%s' property\n", 212 jhuc->jhuc_syscon); 213 return; 214 } 215 if (len != jhuc->jhuc_sclen) { 216 aprint_error(": incorrect syscon data (len = %u)\n", 217 len); 218 return; 219 } 220 221 int syscon_phandle = 222 fdtbus_get_phandle_from_native(be32dec(&syscon_data[0])); 223 224 sc->sc_syscon = fdtbus_syscon_lookup(syscon_phandle); 225 if (sc->sc_syscon == NULL) { 226 aprint_error(": couldn't get syscon\n"); 227 return; 228 } 229 230 jhuc->jhuc_init(sc, syscon_data); 231 232 aprint_naive("\n"); 233 aprint_normal(": USB\n"); 234 235 for (int child = OF_child(phandle); child; child = OF_peer(child)) { 236 if (!fdtbus_status_okay(child)) 237 continue; 238 fdt_add_child(parent, child, faa, 0); 239 } 240 241 //fdtbus_register_phy_controller(self, phandle, &XXX_usbphy_funcs); 242 243} 244 245 246CFATTACH_DECL_NEW(jh71x0_usb, sizeof(struct jh71x0_usb_softc), 247 jh71x0_usb_match, jh71x0_usb_attach, NULL, NULL); 248