Exemple #1
0
void
omap_tll_utmi_enable(unsigned int en_mask)
{
	struct omap_tll_softc *sc;
	unsigned int i;
	uint32_t reg;

	sc = omap_tll_sc;
	if (sc == NULL)
		return;

	/* There are 3 TLL channels, one per USB controller so set them all up the
	 * same, SDR mode, bit stuffing and no autoidle.
	 */
	for (i=0; i<3; i++) {
		reg = omap_tll_read_4(sc, OMAP_USBTLL_TLL_CHANNEL_CONF(i));

		reg &= ~(TLL_CHANNEL_CONF_UTMIAUTOIDLE
				 | TLL_CHANNEL_CONF_ULPINOBITSTUFF
				 | TLL_CHANNEL_CONF_ULPIDDRMODE);

		omap_tll_write_4(sc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg);
	}

	/* Program the common TLL register */
	reg = omap_tll_read_4(sc, OMAP_USBTLL_TLL_SHARED_CONF);

	reg &= ~( TLL_SHARED_CONF_USB_90D_DDR_EN
			| TLL_SHARED_CONF_USB_DIVRATIO_MASK);
	reg |=  ( TLL_SHARED_CONF_FCLK_IS_ON
			| TLL_SHARED_CONF_USB_DIVRATIO_2
			| TLL_SHARED_CONF_USB_180D_SDR_EN);

	omap_tll_write_4(sc, OMAP_USBTLL_TLL_SHARED_CONF, reg);

	/* Enable channels now */
	for (i = 0; i < 3; i++) {
		reg = omap_tll_read_4(sc, OMAP_USBTLL_TLL_CHANNEL_CONF(i));

		/* Enable only the reg that is needed */
		if ((en_mask & (1 << i)) == 0)
			continue;

		reg |= TLL_CHANNEL_CONF_CHANEN;
		omap_tll_write_4(sc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg);
	}
}
Exemple #2
0
/**
 *	omap_ehci_fini - shutdown the EHCI controller
 *	@isc: omap ehci device context
 *
 *	
 *
 *	LOCKING:
 *	none
 *
 *	RETURNS:
 *	0 on success, a negative error code on failure.
 */
static void
omap_ehci_fini(struct omap_ehci_softc *isc)
{
	unsigned long timeout;
	
	device_printf(isc->sc_dev, "Stopping TI EHCI USB Controller\n");
	
	/* Set the timeout */
	if (hz < 10)
		timeout = 1;
	else
		timeout = (100 * hz) / 1000;

	/* Reset the UHH, OHCI and EHCI modules */
	omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, 0x0002);
	while ((omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSSTATUS) & 0x07) == 0x00) {
		/* Sleep for a tick */
		pause("USBRESET", 1);
		
		if (timeout-- == 0) {
			device_printf(isc->sc_dev, "operation timed out\n");
			break;
		}
	}
	

	/* Set the timeout */
	if (hz < 10)
		timeout = 1;
	else
		timeout = (100 * hz) / 1000;

	/* Reset the TLL module */
	omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, 0x0002);
	while ((omap_tll_read_4(isc, OMAP_USBTLL_SYSSTATUS) & (0x01)) == 0x00) {
		/* Sleep for a tick */
		pause("USBRESET", 1);
		
		if (timeout-- == 0) {
			device_printf(isc->sc_dev, "operation timed out\n");
			break;
		}
	}


	/* Disable functional and interface clocks for the TLL and HOST modules */
	ti_prcm_clk_disable(USBTLL_CLK);
	ti_prcm_clk_disable(USBHSHOST_CLK);

	device_printf(isc->sc_dev, "Clock to USB host has been disabled\n");
	
}
Exemple #3
0
static int
omap_tll_init(struct omap_tll_softc *sc)
{
	unsigned long timeout;
	int ret = 0;

	/* Enable the USB TLL */
	ti_prcm_clk_enable(USBTLL_CLK);

	/* Perform TLL soft reset, and wait until reset is complete */
	omap_tll_write_4(sc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET);

	/* Set the timeout to 100ms*/
	timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);

	/* Wait for TLL reset to complete */
	while ((omap_tll_read_4(sc, OMAP_USBTLL_SYSSTATUS) &
	        TLL_SYSSTATUS_RESETDONE) == 0x00) {

		/* Sleep for a tick */
		pause("USBRESET", 1);

		if (timeout-- == 0) {
			device_printf(sc->sc_dev, "TLL reset operation timed out\n");
			ret = EINVAL;
			goto err_sys_status;
		}
	}

	/* CLOCKACTIVITY = 1 : OCP-derived internal clocks ON during idle
	 * SIDLEMODE = 2     : Smart-idle mode. Sidleack asserted after Idlereq
	 *                     assertion when no more activity on the USB.
	 * ENAWAKEUP = 1     : Wakeup generation enabled
	 */
	omap_tll_write_4(sc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_ENAWAKEUP |
	                                            TLL_SYSCONFIG_AUTOIDLE |
	                                            TLL_SYSCONFIG_SIDLE_SMART_IDLE |
	                                            TLL_SYSCONFIG_CACTIVITY);

	return(0);

