summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-08-23 10:58:30 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-08-23 10:58:30 -0600
commit5d2bb2fcaaa33480b2e5fdf1ad522b25b2f5deed (patch)
tree03e7a6c895fc964e04870d54240449b1a47ba02b
parent4d5faa2a3e5001dccc2e9d728f526937e5ef683f (diff)
downloadnuttx-5d2bb2fcaaa33480b2e5fdf1ad522b25b2f5deed.tar.gz
nuttx-5d2bb2fcaaa33480b2e5fdf1ad522b25b2f5deed.tar.bz2
nuttx-5d2bb2fcaaa33480b2e5fdf1ad522b25b2f5deed.zip
SAMA5: Add support for sharing ports when both OHCI and EHCI are enabled
-rw-r--r--nuttx/arch/arm/src/sama5/Kconfig72
-rwxr-xr-xnuttx/arch/arm/src/sama5/sam_ehci.c63
-rw-r--r--nuttx/arch/arm/src/sama5/sam_ohci.c46
-rw-r--r--nuttx/arch/arm/src/sama5/sam_usbhost.h15
-rw-r--r--nuttx/configs/sama5d3x-ek/src/sam_usb.c109
-rw-r--r--nuttx/configs/sama5d3x-ek/src/sama5d3x-ek.h11
6 files changed, 246 insertions, 70 deletions
diff --git a/nuttx/arch/arm/src/sama5/Kconfig b/nuttx/arch/arm/src/sama5/Kconfig
index aadf40224..ce16d974a 100644
--- a/nuttx/arch/arm/src/sama5/Kconfig
+++ b/nuttx/arch/arm/src/sama5/Kconfig
@@ -370,7 +370,7 @@ config SAMA5_OHCI_REGDEBUG
default n
depends on DEBUG
-endif # OHCI
+endif # SAMA5_OHCI
config SAMA5_EHCI
bool "High speed EHCI support"
@@ -408,7 +408,75 @@ config SAMA5_EHCI_REGDEBUG
default n
depends on DEBUG
-endif # EHCI
+endif # SAMA5_EHCI
+
+if SAMA5_OHCI && SAMA5_EHCI
+
+config SAMA5_OHCI_RHPORT1
+ bool "Use Port A for OHCI"
+ default n
+ depends on !SAMA5_UDPHS
+
+config SAMA5_OHCI_RHPORT2
+ bool "Use Port B for OHCI"
+ default n
+
+config SAMA5_OHCI_RHPORT3
+ bool "Use Port C for OHCI"
+ default y
+
+config SAMA5_EHCI_RHPORT1
+ bool
+ default y if !SAMA5_OHCI_RHPORT1
+ default n if SAMA5_OHCI_RHPORT1
+ depends on !SAMA5_UDPHS
+
+config SAMA5_EHCI_RHPORT2
+ bool
+ default y if !SAMA5_OHCI_RHPORT2
+ default n if SAMA5_OHCI_RHPORT2
+
+config SAMA5_EHCI_RHPORT3
+ bool
+ default y if !SAMA5_OHCI_RHPORT3
+ default n if SAMA5_OHCI_RHPORT3
+
+endif # SAMA5_OHCI && SAMA5_EHCI
+
+if SAMA5_OHCI && !SAMA5_EHCI
+
+config SAMA5_OHCI_RHPORT1
+ bool
+ default y
+ depends on !SAMA5_UDPHS
+
+config SAMA5_OHCI_RHPORT2
+ bool
+ default y
+
+config SAMA5_OHCI_RHPORT3
+ bool
+ default y
+
+endif # SAMA5_OHCI && !SAMA5_EHCI
+
+if !SAMA5_OHCI && SAMA5_EHCI
+
+config SAMA5_EHCI_RHPORT1
+ bool
+ default y
+ depends on !SAMA5_UDPHS
+
+config SAMA5_EHCI_RHPORT2
+ bool
+ default y
+
+config SAMA5_EHCI_RHPORT3
+ bool
+ default y
+
+endif # !SAMA5_OHCI && SAMA5_EHCI
+
endmenu # USB High Speed Host driver option
endif # SAMA5_UHPHS
diff --git a/nuttx/arch/arm/src/sama5/sam_ehci.c b/nuttx/arch/arm/src/sama5/sam_ehci.c
index a08025b6b..479d03bb9 100755
--- a/nuttx/arch/arm/src/sama5/sam_ehci.c
+++ b/nuttx/arch/arm/src/sama5/sam_ehci.c
@@ -60,6 +60,7 @@
#include "sam_periphclks.h"
#include "sam_memories.h"
#include "sam_usbhost.h"
+#include "chip/sam_sfr.h"
#include "chip/sam_ehci.h"
#ifdef CONFIG_SAMA5_EHCI
@@ -110,6 +111,18 @@
#undef CONFIG_USBHOST_ISOC_DISABLE
#define CONFIG_USBHOST_ISOC_DISABLE 1
+/* If UDPHS is enabled, then don't use port A */
+
+#ifdef CONFIG_SAMA5_UDPHS
+# undef CONFIG_SAMA5_EHCI_RHPORT1
+#endif
+
+/* For now, suppress use of PORTA in any event. I use that for SAM-BA and
+ * would prefer that the board not try to drive VBUS on that port!
+ */
+
+#undef CONFIG_SAMA5_EHCI_RHPORT1
+
/* Driver-private Definitions **************************************************/
/* This is the set of interrupts handled by this driver */
@@ -874,7 +887,7 @@ static int sam_qh_foreach(struct sam_qh_s *qh, uint32_t **bp, foreach_qh_t handl
* the end of the asynchronous queue?
*/
- else if (sam_virtramaddr(physaddr & QH_HLP_MASK) == &g_asynchead)
+ else if (sam_virtramaddr(physaddr & QH_HLP_MASK) == (uintptr_t)&g_asynchead)
{
/* That will also terminate the loop */
@@ -1973,16 +1986,16 @@ static int sam_qtd_ioccheck(struct sam_qtd_s *qtd, uint32_t **bp, void *arg)
(uintptr_t)&qtd->hw + sizeof(struct ehci_qtd_s));
sam_qtd_print(qtd);
- /* Remove the qTD from the list */
-
- **bp = qtd->hw.nqp;
-
- /* NOTE that we don't check if the qTD is active nor do we check if there
+ /* Remove the qTD from the list
+ *
+ * NOTE that we don't check if the qTD is active nor do we check if there
* are any errors reported in the qTD. If the transfer halted due to
- * an error, then I am not sure if we can believe this information anyway.
- * The only sure place to check for errors in in the QH overlay.
+ * an error, then qTDs in the list after the error qTD will still appear
+ * to be active.
*/
+ **bp = qtd->hw.nqp;
+
/* Release this QH by returning it to the free list */
sam_qtd_free(qtd);
@@ -2064,6 +2077,7 @@ static int sam_qh_ioccheck(struct sam_qh_s *qh, uint32_t **bp, void *arg)
*/
**bp = qh->hw.hlp;
+ cp15_coherent_dcache((uintptr_t)*bp, (uintptr_t)*bp + sizeof(uint32_t));
/* Check for errors, update the data toggle */
@@ -3377,9 +3391,30 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller)
regval = sam_getreg((volatile uint32_t *)SAM_PMC_SCER);
regval |= PMC_UHP;
sam_putreg(regval, (volatile uint32_t *)SAM_PMC_SCER);
+
+ /* "One transceiver is shared with the USB High Speed Device (port A). The
+ * selection between Host Port A and USB Device is controlled by the UDPHS
+ * enable bit (EN_UDPHS) located in the UDPHS_CTRL control register."
+ *
+ * Make all three ports usable for EHCI unless the high speed device is
+ * enabled; then let the device manage port zero. Zero is the reset
+ * value for all ports; one makes the corresponding port available to OHCI.
+ */
+
+ regval = getreg32(SAM_SFR_OHCIICR);
+#ifdef CONFIG_SAMA5_EHCI_RHPORT1
+ regval &= ~SFR_OHCIICR_RES1;
+#endif
+#ifdef CONFIG_SAMA5_EHCI_RHPORT2
+ regval &= ~SFR_OHCIICR_RES1;
+#endif
+#ifdef CONFIG_SAMA5_EHCI_RHPORT3
+ regval &= ~SFR_OHCIICR_RES2;
+#endif
+ putreg32(regval, SAM_SFR_OHCIICR);
irqrestore(flags);
- /* Note that no pin pinconfiguration is required. All USB HS pins have
+ /* Note that no pin configuration is required. All USB HS pins have
* dedicated function
*/
@@ -3631,7 +3666,15 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller)
* mode.
*/
- sam_usbhost_vbusdrive(SAM_EHCI_IFACE, true);
+#ifndef CONFIG_SAMA5_EHCI_RHPORT1
+ sam_usbhost_vbusdrive(SAM_RHPORT1, true);
+#endif
+#ifndef CONFIG_SAMA5_EHCI_RHPORT2
+ sam_usbhost_vbusdrive(SAM_RHPORT2, true);
+#endif
+#ifndef CONFIG_SAMA5_EHCI_RHPORT3
+ sam_usbhost_vbusdrive(SAM_RHPORT3, true);
+#endif
up_mdelay(50);
/* If there is a USB device in the slot at power up, then we will not
diff --git a/nuttx/arch/arm/src/sama5/sam_ohci.c b/nuttx/arch/arm/src/sama5/sam_ohci.c
index ee2160fd1..25c29302a 100644
--- a/nuttx/arch/arm/src/sama5/sam_ohci.c
+++ b/nuttx/arch/arm/src/sama5/sam_ohci.c
@@ -117,6 +117,18 @@
#define SAM_BUFALLOC (CONFIG_SAMA5_OHCI_TDBUFFERS * CONFIG_SAMA5_OHCI_TDBUFSIZE)
+/* If UDPHS is enabled, then don't use port A */
+
+#ifdef CONFIG_SAMA5_UDPHS
+# undef CONFIG_SAMA5_OHCI_RHPORT1
+#endif
+
+/* For now, suppress use of PORTA in any event. I use that for SAM-BA and
+ * would prefer that the board not try to drive VBUS on that port!
+ */
+
+#undef CONFIG_SAMA5_OHCI_RHPORT1
+
/* Debug */
#ifndef CONFIG_DEBUG
@@ -3013,20 +3025,30 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
regval = getreg32(SAM_PMC_SCER);
regval |= PMC_UHP;
putreg32(regval, SAM_PMC_SCER);
- irqrestore(flags);
- /* Make all three ports usable. Zero is the reset value and holds the
- * ports in reset.
- * REVISIT: This will have to change in future. Should be a configuration
- * setting
+ /* "One transceiver is shared with the USB High Speed Device (port A). The
+ * selection between Host Port A and USB Device is controlled by the UDPHS
+ * enable bit (EN_UDPHS) located in the UDPHS_CTRL control register."
+ *
+ * Make all three ports usable for OHCI unless the high speed device is
+ * enabled; then let the device manage port zero. Zero is the reset
+ * value for all ports; one makes the corresponding port available to OHCI.
*/
regval = getreg32(SAM_SFR_OHCIICR);
- regval |= (SFR_OHCIICR_RES0 | SFR_OHCIICR_RES1 | SFR_OHCIICR_RES2);
+#ifdef CONFIG_SAMA5_OHCI_RHPORT1
+ regval |= SFR_OHCIICR_RES1;
+#endif
+#ifdef CONFIG_SAMA5_OHCI_RHPORT2
+ regval |= SFR_OHCIICR_RES1;
+#endif
+#ifdef CONFIG_SAMA5_OHCI_RHPORT3
+ regval |= SFR_OHCIICR_RES2;
+#endif
putreg32(regval, SAM_SFR_OHCIICR);
irqrestore(flags);
- /* Note that no pin pinconfiguration is required. All USB HS pins have
+ /* Note that no pin configuration is required. All USB HS pins have
* dedicated function
*/
@@ -3140,7 +3162,15 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
* mode.
*/
- sam_usbhost_vbusdrive(SAM_OHCI_IFACE, true);
+#ifndef CONFIG_SAMA5_OHCI_RHPORT1
+ sam_usbhost_vbusdrive(SAM_RHPORT1, true);
+#endif
+#ifndef CONFIG_SAMA5_OHCI_RHPORT2
+ sam_usbhost_vbusdrive(SAM_RHPORT2, true);
+#endif
+#ifndef CONFIG_SAMA5_OHCI_RHPORT3
+ sam_usbhost_vbusdrive(SAM_RHPORT3, true);
+#endif
up_mdelay(50);
/* If there is a USB device in the slot at power up, then we will not
diff --git a/nuttx/arch/arm/src/sama5/sam_usbhost.h b/nuttx/arch/arm/src/sama5/sam_usbhost.h
index 47bd7fe15..0a4494a45 100644
--- a/nuttx/arch/arm/src/sama5/sam_usbhost.h
+++ b/nuttx/arch/arm/src/sama5/sam_usbhost.h
@@ -54,6 +54,14 @@
#define SAM_EHCI_IFACE 0
#define SAM_OHCI_IFACE 1
+/* This is the interface argument for call outs to board-specific functions which
+ * need to know which root hub port is being used.
+ */
+
+#define SAM_RHPORT1 0
+#define SAM_RHPORT2 1
+#define SAM_RHPORT3 2
+
/************************************************************************************
* Public Types
************************************************************************************/
@@ -149,9 +157,8 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller);
* each platform that implements the OHCI or EHCI host interface
*
* Input Parameters:
- * iface - Selects USB host interface:
- * 0 = EHCI
- * 1 = OHCI
+ * rhport - Selects root hub port to be powered host interface. See SAM_RHPORT_*
+ * definitions above.
* enable - true: enable VBUS power; false: disable VBUS power
*
* Returned Value:
@@ -159,7 +166,7 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller);
*
***********************************************************************************/
-void sam_usbhost_vbusdrive(int iface, bool enable);
+void sam_usbhost_vbusdrive(int rhport, bool enable);
#undef EXTERN
#if defined(__cplusplus)
diff --git a/nuttx/configs/sama5d3x-ek/src/sam_usb.c b/nuttx/configs/sama5d3x-ek/src/sam_usb.c
index a4c4c16cc..d6b41c2b0 100644
--- a/nuttx/configs/sama5d3x-ek/src/sam_usb.c
+++ b/nuttx/configs/sama5d3x-ek/src/sam_usb.c
@@ -83,6 +83,12 @@ static struct usbhost_connection_s *g_ohciconn;
static struct usbhost_connection_s *g_ehciconn;
#endif
+/* Overcurrent interrupt handler */
+
+#if defined(HAVE_USBHOST) && defined(CONFIG_SAMA5_PIOD_IRQ)
+static xcpt_t g_ochandler;
+#endif
+
/************************************************************************************
* Private Functions
************************************************************************************/
@@ -229,7 +235,7 @@ static int ehci_waiter(int argc, char *argv[])
void weak_function sam_usbinitialize(void)
{
-#if 0
+#ifdef HAVE_USBDEV
/* Configure Port A to support the USB device function */
sam_configpio(PIO_USBA_VBUS_SENSE); /* VBUS sense */
@@ -237,21 +243,20 @@ void weak_function sam_usbinitialize(void)
/* TODO: Configure an interrupt on VBUS sense */
#endif
-#ifdef CONFIG_SAMA5_OHCI
- /* Configure Port C to support the USB OHCI function */
-
- sam_configpio(PIO_USBC_VBUS_ENABLE); /* VBUS enable, initially OFF */
+#ifdef HAVE_USBHOST
+#ifndef HAVE_USBDEV
+ /* Configure Port A to support the USB OHCI/EHCI function only if USB
+ * device is not also supported.
+ */
+ sam_configpio(PIO_USBA_VBUS_ENABLE); /* VBUS enable, initially OFF */
#endif
-#ifdef CONFIG_SAMA5_EHCI
- /* Configure Port B to support the USB OHCI function */
+ /* Configure Ports B and C to support the USB OHCI/EHCI function */
sam_configpio(PIO_USBB_VBUS_ENABLE); /* VBUS enable, initially OFF */
+ sam_configpio(PIO_USBC_VBUS_ENABLE); /* VBUS enable, initially OFF */
-#endif
-
-#if defined(CONFIG_SAMA5_OHCI) || defined(CONFIG_SAMA5_EHCI)
/* Configure Port B/C VBUS overrcurrent detection */
sam_configpio(PIO_USBBC_VBUS_OVERCURRENT); /* VBUS overcurrent */
@@ -271,7 +276,7 @@ void weak_function sam_usbinitialize(void)
#if HAVE_USBHOST
int sam_usbhost_initialize(void)
{
- int pid;
+ pid_t pid;
int ret;
/* First, register all of the class drivers needed to support the drivers
@@ -338,9 +343,8 @@ int sam_usbhost_initialize(void)
* each platform that implements the OHCI or EHCI host interface
*
* Input Parameters:
- * iface - Selects USB host interface:
- * 0 = EHCI (Port B)
- * 1 = OHCI (Port C)
+ * rhport - Selects root hub port to be powered host interface. See SAM_RHPORT_*
+ * definitions above.
* enable - true: enable VBUS power; false: disable VBUS power
*
* Returned Value:
@@ -349,34 +353,37 @@ int sam_usbhost_initialize(void)
***********************************************************************************/
#if HAVE_USBHOST
-void sam_usbhost_vbusdrive(int iface, bool enable)
+void sam_usbhost_vbusdrive(int rhport, bool enable)
{
- pio_pinset_t pinset;
+ pio_pinset_t pinset = 0;
- /* Pick the PIO associated with the OHCI or EHCI interface */
+ uvdbg("RHPort%d: enable=%d\n", rhport+1, enable);
-#ifdef CONFIG_SAMA5_OHCI
- if (iface == SAM_OHCI_IFACE)
+ /* Pick the PIO configuration associated with the selected root hub port */
+
+ switch (rhport)
{
- uvdbg("OHCI: iface %d enable %d\n", iface, enable);
- pinset = PIO_USBC_VBUS_ENABLE;
- }
- else
+ case SAM_RHPORT1:
+#ifdef HAVE_USBDEV
+ udbg("ERROR: RHPort1 is not available in this configuration\n");
+ return;
+#else
+ pinset = PIO_USBA_VBUS_ENABLE;
+ break;
#endif
-#ifdef CONFIG_SAMA5_EHCI
- if (iface == SAM_EHCI_IFACE)
- {
- uvdbg("EHCI: iface %d enable %d\n", iface, enable);
+ case SAM_RHPORT2:
pinset = PIO_USBB_VBUS_ENABLE;
- }
- else
-#endif
+ break;
- {
- udbg("ERROR: Unsupported iface %d\n", iface);
- return;
- }
+ case SAM_RHPORT3:
+ pinset = PIO_USBC_VBUS_ENABLE;
+ break;
+
+ default:
+ udbg("ERROR: RHPort%d is not supported\n", rhport+1);
+ return;
+ }
/* Then enable or disable VBUS power */
@@ -384,13 +391,13 @@ void sam_usbhost_vbusdrive(int iface, bool enable)
{
/* Enable the Power Switch by driving the enable pin low */
- sam_piowrite(pinset, false);
+ sam_piowrite(pinset, false);
}
else
{
/* Disable the Power Switch by driving the enable pin high */
- sam_piowrite(pinset, false);
+ sam_piowrite(pinset, true);
}
}
#endif
@@ -402,6 +409,9 @@ void sam_usbhost_vbusdrive(int iface, bool enable)
* Setup to receive an interrupt-level callback if an overcurrent condition is
* detected.
*
+ * REVISIT: Since this is a common signal, we will need to come up with some way
+ * to inform both EHCI and OHCI drivers when this error occurs.
+ *
* Input paramter:
* handler - New overcurrent interrupt handler
*
@@ -413,12 +423,33 @@ void sam_usbhost_vbusdrive(int iface, bool enable)
#if HAVE_USBHOST
xcpt_t sam_setup_overcurrent(xcpt_t handler)
{
- /* Since this is a common signal, we will need to come up with some way to inform
- * both EHCI and OHCI drivers when this error occurs.
+#if defined(CONFIG_SAMA5_PIOD_IRQ)
+ xcpt_t oldhandler;
+ irqstate_t flags;
+
+ /* Disable interrupts until we are done. This guarantees that the
+ * following operations are atomic.
*/
-# warning Missing logic
+ flags = irqsave();
+
+ /* Get the old button interrupt handler and save the new one */
+
+ oldhandler = *g_ochandler;
+ *g_ochandler = handler;
+
+ /* Configure the interrupt */
+
+ sam_pioirq(IRQ_USBBC_VBUS_OVERCURRENT);
+ (void)irq_attach(IRQ_USBBC_VBUS_OVERCURRENT, handler);
+ sam_pioirqenable(IRQ_USBBC_VBUS_OVERCURRENT);
+
+ /* Return the old button handler (so that it can be restored) */
+
+ return oldhandler;
+#else
return NULL;
+#endif
}
#endif
diff --git a/nuttx/configs/sama5d3x-ek/src/sama5d3x-ek.h b/nuttx/configs/sama5d3x-ek/src/sama5d3x-ek.h
index 9f91aee92..dd77e0f66 100644
--- a/nuttx/configs/sama5d3x-ek/src/sama5d3x-ek.h
+++ b/nuttx/configs/sama5d3x-ek/src/sama5d3x-ek.h
@@ -58,6 +58,7 @@
#define HAVE_HSMCI_MTD 1
#define HAVE_AT25_MTD 1
#define HAVE_USBHOST 1
+#define HAVE_USBDEV 1
/* HSMCI */
/* Can't support MMC/SD if the card interface(s) are not enable */
@@ -120,12 +121,13 @@
#endif
#if !defined(CONFIG_SAMA5_UDPHS)
+# undef HAVE_USBDEV
#endif
/* CONFIG_USBDEV and CONFIG_USBHOST must also be defined */
-#if defined(CONFIG_USBDEV)
-#else
+#if !defined(CONFIG_USBDEV)
+# undef HAVE_USBDEV
#endif
#if defined(CONFIG_USBHOST)
@@ -137,11 +139,6 @@
# undef CONFIG_SAMA5_EHCI
#endif
-#if defined(CONFIG_SAMA5_OHCI) && defined(CONFIG_SAMA5_EHCI)
-# warning Both CONFIG_SAMA5_OHCI and CONFIG_SAMA5_EHCI are defined
-# undef CONFIG_SAMA5_EHCI
-#endif
-
#if !defined(CONFIG_SAMA5_OHCI) && !defined(CONFIG_SAMA5_EHCI)
# undef HAVE_USBHOST
#endif