Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/allwinner/a10_clk.c
Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
#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; | ||||
int pll6_enabled; | int pll6_enabled; | ||||
int ehci_enabled; | |||||
int ohci_enabled; | |||||
}; | }; | ||||
static struct a10_ccm_softc *a10_ccm_sc = NULL; | static struct a10_ccm_softc *a10_ccm_sc = NULL; | ||||
#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)) | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
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); | ||||
/* 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_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 */ | ||||
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); | ||||
/* Enable clock for USB */ | /* Enable clock for USB */ | ||||
jmcneill_invisible.ca: This won't activate the device on the first call, you need ++sc->ehci_cnt | |||||
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_USB_PHY; /* USBPHY */ | ||||
reg_value |= CCM_USB0_RESET; /* disable reset for USB0 */ | reg_value |= CCM_USB0_RESET; /* disable reset for USB0 */ | ||||
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_USB1_RESET; /* disable reset for USB1 */ | reg_value |= CCM_USB1_RESET; /* disable reset for USB1 */ | ||||
reg_value |= CCM_USB2_RESET; /* disable reset for USB2 */ | 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); | ||||
sc->ehci_enabled = 1; | |||||
jmcneill_invisible.caUnsubmitted 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… | |||||
return (0); | return (0); | ||||
} | } | ||||
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 | int | ||||
a10_clk_usb_deactivate(void) | a10_clk_ehci_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); | ||||
if (sc->ehci_enabled == 0) | |||||
return (0); | |||||
/* Disable clock for USB */ | /* Disable clock for USB */ | ||||
if (sc->ohci_enabled == 0) { | |||||
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_USB_PHY; /* USBPHY */ | ||||
Done Inline Actions++var Should this be ohci_cnt? jmcneill_invisible.ca: ++var
Should this be ohci_cnt? | |||||
reg_value &= ~CCM_USB0_RESET; /* reset for USB0 */ | reg_value &= ~CCM_USB0_RESET; /* reset for USB0 */ | ||||
reg_value &= ~CCM_USB1_RESET; /* reset for USB1 */ | reg_value &= ~CCM_USB1_RESET; /* reset for USB1 */ | ||||
reg_value &= ~CCM_USB2_RESET; /* reset for USB2 */ | 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 */ | ||||
reg_value = ccm_read_4(sc, CCM_AHB_GATING0); | reg_value = ccm_read_4(sc, CCM_AHB_GATING0); | ||||
if (sc->ohci_enabled == 0) | |||||
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_EHCI0; /* disable AHB clock gate ehci0 */ | ||||
reg_value &= ~CCM_AHB_GATING_EHCI1; /* disable AHB clock gate ehci1 */ | reg_value &= ~CCM_AHB_GATING_EHCI1; /* disable AHB clock gate ehci1 */ | ||||
ccm_write_4(sc, CCM_AHB_GATING0, reg_value); | |||||
return (0); | |||||
Done Inline ActionsCall this before dropping the lock. jmcneill: Call this before dropping the lock. | |||||
} | |||||
int | |||||
a10_clk_ohci_activate(void) | |||||
{ | |||||
struct a10_ccm_softc *sc = a10_ccm_sc; | |||||
uint32_t reg_value; | |||||
if (sc == NULL) | |||||
return (ENXIO); | |||||
/* Gating AHB clock for USB */ | |||||
Done Inline Actions--ohci_cnt jmcneill_invisible.ca: --ohci_cnt | |||||
reg_value = ccm_read_4(sc, CCM_AHB_GATING0); | |||||
reg_value |= CCM_AHB_GATING_USB0; /* AHB clock gate usb0 */ | |||||
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_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 */ | |||||
reg_value |= CCM_SCLK_GATING_OHCI0; | |||||
reg_value |= CCM_SCLK_GATING_OHCI1; | |||||
ccm_write_4(sc, CCM_USB_CLK, reg_value); | |||||
sc->ohci_enabled = 1; | |||||
return (0); | |||||
} | |||||
int | |||||
Done Inline ActionsCall this before dropping the lock. jmcneill: Call this before dropping the lock. | |||||
a10_clk_ohci_deactivate(void) | |||||
{ | |||||
struct a10_ccm_softc *sc = a10_ccm_sc; | |||||
uint32_t reg_value; | |||||
if (sc == NULL) | |||||
return (ENXIO); | |||||
if (sc->ohci_enabled == 0) | |||||
return (0); | |||||
/* Disable clock for USB */ | |||||
reg_value = ccm_read_4(sc, CCM_USB_CLK); | |||||
if (sc->ehci_enabled == 0) { | |||||
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 */ | |||||
} | |||||
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); | |||||
if (sc->ehci_enabled == 0) | |||||
reg_value &= ~CCM_AHB_GATING_USB0; /* disable AHB clock gate usb0 */ | |||||
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); | ccm_write_4(sc, CCM_AHB_GATING0, reg_value); | ||||
return (0); | return (0); | ||||
Done Inline ActionsCall this before dropping the lock. jmcneill: Call this before dropping the lock. | |||||
} | } | ||||
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; | ||||
uint32_t reg_value; | uint32_t reg_value; | ||||
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. | |||||
if (sc == NULL) | if (sc == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
/* Gating AHB clock for EMAC */ | /* Gating AHB clock for EMAC */ | ||||
reg_value = ccm_read_4(sc, CCM_AHB_GATING0); | reg_value = ccm_read_4(sc, CCM_AHB_GATING0); | ||||
reg_value |= CCM_AHB_GATING_EMAC; | reg_value |= CCM_AHB_GATING_EMAC; | ||||
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. | |||||
ccm_write_4(sc, CCM_AHB_GATING0, reg_value); | ccm_write_4(sc, CCM_AHB_GATING0, reg_value); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
a10_clk_gmac_activate(phandle_t node) | a10_clk_gmac_activate(phandle_t node) | ||||
{ | { | ||||
char *phy_type; | char *phy_type; | ||||
struct a10_ccm_softc *sc; | struct a10_ccm_softc *sc; | ||||
uint32_t reg_value; | uint32_t reg_value; | ||||
sc = a10_ccm_sc; | sc = a10_ccm_sc; | ||||
if (sc == NULL) | if (sc == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
/* Gating AHB clock for GMAC */ | /* Gating AHB clock for GMAC */ | ||||
reg_value = ccm_read_4(sc, CCM_AHB_GATING1); | reg_value = ccm_read_4(sc, CCM_AHB_GATING1); | ||||
reg_value |= CCM_AHB_GATING_GMAC; | reg_value |= CCM_AHB_GATING_GMAC; | ||||
ccm_write_4(sc, CCM_AHB_GATING1, reg_value); | ccm_write_4(sc, CCM_AHB_GATING1, reg_value); | ||||
Done Inline ActionsPass sc as parameter to simplify. jmcneill: Pass sc as parameter to simplify. | |||||
/* Set GMAC mode. */ | /* Set GMAC mode. */ | ||||
reg_value = CCM_GMAC_CLK_MII; | reg_value = CCM_GMAC_CLK_MII; | ||||
if (OF_getprop_alloc(node, "phy-mode", 1, (void **)&phy_type) > 0) { | if (OF_getprop_alloc(node, "phy-mode", 1, (void **)&phy_type) > 0) { | ||||
if (strcasecmp(phy_type, "rgmii") == 0) | if (strcasecmp(phy_type, "rgmii") == 0) | ||||
reg_value = CCM_GMAC_CLK_RGMII | CCM_GMAC_MODE_RGMII; | reg_value = CCM_GMAC_CLK_RGMII | CCM_GMAC_MODE_RGMII; | ||||
Done Inline ActionsSame as activate -- assert that the lock is held instead. jmcneill: Same as activate -- assert that the lock is held instead. | |||||
else if (strcasecmp(phy_type, "rgmii-bpi") == 0) { | else if (strcasecmp(phy_type, "rgmii-bpi") == 0) { | ||||
reg_value = CCM_GMAC_CLK_RGMII | CCM_GMAC_MODE_RGMII; | reg_value = CCM_GMAC_CLK_RGMII | CCM_GMAC_MODE_RGMII; | ||||
reg_value |= (3 << CCM_GMAC_CLK_DELAY_SHIFT); | reg_value |= (3 << CCM_GMAC_CLK_DELAY_SHIFT); | ||||
} | } | ||||
free(phy_type, M_OFWPROP); | free(phy_type, M_OFWPROP); | ||||
} | } | ||||
ccm_write_4(sc, CCM_GMAC_CLK, reg_value); | ccm_write_4(sc, CCM_GMAC_CLK, reg_value); | ||||
▲ Show 20 Lines • Show All 481 Lines • Show Last 20 Lines |
This won't activate the device on the first call, you need ++sc->ehci_cnt