err_sys_status:
	/* Disable the TLL clocks */
	ti_prcm_clk_disable(USBTLL_CLK);

	return(ret);
}
Exemple #4
0
static void
omap_tll_disable(struct omap_tll_softc *sc)
{
	unsigned long timeout;

	timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);

	/* Reset the TLL module */
	omap_tll_write_4(sc, OMAP_USBTLL_SYSCONFIG, 0x0002);
	while ((omap_tll_read_4(sc, OMAP_USBTLL_SYSSTATUS) & (0x01)) == 0x00) {
		/* Sleep for a tick */
		pause("USBRESET", 1);

		if (timeout-- == 0) {
			device_printf(sc->sc_dev, "operation timed out\n");
			break;
		}
	}

	/* Disable functional and interface clocks for the TLL and HOST modules */
	ti_prcm_clk_disable(USBTLL_CLK);
}
Exemple #5
0
/**
 *	omap_ehci_init - initialises the USB host EHCI controller
 *	@isc: omap ehci device context
 *
 *	This initialisation routine is quite heavily based on the work done by the
 *	OMAP Linux team (for which I thank them very much).  The init sequence is
 *	almost identical, diverging only for the FreeBSD specifics.
 *
 *	LOCKING:
 *	none
 *
 *	RETURNS:
 *	0 on success, a negative error code on failure.
 */
