LPC31 EHCI: Fixes so that high- and low-speed devices work with the EHCI host

This commit is contained in:
Gregory Nutt 2013-11-28 15:13:56 -06:00
parent de797768cd
commit a2117320e3
2 changed files with 63 additions and 16 deletions

View File

@ -3262,12 +3262,16 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
* 00b SE0 Not Low-speed device, perform EHCI reset
* 10b J-state Not Low-speed device, perform EHCI reset
* 01b K-state Low-speed device, release ownership of port
*
* NOTE: Low-speed devices could be detected by examining the PORTSC PSPD
* field after resetting the device. The more convential way here, however,
* also appears to work.
*/
regval = lpc31_getreg(&HCOR->portsc[rhpndx]);
if ((regval & EHCI_PORTSC_LSTATUS_MASK) == EHCI_PORTSC_LSTATUS_KSTATE)
{
/* Paragraph 2.3.9:
/* EHCI Paragraph 2.3.9:
*
* "Port Owner ... This bit unconditionally goes to a 0b when the
* Configured bit in the CONFIGFLAG register makes a 0b to 1b
@ -3281,7 +3285,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
* device. A one in this bit means that a companion host
* controller owns and controls the port. ....
*
* Paragraph 4.2:
* EHCI Paragraph 4.2:
*
* "When a port is routed to a companion HC, it remains under the
* control of the companion HC until the device is disconnected
@ -3296,6 +3300,8 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
*/
rhport->ep0.speed = EHCI_LOW_SPEED;
#if 0 /* The LPC31xx does not support a companion host controller */
regval |= EHCI_PORTSC_OWNER;
lpc31_putreg(regval, &HCOR->portsc[rhpndx]);
@ -3303,6 +3309,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
rhport->connected = false;
return -EPERM;
#endif
}
else
{
@ -3322,7 +3329,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
DEBUGASSERT((lpc31_getreg(&HCOR->usbsts) & EHCI_USBSTS_HALTED) == 0);
/* paragraph 2.3.9:
/* EHCI paragraph 2.3.9:
*
* "When software writes a one to [the Port Reset] bit (from a zero), the
* bus reset sequence as defined in the USB Specification Revision 2.0 is
@ -3351,7 +3358,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
/* Wait for the port reset to complete
*
* Paragraph 2.3.9:
* EHCI Paragraph 2.3.9:
*
* "Note that when software writes a zero to this bit there may be a
* delay before the bit status changes to a zero. The bit status will
@ -3366,7 +3373,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
while ((lpc31_getreg(regaddr) & EHCI_PORTSC_RESET) != 0);
usleep(200*1000);
/* Paragraph 4.2.2:
/* EHCI Paragraph 4.2.2:
*
* "... The reset process is actually complete when software reads a zero
* in the PortReset bit. The EHCI Driver checks the PortEnable bit in the
@ -3380,20 +3387,38 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
* indicate that a full-speed device is attached. In either case the EHCI
* driver sets the PortOwner bit in the PORTSC register to a one to
* release port ownership to a companion host controller."
*
* LPC31xx User Manual Paragraph 6.1.3:
*
* "In a standard EHCI controller design, the EHCI host controller driver
* detects a Full speed (FS) or Low speed (LS) device by noting if the
* port enable bit is set after the port reset operation. The port enable
* will only be set in a standard EHCI controller implementation after the
* port reset operation and when the host and device negotiate a High-Speed
* connection (i.e. Chirp completes successfully). Since this controller has
* an embedded Transaction Translator, the port enable will always be set
* after the port reset operation regardless of the result of the host device
* chirp result and the resulting port speed will be indicated by the PSPD
* field in PORTSC1.
*/
regval = lpc31_getreg(&HCOR->portsc[rhpndx]);
#if 0 /* LPC31xx detects high- vs full-speed devices using the PSPD field */
if ((regval & EHCI_PORTSC_PE) != 0)
#else
if ((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_HS)
#endif
{
/* High speed device */
rhport->ep0.speed = EHCI_HIGH_SPEED;
}
else
else if ((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_FS)
{
/* Low- or Full- speed device. Set the port ownership bit.
*
* Paragraph 4.2:
* EHCI Paragraph 4.2:
*
* "When a port is routed to a companion HC, it remains under the
* control of the companion HC until the device is disconnected
@ -3407,6 +3432,9 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
* repeat."
*/
DEBUGASSERT(rhport->ep0.speed = EHCI_FULL_SPEED);
#if 0 /* The LPC31xx does not support a companion host controller */
regval |= EHCI_PORTSC_OWNER;
lpc31_putreg(regval, &HCOR->portsc[rhpndx]);
@ -3414,6 +3442,15 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
rhport->connected = false;
return -EPERM;
#endif
}
/* Otherwise it must be a low speed device */
else
{
DEBUGASSERT(rhport->ep0.speed = EHCI_LOW_SPEED);
DEBUGASSERT((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_LS)
}
/* Let the common usbhost_enumerate do all of the real work. Note that the
@ -4302,16 +4339,25 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller)
/* Program the controller to be the USB host controller
*
* CM = Host mode
* ES = 0, Little endian mode.
* SLOM Not used in host mode.
* SDIS = 1, Stream disable mode. Eliminates overruns/underruns at
* the expense of some performance.
* VBPS = 1, off-chip power source
* Fixed selections:
*
* CM = Host mode
* ES = 0, Little endian mode.
* SLOM Not used in host mode.
* VBPS = 1, off-chip power source
*
* Configurable selections:
*
* SDIS = 1, Stream disable mode. Eliminates overruns/underruns at
* the expense of some performance.
*/
putreg32(USBHOST_USBMODE_CMHOST /* | USBHOST_USBMODE_SDIS */ | USBHOST_USBMODE_VBPS,
#ifdef CONFIG_LPC31_EHCI_SDIS
putreg32(USBHOST_USBMODE_CMHOST | USBHOST_USBMODE_SDIS | USBHOST_USBMODE_VBPS,
LPC31_USBDEV_USBMODE);
#else
putreg32(USBHOST_USBMODE_CMHOST | USBHOST_USBMODE_VBPS, LPC31_USBDEV_USBMODE);
#endif
/* Host Controller Initialization. Paragraph 4.1 */
/* Reset the EHCI hardware */

View File

@ -422,10 +422,11 @@
/* Port Status and Control register PRTSC1 (address 0x19000184) -- Device Mode */
#define USBDEV_PRTSC1_PSPD_SHIFT (26) /* Bits 26-27: Port speed */
# define USBDEV_PRTSC1_PSPD_MASK (3 << USBDEV_PRTSC1_PSPD_SHIFT)
#define USBDEV_PRTSC1_PSPD_MASK (3 << USBDEV_PRTSC1_PSPD_SHIFT)
# define USBDEV_PRTSC1_PSPD_FS (0 << USBDEV_PRTSC1_PSPD_SHIFT) /* Full-speed */
# define USBDEV_PRTSC1_PSPD_LS (1 << USBDEV_PRTSC1_PSPD_SHIFT) /* Low-speed */
# define USBDEV_PRTSC1_PSPD_HS (2 << USBDEV_PRTSC1_PSPD_SHIFT) /* High-speed */
# define USBDEV_PRTSC1_PFSC (1 << 24) /* Bit 24: Port force full speed connect */
#define USBDEV_PRTSC1_PFSC (1 << 24) /* Bit 24: Port force full speed connect */
#define USBDEV_PRTSC1_PHCD (1 << 23) /* Bit 23: PHY low power suspend - clock disable (PLPSCD) */
#define USBDEV_PRTSC1_PTC_SHIFT (16) /* Bits 16-19: 19: Port test control */
#define USBDEV_PRTSC1_PTC_MASK (15 << USBDEV_PRTSC1_PTC_SHIFT)