Module Name: src
Committed By: reinoud
Date: Sun Sep 21 15:22:40 UTC 2014
Modified Files:
src/sys/arch/arm/samsung: exynos_usb.c
Log Message:
Fix Exynos5 SoC OHCI hang
Redo the Exynos 5410 USB phy initialisation following uboot
To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/arm/samsung/exynos_usb.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/samsung/exynos_usb.c
diff -u src/sys/arch/arm/samsung/exynos_usb.c:1.9 src/sys/arch/arm/samsung/exynos_usb.c:1.10
--- src/sys/arch/arm/samsung/exynos_usb.c:1.9 Tue Sep 9 21:26:47 2014
+++ src/sys/arch/arm/samsung/exynos_usb.c Sun Sep 21 15:22:40 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: exynos_usb.c,v 1.9 2014/09/09 21:26:47 reinoud Exp $ */
+/* $NetBSD: exynos_usb.c,v 1.10 2014/09/21 15:22:40 reinoud Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: exynos_usb.c,v 1.9 2014/09/09 21:26:47 reinoud Exp $");
+__KERNEL_RCSID(1, "$NetBSD: exynos_usb.c,v 1.10 2014/09/21 15:22:40 reinoud Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -223,11 +223,20 @@ exynos_usb_attach(device_t parent, devic
/*
* Disable interrupts
+ *
+ * To prevent OHCI lockups on Exynos5 SoCs, we first have to read the
+ * address before we set it; this is most likely a bug in the SoC
*/
#if NOHCI > 0
+ int regval;
+
+ regval = bus_space_read_1(sc->sc_bst, sc->sc_ohci_bsh,
+ OHCI_INTERRUPT_DISABLE);
+ regval = OHCI_ALL_INTRS;
bus_space_write_4(sc->sc_bst, sc->sc_ohci_bsh,
- OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
+ OHCI_INTERRUPT_DISABLE, regval);
#endif
+
#if NEHCI > 0
bus_size_t caplength = bus_space_read_1(sc->sc_bst,
sc->sc_ehci_bsh, EHCI_CAPLENGTH);
@@ -504,7 +513,9 @@ exynos4_usb2phy_enable(struct exynos_usb
static void
exynos5410_usb2phy_enable(struct exynos_usb_softc *sc)
{
- uint32_t phyhost, phyotg, phyhsic, ehcictrl, ohcictrl;
+ uint32_t phyhost; //, phyotg;
+ uint32_t phyhsic1, phyhsic2, hsic_ctrl;
+ uint32_t ehcictrl; //, ohcictrl;
/* host configuration: */
phyhost = bus_space_read_4(sc->sc_bst, sc->sc_usb2phy_bsh,
@@ -518,11 +529,11 @@ exynos5410_usb2phy_enable(struct exynos_
phyhost &= ~(HOST_CTRL0_FORCESUSPEND | HOST_CTRL0_FORCESLEEP);
/* host phy reset */
- phyhost &= ~(HOST_CTRL0_PHY_SWRST | HOST_CTRL0_SIDDQ);
+ phyhost &= ~(HOST_CTRL0_PHY_SWRST | HOST_CTRL0_PHY_SWRST_ALL |
+ HOST_CTRL0_SIDDQ | HOST_CTRL0_COMMONON_N);
/* host link reset */
- phyhost |= HOST_CTRL0_LINK_SWRST | HOST_CTRL0_UTMI_SWRST |
- HOST_CTRL0_COMMONON_N;
+ phyhost |= HOST_CTRL0_LINK_SWRST | HOST_CTRL0_UTMI_SWRST;
/* do the reset */
bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
@@ -532,6 +543,7 @@ exynos5410_usb2phy_enable(struct exynos_
bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
USB_PHY_HOST_CTRL0, phyhost);
+#if 0
/* otg configuration: */
phyotg = bus_space_read_4(sc->sc_bst, sc->sc_usb2phy_bsh,
USB_PHY_OTG_SYS);
@@ -557,23 +569,49 @@ exynos5410_usb2phy_enable(struct exynos_
OTG_SYS_PHYLINK_SWRST);
bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
USB_PHY_OTG_SYS, phyotg);
+#endif
/* HSIC phy configuration: */
- phyhsic = REFCLKDIV_12 | REFCLKSEL_HSIC_DEFAULT |
- HSIC_CTRL_PHY_SWRST;
+ hsic_ctrl = HSIC_CTRL_FORCESUSPEND | HSIC_CTRL_FORCESLEEP |
+ HSIC_CTRL_SIDDQ;
+
+ phyhsic1 = bus_space_read_4(sc->sc_bst, sc->sc_usb2phy_bsh,
+ USB_PHY_HSIC_CTRL1);
+ phyhsic2 = bus_space_read_4(sc->sc_bst, sc->sc_usb2phy_bsh,
+ USB_PHY_HSIC_CTRL1);
+
+ phyhsic1 &= ~hsic_ctrl;
+ phyhsic2 &= ~hsic_ctrl;
bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
- USB_PHY_HSIC_CTRL1, phyhsic);
+ USB_PHY_HSIC_CTRL1, phyhsic1);
bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
- USB_PHY_HSIC_CTRL2, phyhsic);
+ USB_PHY_HSIC_CTRL2, phyhsic2);
DELAY(10000);
- phyhsic &= ~HSIC_CTRL_PHY_SWRST;
+
+ hsic_ctrl = REFCLKDIV_12 | REFCLKSEL_HSIC_DEFAULT |
+ HSIC_CTRL_UTMI_SWRST;
+
+ phyhsic1 |= hsic_ctrl;
+ phyhsic2 |= hsic_ctrl;
+
bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
- USB_PHY_HSIC_CTRL1, phyhsic);
+ USB_PHY_HSIC_CTRL1, phyhsic1);
bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
- USB_PHY_HSIC_CTRL2, phyhsic);
+ USB_PHY_HSIC_CTRL2, phyhsic2);
- DELAY(80000);
+ DELAY(10000);
+
+ hsic_ctrl = HSIC_CTRL_PHY_SWRST | HSIC_CTRL_UTMI_SWRST;
+
+ phyhsic1 &= ~hsic_ctrl;
+ phyhsic2 &= ~hsic_ctrl;
+
+ bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
+ USB_PHY_HSIC_CTRL1, phyhsic1);
+ bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
+ USB_PHY_HSIC_CTRL2, phyhsic2);
+ DELAY(20000);
/* enable EHCI DMA burst: */
ehcictrl = bus_space_read_4(sc->sc_bst, sc->sc_usb2phy_bsh,
@@ -583,13 +621,6 @@ exynos5410_usb2phy_enable(struct exynos_
HOST_EHCICTRL_ENA_INCR16;
bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
USB_PHY_HOST_EHCICTRL, ehcictrl);
-
- /* suspend OHCI legacy (?) */
- ohcictrl = bus_space_read_4(sc->sc_bst, sc->sc_usb2phy_bsh,
- USB_PHY_HOST_OHCICTRL);
- ohcictrl |= HOST_OHCICTRL_SUSPLGCY;
- bus_space_write_4(sc->sc_bst, sc->sc_usb2phy_bsh,
- USB_PHY_HOST_OHCICTRL, ohcictrl);
DELAY(10000);
}