diff --git a/ChangeLog b/ChangeLog index 12847c9d79..a825178b45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7027,3 +7027,7 @@ Manuel Stühn (2014-3-24). * net/netdev_ioctl.c and uip/uip_input.c: IGMP-related bug fixes from Manuel Stühn (2014-3-24). + * arch/arm/src/sam34: Add missing HSCMI configuration settings to + Kconfig; update naming to include SAM34_ (2014-3-24). + * configs/sam4e-ek/include/board.h: Update HSMCI timing to use the + CLKODD bit (2014-3-24). diff --git a/arch/arm/src/sam34/Kconfig b/arch/arm/src/sam34/Kconfig index f79b19cba6..1fc386b47f 100644 --- a/arch/arm/src/sam34/Kconfig +++ b/arch/arm/src/sam34/Kconfig @@ -1131,6 +1131,52 @@ config SAM34_EMAC_ISETH0 endmenu # EMAC device driver options endif # SAM34_EMAC +if SAM34_HSMCI +menu "AT91SAM3/4 HSMCI device driver options" + +config SAM34_HSMCI_RDPROOF + bool "Read Proof Enable" + default n + ---help--- + Enabling Read Proof allows to stop the HSMCI Clock during read + access if the internal FIFO is full. This will guarantee data + integrity, not bandwidth. + +config SAM34_HSMCI_WRPROOF + bool "Write Proof Enable" + default n + ---help--- + Enabling Write Proof allows to stop the HSMCI Clock during write + access if the internal FIFO is full. This will guarantee data + integrity, not bandwidth. + +config SAM34_HSMCI_XFRDEBUG + bool "HSMCI transfer debug" + depends on DEBUG_FS && DEBUG_VERBOSE + default n + ---help--- + Enable special debug instrumentation analyze HSMCI data transfers. + This logic is as non-invasive as possible: It samples HSMCI + registers at key points in the data transfer and then dumps all of + the registers at the end of the transfer. If DEBUG_DMA is also + enabled, then DMA register will be collected as well. Requires also + DEBUG_FS and DEBUG_VERBOSE. + +config SAM34_HSMCI_CMDDEBUG + bool "HSMCI command debug" + depends on DEBUG_FS && DEBUG_VERBOSE + default n + ---help--- + Enable special debug instrumentation analyze HSMCI commands. This + logic is as non-invasive as possible: It samples HSMCI registers at + key points in the data transfer and then dumps all of the registers + at the end of the transfer. If DEBUG_DMA is also enabled, then DMA + register will be collected as well. Requires also DEBUG_FS and + DEBUG_VERBOSE. + +endmenu # HSMCI device driver options +endif # SAM34_HSMCI + if SAM34_UDP menu "AT91SAM3/4 USB Full Speed Device Controller driver (DCD) options" diff --git a/arch/arm/src/sama5/sam_udphs.c b/arch/arm/src/sama5/sam_udphs.c index de9768ee02..ca60c6993e 100644 --- a/arch/arm/src/sama5/sam_udphs.c +++ b/arch/arm/src/sama5/sam_udphs.c @@ -1216,52 +1216,46 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, /* Get the number of bytes remaining to be sent. */ + DEBUGASSERT(privreq->req.xfrd < privreq->req.len); nbytes = privreq->req.len - privreq->req.xfrd; - /* If we are not sending a zero length packet, then clip the size to - * maxpacket and check if we need to send a following zero length packet. + /* Either send the maxpacketsize or all of the remaining data in + * the request. */ - if (nbytes > 0) + if (nbytes >= privep->ep.maxpacket) { - /* Either send the maxpacketsize or all of the remaining data in - * the request. - */ - - if (nbytes >= privep->ep.maxpacket) - { - nbytes = privep->ep.maxpacket; - } - - /* This is the new number of bytes "in-flight" */ - - privreq->inflight = nbytes; - usbtrace(TRACE_WRITE(USB_EPNO(privep->ep.eplog)), nbytes); - - /* The new buffer pointer is the started of the buffer plus the number - * of bytes successfully transfered plus the number of bytes previously - * "in-flight". - */ - - buf = privreq->req.buf + privreq->req.xfrd; - - /* Write packet in the FIFO buffer */ - - fifo = (uint8_t *) - ((uint32_t *)SAM_UDPHSRAM_VSECTION + (EPT_VIRTUAL_SIZE * epno)); - - for (; nbytes; nbytes--) - { - *fifo++ = *buf++; - } - - /* Indicate that there is data in the TX packet memory. This will - * be cleared when the next data out interrupt is received. - */ - - privep->epstate = UDPHS_EPSTATE_SENDING; + nbytes = privep->ep.maxpacket; } + /* This is the new number of bytes "in-flight" */ + + privreq->inflight = nbytes; + usbtrace(TRACE_WRITE(USB_EPNO(privep->ep.eplog)), nbytes); + + /* The new buffer pointer is the started of the buffer plus the number + * of bytes successfully transfered plus the number of bytes previously + * "in-flight". + */ + + buf = privreq->req.buf + privreq->req.xfrd; + + /* Write packet in the FIFO buffer */ + + fifo = (uint8_t *) + ((uint32_t *)SAM_UDPHSRAM_VSECTION + (EPT_VIRTUAL_SIZE * epno)); + + for (; nbytes; nbytes--) + { + *fifo++ = *buf++; + } + + /* Indicate that there is data in the TX packet memory. This will + * be cleared when the next data out interrupt is received. + */ + + privep->epstate = UDPHS_EPSTATE_SENDING; + /* Initiate the transfer and configure to receive the transfer complete * interrupt. */ @@ -1379,7 +1373,8 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep) } /* The way that we handle the transfer is going to depend on - * whether or not this endpoint supports DMA. + * whether or not this endpoint supports DMA. In either case + * the endpoint state will transition to SENDING. */ if ((SAM_EPSET_DMA & SAM_EP_BIT(epno)) != 0) @@ -1424,21 +1419,22 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep) } /* If all of the bytes were sent (including any final zero length - * packet) then we are finished with the request buffer), then we can - * return the request buffer to the class driver. The transfer is not - * finished yet, however. There are still bytes in flight. The - * transfer is truly finished when we are called again and the - * request buffer is empty. + * packet) then we are finished with the request buffer and we can + * return the request buffer to the class driver. The state will + * remain IDLE only if nothing else was put in flight. + * + * Note that we will then loop to check to check the next queued + * write request. */ - if (privreq->req.len >= privreq->req.xfrd && - privep->epstate == UDPHS_EPSTATE_IDLE) + if (privep->epstate == UDPHS_EPSTATE_IDLE) { /* Return the write request to the class driver */ usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), privreq->req.xfrd); + DEBUGASSERT(privreq->req.len == privreq->req.xfrd); sam_req_complete(privep, OK); } } @@ -3577,9 +3573,6 @@ static int sam_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) epno = USB_EPNO(ep->eplog); req->result = -EINPROGRESS; req->xfrd = 0; - privreq->inflight = 0; - privep->zlpneeded = false; - privep->zlpsent = false; flags = irqsave(); /* Handle IN (device-to-host) requests. NOTE: If the class device is diff --git a/configs/sam4e-ek/include/board.h b/configs/sam4e-ek/include/board.h index ef981a1d7f..f9f56beb60 100644 --- a/configs/sam4e-ek/include/board.h +++ b/configs/sam4e-ek/include/board.h @@ -146,28 +146,28 @@ */ #ifdef CONFIG_SAM4EEK_120MHZ - /* MCK = 120MHz, CLKDIV = 149, MCI_SPEED = 120MHz / 2 * (149+1) = 400 KHz */ + /* MCK = 120MHz, CLKDIV = 149 w/o CLKODD, MCI_SPEED = 120MHz / (2*149 + 0 + 2) = 400 KHz */ # define HSMCI_INIT_CLKDIV (149 << HSMCI_MR_CLKDIV_SHIFT) - /* MCK = 120MHz, CLKDIV = 2, MCI_SPEED = 120MHz / 2 * (2+1) = 20 MHz */ + /* MCK = 120MHz, CLKDIV = 2 w/o CLKODD, MCI_SPEED = 120MHz / (2*2 + 0 + 2) = 20 MHz */ # define HSMCI_MMCXFR_CLKDIV (3 << HSMCI_MR_CLKDIV_SHIFT) - /* MCK = 120MHz, CLKDIV = 2, MCI_SPEED = 120MHz / 2 * (2+1) = 20 MHz */ + /* MCK = 120MHz, CLKDIV = 1 w/ CLKODD, MCI_SPEED = 120MHz / (2*1 + 1 + 2) = 24 MHz */ -# define HSMCI_SDXFR_CLKDIV (1 << HSMCI_MR_CLKDIV_SHIFT) +# define HSMCI_SDXFR_CLKDIV ((1 << HSMCI_MR_CLKDIV_SHIFT) | HSMCI_MR_CLKODD) #else -/* MCK = 96MHz, CLKDIV = 119, MCI_SPEED = 96MHz / 2 * (119+1) = 400 KHz */ +/* MCK = 96MHz, CLKDIV = 119, w/o CLKODD, MCI_SPEED = 96MHz / (2 * 119 + 0 + 2) = 400 KHz */ # define HSMCI_INIT_CLKDIV (119 << HSMCI_MR_CLKDIV_SHIFT) -/* MCK = 96MHz, CLKDIV = 3, MCI_SPEED = 96MHz / 2 * (3+1) = 12 MHz */ +/* MCK = 96MHz, CLKDIV = 1 w/ CLKODD, MCI_SPEED = 96MHz / (2*1 + 1 + 2) = 19.2 MHz */ -# define HSMCI_MMCXFR_CLKDIV (3 << HSMCI_MR_CLKDIV_SHIFT) +# define HSMCI_MMCXFR_CLKDIV ((3 << HSMCI_MR_CLKDIV_SHIFT) | HSMCI_MR_CLKODD) -/* MCK = 96MHz, CLKDIV = 1, MCI_SPEED = 96MHz / 2 * (1+1) = 24 MHz */ +/* MCK = 96MHz, CLKDIV = 1 w/o CLKODD, MCI_SPEED = 96MHz / (2*1 + 0 + 2) = 24 MHz */ # define HSMCI_SDXFR_CLKDIV (1 << HSMCI_MR_CLKDIV_SHIFT) #endif