* Shashi Ranjan <shashiranjanmca05@gmail.com>
*
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc.
+ * SPDX-License-Identifier: GPL-2.0+
*/
+
#include <common.h>
#include <usb.h>
#include <usb/ulpi.h>
#include <asm/gpio.h>
#include <asm/arch/ehci.h>
#include <asm/ehci-omap.h>
-#include "ehci-core.h"
+
+#include "ehci.h"
static struct omap_uhh *const uhh = (struct omap_uhh *)OMAP_UHH_BASE;
static struct omap_usbtll *const usbtll = (struct omap_usbtll *)OMAP_USBTLL_BASE;
static int omap_uhh_reset(void)
{
- unsigned long init = get_timer(0);
+ int timeout = 0;
+ u32 rev;
+
+ rev = readl(&uhh->rev);
- /* perform UHH soft reset, and wait until reset is complete */
+ /* Soft RESET */
writel(OMAP_UHH_SYSCONFIG_SOFTRESET, &uhh->sysc);
- /* Wait for UHH reset to complete */
- while (!(readl(&uhh->syss) & OMAP_UHH_SYSSTATUS_EHCI_RESETDONE))
- if (get_timer(init) > CONFIG_SYS_HZ) {
- debug("OMAP UHH error: timeout resetting ehci\n");
- return -EL3RST;
+ switch (rev) {
+ case OMAP_USBHS_REV1:
+ /* Wait for soft RESET to complete */
+ while (!(readl(&uhh->syss) & 0x1)) {
+ if (timeout > 100) {
+ printf("%s: RESET timeout\n", __func__);
+ return -1;
+ }
+ udelay(10);
+ timeout++;
+ }
+
+ /* Set No-Idle, No-Standby */
+ writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
+ break;
+
+ default: /* Rev. 2 onwards */
+
+ udelay(2); /* Need to wait before accessing SYSCONFIG back */
+
+ /* Wait for soft RESET to complete */
+ while ((readl(&uhh->sysc) & 0x1)) {
+ if (timeout > 100) {
+ printf("%s: RESET timeout\n", __func__);
+ return -1;
+ }
+ udelay(10);
+ timeout++;
}
+ writel(OMAP_UHH_SYSCONFIG_VAL, &uhh->sysc);
+ break;
+ }
+
return 0;
}
writel(reg, &usbtll->channel_conf + port);
}
+#ifdef CONFIG_USB_ULPI
static void omap_ehci_soft_phy_reset(int port)
{
struct ulpi_viewport ulpi_vp;
ulpi_reset(&ulpi_vp);
}
-
-inline int __board_usb_init(void)
+#else
+static void omap_ehci_soft_phy_reset(int port)
{
- return 0;
+ return;
}
-int board_usb_init(void) __attribute__((weak, alias("__board_usb_init")));
+#endif
#if defined(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO) || \
- defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO)
+ defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO) || \
+ defined(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO)
/* controls PHY(s) reset signal(s) */
static inline void omap_ehci_phy_reset(int on, int delay)
{
gpio_request(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, "USB PHY2 reset");
gpio_direction_output(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, !on);
#endif
+#ifdef CONFIG_OMAP_EHCI_PHY3_RESET_GPIO
+ gpio_request(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, "USB PHY3 reset");
+ gpio_direction_output(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, !on);
+#endif
/* Hold the PHY in RESET for enough time till DIR is high */
/* Refer: ISSUE1 */
* Based on "drivers/usb/host/ehci-omap.c" from Linux 3.1
* See there for additional Copyrights.
*/
-int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata)
+int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata,
+ struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
int ret;
unsigned int i, reg = 0, rev = 0;
debug("Initializing OMAP EHCI\n");
- ret = board_usb_init();
+ ret = board_usb_init(index, USB_INIT_HOST);
if (ret < 0)
return ret;
else
setbits_le32(®, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
} else if (rev == OMAP_USBHS_REV2) {
+
clrsetbits_le32(®, (OMAP_P1_MODE_CLEAR | OMAP_P2_MODE_CLEAR),
OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
- /* Clear port mode fields for PHY mode*/
+ /* Clear port mode fields for PHY mode */
+
+ if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
+ setbits_le32(®, OMAP_P1_MODE_HSIC);
+
+ if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
+ setbits_le32(®, OMAP_P2_MODE_HSIC);
+
+ } else if (rev == OMAP_USBHS_REV2_1) {
+
+ clrsetbits_le32(®,
+ (OMAP_P1_MODE_CLEAR |
+ OMAP_P2_MODE_CLEAR |
+ OMAP_P3_MODE_CLEAR),
+ OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
+
+ /* Clear port mode fields for PHY mode */
if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
setbits_le32(®, OMAP_P1_MODE_HSIC);
if (is_ehci_phy_mode(usbhs_pdata->port_mode[i]))
omap_ehci_soft_phy_reset(i);
- hccr = (struct ehci_hccr *)(OMAP_EHCI_BASE);
- hcor = (struct ehci_hcor *)(OMAP_EHCI_BASE + 0x10);
+ *hccr = (struct ehci_hccr *)(OMAP_EHCI_BASE);
+ *hcor = (struct ehci_hcor *)(OMAP_EHCI_BASE + 0x10);
debug("OMAP EHCI init done\n");
return 0;