diff --git a/arch/arm/src/rp2040/Make.defs b/arch/arm/src/rp2040/Make.defs index a918e10770d..a2d21c75d8b 100644 --- a/arch/arm/src/rp2040/Make.defs +++ b/arch/arm/src/rp2040/Make.defs @@ -86,6 +86,10 @@ CHIP_CSRCS += rp2040_i2s.c CHIP_CSRCS += rp2040_i2s_pio.c endif +ifeq ($(CONFIG_USBDEV),y) +CHIP_CSRCS += rp2040_usbdev.c +endif + ifeq ($(CONFIG_RP2040_FLASH_BOOT),y) ifneq ($(PICO_SDK_PATH),) include chip/boot2/Make.defs diff --git a/arch/arm/src/rp2040/hardware/rp2040_memorymap.h b/arch/arm/src/rp2040/hardware/rp2040_memorymap.h index 6405f6021ee..46019c91d91 100644 --- a/arch/arm/src/rp2040/hardware/rp2040_memorymap.h +++ b/arch/arm/src/rp2040/hardware/rp2040_memorymap.h @@ -88,6 +88,7 @@ #define RP2040_VREG_AND_CHIP_RESET_BASE 0x40064000 /* control and status for on-chip voltage regulator and chip level reset subsystem */ #define RP2040_TBMAN_BASE 0x4006c000 /* Testbench manager. Allows the programmer to know what platform their software is running on. */ #define RP2040_DMA_BASE 0x50000000 /* DMA with separate read and write masters */ +#define RP2040_USBCTRL_DPSRAM_BASE 0x50100000 /* USB Dual Port SRAM */ #define RP2040_USBCTRL_REGS_BASE 0x50110000 /* USB FS/LS controller device registers */ #define RP2040_PIO0_BASE 0x50200000 /* Programmable IO block */ #define RP2040_PIO1_BASE 0x50300000 /* Programmable IO block */ diff --git a/arch/arm/src/rp2040/hardware/rp2040_usbctrl_dpsram.h b/arch/arm/src/rp2040/hardware/rp2040_usbctrl_dpsram.h new file mode 100644 index 00000000000..787267ef78b --- /dev/null +++ b/arch/arm/src/rp2040/hardware/rp2040_usbctrl_dpsram.h @@ -0,0 +1,102 @@ +/**************************************************************************** + * arch/arm/src/rp2040/hardware/rp2040_usbctrl_dpsram.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_USBCTRL_DPSRAM_H +#define __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_USBCTRL_DPSRAM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "hardware/rp2040_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define RP2040_USBCTRL_DPSRAM_SETUP_PACKET_OFFSET 0x000000 +#define RP2040_USBCTRL_DPSRAM_EP_IN_CTRL_OFFSET(n) (0x000008 + ((n) - 1) * 8) +#define RP2040_USBCTRL_DPSRAM_EP_OUT_CTRL_OFFSET(n) (0x00000c + ((n) - 1) * 8) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_OFFSET(n) (0x000008 + ((n) - 2) * 4) +#define RP2040_USBCTRL_DPSRAM_EP_IN_BUF_CTRL_OFFSET(n) (0x000080 + (n) * 8) +#define RP2040_USBCTRL_DPSRAM_EP_OUT_BUF_CTRL_OFFSET(n) (0x000084 + (n) * 8) +#define RP2040_USBCTRL_DPSRAM_EP_BUF_CTRL_OFFSET(n) (0x000080 + (n) * 4) +#define RP2040_USBCTRL_DPSRAM_EP0_BUF_0_OFFSET 0x000100 +#define RP2040_USBCTRL_DPSRAM_EP0_BUF_1_OFFSET 0x000140 +#define RP2040_USBCTRL_DPSRAM_DATA_BUF_OFFSET 0x000180 + +/* Register definitions *****************************************************/ + +#define RP2040_USBCTRL_DPSRAM_SETUP_PACKET (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_SETUP_PACKET_OFFSET) +#define RP2040_USBCTRL_DPSRAM_EP_IN_CTRL(n) (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_EP_IN_CTRL_OFFSET(n)) +#define RP2040_USBCTRL_DPSRAM_EP_OUT_CTRL(n) (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_EP_OUT_CTRL_OFFSET(n)) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL(n) (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_EP_CTRL_OFFSET(n)) +#define RP2040_USBCTRL_DPSRAM_EP_IN_BUF_CTRL(n) (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_EP_IN_BUF_CTRL_OFFSET(n)) +#define RP2040_USBCTRL_DPSRAM_EP_OUT_BUF_CTRL(n) (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_EP_OUT_BUF_CTRL_OFFSET(n)) +#define RP2040_USBCTRL_DPSRAM_EP_BUF_CTRL(n) (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_EP_BUF_CTRL_OFFSET(n)) +#define RP2040_USBCTRL_DPSRAM_EP0_BUF_0 (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_EP0_BUF_0_OFFSET) +#define RP2040_USBCTRL_DPSRAM_EP0_BUF_1 (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_EP0_BUF_1_OFFSET) +#define RP2040_USBCTRL_DPSRAM_DATA_BUF (RP2040_USBCTRL_DPSRAM_BASE + RP2040_USBCTRL_DPSRAM_DATA_BUF_OFFSET) + +/* Register bit definitions *************************************************/ + +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_ENABLE (1 << 31) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_DOUBLE_BUF (1 << 30) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_INT_1BUF (1 << 29) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_INT_2BUF (1 << 28) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_SHIFT (26) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_MASK (0x3 << RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_CTRL (0 << RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_ISO (1 << RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_BULK (2 << RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_INTR (3 << RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_INT_STALL (1 << 17) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_INT_NAK (1 << 16) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_ADDR_SHIFT (6) +#define RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_ADDR_MASK (0xffc0) + +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_FULL1 (1 << 31) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LAST1 (1 << 30) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID1_SHIFT (29) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID1_MASK (1 << RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID1_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA0_PID1 (0 << RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID1_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA1_PID1 (1 << RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID1_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DBUF_OFF_128 (0 << 27) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DBUF_OFF_256 (1 << 27) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DBUF_OFF_512 (2 << 27) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DBUF_OFF_1024 (3 << 27) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_AVAIL1 (1 << 26) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LEN1_SHIFT (16) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LEN1_MASK (0x3ff << RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LEN1_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_FULL (1 << 15) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LAST (1 << 14) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID_SHIFT (13) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID_MASK (1 << RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA0_PID (0 << RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA1_PID (1 << RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA_PID_SHIFT) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_SEL (1 << 12) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_STALL (1 << 11) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_AVAIL (1 << 10) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LEN_SHIFT (0) +#define RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LEN_MASK (0x3ff << RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LEN_SHIFT) + +#endif /* __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_USBCTRL_DPSRAM_H */ diff --git a/arch/arm/src/rp2040/hardware/rp2040_usbctrl_regs.h b/arch/arm/src/rp2040/hardware/rp2040_usbctrl_regs.h new file mode 100644 index 00000000000..d29414280a2 --- /dev/null +++ b/arch/arm/src/rp2040/hardware/rp2040_usbctrl_regs.h @@ -0,0 +1,484 @@ +/**************************************************************************** + * arch/arm/src/rp2040/hardware/rp2040_usbctrl_regs.h + * + * Generated from rp2040.svd originally provided by + * Raspberry Pi (Trading) Ltd. + * + * Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_USBCTRL_REGS_H +#define __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_USBCTRL_REGS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "hardware/rp2040_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define RP2040_USBCTRL_REGS_ADDR_ENDP_OFFSET 0x000000 /* Device address and endpoint control */ +#define RP2040_USBCTRL_REGS_ADDR_ENDPN_OFFSET(n) (0x000004 + ((n) - 1) * 4) + /* Interrupt endpoint 1. Only valid for HOST mode. */ +#define RP2040_USBCTRL_REGS_MAIN_CTRL_OFFSET 0x000040 /* Main control register */ +#define RP2040_USBCTRL_REGS_SOF_WR_OFFSET 0x000044 /* Set the SOF (Start of Frame) frame number in the host controller. The SOF packet is sent every 1ms and the host will increment the frame number by 1 each time. */ +#define RP2040_USBCTRL_REGS_SOF_RD_OFFSET 0x000048 /* Read the last SOF (Start of Frame) frame number seen. In device mode the last SOF received from the host. In host mode the last SOF sent by the host. */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_OFFSET 0x00004c /* SIE control register */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_OFFSET 0x000050 /* SIE status register */ +#define RP2040_USBCTRL_REGS_INT_EP_CTRL_OFFSET 0x000054 /* interrupt endpoint control register */ +#define RP2040_USBCTRL_REGS_BUFF_STATUS_OFFSET 0x000058 /* Buffer status register. A bit set here indicates that a buffer has completed on the endpoint (if the buffer interrupt is enabled). It is possible for 2 buffers to be completed, so clearing the buffer status bit may instantly re set it on the next clock cycle. */ +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_OFFSET 0x00005c /* Which of the double buffers should be handled. Only valid if using an interrupt per buffer (i.e. not per 2 buffers). Not valid for host interrupt endpoint polling because they are only single buffered. */ +#define RP2040_USBCTRL_REGS_EP_ABORT_OFFSET 0x000060 /* Device only: Can be set to ignore the buffer control register for this endpoint in case you would like to revoke a buffer. A NAK will be sent for every access to the endpoint until this bit is cleared. A corresponding bit in `EP_ABORT_DONE` is set when it is safe to modify the buffer control register. */ +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_OFFSET 0x000064 /* Device only: Used in conjunction with `EP_ABORT`. Set once an endpoint is idle so the programmer knows it is safe to modify the buffer control register. */ +#define RP2040_USBCTRL_REGS_EP_STALL_ARM_OFFSET 0x000068 /* Device: this bit must be set in conjunction with the `STALL` bit in the buffer control register to send a STALL on EP0. The device controller clears these bits when a SETUP packet is received because the USB spec requires that a STALL condition is cleared when a SETUP packet is received. */ +#define RP2040_USBCTRL_REGS_NAK_POLL_OFFSET 0x00006c /* Used by the host controller. Sets the wait time in microseconds before trying again if the device replies with a NAK. */ +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_OFFSET 0x000070 /* Device: bits are set when the `IRQ_ON_NAK` or `IRQ_ON_STALL` bits are set. For EP0 this comes from `SIE_CTRL`. For all other endpoints it comes from the endpoint control register. */ +#define RP2040_USBCTRL_REGS_USB_MUXING_OFFSET 0x000074 /* Where to connect the USB controller. Should be to_phy by default. */ +#define RP2040_USBCTRL_REGS_USB_PWR_OFFSET 0x000078 /* Overrides for the power signals in the event that the VBUS signals are not hooked up to GPIO. Set the value of the override and then the override enable to switch over to the override value. */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OFFSET 0x00007c /* This register allows for direct control of the USB phy. Use in conjunction with usbphy_direct_override register to enable each override bit. */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_OFFSET 0x000080 /* Override enable for each control in usbphy_direct */ +#define RP2040_USBCTRL_REGS_USBPHY_TRIM_OFFSET 0x000084 /* Used to adjust trim values of USB phy pull down resistors. */ +#define RP2040_USBCTRL_REGS_INTR_OFFSET 0x00008c /* Raw Interrupts */ +#define RP2040_USBCTRL_REGS_INTE_OFFSET 0x000090 /* Interrupt Enable */ +#define RP2040_USBCTRL_REGS_INTF_OFFSET 0x000094 /* Interrupt Force */ +#define RP2040_USBCTRL_REGS_INTS_OFFSET 0x000098 /* Interrupt status after masking & forcing */ + +/* Register definitions *****************************************************/ + +#define RP2040_USBCTRL_REGS_ADDR_ENDP (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_ADDR_ENDP_OFFSET) +#define RP2040_USBCTRL_REGS_ADDR_ENDPN(n) (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_ADDR_ENDPN_OFFSET(n)) +#define RP2040_USBCTRL_REGS_MAIN_CTRL (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_MAIN_CTRL_OFFSET) +#define RP2040_USBCTRL_REGS_SOF_WR (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_SOF_WR_OFFSET) +#define RP2040_USBCTRL_REGS_SOF_RD (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_SOF_RD_OFFSET) +#define RP2040_USBCTRL_REGS_SIE_CTRL (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_SIE_CTRL_OFFSET) +#define RP2040_USBCTRL_REGS_SIE_STATUS (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_SIE_STATUS_OFFSET) +#define RP2040_USBCTRL_REGS_INT_EP_CTRL (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_INT_EP_CTRL_OFFSET) +#define RP2040_USBCTRL_REGS_BUFF_STATUS (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_BUFF_STATUS_OFFSET) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_OFFSET) +#define RP2040_USBCTRL_REGS_EP_ABORT (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_EP_ABORT_OFFSET) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_EP_ABORT_DONE_OFFSET) +#define RP2040_USBCTRL_REGS_EP_STALL_ARM (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_EP_STALL_ARM_OFFSET) +#define RP2040_USBCTRL_REGS_NAK_POLL (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_NAK_POLL_OFFSET) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_OFFSET) +#define RP2040_USBCTRL_REGS_USB_MUXING (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_USB_MUXING_OFFSET) +#define RP2040_USBCTRL_REGS_USB_PWR (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_USB_PWR_OFFSET) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_USBPHY_DIRECT_OFFSET) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_OFFSET) +#define RP2040_USBCTRL_REGS_USBPHY_TRIM (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_USBPHY_TRIM_OFFSET) +#define RP2040_USBCTRL_REGS_INTR (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_INTR_OFFSET) +#define RP2040_USBCTRL_REGS_INTE (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_INTE_OFFSET) +#define RP2040_USBCTRL_REGS_INTF (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_INTF_OFFSET) +#define RP2040_USBCTRL_REGS_INTS (RP2040_USBCTRL_REGS_BASE + RP2040_USBCTRL_REGS_INTS_OFFSET) + +/* Register bit definitions *************************************************/ + +#define RP2040_USBCTRL_REGS_ADDR_ENDP_ENDPOINT_SHIFT (16) /* Device endpoint to send data to. Only valid for HOST mode. */ +#define RP2040_USBCTRL_REGS_ADDR_ENDP_ENDPOINT_MASK (0x0f << RP2040_USBCTRL_REGS_ADDR_ENDP_ENDPOINT_SHIFT) +#define RP2040_USBCTRL_REGS_ADDR_ENDP_ADDRESS_MASK (0x7f) /* In device mode, the address that the device should respond to. Set in response to a SET_ADDR setup packet from the host. In host mode set to the address of the device to communicate with. */ + +#define RP2040_USBCTRL_REGS_ADDR_ENDPN_INTEP_PREAMBLE (1 << 26) /* Interrupt EP requires preamble (is a low speed device on a full speed hub) */ +#define RP2040_USBCTRL_REGS_ADDR_ENDPN_INTEP_DIR (1 << 25) /* Direction of the interrupt endpoint. In=0, Out=1 */ +#define RP2040_USBCTRL_REGS_ADDR_ENDPN_ENDPOINT_SHIFT (16) /* Endpoint number of the interrupt endpoint */ +#define RP2040_USBCTRL_REGS_ADDR_ENDPN_ENDPOINT_MASK (0x0f << RP2040_USBCTRL_REGS_ADDR_ENDP1_ENDPOINT_SHIFT) +#define RP2040_USBCTRL_REGS_ADDR_ENDPN_ADDRESS_MASK (0x7f) /* Device address */ + +#define RP2040_USBCTRL_REGS_MAIN_CTRL_SIM_TIMING (1 << 31) /* Reduced timings for simulation */ +#define RP2040_USBCTRL_REGS_MAIN_CTRL_HOST_NDEVICE (1 << 1) /* Device mode = 0, Host mode = 1 */ +#define RP2040_USBCTRL_REGS_MAIN_CTRL_CONTROLLER_EN (1 << 0) /* Enable controller */ + +#define RP2040_USBCTRL_REGS_SOF_WR_COUNT_MASK (0x7ff) + +#define RP2040_USBCTRL_REGS_SOF_RD_COUNT_MASK (0x7ff) + +#define RP2040_USBCTRL_REGS_SIE_CTRL_EP0_INT_STALL (1 << 31) /* Device: Set bit in EP_STATUS_STALL_NAK when EP0 sends a STALL */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_EP0_DOUBLE_BUF (1 << 30) /* Device: EP0 single buffered = 0, double buffered = 1 */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF (1 << 29) /* Device: Set bit in BUFF_STATUS for every buffer completed on EP0 */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_EP0_INT_2BUF (1 << 28) /* Device: Set bit in BUFF_STATUS for every 2 buffers completed on EP0 */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_EP0_INT_NAK (1 << 27) /* Device: Set bit in EP_STATUS_STALL_NAK when EP0 sends a NAK */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_DIRECT_EN (1 << 26) /* Direct bus drive enable */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_DIRECT_DP (1 << 25) /* Direct control of DP */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_DIRECT_DM (1 << 24) /* Direct control of DM */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_TRANSCEIVER_PD (1 << 18) /* Power down bus transceiver */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_RPU_OPT (1 << 17) /* Device: Pull-up strength (0=1K2, 1=2k3) */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_PULLUP_EN (1 << 16) /* Device: Enable pull up resistor */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_PULLDOWN_EN (1 << 15) /* Host: Enable pull down resistors */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_RESET_BUS (1 << 13) /* Host: Reset bus */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_RESUME (1 << 12) /* Device: Remote wakeup. Device can initiate its own resume after suspend. */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_VBUS_EN (1 << 11) /* Host: Enable VBUS */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_KEEP_ALIVE_EN (1 << 10) /* Host: Enable keep alive packet (for low speed bus) */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_SOF_EN (1 << 9) /* Host: Enable SOF generation (for full speed bus) */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_SOF_SYNC (1 << 8) /* Host: Delay packet(s) until after SOF */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_PREAMBLE_EN (1 << 6) /* Host: Preable enable for LS device on FS hub */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_STOP_TRANS (1 << 4) /* Host: Stop transaction */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_RECEIVE_DATA (1 << 3) /* Host: Receive transaction (IN to host) */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_SEND_DATA (1 << 2) /* Host: Send transaction (OUT from host) */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_SEND_SETUP (1 << 1) /* Host: Send Setup packet */ +#define RP2040_USBCTRL_REGS_SIE_CTRL_START_TRANS (1 << 0) /* Host: Start transaction */ + +#define RP2040_USBCTRL_REGS_SIE_STATUS_DATA_SEQ_ERROR (1 << 31) /* Data Sequence Error. */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_ACK_REC (1 << 30) /* ACK received. Raised by both host and device. */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_STALL_REC (1 << 29) /* Host: STALL received */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_NAK_REC (1 << 28) /* Host: NAK received */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_RX_TIMEOUT (1 << 27) /* RX timeout is raised by both the host and device if an ACK is not received in the maximum time specified by the USB spec. */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_RX_OVERFLOW (1 << 26) /* RX overflow is raised by the Serial RX engine if the incoming data is too fast. */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_BIT_STUFF_ERROR (1 << 25) /* Bit Stuff Error. Raised by the Serial RX engine. */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_CRC_ERROR (1 << 24) /* CRC Error. Raised by the Serial RX engine. */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_BUS_RESET (1 << 19) /* Device: bus reset received */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_TRANS_COMPLETE (1 << 18) /* Transaction complete. */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_SETUP_REC (1 << 17) /* Device: Setup packet received */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_CONNECTED (1 << 16) /* Device: connected */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_RESUME (1 << 11) /* Host: Device has initiated a remote resume. Device: host has initiated a resume. */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_VBUS_OVER_CURR (1 << 10) /* VBUS over current detected */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_SPEED_SHIFT (8) /* Host: device speed. Disconnected = 00, LS = 01, FS = 10 */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_SPEED_MASK (0x03 << RP2040_USBCTRL_REGS_SIE_STATUS_SPEED_SHIFT) +#define RP2040_USBCTRL_REGS_SIE_STATUS_SUSPENDED (1 << 4) /* Bus in suspended state. Valid for device and host. Host and device will go into suspend if neither Keep Alive / SOF frames are enabled. */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_LINE_STATE_SHIFT (2) /* USB bus line state */ +#define RP2040_USBCTRL_REGS_SIE_STATUS_LINE_STATE_MASK (0x03 << RP2040_USBCTRL_REGS_SIE_STATUS_LINE_STATE_SHIFT) +#define RP2040_USBCTRL_REGS_SIE_STATUS_VBUS_DETECTED (1 << 0) /* Device: VBUS Detected */ + +#define RP2040_USBCTRL_REGS_INT_EP_CTRL_INT_EP_ACTIVE_SHIFT (1) /* Host: Enable interrupt endpoint 1 -> 15 */ +#define RP2040_USBCTRL_REGS_INT_EP_CTRL_INT_EP_ACTIVE_MASK (0x7fff << RP2040_USBCTRL_REGS_INT_EP_CTRL_INT_EP_ACTIVE_SHIFT) + +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP15_OUT (1 << 31) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP15_IN (1 << 30) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP14_OUT (1 << 29) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP14_IN (1 << 28) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP13_OUT (1 << 27) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP13_IN (1 << 26) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP12_OUT (1 << 25) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP12_IN (1 << 24) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP11_OUT (1 << 23) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP11_IN (1 << 22) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP10_OUT (1 << 21) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP10_IN (1 << 20) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP9_OUT (1 << 19) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP9_IN (1 << 18) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP8_OUT (1 << 17) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP8_IN (1 << 16) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP7_OUT (1 << 15) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP7_IN (1 << 14) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP6_OUT (1 << 13) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP6_IN (1 << 12) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP5_OUT (1 << 11) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP5_IN (1 << 10) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP4_OUT (1 << 9) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP4_IN (1 << 8) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP3_OUT (1 << 7) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP3_IN (1 << 6) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP2_OUT (1 << 5) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP2_IN (1 << 4) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP1_OUT (1 << 3) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP1_IN (1 << 2) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP0_OUT (1 << 1) +#define RP2040_USBCTRL_REGS_BUFF_STATUS_EP0_IN (1 << 0) + +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP15_OUT (1 << 31) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP15_IN (1 << 30) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP14_OUT (1 << 29) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP14_IN (1 << 28) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP13_OUT (1 << 27) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP13_IN (1 << 26) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP12_OUT (1 << 25) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP12_IN (1 << 24) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP11_OUT (1 << 23) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP11_IN (1 << 22) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP10_OUT (1 << 21) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP10_IN (1 << 20) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP9_OUT (1 << 19) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP9_IN (1 << 18) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP8_OUT (1 << 17) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP8_IN (1 << 16) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP7_OUT (1 << 15) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP7_IN (1 << 14) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP6_OUT (1 << 13) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP6_IN (1 << 12) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP5_OUT (1 << 11) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP5_IN (1 << 10) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP4_OUT (1 << 9) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP4_IN (1 << 8) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP3_OUT (1 << 7) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP3_IN (1 << 6) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP2_OUT (1 << 5) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP2_IN (1 << 4) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP1_OUT (1 << 3) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP1_IN (1 << 2) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP0_OUT (1 << 1) +#define RP2040_USBCTRL_REGS_BUFF_CPU_SHOULD_HANDLE_EP0_IN (1 << 0) + +#define RP2040_USBCTRL_REGS_EP_ABORT_EP15_OUT (1 << 31) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP15_IN (1 << 30) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP14_OUT (1 << 29) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP14_IN (1 << 28) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP13_OUT (1 << 27) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP13_IN (1 << 26) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP12_OUT (1 << 25) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP12_IN (1 << 24) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP11_OUT (1 << 23) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP11_IN (1 << 22) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP10_OUT (1 << 21) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP10_IN (1 << 20) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP9_OUT (1 << 19) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP9_IN (1 << 18) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP8_OUT (1 << 17) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP8_IN (1 << 16) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP7_OUT (1 << 15) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP7_IN (1 << 14) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP6_OUT (1 << 13) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP6_IN (1 << 12) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP5_OUT (1 << 11) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP5_IN (1 << 10) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP4_OUT (1 << 9) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP4_IN (1 << 8) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP3_OUT (1 << 7) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP3_IN (1 << 6) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP2_OUT (1 << 5) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP2_IN (1 << 4) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP1_OUT (1 << 3) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP1_IN (1 << 2) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP0_OUT (1 << 1) +#define RP2040_USBCTRL_REGS_EP_ABORT_EP0_IN (1 << 0) + +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP15_OUT (1 << 31) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP15_IN (1 << 30) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP14_OUT (1 << 29) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP14_IN (1 << 28) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP13_OUT (1 << 27) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP13_IN (1 << 26) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP12_OUT (1 << 25) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP12_IN (1 << 24) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP11_OUT (1 << 23) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP11_IN (1 << 22) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP10_OUT (1 << 21) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP10_IN (1 << 20) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP9_OUT (1 << 19) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP9_IN (1 << 18) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP8_OUT (1 << 17) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP8_IN (1 << 16) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP7_OUT (1 << 15) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP7_IN (1 << 14) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP6_OUT (1 << 13) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP6_IN (1 << 12) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP5_OUT (1 << 11) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP5_IN (1 << 10) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP4_OUT (1 << 9) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP4_IN (1 << 8) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP3_OUT (1 << 7) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP3_IN (1 << 6) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP2_OUT (1 << 5) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP2_IN (1 << 4) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP1_OUT (1 << 3) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP1_IN (1 << 2) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP0_OUT (1 << 1) +#define RP2040_USBCTRL_REGS_EP_ABORT_DONE_EP0_IN (1 << 0) + +#define RP2040_USBCTRL_REGS_EP_STALL_ARM_EP0_OUT (1 << 1) +#define RP2040_USBCTRL_REGS_EP_STALL_ARM_EP0_IN (1 << 0) + +#define RP2040_USBCTRL_REGS_NAK_POLL_DELAY_FS_SHIFT (16) /* NAK polling interval for a full speed device */ +#define RP2040_USBCTRL_REGS_NAK_POLL_DELAY_FS_MASK (0x3ff << RP2040_USBCTRL_REGS_NAK_POLL_DELAY_FS_SHIFT) +#define RP2040_USBCTRL_REGS_NAK_POLL_DELAY_LS_MASK (0x3ff) /* NAK polling interval for a low speed device */ + +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP15_OUT (1 << 31) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP15_IN (1 << 30) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP14_OUT (1 << 29) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP14_IN (1 << 28) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP13_OUT (1 << 27) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP13_IN (1 << 26) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP12_OUT (1 << 25) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP12_IN (1 << 24) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP11_OUT (1 << 23) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP11_IN (1 << 22) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP10_OUT (1 << 21) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP10_IN (1 << 20) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP9_OUT (1 << 19) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP9_IN (1 << 18) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP8_OUT (1 << 17) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP8_IN (1 << 16) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP7_OUT (1 << 15) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP7_IN (1 << 14) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP6_OUT (1 << 13) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP6_IN (1 << 12) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP5_OUT (1 << 11) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP5_IN (1 << 10) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP4_OUT (1 << 9) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP4_IN (1 << 8) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP3_OUT (1 << 7) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP3_IN (1 << 6) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP2_OUT (1 << 5) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP2_IN (1 << 4) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP1_OUT (1 << 3) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP1_IN (1 << 2) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP0_OUT (1 << 1) +#define RP2040_USBCTRL_REGS_EP_STATUS_STALL_NAK_EP0_IN (1 << 0) + +#define RP2040_USBCTRL_REGS_USB_MUXING_SOFTCON (1 << 3) +#define RP2040_USBCTRL_REGS_USB_MUXING_TO_DIGITAL_PAD (1 << 2) +#define RP2040_USBCTRL_REGS_USB_MUXING_TO_EXTPHY (1 << 1) +#define RP2040_USBCTRL_REGS_USB_MUXING_TO_PHY (1 << 0) + +#define RP2040_USBCTRL_REGS_USB_PWR_OVERCURR_DETECT_EN (1 << 5) +#define RP2040_USBCTRL_REGS_USB_PWR_OVERCURR_DETECT (1 << 4) +#define RP2040_USBCTRL_REGS_USB_PWR_VBUS_DETECT_OVERRIDE_EN (1 << 3) +#define RP2040_USBCTRL_REGS_USB_PWR_VBUS_DETECT (1 << 2) +#define RP2040_USBCTRL_REGS_USB_PWR_VBUS_EN_OVERRIDE_EN (1 << 1) +#define RP2040_USBCTRL_REGS_USB_PWR_VBUS_EN (1 << 0) + +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DM_OVV (1 << 22) /* DM over voltage */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DP_OVV (1 << 21) /* DP over voltage */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DM_OVCN (1 << 20) /* DM overcurrent */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DP_OVCN (1 << 19) /* DP overcurrent */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_RX_DM (1 << 18) /* DPM pin state */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_RX_DP (1 << 17) /* DPP pin state */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_RX_DD (1 << 16) /* Differential RX */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_TX_DIFFMODE (1 << 15) /* TX_DIFFMODE=0: Single ended mode TX_DIFFMODE=1: Differential drive mode (TX_DM, TX_DM_OE ignored) */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_TX_FSSLEW (1 << 14) /* TX_FSSLEW=0: Low speed slew rate TX_FSSLEW=1: Full speed slew rate */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_TX_PD (1 << 13) /* TX power down override (if override enable is set). 1 = powered down. */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_RX_PD (1 << 12) /* RX power down override (if override enable is set). 1 = powered down. */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_TX_DM (1 << 11) /* Output data. TX_DIFFMODE=1, Ignored TX_DIFFMODE=0, Drives DPM only. TX_DM_OE=1 to enable drive. DPM=TX_DM */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_TX_DP (1 << 10) /* Output data. If TX_DIFFMODE=1, Drives DPP/DPM diff pair. TX_DP_OE=1 to enable drive. DPP=TX_DP, DPM=~TX_DP If TX_DIFFMODE=0, Drives DPP only. TX_DP_OE=1 to enable drive. DPP=TX_DP */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_TX_DM_OE (1 << 9) /* Output enable. If TX_DIFFMODE=1, Ignored. If TX_DIFFMODE=0, OE for DPM only. 0 - DPM in Hi-Z state; 1 - DPM driving */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_TX_DP_OE (1 << 8) /* Output enable. If TX_DIFFMODE=1, OE for DPP/DPM diff pair. 0 - DPP/DPM in Hi-Z state; 1 - DPP/DPM driving If TX_DIFFMODE=0, OE for DPP only. 0 - DPP in Hi-Z state; 1 - DPP driving */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DM_PULLDN_EN (1 << 6) /* DM pull down enable */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DM_PULLUP_EN (1 << 5) /* DM pull up enable */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DM_PULLUP_HISEL (1 << 4) /* Enable the second DM pull up resistor. 0 - Pull = Rpu2; 1 - Pull = Rpu1 + Rpu2 */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DP_PULLDN_EN (1 << 2) /* DP pull down enable */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DP_PULLUP_EN (1 << 1) /* DP pull up enable */ +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_DP_PULLUP_HISEL (1 << 0) /* Enable the second DP pull up resistor. 0 - Pull = Rpu2; 1 - Pull = Rpu1 + Rpu2 */ + +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_TX_DIFFMODE_OVERRIDE_EN (1 << 15) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DM_PULLUP_OVERRIDE_EN (1 << 12) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_TX_FSSLEW_OVERRIDE_EN (1 << 11) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_TX_PD_OVERRIDE_EN (1 << 10) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_RX_PD_OVERRIDE_EN (1 << 9) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_TX_DM_OVERRIDE_EN (1 << 8) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_TX_DP_OVERRIDE_EN (1 << 7) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_TX_DM_OE_OVERRIDE_EN (1 << 6) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_TX_DP_OE_OVERRIDE_EN (1 << 5) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DM_PULLDN_EN_OVERRIDE_EN (1 << 4) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DP_PULLDN_EN_OVERRIDE_EN (1 << 3) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN (1 << 2) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DM_PULLUP_HISEL_OVERRIDE_EN (1 << 1) +#define RP2040_USBCTRL_REGS_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_HISEL_OVERRIDE_EN (1 << 0) + +#define RP2040_USBCTRL_REGS_USBPHY_TRIM_DM_PULLDN_TRIM_SHIFT (8) /* Value to drive to USB PHY DM pulldown resistor trim control Experimental data suggests that the reset value will work, but this register allows adjustment if required */ +#define RP2040_USBCTRL_REGS_USBPHY_TRIM_DM_PULLDN_TRIM_MASK (0x1f << RP2040_USBCTRL_REGS_USBPHY_TRIM_DM_PULLDN_TRIM_SHIFT) +#define RP2040_USBCTRL_REGS_USBPHY_TRIM_DP_PULLDN_TRIM_MASK (0x1f) /* Value to drive to USB PHY DP pulldown resistor trim control Experimental data suggests that the reset value will work, but this register allows adjustment if required */ + +#define RP2040_USBCTRL_REGS_INTR_EP_STALL_NAK (1 << 19) /* Raised when any bit in EP_STATUS_STALL_NAK is set. Clear by clearing all bits in EP_STATUS_STALL_NAK. */ +#define RP2040_USBCTRL_REGS_INTR_ABORT_DONE (1 << 18) /* Raised when any bit in ABORT_DONE is set. Clear by clearing all bits in ABORT_DONE. */ +#define RP2040_USBCTRL_REGS_INTR_DEV_SOF (1 << 17) /* Set every time the device receives a SOF (Start of Frame) packet. Cleared by reading SOF_RD */ +#define RP2040_USBCTRL_REGS_INTR_SETUP_REQ (1 << 16) /* Device. Source: SIE_STATUS.SETUP_REC */ +#define RP2040_USBCTRL_REGS_INTR_DEV_RESUME_FROM_HOST (1 << 15) /* Set when the device receives a resume from the host. Cleared by writing to SIE_STATUS.RESUME */ +#define RP2040_USBCTRL_REGS_INTR_DEV_SUSPEND (1 << 14) /* Set when the device suspend state changes. Cleared by writing to SIE_STATUS.SUSPENDED */ +#define RP2040_USBCTRL_REGS_INTR_DEV_CONN_DIS (1 << 13) /* Set when the device connection state changes. Cleared by writing to SIE_STATUS.CONNECTED */ +#define RP2040_USBCTRL_REGS_INTR_BUS_RESET (1 << 12) /* Source: SIE_STATUS.BUS_RESET */ +#define RP2040_USBCTRL_REGS_INTR_VBUS_DETECT (1 << 11) /* Source: SIE_STATUS.VBUS_DETECT */ +#define RP2040_USBCTRL_REGS_INTR_STALL (1 << 10) /* Source: SIE_STATUS.STALL_REC */ +#define RP2040_USBCTRL_REGS_INTR_ERROR_CRC (1 << 9) /* Source: SIE_STATUS.CRC_ERROR */ +#define RP2040_USBCTRL_REGS_INTR_ERROR_BIT_STUFF (1 << 8) /* Source: SIE_STATUS.BIT_STUFF_ERROR */ +#define RP2040_USBCTRL_REGS_INTR_ERROR_RX_OVERFLOW (1 << 7) /* Source: SIE_STATUS.RX_OVERFLOW */ +#define RP2040_USBCTRL_REGS_INTR_ERROR_RX_TIMEOUT (1 << 6) /* Source: SIE_STATUS.RX_TIMEOUT */ +#define RP2040_USBCTRL_REGS_INTR_ERROR_DATA_SEQ (1 << 5) /* Source: SIE_STATUS.DATA_SEQ_ERROR */ +#define RP2040_USBCTRL_REGS_INTR_BUFF_STATUS (1 << 4) /* Raised when any bit in BUFF_STATUS is set. Clear by clearing all bits in BUFF_STATUS. */ +#define RP2040_USBCTRL_REGS_INTR_TRANS_COMPLETE (1 << 3) /* Raised every time SIE_STATUS.TRANS_COMPLETE is set. Clear by writing to this bit. */ +#define RP2040_USBCTRL_REGS_INTR_HOST_SOF (1 << 2) /* Host: raised every time the host sends a SOF (Start of Frame). Cleared by reading SOF_RD */ +#define RP2040_USBCTRL_REGS_INTR_HOST_RESUME (1 << 1) /* Host: raised when a device wakes up the host. Cleared by writing to SIE_STATUS.RESUME */ +#define RP2040_USBCTRL_REGS_INTR_HOST_CONN_DIS (1 << 0) /* Host: raised when a device is connected or disconnected (i.e. when SIE_STATUS.SPEED changes). Cleared by writing to SIE_STATUS.SPEED */ + +#define RP2040_USBCTRL_REGS_INTE_EP_STALL_NAK (1 << 19) /* Raised when any bit in EP_STATUS_STALL_NAK is set. Clear by clearing all bits in EP_STATUS_STALL_NAK. */ +#define RP2040_USBCTRL_REGS_INTE_ABORT_DONE (1 << 18) /* Raised when any bit in ABORT_DONE is set. Clear by clearing all bits in ABORT_DONE. */ +#define RP2040_USBCTRL_REGS_INTE_DEV_SOF (1 << 17) /* Set every time the device receives a SOF (Start of Frame) packet. Cleared by reading SOF_RD */ +#define RP2040_USBCTRL_REGS_INTE_SETUP_REQ (1 << 16) /* Device. Source: SIE_STATUS.SETUP_REC */ +#define RP2040_USBCTRL_REGS_INTE_DEV_RESUME_FROM_HOST (1 << 15) /* Set when the device receives a resume from the host. Cleared by writing to SIE_STATUS.RESUME */ +#define RP2040_USBCTRL_REGS_INTE_DEV_SUSPEND (1 << 14) /* Set when the device suspend state changes. Cleared by writing to SIE_STATUS.SUSPENDED */ +#define RP2040_USBCTRL_REGS_INTE_DEV_CONN_DIS (1 << 13) /* Set when the device connection state changes. Cleared by writing to SIE_STATUS.CONNECTED */ +#define RP2040_USBCTRL_REGS_INTE_BUS_RESET (1 << 12) /* Source: SIE_STATUS.BUS_RESET */ +#define RP2040_USBCTRL_REGS_INTE_VBUS_DETECT (1 << 11) /* Source: SIE_STATUS.VBUS_DETECT */ +#define RP2040_USBCTRL_REGS_INTE_STALL (1 << 10) /* Source: SIE_STATUS.STALL_REC */ +#define RP2040_USBCTRL_REGS_INTE_ERROR_CRC (1 << 9) /* Source: SIE_STATUS.CRC_ERROR */ +#define RP2040_USBCTRL_REGS_INTE_ERROR_BIT_STUFF (1 << 8) /* Source: SIE_STATUS.BIT_STUFF_ERROR */ +#define RP2040_USBCTRL_REGS_INTE_ERROR_RX_OVERFLOW (1 << 7) /* Source: SIE_STATUS.RX_OVERFLOW */ +#define RP2040_USBCTRL_REGS_INTE_ERROR_RX_TIMEOUT (1 << 6) /* Source: SIE_STATUS.RX_TIMEOUT */ +#define RP2040_USBCTRL_REGS_INTE_ERROR_DATA_SEQ (1 << 5) /* Source: SIE_STATUS.DATA_SEQ_ERROR */ +#define RP2040_USBCTRL_REGS_INTE_BUFF_STATUS (1 << 4) /* Raised when any bit in BUFF_STATUS is set. Clear by clearing all bits in BUFF_STATUS. */ +#define RP2040_USBCTRL_REGS_INTE_TRANS_COMPLETE (1 << 3) /* Raised every time SIE_STATUS.TRANS_COMPLETE is set. Clear by writing to this bit. */ +#define RP2040_USBCTRL_REGS_INTE_HOST_SOF (1 << 2) /* Host: raised every time the host sends a SOF (Start of Frame). Cleared by reading SOF_RD */ +#define RP2040_USBCTRL_REGS_INTE_HOST_RESUME (1 << 1) /* Host: raised when a device wakes up the host. Cleared by writing to SIE_STATUS.RESUME */ +#define RP2040_USBCTRL_REGS_INTE_HOST_CONN_DIS (1 << 0) /* Host: raised when a device is connected or disconnected (i.e. when SIE_STATUS.SPEED changes). Cleared by writing to SIE_STATUS.SPEED */ + +#define RP2040_USBCTRL_REGS_INTF_EP_STALL_NAK (1 << 19) /* Raised when any bit in EP_STATUS_STALL_NAK is set. Clear by clearing all bits in EP_STATUS_STALL_NAK. */ +#define RP2040_USBCTRL_REGS_INTF_ABORT_DONE (1 << 18) /* Raised when any bit in ABORT_DONE is set. Clear by clearing all bits in ABORT_DONE. */ +#define RP2040_USBCTRL_REGS_INTF_DEV_SOF (1 << 17) /* Set every time the device receives a SOF (Start of Frame) packet. Cleared by reading SOF_RD */ +#define RP2040_USBCTRL_REGS_INTF_SETUP_REQ (1 << 16) /* Device. Source: SIE_STATUS.SETUP_REC */ +#define RP2040_USBCTRL_REGS_INTF_DEV_RESUME_FROM_HOST (1 << 15) /* Set when the device receives a resume from the host. Cleared by writing to SIE_STATUS.RESUME */ +#define RP2040_USBCTRL_REGS_INTF_DEV_SUSPEND (1 << 14) /* Set when the device suspend state changes. Cleared by writing to SIE_STATUS.SUSPENDED */ +#define RP2040_USBCTRL_REGS_INTF_DEV_CONN_DIS (1 << 13) /* Set when the device connection state changes. Cleared by writing to SIE_STATUS.CONNECTED */ +#define RP2040_USBCTRL_REGS_INTF_BUS_RESET (1 << 12) /* Source: SIE_STATUS.BUS_RESET */ +#define RP2040_USBCTRL_REGS_INTF_VBUS_DETECT (1 << 11) /* Source: SIE_STATUS.VBUS_DETECT */ +#define RP2040_USBCTRL_REGS_INTF_STALL (1 << 10) /* Source: SIE_STATUS.STALL_REC */ +#define RP2040_USBCTRL_REGS_INTF_ERROR_CRC (1 << 9) /* Source: SIE_STATUS.CRC_ERROR */ +#define RP2040_USBCTRL_REGS_INTF_ERROR_BIT_STUFF (1 << 8) /* Source: SIE_STATUS.BIT_STUFF_ERROR */ +#define RP2040_USBCTRL_REGS_INTF_ERROR_RX_OVERFLOW (1 << 7) /* Source: SIE_STATUS.RX_OVERFLOW */ +#define RP2040_USBCTRL_REGS_INTF_ERROR_RX_TIMEOUT (1 << 6) /* Source: SIE_STATUS.RX_TIMEOUT */ +#define RP2040_USBCTRL_REGS_INTF_ERROR_DATA_SEQ (1 << 5) /* Source: SIE_STATUS.DATA_SEQ_ERROR */ +#define RP2040_USBCTRL_REGS_INTF_BUFF_STATUS (1 << 4) /* Raised when any bit in BUFF_STATUS is set. Clear by clearing all bits in BUFF_STATUS. */ +#define RP2040_USBCTRL_REGS_INTF_TRANS_COMPLETE (1 << 3) /* Raised every time SIE_STATUS.TRANS_COMPLETE is set. Clear by writing to this bit. */ +#define RP2040_USBCTRL_REGS_INTF_HOST_SOF (1 << 2) /* Host: raised every time the host sends a SOF (Start of Frame). Cleared by reading SOF_RD */ +#define RP2040_USBCTRL_REGS_INTF_HOST_RESUME (1 << 1) /* Host: raised when a device wakes up the host. Cleared by writing to SIE_STATUS.RESUME */ +#define RP2040_USBCTRL_REGS_INTF_HOST_CONN_DIS (1 << 0) /* Host: raised when a device is connected or disconnected (i.e. when SIE_STATUS.SPEED changes). Cleared by writing to SIE_STATUS.SPEED */ + +#define RP2040_USBCTRL_REGS_INTS_EP_STALL_NAK (1 << 19) /* Raised when any bit in EP_STATUS_STALL_NAK is set. Clear by clearing all bits in EP_STATUS_STALL_NAK. */ +#define RP2040_USBCTRL_REGS_INTS_ABORT_DONE (1 << 18) /* Raised when any bit in ABORT_DONE is set. Clear by clearing all bits in ABORT_DONE. */ +#define RP2040_USBCTRL_REGS_INTS_DEV_SOF (1 << 17) /* Set every time the device receives a SOF (Start of Frame) packet. Cleared by reading SOF_RD */ +#define RP2040_USBCTRL_REGS_INTS_SETUP_REQ (1 << 16) /* Device. Source: SIE_STATUS.SETUP_REC */ +#define RP2040_USBCTRL_REGS_INTS_DEV_RESUME_FROM_HOST (1 << 15) /* Set when the device receives a resume from the host. Cleared by writing to SIE_STATUS.RESUME */ +#define RP2040_USBCTRL_REGS_INTS_DEV_SUSPEND (1 << 14) /* Set when the device suspend state changes. Cleared by writing to SIE_STATUS.SUSPENDED */ +#define RP2040_USBCTRL_REGS_INTS_DEV_CONN_DIS (1 << 13) /* Set when the device connection state changes. Cleared by writing to SIE_STATUS.CONNECTED */ +#define RP2040_USBCTRL_REGS_INTS_BUS_RESET (1 << 12) /* Source: SIE_STATUS.BUS_RESET */ +#define RP2040_USBCTRL_REGS_INTS_VBUS_DETECT (1 << 11) /* Source: SIE_STATUS.VBUS_DETECT */ +#define RP2040_USBCTRL_REGS_INTS_STALL (1 << 10) /* Source: SIE_STATUS.STALL_REC */ +#define RP2040_USBCTRL_REGS_INTS_ERROR_CRC (1 << 9) /* Source: SIE_STATUS.CRC_ERROR */ +#define RP2040_USBCTRL_REGS_INTS_ERROR_BIT_STUFF (1 << 8) /* Source: SIE_STATUS.BIT_STUFF_ERROR */ +#define RP2040_USBCTRL_REGS_INTS_ERROR_RX_OVERFLOW (1 << 7) /* Source: SIE_STATUS.RX_OVERFLOW */ +#define RP2040_USBCTRL_REGS_INTS_ERROR_RX_TIMEOUT (1 << 6) /* Source: SIE_STATUS.RX_TIMEOUT */ +#define RP2040_USBCTRL_REGS_INTS_ERROR_DATA_SEQ (1 << 5) /* Source: SIE_STATUS.DATA_SEQ_ERROR */ +#define RP2040_USBCTRL_REGS_INTS_BUFF_STATUS (1 << 4) /* Raised when any bit in BUFF_STATUS is set. Clear by clearing all bits in BUFF_STATUS. */ +#define RP2040_USBCTRL_REGS_INTS_TRANS_COMPLETE (1 << 3) /* Raised every time SIE_STATUS.TRANS_COMPLETE is set. Clear by writing to this bit. */ +#define RP2040_USBCTRL_REGS_INTS_HOST_SOF (1 << 2) /* Host: raised every time the host sends a SOF (Start of Frame). Cleared by reading SOF_RD */ +#define RP2040_USBCTRL_REGS_INTS_HOST_RESUME (1 << 1) /* Host: raised when a device wakes up the host. Cleared by writing to SIE_STATUS.RESUME */ +#define RP2040_USBCTRL_REGS_INTS_HOST_CONN_DIS (1 << 0) /* Host: raised when a device is connected or disconnected (i.e. when SIE_STATUS.SPEED changes). Cleared by writing to SIE_STATUS.SPEED */ + +#endif /* __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_USBCTRL_REGS_H */ diff --git a/arch/arm/src/rp2040/rp2040_usbdev.c b/arch/arm/src/rp2040/rp2040_usbdev.c new file mode 100644 index 00000000000..12f6e2d23b2 --- /dev/null +++ b/arch/arm/src/rp2040/rp2040_usbdev.c @@ -0,0 +1,2162 @@ +/**************************************************************************** + * arch/arm/src/rp2040/rp2040_usbdev.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "chip.h" +#include "arm_arch.h" +#include "arm_internal.h" +#include "rp2040_usbdev.h" + +#include "hardware/rp2040_resets.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_USBDEV_EP0_MAXSIZE +# define CONFIG_USBDEV_EP0_MAXSIZE 64 +#endif + +#ifndef CONFIG_USBDEV_SETUP_MAXDATASIZE +# define CONFIG_USBDEV_SETUP_MAXDATASIZE (CONFIG_USBDEV_EP0_MAXSIZE * 4) +#endif + +/* Debug ********************************************************************/ + +/* Trace error codes */ + +#define RP2040_TRACEERR_ALLOCFAIL 0x0001 +#define RP2040_TRACEERR_BINDFAILED 0x0002 +#define RP2040_TRACEERR_DRIVER 0x0003 +#define RP2040_TRACEERR_EPREAD 0x0004 +#define RP2040_TRACEERR_EWRITE 0x0005 +#define RP2040_TRACEERR_INVALIDPARMS 0x0006 +#define RP2040_TRACEERR_IRQREGISTRATION 0x0007 +#define RP2040_TRACEERR_NULLPACKET 0x0008 +#define RP2040_TRACEERR_NULLREQUEST 0x0009 +#define RP2040_TRACEERR_REQABORTED 0x000a +#define RP2040_TRACEERR_STALLEDCLRFEATURE 0x000b +#define RP2040_TRACEERR_STALLEDISPATCH 0x000c +#define RP2040_TRACEERR_STALLEDGETST 0x000d +#define RP2040_TRACEERR_STALLEDGETSTEP 0x000e +#define RP2040_TRACEERR_STALLEDGETSTRECIP 0x000f +#define RP2040_TRACEERR_STALLEDREQUEST 0x0010 +#define RP2040_TRACEERR_STALLEDSETFEATURE 0x0011 +#define RP2040_TRACEERR_TXREQLOST 0x0012 +#define RP2040_TRACEERR_RXREQLOST 0x0013 + +/* Trace interrupt codes */ + +#define RP2040_TRACEINTID_GETSTATUS 1 +#define RP2040_TRACEINTID_GETIFDEV 2 +#define RP2040_TRACEINTID_CLEARFEATURE 3 +#define RP2040_TRACEINTID_SETFEATURE 4 +#define RP2040_TRACEINTID_TESTMODE 5 +#define RP2040_TRACEINTID_SETADDRESS 6 +#define RP2040_TRACEINTID_GETSETDESC 7 +#define RP2040_TRACEINTID_GETSETIFCONFIG 8 +#define RP2040_TRACEINTID_SYNCHFRAME 9 +#define RP2040_TRACEINTID_DISPATCH 10 +#define RP2040_TRACEINTID_GETENDPOINT 11 +#define RP2040_TRACEINTID_HANDLEZLP 12 +#define RP2040_TRACEINTID_USBINTERRUPT 13 +#define RP2040_TRACEINTID_INTR_BUSRESET 14 +#define RP2040_TRACEINTID_INTR_BUFFSTAT 15 +#define RP2040_TRACEINTID_INTR_SETUP 16 +#define RP2040_TRACEINTID_EPOUTQEMPTY 17 + +#ifdef CONFIG_USBDEV_TRACE_STRINGS +const struct trace_msg_t g_usb_trace_strings_deverror[] = +{ + TRACE_STR(RP2040_TRACEERR_ALLOCFAIL), + TRACE_STR(RP2040_TRACEERR_BINDFAILED), + TRACE_STR(RP2040_TRACEERR_DRIVER), + TRACE_STR(RP2040_TRACEERR_EPREAD), + TRACE_STR(RP2040_TRACEERR_EWRITE), + TRACE_STR(RP2040_TRACEERR_INVALIDPARMS), + TRACE_STR(RP2040_TRACEERR_IRQREGISTRATION), + TRACE_STR(RP2040_TRACEERR_NULLPACKET), + TRACE_STR(RP2040_TRACEERR_NULLREQUEST), + TRACE_STR(RP2040_TRACEERR_REQABORTED), + TRACE_STR(RP2040_TRACEERR_STALLEDCLRFEATURE), + TRACE_STR(RP2040_TRACEERR_STALLEDISPATCH), + TRACE_STR(RP2040_TRACEERR_STALLEDGETST), + TRACE_STR(RP2040_TRACEERR_STALLEDGETSTEP), + TRACE_STR(RP2040_TRACEERR_STALLEDGETSTRECIP), + TRACE_STR(RP2040_TRACEERR_STALLEDREQUEST), + TRACE_STR(RP2040_TRACEERR_STALLEDSETFEATURE), + TRACE_STR(RP2040_TRACEERR_TXREQLOST), + TRACE_STR(RP2040_TRACEERR_RXREQLOST), + TRACE_STR_END +}; + +const struct trace_msg_t g_usb_trace_strings_intdecode[] = +{ + TRACE_STR(RP2040_TRACEINTID_GETSTATUS), + TRACE_STR(RP2040_TRACEINTID_GETIFDEV), + TRACE_STR(RP2040_TRACEINTID_CLEARFEATURE), + TRACE_STR(RP2040_TRACEINTID_SETFEATURE), + TRACE_STR(RP2040_TRACEINTID_TESTMODE), + TRACE_STR(RP2040_TRACEINTID_SETADDRESS), + TRACE_STR(RP2040_TRACEINTID_GETSETDESC), + TRACE_STR(RP2040_TRACEINTID_GETSETIFCONFIG), + TRACE_STR(RP2040_TRACEINTID_SYNCHFRAME), + TRACE_STR(RP2040_TRACEINTID_DISPATCH), + TRACE_STR(RP2040_TRACEINTID_GETENDPOINT), + TRACE_STR(RP2040_TRACEINTID_HANDLEZLP), + TRACE_STR(RP2040_TRACEINTID_USBINTERRUPT), + TRACE_STR(RP2040_TRACEINTID_INTR_BUSRESET), + TRACE_STR(RP2040_TRACEINTID_INTR_BUFFSTAT), + TRACE_STR(RP2040_TRACEINTID_INTR_SETUP), + TRACE_STR(RP2040_TRACEINTID_EPOUTQEMPTY), + TRACE_STR_END +}; +#endif + +/* Hardware interface *******************************************************/ + +/* Hardware dependent sizes and numbers */ + +#define RP2040_EP0MAXPACKET 64 /* EP0 max packet size */ +#define RP2040_BULKMAXPACKET 64 /* Bulk endpoint max packet */ +#define RP2040_INTRMAXPACKET 64 /* Interrupt endpoint max packet */ +#define RP2040_ISOMAXPACKET 1023 /* Isochronous max packet size */ + +/* USB endpoint number conversion macros + * EPINDEX: eplist[] index (the endpoint list in rp2040_usbdev_s) + * 0 - Endpoint 0 IN + * 1 - Endpoint 0 OUT + * 2 - Endpoint 1 (IN or OUT - depends on the endpoint configuration) + * 3 - Endpoint 2 (IN or OUT - depends on the endpoint configuration) + * 4 - Endpoint 3 (IN or OUT - depends on the endpoint configuration) + * : + * 15 - Endpoint 14 (IN or OUT - depends on the endpoint configuration) + * 16 - Endpoint 15 (IN or OUT - depends on the endpoint configuration) + * + * DPINDEX: RP2040 DPSRAM control index + * 0 - Endpoint 0 IN + * 1 - Endpoint 0 OUT + * 2 - Endpoint 1 IN + * 3 - Endpoint 1 OUT + * 4 - Endpoint 2 IN + * 5 - Endpoint 2 OUT + * : + * 30 - Endpoint 15 IN + * 31 - Endpoint 15 OUT + */ + +#define RP2040_EPINDEX(eplog) (USB_EPNO(eplog) == 0 ? \ + (USB_ISEPIN(eplog) ? 0 : 1) : \ + (USB_EPNO(eplog) + 1)) +#define RP2040_DPINDEX(eplog) (USB_EPNO(eplog) * 2 + USB_ISEPOUT(eplog)) +#define RP2040_DPTOEP(index) ((index) < 2 ? (index) : (index) / 2 + 1) + +#define RP2040_NENDPOINTS (16 + 1) /* EP0 IN, EP0 OUT, EP1..EP15 */ + +/* Request queue operations *************************************************/ + +#define rp2040_rqempty(ep) ((ep)->head == NULL) +#define rp2040_rqpeek(ep) ((ep)->head) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* USB Zero Length Packet type */ + +enum rp2040_zlp_e +{ + RP2040_ZLP_NONE = 0, /* Don't send/receive Zero Length Packet */ + RP2040_ZLP_IN_REPLY, /* Receive ZLP to reply IN transfer */ + RP2040_ZLP_OUT_REPLY, /* Send ZLP to reply OUT transfer */ +}; + +/* A container for a request so that the request make be retained in a list */ + +struct rp2040_req_s +{ + struct usbdev_req_s req; /* Standard USB request */ + struct rp2040_req_s *flink; /* Supports a singly linked list */ +}; + +/* This is the internal representation of an endpoint */ + +struct rp2040_ep_s +{ + /* Common endpoint fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbdev_ep_s + * to struct rp2040_ep_s. + */ + + struct usbdev_ep_s ep; /* Standard endpoint structure */ + + /* RP2040-specific fields */ + + struct rp2040_usbdev_s *dev; /* Reference to private driver data */ + struct rp2040_req_s *head; /* Request list for this endpoint */ + struct rp2040_req_s *tail; + uint8_t *data_buf; /* DPSRAM buffer address */ + uint32_t ep_ctrl; /* DPSRAM EP control register address */ + uint32_t buf_ctrl; /* DPSRAM buffer control register address */ + int next_pid; /* Next PID 0:DATA0, 1:DATA1 */ + uint8_t type; /* 0:cont, 1:iso, 2:bulk, 3:int */ + uint8_t epphy; /* Physical EP address */ + bool txnullpkt; /* Null packet needed at end of transfer */ + bool in; /* in = true, out = false */ + bool stalled; /* The EP is stalled */ + bool pending_stall; /* Pending stall request */ +}; + +/* This structure encapsulates the overall driver state */ + +struct rp2040_usbdev_s +{ + /* Common device fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbdev_s + * to struct rp2040_usbdev_s. + */ + + struct usbdev_s usbdev; + + /* The bound device class driver */ + + struct usbdevclass_driver_s *driver; + + /* RP2040-specific fields */ + + uint16_t next_offset; /* Unused DPSRAM buffer offset */ + uint8_t dev_addr; /* USB device address */ + enum rp2040_zlp_e zlp_stat; /* Pending EP0 ZLP status */ + uint16_t used; /* used epphy */ + bool stalled; + bool selfpowered; /* 1: Device is self powered */ + + /* EP0 SETUP data buffering. + * + * ctrl + * The 8-byte SETUP request is received on the EP0 OUT endpoint and is + * saved. + * + * ep0data + * For OUT SETUP requests, the SETUP data phase must also complete before + * the SETUP command can be processed. + * + * ep0datlen + * Length of OUT DATA received in ep0data[] + */ + + struct usb_ctrlreq_s ctrl; /* Last EP0 request */ + + uint8_t ep0data[CONFIG_USBDEV_SETUP_MAXDATASIZE]; + uint16_t ep0datlen; + uint16_t ep0reqlen; + + /* The endpoint list */ + + struct rp2040_ep_s eplist[RP2040_NENDPOINTS]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Request queue operations *************************************************/ + +static FAR struct +rp2040_req_s *rp2040_rqdequeue(FAR struct rp2040_ep_s *privep); +static void rp2040_rqenqueue(FAR struct rp2040_ep_s *privep, + FAR struct rp2040_req_s *req); + +/* Low level data transfers and request operations */ + +static void rp2040_update_buffer_control(FAR struct rp2040_ep_s *privep, + uint32_t and_mask, + uint32_t or_mask); +static int rp2040_epwrite(FAR struct rp2040_ep_s *privep, FAR uint8_t *buf, + uint16_t nbytes); +static int rp2040_epread(FAR struct rp2040_ep_s *privep, uint16_t nbytes); +static void rp2040_abortrequest(struct rp2040_ep_s *privep, + struct rp2040_req_s *privreq, + int16_t result); +static void rp2040_reqcomplete(struct rp2040_ep_s *privep, int16_t result); +static void rp2040_txcomplete(FAR struct rp2040_ep_s *privep); +static int rp2040_wrrequest(struct rp2040_ep_s *privep); +static void rp2040_rxcomplete(FAR struct rp2040_ep_s *privep); +static int rp2040_rdrequest(FAR struct rp2040_ep_s *privep); + +static void rp2040_handle_zlp(FAR struct rp2040_usbdev_s *priv); + +static void rp2040_cancelrequests(FAR struct rp2040_ep_s *privep); +static FAR struct rp2040_ep_s * + rp2040_epfindbyaddr(FAR struct rp2040_usbdev_s *priv, uint16_t eplog); +static void rp2040_dispatchrequest(FAR struct rp2040_usbdev_s *priv); +static void rp2040_ep0setup(FAR struct rp2040_usbdev_s *priv); + +/* Interrupt handling */ + +static void rp2040_usbintr_setup(FAR struct rp2040_usbdev_s *priv); +static void rp2040_usbintr_ep0out(FAR struct rp2040_usbdev_s *priv, + FAR struct rp2040_ep_s *privep); +static bool rp2040_usbintr_buffstat(FAR struct rp2040_usbdev_s *priv); +static void rp2040_usbintr_busreset(FAR struct rp2040_usbdev_s *priv); +static int rp2040_usbinterrupt(int irq, FAR void *context, FAR void *arg); + +/* Endpoint methods */ + +static int rp2040_epconfigure(FAR struct usbdev_ep_s *ep, + FAR const struct usb_epdesc_s *desc, + bool last); + +static int rp2040_epdisable(FAR struct usbdev_ep_s *ep); +static FAR struct usbdev_req_s *rp2040_epallocreq(FAR struct usbdev_ep_s + *ep); +static void rp2040_epfreereq(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req); +static int rp2040_epsubmit(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *privreq); +static int rp2040_epcancel(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *privreq); +static int rp2040_epstall_exec(FAR struct usbdev_ep_s *ep); +static int rp2040_epstall(FAR struct usbdev_ep_s *ep, bool resume); + +/* USB device controller methods */ + +static FAR struct usbdev_ep_s *rp2040_allocep(FAR struct usbdev_s *dev, + uint8_t epno, bool in, + uint8_t eptype); +static void rp2040_freeep(FAR struct usbdev_s *dev, + FAR struct usbdev_ep_s *ep); +static int rp2040_getframe(FAR struct usbdev_s *dev); +static int rp2040_wakeup(FAR struct usbdev_s *dev); +static int rp2040_selfpowered(FAR struct usbdev_s *dev, bool selfpowered); +static int rp2040_pullup(FAR struct usbdev_s *dev, bool enable); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Endpoint methods */ + +static const struct usbdev_epops_s g_epops = +{ + .configure = rp2040_epconfigure, + .disable = rp2040_epdisable, + .allocreq = rp2040_epallocreq, + .freereq = rp2040_epfreereq, + .submit = rp2040_epsubmit, + .cancel = rp2040_epcancel, + .stall = rp2040_epstall, +}; + +/* USB controller device methods */ + +static const struct usbdev_ops_s g_devops = +{ + .allocep = rp2040_allocep, + .freeep = rp2040_freeep, + .getframe = rp2040_getframe, + .wakeup = rp2040_wakeup, + .selfpowered = rp2040_selfpowered, + .pullup = rp2040_pullup, +}; + +static struct rp2040_usbdev_s g_usbdev; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rp2040_rqdequeue + * + * Description: + * Remove a request from an endpoint request queue + * + ****************************************************************************/ + +static FAR struct +rp2040_req_s *rp2040_rqdequeue(FAR struct rp2040_ep_s *privep) +{ + FAR struct rp2040_req_s *ret = privep->head; + + if (ret) + { + privep->head = ret->flink; + if (!privep->head) + { + privep->tail = NULL; + } + + ret->flink = NULL; + } + + return ret; +} + +/**************************************************************************** + * Name: rp2040_rqenqueue + * + * Description: + * Add a request from an endpoint request queue + * + ****************************************************************************/ + +static void rp2040_rqenqueue(FAR struct rp2040_ep_s *privep, + FAR struct rp2040_req_s *req) +{ + req->flink = NULL; + if (!privep->head) + { + privep->head = req; + privep->tail = req; + } + else + { + privep->tail->flink = req; + privep->tail = req; + } +} + +/**************************************************************************** + * Name: rp2040_update_buffer_control + * + * Description: + * Update DPSRAM buffer control register + * + ****************************************************************************/ + +static void rp2040_update_buffer_control(FAR struct rp2040_ep_s *privep, + uint32_t and_mask, + uint32_t or_mask) +{ + uint32_t value = 0; + + if (and_mask) + { + value = getreg32(privep->buf_ctrl) & and_mask; + } + + if (or_mask) + { + value |= or_mask; + } + + putreg32(value, privep->buf_ctrl); +} + +/**************************************************************************** + * Name: rp2040_epwrite + * + * Description: + * Endpoint write (IN) + * + ****************************************************************************/ + +static int rp2040_epwrite(FAR struct rp2040_ep_s *privep, FAR uint8_t *buf, + uint16_t nbytes) +{ + uint32_t val; + irqstate_t flags; + + /* Copy the transmit data into DPSRAM */ + + memcpy(privep->data_buf, buf, nbytes); + + val = nbytes | + RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_AVAIL | + RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_FULL | + (privep->next_pid ? + RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA1_PID : 0); + + privep->next_pid = 1 - privep->next_pid; /* Invert DATA0 <-> DATA1 */ + + /* Start the transfer */ + + flags = spin_lock_irqsave(NULL); + rp2040_update_buffer_control(privep, 0, val); + spin_unlock_irqrestore(NULL, flags); + + return nbytes; +} + +/**************************************************************************** + * Name: rp2040_epread + * + * Description: + * Endpoint read (OUT) + * + ****************************************************************************/ + +static int rp2040_epread(FAR struct rp2040_ep_s *privep, uint16_t nbytes) +{ + uint32_t val; + irqstate_t flags; + + val = nbytes | + RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_AVAIL | + (privep->next_pid ? + RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_DATA1_PID : 0); + + privep->next_pid = 1 - privep->next_pid; /* Invert DATA0 <-> DATA1 */ + + /* Start the transfer */ + + flags = spin_lock_irqsave(NULL); + rp2040_update_buffer_control(privep, 0, val); + spin_unlock_irqrestore(NULL, flags); + + return OK; +} + +/**************************************************************************** + * Name: rp2040_abortrequest + * + * Description: + * Discard a request + * + ****************************************************************************/ + +static void rp2040_abortrequest(struct rp2040_ep_s *privep, + struct rp2040_req_s *privreq, + int16_t result) +{ + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_REQABORTED), + (uint16_t)privep->epphy); + + /* Save the result in the request structure */ + + privreq->req.result = result; + + /* Callback to the request completion handler */ + + privreq->req.callback(&privep->ep, &privreq->req); +} + +/**************************************************************************** + * Name: rp2040_reqcomplete + * + * Description: + * Handle termination of a request. + * + ****************************************************************************/ + +static void rp2040_reqcomplete(struct rp2040_ep_s *privep, int16_t result) +{ + FAR struct rp2040_req_s *privreq; + int stalled = privep->stalled; + irqstate_t flags; + + /* Remove the completed request at the head of the endpoint request list */ + + flags = enter_critical_section(); + privreq = rp2040_rqdequeue(privep); + leave_critical_section(flags); + + if (privreq) + { + /* If endpoint 0, temporarily reflect the state of protocol stalled + * in the callback. + */ + + if (privep->epphy == 0) + { + privep->stalled = privep->dev->stalled; + } + + /* Save the result in the request structure */ + + privreq->req.result = result; + + /* Callback to the request completion handler */ + + privreq->flink = NULL; + privreq->req.callback(&privep->ep, &privreq->req); + + /* Restore the stalled indication */ + + privep->stalled = stalled; + } +} + +/**************************************************************************** + * Name: rp2040_txcomplete + * + * Description: + * Transfer is completed. + * + ****************************************************************************/ + +static void rp2040_txcomplete(FAR struct rp2040_ep_s *privep) +{ + FAR struct rp2040_req_s *privreq; + + privreq = rp2040_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_TXREQLOST), privep->epphy); + } + else + { + privreq->req.xfrd += getreg32(privep->buf_ctrl) + & RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LEN_MASK; + + if (privreq->req.xfrd >= privreq->req.len && !privep->txnullpkt) + { + usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); + privep->txnullpkt = 0; + rp2040_reqcomplete(privep, OK); + } + } + + rp2040_wrrequest(privep); +} + +/**************************************************************************** + * Name: rp2040_wrrequest + * + * Description: + * Send from the next queued write request + * + ****************************************************************************/ + +static int rp2040_wrrequest(struct rp2040_ep_s *privep) +{ + FAR struct rp2040_req_s *privreq; + uint8_t *buf; + int nbytes; + int bytesleft; + + /* Check the request from the head of the endpoint request queue */ + + privreq = rp2040_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_NULLREQUEST), 0); + return OK; + } + + /* Ignore any attempt to send a zero length packet on anything but EP0IN */ + + if (privreq->req.len == 0) + { + if (privep->epphy == 0) + { + rp2040_epwrite(privep, NULL, 0); + } + else + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_NULLPACKET), 0); + } + + return OK; + } + + /* Get the number of bytes left to be sent in the packet */ + + bytesleft = privreq->req.len - privreq->req.xfrd; + + /* Send the next packet if (1) there are more bytes to be sent, or + * (2) the last packet sent was exactly maxpacketsize (bytesleft == 0) + */ + + usbtrace(TRACE_WRITE(privep->epphy), (uint16_t)bytesleft); + if (bytesleft > 0 || privep->txnullpkt) + { + /* Try to send maxpacketsize -- unless we don't have that many + * bytes to send. + */ + + privep->txnullpkt = 0; + if (bytesleft > privep->ep.maxpacket) + { + nbytes = privep->ep.maxpacket; + } + else + { + nbytes = bytesleft; + if ((privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0) + { + privep->txnullpkt = (bytesleft == privep->ep.maxpacket); + } + } + + /* Send the largest number of bytes that we can in this packet */ + + buf = privreq->req.buf + privreq->req.xfrd; + rp2040_epwrite(privep, buf, nbytes); + } + + return OK; +} + +/**************************************************************************** + * Name: rp2040_rxcomplete + * + * Description: + * Notify the upper layer and continue to next receive request. + * + ****************************************************************************/ + +static void rp2040_rxcomplete(FAR struct rp2040_ep_s *privep) +{ + FAR struct rp2040_req_s *privreq; + uint16_t nrxbytes; + + nrxbytes = getreg32(privep->buf_ctrl) + & RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LEN_MASK; + + privreq = rp2040_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_RXREQLOST), privep->epphy); + return; + } + + memcpy(privreq->req.buf + privreq->req.xfrd, privep->data_buf, nrxbytes); + + privreq->req.xfrd += nrxbytes; + + if (privreq->req.xfrd >= privreq->req.len || + nrxbytes < privep->ep.maxpacket) + { + usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); + rp2040_reqcomplete(privep, OK); + } + + rp2040_rdrequest(privep); +} + +/**************************************************************************** + * Name: rp2040_rdrequest + * + * Description: + * Receive to the next queued read request + * + ****************************************************************************/ + +static int rp2040_rdrequest(FAR struct rp2040_ep_s *privep) +{ + FAR struct rp2040_req_s *privreq; + + /* Check the request from the head of the endpoint request queue */ + + privreq = rp2040_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_EPOUTQEMPTY), 0); + return OK; + } + + /* Receive the next packet */ + + usbtrace(TRACE_READ(privep->epphy), privreq->req.len); + + return rp2040_epread(privep, privreq->req.len); +} + +/**************************************************************************** + * Name: rp2040_handle_zlp + * + * Description: + * Handle Zero Length Packet to reply to the control transfer + * + ****************************************************************************/ + +static void rp2040_handle_zlp(FAR struct rp2040_usbdev_s *priv) +{ + FAR struct rp2040_ep_s *privep = NULL; + + switch (priv->zlp_stat) + { + case RP2040_ZLP_NONE: + return; + + case RP2040_ZLP_IN_REPLY: + + /* Reply to control IN : receive ZLP from EP0 (0x00) */ + + privep = &priv->eplist[RP2040_EPINDEX(0x00)]; + break; + + case RP2040_ZLP_OUT_REPLY: + + /* Reply to control OUT : send ZLP to EP0 (0x80) */ + + privep = &priv->eplist[RP2040_EPINDEX(0x80)]; + break; + + default: + DEBUGASSERT(0); + } + + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_HANDLEZLP), privep->ep.eplog); + privep->next_pid = 1; /* ZLP is always sent by DATA1 packet */ + + if (priv->zlp_stat == RP2040_ZLP_IN_REPLY) + { + rp2040_epread(privep, 0); + } + else + { + rp2040_epwrite(privep, NULL, 0); + } + + priv->zlp_stat = RP2040_ZLP_NONE; +} + +/**************************************************************************** + * Name: rp2040_cancelrequests + * + * Description: + * Cancel all pending requests for an endpoint + * + ****************************************************************************/ + +static void rp2040_cancelrequests(FAR struct rp2040_ep_s *privep) +{ + while (!rp2040_rqempty(privep)) + { + usbtrace(TRACE_COMPLETE(privep->epphy), + (rp2040_rqpeek(privep))->req.xfrd); + rp2040_reqcomplete(privep, -ESHUTDOWN); + } +} + +/**************************************************************************** + * Name: rp2040_epfindbyaddr + * + * Description: + * Find the physical endpoint structure corresponding to a logic endpoint + * address + * + ****************************************************************************/ + +static FAR struct rp2040_ep_s * +rp2040_epfindbyaddr(FAR struct rp2040_usbdev_s *priv, uint16_t eplog) +{ + return &priv->eplist[RP2040_EPINDEX(eplog)]; +} + +/**************************************************************************** + * Name: rp2040_dispatchrequest + * + * Description: + * Provide unhandled setup actions to the class driver + * + ****************************************************************************/ + +static void rp2040_dispatchrequest(FAR struct rp2040_usbdev_s *priv) +{ + int ret; + + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_DISPATCH), 0); + if (priv && priv->driver) + { + ret = CLASS_SETUP(priv->driver, &priv->usbdev, &priv->ctrl, + priv->ep0data, priv->ep0datlen); + if (ret < 0) + { + /* Stall on failure */ + + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_STALLEDISPATCH), + priv->ctrl.req); + priv->stalled = true; + } + + if (!priv->stalled && USB_REQ_ISOUT(priv->ctrl.type)) + { + priv->zlp_stat = RP2040_ZLP_NONE; /* already sent */ + } + } +} + +/**************************************************************************** + * Name: rp2040_ep0setup + * + * Description: + * USB control EP setup event + * + ****************************************************************************/ + +static void rp2040_ep0setup(FAR struct rp2040_usbdev_s *priv) +{ + FAR struct rp2040_ep_s *ep0 = &priv->eplist[0]; + FAR struct rp2040_ep_s *privep; + uint16_t index; + uint16_t value; + uint16_t len; + + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_INTR_SETUP), 0); + + /* Assume NOT stalled */ + + ep0->stalled = 0; + priv->stalled = 0; + + /* Extract the little-endian 16-bit values to host order */ + + index = GETUINT16(priv->ctrl.index); + value = GETUINT16(priv->ctrl.value); + len = GETUINT16(priv->ctrl.len); + + uinfo("type=%02x req=%02x value=%04x index=%04x len=%04x\n", + priv->ctrl.type, priv->ctrl.req, value, index, len); + + /* Dispatch any non-standard requests */ + + if ((priv->ctrl.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) + { + rp2040_dispatchrequest(priv); + } + else + { + /* Handle standard request. Pick off the things of interest to the + * USB device controller driver; pass what is left to the class driver + */ + + switch (priv->ctrl.req) + { + case USB_REQ_GETSTATUS: + { + /* type: device-to-host; + * recipient = device, + * interface, + * endpoint + * value: 0 + * index: zero interface endpoint + * len: 2; data = status + */ + + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_GETSTATUS), + priv->ctrl.req); + + if (len != 2 || (priv->ctrl.type & USB_REQ_DIR_IN) == 0 || + value != 0) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_STALLEDGETST), + priv->ctrl.req); + priv->stalled = true; + } + else + { + switch (priv->ctrl.type & USB_REQ_RECIPIENT_MASK) + { + case USB_REQ_RECIPIENT_ENDPOINT: + { + usbtrace(TRACE_INTDECODE( + RP2040_TRACEINTID_GETENDPOINT), + 0); + privep = rp2040_epfindbyaddr(priv, index); + if (!privep) + { + usbtrace( + TRACE_DEVERROR( + RP2040_TRACEERR_STALLEDGETSTEP), + priv->ctrl.type); + priv->stalled = true; + } + } + break; + + case USB_REQ_RECIPIENT_DEVICE: + case USB_REQ_RECIPIENT_INTERFACE: + usbtrace(TRACE_INTDECODE( + RP2040_TRACEINTID_GETIFDEV), + 0); + break; + + default: + { + usbtrace(TRACE_DEVERROR( + RP2040_TRACEERR_STALLEDGETSTRECIP), + priv->ctrl.type); + priv->stalled = true; + } + break; + } + } + } + break; + + case USB_REQ_CLEARFEATURE: + { + /* type: host-to device; + * recipient = device, + * interface or endpoint + * value: feature selector + * index: zero interface endpoint; + * len: zero, data = none + */ + + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_CLEARFEATURE), + (uint16_t)priv->ctrl.req); + if ((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) != + USB_REQ_RECIPIENT_ENDPOINT) + { + rp2040_dispatchrequest(priv); + } + else if (value == USB_FEATURE_ENDPOINTHALT && + len == 0 && + (privep = rp2040_epfindbyaddr(priv, index)) != NULL) + { + rp2040_epstall(&privep->ep, true); + rp2040_epwrite(ep0, NULL, 0); + } + else + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_STALLEDCLRFEATURE), + priv->ctrl.type); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETFEATURE: + { + /* type: host-to-device; + * recipient = device, + * interface, + * endpoint + * value: feature selector + * index: zero interface endpoint; + * len: 0; data = none + */ + + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_SETFEATURE), + priv->ctrl.req); + if (priv->ctrl.type == USB_REQ_RECIPIENT_DEVICE && + value == USB_FEATURE_TESTMODE) + { + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_TESTMODE), + index); + } + else if (priv->ctrl.type != USB_REQ_RECIPIENT_ENDPOINT) + { + rp2040_dispatchrequest(priv); + } + else if (value == USB_FEATURE_ENDPOINTHALT && len == 0 && + (privep = rp2040_epfindbyaddr(priv, index)) != NULL) + { + rp2040_epstall(&privep->ep, true); + rp2040_epwrite(ep0, NULL, 0); + } + else + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_STALLEDSETFEATURE), + priv->ctrl.type); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETADDRESS: + { + /* type: host-to-device; recipient = device + * value: device address + * index: 0 + * len: 0; data = none + */ + + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_SETADDRESS), value); + priv->dev_addr = value & 0xff; + } + break; + + case USB_REQ_GETDESCRIPTOR: + /* type: device-to-host; recipient = device + * value: descriptor type and index + * index: 0 or language ID; + * len: descriptor len; data = descriptor + */ + + case USB_REQ_SETDESCRIPTOR: + /* type: host-to-device; recipient = device + * value: descriptor type and index + * index: 0 or language ID; + * len: descriptor len; data = descriptor + */ + + { + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_GETSETDESC), + priv->ctrl.req); + rp2040_dispatchrequest(priv); + } + break; + + case USB_REQ_GETCONFIGURATION: + /* type: device-to-host; recipient = device + * value: 0; + * index: 0; + * len: 1; data = configuration value + */ + + case USB_REQ_SETCONFIGURATION: + /* type: host-to-device; recipient = device + * value: configuration value + * index: 0; + * len: 0; data = none + */ + + case USB_REQ_GETINTERFACE: + /* type: device-to-host; recipient = interface + * value: 0 + * index: interface; + * len: 1; data = alt interface + */ + + case USB_REQ_SETINTERFACE: + /* type: host-to-device; recipient = interface + * value: alternate setting + * index: interface; + * len: 0; data = none + */ + + { + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_GETSETIFCONFIG), + priv->ctrl.req); + rp2040_dispatchrequest(priv); + } + break; + + case USB_REQ_SYNCHFRAME: + /* type: device-to-host; recipient = endpoint + * value: 0 + * index: endpoint; + * len: 2; data = frame number + */ + + { + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_SYNCHFRAME), 0); + break; + } + + default: + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_STALLEDREQUEST), + priv->ctrl.req); + priv->stalled = true; + } + break; + } + } + + /* Check if the setup processing resulted in a STALL */ + + if (priv->stalled) + { + rp2040_epstall(&priv->eplist[0].ep, false); + rp2040_epstall(&priv->eplist[1].ep, false); + } + else if (priv->zlp_stat != RP2040_ZLP_NONE) + { + rp2040_handle_zlp(priv); + } +} + +/**************************************************************************** + * Name: rp2040_usbintr_setup + * + * Description: + * Handle USB SETUP_REQ interrupt + * + ****************************************************************************/ + +static void rp2040_usbintr_setup(FAR struct rp2040_usbdev_s *priv) +{ + uint16_t len; + + /* Read USB control request data */ + + memcpy(&priv->ctrl, (void *)RP2040_USBCTRL_DPSRAM_SETUP_PACKET, + USB_SIZEOF_CTRLREQ); + len = GETUINT16(priv->ctrl.len); + + /* Reset PID and stall status in setup stage */ + + priv->eplist[0].next_pid = 1; + priv->eplist[1].next_pid = 1; + priv->eplist[0].stalled = false; + priv->eplist[1].stalled = false; + + /* ZLP type in status stage */ + + priv->zlp_stat = USB_REQ_ISIN(priv->ctrl.type) ? RP2040_ZLP_IN_REPLY : + RP2040_ZLP_OUT_REPLY; + + if (USB_REQ_ISOUT(priv->ctrl.type) && len != priv->ep0datlen) + { + /* Receive the subsequent OUT data for the setup */ + + priv->ep0reqlen = len; + rp2040_epread(&priv->eplist[RP2040_EPINDEX(0x00)], len); + } + else + { + /* Start the setup */ + + priv->ep0reqlen = 0; + rp2040_ep0setup(priv); + } +} + +/**************************************************************************** + * Name: rp2040_usbintr_ep0out + * + * Description: + * Handle the end of EP0OUT data transfer + * + ****************************************************************************/ + +static void rp2040_usbintr_ep0out(FAR struct rp2040_usbdev_s *priv, + FAR struct rp2040_ep_s *privep) +{ + int len; + + len = getreg32(privep->buf_ctrl) + & RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_LEN_MASK; + + if (len == 0) + { + privep->next_pid = 1; + priv->ep0datlen = 0; + return; + } + + memcpy(priv->ep0data + priv->ep0datlen, privep->data_buf, len); + priv->ep0datlen += len; + + if (priv->ep0datlen == priv->ep0reqlen) + { + priv->zlp_stat = RP2040_ZLP_NONE; + rp2040_ep0setup(priv); + priv->ep0datlen = 0; + } + else + { + rp2040_epread(privep, RP2040_EP0MAXPACKET); + } +} + +/**************************************************************************** + * Name: rp2040_usbintr_buffstat + * + * Description: + * Handle USB BUFF_STATUS interrupt + * + ****************************************************************************/ + +static bool rp2040_usbintr_buffstat(FAR struct rp2040_usbdev_s *priv) +{ + uint32_t stat = getreg32(RP2040_USBCTRL_REGS_BUFF_STATUS); + uint32_t bit; + int i; + FAR struct rp2040_ep_s *privep; + + if (stat == 0) + { + return false; + } + + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_INTR_BUFFSTAT), stat & 0xffff); + + bit = 1; + for (i = 0; i < 32 && stat != 0; i++) + { + if (stat & bit) + { + clrbits_reg32(bit, RP2040_USBCTRL_REGS_BUFF_STATUS); + privep = &priv->eplist[RP2040_DPTOEP(i)]; + + if (i == 1) + { + rp2040_usbintr_ep0out(priv, privep); + } + else + { + if (i == 0 && priv->dev_addr != 0) + { + putreg32(priv->dev_addr, RP2040_USBCTRL_REGS_ADDR_ENDP); + priv->dev_addr = 0; + } + + if (privep->in) + { + if (!rp2040_rqempty(privep)) + { + rp2040_txcomplete(privep); + } + else if (privep->pending_stall) + { + rp2040_epstall_exec(&privep->ep); + } + } + else + { + rp2040_rxcomplete(privep); + } + } + + stat &= ~bit; + } + + bit <<= 1; + } + + return true; +} + +/**************************************************************************** + * Name: rp2040_usbintr_busreset + * + * Description: + * Handle USB BUS_RESET interrupt + * + ****************************************************************************/ + +static void rp2040_usbintr_busreset(FAR struct rp2040_usbdev_s *priv) +{ + int i; + + usbtrace(TRACE_INTDECODE(RP2040_TRACEINTID_INTR_BUSRESET), 0); + + putreg32(0, RP2040_USBCTRL_REGS_ADDR_ENDP); + priv->dev_addr = 0; + priv->zlp_stat = RP2040_ZLP_NONE; + priv->next_offset = RP2040_USBCTRL_DPSRAM_DATA_BUF_OFFSET; + + for (i = 0; i < RP2040_NENDPOINTS; i++) + { + FAR struct rp2040_ep_s *privep = &g_usbdev.eplist[i]; + + rp2040_cancelrequests(privep); + } + + rp2040_pullup(&g_usbdev.usbdev, false); + if (g_usbdev.driver) + { + CLASS_DISCONNECT(priv->driver, &priv->usbdev); + } + + clrbits_reg32(RP2040_USBCTRL_REGS_SIE_STATUS_BUS_RESET, + RP2040_USBCTRL_REGS_SIE_STATUS); +} + +/**************************************************************************** + * Name: rp2040_usbinterrupt + * + * Description: + * USB interrupt handler + * + ****************************************************************************/ + +static int rp2040_usbinterrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct rp2040_usbdev_s *priv = (FAR struct rp2040_usbdev_s *)arg; + uint32_t stat; + + stat = getreg32(RP2040_USBCTRL_REGS_INTS); + + usbtrace(TRACE_INTENTRY(RP2040_TRACEINTID_USBINTERRUPT), 0); + + if (stat & RP2040_USBCTRL_REGS_INTR_BUFF_STATUS) + { + while (rp2040_usbintr_buffstat(priv)) + ; + } + + if (stat & RP2040_USBCTRL_REGS_INTR_SETUP_REQ) + { + clrbits_reg32(RP2040_USBCTRL_REGS_SIE_STATUS_SETUP_REC, + RP2040_USBCTRL_REGS_SIE_STATUS); + + rp2040_usbintr_setup(priv); + } + + if (stat & RP2040_USBCTRL_REGS_INTR_BUS_RESET) + { + clrbits_reg32(RP2040_USBCTRL_REGS_SIE_STATUS_BUS_RESET, + RP2040_USBCTRL_REGS_SIE_STATUS); + + rp2040_usbintr_busreset(priv); + } + + usbtrace(TRACE_INTEXIT(RP2040_TRACEINTID_USBINTERRUPT), 0); + + return OK; +} + +/**************************************************************************** + * Endpoint Methods + ****************************************************************************/ + +/**************************************************************************** + * Name: rp2040_epconfigure + * + * Description: + * Configure endpoint, making it usable + * + * Input Parameters: + * ep - the struct usbdev_ep_s instance obtained from allocep() + * desc - A struct usb_epdesc_s instance describing the endpoint + * last - true if this is the last endpoint to be configured. Some + * hardware needs to take special action when all of the endpoints + * have been configured. + * + ****************************************************************************/ + +static int rp2040_epconfigure(FAR struct usbdev_ep_s *ep, + FAR const struct usb_epdesc_s *desc, bool last) +{ + FAR struct rp2040_ep_s *privep = (FAR struct rp2040_ep_s *)ep; + FAR struct rp2040_usbdev_s *priv = privep->dev; + int eptype; + uint16_t maxpacket; + + usbtrace(TRACE_EPCONFIGURE, privep->epphy); + DEBUGASSERT(desc->addr == ep->eplog); + + eptype = desc->attr & USB_EP_ATTR_XFERTYPE_MASK; + maxpacket = GETUINT16(desc->mxpacketsize); + + uinfo("config: EP%d %s %d maxpacket=%d\n", privep->epphy, + privep->in ? "IN" : "OUT", eptype, maxpacket); + + if (desc) + { + privep->ep.maxpacket = GETUINT16(desc->mxpacketsize); + } + + if (privep->epphy != 0) + { + /* Configure the EP data buffer address + * (No need for EP0 because it has the dedicated buffer) + */ + + privep->data_buf = (uint8_t *)(RP2040_USBCTRL_DPSRAM_BASE + + priv->next_offset); + priv->next_offset = + (priv->next_offset + privep->ep.maxpacket + 63) & ~63; + + /* Enable EP */ + + putreg32(RP2040_USBCTRL_DPSRAM_EP_CTRL_ENABLE | + RP2040_USBCTRL_DPSRAM_EP_CTRL_INT_1BUF | + (eptype << RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_TYPE_SHIFT) | + ((uint32_t)privep->data_buf & + RP2040_USBCTRL_DPSRAM_EP_CTRL_EP_ADDR_MASK), + privep->ep_ctrl); + } + + return OK; +} + +/**************************************************************************** + * Name: rp2040_epdisable + * + * Description: + * The endpoint will no longer be used + * + ****************************************************************************/ + +static int rp2040_epdisable(FAR struct usbdev_ep_s *ep) +{ + FAR struct rp2040_ep_s *privep = (FAR struct rp2040_ep_s *)ep; + irqstate_t flags; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPDISABLE, privep->epphy); + uinfo("EP%d\n", privep->epphy); + + flags = enter_critical_section(); + + privep->ep.maxpacket = 64; + privep->stalled = false; + privep->next_pid = 0; + putreg32(0, privep->buf_ctrl); + + /* Cancel all queued requests */ + + rp2040_cancelrequests(privep); + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: rp2040_epallocreq + * + * Description: + * Allocate an I/O request + * + ****************************************************************************/ + +static FAR struct usbdev_req_s *rp2040_epallocreq(FAR struct usbdev_ep_s *ep) +{ + FAR struct rp2040_req_s *privreq; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep) + { + return NULL; + } +#endif + + usbtrace(TRACE_EPALLOCREQ, ((FAR struct rp2040_ep_s *)ep)->epphy); + + privreq = (FAR struct rp2040_req_s *) + kmm_malloc(sizeof(struct rp2040_req_s)); + + if (!privreq) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_ALLOCFAIL), 0); + return NULL; + } + + memset(privreq, 0, sizeof(struct rp2040_req_s)); + return &privreq->req; +} + +/**************************************************************************** + * Name: rp2040_epfreereq + * + * Description: + * Free an I/O request + * + ****************************************************************************/ + +static void rp2040_epfreereq(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req) +{ + FAR struct rp2040_req_s *privreq = (FAR struct rp2040_req_s *)req; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_INVALIDPARMS), 0); + return; + } +#endif + + usbtrace(TRACE_EPFREEREQ, ((FAR struct rp2040_ep_s *)ep)->epphy); + kmm_free(privreq); +} + +/**************************************************************************** + * Name: rp2040_epsubmit + * + * Description: + * Submit an I/O request to the endpoint + * + ****************************************************************************/ + +static int rp2040_epsubmit(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req) +{ + FAR struct rp2040_req_s *privreq = (FAR struct rp2040_req_s *)req; + FAR struct rp2040_ep_s *privep = (FAR struct rp2040_ep_s *)ep; + irqstate_t flags; + int ret = OK; + +#ifdef CONFIG_DEBUG_FEATURES + if (!req || !req->callback || !req->buf || !ep) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPSUBMIT, privep->ep.eplog); + + req->result = -EINPROGRESS; + req->xfrd = 0; + + flags = enter_critical_section(); + + if (privep->stalled && privep->in) + { + rp2040_abortrequest(privep, privreq, -EBUSY); + ret = -EBUSY; + } + + /* Handle IN (device-to-host) requests */ + + else if (privep->in) + { + /* Add the new request to the request queue for the IN endpoint */ + + bool empty = rp2040_rqempty(privep); + + rp2040_rqenqueue(privep, privreq); + usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len); + + if (empty) + { + rp2040_wrrequest(privep); + } + } + + /* Handle OUT (host-to-device) requests */ + + else + { + /* Add the new request to the request queue for the OUT endpoint */ + + bool empty = rp2040_rqempty(privep); + + privep->txnullpkt = 0; + rp2040_rqenqueue(privep, privreq); + usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len); + + /* This there a incoming data pending the availability of a request? */ + + if (empty) + { + ret = rp2040_rdrequest(privep); + } + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: rp2040_epcancel + * + * Description: + * Cancel an I/O request previously sent to an endpoint + * + ****************************************************************************/ + +static int rp2040_epcancel(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req) +{ + FAR struct rp2040_ep_s *privep = (FAR struct rp2040_ep_s *)ep; + irqstate_t flags; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPCANCEL, privep->epphy); + + /* Remove request from req_queue */ + + flags = enter_critical_section(); + rp2040_cancelrequests(privep); + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: rp2040_epstall_exec + * + * Description: + * Stall endpoint immediately + * + ****************************************************************************/ + +static int rp2040_epstall_exec(FAR struct usbdev_ep_s *ep) +{ + FAR struct rp2040_ep_s *privep = (FAR struct rp2040_ep_s *)ep; + irqstate_t flags; + + usbtrace(TRACE_EPSTALL, privep->epphy); + + flags = spin_lock_irqsave(NULL); + + if (privep->epphy == 0) + { + setbits_reg32(privep->in ? + RP2040_USBCTRL_REGS_EP_STALL_ARM_EP0_IN : + RP2040_USBCTRL_REGS_EP_STALL_ARM_EP0_OUT, + RP2040_USBCTRL_REGS_EP_STALL_ARM); + } + + rp2040_update_buffer_control(privep, + 0, + RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_STALL); + + privep->pending_stall = false; + + spin_unlock_irqrestore(NULL, flags); + return OK; +} + +/**************************************************************************** + * Name: rp2040_epstall + * + * Description: + * Stall or resume and endpoint + * + ****************************************************************************/ + +static int rp2040_epstall(FAR struct usbdev_ep_s *ep, bool resume) +{ + FAR struct rp2040_ep_s *privep = (FAR struct rp2040_ep_s *)ep; + FAR struct rp2040_usbdev_s *priv = privep->dev; + irqstate_t flags; + + flags = spin_lock_irqsave(NULL); + + if (resume) + { + usbtrace(TRACE_EPRESUME, privep->epphy); + privep->stalled = false; + if (privep->epphy == 0) + { + clrbits_reg32(privep->in ? + RP2040_USBCTRL_REGS_EP_STALL_ARM_EP0_IN : + RP2040_USBCTRL_REGS_EP_STALL_ARM_EP0_OUT, + RP2040_USBCTRL_REGS_EP_STALL_ARM); + } + + rp2040_update_buffer_control(privep, + ~(RP2040_USBCTRL_DPSRAM_EP_BUFF_CTRL_STALL), + 0); + + privep->next_pid = 0; + priv->zlp_stat = RP2040_ZLP_NONE; + } + else + { + privep->stalled = true; + + if (privep->epphy == 0 && !rp2040_rqempty(privep)) + { + /* EP0 IN Transfer ongoing : postpone the stall until the end */ + + privep->pending_stall = true; + } + else + { + /* Stall immediately */ + + rp2040_epstall_exec(ep); + } + + priv->zlp_stat = RP2040_ZLP_NONE; + } + + spin_unlock_irqrestore(NULL, flags); + + return OK; +} + +/**************************************************************************** + * Device Methods + ****************************************************************************/ + +/**************************************************************************** + * Name: rp2040_allocep + * + * Description: + * Allocate an endpoint matching the parameters + * + * Input Parameters: + * eplog - 7-bit logical endpoint number (direction bit ignored). + * Zero means that any endpoint matching the other requirements + * will suffice. The assigned endpoint can be found in the eplog + * field. + * in - true: IN (device-to-host) endpoint requested + * eptype - Endpoint type. + * One of {USB_EP_ATTR_XFER_ISOC, + * USB_EP_ATTR_XFER_BULK, + * USB_EP_ATTR_XFER_INT} + * + ****************************************************************************/ + +static FAR struct usbdev_ep_s *rp2040_allocep(FAR struct usbdev_s *dev, + uint8_t eplog, bool in, + uint8_t eptype) +{ + struct rp2040_usbdev_s *priv = (FAR struct rp2040_usbdev_s *)dev; + struct rp2040_ep_s *privep; + int epphy; + int epindex; + int dpindex; + + usbtrace(TRACE_DEVALLOCEP, (uint16_t)eplog); + + /* Ignore any direction bits in the logical address */ + + epphy = USB_EPNO(eplog); + epindex = RP2040_EPINDEX(eplog); + dpindex = RP2040_DPINDEX(eplog); + + if ((priv->used & 1 << epphy) && (epphy != 0)) + { + uinfo("ep is still used\n"); + return NULL; + } + + priv->used |= 1 << epphy; + + privep = &priv->eplist[epindex]; + privep->in = in; + privep->type = eptype; + privep->epphy = epphy; + privep->ep.eplog = eplog; + + privep->next_pid = 0; + privep->stalled = false; + privep->buf_ctrl = RP2040_USBCTRL_DPSRAM_EP_BUF_CTRL(dpindex); + + if (epphy == 0) + { + privep->data_buf = (uint8_t *)RP2040_USBCTRL_DPSRAM_EP0_BUF_0; + privep->ep_ctrl = 0; + } + else + { + privep->ep_ctrl = RP2040_USBCTRL_DPSRAM_EP_CTRL(dpindex); + } + + return &privep->ep; +} + +/**************************************************************************** + * Name: rp2040_freeep + * + * Description: + * Free the previously allocated endpoint + * + ****************************************************************************/ + +static void rp2040_freeep(FAR struct usbdev_s *dev, + FAR struct usbdev_ep_s *ep) +{ + FAR struct rp2040_usbdev_s *priv = (FAR struct rp2040_usbdev_s *)dev; + FAR struct rp2040_ep_s *privep = (FAR struct rp2040_ep_s *)ep; + + usbtrace(TRACE_DEVFREEEP, (uint16_t)privep->epphy); + + priv->used &= ~(1 << privep->epphy); +} + +/**************************************************************************** + * Name: rp2040_getframe + * + * Description: + * Returns the current frame number + * + ****************************************************************************/ + +static int rp2040_getframe(FAR struct usbdev_s *dev) +{ + usbtrace(TRACE_DEVGETFRAME, 0); + +#ifdef CONFIG_DEBUG_FEATURES + if (!dev) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_INVALIDPARMS), 0); + return -ENODEV; + } +#endif + + return (int)(getreg32(RP2040_USBCTRL_REGS_SOF_RD) & + RP2040_USBCTRL_REGS_SOF_RD_COUNT_MASK); +} + +/**************************************************************************** + * Name: rp2040_wakeup + * + * Description: + * Tries to wake up the host connected to this device + * + ****************************************************************************/ + +static int rp2040_wakeup(FAR struct usbdev_s *dev) +{ + usbtrace(TRACE_DEVWAKEUP, 0); + + setbits_reg32(RP2040_USBCTRL_REGS_SIE_CTRL_RESUME, + RP2040_USBCTRL_REGS_SIE_CTRL); + + return OK; +} + +/**************************************************************************** + * Name: rp2040_selfpowered + * + * Description: + * Sets/clears the device selfpowered feature + * + ****************************************************************************/ + +static int rp2040_selfpowered(FAR struct usbdev_s *dev, bool selfpowered) +{ + FAR struct rp2040_usbdev_s *priv = (FAR struct rp2040_usbdev_s *)dev; + + usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered); + +#ifdef CONFIG_DEBUG_FEATURES + if (!dev) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_INVALIDPARMS), 0); + return -ENODEV; + } +#endif + + priv->selfpowered = selfpowered; + return OK; +} + +/**************************************************************************** + * Name: rp2040_pullup + * + * Description: + * Software-controlled connect to/disconnect from USB host + * + ****************************************************************************/ + +static int rp2040_pullup(FAR struct usbdev_s *dev, bool enable) +{ + usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); + + if (enable) + { + setbits_reg32(RP2040_USBCTRL_REGS_SIE_CTRL_PULLUP_EN, + RP2040_USBCTRL_REGS_SIE_CTRL); + } + else + { + clrbits_reg32(RP2040_USBCTRL_REGS_SIE_CTRL_PULLUP_EN, + RP2040_USBCTRL_REGS_SIE_CTRL); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_usbinitialize + * + * Description: + * Initialize the USB driver + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void arm_usbinitialize(void) +{ + int i; + + usbtrace(TRACE_DEVINIT, 0); + + putreg32(0, RP2040_USBCTRL_REGS_ADDR_ENDP); + + /* Initialize driver instance */ + + memset(&g_usbdev, 0, sizeof(struct rp2040_usbdev_s)); + + g_usbdev.usbdev.ops = &g_devops; + g_usbdev.usbdev.ep0 = &g_usbdev.eplist[0].ep; + + g_usbdev.dev_addr = 0; + g_usbdev.next_offset = RP2040_USBCTRL_DPSRAM_DATA_BUF_OFFSET; + + for (i = 0; i < RP2040_NENDPOINTS; i++) + { + g_usbdev.eplist[i].ep.ops = &g_epops; + g_usbdev.eplist[i].ep.maxpacket = 64; + g_usbdev.eplist[i].dev = &g_usbdev; + g_usbdev.eplist[i].epphy = 0; + g_usbdev.eplist[i].head = NULL; + g_usbdev.eplist[i].tail = NULL; + g_usbdev.eplist[i].ep.eplog = 0; + } + + if (irq_attach(RP2040_USBCTRL_IRQ, rp2040_usbinterrupt, &g_usbdev) != 0) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_IRQREGISTRATION), + (uint16_t)RP2040_USBCTRL_IRQ); + return; + } +} + +/**************************************************************************** + * Name: usbdev_register + * + * Description: + * Register a USB device class driver. The class driver's bind() method + * will be called to bind it to a USB device driver. + * + ****************************************************************************/ + +int usbdev_register(FAR struct usbdevclass_driver_s *driver) +{ + int ret = -1; + + usbtrace(TRACE_DEVREGISTER, 0); + +#ifdef CONFIG_DEBUG_FEATURES + if (!driver || !driver->ops->bind || !driver->ops->unbind || + !driver->ops->setup) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } + + if (g_usbdev.driver) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_DRIVER), 0); + return -EBUSY; + } +#endif + + /* Hook up the driver */ + + g_usbdev.driver = driver; + + setbits_reg32(RP2040_RESETS_RESET_USBCTRL, RP2040_RESETS_RESET); + clrbits_reg32(RP2040_RESETS_RESET_USBCTRL, RP2040_RESETS_RESET); + + memset((void *)RP2040_USBCTRL_DPSRAM_BASE, 0, 0x1000); + + putreg32(RP2040_USBCTRL_REGS_USB_MUXING_SOFTCON | + RP2040_USBCTRL_REGS_USB_MUXING_TO_PHY, + RP2040_USBCTRL_REGS_USB_MUXING); + putreg32(RP2040_USBCTRL_REGS_USB_PWR_VBUS_DETECT | + RP2040_USBCTRL_REGS_USB_PWR_VBUS_DETECT_OVERRIDE_EN, + RP2040_USBCTRL_REGS_USB_PWR); + + rp2040_allocep(&g_usbdev.usbdev, 0x00, 0, USB_EP_ATTR_XFER_CONTROL); + rp2040_allocep(&g_usbdev.usbdev, 0x80, 1, USB_EP_ATTR_XFER_CONTROL); + + /* Then bind the class driver */ + + ret = CLASS_BIND(driver, &g_usbdev.usbdev); + if (ret) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_BINDFAILED), (uint16_t)-ret); + g_usbdev.driver = NULL; + return ret; + } + + g_usbdev.usbdev.speed = USB_SPEED_FULL; + + putreg32(RP2040_USBCTRL_REGS_MAIN_CTRL_CONTROLLER_EN, + RP2040_USBCTRL_REGS_MAIN_CTRL); + + /* Enable interrupt */ + + putreg32(RP2040_USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF, + RP2040_USBCTRL_REGS_SIE_CTRL); + putreg32(RP2040_USBCTRL_REGS_INTR_BUFF_STATUS | + RP2040_USBCTRL_REGS_INTR_BUS_RESET | + RP2040_USBCTRL_REGS_INTR_SETUP_REQ, + RP2040_USBCTRL_REGS_INTE); + + up_enable_irq(RP2040_USBCTRL_IRQ); + + return OK; +} + +/**************************************************************************** + * Name: usbdev_unregister + * + * Description: + * Un-register usbdev class driver. If the USB device is connected to a + * USB host, it will first disconnect(). The driver is also requested to + * unbind() and clean up any device state, before this procedure finally + * returns. + * + ****************************************************************************/ + +int usbdev_unregister(FAR struct usbdevclass_driver_s *driver) +{ + FAR struct rp2040_usbdev_s *priv = &g_usbdev; + irqstate_t flags; + +#ifdef CONFIG_DEBUG_FEATURES + if (driver != priv->driver) + { + usbtrace(TRACE_DEVERROR(RP2040_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + usbtrace(TRACE_DEVUNREGISTER, 0); + + flags = spin_lock_irqsave(NULL); + + /* Unbind the class driver */ + + CLASS_UNBIND(driver, &priv->usbdev); + + /* Disable interrupts */ + + up_disable_irq(RP2040_USBCTRL_IRQ); + + /* Disconnect device */ + + rp2040_pullup(&priv->usbdev, false); + + /* Unhook the driver */ + + priv->driver = NULL; + + spin_unlock_irqrestore(NULL, flags); + + return OK; +} diff --git a/arch/arm/src/rp2040/rp2040_usbdev.h b/arch/arm/src/rp2040/rp2040_usbdev.h new file mode 100644 index 00000000000..601a7626b6c --- /dev/null +++ b/arch/arm/src/rp2040/rp2040_usbdev.h @@ -0,0 +1,59 @@ +/**************************************************************************** + * arch/arm/src/rp2040/rp2040_usbdev.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_RP2040_RP2040_USBDEV_H +#define __ARCH_ARM_SRC_RP2040_RP2040_USBDEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "hardware/rp2040_usbctrl_regs.h" +#include "hardware/rp2040_usbctrl_dpsram.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_RP2040_RP2040_USBDEV_H */