Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109171527
D5467.id13848.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D5467.id13848.diff
View Options
Index: sys/arm/allwinner/a10_ehci.c
===================================================================
--- sys/arm/allwinner/a10_ehci.c
+++ sys/arm/allwinner/a10_ehci.c
@@ -40,7 +40,6 @@
#include <sys/condvar.h>
#include <sys/kernel.h>
#include <sys/module.h>
-#include <sys/gpio.h>
#include <machine/bus.h>
#include <dev/ofw/ofw_bus.h>
@@ -59,9 +58,9 @@
#include <dev/usb/controller/ehci.h>
#include <dev/usb/controller/ehcireg.h>
-#include "gpio_if.h"
-
-#include "a10_clk.h"
+#include <arm/allwinner/allwinner_machdep.h>
+#include <arm/allwinner/a10_clk.h>
+#include <arm/allwinner/a31/a31_clk.h>
#define EHCI_HC_DEVSTR "Allwinner Integrated USB 2.0 controller"
@@ -75,8 +74,9 @@
#define SW_AHB_INCRX_ALIGN (1 << 8)
#define SW_AHB_INCR4 (1 << 9)
#define SW_AHB_INCR8 (1 << 10)
-#define GPIO_USB1_PWR 230
-#define GPIO_USB2_PWR 227
+
+#define USB_CONF(d) \
+ (void *)(uintptr_t)ofw_bus_search_compatible((d), compat_data)->ocd_data
#define A10_READ_4(sc, reg) \
bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
@@ -90,10 +90,32 @@
bs_r_1_proto(reversed);
bs_w_1_proto(reversed);
+struct aw_ehci_conf {
+ int (*clk_activate)(void);
+ int (*clk_deactivate)(void);
+ bool sdram_init;
+};
+
+static const struct aw_ehci_conf a10_ehci_conf = {
+#if defined(SOC_ALLWINNER_A10) || defined(SOC_ALLWINNER_A20)
+ .clk_activate = a10_clk_usb_activate,
+ .clk_deactivate = a10_clk_usb_deactivate,
+#endif
+ .sdram_init = true,
+};
+
+static const struct aw_ehci_conf a31_ehci_conf = {
+#if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S)
+ .clk_activate = a31_clk_ehci_activate,
+ .clk_deactivate = a31_clk_ehci_deactivate,
+#endif
+};
+
static struct ofw_compat_data compat_data[] = {
- {"allwinner,sun4i-a10-ehci", 1},
- {"allwinner,sun7i-a20-ehci", 1},
- {NULL, 0}
+ { "allwinner,sun4i-a10-ehci", (uintptr_t)&a10_ehci_conf },
+ { "allwinner,sun6i-a31-ehci", (uintptr_t)&a31_ehci_conf },
+ { "allwinner,sun7i-a20-ehci", (uintptr_t)&a10_ehci_conf },
+ { NULL, (uintptr_t)NULL }
};
static int
@@ -115,12 +137,18 @@
a10_ehci_attach(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
+ const struct aw_ehci_conf *conf;
bus_space_handle_t bsh;
- device_t sc_gpio_dev;
int err;
int rid;
uint32_t reg_value = 0;
+ conf = USB_CONF(self);
+ if (conf->clk_activate == NULL) {
+ device_printf(self, "clock not supported\n");
+ return (ENXIO);
+ }
+
/* initialise some bus fields */
sc->sc_bus.parent = self;
sc->sc_bus.devices = sc->sc_devices;
@@ -170,13 +198,6 @@
sprintf(sc->sc_vendor, "Allwinner");
- /* Get the GPIO device, we need this to give power to USB */
- sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
- if (sc_gpio_dev == NULL) {
- device_printf(self, "Error: failed to get the GPIO device\n");
- goto error;
- }
-
err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
if (err) {
@@ -188,15 +209,10 @@
sc->sc_flags |= EHCI_SCFLG_DONTRESET;
/* Enable clock for USB */
- a10_clk_usb_activate();
-
- /* Give power to USB */
- GPIO_PIN_SETFLAGS(sc_gpio_dev, GPIO_USB2_PWR, GPIO_PIN_OUTPUT);
- GPIO_PIN_SET(sc_gpio_dev, GPIO_USB2_PWR, GPIO_PIN_HIGH);
-
- /* Give power to USB */
- GPIO_PIN_SETFLAGS(sc_gpio_dev, GPIO_USB1_PWR, GPIO_PIN_OUTPUT);
- GPIO_PIN_SET(sc_gpio_dev, GPIO_USB1_PWR, GPIO_PIN_HIGH);
+ if (conf->clk_activate() != 0) {
+ device_printf(self, "Could not activate clock\n");
+ goto error;
+ }
/* Enable passby */
reg_value = A10_READ_4(sc, SW_USB_PMU_IRQ_ENABLE);
@@ -207,9 +223,11 @@
A10_WRITE_4(sc, SW_USB_PMU_IRQ_ENABLE, reg_value);
/* Configure port */
- reg_value = A10_READ_4(sc, SW_SDRAM_REG_HPCR_USB2);
- reg_value |= SW_SDRAM_BP_HPCR_ACCESS;
- A10_WRITE_4(sc, SW_SDRAM_REG_HPCR_USB2, reg_value);
+ if (conf->sdram_init) {
+ reg_value = A10_READ_4(sc, SW_SDRAM_REG_HPCR_USB2);
+ reg_value |= SW_SDRAM_BP_HPCR_ACCESS;
+ A10_WRITE_4(sc, SW_SDRAM_REG_HPCR_USB2, reg_value);
+ }
err = ehci_init(sc);
if (!err) {
@@ -230,10 +248,13 @@
a10_ehci_detach(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
+ const struct aw_ehci_conf *conf;
device_t bdev;
int err;
uint32_t reg_value = 0;
+ conf = USB_CONF(self);
+
if (sc->sc_bus.bdev) {
bdev = sc->sc_bus.bdev;
device_detach(bdev);
@@ -269,9 +290,11 @@
usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
/* Disable configure port */
- reg_value = A10_READ_4(sc, SW_SDRAM_REG_HPCR_USB2);
- reg_value &= ~SW_SDRAM_BP_HPCR_ACCESS;
- A10_WRITE_4(sc, SW_SDRAM_REG_HPCR_USB2, reg_value);
+ if (conf->sdram_init) {
+ reg_value = A10_READ_4(sc, SW_SDRAM_REG_HPCR_USB2);
+ reg_value &= ~SW_SDRAM_BP_HPCR_ACCESS;
+ A10_WRITE_4(sc, SW_SDRAM_REG_HPCR_USB2, reg_value);
+ }
/* Disable passby */
reg_value = A10_READ_4(sc, SW_USB_PMU_IRQ_ENABLE);
@@ -282,7 +305,7 @@
A10_WRITE_4(sc, SW_USB_PMU_IRQ_ENABLE, reg_value);
/* Disable clock for USB */
- a10_clk_usb_deactivate();
+ conf->clk_deactivate();
return (0);
}
Index: sys/arm/allwinner/a31/a31_clk.h
===================================================================
--- sys/arm/allwinner/a31/a31_clk.h
+++ sys/arm/allwinner/a31/a31_clk.h
@@ -134,8 +134,14 @@
#define A31_CCM_PLL6_CFG_REG_LOCK (1 << 28)
/* AHB_GATING_REG0 */
-#define A31_CCM_AHB_GATING_SDMMC0 (1 << 8)
+#define A31_CCM_AHB_GATING_OHCI2 (1 << 31)
+#define A31_CCM_AHB_GATING_OHCI1 (1 << 30)
+#define A31_CCM_AHB_GATING_OHCI0 (1 << 29)
+#define A31_CCM_AHB_GATING_EHCI1 (1 << 27)
+#define A31_CCM_AHB_GATING_EHCI0 (1 << 26)
+#define A31_CCM_AHB_GATING_USBDRD (1 << 24)
#define A31_CCM_AHB_GATING_GMAC (1 << 17)
+#define A31_CCM_AHB_GATING_SDMMC0 (1 << 8)
#define A31_CCM_PLL_CFG_ENABLE (1U << 31)
#define A31_CCM_PLL_CFG_BYPASS (1U << 30)
@@ -151,6 +157,11 @@
#define A31_CCM_APB2_GATING_TWI (1 << 0)
/* AHB1_RST_REG0 */
+#define A31_CCM_AHB1_RST_REG0_OHCI2 (1 << 31)
+#define A31_CCM_AHB1_RST_REG0_OHCI1 (1 << 30)
+#define A31_CCM_AHB1_RST_REG0_OHCI0 (1 << 29)
+#define A31_CCM_AHB1_RST_REG0_EHCI1 (1 << 27)
+#define A31_CCM_AHB1_RST_REG0_EHCI0 (1 << 26)
#define A31_CCM_AHB1_RST_REG0_GMAC (1 << 17)
#define A31_CCM_AHB1_RST_REG0_SDMMC (1 << 8)
@@ -179,11 +190,24 @@
#define A31_CCM_SD_CLK_OPHASE_CTR_SHIFT 8
#define A31_CCM_SD_CLK_DIV_RATIO_M 0xf
+/* USB */
+#define A31_CCM_USBPHY_CLK_GATING_OHCI2 (1 << 18)
+#define A31_CCM_USBPHY_CLK_GATING_OHCI1 (1 << 17)
+#define A31_CCM_USBPHY_CLK_GATING_OHCI0 (1 << 16)
+#define A31_CCM_USBPHY_CLK_GATING_USBPHY2 (1 << 10)
+#define A31_CCM_USBPHY_CLK_GATING_USBPHY1 (1 << 9)
+#define A31_CCM_USBPHY_CLK_GATING_USBPHY0 (1 << 8)
+#define A31_CCM_USBPHY_CLK_USBPHY2_RST (1 << 2)
+#define A31_CCM_USBPHY_CLK_USBPHY1_RST (1 << 1)
+#define A31_CCM_USBPHY_CLK_USBPHY0_RST (1 << 0)
+
#define A31_CCM_CLK_REF_FREQ 24000000U
int a31_clk_gmac_activate(phandle_t);
int a31_clk_mmc_activate(int);
int a31_clk_mmc_cfg(int, int);
int a31_clk_i2c_activate(int);
+int a31_clk_ehci_activate(void);
+int a31_clk_ehci_deactivate(void);
#endif /* _A31_CLK_H_ */
Index: sys/arm/allwinner/a31/a31_clk.c
===================================================================
--- sys/arm/allwinner/a31/a31_clk.c
+++ sys/arm/allwinner/a31/a31_clk.c
@@ -48,7 +48,9 @@
struct a31_ccm_softc {
struct resource *res;
+ struct mtx mtx;
int pll6_enabled;
+ int ehci_refcnt;
};
static struct a31_ccm_softc *a31_ccm_sc = NULL;
@@ -58,6 +60,9 @@
#define ccm_write_4(sc, reg, val) \
bus_write_4((sc)->res, (reg), (val))
+#define CCM_LOCK(sc) mtx_lock(&(sc)->mtx)
+#define CCM_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
+
#define PLL6_TIMEOUT 10
static int
@@ -90,6 +95,8 @@
return (ENXIO);
}
+ mtx_init(&sc->mtx, "a31 ccm", NULL, MTX_DEF);
+
a31_ccm_sc = sc;
return (0);
@@ -293,3 +300,79 @@
return (0);
}
+
+int
+a31_clk_ehci_activate(void)
+{
+ struct a31_ccm_softc *sc;
+ uint32_t reg_value;
+
+ sc = a31_ccm_sc;
+ if (sc == NULL)
+ return (ENXIO);
+
+ CCM_LOCK(sc);
+ if (++sc->ehci_refcnt == 1) {
+ /* Enable USB PHY */
+ reg_value = ccm_read_4(sc, A31_CCM_USBPHY_CLK);
+ reg_value |= A31_CCM_USBPHY_CLK_GATING_USBPHY0;
+ reg_value |= A31_CCM_USBPHY_CLK_GATING_USBPHY1;
+ reg_value |= A31_CCM_USBPHY_CLK_GATING_USBPHY2;
+ reg_value |= A31_CCM_USBPHY_CLK_USBPHY1_RST;
+ reg_value |= A31_CCM_USBPHY_CLK_USBPHY2_RST;
+ ccm_write_4(sc, A31_CCM_USBPHY_CLK, reg_value);
+
+ /* Gating AHB clock for EHCI */
+ reg_value = ccm_read_4(sc, A31_CCM_AHB_GATING0);
+ reg_value |= A31_CCM_AHB_GATING_EHCI0;
+ reg_value |= A31_CCM_AHB_GATING_EHCI1;
+ ccm_write_4(sc, A31_CCM_AHB_GATING0, reg_value);
+
+ /* De-assert reset */
+ reg_value = ccm_read_4(sc, A31_CCM_AHB1_RST_REG0);
+ reg_value |= A31_CCM_AHB1_RST_REG0_EHCI0;
+ reg_value |= A31_CCM_AHB1_RST_REG0_EHCI1;
+ ccm_write_4(sc, A31_CCM_AHB1_RST_REG0, reg_value);
+ }
+ CCM_UNLOCK(sc);
+
+ return (0);
+}
+
+int
+a31_clk_ehci_deactivate(void)
+{
+ struct a31_ccm_softc *sc;
+ uint32_t reg_value;
+
+ sc = a31_ccm_sc;
+ if (sc == NULL)
+ return (ENXIO);
+
+ CCM_LOCK(sc);
+ if (--sc->ehci_refcnt == 0) {
+ /* Disable USB PHY */
+ reg_value = ccm_read_4(sc, A31_CCM_USBPHY_CLK);
+ reg_value &= ~A31_CCM_USBPHY_CLK_GATING_USBPHY0;
+ reg_value &= ~A31_CCM_USBPHY_CLK_GATING_USBPHY1;
+ reg_value &= ~A31_CCM_USBPHY_CLK_GATING_USBPHY2;
+ reg_value &= ~A31_CCM_USBPHY_CLK_USBPHY1_RST;
+ reg_value &= ~A31_CCM_USBPHY_CLK_USBPHY2_RST;
+ ccm_write_4(sc, A31_CCM_USBPHY_CLK, reg_value);
+
+ /* Gating AHB clock for EHCI */
+ reg_value = ccm_read_4(sc, A31_CCM_AHB_GATING0);
+ reg_value &= ~A31_CCM_AHB_GATING_EHCI0;
+ reg_value &= ~A31_CCM_AHB_GATING_EHCI1;
+ ccm_write_4(sc, A31_CCM_AHB_GATING0, reg_value);
+
+ /* Assert reset */
+ reg_value = ccm_read_4(sc, A31_CCM_AHB1_RST_REG0);
+ reg_value &= ~A31_CCM_AHB1_RST_REG0_EHCI0;
+ reg_value &= ~A31_CCM_AHB1_RST_REG0_EHCI1;
+ ccm_write_4(sc, A31_CCM_AHB1_RST_REG0, reg_value);
+ }
+ CCM_UNLOCK(sc);
+
+ return (0);
+}
Index: sys/arm/allwinner/aw_usbphy.c
===================================================================
--- /dev/null
+++ sys/arm/allwinner/aw_usbphy.c
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Allwinner USB PHY
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/gpio.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "gpio_if.h"
+
+#define USBPHY_NUMOFF 3
+#define GPIO_POLARITY(flags) (((flags) & 1) ? GPIO_PIN_LOW : GPIO_PIN_HIGH)
+
+static struct ofw_compat_data compat_data[] = {
+ { "allwinner,sun4i-a10-usb-phy", 1 },
+ { "allwinner,sun5i-a13-usb-phy", 1 },
+ { "allwinner,sun6i-a31-usb-phy", 1 },
+ { "allwinner,sun7i-a20-usb-phy", 1 },
+ { NULL, 0 }
+};
+
+static int
+awusbphy_gpio_set(device_t dev, phandle_t node, const char *pname)
+{
+ pcell_t gpio_prop[4];
+ phandle_t gpio_node;
+ device_t gpio_dev;
+ uint32_t pin, flags;
+ ssize_t len;
+ int val;
+
+ len = OF_getencprop(node, pname, gpio_prop, sizeof(gpio_prop));
+ if (len == -1)
+ return (0);
+
+ if (len != sizeof(gpio_prop)) {
+ device_printf(dev, "property %s length was %d, expected %d\n",
+ pname, len, sizeof(gpio_prop));
+ return (ENXIO);
+ }
+
+ gpio_node = OF_node_from_xref(gpio_prop[0]);
+ gpio_dev = OF_device_from_xref(gpio_prop[0]);
+ if (gpio_dev == NULL) {
+ device_printf(dev, "failed to get the GPIO device for %s\n",
+ pname);
+ return (ENOENT);
+ }
+
+ if (GPIO_MAP_GPIOS(gpio_dev, node, gpio_node,
+ sizeof(gpio_prop) / sizeof(gpio_prop[0]) - 1, gpio_prop + 1,
+ &pin, &flags) != 0) {
+ device_printf(dev, "failed to map the GPIO pin for %s\n",
+ pname);
+ return (ENXIO);
+ }
+
+ val = GPIO_POLARITY(flags);
+
+ GPIO_PIN_SETFLAGS(gpio_dev, pin, GPIO_PIN_OUTPUT);
+ GPIO_PIN_SET(gpio_dev, pin, val);
+
+ return (0);
+}
+
+static int
+awusbphy_supply_set(device_t dev, const char *pname)
+{
+ phandle_t node, reg_node;
+ pcell_t reg_xref;
+
+ node = ofw_bus_get_node(dev);
+
+ if (OF_getencprop(node, pname, ®_xref, sizeof(reg_xref)) == -1)
+ return (0);
+
+ reg_node = OF_node_from_xref(reg_xref);
+
+ return (awusbphy_gpio_set(dev, reg_node, "gpio"));
+}
+
+static int
+awusbphy_init(device_t dev)
+{
+ char pname[20];
+ phandle_t node;
+ int error, off;
+
+ node = ofw_bus_get_node(dev);
+
+ for (off = 0; off < USBPHY_NUMOFF; off++) {
+ snprintf(pname, sizeof(pname), "usb%d_id_det-gpio", off);
+ error = awusbphy_gpio_set(dev, node, pname);
+ if (error)
+ return (error);
+
+ snprintf(pname, sizeof(pname), "usb%d_vbus_det-gpio", off);
+ error = awusbphy_gpio_set(dev, node, pname);
+ if (error)
+ return (error);
+
+ snprintf(pname, sizeof(pname), "usb%d_vbus-supply", off);
+ error = awusbphy_supply_set(dev, pname);
+ if (error)
+ return (error);
+ }
+
+ return (0);
+}
+
+static int
+awusbphy_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Allwinner USB PHY");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+awusbphy_attach(device_t dev)
+{
+ int error;
+
+ error = awusbphy_init(dev);
+ if (error)
+ device_printf(dev, "failed to initialize USB PHY, error %d\n",
+ error);
+
+ return (error);
+}
+
+static device_method_t awusbphy_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, awusbphy_probe),
+ DEVMETHOD(device_attach, awusbphy_attach),
+
+ DEVMETHOD_END
+};
+
+static driver_t awusbphy_driver = {
+ "awusbphy",
+ awusbphy_methods,
+ 0,
+};
+
+static devclass_t awusbphy_devclass;
+
+DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, awusbphy_devclass, 0, 0);
+MODULE_VERSION(awusbphy, 1);
Index: sys/arm/allwinner/files.allwinner
===================================================================
--- sys/arm/allwinner/files.allwinner
+++ sys/arm/allwinner/files.allwinner
@@ -7,6 +7,7 @@
arm/allwinner/a10_common.c standard
arm/allwinner/a10_dmac.c standard
arm/allwinner/a10_ehci.c optional ehci
+arm/allwinner/aw_usbphy.c optional ehci
arm/allwinner/a10_gpio.c optional gpio
arm/allwinner/a10_mmc.c optional mmc
arm/allwinner/a10_sramc.c standard
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 2, 5:40 PM (3 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16407126
Default Alt Text
D5467.id13848.diff (15 KB)
Attached To
Mode
D5467: Allwinner A31/A31s USB support
Attached
Detach File
Event Timeline
Log In to Comment