static int
omap_ehci_init(struct omap_ehci_softc *isc)
{
	unsigned long timeout;
	int ret = 0;
	uint8_t tll_ch_mask = 0;
	uint32_t reg = 0;
	int reset_performed = 0;
	int i;
	
	device_printf(isc->sc_dev, "Starting TI EHCI USB Controller\n");
	
	
	/* Enable Clocks for high speed USBHOST */
	ti_prcm_clk_enable(USBHSHOST_CLK);
	
	/* Hold the PHY in reset while configuring */
	for (int i = 0; i < 3; i++) {
		if (isc->phy_reset[i]) {
			/* Configure the GPIO to drive low (hold in reset) */
			if ((isc->reset_gpio_pin[i] != -1) && (isc->sc_gpio_dev != NULL)) {
				GPIO_PIN_SETFLAGS(isc->sc_gpio_dev, isc->reset_gpio_pin[i],
				    GPIO_PIN_OUTPUT);
				GPIO_PIN_SET(isc->sc_gpio_dev, isc->reset_gpio_pin[i],
				    GPIO_PIN_LOW);
				reset_performed = 1;
			}
		}
	}

	/* Hold the PHY in RESET for enough time till DIR is high */
	if (reset_performed)
		DELAY(10);

	/* Read the UHH revision */
	isc->ehci_rev = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_REVISION);
	device_printf(isc->sc_dev, "UHH revision 0x%08x\n", isc->ehci_rev);
	
	/* Initilise the low level interface module(s) */
	if (isc->ehci_rev == OMAP_EHCI_REV1) {

		/* Enable the USB TLL */
		ti_prcm_clk_enable(USBTLL_CLK);

		/* Perform TLL soft reset, and wait until reset is complete */
		omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET);
	
		/* Set the timeout to 100ms*/
		timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);

		/* Wait for TLL reset to complete */
		while ((omap_tll_read_4(isc, OMAP_USBTLL_SYSSTATUS) & 
		        TLL_SYSSTATUS_RESETDONE) == 0x00) {

			/* Sleep for a tick */
			pause("USBRESET", 1);
		
			if (timeout-- == 0) {
				device_printf(isc->sc_dev, "TLL reset operation timed out\n");
				ret = EINVAL;
				goto err_sys_status;
			}
		}
	
		device_printf(isc->sc_dev, "TLL RESET DONE\n");
		
		/* CLOCKACTIVITY = 1 : OCP-derived internal clocks ON during idle
		 * SIDLEMODE = 2     : Smart-idle mode. Sidleack asserted after Idlereq
		 *                     assertion when no more activity on the USB.
		 * ENAWAKEUP = 1     : Wakeup generation enabled
		 */
		omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_ENAWAKEUP |
		                                            TLL_SYSCONFIG_AUTOIDLE |
		                                            TLL_SYSCONFIG_SIDLE_SMART_IDLE |
		                                            TLL_SYSCONFIG_CACTIVITY);

	} else if (isc->ehci_rev == OMAP_EHCI_REV2) {
	
		/* For OMAP44xx devices you have to enable the per-port clocks:
		 *  PHY_MODE  - External ULPI clock
		 *  TTL_MODE  - Internal UTMI clock
		 *  HSIC_MODE - Internal 480Mhz and 60Mhz clocks
		 */
		if (isc->ehci_rev == OMAP_EHCI_REV2) {
			if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) {
				ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK);
				ti_prcm_clk_enable(USBP1_PHY_CLK);
			} else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
				ti_prcm_clk_enable(USBP1_UTMI_CLK);
			else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
				ti_prcm_clk_enable(USBP1_HSIC_CLK);

			if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) {
				ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK);
				ti_prcm_clk_enable(USBP2_PHY_CLK);
			} else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
				ti_prcm_clk_enable(USBP2_UTMI_CLK);
			else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
				ti_prcm_clk_enable(USBP2_HSIC_CLK);
		}
	}

	/* Put UHH in SmartIdle/SmartStandby mode */
	reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSCONFIG);
	if (isc->ehci_rev == OMAP_EHCI_REV1) {
		reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK |
		         UHH_SYSCONFIG_MIDLEMODE_MASK);
		reg |= (UHH_SYSCONFIG_ENAWAKEUP |
		        UHH_SYSCONFIG_AUTOIDLE |
		        UHH_SYSCONFIG_CLOCKACTIVITY |
		        UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE |
		        UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY);
	} else if (isc->ehci_rev == OMAP_EHCI_REV2) {
		reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK;
		reg |=  UHH_SYSCONFIG_IDLEMODE_NOIDLE;
		reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK;
		reg |=  UHH_SYSCONFIG_STANDBYMODE_NOSTDBY;
	}
	omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, reg);
	device_printf(isc->sc_dev, "OMAP_UHH_SYSCONFIG: 0x%08x\n", reg);

	reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG);
	
	/* Setup ULPI bypass and burst configurations */
	reg |= (UHH_HOSTCONFIG_ENA_INCR4 |
			UHH_HOSTCONFIG_ENA_INCR8 |
			UHH_HOSTCONFIG_ENA_INCR16);
	reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN;
	
	if (isc->ehci_rev == OMAP_EHCI_REV1) {
		if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS;
		if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS;
		if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
			reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS;
	
		/* Bypass the TLL module for PHY mode operation */
		if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
		    (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
		    (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
			reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS;
		else
			reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS;
			
	} else if (isc->ehci_rev == OMAP_EHCI_REV2) {
		reg |=  UHH_HOSTCONFIG_APP_START_CLK;
		
		/* Clear port mode fields for PHY mode*/
		reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK;
		reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK;

		if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY;
		else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
			reg |= UHH_HOSTCONFIG_P1_MODE_HSIC;

		if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY;
		else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
			reg |= UHH_HOSTCONFIG_P2_MODE_HSIC;
	}

	omap_uhh_write_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG, reg);
	device_printf(isc->sc_dev, "UHH setup done, uhh_hostconfig=0x%08x\n", reg);
	

	/* I found the code and comments in the Linux EHCI driver - thanks guys :)
	 *
	 * "An undocumented "feature" in the OMAP3 EHCI controller, causes suspended
	 * ports to be taken out of suspend when the USBCMD.Run/Stop bit is cleared
	 * (for example when we do ehci_bus_suspend). This breaks suspend-resume if
	 * the root-hub is allowed to suspend. Writing 1 to this undocumented
	 * register bit disables this feature and restores normal behavior."
	 */
#if 0
	omap_ehci_write_4(isc, OMAP_USBHOST_INSNREG04,
	                 OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND);
#endif

	/* If any of the ports are configured in TLL mode, enable them */
	if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) ||
		(isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) ||
		(isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) {
		
		if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= 0x1;
		if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= 0x2;
		if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
			tll_ch_mask |= 0x4;
		
		/* Enable UTMI mode for required TLL channels */
		omap_ehci_utmi_init(isc, tll_ch_mask);
	}


	/* Release the PHY reset signal now we have configured everything */
	if (reset_performed) {

		/* Delay for 10ms */
		DELAY(10000);
		
		for (i = 0; i < 3; i++) {
			/* Release reset */
	
			if (isc->phy_reset[i] && (isc->reset_gpio_pin[i] != -1) 
			    && (isc->sc_gpio_dev != NULL)) {
				GPIO_PIN_SET(isc->sc_gpio_dev, 
					isc->reset_gpio_pin[i], GPIO_PIN_HIGH);
			}
		}
	}

	/* Set the interrupt threshold control, it controls the maximum rate at
	 * which the host controller issues interrupts.  We set it to 1 microframe
	 * at startup - the default is 8 mircoframes (equates to 1ms).
	 */
	reg = omap_ehci_read_4(isc, OMAP_USBHOST_USBCMD);
	reg &= 0xff00ffff;
	reg |= (1 << 16);
	omap_ehci_write_4(isc, OMAP_USBHOST_USBCMD, reg);

	/* Soft reset the PHY using PHY reset command over ULPI */
	if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
		omap_ehci_soft_phy_reset(isc, 0);
	if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
		omap_ehci_soft_phy_reset(isc, 1);	

	return(0);

err_sys_status:
	
	/* Disable the TLL clocks */
	ti_prcm_clk_disable(USBTLL_CLK);
	
	/* Disable Clocks for USBHOST */
	ti_prcm_clk_disable(USBHSHOST_CLK);

	return(ret);
}