SAMA5 EHCI: Added logic to detect port speed. Handling is insufficient

This commit is contained in:
Gregory Nutt 2013-08-24 07:36:05 -06:00
parent 3786e72947
commit 1f3cebdb40
2 changed files with 82 additions and 3 deletions

View File

@ -1534,7 +1534,8 @@ static int sam_qtd_addbpl(struct sam_qtd_s *qtd, const void *buffer, size_t bufl
qtd->hw.bpl[ndx] = sam_swap32(physaddr); qtd->hw.bpl[ndx] = sam_swap32(physaddr);
/* Get the next buffer pointer (in the case where we will have to transfer /* Get the next buffer pointer (in the case where we will have to transfer
* more then on 4KB chunks. * more then one chunk). This buffer must be aligned to a 4KB address
* boundary.
*/ */
next = (physaddr + 4096) & ~4095; next = (physaddr + 4096) & ~4095;
@ -2675,6 +2676,51 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
usleep(100*1000); usleep(100*1000);
/* Paragraph 2.3.9:
*
* "Line Status ... These bits reflect the current logical levels of the
* D+ (bit 11) and D- (bit 10) signal lines. These bits are used for
* detection of low-speed USB devices prior to the port reset and enable
* sequence. This field is valid only when the port enable bit is zero
* and the current connect status bit is set to a one."
*
* Bits[11:10] USB State Interpretation
* ----------- --------- --------------
* 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
*/
regval = sam_getreg(&HCOR->portsc[rhpndx]);
if ((regval & EHCI_PORTSC_LSTATUS_MASK) == EHCI_PORTSC_LSTATUS_KSTATE)
{
/* 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
* transition. This bit unconditionally goes to 1b whenever the
* Configured bit is zero.
*
* "System software uses this field to release ownership of the
* port to a selected host controller (in the event that the
* attached device is not a high-speed device). Software writes
* a one to this bit when the attached device is not a high-speed
* device. A one in this bit means that a companion host
* controller owns and controls the port. ....
*/
#warning REVISIT
rhport->ep0.speed = EHCI_LOW_SPEED;
regval &= EHCI_PORTSC_OWNER;
sam_putreg(regval, &HCOR->portsc[rhpndx]);
}
else
{
/* Assume full-speed for now */
rhport->ep0.speed = EHCI_FULL_SPEED;
}
/* Put the root hub port in reset. /* Put the root hub port in reset.
* *
* Paragraph 2.3.9: * Paragraph 2.3.9:
@ -2730,6 +2776,38 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
while ((sam_getreg(regaddr) & EHCI_PORTSC_RESET) != 0); while ((sam_getreg(regaddr) & EHCI_PORTSC_RESET) != 0);
usleep(200*1000); usleep(200*1000);
/* 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
* PORTSC register. If set to a one, the connected device is a high-speed
* device and EHCI Driver (root hub emulator) issues a change report to the
* hub driver and the hub driver continues to enumerate the attached device."
*
* "At the time the EHCI Driver receives the port reset and enable request
* the LineStatus bits might indicate a low-speed device. Additionally,
* when the port reset process is complete, the PortEnable field may
* 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."
*/
#warning REVISIT
regval = sam_getreg(&HCOR->portsc[rhpndx]);
if ((regval & EHCI_PORTSC_PE) != 0)
{
/* High speed device */
rhport->ep0.speed = EHCI_HIGH_SPEED;
}
else
{
/* Low- or Full- speed device */
regval &= EHCI_PORTSC_OWNER;
sam_putreg(regval, &HCOR->portsc[rhpndx]);
}
/* Let the common usbhost_enumerate do all of the real work. Note that the /* Let the common usbhost_enumerate do all of the real work. Note that the
* FunctionAddress (USB address) is set to the root hub port number + 1 * FunctionAddress (USB address) is set to the root hub port number + 1
* for now. * for now.
@ -2818,6 +2896,7 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
static int sam_epalloc(FAR struct usbhost_driver_s *drvr, static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep) const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep)
{ {
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
struct sam_epinfo_s *epinfo; struct sam_epinfo_s *epinfo;
/* Sanity check. NOTE that this method should only be called if a device is /* Sanity check. NOTE that this method should only be called if a device is
@ -2847,11 +2926,12 @@ static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
epinfo->epno = epdesc->addr; epinfo->epno = epdesc->addr;
epinfo->dirin = epdesc->in; epinfo->dirin = epdesc->in;
epinfo->devaddr = epdesc->funcaddr; epinfo->devaddr = epdesc->funcaddr;
epinfo->xfrtype = epdesc->xfrtype;
#ifndef CONFIG_USBHOST_INT_DISABLE #ifndef CONFIG_USBHOST_INT_DISABLE
epinfo->interval = epdesc->interval; epinfo->interval = epdesc->interval;
#endif #endif
epinfo->maxpacket = epdesc->mxpacketsize; epinfo->maxpacket = epdesc->mxpacketsize;
epinfo->xfrtype = epdesc->xfrtype;
epinfo->speed = rhport->ep0.speed;
sem_init(&epinfo->iocsem, 0, 0); sem_init(&epinfo->iocsem, 0, 0);
/* Success.. return an opaque reference to the endpoint information structure /* Success.. return an opaque reference to the endpoint information structure

View File

@ -125,4 +125,3 @@ void stm32_usbhost_vbusdrive(int iface, bool enable);
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* CONFIG_STM32_OTGFS && CONFIG_USBHOST */ #endif /* CONFIG_STM32_OTGFS && CONFIG_USBHOST */
#endif /* __ARCH_ARM_SRC_STM32_STM32_USBHOST_H */ #endif /* __ARCH_ARM_SRC_STM32_STM32_USBHOST_H */