Merge branch 'master' into master
This commit is contained in:
1110
src/portable/bridgetek/ft9xx/dcd_ft9xx.c
Normal file
1110
src/portable/bridgetek/ft9xx/dcd_ft9xx.c
Normal file
File diff suppressed because it is too large
Load Diff
741
src/portable/microchip/pic32mz/dcd_pic32mz.c
Normal file
741
src/portable/microchip/pic32mz/dcd_pic32mz.c
Normal file
@@ -0,0 +1,741 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Jerzy Kasenberg
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_PIC32MZ
|
||||
|
||||
#include <common/tusb_common.h>
|
||||
#include <device/dcd.h>
|
||||
|
||||
#include <xc.h>
|
||||
#include "usbhs_registers.h"
|
||||
|
||||
#define USB_REGS ((usbhs_registers_t *) (_USB_BASE_ADDRESS))
|
||||
|
||||
// Maximum number of endpoints, could be trimmed down in tusb_config to reduce RAM usage.
|
||||
#ifndef EP_MAX
|
||||
#define EP_MAX 8
|
||||
#endif
|
||||
|
||||
|
||||
typedef enum {
|
||||
EP0_STAGE_NONE,
|
||||
EP0_STAGE_SETUP_IN_DATA,
|
||||
EP0_STAGE_SETUP_OUT_NO_DATA,
|
||||
EP0_STAGE_SETUP_OUT_DATA,
|
||||
EP0_STAGE_DATA_IN,
|
||||
EP0_STAGE_DATA_IN_LAST_PACKET_FILLED,
|
||||
EP0_STAGE_DATA_IN_SENT,
|
||||
EP0_STAGE_DATA_OUT,
|
||||
EP0_STAGE_DATA_OUT_COMPLETE,
|
||||
EP0_STAGE_STATUS_IN,
|
||||
EP0_STAGE_ADDRESS_CHANGE,
|
||||
} ep0_stage_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t * buffer;
|
||||
// Total length of current transfer
|
||||
uint16_t total_len;
|
||||
// Bytes transferred so far
|
||||
uint16_t transferred;
|
||||
uint16_t max_packet_size;
|
||||
uint16_t fifo_size;
|
||||
// Packet size sent or received so far. It is used to modify transferred field
|
||||
// after ACK is received or when filling ISO endpoint with size larger then
|
||||
// FIFO size.
|
||||
uint16_t last_packet_size;
|
||||
uint8_t ep_addr;
|
||||
} xfer_ctl_t;
|
||||
|
||||
static struct
|
||||
{
|
||||
// Current FIFO RAM address used for FIFO allocation
|
||||
uint16_t fifo_addr_top;
|
||||
// EP0 transfer stage
|
||||
ep0_stage_t ep0_stage;
|
||||
// Device address
|
||||
uint8_t dev_addr;
|
||||
xfer_ctl_t xfer_status[EP_MAX][2];
|
||||
} _dcd;
|
||||
|
||||
// Two endpoint 0 descriptor definition for unified dcd_edpt_open()
|
||||
static tusb_desc_endpoint_t const ep0OUT_desc =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_endpoint_t),
|
||||
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = 0x00,
|
||||
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
|
||||
.wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
static tusb_desc_endpoint_t const ep0IN_desc =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_endpoint_t),
|
||||
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = 0x80,
|
||||
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
|
||||
.wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
#define XFER_CTL_BASE(_ep, _dir) &_dcd.xfer_status[_ep][_dir]
|
||||
|
||||
static void ep0_set_stage(ep0_stage_t stage)
|
||||
{
|
||||
_dcd.ep0_stage = stage;
|
||||
}
|
||||
|
||||
static ep0_stage_t ep0_get_stage(void)
|
||||
{
|
||||
return _dcd.ep0_stage;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Controller API
|
||||
*------------------------------------------------------------------*/
|
||||
void dcd_init(uint8_t rhport)
|
||||
{
|
||||
// Disable endpoint interrupts for now
|
||||
USB_REGS->INTRRXEbits.w = 0;
|
||||
USB_REGS->INTRTXEbits.w = 0;
|
||||
// Enable Reset/Suspend/Resume interrupts only
|
||||
USB_REGS->INTRUSBEbits.w = 7;
|
||||
|
||||
dcd_connect(rhport);
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
USBCRCONbits.USBIE = 1;
|
||||
}
|
||||
|
||||
void dcd_int_disable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
USBCRCONbits.USBIE = 0;
|
||||
}
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
ep0_set_stage(EP0_STAGE_ADDRESS_CHANGE);
|
||||
// Store address it will be used later after status stage is done
|
||||
_dcd.dev_addr = dev_addr;
|
||||
// Confirm packet now, address will be set when status stage is detected
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
USB_REGS->POWERbits.RESUME = 1;
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
osal_task_delay(10);
|
||||
#else
|
||||
// TODO: Wait in non blocking mode
|
||||
unsigned cnt = 2000;
|
||||
while (cnt--) __asm__("nop");
|
||||
#endif
|
||||
USB_REGS->POWERbits.RESUME = 0;
|
||||
}
|
||||
|
||||
void dcd_connect(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
USB_REGS->POWERbits.HSEN = TUD_OPT_HIGH_SPEED ? 1 : 0;
|
||||
USB_REGS->POWERbits.SOFTCONN = 1;
|
||||
}
|
||||
|
||||
void dcd_disconnect(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
USB_REGS->POWERbits.SOFTCONN = 1;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
|
||||
{
|
||||
return (_CP0_GET_STATUS() & (_CP0_STATUS_EXL_MASK | _CP0_STATUS_IPL_MASK)) != 0;
|
||||
}
|
||||
|
||||
static void epn_rx_configure(uint8_t endpoint, uint16_t endpointSize,
|
||||
uint16_t fifoAddress, uint8_t fifoSize,
|
||||
uint32_t transferType)
|
||||
{
|
||||
uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
|
||||
|
||||
// Select endpoint register set (same register address is used for all endpoints.
|
||||
USB_REGS->INDEXbits.ENDPOINT = endpoint;
|
||||
|
||||
// Configure the Endpoint size
|
||||
USB_REGS->INDEXED_EPCSR.RXMAXPbits.RXMAXP = endpointSize;
|
||||
|
||||
// Set up the fifo address.
|
||||
USB_REGS->RXFIFOADDbits.RXFIFOAD = fifoAddress;
|
||||
|
||||
// Resets the endpoint data toggle to 0
|
||||
USB_REGS->INDEXED_EPCSR.RXCSRL_DEVICEbits.CLRDT = 1;
|
||||
|
||||
// Set up the FIFO size
|
||||
USB_REGS->RXFIFOSZbits.RXFIFOSZ = fifoSize;
|
||||
|
||||
USB_REGS->INDEXED_EPCSR.RXCSRH_DEVICEbits.ISO = transferType == 1 ? 1 : 0;
|
||||
// Disable NYET Handshakes for interrupt endpoints
|
||||
USB_REGS->INDEXED_EPCSR.RXCSRH_DEVICEbits.DISNYET = transferType == 3 ? 1 : 0;
|
||||
|
||||
// Restore the index register.
|
||||
USB_REGS->INDEXbits.ENDPOINT = old_index;
|
||||
|
||||
// Enable the endpoint interrupt.
|
||||
USB_REGS->INTRRXEbits.w |= (1 << endpoint);
|
||||
}
|
||||
|
||||
static void epn_tx_configure(uint8_t endpoint, uint16_t endpointSize,
|
||||
uint16_t fifoAddress, uint8_t fifoSize,
|
||||
uint32_t transferType)
|
||||
{
|
||||
uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
|
||||
|
||||
// Select endpoint register set (same register address is used for all endpoints.
|
||||
USB_REGS->INDEXbits.ENDPOINT = endpoint;
|
||||
|
||||
// Configure the Endpoint size
|
||||
USB_REGS->INDEXED_EPCSR.TXMAXPbits.TXMAXP = endpointSize;
|
||||
|
||||
// Set up the fifo address
|
||||
USB_REGS->TXFIFOADDbits.TXFIFOAD = fifoAddress;
|
||||
|
||||
// Resets the endpoint data toggle to 0
|
||||
USB_REGS->INDEXED_EPCSR.TXCSRL_DEVICEbits.CLRDT = 1;
|
||||
|
||||
// Set up the FIFO size
|
||||
USB_REGS->TXFIFOSZbits.TXFIFOSZ = fifoSize;
|
||||
|
||||
USB_REGS->INDEXED_EPCSR.TXCSRH_DEVICEbits.ISO = 1 == transferType ? 1 : 0;
|
||||
|
||||
// Restore the index register
|
||||
USB_REGS->INDEXbits.ENDPOINT = old_index;
|
||||
|
||||
// Enable the interrupt
|
||||
USB_REGS->INTRTXEbits.w |= (1 << endpoint);
|
||||
}
|
||||
|
||||
static void tx_fifo_write(uint8_t endpoint, uint8_t const * buffer, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
volatile uint8_t * fifo_reg;
|
||||
|
||||
fifo_reg = (volatile uint8_t *) (&USB_REGS->FIFO[endpoint]);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
*fifo_reg = buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
static int rx_fifo_read(uint8_t epnum, uint8_t * buffer)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t count;
|
||||
volatile uint8_t * fifo_reg;
|
||||
|
||||
fifo_reg = (volatile uint8_t *) (&USB_REGS->FIFO[epnum]);
|
||||
|
||||
count = USB_REGS->EPCSR[epnum].RXCOUNTbits.RXCNT;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
buffer[i] = fifo_reg[i & 3];
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void xfer_complete(xfer_ctl_t * xfer, uint8_t result, bool in_isr)
|
||||
{
|
||||
dcd_event_xfer_complete(0, xfer->ep_addr, xfer->transferred, result, in_isr);
|
||||
}
|
||||
|
||||
static void ep0_fill_tx(xfer_ctl_t * xfer_in)
|
||||
{
|
||||
uint16_t left = xfer_in->total_len - xfer_in->transferred;
|
||||
|
||||
if (left)
|
||||
{
|
||||
xfer_in->last_packet_size = tu_min16(xfer_in->max_packet_size, left);
|
||||
tx_fifo_write(0, xfer_in->buffer + xfer_in->transferred, xfer_in->last_packet_size);
|
||||
xfer_in->transferred += xfer_in->last_packet_size;
|
||||
left = xfer_in->total_len - xfer_in->transferred;
|
||||
}
|
||||
|
||||
if (xfer_in->last_packet_size < xfer_in->max_packet_size || left == 0)
|
||||
{
|
||||
switch (ep0_get_stage())
|
||||
{
|
||||
case EP0_STAGE_SETUP_IN_DATA:
|
||||
case EP0_STAGE_DATA_IN:
|
||||
case EP0_STAGE_DATA_IN_SENT:
|
||||
ep0_set_stage(EP0_STAGE_DATA_IN_LAST_PACKET_FILLED);
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.TXPKTRDY = 1;
|
||||
break;
|
||||
case EP0_STAGE_SETUP_OUT_NO_DATA:
|
||||
ep0_set_stage(EP0_STAGE_STATUS_IN);
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
|
||||
break;
|
||||
case EP0_STAGE_DATA_OUT_COMPLETE:
|
||||
ep0_set_stage(EP0_STAGE_STATUS_IN);
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.w = (USBHS_EP0_DEVICE_SERVICED_RXPKTRDY | USBHS_EP0_DEVICE_DATAEND);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ep0_get_stage())
|
||||
{
|
||||
case EP0_STAGE_SETUP_IN_DATA:
|
||||
ep0_set_stage(EP0_STAGE_DATA_IN);
|
||||
// fall through
|
||||
case EP0_STAGE_DATA_IN:
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.TXPKTRDY = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void epn_fill_tx(xfer_ctl_t * xfer_in, uint8_t epnum)
|
||||
{
|
||||
uint16_t left = xfer_in->total_len - xfer_in->transferred;
|
||||
if (left)
|
||||
{
|
||||
xfer_in->last_packet_size = tu_min16(xfer_in->max_packet_size, left);
|
||||
tx_fifo_write(epnum, xfer_in->buffer + xfer_in->transferred, xfer_in->last_packet_size);
|
||||
}
|
||||
USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.TXPKTRDY = 1;
|
||||
}
|
||||
|
||||
static bool ep0_xfer(xfer_ctl_t * xfer, int dir)
|
||||
{
|
||||
if (dir == TUSB_DIR_OUT)
|
||||
{
|
||||
if (xfer->total_len)
|
||||
{
|
||||
switch (_dcd.ep0_stage)
|
||||
{
|
||||
case EP0_STAGE_DATA_OUT_COMPLETE:
|
||||
case EP0_STAGE_SETUP_OUT_DATA:
|
||||
ep0_set_stage(EP0_STAGE_DATA_OUT);
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
|
||||
break;
|
||||
default:
|
||||
TU_ASSERT(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (_dcd.ep0_stage)
|
||||
{
|
||||
case EP0_STAGE_DATA_IN_SENT:
|
||||
ep0_set_stage(EP0_STAGE_NONE);
|
||||
// fall through
|
||||
case EP0_STAGE_NONE:
|
||||
xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // IN
|
||||
{
|
||||
ep0_fill_tx(xfer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* DCD Endpoint port
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
|
||||
{
|
||||
(void) rhport;
|
||||
uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
|
||||
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
|
||||
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
|
||||
|
||||
TU_ASSERT(epnum < EP_MAX);
|
||||
|
||||
xfer->max_packet_size = tu_edpt_packet_size(desc_edpt);
|
||||
xfer->fifo_size = xfer->max_packet_size;
|
||||
xfer->ep_addr = desc_edpt->bEndpointAddress;
|
||||
|
||||
if (epnum != 0)
|
||||
{
|
||||
if (dir == TUSB_DIR_OUT)
|
||||
{
|
||||
epn_rx_configure(epnum, xfer->max_packet_size, _dcd.fifo_addr_top, __builtin_ctz(xfer->fifo_size) - 3, desc_edpt->bmAttributes.xfer);
|
||||
_dcd.fifo_addr_top += (xfer->fifo_size + 7) >> 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
epn_tx_configure(epnum, xfer->max_packet_size, _dcd.fifo_addr_top, __builtin_ctz(xfer->fifo_size) - 3, desc_edpt->bmAttributes.xfer);
|
||||
_dcd.fifo_addr_top += (xfer->fifo_size + 7) >> 3;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_edpt_close_all (uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
// Reserve EP0 FIFO address
|
||||
_dcd.fifo_addr_top = 64 >> 3;
|
||||
for (int i = 1; i < EP_MAX; ++i)
|
||||
{
|
||||
tu_memclr(&_dcd.xfer_status[i], sizeof(_dcd.xfer_status[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) ep_addr;
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
|
||||
(void) rhport;
|
||||
|
||||
xfer->buffer = buffer;
|
||||
xfer->total_len = total_bytes;
|
||||
xfer->last_packet_size = 0;
|
||||
xfer->transferred = 0;
|
||||
|
||||
if (epnum == 0)
|
||||
{
|
||||
return ep0_xfer(xfer, dir);
|
||||
}
|
||||
if (dir == TUSB_DIR_OUT)
|
||||
{
|
||||
USB_REGS->INTRRXEbits.w |= (1u << epnum);
|
||||
}
|
||||
else // IN
|
||||
{
|
||||
epn_fill_tx(xfer, epnum);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
(void) rhport;
|
||||
|
||||
if (epnum == 0)
|
||||
{
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENDSTALL = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dir == TUSB_DIR_OUT)
|
||||
{
|
||||
USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.SENDSTALL = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.SENDSTALL = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
(void) rhport;
|
||||
|
||||
if (epnum == 0)
|
||||
{
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENDSTALL = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dir == TUSB_DIR_OUT)
|
||||
{
|
||||
USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w &= ~(USBHS_EP_DEVICE_RX_SENT_STALL | USBHS_EP_DEVICE_RX_SEND_STALL);
|
||||
USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.CLRDT = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w &= ~(USBHS_EP_DEVICE_TX_SENT_STALL | USBHS_EP_DEVICE_TX_SEND_STALL);
|
||||
USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.CLRDT = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Interrupt Handler
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
static void ep0_handle_rx(void)
|
||||
{
|
||||
int transferred;
|
||||
xfer_ctl_t * xfer = XFER_CTL_BASE(0, TUSB_DIR_OUT);
|
||||
|
||||
TU_ASSERT(xfer->buffer,);
|
||||
|
||||
transferred = rx_fifo_read(0, xfer->buffer + xfer->transferred);
|
||||
xfer->transferred += transferred;
|
||||
if (transferred < xfer->max_packet_size || xfer->transferred == xfer->total_len)
|
||||
{
|
||||
ep0_set_stage(EP0_STAGE_DATA_OUT_COMPLETE);
|
||||
xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void epn_handle_rx_int(uint8_t epnum)
|
||||
{
|
||||
uint8_t ep_status;
|
||||
int transferred;
|
||||
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
|
||||
|
||||
ep_status = USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w;
|
||||
if (ep_status & USBHS_EP_DEVICE_RX_SENT_STALL)
|
||||
{
|
||||
USB_REGS->EPCSR[epnum].RXCSRL_DEVICEbits.w &= ~USBHS_EP_DEVICE_RX_SENT_STALL;
|
||||
}
|
||||
|
||||
if (ep_status & USBHS_EP0_HOST_RXPKTRDY)
|
||||
{
|
||||
TU_ASSERT(xfer->buffer != NULL,);
|
||||
|
||||
transferred = rx_fifo_read(epnum, xfer->buffer + xfer->transferred);
|
||||
USB_REGS->EPCSR[epnum].RXCSRL_HOSTbits.RXPKTRDY = 0;
|
||||
xfer->transferred += transferred;
|
||||
if (transferred < xfer->max_packet_size || xfer->transferred == xfer->total_len)
|
||||
{
|
||||
xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void epn_handle_tx_int(uint8_t epnum)
|
||||
{
|
||||
uint8_t ep_status = USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w;
|
||||
xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
|
||||
|
||||
if (ep_status & USBHS_EP_DEVICE_TX_SENT_STALL)
|
||||
{
|
||||
USB_REGS->EPCSR[epnum].TXCSRL_DEVICEbits.w &= ~USBHS_EP_DEVICE_TX_SENT_STALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
xfer->transferred += xfer->last_packet_size;
|
||||
if (xfer->last_packet_size < xfer->max_packet_size || xfer->transferred == xfer->total_len)
|
||||
{
|
||||
xfer->last_packet_size = 0;
|
||||
xfer_complete(xfer, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
epn_fill_tx(xfer, epnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ep0_handle_int(void)
|
||||
{
|
||||
__USBHS_CSR0L_DEVICE_t ep0_status;
|
||||
union {
|
||||
tusb_control_request_t request;
|
||||
uint32_t setup_buffer[2];
|
||||
} setup_packet;
|
||||
xfer_ctl_t * xfer_in = XFER_CTL_BASE(0, TUSB_DIR_IN);
|
||||
uint8_t old_index = USB_REGS->INDEXbits.ENDPOINT;
|
||||
|
||||
// Select EP0 registers
|
||||
USB_REGS->INDEXbits.ENDPOINT = 0;
|
||||
|
||||
ep0_status = USB_REGS->EPCSR[0].CSR0L_DEVICEbits;
|
||||
|
||||
if (ep0_status.SENTSTALL)
|
||||
{
|
||||
// Stall was sent. Reset the endpoint 0 state.
|
||||
// Clear the sent stall bit.
|
||||
ep0_set_stage(EP0_STAGE_NONE);
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SENTSTALL = 0;
|
||||
}
|
||||
|
||||
if (ep0_status.SETUPEND)
|
||||
{
|
||||
// This means the current control transfer end prematurely. We don't
|
||||
// need to end any transfers. The device layer will manage the
|
||||
// premature transfer end. We clear the SetupEnd bit and reset the
|
||||
// driver control transfer state machine to waiting for next setup
|
||||
// packet from host.
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVSSETEND = 1;
|
||||
ep0_set_stage(EP0_STAGE_NONE);
|
||||
}
|
||||
|
||||
if (ep0_status.RXPKTRDY)
|
||||
{
|
||||
switch (ep0_get_stage())
|
||||
{
|
||||
default:
|
||||
// Data arrived at unexpected state, this must be setup stage packet after all.
|
||||
// Fall through
|
||||
case EP0_STAGE_NONE:
|
||||
// This means we were expecting a SETUP packet and we got one.
|
||||
setup_packet.setup_buffer[0] = USB_REGS->FIFO[0];
|
||||
setup_packet.setup_buffer[1] = USB_REGS->FIFO[0];
|
||||
if (setup_packet.request.bmRequestType_bit.direction == TUSB_DIR_OUT)
|
||||
{
|
||||
// SVCRPR is not set yet, it will be set later when out xfer is started
|
||||
// Till then NAKs will hold incommint data
|
||||
ep0_set_stage(setup_packet.request.wLength == 0 ? EP0_STAGE_SETUP_OUT_NO_DATA : EP0_STAGE_SETUP_OUT_DATA);
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_REGS->EPCSR[0].CSR0L_DEVICEbits.SVCRPR = 1;
|
||||
ep0_set_stage(EP0_STAGE_SETUP_IN_DATA);
|
||||
}
|
||||
dcd_event_setup_received(0, &setup_packet.request.bmRequestType, true);
|
||||
break;
|
||||
case EP0_STAGE_DATA_OUT:
|
||||
ep0_handle_rx();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ep0_get_stage())
|
||||
{
|
||||
case EP0_STAGE_STATUS_IN:
|
||||
// Status was just sent, this concludes request, notify client
|
||||
ep0_set_stage(EP0_STAGE_NONE);
|
||||
xfer_complete(xfer_in, XFER_RESULT_SUCCESS, true);
|
||||
break;
|
||||
case EP0_STAGE_DATA_IN:
|
||||
// Packet sent, fill more data
|
||||
ep0_fill_tx(xfer_in);
|
||||
break;
|
||||
case EP0_STAGE_DATA_IN_LAST_PACKET_FILLED:
|
||||
ep0_set_stage(EP0_STAGE_DATA_IN_SENT);
|
||||
xfer_complete(xfer_in, XFER_RESULT_SUCCESS, true);
|
||||
break;
|
||||
case EP0_STAGE_ADDRESS_CHANGE:
|
||||
// Status stage after set address request finished, address can be changed
|
||||
USB_REGS->FADDRbits.FUNC = _dcd.dev_addr;
|
||||
ep0_set_stage(EP0_STAGE_NONE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Restore register index
|
||||
USB_REGS->INDEXbits.ENDPOINT = old_index;
|
||||
}
|
||||
|
||||
void dcd_int_handler(uint8_t rhport)
|
||||
{
|
||||
int i;
|
||||
uint8_t mask;
|
||||
__USBCSR2bits_t csr2_bits;
|
||||
uint16_t rxints = USB_REGS->INTRRX;
|
||||
uint16_t txints = USB_REGS->INTRTX;
|
||||
csr2_bits = USBCSR2bits;
|
||||
(void) rhport;
|
||||
|
||||
IFS4CLR = _IFS4_USBIF_MASK;
|
||||
|
||||
if (csr2_bits.SOFIF && csr2_bits.SOFIE)
|
||||
{
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
|
||||
}
|
||||
if (csr2_bits.RESETIF)
|
||||
{
|
||||
dcd_edpt_open(0, &ep0OUT_desc);
|
||||
dcd_edpt_open(0, &ep0IN_desc);
|
||||
dcd_event_bus_reset(0, USB_REGS->POWERbits.HSMODE ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true);
|
||||
}
|
||||
if (csr2_bits.SUSPIF)
|
||||
{
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
|
||||
}
|
||||
if (csr2_bits.RESUMEIF)
|
||||
{
|
||||
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
|
||||
}
|
||||
// INTRTX has bit for EP0
|
||||
if (txints & 1)
|
||||
{
|
||||
txints ^= 1;
|
||||
ep0_handle_int();
|
||||
}
|
||||
for (mask = 0x02, i = 1; rxints != 0 && mask != 0; mask <<= 1, ++i)
|
||||
{
|
||||
if (rxints & mask)
|
||||
{
|
||||
rxints ^= mask;
|
||||
epn_handle_rx_int(i);
|
||||
}
|
||||
}
|
||||
for (mask = 0x02, i = 1; txints != 0 && mask != 0; mask <<= 1, ++i)
|
||||
{
|
||||
if (txints & mask)
|
||||
{
|
||||
txints ^= mask;
|
||||
epn_handle_tx_int(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
931
src/portable/microchip/pic32mz/usbhs_registers.h
Normal file
931
src/portable/microchip/pic32mz/usbhs_registers.h
Normal file
@@ -0,0 +1,931 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries.
|
||||
*
|
||||
* Subject to your compliance with these terms, you may use Microchip software
|
||||
* and any derivatives exclusively with Microchip products. It is your
|
||||
* responsibility to comply with third party license terms applicable to your
|
||||
* use of third party software (including open source software) that may
|
||||
* accompany Microchip software.
|
||||
*
|
||||
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
|
||||
* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
|
||||
* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE.
|
||||
*
|
||||
* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
|
||||
* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
|
||||
* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
|
||||
* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
|
||||
* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
|
||||
* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
||||
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
||||
*******************************************************************************/
|
||||
/*******************************************************************************
|
||||
USBHS Peripheral Library Register Defintions
|
||||
|
||||
File Name:
|
||||
usbhs_registers.h
|
||||
|
||||
Summary:
|
||||
USBHS PLIB Register Defintions
|
||||
|
||||
Description:
|
||||
This file contains the constants and defintions which are required by the
|
||||
the USBHS library.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __USBHS_REGISTERS_H__
|
||||
#define __USBHS_REGISTERS_H__
|
||||
|
||||
#include <p32xxxx.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*****************************************
|
||||
* Module Register Offsets.
|
||||
*****************************************/
|
||||
|
||||
#define USBHS_REG_FADDR 0x000
|
||||
#define USBHS_REG_POWER 0x001
|
||||
#define USBHS_REG_INTRTX 0x002
|
||||
#define USBHS_REG_INTRRX 0x004
|
||||
#define USBHS_REG_INTRTXE 0x006
|
||||
#define USBHS_REG_INTRRXE 0x008
|
||||
#define USBHS_REG_INTRUSB 0x00A
|
||||
#define USBHS_REG_INTRUSBE 0x00B
|
||||
#define USBHS_REG_FRAME 0x00C
|
||||
#define USBHS_REG_INDEX 0x00E
|
||||
#define USBHS_REG_TESTMODE 0x00F
|
||||
|
||||
/*******************************************************
|
||||
* Endpoint Control Status Registers (CSR). These values
|
||||
* should be added to either the 0x10 to access the
|
||||
* register through Indexed CSR. To access the actual
|
||||
* CSR, see ahead in this header file.
|
||||
******************************************************/
|
||||
|
||||
#define USBHS_REG_EP_TXMAXP 0x000
|
||||
#define USBHS_REG_EP_CSR0L 0x002
|
||||
#define USBHS_REG_EP_CSR0H 0x003
|
||||
#define USBHS_REG_EP_TXCSRL 0x002
|
||||
#define USBHS_REG_EP_TXCSRH 0x003
|
||||
#define USBHS_REG_EP_RXMAXP 0x004
|
||||
#define USBHS_REG_EP_RXCSRL 0x006
|
||||
#define USBHS_REG_EP_RXCSRH 0x007
|
||||
#define USBHS_REG_EP_COUNT0 0x008
|
||||
#define USBHS_REG_EP_RXCOUNT 0x008
|
||||
#define USBHS_REG_EP_TYPE0 0x01A
|
||||
#define USBHS_REG_EP_TXTYPE 0x01A
|
||||
#define USBHS_REG_EP_NAKLIMIT0 0x01B
|
||||
#define USBHS_REG_EP_TXINTERVAL 0x01B
|
||||
#define USBHS_REG_EP_RXTYPE 0x01C
|
||||
#define USBHS_REG_EP_RXINTERVAL 0x01D
|
||||
#define USBHS_REG_EP_CONFIGDATA 0x01F
|
||||
#define USBHS_REG_EP_FIFOSIZE 0x01F
|
||||
|
||||
#define USBHS_HOST_EP0_SETUPKT_SET 0x8
|
||||
#define USBHS_HOST_EP0_TXPKTRDY_SET 0x2
|
||||
#define USBHS_SOFT_RST_NRST_SET 0x1
|
||||
#define USBHS_SOFT_RST_NRSTX_SET 0x2
|
||||
#define USBHS_EP0_DEVICE_SERVICED_RXPKTRDY 0x40
|
||||
#define USBHS_EP0_DEVICE_DATAEND 0x08
|
||||
#define USBHS_EP0_DEVICE_TXPKTRDY 0x02
|
||||
#define USBHS_EP0_HOST_STATUS_STAGE_START 0x40
|
||||
#define USBHS_EP0_HOST_REQPKT 0x20
|
||||
#define USBHS_EP0_HOST_TXPKTRDY 0x02
|
||||
#define USBHS_EP0_HOST_RXPKTRDY 0x01
|
||||
#define USBHS_EP_DEVICE_TX_SENT_STALL 0x20
|
||||
#define USBHS_EP_DEVICE_TX_SEND_STALL 0x10
|
||||
#define USBHS_EP_DEVICE_RX_SENT_STALL 0x40
|
||||
#define USBHS_EP_DEVICE_RX_SEND_STALL 0x20
|
||||
|
||||
/* FADDR - Device Function Address */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned FUNC:7;
|
||||
unsigned :1;
|
||||
};
|
||||
|
||||
uint8_t w;
|
||||
|
||||
} __USBHS_FADDR_t;
|
||||
|
||||
/* POWER - Control Resume and Suspend signalling */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned SUSPEN:1;
|
||||
unsigned SUSPMODE:1;
|
||||
unsigned RESUME:1;
|
||||
unsigned RESET:1;
|
||||
unsigned HSMODE:1;
|
||||
unsigned HSEN:1;
|
||||
unsigned SOFTCONN:1;
|
||||
unsigned ISOUPD:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_POWER_t;
|
||||
|
||||
/* INTRTXE - Transmit endpoint interrupt enable */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned EP0IE:1;
|
||||
unsigned EP1TXIE:1;
|
||||
unsigned EP2TXIE:1;
|
||||
unsigned EP3TXIE:1;
|
||||
unsigned EP4TXIE:1;
|
||||
unsigned EP5TXIE:1;
|
||||
unsigned EP6TXIE:1;
|
||||
unsigned EP7TXIE:1;
|
||||
unsigned :8;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint16_t w;
|
||||
};
|
||||
|
||||
} __USBHS_INTRTXE_t;
|
||||
|
||||
/* INTRRXE - Receive endpoint interrupt enable */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned :1;
|
||||
unsigned EP1RXIE:1;
|
||||
unsigned EP2RXIE:1;
|
||||
unsigned EP3RXIE:1;
|
||||
unsigned EP4RXIE:1;
|
||||
unsigned EP5RXIE:1;
|
||||
unsigned EP6RXIE:1;
|
||||
unsigned EP7RXIE:1;
|
||||
unsigned :8;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint16_t w;
|
||||
};
|
||||
|
||||
} __USBHS_INTRRXE_t;
|
||||
|
||||
/* INTRUSBE - General USB Interrupt enable */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned SUSPIE:1;
|
||||
unsigned RESUMEIE:1;
|
||||
unsigned RESETIE:1;
|
||||
unsigned SOFIE:1;
|
||||
unsigned CONNIE:1;
|
||||
unsigned DISCONIE:1;
|
||||
unsigned SESSRQIE:1;
|
||||
unsigned VBUSERRIE:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_INTRUSBE_t;
|
||||
|
||||
/* FRAME - Frame number */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RFRMNUM:11;
|
||||
unsigned :5;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint16_t w;
|
||||
};
|
||||
|
||||
} __USBHS_FRAME_t;
|
||||
|
||||
/* INDEX - Endpoint index */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned ENDPOINT:4;
|
||||
unsigned :4;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_INDEX_t;
|
||||
|
||||
/* TESTMODE - Test mode register */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned NAK:1;
|
||||
unsigned TESTJ:1;
|
||||
unsigned TESTK:1;
|
||||
unsigned PACKET:1;
|
||||
unsigned FORCEHS:1;
|
||||
unsigned FORCEFS:1;
|
||||
unsigned FIFOACC:1;
|
||||
unsigned FORCEHST:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_TESTMODE_t;
|
||||
|
||||
/* COUNT0 - Indicates the amount of data received in endpoint 0 */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXCNT:7;
|
||||
unsigned :1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_COUNT0_t;
|
||||
|
||||
/* TYPE0 - Operating speed of target device */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned :6;
|
||||
unsigned SPEED:2;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_TYPE0_t;
|
||||
|
||||
/* DEVCTL - Module control register */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned SESSION:1;
|
||||
unsigned HOSTREQ:1;
|
||||
unsigned HOSTMODE:1;
|
||||
unsigned VBUS:2;
|
||||
unsigned LSDEV:1;
|
||||
unsigned FSDEV:1;
|
||||
unsigned BDEV:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_DEVCTL_t;
|
||||
|
||||
/* CSR0L Device - Endpoint Device Mode Control Status Register */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXPKTRDY:1;
|
||||
unsigned TXPKTRDY:1;
|
||||
unsigned SENTSTALL:1;
|
||||
unsigned DATAEND:1;
|
||||
unsigned SETUPEND:1;
|
||||
unsigned SENDSTALL:1;
|
||||
unsigned SVCRPR:1;
|
||||
unsigned SVSSETEND:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_CSR0L_DEVICE_t;
|
||||
|
||||
/* CSR0L Host - Endpoint Host Mode Control Status Register */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXPKTRDY:1;
|
||||
unsigned TXPKTRDY:1;
|
||||
unsigned RXSTALL:1;
|
||||
unsigned SETUPPKT:1;
|
||||
unsigned ERROR:1;
|
||||
unsigned REQPKT:1;
|
||||
unsigned STATPKT:1;
|
||||
unsigned NAKTMOUT:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_CSR0L_HOST_t;
|
||||
|
||||
/* TXCSRL Device - Endpoint Transmit Control Status Register Low */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned TXPKTRDY:1;
|
||||
unsigned FIFOONE:1;
|
||||
unsigned UNDERRUN:1;
|
||||
unsigned FLUSH:1;
|
||||
unsigned SENDSTALL:1;
|
||||
unsigned SENTSTALL:1;
|
||||
unsigned CLRDT:1;
|
||||
unsigned INCOMPTX:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_TXCSRL_DEVICE_t;
|
||||
|
||||
/* TXCSRL Host - Endpoint Transmit Control Status Register Low */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned TXPKTRDY:1;
|
||||
unsigned FIFONE:1;
|
||||
unsigned ERROR:1;
|
||||
unsigned FLUSH:1;
|
||||
unsigned SETUPPKT:1;
|
||||
unsigned RXSTALL:1;
|
||||
unsigned CLRDT:1;
|
||||
unsigned INCOMPTX:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_TXCSRL_HOST_t;
|
||||
|
||||
/* TXCSRH Device - Endpoint Transmit Control Status Register High */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned :2;
|
||||
unsigned DMAREQMD:1;
|
||||
unsigned FRCDATTG:1;
|
||||
unsigned DMAREQENL:1;
|
||||
unsigned MODE:1;
|
||||
unsigned ISO:1;
|
||||
unsigned AUTOSET:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_TXCSRH_DEVICE_t;
|
||||
|
||||
/* TXCSRH Host - Endpoint Transmit Control Status Register High */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned DATATGGL:1;
|
||||
unsigned DTWREN:1;
|
||||
unsigned DMAREQMD:1;
|
||||
unsigned FRCDATTG:1;
|
||||
unsigned DMAREQEN:1;
|
||||
unsigned MODE:1;
|
||||
unsigned :1;
|
||||
unsigned AUOTSET:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_TXCSRH_HOST_t;
|
||||
|
||||
/* CSR0H Device - Endpoint 0 Control Status Register High */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned FLSHFIFO:1;
|
||||
unsigned :7;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_CSR0H_DEVICE_t;
|
||||
|
||||
/* CSR0H Host - Endpoint 0 Control Status Register High */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned FLSHFIFO:1;
|
||||
unsigned DATATGGL:1;
|
||||
unsigned DTWREN:1;
|
||||
unsigned DISPING:1;
|
||||
unsigned :4;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_CSR0H_HOST_t;
|
||||
|
||||
/* RXMAXP - Receive Endpoint Max packet size. */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXMAXP:11;
|
||||
unsigned MULT:5;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint16_t w;
|
||||
};
|
||||
|
||||
} __USBHS_RXMAXP_t;
|
||||
|
||||
/* RXCSRL Device - Receive endpoint Control Status Register */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXPKTRDY:1;
|
||||
unsigned FIFOFULL:1;
|
||||
unsigned OVERRUN:1;
|
||||
unsigned DATAERR:1;
|
||||
unsigned FLUSH:1;
|
||||
unsigned SENDSTALL:1;
|
||||
unsigned SENTSTALL:1;
|
||||
unsigned CLRDT:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_RXCSRL_DEVICE_t;
|
||||
|
||||
/* RXCSRL Host - Receive endpoint Control Status Register */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXPKTRDY:1;
|
||||
unsigned FIFOFULL:1;
|
||||
unsigned ERROR:1;
|
||||
unsigned DERRNAKT:1;
|
||||
unsigned FLUSH:1;
|
||||
unsigned REQPKT:1;
|
||||
unsigned RXSTALL:1;
|
||||
unsigned CLRDT:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_RXCSRL_HOST_t;
|
||||
|
||||
/* RXCSRH Device - Receive endpoint Control Status Register */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned INCOMPRX:1;
|
||||
unsigned :2;
|
||||
unsigned DMAREQMODE:1;
|
||||
unsigned DISNYET:1;
|
||||
unsigned DMAREQEN:1;
|
||||
unsigned ISO:1;
|
||||
unsigned AUTOCLR:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_RXCSRH_DEVICE_t;
|
||||
|
||||
/* RXCSRH Host - Receive endpoint Control Status Register */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned INCOMPRX:1;
|
||||
unsigned DATATGGL:1;
|
||||
unsigned DATATWEN:1;
|
||||
unsigned DMAREQMD:1;
|
||||
unsigned PIDERR:1;
|
||||
unsigned DMAREQEN:1;
|
||||
unsigned AUTORQ:1;
|
||||
unsigned AUOTCLR:1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_RXCSRH_HOST_t;
|
||||
|
||||
/* RXCOUNT - Amount of data pending in RX FIFO */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXCNT:14;
|
||||
unsigned :2;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint16_t w;
|
||||
};
|
||||
|
||||
} __USBHS_RXCOUNT_t;
|
||||
|
||||
/* TXTYPE - Specifies the target transmit endpoint */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned TEP:4;
|
||||
unsigned PROTOCOL:2;
|
||||
unsigned SPEED:2;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_TXTYPE_t;
|
||||
|
||||
/* RXTYPE - Specifies the target receive endpoint */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned TEP:4;
|
||||
unsigned PROTOCOL:2;
|
||||
unsigned SPEED:2;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
} __USBHS_RXTYPE_t;
|
||||
|
||||
/* TXINTERVAL - Defines the polling interval */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t TXINTERV;
|
||||
|
||||
} __USBHS_TXINTERVAL_t;
|
||||
|
||||
/* RXINTERVAL - Defines the polling interval */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t RXINTERV;
|
||||
|
||||
} __USBHS_RXINTERVAL_t;
|
||||
|
||||
/* TXMAXP - Maximum amount of data that can be transferred through a TX endpoint
|
||||
* */
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned TXMAXP:11;
|
||||
unsigned MULT:5;
|
||||
};
|
||||
uint16_t w;
|
||||
|
||||
} __USBHS_TXMAXP_t;
|
||||
|
||||
/* TXFIFOSZ - Size of the transmit endpoint FIFO */
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
unsigned TXFIFOSZ:4;
|
||||
unsigned TXDPB:1;
|
||||
unsigned :3;
|
||||
|
||||
} __USBHS_TXFIFOSZ_t;
|
||||
|
||||
/* RXFIFOSZ - Size of the receive endpoint FIFO */
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXFIFOSZ:4;
|
||||
unsigned RXDPB:1;
|
||||
unsigned :3;
|
||||
|
||||
} __USBHS_RXFIFOSZ_t;
|
||||
|
||||
/* TXFIFOADD - Start address of the transmit endpoint FIFO */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned TXFIFOAD:13;
|
||||
unsigned :3;
|
||||
};
|
||||
uint16_t w;
|
||||
|
||||
} __USBHS_TXFIFOADD_t;
|
||||
|
||||
/* RXFIFOADD - Start address of the receive endpoint FIFO */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXFIFOAD:13;
|
||||
unsigned :3;
|
||||
};
|
||||
uint16_t w;
|
||||
|
||||
} __USBHS_RXFIFOADD_t;
|
||||
|
||||
/* SOFTRST - Asserts NRSTO and NRSTOX */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned NRST:1;
|
||||
unsigned NRSTX:1;
|
||||
unsigned :6;
|
||||
};
|
||||
uint8_t w;
|
||||
|
||||
} __USBHS_SOFTRST_t;
|
||||
|
||||
/* TXFUNCADDR - Target address of transmit endpoint */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned TXFADDR:7;
|
||||
unsigned :1;
|
||||
};
|
||||
uint8_t w;
|
||||
|
||||
} __USBHS_TXFUNCADDR_t;
|
||||
|
||||
/* RXFUNCADDR - Target address of receive endpoint */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXFADDR:7;
|
||||
unsigned :1;
|
||||
};
|
||||
uint8_t w;
|
||||
|
||||
} __USBHS_RXFUNCADDR_t;
|
||||
|
||||
/* TXHUBADDR - Address of the hub to which the target transmit device endpoint
|
||||
* is connected */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned TXHUBADDR:7;
|
||||
unsigned MULTTRAN:1;
|
||||
};
|
||||
uint8_t w;
|
||||
|
||||
} __USBHS_TXHUBADDR_t;
|
||||
|
||||
/* RXHUBADDR - Address of the hub to which the target receive device endpoint is
|
||||
* connected */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXHUBADDR:7;
|
||||
unsigned MULTTRAN:1;
|
||||
};
|
||||
uint8_t w;
|
||||
|
||||
} __USBHS_RXHUBADDR_t;
|
||||
|
||||
/* TXHUBPORT - Address of the hub to which the target transmit device endpoint
|
||||
* is connected. */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned TXHUBPRT:7;
|
||||
unsigned :1;
|
||||
};
|
||||
|
||||
uint8_t w;
|
||||
|
||||
} __USBHS_TXHUBPORT_t;
|
||||
|
||||
/* RXHUBPORT - Address of the hub to which the target receive device endpoint
|
||||
* is connected. */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned RXHUBPRT:7;
|
||||
unsigned :1;
|
||||
};
|
||||
|
||||
uint8_t w;
|
||||
|
||||
} __USBHS_RXHUBPORT_t;
|
||||
|
||||
/* DMACONTROL - Configures a DMA channel */
|
||||
typedef union
|
||||
{
|
||||
struct __attribute__((packed))
|
||||
{
|
||||
unsigned DMAEN:1;
|
||||
unsigned DMADIR:1;
|
||||
unsigned DMAMODE:1;
|
||||
unsigned DMAIE:1;
|
||||
unsigned DMAEP:4;
|
||||
unsigned DMAERR:1;
|
||||
unsigned DMABRSTM:2;
|
||||
unsigned:21;
|
||||
};
|
||||
|
||||
uint32_t w;
|
||||
|
||||
} __USBHS_DMACNTL_t;
|
||||
|
||||
/* Endpoint Control and Status Register Set */
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
volatile __USBHS_TXMAXP_t TXMAXPbits;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
volatile __USBHS_CSR0L_DEVICE_t CSR0L_DEVICEbits;
|
||||
volatile __USBHS_CSR0L_HOST_t CSR0L_HOSTbits;
|
||||
};
|
||||
union
|
||||
{
|
||||
volatile __USBHS_CSR0H_DEVICE_t CSR0H_DEVICEbits;
|
||||
volatile __USBHS_CSR0H_HOST_t CSR0H_HOSTbits;
|
||||
};
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
volatile __USBHS_TXCSRL_DEVICE_t TXCSRL_DEVICEbits;
|
||||
volatile __USBHS_TXCSRL_HOST_t TXCSRL_HOSTbits;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
volatile __USBHS_TXCSRH_DEVICE_t TXCSRH_DEVICEbits;
|
||||
volatile __USBHS_TXCSRH_HOST_t TXCSRH_HOSTbits;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
volatile __USBHS_RXMAXP_t RXMAXPbits;
|
||||
|
||||
union
|
||||
{
|
||||
volatile __USBHS_RXCSRL_DEVICE_t RXCSRL_DEVICEbits;
|
||||
volatile __USBHS_RXCSRL_HOST_t RXCSRL_HOSTbits;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
volatile __USBHS_RXCSRH_DEVICE_t RXCSRH_DEVICEbits;
|
||||
volatile __USBHS_RXCSRH_HOST_t RXCSRH_HOSTbits;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
volatile __USBHS_COUNT0_t COUNT0bits;
|
||||
volatile __USBHS_RXCOUNT_t RXCOUNTbits;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
volatile __USBHS_TYPE0_t TYPE0bits;
|
||||
volatile __USBHS_TXTYPE_t TXTYPEbits;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
volatile uint8_t NAKLIMIT0;
|
||||
volatile __USBHS_TXINTERVAL_t TXINTERVALbits;
|
||||
};
|
||||
|
||||
volatile __USBHS_RXTYPE_t RXTYPEbits;
|
||||
volatile __USBHS_RXINTERVAL_t RXINTERVALbits;
|
||||
unsigned :8;
|
||||
union
|
||||
{
|
||||
volatile uint8_t CONFIGDATA;
|
||||
volatile uint8_t FIFOSIZE;
|
||||
};
|
||||
|
||||
} __USBHS_EPCSR_t;
|
||||
|
||||
/* Set of registers that configure the multi-point option */
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
volatile __USBHS_TXFUNCADDR_t TXFUNCADDRbits;
|
||||
unsigned :8;
|
||||
volatile __USBHS_TXHUBADDR_t TXHUBADDRbits;
|
||||
volatile __USBHS_TXHUBPORT_t TXHUBPORTbits;
|
||||
volatile __USBHS_RXFUNCADDR_t RXFUNCADDRbits;
|
||||
unsigned :8;
|
||||
volatile __USBHS_RXHUBADDR_t RXHUBADDRbits;
|
||||
volatile __USBHS_RXHUBPORT_t RXHUBPORTbits;
|
||||
|
||||
} __USBHS_TARGET_ADDR_t;
|
||||
|
||||
/* Set of registers that configure the DMA channel */
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
volatile __USBHS_DMACNTL_t DMACNTLbits;
|
||||
volatile uint32_t DMAADDR;
|
||||
volatile uint32_t DMACOUNT;
|
||||
volatile uint32_t pad;
|
||||
} __USBHS_DMA_CHANNEL_t;
|
||||
|
||||
/* USBHS module register set */
|
||||
typedef struct __attribute__((aligned(4),packed))
|
||||
{
|
||||
volatile __USBHS_FADDR_t FADDRbits;
|
||||
volatile __USBHS_POWER_t POWERbits;
|
||||
volatile uint16_t INTRTX;
|
||||
volatile uint16_t INTRRX;
|
||||
volatile __USBHS_INTRTXE_t INTRTXEbits;
|
||||
volatile __USBHS_INTRRXE_t INTRRXEbits;
|
||||
volatile uint8_t INTRUSB;
|
||||
volatile __USBHS_INTRUSBE_t INTRUSBEbits;
|
||||
volatile __USBHS_FRAME_t FRAMEbits;
|
||||
volatile __USBHS_INDEX_t INDEXbits;
|
||||
volatile __USBHS_TESTMODE_t TESTMODEbits;
|
||||
volatile __USBHS_EPCSR_t INDEXED_EPCSR;
|
||||
volatile uint32_t FIFO[16];
|
||||
volatile __USBHS_DEVCTL_t DEVCTLbits;
|
||||
volatile uint8_t MISC;
|
||||
volatile __USBHS_TXFIFOSZ_t TXFIFOSZbits;
|
||||
volatile __USBHS_RXFIFOSZ_t RXFIFOSZbits;
|
||||
|
||||
volatile __USBHS_TXFIFOADD_t TXFIFOADDbits;
|
||||
volatile __USBHS_RXFIFOADD_t RXFIFOADDbits;
|
||||
|
||||
volatile uint32_t VCONTROL;
|
||||
volatile uint16_t HWVERS;
|
||||
volatile uint8_t padding1[10];
|
||||
volatile uint8_t EPINFO;
|
||||
volatile uint8_t RAMINFO;
|
||||
volatile uint8_t LINKINFO;
|
||||
volatile uint8_t VPLEN;
|
||||
volatile uint8_t HS_EOF1;
|
||||
volatile uint8_t FS_EOF1;
|
||||
volatile uint8_t LS_EOF1;
|
||||
|
||||
volatile __USBHS_SOFTRST_t SOFTRSTbits;
|
||||
|
||||
volatile __USBHS_TARGET_ADDR_t TADDR[16];
|
||||
volatile __USBHS_EPCSR_t EPCSR[16];
|
||||
volatile uint32_t DMA_INTR;
|
||||
volatile __USBHS_DMA_CHANNEL_t DMA_CHANNEL[8];
|
||||
volatile uint32_t RQPKTXOUNT[16];
|
||||
|
||||
} usbhs_registers_t;
|
||||
|
||||
#endif
|
||||
@@ -38,6 +38,10 @@
|
||||
#include "device/usbd.h"
|
||||
#include "device/usbd_pvt.h" // to use defer function helper
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_MYNEWT
|
||||
#include "mcu/mcu.h"
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* MACRO TYPEDEF CONSTANT ENUM
|
||||
*------------------------------------------------------------------*/
|
||||
@@ -453,9 +457,11 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
|
||||
|
||||
xfer_td_t* xfer = get_td(epnum, dir);
|
||||
|
||||
dcd_int_disable(rhport);
|
||||
xfer->buffer = buffer;
|
||||
xfer->total_len = total_bytes;
|
||||
xfer->actual_len = 0;
|
||||
dcd_int_enable(rhport);
|
||||
|
||||
// Control endpoint with zero-length packet and opposite direction to 1st request byte --> status stage
|
||||
bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE));
|
||||
@@ -476,7 +482,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
|
||||
edpt_dma_start(&NRF_USBD->TASKS_EP0RCVOUT);
|
||||
}else
|
||||
{
|
||||
if ( xfer->data_received )
|
||||
if ( xfer->data_received && xfer->total_len > xfer->actual_len)
|
||||
{
|
||||
// Data is already received previously
|
||||
// start DMA to copy to SRAM
|
||||
@@ -891,6 +897,11 @@ static bool hfclk_running(void)
|
||||
|
||||
static void hfclk_enable(void)
|
||||
{
|
||||
#if CFG_TUSB_OS == OPT_OS_MYNEWT
|
||||
usb_clock_request();
|
||||
return;
|
||||
#else
|
||||
|
||||
// already running, nothing to do
|
||||
if ( hfclk_running() ) return;
|
||||
|
||||
@@ -904,10 +915,16 @@ static void hfclk_enable(void)
|
||||
|
||||
nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
|
||||
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void hfclk_disable(void)
|
||||
{
|
||||
#if CFG_TUSB_OS == OPT_OS_MYNEWT
|
||||
usb_clock_release();
|
||||
return;
|
||||
#else
|
||||
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
if ( is_sd_enabled() )
|
||||
{
|
||||
@@ -917,6 +934,7 @@ static void hfclk_disable(void)
|
||||
#endif
|
||||
|
||||
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Power & Clock Peripheral on nRF5x to manage USB
|
||||
|
||||
870
src/portable/renesas/usba/hcd_usba.c
Normal file
870
src/portable/renesas/usba/hcd_usba.c
Normal file
@@ -0,0 +1,870 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Koji Kitayama
|
||||
* Portions copyrighted (c) 2021 Roland Winistoerfer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
|
||||
CFG_TUSB_MCU == OPT_MCU_RX65X || \
|
||||
CFG_TUSB_MCU == OPT_MCU_RX72N )
|
||||
#include "host/hcd.h"
|
||||
#include "iodefine.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
#define SYSTEM_PRCR_PRC1 (1<<1)
|
||||
#define SYSTEM_PRCR_PRKEY (0xA5u<<8)
|
||||
|
||||
#define USB_DVSTCTR0_LOW (1u)
|
||||
#define USB_DVSTCTR0_FULL (2u)
|
||||
|
||||
#define USB_FIFOSEL_TX ((uint16_t)(1u<<5))
|
||||
#define USB_FIFOSEL_BIGEND ((uint16_t)(1u<<8))
|
||||
#define USB_FIFOSEL_MBW_8 ((uint16_t)(0u<<10))
|
||||
#define USB_FIFOSEL_MBW_16 ((uint16_t)(1u<<10))
|
||||
#define USB_IS0_CTSQ ((uint16_t)(7u))
|
||||
#define USB_IS0_DVSQ ((uint16_t)(7u<<4))
|
||||
#define USB_IS0_VALID ((uint16_t)(1u<<3))
|
||||
#define USB_IS0_BRDY ((uint16_t)(1u<<8))
|
||||
#define USB_IS0_NRDY ((uint16_t)(1u<<9))
|
||||
#define USB_IS0_BEMP ((uint16_t)(1u<<10))
|
||||
#define USB_IS0_CTRT ((uint16_t)(1u<<11))
|
||||
#define USB_IS0_DVST ((uint16_t)(1u<<12))
|
||||
#define USB_IS0_SOFR ((uint16_t)(1u<<13))
|
||||
#define USB_IS0_RESM ((uint16_t)(1u<<14))
|
||||
#define USB_IS0_VBINT ((uint16_t)(1u<<15))
|
||||
#define USB_IS1_SACK ((uint16_t)(1u<<4))
|
||||
#define USB_IS1_SIGN ((uint16_t)(1u<<5))
|
||||
#define USB_IS1_EOFERR ((uint16_t)(1u<<6))
|
||||
#define USB_IS1_ATTCH ((uint16_t)(1u<<11))
|
||||
#define USB_IS1_DTCH ((uint16_t)(1u<<12))
|
||||
#define USB_IS1_BCHG ((uint16_t)(1u<<14))
|
||||
#define USB_IS1_OVRCR ((uint16_t)(1u<<15))
|
||||
|
||||
#define USB_IS0_CTSQ_MSK (7u)
|
||||
#define USB_IS0_CTSQ_SETUP (1u)
|
||||
#define USB_IS0_DVSQ_DEF (1u<<4)
|
||||
#define USB_IS0_DVSQ_ADDR (2u<<4)
|
||||
#define USB_IS0_DVSQ_SUSP0 (4u<<4)
|
||||
#define USB_IS0_DVSQ_SUSP1 (5u<<4)
|
||||
#define USB_IS0_DVSQ_SUSP2 (6u<<4)
|
||||
#define USB_IS0_DVSQ_SUSP3 (7u<<4)
|
||||
|
||||
#define USB_PIPECTR_PID_MSK (3u)
|
||||
#define USB_PIPECTR_PID_NAK (0u)
|
||||
#define USB_PIPECTR_PID_BUF (1u)
|
||||
#define USB_PIPECTR_PID_STALL (2u)
|
||||
#define USB_PIPECTR_CCPL (1u<<2)
|
||||
#define USB_PIPECTR_SQMON (1u<<6)
|
||||
#define USB_PIPECTR_SQCLR (1u<<8)
|
||||
#define USB_PIPECTR_ACLRM (1u<<9)
|
||||
#define USB_PIPECTR_INBUFM (1u<<14)
|
||||
#define USB_PIPECTR_BSTS (1u<<15)
|
||||
|
||||
#define USB_FIFOCTR_DTLN (0x1FF)
|
||||
#define USB_FIFOCTR_FRDY (1u<<13)
|
||||
#define USB_FIFOCTR_BCLR (1u<<14)
|
||||
#define USB_FIFOCTR_BVAL (1u<<15)
|
||||
|
||||
#define USB_PIPECFG_SHTNAK (1u<<7)
|
||||
#define USB_PIPECFG_DBLB (1u<<9)
|
||||
#define USB_PIPECFG_BULK (1u<<14)
|
||||
#define USB_PIPECFG_ISO (3u<<14)
|
||||
#define USB_PIPECFG_INT (2u<<14)
|
||||
|
||||
#define USB_DEVADD_LOW (1u<<6)
|
||||
#define USB_DEVADD_FULL (2u<<6)
|
||||
|
||||
#define FIFO_REQ_CLR (1u)
|
||||
#define FIFO_COMPLETE (1u<<1)
|
||||
|
||||
// Start of definition of packed structs (used by the CCRX toolchain)
|
||||
TU_ATTR_PACKED_BEGIN
|
||||
TU_ATTR_BIT_FIELD_ORDER_BEGIN
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint16_t : 8;
|
||||
uint16_t TRCLR: 1;
|
||||
uint16_t TRENB: 1;
|
||||
uint16_t : 0;
|
||||
};
|
||||
uint16_t TRE;
|
||||
};
|
||||
uint16_t TRN;
|
||||
} reg_pipetre_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
volatile uint16_t u8: 8;
|
||||
volatile uint16_t : 0;
|
||||
};
|
||||
volatile uint16_t u16;
|
||||
} hw_fifo_t;
|
||||
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
void *buf; /* the start address of a transfer data buffer */
|
||||
uint16_t length; /* the number of bytes in the buffer */
|
||||
uint16_t remaining; /* the number of bytes remaining in the buffer */
|
||||
struct {
|
||||
uint32_t ep : 8; /* an assigned endpoint address */
|
||||
uint32_t dev : 8; /* an assigned device address */
|
||||
uint32_t ff : 1; /* `buf` is TU_FUFO or POD */
|
||||
uint32_t : 0;
|
||||
};
|
||||
} pipe_state_t;
|
||||
|
||||
TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain)
|
||||
TU_ATTR_BIT_FIELD_ORDER_END
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool need_reset; /* The device has not been reset after connection. */
|
||||
pipe_state_t pipe[10];
|
||||
uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
|
||||
uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
|
||||
} hcd_data_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
static hcd_data_t _hcd;
|
||||
|
||||
static uint32_t disable_interrupt(void)
|
||||
{
|
||||
uint32_t pswi;
|
||||
#if defined(__CCRX__)
|
||||
pswi = get_psw() & 0x010000;
|
||||
clrpsw_i();
|
||||
#else
|
||||
pswi = __builtin_rx_mvfc(0) & 0x010000;
|
||||
__builtin_rx_clrpsw('I');
|
||||
#endif
|
||||
return pswi;
|
||||
}
|
||||
|
||||
static void enable_interrupt(uint32_t pswi)
|
||||
{
|
||||
#if defined(__CCRX__)
|
||||
set_psw(get_psw() | pswi);
|
||||
#else
|
||||
__builtin_rx_mvtc(0, __builtin_rx_mvfc(0) | pswi);
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned find_pipe(unsigned xfer)
|
||||
{
|
||||
switch (xfer) {
|
||||
case TUSB_XFER_ISOCHRONOUS:
|
||||
for (int i = 1; i <= 2; ++i) {
|
||||
if (0 == _hcd.pipe[i].ep) return i;
|
||||
}
|
||||
break;
|
||||
case TUSB_XFER_BULK:
|
||||
for (int i = 3; i <= 5; ++i) {
|
||||
if (0 == _hcd.pipe[i].ep) return i;
|
||||
}
|
||||
for (int i = 1; i <= 1; ++i) {
|
||||
if (0 == _hcd.pipe[i].ep) return i;
|
||||
}
|
||||
break;
|
||||
case TUSB_XFER_INTERRUPT:
|
||||
for (int i = 6; i <= 9; ++i) {
|
||||
if (0 == _hcd.pipe[i].ep) return i;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* No support for control transfer */
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static volatile uint16_t* get_pipectr(unsigned num)
|
||||
{
|
||||
volatile uint16_t *ctr = NULL;
|
||||
if (num) {
|
||||
ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD;
|
||||
ctr += num - 1;
|
||||
} else {
|
||||
ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD;
|
||||
}
|
||||
return ctr;
|
||||
}
|
||||
|
||||
static volatile reg_pipetre_t* get_pipetre(unsigned num)
|
||||
{
|
||||
volatile reg_pipetre_t* tre = NULL;
|
||||
if ((1 <= num) && (num <= 5)) {
|
||||
tre = (volatile reg_pipetre_t*)&USB0.PIPE1TRE.WORD;
|
||||
tre += num - 1;
|
||||
}
|
||||
return tre;
|
||||
}
|
||||
|
||||
static volatile uint16_t* addr_to_pipectr(uint8_t dev_addr, unsigned ep_addr)
|
||||
{
|
||||
volatile uint16_t *ctr = NULL;
|
||||
const unsigned epn = tu_edpt_number(ep_addr);
|
||||
if (epn) {
|
||||
const unsigned dir_in = tu_edpt_dir(ep_addr);
|
||||
const unsigned num = _hcd.ep[dev_addr][dir_in][epn - 1];
|
||||
if (num) {
|
||||
ctr = (volatile uint16_t*)&USB0.PIPE1CTR.WORD;
|
||||
ctr += num - 1;
|
||||
}
|
||||
} else {
|
||||
ctr = (volatile uint16_t*)&USB0.DCPCTR.WORD;
|
||||
}
|
||||
return ctr;
|
||||
}
|
||||
|
||||
static unsigned edpt0_max_packet_size(void)
|
||||
{
|
||||
return USB0.DCPMAXP.BIT.MXPS;
|
||||
}
|
||||
|
||||
static unsigned edpt_max_packet_size(unsigned num)
|
||||
{
|
||||
USB0.PIPESEL.WORD = num;
|
||||
return USB0.PIPEMAXP.BIT.MXPS;
|
||||
}
|
||||
|
||||
static inline void pipe_wait_for_ready(unsigned num)
|
||||
{
|
||||
while (USB0.D0FIFOSEL.BIT.CURPIPE != num) ;
|
||||
while (!USB0.D0FIFOCTR.BIT.FRDY) ;
|
||||
}
|
||||
|
||||
static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
|
||||
{
|
||||
volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
|
||||
uintptr_t addr = (uintptr_t)buf;
|
||||
while (len >= 2) {
|
||||
reg->u16 = *(const uint16_t *)addr;
|
||||
addr += 2;
|
||||
len -= 2;
|
||||
}
|
||||
if (len) {
|
||||
reg->u8 = *(const uint8_t *)addr;
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
|
||||
static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
|
||||
{
|
||||
uint8_t *p = (uint8_t*)buf;
|
||||
volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
|
||||
while (len--) *p++ = *reg;
|
||||
}
|
||||
|
||||
static bool pipe0_xfer_in(void)
|
||||
{
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
const unsigned rem = pipe->remaining;
|
||||
|
||||
const unsigned mps = edpt0_max_packet_size();
|
||||
const unsigned vld = USB0.CFIFOCTR.BIT.DTLN;
|
||||
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
|
||||
pipe_read_packet(buf, (volatile void*)&USB0.CFIFO.WORD, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BCLR;
|
||||
pipe->remaining = rem - len;
|
||||
if ((len < mps) || (rem == len)) {
|
||||
pipe->buf = NULL;
|
||||
return true;
|
||||
}
|
||||
USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool pipe0_xfer_out(void)
|
||||
{
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
const unsigned rem = pipe->remaining;
|
||||
if (!rem) {
|
||||
pipe->buf = NULL;
|
||||
return true;
|
||||
}
|
||||
const unsigned mps = edpt0_max_packet_size();
|
||||
const unsigned len = TU_MIN(mps, rem);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
pipe_write_packet(buf, (volatile void*)&USB0.CFIFO.WORD, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL;
|
||||
pipe->remaining = rem - len;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool pipe_xfer_in(unsigned num)
|
||||
{
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
const unsigned rem = pipe->remaining;
|
||||
|
||||
USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_8;
|
||||
const unsigned mps = edpt_max_packet_size(num);
|
||||
pipe_wait_for_ready(num);
|
||||
const unsigned vld = USB0.D0FIFOCTR.BIT.DTLN;
|
||||
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
pipe_read_packet(buf, (volatile void*)&USB0.D0FIFO.WORD, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BCLR;
|
||||
USB0.D0FIFOSEL.WORD = 0;
|
||||
while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
|
||||
pipe->remaining = rem - len;
|
||||
if ((len < mps) || (rem == len)) {
|
||||
pipe->buf = NULL;
|
||||
return NULL != buf;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool pipe_xfer_out(unsigned num)
|
||||
{
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
const unsigned rem = pipe->remaining;
|
||||
|
||||
if (!rem) {
|
||||
pipe->buf = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
USB0.D0FIFOSEL.WORD = num | USB_FIFOSEL_MBW_16 | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? USB_FIFOSEL_BIGEND : 0);
|
||||
const unsigned mps = edpt_max_packet_size(num);
|
||||
pipe_wait_for_ready(num);
|
||||
const unsigned len = TU_MIN(rem, mps);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
pipe_write_packet(buf, (volatile void*)&USB0.D0FIFO.WORD, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL;
|
||||
USB0.D0FIFOSEL.WORD = 0;
|
||||
while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
|
||||
pipe->remaining = rem - len;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool process_pipe0_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
|
||||
{
|
||||
(void)dev_addr;
|
||||
const unsigned dir_in = tu_edpt_dir(ep_addr);
|
||||
|
||||
/* configure fifo direction and access unit settings */
|
||||
if (dir_in) { /* IN, a byte */
|
||||
USB0.CFIFOSEL.WORD = USB_FIFOSEL_MBW_8;
|
||||
while (USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX) ;
|
||||
} else { /* OUT, 2 bytes */
|
||||
USB0.CFIFOSEL.WORD = USB_FIFOSEL_TX | USB_FIFOSEL_MBW_16 | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? USB_FIFOSEL_BIGEND : 0);
|
||||
while (!(USB0.CFIFOSEL.WORD & USB_FIFOSEL_TX)) ;
|
||||
}
|
||||
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
pipe->ep = ep_addr;
|
||||
pipe->length = buflen;
|
||||
pipe->remaining = buflen;
|
||||
if (buflen) {
|
||||
pipe->buf = buffer;
|
||||
if (!dir_in) { /* OUT */
|
||||
TU_ASSERT(USB0.DCPCTR.BIT.BSTS && (USB0.USBREQ.WORD & 0x80));
|
||||
pipe0_xfer_out();
|
||||
}
|
||||
} else { /* ZLP */
|
||||
pipe->buf = NULL;
|
||||
if (!dir_in) { /* OUT */
|
||||
USB0.CFIFOCTR.WORD = USB_FIFOCTR_BVAL;
|
||||
}
|
||||
if (dir_in == USB0.DCPCFG.BIT.DIR) {
|
||||
TU_ASSERT(USB_PIPECTR_PID_NAK == USB0.DCPCTR.BIT.PID);
|
||||
USB0.DCPCTR.BIT.SQSET = 1;
|
||||
USB0.DCPCFG.BIT.DIR = dir_in ^ 1;
|
||||
}
|
||||
}
|
||||
USB0.DCPCTR.WORD = USB_PIPECTR_PID_BUF;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool process_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
|
||||
{
|
||||
const unsigned epn = tu_edpt_number(ep_addr);
|
||||
const unsigned dir_in = tu_edpt_dir(ep_addr);
|
||||
const unsigned num = _hcd.ep[dev_addr - 1][dir_in][epn - 1];
|
||||
|
||||
TU_ASSERT(num);
|
||||
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
pipe->buf = buffer;
|
||||
pipe->length = buflen;
|
||||
pipe->remaining = buflen;
|
||||
if (!dir_in) { /* OUT */
|
||||
if (buflen) {
|
||||
pipe_xfer_out(num);
|
||||
} else { /* ZLP */
|
||||
USB0.D0FIFOSEL.WORD = num;
|
||||
pipe_wait_for_ready(num);
|
||||
USB0.D0FIFOCTR.WORD = USB_FIFOCTR_BVAL;
|
||||
USB0.D0FIFOSEL.WORD = 0;
|
||||
while (USB0.D0FIFOSEL.BIT.CURPIPE) ; /* if CURPIPE bits changes, check written value */
|
||||
}
|
||||
} else {
|
||||
volatile uint16_t *ctr = get_pipectr(num);
|
||||
volatile reg_pipetre_t *pt = get_pipetre(num);
|
||||
if (pt) {
|
||||
const unsigned mps = edpt_max_packet_size(num);
|
||||
if (*ctr & 0x3) *ctr = USB_PIPECTR_PID_NAK;
|
||||
pt->TRE = TU_BIT(8);
|
||||
pt->TRN = (buflen + mps - 1) / mps;
|
||||
pt->TRENB = 1;
|
||||
}
|
||||
*ctr = USB_PIPECTR_PID_BUF;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool process_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
|
||||
{
|
||||
const unsigned epn = tu_edpt_number(ep_addr);
|
||||
if (0 == epn) {
|
||||
return process_pipe0_xfer(dev_addr, ep_addr, buffer, buflen);
|
||||
} else {
|
||||
return process_pipe_xfer(dev_addr, ep_addr, buffer, buflen);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_pipe0_bemp(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
bool completed = pipe0_xfer_out();
|
||||
if (completed) {
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
hcd_event_xfer_complete(pipe->dev,
|
||||
tu_edpt_addr(0, TUSB_DIR_OUT),
|
||||
pipe->length - pipe->remaining,
|
||||
XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_pipe_nrdy(uint8_t rhport, unsigned num)
|
||||
{
|
||||
(void)rhport;
|
||||
unsigned result;
|
||||
uint16_t volatile *ctr = get_pipectr(num);
|
||||
// TU_LOG1("NRDY %d %x\n", num, *ctr);
|
||||
switch (*ctr & USB_PIPECTR_PID_MSK) {
|
||||
default: return;
|
||||
case USB_PIPECTR_PID_STALL: result = XFER_RESULT_STALLED; break;
|
||||
case USB_PIPECTR_PID_NAK: result = XFER_RESULT_FAILED; break;
|
||||
}
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
hcd_event_xfer_complete(pipe->dev, pipe->ep,
|
||||
pipe->length - pipe->remaining,
|
||||
result, true);
|
||||
}
|
||||
|
||||
static void process_pipe_brdy(uint8_t rhport, unsigned num)
|
||||
{
|
||||
(void)rhport;
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
const unsigned dir_in = tu_edpt_dir(pipe->ep);
|
||||
bool completed;
|
||||
|
||||
if (dir_in) { /* IN */
|
||||
if (num) {
|
||||
completed = pipe_xfer_in(num);
|
||||
} else {
|
||||
completed = pipe0_xfer_in();
|
||||
}
|
||||
} else {
|
||||
completed = pipe_xfer_out(num);
|
||||
}
|
||||
if (completed) {
|
||||
hcd_event_xfer_complete(pipe->dev, pipe->ep,
|
||||
pipe->length - pipe->remaining,
|
||||
XFER_RESULT_SUCCESS, true);
|
||||
// TU_LOG1("C %d %d\r\n", num, pipe->length - pipe->remaining);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Host API
|
||||
*------------------------------------------------------------------*/
|
||||
bool hcd_init(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
/* Enable USB0 */
|
||||
uint32_t pswi = disable_interrupt();
|
||||
SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1;
|
||||
MSTP(USB0) = 0;
|
||||
SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY;
|
||||
enable_interrupt(pswi);
|
||||
USB0.SYSCFG.BIT.SCKE = 1;
|
||||
while (!USB0.SYSCFG.BIT.SCKE) ;
|
||||
USB0.SYSCFG.BIT.DPRPU = 0;
|
||||
USB0.SYSCFG.BIT.DRPD = 0;
|
||||
USB0.SYSCFG.BIT.DCFM = 1;
|
||||
|
||||
USB0.DVSTCTR0.BIT.VBUSEN = 1;
|
||||
|
||||
USB0.SYSCFG.BIT.DRPD = 1;
|
||||
for (volatile int i = 0; i < 30000; ++i) ;
|
||||
USB0.SYSCFG.BIT.USBE = 1;
|
||||
|
||||
USB.DPUSR0R.BIT.FIXPHY0 = 0u; /* USB0 Transceiver Output fixed */
|
||||
#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
|
||||
USB0.PHYSLEW.LONG = 0x5;
|
||||
IR(PERIB, INTB185) = 0;
|
||||
#else
|
||||
IR(USB0, USBI0) = 0;
|
||||
#endif
|
||||
|
||||
/* Setup default control pipe */
|
||||
USB0.DCPCFG.WORD = USB_PIPECFG_SHTNAK;
|
||||
USB0.DCPMAXP.WORD = 64;
|
||||
USB0.INTENB0.WORD = USB_IS0_BRDY | USB_IS0_NRDY | USB_IS0_BEMP;
|
||||
USB0.INTENB1.WORD = USB_IS1_SACK | USB_IS1_SIGN |
|
||||
USB_IS1_ATTCH | USB_IS1_DTCH;
|
||||
USB0.BEMPENB.WORD = 1;
|
||||
USB0.NRDYENB.WORD = 1;
|
||||
USB0.BRDYENB.WORD = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
void hcd_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
|
||||
IEN(PERIB, INTB185) = 1;
|
||||
#else
|
||||
IEN(USB0, USBI0) = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void hcd_int_disable(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
#if ( CFG_TUSB_MCU == OPT_MCU_RX72N )
|
||||
IEN(PERIB, INTB185) = 0;
|
||||
#else
|
||||
IEN(USB0, USBI0) = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t hcd_frame_number(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
/* The device must be reset at least once after connection
|
||||
* in order to start the frame counter. */
|
||||
if (_hcd.need_reset) hcd_port_reset(rhport);
|
||||
return USB0.FRMNUM.BIT.FRNM;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------+
|
||||
* Port API
|
||||
*--------------------------------------------------------------------+*/
|
||||
bool hcd_port_connect_status(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
return USB0.INTSTS1.BIT.ATTCH ? true: false;
|
||||
}
|
||||
|
||||
void hcd_port_reset(uint8_t rhport)
|
||||
{
|
||||
USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
|
||||
while (USB0.DCPCTR.BIT.PBUSY) ;
|
||||
hcd_int_disable(rhport);
|
||||
USB0.DVSTCTR0.BIT.UACT = 0;
|
||||
if (USB0.DCPCTR.BIT.SUREQ)
|
||||
USB0.DCPCTR.BIT.SUREQCLR = 1;
|
||||
hcd_int_enable(rhport);
|
||||
/* Reset should be asserted 10-20ms. */
|
||||
USB0.DVSTCTR0.BIT.USBRST = 1;
|
||||
for (volatile int i = 0; i < 2400000; ++i) ;
|
||||
USB0.DVSTCTR0.BIT.USBRST = 0;
|
||||
USB0.DVSTCTR0.BIT.UACT = 1;
|
||||
_hcd.need_reset = false;
|
||||
}
|
||||
|
||||
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
switch (USB0.DVSTCTR0.BIT.RHST) {
|
||||
default: return TUSB_SPEED_INVALID;
|
||||
case USB_DVSTCTR0_FULL: return TUSB_SPEED_FULL;
|
||||
case USB_DVSTCTR0_LOW: return TUSB_SPEED_LOW;
|
||||
}
|
||||
}
|
||||
|
||||
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
(void)rhport;
|
||||
uint16_t volatile *ctr;
|
||||
TU_ASSERT(dev_addr < 6,); /* USBa can only handle addresses from 0 to 5. */
|
||||
if (!dev_addr) return;
|
||||
_hcd.ctl_mps[dev_addr] = 0;
|
||||
uint8_t *ep = &_hcd.ep[dev_addr - 1][0][0];
|
||||
for (int i = 0; i < 2 * 15; ++i, ++ep) {
|
||||
unsigned num = *ep;
|
||||
if (!num || dev_addr != _hcd.pipe[num].dev) continue;
|
||||
|
||||
ctr = (uint16_t volatile*)&USB0.PIPE1CTR.WORD + num - 1;
|
||||
*ctr = 0;
|
||||
USB0.NRDYENB.WORD &= ~TU_BIT(num);
|
||||
USB0.BRDYENB.WORD &= ~TU_BIT(num);
|
||||
USB0.PIPESEL.WORD = num;
|
||||
USB0.PIPECFG.WORD = 0;
|
||||
USB0.PIPEMAXP.WORD = 0;
|
||||
|
||||
_hcd.pipe[num].ep = 0;
|
||||
_hcd.pipe[num].dev = 0;
|
||||
*ep = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------+
|
||||
* Endpoints API
|
||||
*--------------------------------------------------------------------+*/
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
|
||||
{
|
||||
(void)rhport;
|
||||
// TU_LOG1("S %d %x\n", dev_addr, USB0.DCPCTR.WORD);
|
||||
|
||||
TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
|
||||
TU_ASSERT(0 == USB0.DCPCTR.BIT.SUREQ);
|
||||
|
||||
USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
|
||||
|
||||
_hcd.pipe[0].buf = NULL;
|
||||
_hcd.pipe[0].length = 8;
|
||||
_hcd.pipe[0].remaining = 0;
|
||||
_hcd.pipe[0].dev = dev_addr;
|
||||
|
||||
while (USB0.DCPCTR.BIT.PBUSY) ;
|
||||
USB0.DCPMAXP.WORD = (dev_addr << 12) | _hcd.ctl_mps[dev_addr];
|
||||
|
||||
/* Set direction in advance for DATA stage */
|
||||
uint8_t const bmRequesttype = setup_packet[0];
|
||||
USB0.DCPCFG.BIT.DIR = tu_edpt_dir(bmRequesttype) ? 0: 1;
|
||||
|
||||
uint16_t const* p = (uint16_t const*)(uintptr_t)&setup_packet[0];
|
||||
USB0.USBREQ.WORD = tu_htole16(p[0]);
|
||||
USB0.USBVAL = p[1];
|
||||
USB0.USBINDX = p[2];
|
||||
USB0.USBLENG = p[3];
|
||||
|
||||
USB0.DCPCTR.BIT.SUREQ = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
|
||||
{
|
||||
(void)rhport;
|
||||
TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
|
||||
|
||||
const unsigned ep_addr = ep_desc->bEndpointAddress;
|
||||
const unsigned epn = tu_edpt_number(ep_addr);
|
||||
const unsigned mps = tu_edpt_packet_size(ep_desc);
|
||||
if (0 == epn) {
|
||||
USB0.DCPCTR.WORD = USB_PIPECTR_PID_NAK;
|
||||
hcd_devtree_info_t devtree;
|
||||
hcd_devtree_get_info(dev_addr, &devtree);
|
||||
uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t)&USB0.DEVADD0.WORD;
|
||||
devadd += dev_addr;
|
||||
while (USB0.DCPCTR.BIT.PBUSY) ;
|
||||
USB0.DCPMAXP.WORD = (dev_addr << 12) | mps;
|
||||
*devadd = (TUSB_SPEED_FULL == devtree.speed) ? USB_DEVADD_FULL : USB_DEVADD_LOW;
|
||||
_hcd.ctl_mps[dev_addr] = mps;
|
||||
return true;
|
||||
}
|
||||
|
||||
const unsigned dir_in = tu_edpt_dir(ep_addr);
|
||||
const unsigned xfer = ep_desc->bmAttributes.xfer;
|
||||
if (xfer == TUSB_XFER_ISOCHRONOUS && mps > 256) {
|
||||
/* USBa supports up to 256 bytes */
|
||||
return false;
|
||||
}
|
||||
const unsigned num = find_pipe(xfer);
|
||||
if (!num) return false;
|
||||
_hcd.pipe[num].dev = dev_addr;
|
||||
_hcd.pipe[num].ep = ep_addr;
|
||||
_hcd.ep[dev_addr - 1][dir_in][epn - 1] = num;
|
||||
|
||||
/* setup pipe */
|
||||
hcd_int_disable(rhport);
|
||||
USB0.PIPESEL.WORD = num;
|
||||
USB0.PIPEMAXP.WORD = (dev_addr << 12) | mps;
|
||||
volatile uint16_t *ctr = get_pipectr(num);
|
||||
*ctr = USB_PIPECTR_ACLRM | USB_PIPECTR_SQCLR;
|
||||
*ctr = 0;
|
||||
unsigned cfg = ((1 ^ dir_in) << 4) | epn;
|
||||
if (xfer == TUSB_XFER_BULK) {
|
||||
cfg |= USB_PIPECFG_BULK | USB_PIPECFG_SHTNAK | USB_PIPECFG_DBLB;
|
||||
} else if (xfer == TUSB_XFER_INTERRUPT) {
|
||||
cfg |= USB_PIPECFG_INT;
|
||||
} else {
|
||||
cfg |= USB_PIPECFG_ISO | USB_PIPECFG_DBLB;
|
||||
}
|
||||
USB0.PIPECFG.WORD = cfg;
|
||||
USB0.BRDYSTS.WORD = 0x1FFu ^ TU_BIT(num);
|
||||
USB0.NRDYENB.WORD |= TU_BIT(num);
|
||||
USB0.BRDYENB.WORD |= TU_BIT(num);
|
||||
if (!dir_in) {
|
||||
*ctr = USB_PIPECTR_PID_BUF;
|
||||
}
|
||||
hcd_int_enable(rhport);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
|
||||
{
|
||||
bool r;
|
||||
hcd_int_disable(rhport);
|
||||
// TU_LOG1("X %d %x %u\n", dev_addr, ep_addr, buflen);
|
||||
r = process_edpt_xfer(dev_addr, ep_addr, buffer, buflen);
|
||||
hcd_int_enable(rhport);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint16_t volatile *ctr = addr_to_pipectr(dev_addr, ep_addr);
|
||||
TU_ASSERT(ctr);
|
||||
|
||||
const uint32_t pid = *ctr & 0x3;
|
||||
if (pid & 2) {
|
||||
*ctr = pid & 2;
|
||||
*ctr = 0;
|
||||
}
|
||||
*ctr = USB_PIPECTR_SQCLR;
|
||||
unsigned const epn = tu_edpt_number(ep_addr);
|
||||
if (!epn) return true;
|
||||
|
||||
if (!tu_edpt_dir(ep_addr)) { /* OUT */
|
||||
*ctr = USB_PIPECTR_PID_BUF;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// ISR
|
||||
//--------------------------------------------------------------------+
|
||||
void hcd_int_handler(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
#if defined(__CCRX__)
|
||||
static const int Mod37BitPosition[] = {
|
||||
-1, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
|
||||
7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5,
|
||||
20, 8, 19, 18};
|
||||
#endif
|
||||
|
||||
unsigned is1 = USB0.INTSTS1.WORD;
|
||||
unsigned is0 = USB0.INTSTS0.WORD;
|
||||
/* clear active bits except VALID (don't write 0 to already cleared bits according to the HW manual) */
|
||||
USB0.INTSTS1.WORD = ~((USB_IS1_SACK | USB_IS1_SIGN | USB_IS1_ATTCH | USB_IS1_DTCH) & is1);
|
||||
USB0.INTSTS0.WORD = ~((USB_IS0_BRDY | USB_IS0_NRDY | USB_IS0_BEMP) & is0);
|
||||
// TU_LOG1("IS %04x %04x\n", is0, is1);
|
||||
is1 &= USB0.INTENB1.WORD;
|
||||
is0 &= USB0.INTENB0.WORD;
|
||||
|
||||
if (is1 & USB_IS1_SACK) {
|
||||
/* Set DATA1 in advance for the next transfer. */
|
||||
USB0.DCPCTR.BIT.SQSET = 1;
|
||||
hcd_event_xfer_complete(USB0.DCPMAXP.BIT.DEVSEL,
|
||||
tu_edpt_addr(0, TUSB_DIR_OUT),
|
||||
8, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
if (is1 & USB_IS1_SIGN) {
|
||||
hcd_event_xfer_complete(USB0.DCPMAXP.BIT.DEVSEL,
|
||||
tu_edpt_addr(0, TUSB_DIR_OUT),
|
||||
8, XFER_RESULT_FAILED, true);
|
||||
}
|
||||
if (is1 & USB_IS1_ATTCH) {
|
||||
USB0.DVSTCTR0.BIT.UACT = 1;
|
||||
_hcd.need_reset = true;
|
||||
USB0.INTENB1.WORD = (USB0.INTENB1.WORD & ~USB_IS1_ATTCH) | USB_IS1_DTCH;
|
||||
hcd_event_device_attach(rhport, true);
|
||||
}
|
||||
if (is1 & USB_IS1_DTCH) {
|
||||
USB0.DVSTCTR0.BIT.UACT = 0;
|
||||
if (USB0.DCPCTR.BIT.SUREQ)
|
||||
USB0.DCPCTR.BIT.SUREQCLR = 1;
|
||||
USB0.INTENB1.WORD = (USB0.INTENB1.WORD & ~USB_IS1_DTCH) | USB_IS1_ATTCH;
|
||||
hcd_event_device_remove(rhport, true);
|
||||
}
|
||||
|
||||
if (is0 & USB_IS0_BEMP) {
|
||||
const unsigned s = USB0.BEMPSTS.WORD;
|
||||
USB0.BEMPSTS.WORD = 0;
|
||||
if (s & 1) {
|
||||
process_pipe0_bemp(rhport);
|
||||
}
|
||||
}
|
||||
if (is0 & USB_IS0_NRDY) {
|
||||
const unsigned m = USB0.NRDYENB.WORD;
|
||||
unsigned s = USB0.NRDYSTS.WORD & m;
|
||||
USB0.NRDYSTS.WORD = ~s;
|
||||
while (s) {
|
||||
#if defined(__CCRX__)
|
||||
const unsigned num = Mod37BitPosition[(-s & s) % 37];
|
||||
#else
|
||||
const unsigned num = __builtin_ctz(s);
|
||||
#endif
|
||||
process_pipe_nrdy(rhport, num);
|
||||
s &= ~TU_BIT(num);
|
||||
}
|
||||
}
|
||||
if (is0 & USB_IS0_BRDY) {
|
||||
const unsigned m = USB0.BRDYENB.WORD;
|
||||
unsigned s = USB0.BRDYSTS.WORD & m;
|
||||
/* clear active bits (don't write 0 to already cleared bits according to the HW manual) */
|
||||
USB0.BRDYSTS.WORD = ~s;
|
||||
while (s) {
|
||||
#if defined(__CCRX__)
|
||||
const unsigned num = Mod37BitPosition[(-s & s) % 37];
|
||||
#else
|
||||
const unsigned num = __builtin_ctz(s);
|
||||
#endif
|
||||
process_pipe_brdy(rhport, num);
|
||||
s &= ~TU_BIT(num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -33,7 +33,8 @@
|
||||
#if TUSB_OPT_DEVICE_ENABLED && \
|
||||
( defined(DCD_ATTR_DWC2_STM32) || \
|
||||
TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_GD32VF103) || \
|
||||
TU_CHECK_MCU(OPT_MCU_EFM32GG, OPT_MCU_BCM2711, OPT_MCU_XMC4000) )
|
||||
TU_CHECK_MCU(OPT_MCU_EFM32GG, OPT_MCU_BCM2711, OPT_MCU_BCM2835) || \
|
||||
TU_CHECK_MCU(OPT_MCU_BCM2837, OPT_MCU_XMC4000) )
|
||||
|
||||
#include "device/dcd.h"
|
||||
#include "dwc2_type.h"
|
||||
@@ -44,7 +45,7 @@
|
||||
#include "dwc2_esp32.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
|
||||
#include "dwc2_gd32.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_BCM2711)
|
||||
#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
|
||||
#include "dwc2_bcm.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
|
||||
#include "dwc2_efm32.h"
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "broadcom/defines.h"
|
||||
#include "broadcom/interrupts.h"
|
||||
#include "broadcom/caches.h"
|
||||
|
||||
@@ -47,7 +48,6 @@ static inline void dwc2_dcd_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
BP_EnableIRQ(USB_IRQn);
|
||||
__asm__ volatile("isb"); // needed if TIMER1 IRQ is not enabled !?
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE
|
||||
@@ -55,7 +55,6 @@ static inline void dwc2_dcd_int_disable (uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
BP_DisableIRQ(USB_IRQn);
|
||||
__asm__ volatile("isb"); // needed if TIMER1 IRQ is not enabled !?
|
||||
}
|
||||
|
||||
static inline void dwc2_remote_wakeup_delay(void)
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#endif
|
||||
@@ -32,10 +36,6 @@
|
||||
#define LOG_USB 0
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED && (CFG_TUSB_MCU == OPT_MCU_VALENTYUSB_EPTRI)
|
||||
|
||||
#include "device/dcd.h"
|
||||
#include "dcd_eptri.h"
|
||||
#include "csr.h"
|
||||
|
||||
Reference in New Issue
Block a user