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:
parent
3135102b59
commit
c794871343
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296408
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user