diff options
| author | Mengsk <[email protected]> | 2022-11-07 12:47:41 +0100 |
|---|---|---|
| committer | Mengsk <[email protected]> | 2022-11-07 12:47:41 +0100 |
| commit | 9d3d8fd5b0788b811ad283d10d37dfd1b1005224 (patch) | |
| tree | f66b39fe968cc1a6e46e3074bbda9b907064bc15 /src/portable/microchip | |
| parent | 1eae139aa94130a63ecc4725852cb69c02566c82 (diff) | |
| parent | e434a1dc0584e841da1ae4ff525bbe81a0f5514b (diff) | |
Merge branch 'master' of https://github.com/hathach/tinyusb into bsp_412
Diffstat (limited to 'src/portable/microchip')
| -rw-r--r-- | src/portable/microchip/pic/dcd_pic.c | 786 | ||||
| -rw-r--r-- | src/portable/microchip/pic32mz/dcd_pic32mz.c | 753 | ||||
| -rw-r--r-- | src/portable/microchip/pic32mz/usbhs_registers.h | 931 | ||||
| -rw-r--r-- | src/portable/microchip/samd/dcd_samd.c | 29 | ||||
| -rw-r--r-- | src/portable/microchip/samg/dcd_samg.c | 8 | ||||
| -rw-r--r-- | src/portable/microchip/samx7x/dcd_samx7x.c | 10 |
6 files changed, 2509 insertions, 8 deletions
diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c new file mode 100644 index 000000000..6cf0e6285 --- /dev/null +++ b/src/portable/microchip/pic/dcd_pic.c @@ -0,0 +1,786 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Koji Kitayama + * Copyright (c) 2022 Reimu NotMoe <[email protected]> + * + * 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 CFG_TUD_ENABLED && \ + (CFG_TUSB_MCU == OPT_MCU_PIC32MX || CFG_TUSB_MCU == OPT_MCU_PIC32MM || \ + CFG_TUSB_MCU == OPT_MCU_PIC32MK || CFG_TUSB_MCU == OPT_MCU_PIC24 || \ + CFG_TUSB_MCU == OPT_MCU_DSPIC33) + +#include <xc.h> + +#include "device/dcd.h" + + +#if (CFG_TUSB_MCU == OPT_MCU_PIC32MX || CFG_TUSB_MCU == OPT_MCU_PIC32MM || CFG_TUSB_MCU == OPT_MCU_PIC32MK) + +#define TU_PIC_INT_SIZE 4 + +#elif (CFG_TUSB_MCU == OPT_MCU_PIC24 || CFG_TUSB_MCU == OPT_MCU_DSPIC33) + +#define TU_PIC_INT_SIZE 2 + +#else + +#error Unsupportd PIC MCU + +#endif + + +#if TU_PIC_INT_SIZE == 4 + +#ifndef KVA_TO_PA +#define KVA_TO_PA(kva) ((uint32_t)(kva) & 0x1fffffff) +#endif + +#ifndef PA_TO_KVA1 +#define PA_TO_KVA1(pa) ((uint32_t)(pa) | 0xA0000000) +#endif + +#else + +#ifndef KVA_TO_PA +#define KVA_TO_PA(kva) (kva) +#endif + +#ifndef PA_TO_KVA1 +#define PA_TO_KVA1(pa) (pa) +#endif + +#endif + + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + +enum { + TOK_PID_OUT = 0x1u, + TOK_PID_IN = 0x9u, + TOK_PID_SETUP = 0xDu, +}; + +// The BDT is 8 bytes on 32bit PICs and 4 bytes on 8/16bit PICs +#if TU_PIC_INT_SIZE == 4 +typedef struct TU_ATTR_PACKED +{ + union { + uint32_t head; + struct { + union { + struct { + uint16_t : 2; + uint16_t tok_pid : 4; + uint16_t data : 1; + uint16_t own : 1; + uint16_t : 8; + }; + struct { + uint16_t : 2; + uint16_t bdt_stall : 1; + uint16_t dts : 1; + uint16_t ninc : 1; + uint16_t keep : 1; + uint16_t : 10; + }; + }; + uint16_t bc : 10; + uint16_t : 6; + }; + }; + uint8_t *addr; +} buffer_descriptor_t; + +TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" ); +#else +typedef struct TU_ATTR_PACKED +{ + union { + uint16_t head; + + struct { + uint16_t : 10; + uint16_t tok_pid : 4; + uint16_t data : 1; + uint16_t own : 1; + }; + struct { + uint16_t : 10; + uint16_t bdt_stall : 1; + uint16_t dts : 1; + uint16_t ninc : 1; + uint16_t keep : 1; + }; + + struct { + uint16_t bc : 10; + uint16_t : 6; + }; + }; + uint8_t *addr; +} buffer_descriptor_t; + +TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 4, "size is not correct" ); +#endif + + +typedef struct TU_ATTR_PACKED +{ + union { + uint32_t state; + struct { + uint32_t max_packet_size :11; + uint32_t : 5; + uint32_t odd : 1; + uint32_t :15; + }; + }; + uint16_t length; + uint16_t remaining; +} endpoint_state_t; + +TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" ); + +typedef struct +{ + union { + /* [#EP][OUT,IN][EVEN,ODD] */ + buffer_descriptor_t bdt[16][2][2]; +#if TU_PIC_INT_SIZE == 4 + uint16_t bda[256]; +#else + uint8_t bda[256]; +#endif + }; + TU_ATTR_ALIGNED(4) union { + endpoint_state_t endpoint[16][2]; + endpoint_state_t endpoint_unified[16 * 2]; + }; + uint8_t setup_packet[8]; + uint8_t addr; +} dcd_data_t; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +// BDT(Buffer Descriptor Table) must be 256-byte aligned +CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) volatile static dcd_data_t _dcd; + +#if TU_PIC_INT_SIZE == 4 +TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" ); +#else +TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 256, "size is not correct" ); +#endif + +#if TU_PIC_INT_SIZE == 4 +typedef uint32_t ep_reg_t; +#elif TU_PIC_INT_SIZE == 2 +typedef uint16_t ep_reg_t; +#endif + +static inline volatile void *ep_addr(uint8_t rhport, uint8_t ep_num) { +#if CFG_TUSB_MCU == OPT_MCU_PIC32MK + volatile void *ep_reg_base = rhport ? (&U2EP0) : (&U1EP0); +#else + volatile void *ep_reg_base = &U1EP0; +#endif +#if TU_PIC_INT_SIZE == 4 + const size_t offset = 0x10; +#else + const size_t offset = 0x2; +#endif + return ep_reg_base + offset * ep_num; +} + +static inline ep_reg_t ep_read(uint8_t rhport, uint8_t ep_num) { + volatile ep_reg_t *ep = ep_addr(rhport, ep_num); + return *ep; +} + +static inline void ep_write(uint8_t rhport, uint8_t ep_num, ep_reg_t val) { + volatile ep_reg_t *ep = ep_addr(rhport, ep_num); + *ep = val; +} + +static inline void ep_clear(uint8_t rhport, uint8_t ep_num, ep_reg_t val) { +#if TU_PIC_INT_SIZE == 4 + volatile ep_reg_t *ep_clr = (ep_addr(rhport, ep_num) + 0x4); + *ep_clr = val; +#else + ep_reg_t v = ep_read(rhport, ep_num); + v &= ~val; + ep_write(rhport, ep_num, v); +#endif +} + +static inline void ep_set(uint8_t rhport, uint8_t ep_num, ep_reg_t val) { +#if TU_PIC_INT_SIZE == 4 + volatile ep_reg_t *ep_s = (ep_addr(rhport, ep_num) + 0x8); + *ep_s = val; +#else + ep_reg_t v = ep_read(rhport, ep_num); + v |= val; + ep_write(rhport, ep_num, v); +#endif +} + +static inline void intr_enable(uint8_t rhport) { +#if CFG_TUSB_MCU == OPT_MCU_PIC32MM + IEC0SET = _IEC0_USBIE_MASK; +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX + IEC1SET = _IEC1_USBIE_MASK; +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK + if (rhport == 0) + IEC1SET = _IEC1_USB1IE_MASK; + else + IEC7SET = _IEC7_USB2IE_MASK; +#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33) + IEC5bits.USB1IE = 1; +#endif +} + +static inline void intr_disable(uint8_t rhport) { +#if CFG_TUSB_MCU == OPT_MCU_PIC32MM + IEC0CLR = _IEC0_USBIE_MASK; +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX + IEC1CLR = _IEC1_USBIE_MASK; +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK + if (rhport == 0) + IEC1CLR = _IEC1_USB1IE_MASK; + else + IEC7CLR = _IEC7_USB2IE_MASK; +#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33) + IEC5bits.USB1IE = 0; +#endif +} + +static inline int intr_is_enabled(uint8_t rhport) { +#if CFG_TUSB_MCU == OPT_MCU_PIC32MM + return IEC0bits.USBIE; +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX + return IEC1bits.USBIE; +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK + if (rhport == 0) + return IEC1bits.USB1IE; + else + return IEC7bits.USB2IE; +#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33) + return IEC5bits.USB1IE; +#endif +} + +static inline void intr_clear(uint8_t rhport) { +#if CFG_TUSB_MCU == OPT_MCU_PIC32MM + IFS0CLR = _IFS0_USBIF_MASK; +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MX + IFS1CLR = _IFS1_USBIF_MASK; +#elif CFG_TUSB_MCU == OPT_MCU_PIC32MK + if (rhport == 0) + IFS1CLR = _IFS1_USB1IF_MASK; + else + IFS7CLR = _IFS7_USB2IF_MASK; +#elif (CFG_TUSB_MCU == OPT_MCU_PIC24) || (CFG_TUSB_MCU == OPT_MCU_DSPIC33) + IFS5bits.USB1IF = 0; +#endif +} + +static void prepare_next_setup_packet(uint8_t rhport) +{ + const unsigned out_odd = _dcd.endpoint[0][0].odd; + const unsigned in_odd = _dcd.endpoint[0][1].odd; + TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, ); + + _dcd.bdt[0][0][out_odd].data = 0; + _dcd.bdt[0][0][out_odd ^ 1].data = 1; + _dcd.bdt[0][1][in_odd].data = 1; + _dcd.bdt[0][1][in_odd ^ 1].data = 0; + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT), + _dcd.setup_packet, sizeof(_dcd.setup_packet)); +} + +static void process_stall(uint8_t rhport) +{ + for (int i = 0; i < 16; ++i) { + unsigned const endpt = ep_read(rhport, i); + + if (endpt & _U1EP0_EPSTALL_MASK) { + // prepare next setup if endpoint0 + if ( i == 0 ) prepare_next_setup_packet(rhport); + + // clear stall bit + ep_clear(rhport, i, _U1EP0_EPSTALL_MASK); + } + } +} + +static void process_tokdne(uint8_t rhport) +{ + ep_reg_t s = U1STAT; + + U1IR = _U1IR_TRNIF_MASK; + + uint8_t epnum = (s >> _U1STAT_ENDPT0_POSITION); + uint8_t dir = (s & _U1STAT_DIR_MASK) >> _U1STAT_DIR_POSITION; + unsigned odd = (s & _U1STAT_PPBI_MASK) ? 1 : 0; + + buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s]; + endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3]; + + /* fetch pid before discarded by the next steps */ + const unsigned pid = bd->tok_pid; + + /* reset values for a next transfer */ + bd->bdt_stall = 0; + bd->dts = 1; + bd->ninc = 0; + bd->keep = 0; + /* update the odd variable to prepare for the next transfer */ + ep->odd = odd ^ 1; + if (pid == TOK_PID_SETUP) { + dcd_event_setup_received(rhport, (uint8_t *)PA_TO_KVA1(bd->addr), true); +#if TU_PIC_INT_SIZE == 4 + U1CONCLR = _U1CON_PKTDIS_TOKBUSY_MASK; +#else + U1CONbits.PKTDIS = 0; +#endif + return; + } + + const unsigned bc = bd->bc; + const unsigned remaining = ep->remaining - bc; + if (remaining && bc == ep->max_packet_size) { + /* continue the transferring consecutive data */ + ep->remaining = remaining; + const int next_remaining = remaining - ep->max_packet_size; + if (next_remaining > 0) { + /* prepare to the after next transfer */ + bd->addr += ep->max_packet_size * 2; + bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining; + bd->own = 1; /* the own bit must set after addr */ + } + return; + } + const unsigned length = ep->length; + dcd_event_xfer_complete(rhport, + tu_edpt_addr(epnum, dir), + length - remaining, XFER_RESULT_SUCCESS, true); + if (0 == epnum && 0 == length) { + /* After completion a ZLP of control transfer, + * it prepares for the next steup transfer. */ + if (_dcd.addr) { + /* When the transfer was the SetAddress, + * the device address should be updated here. */ + U1ADDR = _dcd.addr; + _dcd.addr = 0; + } + prepare_next_setup_packet(rhport); + } +} + +static void process_bus_reset(uint8_t rhport) +{ +#if TU_PIC_INT_SIZE == 4 + U1PWRCCLR = _U1PWRC_USUSPEND_MASK; + U1CONSET = _U1CON_PPBRST_MASK; +#else + U1PWRCbits.USUSPND = 0; + U1CONbits.PPBRST = 1; +#endif + U1ADDR = 0; + + U1IE = _U1IE_URSTIE_MASK | _U1IE_TRNIE_MASK | _U1IE_IDLEIE_MASK | + _U1IE_UERRIE_MASK | _U1IE_STALLIE_MASK; + + U1EP0 = _U1EP0_EPHSHK_MASK | _U1EP0_EPRXEN_MASK | _U1EP0_EPTXEN_MASK; + + for (unsigned i = 1; i < 16; ++i) { + ep_write(rhport, i, 0); + } + + buffer_descriptor_t *bd = _dcd.bdt[0][0]; + for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) { + bd->head = 0; + } + const endpoint_state_t ep0 = { + .max_packet_size = CFG_TUD_ENDPOINT0_SIZE, + .odd = 0, + .length = 0, + .remaining = 0, + }; + _dcd.endpoint[0][0] = ep0; + _dcd.endpoint[0][1] = ep0; + tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0])); + _dcd.addr = 0; + prepare_next_setup_packet(rhport); +#if TU_PIC_INT_SIZE == 4 + U1CONCLR = _U1CON_PPBRST_MASK; +#else + U1CONbits.PPBRST = 0; +#endif + dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true); +} + +static void process_bus_sleep(uint8_t rhport) +{ + // Enable resume & disable suspend interrupt + dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); +} + +static void process_bus_resume(uint8_t rhport) +{ + // Enable suspend & disable resume interrupt +#if TU_PIC_INT_SIZE == 4 + U1PWRCCLR = _U1PWRC_USUSPEND_MASK; + U1IECLR = _U1IE_RESUMEIE_MASK; + U1IESET = _U1IE_IDLEIE_MASK; +#else + U1PWRCbits.USUSPND = 0; + U1IEbits.RESUMEIE = 0; + U1IEbits.IDLEIE = 1; +#endif + + dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); +} + +/*------------------------------------------------------------------*/ +/* Device API + *------------------------------------------------------------------*/ +void dcd_init(uint8_t rhport) +{ + intr_disable(rhport); + intr_clear(rhport); + +#if CFG_TUSB_MCU == OPT_MCU_PIC32MM + TRISBbits.TRISB6 = 1; +#endif + + tu_memclr(&_dcd, sizeof(_dcd)); + +#if TU_PIC_INT_SIZE == 4 + U1PWRCSET = _U1PWRC_USBPWR_MASK; +#else + U1PWRCbits.USBPWR = 1; +#endif + +#if TU_PIC_INT_SIZE == 4 + uint32_t bdt_phys = KVA_TO_PA((uintptr_t)_dcd.bdt); + + U1BDTP1 = (uint8_t)(bdt_phys >> 8); + U1BDTP2 = (uint8_t)(bdt_phys >> 16); + U1BDTP3 = (uint8_t)(bdt_phys >> 24); +#else + U1BDTP1 = (uint8_t)((uint16_t)(void *)_dcd.bdt >> 8); + + U1CNFG1bits.PPB = 2; +#endif + + U1IE = _U1IE_URSTIE_MASK; + + dcd_connect(rhport); +} + +void dcd_int_enable(uint8_t rhport) +{ + intr_enable(rhport); +} + +void dcd_int_disable(uint8_t rhport) +{ + intr_disable(rhport); +} + +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) +{ + _dcd.addr = dev_addr & 0x7F; + /* Response with status first before changing device address */ + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); +} + +void dcd_remote_wakeup(uint8_t rhport) +{ +#if TU_PIC_INT_SIZE == 4 + U1CONSET = _U1CON_RESUME_MASK; +#else + U1CONbits.RESUME = 1; +#endif + unsigned cnt = 25000000 / 1000; + while (cnt--) asm volatile("nop"); + +#if TU_PIC_INT_SIZE == 4 + U1CONCLR = _U1CON_RESUME_MASK; +#else + U1CONbits.RESUME = 0; +#endif +} + +void dcd_connect(uint8_t rhport) +{ + while (!U1CONbits.USBEN) { +#if TU_PIC_INT_SIZE == 4 + U1CONSET = _U1CON_USBEN_SOFEN_MASK; +#else + U1CONbits.USBEN = 1; +#endif + } +} + +void dcd_disconnect(uint8_t rhport) +{ + U1CON = 0; +} + +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + (void) en; +} + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) +{ + const unsigned ep_addr = ep_desc->bEndpointAddress; + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir = tu_edpt_dir(ep_addr); + const unsigned xfer = ep_desc->bmAttributes.xfer; + endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; + const unsigned odd = ep->odd; + buffer_descriptor_t *bd = _dcd.bdt[epn][dir]; + + /* No support for control transfer */ + TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL)); + + ep->max_packet_size = tu_edpt_packet_size(ep_desc); + + + unsigned val = _U1EP0_EPCONDIS_MASK; + val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? _U1EP0_EPHSHK_MASK : 0; + val |= dir ? _U1EP0_EPTXEN_MASK : _U1EP0_EPRXEN_MASK; + + ep_reg_t tmp = ep_read(rhport, epn); + tmp |= val; + ep_write(rhport, epn, tmp); + + if (xfer != TUSB_XFER_ISOCHRONOUS) { + bd[odd].dts = 1; + bd[odd].data = 0; + bd[odd ^ 1].dts = 1; + bd[odd ^ 1].data = 1; + } + + return true; +} + +void dcd_edpt_close_all(uint8_t rhport) +{ + const unsigned ie = intr_is_enabled(rhport); + intr_disable(rhport); + + for (unsigned i = 1; i < 16; ++i) { + ep_write(rhport, i, 0); + } + + if (ie) intr_enable(rhport); + + buffer_descriptor_t *bd = _dcd.bdt[1][0]; + for (unsigned i = 2; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) { + bd->head = 0; + } + endpoint_state_t *ep = &_dcd.endpoint[1][0]; + for (unsigned i = 2; i < sizeof(_dcd.endpoint)/sizeof(*ep); ++i, ++ep) { + /* Clear except the odd */ + ep->max_packet_size = 0; + ep->length = 0; + ep->remaining = 0; + } +} + +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) +{ + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir = tu_edpt_dir(ep_addr); + endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; + buffer_descriptor_t *bd = _dcd.bdt[epn][dir]; + const unsigned msk = dir ? _U1EP0_EPTXEN_MASK : _U1EP0_EPRXEN_MASK; + const unsigned ie = intr_is_enabled(rhport); + + intr_disable(rhport); + + ep_clear(rhport, epn, msk); + + ep->max_packet_size = 0; + ep->length = 0; + ep->remaining = 0; + bd[0].head = 0; + bd[1].head = 0; + + if (ie) intr_enable(rhport); +} + +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +{ + + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir = tu_edpt_dir(ep_addr); + endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; + buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd]; + TU_ASSERT(0 == bd->own); + + const unsigned ie = intr_is_enabled(rhport); + + intr_disable(rhport); + + ep->length = total_bytes; + ep->remaining = total_bytes; + + const unsigned mps = ep->max_packet_size; + if (total_bytes > mps) { + buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1; + /* When total_bytes is greater than the max packet size, + * it prepares to the next transfer to avoid NAK in advance. */ + next->bc = total_bytes >= 2 * mps ? mps: total_bytes - mps; + next->addr = (uint8_t *)KVA_TO_PA(buffer + mps); + next->own = 1; + } + bd->bc = total_bytes >= mps ? mps: total_bytes; + bd->addr = (uint8_t *)KVA_TO_PA(buffer); + bd->own = 1; /* This bit must be set last */ + + if (ie) intr_enable(rhport); + + return true; +} + +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + const unsigned epn = tu_edpt_number(ep_addr); + + if (0 == epn) { + ep_set(rhport, epn, _U1EP0_EPSTALL_MASK); + } else { + const unsigned dir = tu_edpt_dir(ep_addr); + const unsigned odd = _dcd.endpoint[epn][dir].odd; + buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][odd]; + TU_ASSERT(0 == bd->own,); + + const unsigned ie = intr_is_enabled(rhport); + + intr_disable(rhport); + + bd->bdt_stall = 1; + bd->own = 1; /* This bit must be set last */ + + if (ie) intr_enable(rhport); + } +} + +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) +{ + const unsigned epn = tu_edpt_number(ep_addr); + TU_VERIFY(epn,); + const unsigned dir = tu_edpt_dir(ep_addr); + const unsigned odd = _dcd.endpoint[epn][dir].odd; + buffer_descriptor_t *bd = _dcd.bdt[epn][dir]; + TU_VERIFY(bd[odd].own,); + + const unsigned ie = intr_is_enabled(rhport); + + intr_disable(rhport); + + bd[odd].own = 0; + + // clear stall + bd[odd].bdt_stall = 0; + + // Reset data toggle + bd[odd ].data = 0; + bd[odd ^ 1].data = 1; + + // We already cleared this in ISR, but just clear it here to be safe + const unsigned endpt = ep_read(rhport, epn); + if (endpt & _U1EP0_EPSTALL_MASK) { + ep_clear(rhport, endpt, _U1EP0_EPSTALL_MASK); + } + + if (ie) intr_enable(rhport); +} + +//--------------------------------------------------------------------+ +// ISR +//--------------------------------------------------------------------+ +void dcd_int_handler(uint8_t rhport) +{ + uint32_t is = U1IR; + uint32_t msk = U1IE; + + U1IR = is & ~msk; + is &= msk; + + if (is & _U1IR_UERRIF_MASK) { + uint32_t es = U1EIR; + U1EIR = es; + U1IR = is; /* discard any pending events */ + } + + if (is & _U1IR_URSTIF_MASK) { + U1IR = is; /* discard any pending events */ + process_bus_reset(rhport); + } + + if (is & _U1IR_IDLEIF_MASK) { + // Note Host usually has extra delay after bus reset (without SOF), which could falsely + // detected as Sleep event. Though usbd has debouncing logic so we are good + U1IR = _U1IR_IDLEIF_MASK; + process_bus_sleep(rhport); + } + + if (is & _U1IR_RESUMEIF_MASK) { + U1IR = _U1IR_RESUMEIF_MASK; + process_bus_resume(rhport); + } + + if (is & _U1IR_SOFIF_MASK) { + U1IR = _U1IR_SOFIF_MASK; + dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); + } + + if (is & _U1IR_STALLIF_MASK) { + U1IR = _U1IR_STALLIF_MASK; + process_stall(rhport); + } + + if (is & _U1IR_TRNIF_MASK) { + process_tokdne(rhport); + } + + intr_clear(rhport); +} + +#endif diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c new file mode 100644 index 000000000..9ad755670 --- /dev/null +++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c @@ -0,0 +1,753 @@ +/* + * 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 CFG_TUD_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; +} + +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + (void) en; + + // TODO implement later +} + +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; + TU_ASSERT(xfer->transferred <= xfer->total_len,); + 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; + TU_ASSERT(xfer->transferred <= xfer->total_len,); + if (transferred < xfer->max_packet_size || xfer->transferred == xfer->total_len) + { + USB_REGS->INTRRXEbits.w &= ~(1u << epnum); + 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; + TU_ASSERT(xfer->transferred <= xfer->total_len,); + 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 & USB_REGS->INTRRXEbits.w; + 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 diff --git a/src/portable/microchip/pic32mz/usbhs_registers.h b/src/portable/microchip/pic32mz/usbhs_registers.h new file mode 100644 index 000000000..757e3f083 --- /dev/null +++ b/src/portable/microchip/pic32mz/usbhs_registers.h @@ -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 diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c index 46aabc5aa..976d3dfd0 100644 --- a/src/portable/microchip/samd/dcd_samd.c +++ b/src/portable/microchip/samd/dcd_samd.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if TUSB_OPT_DEVICE_ENABLED && \ +#if CFG_TUD_ENABLED && \ (CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \ CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X || \ CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21) @@ -180,6 +180,14 @@ void dcd_connect(uint8_t rhport) USB->DEVICE.CTRLB.reg &= ~USB_DEVICE_CTRLB_DETACH; } +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + (void) en; + + // TODO implement later +} + /*------------------------------------------------------------------*/ /* DCD Endpoint port *------------------------------------------------------------------*/ @@ -214,14 +222,14 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) UsbDeviceDescBank* bank = &sram_registers[epnum][dir]; uint32_t size_value = 0; while (size_value < 7) { - if (1 << (size_value + 3) == tu_edpt_packet_size(desc_edpt)) { + if (1 << (size_value + 3) >= tu_edpt_packet_size(desc_edpt)) { break; } size_value++; } // unsupported endpoint size - if ( size_value == 7 && tu_edpt_packet_size(desc_edpt) != 1023 ) return false; + if ( size_value == 7 && tu_edpt_packet_size(desc_edpt) > 1023 ) return false; bank->PCKSIZE.bit.SIZE = size_value; @@ -242,6 +250,13 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) return true; } +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) { + (void) rhport; + (void) ep_addr; + + // TODO: implement if necessary? +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; @@ -271,14 +286,14 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t { bank->PCKSIZE.bit.MULTI_PACKET_SIZE = total_bytes; bank->PCKSIZE.bit.BYTE_COUNT = 0; - ep->EPSTATUSCLR.reg |= USB_DEVICE_EPSTATUSCLR_BK0RDY; - ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL0; + ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY; + ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL0; } else { bank->PCKSIZE.bit.MULTI_PACKET_SIZE = 0; bank->PCKSIZE.bit.BYTE_COUNT = total_bytes; - ep->EPSTATUSSET.reg |= USB_DEVICE_EPSTATUSSET_BK1RDY; - ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL1; + ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK1RDY; + ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRFAIL1; } return true; diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 2e9854153..814e680fb 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -210,6 +210,14 @@ void dcd_disconnect(uint8_t rhport) UDP->UDP_TXVC = UDP_TXVC_TXVDIS_Msk; } +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + (void) en; + + // TODO implement later +} + //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c index 9e3b43840..7507c0f69 100644 --- a/src/portable/microchip/samx7x/dcd_samx7x.c +++ b/src/portable/microchip/samx7x/dcd_samx7x.c @@ -27,7 +27,7 @@ #include "tusb_option.h" -#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMX7X +#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMX7X #include "device/dcd.h" #include "sam.h" @@ -191,6 +191,14 @@ void dcd_disconnect(uint8_t rhport) USB_REG->DEVCTRL &=~(DEVCTRL_ADDEN | DEVCTRL_UADD); } +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + (void) en; + + // TODO implement later +} + static tusb_speed_t get_speed(void) { switch (USB_REG->SR & SR_SPEED) { |
