mirror of
https://github.com/apache/nuttx.git
synced 2026-06-01 16:59:28 +08:00
SAMA5 OHCI: Use physical address and flush and/or invalidate data caches as necessary
This commit is contained in:
@@ -5330,7 +5330,7 @@
|
|||||||
* arch/arm/src/sama5/sam_dmac.c: Finally after many bugfixes (the
|
* arch/arm/src/sama5/sam_dmac.c: Finally after many bugfixes (the
|
||||||
last being caching issues), the SAMA5 DMA support has been
|
last being caching issues), the SAMA5 DMA support has been
|
||||||
verified (with SPI) (2013-8-9).
|
verified (with SPI) (2013-8-9).
|
||||||
* arch/arm/src/sama5/sam_memories.c and .h: Central logic for
|
* arch/arm/src/sama5/sam_memories.c and .h: Centralize logic for
|
||||||
conversions between physical and virtual addresses (2013-8-9).
|
conversions between physical and virtual addresses (2013-8-9).
|
||||||
* arch/arm/src/sama5/sam_hsmci.c and sam34/sam_hsmci.c: Correct a
|
* arch/arm/src/sama5/sam_hsmci.c and sam34/sam_hsmci.c: Correct a
|
||||||
race condition in the SAMA5 HSCMI driver: The tranfer done
|
race condition in the SAMA5 HSCMI driver: The tranfer done
|
||||||
@@ -5404,3 +5404,7 @@
|
|||||||
passes information associated with the RHport implicitly. The klugey,
|
passes information associated with the RHport implicitly. The klugey,
|
||||||
procedural alternative was to add the function address to every
|
procedural alternative was to add the function address to every
|
||||||
interface method (which I started to do but backed above) (2013-8-13).
|
interface method (which I started to do but backed above) (2013-8-13).
|
||||||
|
* arch/arm/src/sama5/sam_memories.c and .h: Extended logic so do
|
||||||
|
conversions from physical to virtual addresses (2013-8-14).
|
||||||
|
* arch/arm/src/sama5/sam_ohci.c: Add D cache contols and conversion
|
||||||
|
between physical and virtual address (2013-8-14).
|
||||||
|
|||||||
@@ -348,15 +348,15 @@ config SAMA5_OHCI
|
|||||||
if SAMA5_OHCI
|
if SAMA5_OHCI
|
||||||
config SAMA5_OHCI_NEDS
|
config SAMA5_OHCI_NEDS
|
||||||
int "Number of endpoint descriptors"
|
int "Number of endpoint descriptors"
|
||||||
default 2
|
default 6
|
||||||
|
|
||||||
config SAMA5_OHCI_NTDS
|
config SAMA5_OHCI_NTDS
|
||||||
int "Number of transfer descriptors"
|
int "Number of transfer descriptors"
|
||||||
default 3
|
default 9
|
||||||
|
|
||||||
config SAMA5_OHCI_TDBUFFERS
|
config SAMA5_OHCI_TDBUFFERS
|
||||||
int "Number of transfer descriptor buffers"
|
int "Number of transfer descriptor buffers"
|
||||||
default 2
|
default 6
|
||||||
|
|
||||||
config SAMA5_OHCI_TDBUFSIZE
|
config SAMA5_OHCI_TDBUFSIZE
|
||||||
int "Size of one transfer descriptor buffer"
|
int "Size of one transfer descriptor buffer"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -82,7 +82,7 @@ extern "C"
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
uintptr_t sam_physregaddr(uintptr_t vregaddr);
|
uintptr_t sam_physregaddr(uintptr_t virtregaddr);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: sam_physramaddr
|
* Name: sam_physramaddr
|
||||||
@@ -93,7 +93,18 @@ uintptr_t sam_physregaddr(uintptr_t vregaddr);
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
uintptr_t sam_physramaddr(uintptr_t vregaddr);
|
uintptr_t sam_physramaddr(uintptr_t vramaddr);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sam_virtramaddr
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Give the phsical address of a RAM memory location, return the virtual
|
||||||
|
* address of that location.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
uintptr_t sam_virtramaddr(uintptr_t physramaddr);
|
||||||
|
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
|
|||||||
+158
-74
@@ -61,8 +61,10 @@
|
|||||||
#include "up_arch.h"
|
#include "up_arch.h"
|
||||||
#include "up_internal.h"
|
#include "up_internal.h"
|
||||||
|
|
||||||
|
#include "cache.h"
|
||||||
#include "chip.h"
|
#include "chip.h"
|
||||||
#include "sam_periphclks.h"
|
#include "sam_periphclks.h"
|
||||||
|
#include "sam_memories.h"
|
||||||
#include "sam_usbhost.h"
|
#include "sam_usbhost.h"
|
||||||
#include "chip/sam_pmc.h"
|
#include "chip/sam_pmc.h"
|
||||||
#include "chip/sam_sfr.h"
|
#include "chip/sam_sfr.h"
|
||||||
@@ -73,14 +75,6 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
/* Configuration ***************************************************************/
|
/* Configuration ***************************************************************/
|
||||||
|
|
||||||
/* Fixed endpoint descriptor size. The actual size required by the hardware is only
|
|
||||||
* 16 bytes, however, we set aside an additional 16 bytes for for internal use by
|
|
||||||
* the OHCI host driver. 16-bytes is set aside because the EDs must still be
|
|
||||||
* aligned to 16-byte boundaries.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define SAM_ED_SIZE 32
|
|
||||||
|
|
||||||
/* Configurable number of user endpoint descriptors (EDs). This number excludes
|
/* Configurable number of user endpoint descriptors (EDs). This number excludes
|
||||||
* the control endpoint that is always allocated.
|
* the control endpoint that is always allocated.
|
||||||
*/
|
*/
|
||||||
@@ -89,14 +83,6 @@
|
|||||||
# define CONFIG_SAMA5_OHCI_NEDS 2
|
# define CONFIG_SAMA5_OHCI_NEDS 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Fixed transfer descriptor size. The actual size required by the hardware is
|
|
||||||
* only 16 bytes, however, we set aside an additional 16 bytes for for internal
|
|
||||||
* use by the OHCI host driver. 16-bytes is set aside because the TDs must still
|
|
||||||
* be aligned to 16-byte boundaries.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define SAM_TD_SIZE 32
|
|
||||||
|
|
||||||
/* Configurable number of user transfer descriptors (TDs). */
|
/* Configurable number of user transfer descriptors (TDs). */
|
||||||
|
|
||||||
#ifndef CONFIG_SAMA5_OHCI_NTDS
|
#ifndef CONFIG_SAMA5_OHCI_NTDS
|
||||||
@@ -198,7 +184,7 @@ struct sam_rhport_s
|
|||||||
struct usbhost_class_s *class;
|
struct usbhost_class_s *class;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This structure retains the state of the USB host controller */
|
/* This structure retains the overall state of the USB host controller */
|
||||||
|
|
||||||
struct sam_ohci_s
|
struct sam_ohci_s
|
||||||
{
|
{
|
||||||
@@ -219,27 +205,34 @@ struct sam_ohci_s
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* The OCHI expects the size of an endpoint descriptor to be 16 bytes.
|
/* The OCHI expects the size of an endpoint descriptor to be 16 bytes.
|
||||||
* However, the size allocated for an endpoint descriptor is 32 bytes in
|
* However, the size allocated for an endpoint descriptor is 32 bytes. This
|
||||||
* sam_ohciram.h. This extra 16-bytes is used by the OHCI host driver in
|
* extra 16-bytes is used by the OHCI host driver in order to maintain
|
||||||
* order to maintain additional endpoint-specific data.
|
* additional endpoint-specific data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define SAMD_ED_PADSIZE (12 - sizeof(sem_t))
|
||||||
|
|
||||||
struct sam_ed_s
|
struct sam_ed_s
|
||||||
{
|
{
|
||||||
/* Hardware specific fields */
|
/* Hardware specific fields */
|
||||||
|
|
||||||
struct ohci_ed_s hw;
|
struct ohci_ed_s hw; /* 0-15 */
|
||||||
|
|
||||||
/* Software specific fields */
|
/* Software specific fields */
|
||||||
|
|
||||||
uint8_t xfrtype; /* Transfer type. See SB_EP_ATTR_XFER_* in usb.h */
|
uint8_t xfrtype; /* 16: Transfer type. See SB_EP_ATTR_XFER_* in usb.h */
|
||||||
uint8_t interval; /* Periodic EP polling interval: 2, 4, 6, 16, or 32 */
|
uint8_t interval; /* 17: Periodic EP polling interval: 2, 4, 6, 16, or 32 */
|
||||||
volatile uint8_t tdstatus; /* TD control status bits from last Writeback Done Head event */
|
volatile uint8_t tdstatus; /* 18: TD control status bits from last Writeback Done Head event */
|
||||||
volatile bool wdhwait; /* TRUE: Thread is waiting for WDH interrupt */
|
volatile bool wdhwait; /* 19: TRUE: Thread is waiting for WDH interrupt */
|
||||||
sem_t wdhsem; /* Semaphore used to wait for Writeback Done Head event */
|
sem_t wdhsem; /* 20-23: Semaphore used to wait for Writeback Done Head event */
|
||||||
/* Unused bytes follow, depending on the size of sem_t */
|
|
||||||
|
/* Padding to 32-bytes follow. The amount of padding depends on the size of sem_t */
|
||||||
|
|
||||||
|
uint8_t pad[SAMD_ED_PADSIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SIZEOF_SAM_ED_S 32
|
||||||
|
|
||||||
/* The OCHI expects the size of an transfer descriptor to be 16 bytes.
|
/* The OCHI expects the size of an transfer descriptor to be 16 bytes.
|
||||||
* However, the size allocated for an endpoint descriptor is 32 bytes in
|
* However, the size allocated for an endpoint descriptor is 32 bytes in
|
||||||
* RAM. This extra 16-bytes is used by the OHCI host driver in order to
|
* RAM. This extra 16-bytes is used by the OHCI host driver in order to
|
||||||
@@ -250,15 +243,17 @@ struct sam_gtd_s
|
|||||||
{
|
{
|
||||||
/* Hardware specific fields */
|
/* Hardware specific fields */
|
||||||
|
|
||||||
struct ohci_gtd_s hw;
|
struct ohci_gtd_s hw; /* 0-15 */
|
||||||
|
|
||||||
/* Software specific fields */
|
/* Software specific fields */
|
||||||
|
|
||||||
struct sam_ed_s *ed; /* Pointer to parent ED */
|
struct sam_ed_s *ed; /* 16-19: Pointer to parent ED */
|
||||||
bool prealloc; /* Indicates a pre-allocated ED */
|
bool prealloc; /* 20: Indicates a pre-allocated ED */
|
||||||
uint8_t pad[11];
|
uint8_t pad[11]; /* 21-31: Pad to 32 bytes */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SIZEOF_SAM_TD_S 32
|
||||||
|
|
||||||
/* The following is used to manage lists of free EDs, TDs, and TD buffers */
|
/* The following is used to manage lists of free EDs, TDs, and TD buffers */
|
||||||
|
|
||||||
struct sam_list_s
|
struct sam_list_s
|
||||||
@@ -730,11 +725,14 @@ static inline int sam_addbulked(struct sam_ed_s *ed)
|
|||||||
{
|
{
|
||||||
#ifndef CONFIG_USBHOST_BULK_DISABLE
|
#ifndef CONFIG_USBHOST_BULK_DISABLE
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
uintptr_t physed;
|
||||||
|
|
||||||
/* Add the new bulk ED to the head of the bulk list */
|
/* Add the new bulk ED to the head of the bulk list */
|
||||||
|
|
||||||
ed->hw.nexted = sam_getreg(SAM_USBHOST_BULKHEADED);
|
ed->hw.nexted = sam_getreg(SAM_USBHOST_BULKHEADED);
|
||||||
sam_putreg((uint32_t)ed, SAM_USBHOST_BULKHEADED);
|
|
||||||
|
physed = sam_physramaddr((uintptr_t)ed);
|
||||||
|
sam_putreg((uint32_t)physed, SAM_USBHOST_BULKHEADED);
|
||||||
|
|
||||||
/* BulkListEnable. This bit is set to enable the processing of the
|
/* BulkListEnable. This bit is set to enable the processing of the
|
||||||
* Bulk list. Note: once enabled, it remains. We really should
|
* Bulk list. Note: once enabled, it remains. We really should
|
||||||
@@ -763,14 +761,15 @@ static inline int sam_rembulked(struct sam_ed_s *ed)
|
|||||||
#ifndef CONFIG_USBHOST_BULK_DISABLE
|
#ifndef CONFIG_USBHOST_BULK_DISABLE
|
||||||
struct sam_ed_s *curr;
|
struct sam_ed_s *curr;
|
||||||
struct sam_ed_s *prev;
|
struct sam_ed_s *prev;
|
||||||
|
uintptr_t physed;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
/* Find the ED in the bulk list. NOTE: We really should never be mucking
|
/* Find the ED in the bulk list. NOTE: We really should never be mucking
|
||||||
* with the bulk list while BLE is set.
|
* with the bulk list while BLE is set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (curr = (struct sam_ed_s *)sam_getreg(SAM_USBHOST_BULKHEADED),
|
physed = sam_getreg(SAM_USBHOST_BULKHEADED);
|
||||||
prev = NULL;
|
for (curr = (struct sam_ed_s *)sam_virtramaddr(physed), prev = NULL;
|
||||||
curr && curr != ed;
|
curr && curr != ed;
|
||||||
prev = curr, curr = (struct sam_ed_s *)curr->hw.nexted);
|
prev = curr, curr = (struct sam_ed_s *)curr->hw.nexted);
|
||||||
|
|
||||||
@@ -897,7 +896,8 @@ static inline int sam_addinted(const FAR struct usbhost_epdesc_s *epdesc,
|
|||||||
#ifndef CONFIG_USBHOST_INT_DISABLE
|
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||||
unsigned int interval;
|
unsigned int interval;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
uint32_t head;
|
uintptr_t physed;
|
||||||
|
uintptr_t physhead;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
/* Disable periodic list processing. Does this take effect immediately? Or
|
/* Disable periodic list processing. Does this take effect immediately? Or
|
||||||
@@ -949,11 +949,12 @@ static inline int sam_addinted(const FAR struct usbhost_epdesc_s *epdesc,
|
|||||||
}
|
}
|
||||||
uvdbg("min interval: %d offset: %d\n", interval, offset);
|
uvdbg("min interval: %d offset: %d\n", interval, offset);
|
||||||
|
|
||||||
/* Get the head of the first of the duplicated entries. The first offset
|
/* Get the (physical) head of the first of the duplicated entries. The
|
||||||
* entry is always guaranteed to contain the common ED list head.
|
* first offset entry is always guaranteed to contain the common ED list
|
||||||
|
* head.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
head = g_hcca.inttbl[offset];
|
physhead = g_hcca.inttbl[offset];
|
||||||
|
|
||||||
/* Clear all current entries in the interrupt table for this direction */
|
/* Clear all current entries in the interrupt table for this direction */
|
||||||
|
|
||||||
@@ -964,9 +965,10 @@ static inline int sam_addinted(const FAR struct usbhost_epdesc_s *epdesc,
|
|||||||
* interrupt table.
|
* interrupt table.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ed->hw.nexted = head;
|
ed->hw.nexted = physhead;
|
||||||
sam_setinttab((uint32_t)ed, interval, offset);
|
physed = sam_virtramaddr((uintptr_t)ed);
|
||||||
uvdbg("head: %08x next: %08x\n", ed, head);
|
sam_setinttab((uint32_t)physed, interval, offset);
|
||||||
|
uvdbg("head: %08x next: %08x\n", physed, physhead);
|
||||||
|
|
||||||
/* Re-enabled periodic list processing */
|
/* Re-enabled periodic list processing */
|
||||||
|
|
||||||
@@ -1005,6 +1007,7 @@ static inline int sam_reminted(struct sam_ed_s *ed)
|
|||||||
struct sam_ed_s *head;
|
struct sam_ed_s *head;
|
||||||
struct sam_ed_s *curr;
|
struct sam_ed_s *curr;
|
||||||
struct sam_ed_s *prev;
|
struct sam_ed_s *prev;
|
||||||
|
uintptr_t physhead;
|
||||||
unsigned int interval;
|
unsigned int interval;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
@@ -1034,9 +1037,11 @@ static inline int sam_reminted(struct sam_ed_s *ed)
|
|||||||
* entry is always guaranteed to contain the common ED list head.
|
* entry is always guaranteed to contain the common ED list head.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
head = (struct sam_ed_s *)g_hcca.inttbl[offset];
|
physhead = g_hcca.inttbl[offset];
|
||||||
|
head = (struct sam_ed_s *)sam_virtramaddr((uintptr_t)physhead);
|
||||||
|
|
||||||
uvdbg("ed: %08x head: %08x next: %08x offset: %d\n",
|
uvdbg("ed: %08x head: %08x next: %08x offset: %d\n",
|
||||||
ed, head, head ? head->hw.nexted : 0, offset);
|
ed, physhead, head ? head->hw.nexted : 0, offset);
|
||||||
|
|
||||||
/* Find the ED to be removed in the ED list */
|
/* Find the ED to be removed in the ED list */
|
||||||
|
|
||||||
@@ -1059,7 +1064,8 @@ static inline int sam_reminted(struct sam_ed_s *ed)
|
|||||||
{
|
{
|
||||||
/* Yes... set the head of the bulk list to skip over this ED */
|
/* Yes... set the head of the bulk list to skip over this ED */
|
||||||
|
|
||||||
head = (struct sam_ed_s *)ed->hw.nexted;
|
physhead = ed->hw.nexted;
|
||||||
|
head = (struct sam_ed_s *)sam_virtramaddr((uintptr_t)physhead);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1069,8 +1075,9 @@ static inline int sam_reminted(struct sam_ed_s *ed)
|
|||||||
|
|
||||||
prev->hw.nexted = ed->hw.nexted;
|
prev->hw.nexted = ed->hw.nexted;
|
||||||
}
|
}
|
||||||
|
|
||||||
uvdbg("ed: %08x head: %08x next: %08x\n",
|
uvdbg("ed: %08x head: %08x next: %08x\n",
|
||||||
ed, head, head ? head->hw.nexted : 0);
|
ed, physhead, head ? head->hw.nexted : 0);
|
||||||
|
|
||||||
/* Calculate the new minimum interval for this list */
|
/* Calculate the new minimum interval for this list */
|
||||||
|
|
||||||
@@ -1082,6 +1089,7 @@ static inline int sam_reminted(struct sam_ed_s *ed)
|
|||||||
interval = curr->interval;
|
interval = curr->interval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uvdbg("min interval: %d offset: %d\n", interval, offset);
|
uvdbg("min interval: %d offset: %d\n", interval, offset);
|
||||||
|
|
||||||
/* Save the new minimum interval */
|
/* Save the new minimum interval */
|
||||||
@@ -1099,7 +1107,7 @@ static inline int sam_reminted(struct sam_ed_s *ed)
|
|||||||
* table (head might be NULL).
|
* table (head might be NULL).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sam_setinttab((uint32_t)head, interval, offset);
|
sam_setinttab((uint32_t)physhead, interval, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-enabled periodic list processing */
|
/* Re-enabled periodic list processing */
|
||||||
@@ -1166,6 +1174,9 @@ static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_ed_s *ed,
|
|||||||
{
|
{
|
||||||
struct sam_gtd_s *td;
|
struct sam_gtd_s *td;
|
||||||
struct sam_gtd_s *tdtail;
|
struct sam_gtd_s *tdtail;
|
||||||
|
uintptr_t phytd;
|
||||||
|
uintptr_t phytail;
|
||||||
|
uintptr_t phybuf;
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
/* Allocate a TD from the free list */
|
/* Allocate a TD from the free list */
|
||||||
@@ -1173,17 +1184,30 @@ static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_ed_s *ed,
|
|||||||
td = sam_tdalloc();
|
td = sam_tdalloc();
|
||||||
if (td != NULL)
|
if (td != NULL)
|
||||||
{
|
{
|
||||||
|
/* Skip processing of this ED */
|
||||||
|
|
||||||
|
ed->hw.ctrl |= ED_CONTROL_K;
|
||||||
|
|
||||||
|
/* Select the common tail ED for this root hub port */
|
||||||
|
|
||||||
tdtail = &g_tdtail[rhport->rhpndx];
|
tdtail = &g_tdtail[rhport->rhpndx];
|
||||||
|
|
||||||
|
/* Get physical addresses to support the DMA */
|
||||||
|
|
||||||
|
phytd = sam_physramaddr((uintptr_t)td);
|
||||||
|
phytail = sam_physramaddr((uintptr_t)tdtail);
|
||||||
|
phybuf = sam_physramaddr((uintptr_t)buffer);
|
||||||
|
|
||||||
/* Initialize the allocated TD and link it before the common tail TD. */
|
/* Initialize the allocated TD and link it before the common tail TD. */
|
||||||
|
|
||||||
td->hw.ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | GTD_STATUS_CC_MASK);
|
td->hw.ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) |
|
||||||
|
toggle | GTD_STATUS_CC_MASK);
|
||||||
tdtail->hw.ctrl = 0;
|
tdtail->hw.ctrl = 0;
|
||||||
td->hw.cbp = (uint32_t)buffer;
|
td->hw.cbp = (uint32_t)phybuf;
|
||||||
tdtail->hw.cbp = 0;
|
tdtail->hw.cbp = 0;
|
||||||
td->hw.nexttd = (uint32_t)tdtail;
|
td->hw.nexttd = (uint32_t)phytail;
|
||||||
tdtail->hw.nexttd = 0;
|
tdtail->hw.nexttd = 0;
|
||||||
td->hw.be = (uint32_t)(buffer + (buflen - 1));
|
td->hw.be = (uint32_t)(phybuf + (buflen - 1));
|
||||||
tdtail->hw.be = 0;
|
tdtail->hw.be = 0;
|
||||||
|
|
||||||
/* Configure driver-only fields in the extended TD structure */
|
/* Configure driver-only fields in the extended TD structure */
|
||||||
@@ -1192,9 +1216,19 @@ static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_ed_s *ed,
|
|||||||
|
|
||||||
/* Link the td to the head of the ED's TD list */
|
/* Link the td to the head of the ED's TD list */
|
||||||
|
|
||||||
ed->hw.headp = (uint32_t)td | ((ed->hw.headp) & ED_HEADP_C);
|
ed->hw.headp = (uint32_t)phytd | ((ed->hw.headp) & ED_HEADP_C);
|
||||||
ed->hw.tailp = (uint32_t)tdtail;
|
ed->hw.tailp = (uint32_t)phytail;
|
||||||
|
|
||||||
|
/* Flush the buffer, the new TD, and the modified ED to RAM */
|
||||||
|
|
||||||
|
cp15_coherent_dcache((uintptr_t)buffer, buflen);
|
||||||
|
cp15_coherent_dcache((uintptr_t)tdtail, sizeof(struct sam_gtd_s));
|
||||||
|
cp15_coherent_dcache((uintptr_t)td, sizeof(struct sam_gtd_s));
|
||||||
|
|
||||||
|
/* Resume processing of this ED */
|
||||||
|
|
||||||
|
ed->hw.ctrl &= ~ED_CONTROL_K;
|
||||||
|
cp15_coherent_dcache((uintptr_t)ed, sizeof(struct sam_ed_s));
|
||||||
ret = OK;
|
ret = OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1296,6 +1330,13 @@ static int sam_ctrltd(struct sam_rhport_s *rhport, uint32_t dirpid,
|
|||||||
|
|
||||||
sam_takesem(&edctrl->wdhsem);
|
sam_takesem(&edctrl->wdhsem);
|
||||||
|
|
||||||
|
/* Invalidate the D cache to force the control ED to be reloaded from
|
||||||
|
* RAM.
|
||||||
|
*/
|
||||||
|
|
||||||
|
cp15_invalidate_dcache((uintptr_t)edctrl,
|
||||||
|
(uintptr_t)edctrl + sizeof(struct sam_ed_s));
|
||||||
|
|
||||||
/* Check the TD completion status bits */
|
/* Check the TD completion status bits */
|
||||||
|
|
||||||
if (edctrl->tdstatus == TD_CC_NOERROR)
|
if (edctrl->tdstatus == TD_CC_NOERROR)
|
||||||
@@ -1470,7 +1511,7 @@ static void sam_wdh_interrupt(void)
|
|||||||
* cleared in the interrupt status register.
|
* cleared in the interrupt status register.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
td = (struct sam_gtd_s *)g_hcca.donehead;
|
td = (struct sam_gtd_s *)sam_virtramaddr(g_hcca.donehead);
|
||||||
g_hcca.donehead = 0;
|
g_hcca.donehead = 0;
|
||||||
|
|
||||||
/* Process each TD in the write done list */
|
/* Process each TD in the write done list */
|
||||||
@@ -1795,6 +1836,10 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
|
|||||||
/* Set the transfer type to control */
|
/* Set the transfer type to control */
|
||||||
|
|
||||||
edctrl->xfrtype = USB_EP_ATTR_XFER_CONTROL;
|
edctrl->xfrtype = USB_EP_ATTR_XFER_CONTROL;
|
||||||
|
|
||||||
|
/* Flush the modified control ED to RAM */
|
||||||
|
|
||||||
|
cp15_coherent_dcache((uintptr_t)edctrl, sizeof(struct sam_ed_s));
|
||||||
sam_givesem(&g_ohci.exclsem);
|
sam_givesem(&g_ohci.exclsem);
|
||||||
|
|
||||||
uvdbg("RHPort%d EP0 CTRL: %08x\n", rhport->rhpndx + 1, edctrl->hw.ctrl);
|
uvdbg("RHPort%d EP0 CTRL: %08x\n", rhport->rhpndx + 1, edctrl->hw.ctrl);
|
||||||
@@ -2195,7 +2240,8 @@ static int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
|
|||||||
* created by DRVR_ALLOC.
|
* created by DRVR_ALLOC.
|
||||||
* buffer - A buffer used for sending the request and for returning any
|
* buffer - A buffer used for sending the request and for returning any
|
||||||
* responses. This buffer must be large enough to hold the length value
|
* responses. This buffer must be large enough to hold the length value
|
||||||
* in the request description. buffer must have been allocated using DRVR_ALLOC
|
* in the request description. buffer must have been allocated using
|
||||||
|
* DRVR_ALLOC
|
||||||
*
|
*
|
||||||
* NOTE: On an IN transaction, req and buffer may refer to the same allocated
|
* NOTE: On an IN transaction, req and buffer may refer to the same allocated
|
||||||
* memory.
|
* memory.
|
||||||
@@ -2243,7 +2289,13 @@ static int sam_ctrlin(FAR struct usbhost_driver_s *drvr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* On an IN transaction, we need to invalidate the buffer contents to force
|
||||||
|
* it to be reloaded from RAM after the DMA.
|
||||||
|
*/
|
||||||
|
|
||||||
sam_givesem(&g_ohci.exclsem);
|
sam_givesem(&g_ohci.exclsem);
|
||||||
|
cp15_invalidate_dcache((uintptr_t)buffer, (uintptr_t)buffer + len);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2337,6 +2389,7 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
|
|||||||
DEBUGASSERT(rhport && ed && buffer && buflen > 0);
|
DEBUGASSERT(rhport && ed && buffer && buflen > 0);
|
||||||
|
|
||||||
in = (ed->hw.ctrl & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN;
|
in = (ed->hw.ctrl & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN;
|
||||||
|
|
||||||
uvdbg("EP%d %s toggle: %d maxpacket: %d buflen: %d\n",
|
uvdbg("EP%d %s toggle: %d maxpacket: %d buflen: %d\n",
|
||||||
(ed->hw.ctrl & ED_CONTROL_EN_MASK) >> ED_CONTROL_EN_SHIFT,
|
(ed->hw.ctrl & ED_CONTROL_EN_MASK) >> ED_CONTROL_EN_SHIFT,
|
||||||
in ? "IN" : "OUT",
|
in ? "IN" : "OUT",
|
||||||
@@ -2391,10 +2444,25 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
|
|||||||
|
|
||||||
sam_takesem(&ed->wdhsem);
|
sam_takesem(&ed->wdhsem);
|
||||||
|
|
||||||
|
/* Invalidate the D cache to force the ED to be reloaded from RAM */
|
||||||
|
|
||||||
|
cp15_invalidate_dcache((uintptr_t)ed,
|
||||||
|
(uintptr_t)ed + sizeof(struct sam_ed_s));
|
||||||
|
|
||||||
/* Check the TD completion status bits */
|
/* Check the TD completion status bits */
|
||||||
|
|
||||||
if (ed->tdstatus == TD_CC_NOERROR)
|
if (ed->tdstatus == TD_CC_NOERROR)
|
||||||
{
|
{
|
||||||
|
/* On an IN transaction, we also need to invalidate the buffer
|
||||||
|
* contents to force it to be reloaded from RAM.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (in)
|
||||||
|
{
|
||||||
|
cp15_invalidate_dcache((uintptr_t)buffer,
|
||||||
|
(uintptr_t)buffer + buflen);
|
||||||
|
}
|
||||||
|
|
||||||
ret = OK;
|
ret = OK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2467,6 +2535,8 @@ static inline void sam_ep0init(void)
|
|||||||
struct sam_ed_s *edctrl;
|
struct sam_ed_s *edctrl;
|
||||||
struct sam_ed_s *preved;
|
struct sam_ed_s *preved;
|
||||||
struct sam_gtd_s *tdtail;
|
struct sam_gtd_s *tdtail;
|
||||||
|
uintptr_t phyctrl;
|
||||||
|
uintptr_t phytail;
|
||||||
int rhpndx;
|
int rhpndx;
|
||||||
|
|
||||||
/* Initialize the EP0 control EDs */
|
/* Initialize the EP0 control EDs */
|
||||||
@@ -2475,15 +2545,17 @@ static inline void sam_ep0init(void)
|
|||||||
rhpndx < SAM_USBHOST_NRHPORT;
|
rhpndx < SAM_USBHOST_NRHPORT;
|
||||||
rhpndx++, preved = edctrl)
|
rhpndx++, preved = edctrl)
|
||||||
{
|
{
|
||||||
/* Set up some default values */
|
/* Get some pointers to the EP0 control ED and to the common tail TD
|
||||||
|
* for this root hub port.
|
||||||
(void)sam_ep0configure(&g_ohci.rhport[rhpndx].drvr, 1, 8);
|
*/
|
||||||
|
|
||||||
/* Get some convenience pointers */
|
|
||||||
|
|
||||||
tdtail = &g_tdtail[rhpndx];
|
tdtail = &g_tdtail[rhpndx];
|
||||||
edctrl = &g_edctrl[rhpndx];
|
edctrl = &g_edctrl[rhpndx];
|
||||||
|
|
||||||
|
/* We will also need the physical addresses for the DMA */
|
||||||
|
|
||||||
|
phytail = sam_physramaddr((uintptr_t)tdtail);
|
||||||
|
|
||||||
/* Initialize the common tail TD for this port */
|
/* Initialize the common tail TD for this port */
|
||||||
|
|
||||||
memset(tdtail, 0, sizeof(struct sam_gtd_s));
|
memset(tdtail, 0, sizeof(struct sam_gtd_s));
|
||||||
@@ -2495,10 +2567,14 @@ static inline void sam_ep0init(void)
|
|||||||
memset(edctrl, 0, sizeof(struct sam_ed_s));
|
memset(edctrl, 0, sizeof(struct sam_ed_s));
|
||||||
sem_init(&edctrl->wdhsem, 0, 0);
|
sem_init(&edctrl->wdhsem, 0, 0);
|
||||||
|
|
||||||
|
/* Set up some default values (like max packetsize = 8). */
|
||||||
|
|
||||||
|
(void)sam_ep0configure(&g_ohci.rhport[rhpndx].drvr, 0, 8);
|
||||||
|
|
||||||
/* Link the common tail TD to the ED's TD list */
|
/* Link the common tail TD to the ED's TD list */
|
||||||
|
|
||||||
edctrl->hw.headp = (uint32_t)tdtail;
|
edctrl->hw.headp = (uint32_t)phytail;
|
||||||
edctrl->hw.tailp = (uint32_t)tdtail;
|
edctrl->hw.tailp = (uint32_t)phytail;
|
||||||
|
|
||||||
/* If this is not the first ED in the list, then link the previous ED
|
/* If this is not the first ED in the list, then link the previous ED
|
||||||
* to this one. Because of the memset, the last ED in the list will
|
* to this one. Because of the memset, the last ED in the list will
|
||||||
@@ -2507,13 +2583,22 @@ static inline void sam_ep0init(void)
|
|||||||
|
|
||||||
if (preved)
|
if (preved)
|
||||||
{
|
{
|
||||||
preved->hw.nexted = (uint32_t)edctrl;
|
phyctrl = sam_physramaddr((uintptr_t)edctrl);
|
||||||
|
preved->hw.nexted = (uint32_t)phyctrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Flush all of the control EDs and tail TDs to RAM */
|
||||||
|
|
||||||
|
cp15_coherent_dcache((uintptr_t)g_edctrl,
|
||||||
|
SAM_USBHOST_NRHPORT * sizeof(struct sam_ed_s));
|
||||||
|
cp15_coherent_dcache((uintptr_t)g_tdtail,
|
||||||
|
SAM_USBHOST_NRHPORT * sizeof(struct sam_gtd_s));
|
||||||
|
|
||||||
/* Set the head of the control list to the EP0 ED for RHport0. */
|
/* Set the head of the control list to the EP0 ED for RHport0. */
|
||||||
|
|
||||||
sam_putreg((uint32_t)&g_edctrl[0], SAM_USBHOST_CTRLHEADED);
|
sam_putreg((uint32_t)sam_physramaddr((uintptr_t)&g_edctrl[0]),
|
||||||
|
SAM_USBHOST_CTRLHEADED);
|
||||||
|
|
||||||
/* ControlListEnable. This bit is set to enable the processing of the
|
/* ControlListEnable. This bit is set to enable the processing of the
|
||||||
* Control list. Note: once enabled, it remains enabled and we may even
|
* Control list. Note: once enabled, it remains enabled and we may even
|
||||||
@@ -2562,13 +2647,11 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
|
|||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Sanity checks. NOTE: If certain OS features are enabled, it may be
|
/* One time sanity checks */
|
||||||
* necessary to increase the size of SAM_ED/TD_SIZE in sam_ohciram.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
DEBUGASSERT(controller == 0);
|
DEBUGASSERT(controller == 0);
|
||||||
DEBUGASSERT(sizeof(struct sam_ed_s) <= SAM_ED_SIZE);
|
DEBUGASSERT(sizeof(struct sam_ed_s) == SIZEOF_SAM_ED_S);
|
||||||
DEBUGASSERT(sizeof(struct sam_gtd_s) <= SAM_TD_SIZE);
|
DEBUGASSERT(sizeof(struct sam_gtd_s) == SIZEOF_SAM_TD_S);
|
||||||
|
|
||||||
/* Initialize the state data structure */
|
/* Initialize the state data structure */
|
||||||
|
|
||||||
@@ -2722,6 +2805,13 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Drive Vbus +5V (the smoke test). Should be done elsewhere in OTG
|
||||||
|
* mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sam_usbhost_vbusdrive(SAM_OHCI_IFACE, true);
|
||||||
|
up_mdelay(50);
|
||||||
|
|
||||||
/* If there is a USB device in the slot at power up, then we will not
|
/* If there is a USB device in the slot at power up, then we will not
|
||||||
* get the status change interrupt to signal us that the device is
|
* get the status change interrupt to signal us that the device is
|
||||||
* connected. We need to set the initial connected state accordingly.
|
* connected. We need to set the initial connected state accordingly.
|
||||||
@@ -2736,12 +2826,6 @@ FAR struct usbhost_connection_s *sam_ohci_initialize(int controller)
|
|||||||
i+1, g_ohci.rhport[i].connected ? "YES" : "NO");
|
i+1, g_ohci.rhport[i].connected ? "YES" : "NO");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drive Vbus +5V (the smoke test). Should be done elsewhere in OTG
|
|
||||||
* mode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sam_usbhost_vbusdrive(SAM_OHCI_IFACE, true);
|
|
||||||
|
|
||||||
/* Enable interrupts at the interrupt controller */
|
/* Enable interrupts at the interrupt controller */
|
||||||
|
|
||||||
up_enable_irq(SAM_IRQ_UHPHS); /* enable USB interrupt */
|
up_enable_irq(SAM_IRQ_UHPHS); /* enable USB interrupt */
|
||||||
|
|||||||
Reference in New Issue
Block a user