ti_omapmusb.c revision 1.1
11.1Sskrll/* $NetBSD: ti_omapmusb.c,v 1.1 2025/12/16 12:20:22 skrll Exp $ */ 21.1Sskrll 31.1Sskrll/*- 41.1Sskrll * Copyright (c) 2025 Rui-Xiang Guo 51.1Sskrll * All rights reserved. 61.1Sskrll * 71.1Sskrll * Redistribution and use in source and binary forms, with or without 81.1Sskrll * modification, are permitted provided that the following conditions 91.1Sskrll * are met: 101.1Sskrll * 1. Redistributions of source code must retain the above copyright 111.1Sskrll * notice, this list of conditions and the following disclaimer. 121.1Sskrll * 2. The name of the author may not be used to endorse or promote products 131.1Sskrll * derived from this software without specific prior written permission. 141.1Sskrll * 151.1Sskrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 161.1Sskrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 171.1Sskrll * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 181.1Sskrll * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 191.1Sskrll * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 201.1Sskrll * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 211.1Sskrll * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 221.1Sskrll * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 231.1Sskrll * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 241.1Sskrll * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 251.1Sskrll * SUCH DAMAGE. 261.1Sskrll */ 271.1Sskrll 281.1Sskrll#include <sys/cdefs.h> 291.1Sskrll__KERNEL_RCSID(0, "$NetBSD: ti_omapmusb.c,v 1.1 2025/12/16 12:20:22 skrll Exp $"); 301.1Sskrll 311.1Sskrll#include <sys/param.h> 321.1Sskrll#include <sys/systm.h> 331.1Sskrll#include <sys/device.h> 341.1Sskrll#include <sys/conf.h> 351.1Sskrll#include <sys/mutex.h> 361.1Sskrll#include <sys/bus.h> 371.1Sskrll#include <sys/pool.h> 381.1Sskrll 391.1Sskrll#include <dev/usb/usb.h> 401.1Sskrll#include <dev/usb/usbdi.h> 411.1Sskrll#include <dev/usb/usbdivar.h> 421.1Sskrll#include <dev/usb/motgvar.h> 431.1Sskrll#include <dev/usb/motgreg.h> 441.1Sskrll 451.1Sskrll#include <dev/fdt/fdtvar.h> 461.1Sskrll 471.1Sskrll#include <arm/ti/ti_prcm.h> 481.1Sskrll 491.1Sskrll#define OTG_SYSCONFIG 0x404 501.1Sskrll#define OTG_SYSCONFIG_MIDLEMODE __BITS(13,12) 511.1Sskrll#define OTG_SYSCONFIG_SIDLEMODE __BITS(4,3) 521.1Sskrll#define OTG_SYSCONFIG_ENAWAKEUP __BIT(2) 531.1Sskrll#define OTG_SYSCONFIG_SOFTRESET __BIT(1) 541.1Sskrll#define OTG_SYSCONFIG_AUTOIDLE __BIT(0) 551.1Sskrll 561.1Sskrll#define OTG_SYSSTATUS 0x408 571.1Sskrll#define OTG_SYSSTATUS_RESETDONE __BIT(0) 581.1Sskrll 591.1Sskrll#define IDLEMODE_FORCE 0x0 601.1Sskrll#define IDLEMODE_NO 0x1 611.1Sskrll#define IDLEMODE_SMART 0x2 621.1Sskrll#define IDLEMODE_SMART_WKUP 0x3 631.1Sskrll 641.1Sskrllstatic const struct device_compatible_entry compat_data[] = { 651.1Sskrll { .compat = "ti,omap4-musb" }, 661.1Sskrll DEVICE_COMPAT_EOL 671.1Sskrll}; 681.1Sskrll 691.1Sskrllstatic int omapmusb_match(device_t, cfdata_t, void *); 701.1Sskrllstatic void omapmusb_attach(device_t, device_t, void *); 711.1Sskrll 721.1SskrllCFATTACH_DECL_NEW(omapmusb, sizeof(struct motg_softc), 731.1Sskrll omapmusb_match, omapmusb_attach, NULL, NULL); 741.1Sskrll 751.1Sskrll#define RD1(sc, reg) \ 761.1Sskrll bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (reg)) 771.1Sskrll#define WR1(sc, reg, val) \ 781.1Sskrll bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 791.1Sskrll#define RD2(sc, reg) \ 801.1Sskrll bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg)) 811.1Sskrll#define WR2(sc, reg, val) \ 821.1Sskrll bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 831.1Sskrll#define RD4(sc, reg) \ 841.1Sskrll bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) 851.1Sskrll#define WR4(sc, reg, val) \ 861.1Sskrll bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 871.1Sskrll 881.1Sskrllstatic int 891.1Sskrllomapmusb_intr(void *priv) 901.1Sskrll{ 911.1Sskrll struct motg_softc * const sc = priv; 921.1Sskrll uint16_t inttx, intrx; 931.1Sskrll uint8_t intusb; 941.1Sskrll int ret; 951.1Sskrll 961.1Sskrll mutex_enter(&sc->sc_intr_lock); 971.1Sskrll 981.1Sskrll intusb = RD1(sc, MUSB2_REG_INTUSB); 991.1Sskrll inttx = RD2(sc, MUSB2_REG_INTTX); 1001.1Sskrll intrx = RD2(sc, MUSB2_REG_INTRX); 1011.1Sskrll if (!intusb && !inttx && !intrx) { 1021.1Sskrll mutex_exit(&sc->sc_intr_lock); 1031.1Sskrll return 0; 1041.1Sskrll } 1051.1Sskrll 1061.1Sskrll if (intusb) 1071.1Sskrll WR1(sc, MUSB2_REG_INTUSB, intusb); 1081.1Sskrll if (inttx) 1091.1Sskrll WR2(sc, MUSB2_REG_INTTX, inttx); 1101.1Sskrll if (intrx) 1111.1Sskrll WR2(sc, MUSB2_REG_INTRX, intrx); 1121.1Sskrll 1131.1Sskrll ret = motg_intr(sc, intrx, inttx, intusb); 1141.1Sskrll 1151.1Sskrll mutex_exit(&sc->sc_intr_lock); 1161.1Sskrll 1171.1Sskrll return ret; 1181.1Sskrll} 1191.1Sskrll 1201.1Sskrllstatic void 1211.1Sskrllomapmusb_poll(void *priv) 1221.1Sskrll{ 1231.1Sskrll omapmusb_intr(priv); 1241.1Sskrll} 1251.1Sskrll 1261.1Sskrllstatic void 1271.1Sskrllomapmusb_reset(struct motg_softc *sc) 1281.1Sskrll{ 1291.1Sskrll uint32_t val; 1301.1Sskrll int retry = 5000; 1311.1Sskrll 1321.1Sskrll WR4(sc, OTG_SYSCONFIG, OTG_SYSCONFIG_SOFTRESET); 1331.1Sskrll do { 1341.1Sskrll val = RD4(sc, OTG_SYSSTATUS); 1351.1Sskrll if (val & OTG_SYSSTATUS_RESETDONE) 1361.1Sskrll break; 1371.1Sskrll delay(10); 1381.1Sskrll } while (--retry > 0); 1391.1Sskrll if (retry == 0) 1401.1Sskrll aprint_error_dev(sc->sc_dev, "reset timeout\n"); 1411.1Sskrll} 1421.1Sskrll 1431.1Sskrllstatic void 1441.1Sskrllomapmusb_init(struct motg_softc *sc) 1451.1Sskrll{ 1461.1Sskrll uint32_t val; 1471.1Sskrll 1481.1Sskrll omapmusb_reset(sc); 1491.1Sskrll 1501.1Sskrll val = __SHIFTIN(IDLEMODE_SMART, OTG_SYSCONFIG_MIDLEMODE) | 1511.1Sskrll __SHIFTIN(IDLEMODE_SMART, OTG_SYSCONFIG_SIDLEMODE) | 1521.1Sskrll OTG_SYSCONFIG_AUTOIDLE; 1531.1Sskrll WR4(sc, OTG_SYSCONFIG, val); 1541.1Sskrll 1551.1Sskrll motg_init(sc); 1561.1Sskrll} 1571.1Sskrll 1581.1Sskrllstatic int 1591.1Sskrllomapmusb_match(device_t parent, cfdata_t match, void *aux) 1601.1Sskrll{ 1611.1Sskrll struct fdt_attach_args * const faa = aux; 1621.1Sskrll 1631.1Sskrll return of_compatible_match(faa->faa_phandle, compat_data); 1641.1Sskrll} 1651.1Sskrll 1661.1Sskrllstatic void 1671.1Sskrllomapmusb_attach(device_t parent, device_t self, void *aux) 1681.1Sskrll{ 1691.1Sskrll struct motg_softc * const sc = device_private(self); 1701.1Sskrll struct fdt_attach_args * const faa = aux; 1711.1Sskrll const int phandle = faa->faa_phandle; 1721.1Sskrll struct fdtbus_phy *phy; 1731.1Sskrll char intrstr[128]; 1741.1Sskrll bus_addr_t addr; 1751.1Sskrll bus_size_t size; 1761.1Sskrll uint32_t ep_max; 1771.1Sskrll void *ih; 1781.1Sskrll 1791.1Sskrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 1801.1Sskrll aprint_error(": couldn't get registers\n"); 1811.1Sskrll return; 1821.1Sskrll } 1831.1Sskrll 1841.1Sskrll if (ti_prcm_enable_hwmod(phandle, 0) != 0) { 1851.1Sskrll aprint_error(": couldn't enable module\n"); 1861.1Sskrll return; 1871.1Sskrll } 1881.1Sskrll 1891.1Sskrll if (of_getprop_uint32(phandle, "num-eps", &ep_max)) 1901.1Sskrll ep_max = MOTG_MAX_HW_EP; 1911.1Sskrll 1921.1Sskrll phy = fdtbus_phy_get(phandle, "usb2-phy"); 1931.1Sskrll if (phy && fdtbus_phy_enable(phy, true) != 0) { 1941.1Sskrll aprint_error(": couldn't enable phy\n"); 1951.1Sskrll return; 1961.1Sskrll } 1971.1Sskrll 1981.1Sskrll sc->sc_dev = self; 1991.1Sskrll sc->sc_bus.ub_hcpriv = sc; 2001.1Sskrll sc->sc_bus.ub_dmatag = faa->faa_dmat; 2011.1Sskrll sc->sc_size = size; 2021.1Sskrll sc->sc_iot = faa->faa_bst; 2031.1Sskrll if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) { 2041.1Sskrll aprint_error(": couldn't map registers\n"); 2051.1Sskrll return; 2061.1Sskrll } 2071.1Sskrll sc->sc_intr_poll = omapmusb_poll; 2081.1Sskrll sc->sc_intr_poll_arg = sc; 2091.1Sskrll sc->sc_mode = MOTG_MODE_HOST; 2101.1Sskrll sc->sc_ep_max = ep_max; 2111.1Sskrll sc->sc_ep_fifosize = 512; 2121.1Sskrll 2131.1Sskrll aprint_naive("\n"); 2141.1Sskrll aprint_normal(": USB OTG\n"); 2151.1Sskrll 2161.1Sskrll if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 2171.1Sskrll aprint_error_dev(self, "failed to decode interrupt\n"); 2181.1Sskrll return; 2191.1Sskrll } 2201.1Sskrll 2211.1Sskrll ih = fdtbus_intr_establish_xname(phandle, 0, IPL_USB, FDT_INTR_MPSAFE, 2221.1Sskrll omapmusb_intr, sc, device_xname(self)); 2231.1Sskrll if (ih == NULL) { 2241.1Sskrll aprint_error_dev(self, "couldn't establish interrupt on %s\n", 2251.1Sskrll intrstr); 2261.1Sskrll return; 2271.1Sskrll } 2281.1Sskrll aprint_normal_dev(self, "interrupting on %s\n", intrstr); 2291.1Sskrll 2301.1Sskrll omapmusb_init(sc); 2311.1Sskrll} 232