Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/allwinner/a10_clk.c
Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
#define TCON_RATE_HZ(rate_khz) ((rate_khz) * 1000) | #define TCON_RATE_HZ(rate_khz) ((rate_khz) * 1000) | ||||
#define HDMI_DEFAULT_RATE 297000000 | #define HDMI_DEFAULT_RATE 297000000 | ||||
#define DEBE_DEFAULT_RATE 300000000 | #define DEBE_DEFAULT_RATE 300000000 | ||||
struct a10_ccm_softc { | struct a10_ccm_softc { | ||||
struct resource *res; | struct resource *res; | ||||
bus_space_tag_t bst; | bus_space_tag_t bst; | ||||
bus_space_handle_t bsh; | bus_space_handle_t bsh; | ||||
struct mtx mtx; | |||||
int pll6_enabled; | int pll6_enabled; | ||||
int ehci_cnt; | |||||
int ohci_cnt; | |||||
int usbphy_cnt; | |||||
int usb_cnt; | |||||
}; | }; | ||||
static struct a10_ccm_softc *a10_ccm_sc = NULL; | static struct a10_ccm_softc *a10_ccm_sc = NULL; | ||||
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) \ | #define ccm_read_4(sc, reg) \ | ||||
bus_space_read_4((sc)->bst, (sc)->bsh, (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)) | bus_space_write_4((sc)->bst, (sc)->bsh, (reg), (val)) | ||||
static int | static int | ||||
a10_ccm_probe(device_t dev) | a10_ccm_probe(device_t dev) | ||||
{ | { | ||||
if (!ofw_bus_status_okay(dev)) | if (!ofw_bus_status_okay(dev)) | ||||
return (ENXIO); | return (ENXIO); | ||||
Show All 19 Lines | a10_ccm_attach(device_t dev) | ||||
if (!sc->res) { | if (!sc->res) { | ||||
device_printf(dev, "could not allocate resource\n"); | device_printf(dev, "could not allocate resource\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
sc->bst = rman_get_bustag(sc->res); | sc->bst = rman_get_bustag(sc->res); | ||||
sc->bsh = rman_get_bushandle(sc->res); | sc->bsh = rman_get_bushandle(sc->res); | ||||
mtx_init(&sc->mtx, "a10_ccm", NULL, MTX_DEF); | |||||
a10_ccm_sc = sc; | a10_ccm_sc = sc; | ||||
return (0); | return (0); | ||||
} | } | ||||
static device_method_t a10_ccm_methods[] = { | static device_method_t a10_ccm_methods[] = { | ||||
DEVMETHOD(device_probe, a10_ccm_probe), | DEVMETHOD(device_probe, a10_ccm_probe), | ||||
DEVMETHOD(device_attach, a10_ccm_attach), | DEVMETHOD(device_attach, a10_ccm_attach), | ||||
{ 0, 0 } | { 0, 0 } | ||||
}; | }; | ||||
static driver_t a10_ccm_driver = { | static driver_t a10_ccm_driver = { | ||||
"a10_ccm", | "a10_ccm", | ||||
a10_ccm_methods, | a10_ccm_methods, | ||||
sizeof(struct a10_ccm_softc), | sizeof(struct a10_ccm_softc), | ||||
}; | }; | ||||
static devclass_t a10_ccm_devclass; | static devclass_t a10_ccm_devclass; | ||||
EARLY_DRIVER_MODULE(a10_ccm, simplebus, a10_ccm_driver, a10_ccm_devclass, 0, 0, | EARLY_DRIVER_MODULE(a10_ccm, simplebus, a10_ccm_driver, a10_ccm_devclass, 0, 0, | ||||
BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); | BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); | ||||
int | int | ||||
a10_clk_usb_activate(void) | a10_clk_ehci_activate(void) | ||||
{ | { | ||||
struct a10_ccm_softc *sc = a10_ccm_sc; | struct a10_ccm_softc *sc = a10_ccm_sc; | ||||
uint32_t reg_value; | uint32_t reg_value; | ||||
if (sc == NULL) | if (sc == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
CCM_LOCK(sc); | |||||
if (++sc->ehci_cnt == 1) { | |||||
jmcneill_invisible.ca: This won't activate the device on the first call, you need ++sc->ehci_cnt | |||||
/* Gating AHB clock for USB */ | /* Gating AHB clock for USB */ | ||||
reg_value = ccm_read_4(sc, CCM_AHB_GATING0); | 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_EHCI0; /* AHB clock gate ehci0 */ | ||||
Done Inline ActionsIt looks like some of the clock gate and resets are shared between EHCI and OHCI. You'll need to track references to those separately. jmcneill_invisible.ca: It looks like some of the clock gate and resets are shared between EHCI and OHCI. You'll need… | |||||
reg_value |= CCM_AHB_GATING_EHCI1; /* AHB clock gate ehci1 */ | reg_value |= CCM_AHB_GATING_EHCI1; /* AHB clock gate ehci1 */ | ||||
ccm_write_4(sc, CCM_AHB_GATING0, reg_value); | ccm_write_4(sc, CCM_AHB_GATING0, reg_value); | ||||
} | |||||
a10_clk_usb_activate(sc); | |||||
a10_clk_usbphy_activate(sc); | |||||
CCM_UNLOCK(sc); | |||||
return (0); | |||||
Done Inline ActionsInstead of on/off you should use a counter here. Otherwise detaching a single instance of ehci/ohci will deactivate the others. jmcneill_invisible.ca: Instead of on/off you should use a counter here. Otherwise detaching a single instance of… | |||||
} | |||||
Done Inline Actionsif (--sc->ehci_cnt == 0) { jmcneill_invisible.ca: if (--sc->ehci_cnt == 0) { | |||||
Done Inline ActionsYou need to call this before dropping the lock, and pass in sc for convenience. jmcneill: You need to call this before dropping the lock, and pass in sc for convenience. | |||||
int | |||||
a10_clk_ehci_deactivate(void) | |||||
{ | |||||
struct a10_ccm_softc *sc = a10_ccm_sc; | |||||
uint32_t reg_value; | |||||
if (sc == NULL) | |||||
return (ENXIO); | |||||
CCM_LOCK(sc); | |||||
if (--sc->ehci_cnt == 0) { | |||||
Done Inline Actions++var Should this be ohci_cnt? jmcneill_invisible.ca: ++var
Should this be ohci_cnt? | |||||
/* Disable gating AHB clock for USB */ | |||||
reg_value = ccm_read_4(sc, CCM_AHB_GATING0); | |||||
Done Inline ActionsCall this before dropping the lock. jmcneill: Call this before dropping the lock. | |||||
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); | |||||
} | |||||
Done Inline Actions--ohci_cnt jmcneill_invisible.ca: --ohci_cnt | |||||
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 */ | /* Enable clock for USB */ | ||||
reg_value = ccm_read_4(sc, CCM_USB_CLK); | reg_value = ccm_read_4(sc, CCM_USB_CLK); | ||||
Done Inline ActionsCall this before dropping the lock. jmcneill: Call this before dropping the lock. | |||||
reg_value |= CCM_USB_PHY; /* USBPHY */ | reg_value |= CCM_SCLK_GATING_OHCI0; | ||||
reg_value |= CCM_USB0_RESET; /* disable reset for USB0 */ | reg_value |= CCM_SCLK_GATING_OHCI1; | ||||
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_write_4(sc, CCM_USB_CLK, reg_value); | ||||
} | |||||
a10_clk_usb_activate(sc); | |||||
a10_clk_usbphy_activate(sc); | |||||
CCM_UNLOCK(sc); | |||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
a10_clk_usb_deactivate(void) | a10_clk_ohci_deactivate(void) | ||||
{ | { | ||||
struct a10_ccm_softc *sc = a10_ccm_sc; | struct a10_ccm_softc *sc = a10_ccm_sc; | ||||
uint32_t reg_value; | uint32_t reg_value; | ||||
if (sc == NULL) | if (sc == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
CCM_LOCK(sc); | |||||
if (--sc->ohci_cnt == 0) { | |||||
/* Disable clock for USB */ | /* Disable clock for USB */ | ||||
reg_value = ccm_read_4(sc, CCM_USB_CLK); | reg_value = ccm_read_4(sc, CCM_USB_CLK); | ||||
reg_value &= ~CCM_USB_PHY; /* USBPHY */ | reg_value &= ~CCM_SCLK_GATING_OHCI0; | ||||
reg_value &= ~CCM_USB0_RESET; /* reset for USB0 */ | reg_value &= ~CCM_SCLK_GATING_OHCI1; | ||||
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_write_4(sc, CCM_USB_CLK, reg_value); | ||||
/* Disable gating AHB clock for USB */ | /* Disable gating AHB clock for USB */ | ||||
Done Inline ActionsCall this before dropping the lock. jmcneill: Call this before dropping the lock. | |||||
reg_value = ccm_read_4(sc, CCM_AHB_GATING0); | 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); | |||||
Done Inline ActionsThis can be simplified if you add softc as a parameter. jmcneill: This can be simplified if you add softc as a parameter. | |||||
CCM_UNLOCK(sc); | |||||
return (0); | |||||
} | |||||
Done Inline ActionsInstead of acquiring the lock here, assert that it is held. jmcneill: Instead of acquiring the lock here, assert that it is held. | |||||
static int | |||||
a10_clk_usb_activate(struct a10_ccm_softc *sc) | |||||
{ | |||||
uint32_t reg_value; | |||||
if (sc == NULL) | |||||
return (ENXIO); | |||||
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); | |||||
} | |||||
Done Inline ActionsPass sc as parameter to simplify. jmcneill: Pass sc as parameter to simplify. | |||||
static int | |||||
a10_clk_usb_deactivate(struct a10_ccm_softc *sc) | |||||
{ | |||||
uint32_t reg_value; | |||||
if (sc == NULL) | |||||
Done Inline ActionsSame as activate -- assert that the lock is held instead. jmcneill: Same as activate -- assert that the lock is held instead. | |||||
return (ENXIO); | |||||
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 */ | 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); | 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; | |||||
if (sc == NULL) | |||||
return (ENXIO); | |||||
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; | |||||
if (sc == NULL) | |||||
return (ENXIO); | |||||
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); | return (0); | ||||
} | } | ||||
int | int | ||||
a10_clk_emac_activate(void) | a10_clk_emac_activate(void) | ||||
{ | { | ||||
struct a10_ccm_softc *sc = a10_ccm_sc; | struct a10_ccm_softc *sc = a10_ccm_sc; | ||||
▲ Show 20 Lines • Show All 523 Lines • Show Last 20 Lines |
This won't activate the device on the first call, you need ++sc->ehci_cnt