svn commit: r296408 - head/sys/arm/allwinner
Andrew Turner
andrew at FreeBSD.org
Sat Mar 5 13:17:55 UTC 2016
Author: andrew
Date: Sat Mar 5 13:17:53 2016
New Revision: 296408
URL: https://svnweb.freebsd.org/changeset/base/296408
Log:
Add support to enable/disable both the EHCI and OHCI Allwinner clocks. This
adds a lock to ensure only a single device is accessing the hardware. A
reference count is added to only enable when we start to use the clock,
and to disable after we have finished needing the clock.
This was extracted from a larger review to add OHCI support to the
Allwinner SoCs.
Submitted by: Emmanuel Vadot <manu at bidouilliste.com>
Reviewed by: jmcneill
X-Differential Revision: https://reviews.freebsd.org/D5481
Modified:
head/sys/arm/allwinner/a10_clk.c
head/sys/arm/allwinner/a10_clk.h
head/sys/arm/allwinner/a10_ehci.c
Modified: head/sys/arm/allwinner/a10_clk.c
==============================================================================
--- head/sys/arm/allwinner/a10_clk.c Sat Mar 5 11:20:02 2016 (r296407)
+++ head/sys/arm/allwinner/a10_clk.c Sat Mar 5 13:17:53 2016 (r296408)
@@ -59,14 +59,27 @@ struct a10_ccm_softc {
struct resource *res;
bus_space_tag_t bst;
bus_space_handle_t bsh;
+ struct mtx mtx;
int pll6_enabled;
+ int ehci_cnt;
+ int ohci_cnt;
+ int usbphy_cnt;
+ int usb_cnt;
};
static struct a10_ccm_softc *a10_ccm_sc = NULL;
-#define ccm_read_4(sc, reg) \
+static int a10_clk_usbphy_activate(struct a10_ccm_softc *sc);
+static int a10_clk_usbphy_deactivate(struct a10_ccm_softc *sc);
+static int a10_clk_usb_activate(struct a10_ccm_softc *sc);
+static int a10_clk_usb_deactivate(struct a10_ccm_softc *sc);
+
+#define CCM_LOCK(sc) mtx_lock(&(sc)->mtx);
+#define CCM_UNLOCK(sc) mtx_unlock(&(sc)->mtx);
+#define CCM_LOCK_ASSERT(sc) mtx_assert(&(sc)->mtx, MA_OWNED)
+#define ccm_read_4(sc, reg) \
bus_space_read_4((sc)->bst, (sc)->bsh, (reg))
-#define ccm_write_4(sc, reg, val) \
+#define ccm_write_4(sc, reg, val) \
bus_space_write_4((sc)->bst, (sc)->bsh, (reg), (val))
static int
@@ -102,6 +115,8 @@ a10_ccm_attach(device_t dev)
sc->bst = rman_get_bustag(sc->res);
sc->bsh = rman_get_bushandle(sc->res);
+ mtx_init(&sc->mtx, "a10_ccm", NULL, MTX_DEF);
+
a10_ccm_sc = sc;
return (0);
@@ -125,7 +140,7 @@ EARLY_DRIVER_MODULE(a10_ccm, simplebus,
BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
int
-a10_clk_usb_activate(void)
+a10_clk_ehci_activate(void)
{
struct a10_ccm_softc *sc = a10_ccm_sc;
uint32_t reg_value;
@@ -133,26 +148,26 @@ a10_clk_usb_activate(void)
if (sc == NULL)
return (ENXIO);
- /* Gating AHB clock for USB */
- reg_value = ccm_read_4(sc, CCM_AHB_GATING0);
- reg_value |= CCM_AHB_GATING_USB0; /* AHB clock gate usb0 */
- reg_value |= CCM_AHB_GATING_EHCI0; /* AHB clock gate ehci0 */
- reg_value |= CCM_AHB_GATING_EHCI1; /* AHB clock gate ehci1 */
- ccm_write_4(sc, CCM_AHB_GATING0, reg_value);
+ CCM_LOCK(sc);
+
+ if (++sc->ehci_cnt == 1) {
+ /* Gating AHB clock for USB */
+ reg_value = ccm_read_4(sc, CCM_AHB_GATING0);
+ reg_value |= CCM_AHB_GATING_EHCI0; /* AHB clock gate ehci0 */
+ reg_value |= CCM_AHB_GATING_EHCI1; /* AHB clock gate ehci1 */
+ ccm_write_4(sc, CCM_AHB_GATING0, reg_value);
+ }
+
+ a10_clk_usb_activate(sc);
+ a10_clk_usbphy_activate(sc);
- /* Enable clock for USB */
- reg_value = ccm_read_4(sc, CCM_USB_CLK);
- reg_value |= CCM_USB_PHY; /* USBPHY */
- reg_value |= CCM_USB0_RESET; /* disable reset for USB0 */
- reg_value |= CCM_USB1_RESET; /* disable reset for USB1 */
- reg_value |= CCM_USB2_RESET; /* disable reset for USB2 */
- ccm_write_4(sc, CCM_USB_CLK, reg_value);
+ CCM_UNLOCK(sc);
return (0);
}
int
-a10_clk_usb_deactivate(void)
+a10_clk_ehci_deactivate(void)
{
struct a10_ccm_softc *sc = a10_ccm_sc;
uint32_t reg_value;
@@ -160,20 +175,160 @@ a10_clk_usb_deactivate(void)
if (sc == NULL)
return (ENXIO);
- /* Disable clock for USB */
- reg_value = ccm_read_4(sc, CCM_USB_CLK);
- reg_value &= ~CCM_USB_PHY; /* USBPHY */
- reg_value &= ~CCM_USB0_RESET; /* reset for USB0 */
- reg_value &= ~CCM_USB1_RESET; /* reset for USB1 */
- reg_value &= ~CCM_USB2_RESET; /* reset for USB2 */
- ccm_write_4(sc, CCM_USB_CLK, reg_value);
+ CCM_LOCK(sc);
- /* Disable gating AHB clock for USB */
- reg_value = ccm_read_4(sc, CCM_AHB_GATING0);
- reg_value &= ~CCM_AHB_GATING_USB0; /* disable AHB clock gate usb0 */
- reg_value &= ~CCM_AHB_GATING_EHCI0; /* disable AHB clock gate ehci0 */
- reg_value &= ~CCM_AHB_GATING_EHCI1; /* disable AHB clock gate ehci1 */
- ccm_write_4(sc, CCM_AHB_GATING0, reg_value);
+ if (--sc->ehci_cnt == 0) {
+ /* Disable gating AHB clock for USB */
+ reg_value = ccm_read_4(sc, CCM_AHB_GATING0);
+ reg_value &= ~CCM_AHB_GATING_EHCI0; /* disable AHB clock gate ehci0 */
+ reg_value &= ~CCM_AHB_GATING_EHCI1; /* disable AHB clock gate ehci1 */
+ ccm_write_4(sc, CCM_AHB_GATING0, reg_value);
+ }
+
+ a10_clk_usb_deactivate(sc);
+ a10_clk_usbphy_deactivate(sc);
+
+ CCM_UNLOCK(sc);
+
+ return (0);
+}
+
+int
+a10_clk_ohci_activate(void)
+{
+ struct a10_ccm_softc *sc = a10_ccm_sc;
+ uint32_t reg_value;
+
+ if (sc == NULL)
+ return (ENXIO);
+
+ CCM_LOCK(sc);
+
+ if (++sc->ohci_cnt == 1) {
+ /* Gating AHB clock for USB */
+ reg_value = ccm_read_4(sc, CCM_AHB_GATING0);
+ reg_value |= CCM_AHB_GATING_OHCI0; /* AHB clock gate ohci0 */
+ reg_value |= CCM_AHB_GATING_OHCI1; /* AHB clock gate ohci1 */
+ ccm_write_4(sc, CCM_AHB_GATING0, reg_value);
+
+ /* Enable clock for USB */
+ reg_value = ccm_read_4(sc, CCM_USB_CLK);
+ reg_value |= CCM_SCLK_GATING_OHCI0;
+ reg_value |= CCM_SCLK_GATING_OHCI1;
+ ccm_write_4(sc, CCM_USB_CLK, reg_value);
+ }
+
+ a10_clk_usb_activate(sc);
+ a10_clk_usbphy_activate(sc);
+
+ CCM_UNLOCK(sc);
+
+ return (0);
+}
+
+int
+a10_clk_ohci_deactivate(void)
+{
+ struct a10_ccm_softc *sc = a10_ccm_sc;
+ uint32_t reg_value;
+
+ if (sc == NULL)
+ return (ENXIO);
+
+ CCM_LOCK(sc);
+
+ if (--sc->ohci_cnt == 0) {
+ /* Disable clock for USB */
+ reg_value = ccm_read_4(sc, CCM_USB_CLK);
+ reg_value &= ~CCM_SCLK_GATING_OHCI0;
+ reg_value &= ~CCM_SCLK_GATING_OHCI1;
+ ccm_write_4(sc, CCM_USB_CLK, reg_value);
+
+ /* Disable gating AHB clock for USB */
+ reg_value = ccm_read_4(sc, CCM_AHB_GATING0);
+ reg_value &= ~CCM_AHB_GATING_OHCI0; /* disable AHB clock gate ohci0 */
+ reg_value &= ~CCM_AHB_GATING_OHCI1; /* disable AHB clock gate ohci1 */
+ ccm_write_4(sc, CCM_AHB_GATING0, reg_value);
+ }
+
+ a10_clk_usb_deactivate(sc);
+ a10_clk_usbphy_deactivate(sc);
+
+ CCM_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+a10_clk_usb_activate(struct a10_ccm_softc *sc)
+{
+ uint32_t reg_value;
+
+ CCM_LOCK_ASSERT(sc);
+
+ if (++sc->usb_cnt == 1) {
+ /* Gating AHB clock for USB */
+ reg_value = ccm_read_4(sc, CCM_AHB_GATING0);
+ reg_value |= CCM_AHB_GATING_USB0; /* AHB clock gate usb0 */
+ ccm_write_4(sc, CCM_AHB_GATING0, reg_value);
+ }
+
+ return (0);
+}
+
+static int
+a10_clk_usb_deactivate(struct a10_ccm_softc *sc)
+{
+ uint32_t reg_value;
+
+ CCM_LOCK_ASSERT(sc);
+
+ if (--sc->usb_cnt == 0) {
+ /* Disable gating AHB clock for USB */
+ reg_value = ccm_read_4(sc, CCM_AHB_GATING0);
+ reg_value &= ~CCM_AHB_GATING_USB0; /* disable AHB clock gate usb0 */
+ ccm_write_4(sc, CCM_AHB_GATING0, reg_value);
+ }
+
+ return (0);
+}
+
+static int
+a10_clk_usbphy_activate(struct a10_ccm_softc *sc)
+{
+ uint32_t reg_value;
+
+ CCM_LOCK_ASSERT(sc);
+
+ if (++sc->usbphy_cnt == 1) {
+ /* Enable clock for USB */
+ reg_value = ccm_read_4(sc, CCM_USB_CLK);
+ reg_value |= CCM_USB_PHY; /* USBPHY */
+ reg_value |= CCM_USBPHY0_RESET; /* disable reset for USBPHY0 */
+ reg_value |= CCM_USBPHY1_RESET; /* disable reset for USBPHY1 */
+ reg_value |= CCM_USBPHY2_RESET; /* disable reset for USBPHY2 */
+ ccm_write_4(sc, CCM_USB_CLK, reg_value);
+ }
+
+ return (0);
+}
+
+static int
+a10_clk_usbphy_deactivate(struct a10_ccm_softc *sc)
+{
+ uint32_t reg_value;
+
+ CCM_LOCK_ASSERT(sc);
+
+ if (--sc->usbphy_cnt == 0) {
+ /* Disable clock for USB */
+ reg_value = ccm_read_4(sc, CCM_USB_CLK);
+ reg_value &= ~CCM_USB_PHY; /* USBPHY */
+ reg_value &= ~CCM_USBPHY0_RESET; /* reset for USBPHY0 */
+ reg_value &= ~CCM_USBPHY1_RESET; /* reset for USBPHY1 */
+ reg_value &= ~CCM_USBPHY2_RESET; /* reset for USBPHY2 */
+ ccm_write_4(sc, CCM_USB_CLK, reg_value);
+ }
return (0);
}
Modified: head/sys/arm/allwinner/a10_clk.h
==============================================================================
--- head/sys/arm/allwinner/a10_clk.h Sat Mar 5 11:20:02 2016 (r296407)
+++ head/sys/arm/allwinner/a10_clk.h Sat Mar 5 13:17:53 2016 (r296408)
@@ -112,7 +112,9 @@
/* AHB_GATING_REG0 */
#define CCM_AHB_GATING_USB0 (1 << 0)
#define CCM_AHB_GATING_EHCI0 (1 << 1)
+#define CCM_AHB_GATING_OHCI0 (1 << 2)
#define CCM_AHB_GATING_EHCI1 (1 << 3)
+#define CCM_AHB_GATING_OHCI1 (1 << 4)
#define CCM_AHB_GATING_DMA (1 << 6)
#define CCM_AHB_GATING_SDMMC0 (1 << 8)
#define CCM_AHB_GATING_EMAC (1 << 17)
@@ -129,10 +131,13 @@
/* APB1_GATING_REG */
#define CCM_APB1_GATING_TWI (1 << 0)
+/* USB */
#define CCM_USB_PHY (1 << 8)
-#define CCM_USB0_RESET (1 << 0)
-#define CCM_USB1_RESET (1 << 1)
-#define CCM_USB2_RESET (1 << 2)
+#define CCM_SCLK_GATING_OHCI1 (1 << 7)
+#define CCM_SCLK_GATING_OHCI0 (1 << 6)
+#define CCM_USBPHY2_RESET (1 << 2)
+#define CCM_USBPHY1_RESET (1 << 1)
+#define CCM_USBPHY0_RESET (1 << 0)
#define CCM_PLL_CFG_ENABLE (1U << 31)
#define CCM_PLL_CFG_BYPASS (1U << 30)
@@ -221,8 +226,10 @@
#define CCM_CLK_REF_FREQ 24000000U
-int a10_clk_usb_activate(void);
-int a10_clk_usb_deactivate(void);
+int a10_clk_ehci_activate(void);
+int a10_clk_ehci_deactivate(void);
+int a10_clk_ohci_activate(void);
+int a10_clk_ohci_deactivate(void);
int a10_clk_emac_activate(void);
int a10_clk_gmac_activate(phandle_t);
int a10_clk_ahci_activate(void);
Modified: head/sys/arm/allwinner/a10_ehci.c
==============================================================================
--- head/sys/arm/allwinner/a10_ehci.c Sat Mar 5 11:20:02 2016 (r296407)
+++ head/sys/arm/allwinner/a10_ehci.c Sat Mar 5 13:17:53 2016 (r296408)
@@ -98,8 +98,8 @@ struct aw_ehci_conf {
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,
+ .clk_activate = a10_clk_ehci_activate,
+ .clk_deactivate = a10_clk_ehci_deactivate,
#endif
.sdram_init = true,
};
More information about the svn-src-all
mailing list