Home | History | Annotate | Line # | Download | only in rockchip
rk_usb.c revision 1.1
      1 /* $NetBSD: rk_usb.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2018 Jared McNeill <jmcneill (at) invisible.ca>
      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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING 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 
     31 __KERNEL_RCSID(0, "$NetBSD: rk_usb.c,v 1.1 2018/06/16 00:19:04 jmcneill Exp $");
     32 
     33 #include <sys/param.h>
     34 #include <sys/bus.h>
     35 #include <sys/device.h>
     36 #include <sys/intr.h>
     37 #include <sys/systm.h>
     38 #include <sys/time.h>
     39 #include <sys/kmem.h>
     40 
     41 #include <dev/clk/clk_backend.h>
     42 
     43 #include <dev/fdt/fdtvar.h>
     44 
     45 static int rk_usb_match(device_t, cfdata_t, void *);
     46 static void rk_usb_attach(device_t, device_t, void *);
     47 
     48 #define	CON0_REG	0x00
     49 #define	CON1_REG	0x04
     50 #define	CON2_REG	0x08
     51 #define	 USBPHY_COMMONONN	__BIT(4)
     52 
     53 enum rk_usb_type {
     54 	USB_RK3328 = 1,
     55 };
     56 
     57 static const struct of_compat_data compat_data[] = {
     58 	{ "rockchip,rk3328-usb2phy",		USB_RK3328 },
     59 	{ NULL }
     60 };
     61 
     62 struct rk_usb_clk {
     63 	struct clk		base;
     64 	bus_size_t		reg;
     65 };
     66 
     67 struct rk_usb_softc {
     68 	device_t		sc_dev;
     69 	bus_space_tag_t		sc_bst;
     70 	bus_space_handle_t	sc_bsh;
     71 	enum rk_usb_type	sc_type;
     72 
     73 	struct clk_domain	sc_clkdom;
     74 	struct rk_usb_clk	sc_usbclk;
     75 };
     76 
     77 #define USB_READ(sc, reg)			\
     78 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
     79 #define USB_WRITE(sc, reg, val)			\
     80 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
     81 
     82 CFATTACH_DECL_NEW(rk_usb, sizeof(struct rk_usb_softc),
     83 	rk_usb_match, rk_usb_attach, NULL, NULL);
     84 
     85 static struct clk *
     86 rk_usb_clk_get(void *priv, const char *name)
     87 {
     88 	struct rk_usb_softc * const sc = priv;
     89 
     90 	if (strcmp(name, sc->sc_usbclk.base.name) != 0)
     91 		return NULL;
     92 
     93 	return &sc->sc_usbclk.base;
     94 }
     95 
     96 static void
     97 rk_usb_clk_put(void *priv, struct clk *clk)
     98 {
     99 }
    100 
    101 static u_int
    102 rk_usb_clk_get_rate(void *priv, struct clk *clk)
    103 {
    104 	return 480000000;
    105 }
    106 
    107 static int
    108 rk_usb_clk_enable(void *priv, struct clk *clk)
    109 {
    110 	struct rk_usb_softc * const sc = priv;
    111 
    112 	const uint32_t write_mask = USBPHY_COMMONONN << 16;
    113 	const uint32_t write_val = 0;
    114 	USB_WRITE(sc, CON2_REG, write_mask | write_val);
    115 
    116 	return 0;
    117 }
    118 
    119 static int
    120 rk_usb_clk_disable(void *priv, struct clk *clk)
    121 {
    122 	struct rk_usb_softc * const sc = priv;
    123 
    124 	const uint32_t write_mask = USBPHY_COMMONONN << 16;
    125 	const uint32_t write_val = USBPHY_COMMONONN;
    126 	USB_WRITE(sc, CON2_REG, write_mask | write_val);
    127 
    128 	return 0;
    129 }
    130 
    131 static const struct clk_funcs rk_usb_clk_funcs = {
    132 	.get = rk_usb_clk_get,
    133 	.put = rk_usb_clk_put,
    134 	.get_rate = rk_usb_clk_get_rate,
    135 	.enable = rk_usb_clk_enable,
    136 	.disable = rk_usb_clk_disable,
    137 };
    138 
    139 static struct clk *
    140 rk_usb_fdt_decode(device_t dev, const void *data, size_t len)
    141 {
    142 	struct rk_usb_softc * const sc = device_private(dev);
    143 
    144 	if (len != 0)
    145 		return NULL;
    146 
    147 	return &sc->sc_usbclk.base;
    148 }
    149 
    150 static const struct fdtbus_clock_controller_func rk_usb_fdt_funcs = {
    151 	.decode = rk_usb_fdt_decode
    152 };
    153 
    154 static int
    155 rk_usb_match(device_t parent, cfdata_t cf, void *aux)
    156 {
    157 	struct fdt_attach_args * const faa = aux;
    158 
    159 	return of_match_compat_data(faa->faa_phandle, compat_data);
    160 }
    161 
    162 static void
    163 rk_usb_attach(device_t parent, device_t self, void *aux)
    164 {
    165 	struct rk_usb_softc * const sc = device_private(self);
    166 	struct fdt_attach_args * const faa = aux;
    167 	const int phandle = faa->faa_phandle;
    168 	bus_addr_t grf_addr, phy_addr, phy_size;
    169 	int child;
    170 
    171 	sc->sc_dev = self;
    172 	sc->sc_bst = faa->faa_bst;
    173 	sc->sc_type = of_search_compatible(phandle, compat_data)->data;
    174 
    175 	if (fdtbus_get_reg(OF_parent(phandle), 0, &grf_addr, NULL) != 0) {
    176 		aprint_error(": couldn't get grf registers\n");
    177 	}
    178 	if (fdtbus_get_reg(phandle, 0, &phy_addr, &phy_size) != 0) {
    179 		aprint_error(": couldn't get phy registers\n");
    180 		return;
    181 	}
    182 	if (bus_space_map(sc->sc_bst, grf_addr + phy_addr, phy_size, 0, &sc->sc_bsh) != 0) {
    183 		aprint_error(": couldn't map phy registers\n");
    184 		return;
    185 	}
    186 
    187 	const char *clkname = fdtbus_get_string(phandle, "clock-output-names");
    188 	if (clkname == NULL)
    189 		clkname = faa->faa_name;
    190 
    191 	sc->sc_clkdom.name = device_xname(self);
    192 	sc->sc_clkdom.funcs = &rk_usb_clk_funcs;
    193 	sc->sc_clkdom.priv = sc;
    194 	sc->sc_usbclk.base.domain = &sc->sc_clkdom;
    195 	sc->sc_usbclk.base.name = kmem_asprintf("%s", clkname);
    196 	clk_attach(&sc->sc_usbclk.base);
    197 
    198 	aprint_naive("\n");
    199 	aprint_normal(": USB2 PHY\n");
    200 
    201 	fdtbus_register_clock_controller(self, phandle, &rk_usb_fdt_funcs);
    202 
    203 	for (child = OF_child(phandle); child; child = OF_peer(child)) {
    204 		if (!fdtbus_status_okay(child))
    205 			continue;
    206 
    207 		struct fdt_attach_args cfaa = *faa;
    208 		cfaa.faa_phandle = child;
    209 		cfaa.faa_name = fdtbus_get_string(child, "name");
    210 		cfaa.faa_quiet = false;
    211 
    212 		config_found(self, &cfaa, NULL);
    213 	}
    214 }
    215 
    216 /*
    217  * USB PHY
    218  */
    219 
    220 static int rk_usbphy_match(device_t, cfdata_t, void *);
    221 static void rk_usbphy_attach(device_t, device_t, void *);
    222 
    223 struct rk_usbphy_softc {
    224 	device_t	sc_dev;
    225 	int		sc_phandle;
    226 };
    227 
    228 CFATTACH_DECL_NEW(rk_usbphy, sizeof(struct rk_usbphy_softc),
    229 	rk_usbphy_match, rk_usbphy_attach, NULL, NULL);
    230 
    231 static void *
    232 rk_usbphy_acquire(device_t dev, const void *data, size_t len)
    233 {
    234 	struct rk_usbphy_softc * const sc = device_private(dev);
    235 
    236 	if (len != 0)
    237 		return NULL;
    238 
    239 	return sc;
    240 }
    241 
    242 static void
    243 rk_usbphy_release(device_t dev, void *priv)
    244 {
    245 }
    246 
    247 static int
    248 rk_usbphy_otg_enable(device_t dev, void *priv, bool enable)
    249 {
    250 	struct rk_usb_softc * const usb_sc = device_private(device_parent(dev));
    251 
    252 	const uint32_t write_mask = 0x1ffU << 16;
    253 	const uint32_t write_val = enable ? 0 : 0x1d1;
    254 	USB_WRITE(usb_sc, CON0_REG, write_mask | write_val);
    255 
    256 	return 0;
    257 }
    258 
    259 static int
    260 rk_usbphy_host_enable(device_t dev, void *priv, bool enable)
    261 {
    262 	struct rk_usb_softc * const usb_sc = device_private(device_parent(dev));
    263 
    264 	const uint32_t write_mask = 0x1ffU << 16;
    265 	const uint32_t write_val = enable ? 0 : 0x1d1;
    266 	USB_WRITE(usb_sc, CON1_REG, write_mask | write_val);
    267 
    268 	return 0;
    269 }
    270 
    271 const struct fdtbus_phy_controller_func rk_usbphy_otg_funcs = {
    272 	.acquire = rk_usbphy_acquire,
    273 	.release = rk_usbphy_release,
    274 	.enable = rk_usbphy_otg_enable,
    275 };
    276 
    277 const struct fdtbus_phy_controller_func rk_usbphy_host_funcs = {
    278 	.acquire = rk_usbphy_acquire,
    279 	.release = rk_usbphy_release,
    280 	.enable = rk_usbphy_host_enable,
    281 };
    282 
    283 static int
    284 rk_usbphy_match(device_t parent, cfdata_t cf, void *aux)
    285 {
    286 	struct fdt_attach_args * const faa = aux;
    287 	const int phandle = faa->faa_phandle;
    288 	const char *name = fdtbus_get_string(phandle, "name");
    289 
    290 	if (strcmp(name, "otg-port") == 0 || strcmp(name, "host-port") == 0)
    291 		return 1;
    292 
    293 	return 0;
    294 }
    295 
    296 static void
    297 rk_usbphy_attach(device_t parent, device_t self, void *aux)
    298 {
    299 	struct rk_usbphy_softc * const sc = device_private(self);
    300 	struct fdt_attach_args * const faa = aux;
    301 	const int phandle = faa->faa_phandle;
    302 	const char *name = fdtbus_get_string(phandle, "name");
    303 
    304 	sc->sc_dev = self;
    305 	sc->sc_phandle = phandle;
    306 
    307 	aprint_naive("\n");
    308 
    309 	if (strcmp(name, "otg-port") == 0) {
    310 		aprint_normal(": USB2 OTG port\n");
    311 		fdtbus_register_phy_controller(self, phandle, &rk_usbphy_otg_funcs);
    312 	} else if (strcmp(name, "host-port") == 0) {
    313 		aprint_normal(": USB2 host port\n");
    314 		fdtbus_register_phy_controller(self, phandle, &rk_usbphy_host_funcs);
    315 	}
    316 }
    317