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@bidouilliste.com>
Reviewed by:	jmcneill
X-Differential Revision:	https://reviews.freebsd.org/D5481
This commit is contained in:
Andrew Turner 2016-03-05 13:17:53 +00:00
parent 3135102b59
commit c794871343
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296408
3 changed files with 199 additions and 37 deletions

View File

@ -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, a10_ccm_driver, a10_ccm_devclass, 0, 0,
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);
/* 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);
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);
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);
}

View File

@ -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);

View File

@ -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,
};