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