Home | History | Annotate | Line # | Download | only in starfive
      1 /* $NetBSD: jh71x0_usb.c,v 1.3 2024/09/18 08:31:50 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.3 2024/09/18 08:31:50 skrll Exp $");
     34 
     35 #include <sys/param.h>
     36 
     37 
     38 #include <dev/fdt/fdtvar.h>
     39 #include <dev/fdt/syscon.h>
     40 
     41 struct 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 
     87 enum 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 
     94 static inline void
     95 jh71x0_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 
    107 static int
    108 jh7100_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 
    134 static int
    135 jh7110_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 
    160 struct 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 
    166 struct 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 
    172 struct 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) */
    179 static 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 
    185 static int
    186 jh71x0_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 
    193 static void
    194 jh71x0_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 
    246 CFATTACH_DECL_NEW(jh71x0_usb, sizeof(struct jh71x0_usb_softc),
    247 	jh71x0_usb_match, jh71x0_usb_attach, NULL, NULL);
    248