Skip to content

machine/rp2: merge common usb code #4856

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 2 additions & 231 deletions src/machine/machine_rp2040_usb.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@ import (
"device/rp"
"machine/usb"
"runtime/interrupt"
"runtime/volatile"
"unsafe"
)

var (
sendOnEP0DATADONE struct {
offset int
data []byte
pid uint32
}
)

// Configure the USB peripheral. The config is here for compatibility with the UART interface.
Expand Down Expand Up @@ -134,40 +124,6 @@ func handleUSBIRQ(intr interrupt.Interrupt) {
}
}

func initEndpoint(ep, config uint32) {
val := uint32(usbEpControlEnable) | uint32(usbEpControlInterruptPerBuff)
offset := ep*2*usbBufferLen + 0x100
val |= offset

switch config {
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn:
val |= usbEpControlEndpointTypeInterrupt
_usbDPSRAM.EPxControl[ep].In.Set(val)

case usb.ENDPOINT_TYPE_BULK | usb.EndpointOut:
val |= usbEpControlEndpointTypeBulk
_usbDPSRAM.EPxControl[ep].Out.Set(val)
_usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask)
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)

case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut:
val |= usbEpControlEndpointTypeInterrupt
_usbDPSRAM.EPxControl[ep].Out.Set(val)
_usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask)
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)

case usb.ENDPOINT_TYPE_BULK | usb.EndpointIn:
val |= usbEpControlEndpointTypeBulk
_usbDPSRAM.EPxControl[ep].In.Set(val)

case usb.ENDPOINT_TYPE_CONTROL:
val |= usbEpControlEndpointTypeControl
_usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBuf0CtrlData1Pid)
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)

}
}

func handleUSBSetAddress(setup usb.Setup) bool {
// Using 570μs timeout which is exactly the same as SAMD21.
const ackTimeout = 570
Expand All @@ -188,191 +144,6 @@ func handleUSBSetAddress(setup usb.Setup) bool {
return true
}

// SendUSBInPacket sends a packet for USB (interrupt in / bulk in).
func SendUSBInPacket(ep uint32, data []byte) bool {
sendUSBPacket(ep, data, 0)
return true
}

//go:noinline
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
count := len(data)
if 0 < int(maxsize) && int(maxsize) < count {
count = int(maxsize)
}

if ep == 0 {
if count > usb.EndpointPacketSize {
count = usb.EndpointPacketSize

sendOnEP0DATADONE.offset = count
sendOnEP0DATADONE.data = data
} else {
sendOnEP0DATADONE.offset = 0
}
epXdata0[ep] = true
}

sendViaEPIn(ep, data, count)
}

func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
var b [cdcLineInfoSize]byte
ep := 0

for !_usbDPSRAM.EPxBufferControl[ep].Out.HasBits(usbBuf0CtrlFull) {
// TODO: timeout
}

ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get()
_usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask)
sz := ctrl & usbBuf0CtrlLenMask

copy(b[:], _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz])

_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid)
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)

return b, nil
}

func handleEndpointRx(ep uint32) []byte {
ctrl := _usbDPSRAM.EPxBufferControl[ep].Out.Get()
_usbDPSRAM.EPxBufferControl[ep].Out.Set(usbBufferLen & usbBuf0CtrlLenMask)
sz := ctrl & usbBuf0CtrlLenMask

return _usbDPSRAM.EPxBuffer[ep].Buffer0[:sz]
}

func handleEndpointRxComplete(ep uint32) {
epXdata0[ep] = !epXdata0[ep]
if epXdata0[ep] || ep == 0 {
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid)
}

_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlAvail)
func armEPZeroStall() {
rp.USBCTRL_REGS.EP_STALL_ARM.Set(rp.USBCTRL_REGS_EP_STALL_ARM_EP0_IN)
}

func SendZlp() {
sendUSBPacket(0, []byte{}, 0)
}

func sendViaEPIn(ep uint32, data []byte, count int) {
// Prepare buffer control register value
val := uint32(count) | usbBuf0CtrlAvail

// DATA0 or DATA1
epXdata0[ep&0x7F] = !epXdata0[ep&0x7F]
if !epXdata0[ep&0x7F] {
val |= usbBuf0CtrlData1Pid
}

// Mark as full
val |= usbBuf0CtrlFull

copy(_usbDPSRAM.EPxBuffer[ep&0x7F].Buffer0[:], data[:count])
_usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val)
}

func sendStallViaEPIn(ep uint32) {
// Prepare buffer control register value
if ep == 0 {
rp.USBCTRL_REGS.EP_STALL_ARM.Set(rp.USBCTRL_REGS_EP_STALL_ARM_EP0_IN)
}
val := uint32(usbBuf0CtrlFull)
_usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val)
val |= uint32(usbBuf0CtrlStall)
_usbDPSRAM.EPxBufferControl[ep&0x7F].In.Set(val)
}

type usbDPSRAM struct {
// Note that EPxControl[0] is not EP0Control but 8-byte setup data.
EPxControl [16]usbEndpointControlRegister

EPxBufferControl [16]usbBufferControlRegister

EPxBuffer [16]usbBuffer
}

type usbEndpointControlRegister struct {
In volatile.Register32
Out volatile.Register32
}
type usbBufferControlRegister struct {
In volatile.Register32
Out volatile.Register32
}

type usbBuffer struct {
Buffer0 [usbBufferLen]byte
Buffer1 [usbBufferLen]byte
}

var (
_usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000)))
epXdata0 [16]bool
setupBytes [8]byte
)

func (d *usbDPSRAM) setupBytes() []byte {

data := d.EPxControl[usb.CONTROL_ENDPOINT].In.Get()
setupBytes[0] = byte(data)
setupBytes[1] = byte(data >> 8)
setupBytes[2] = byte(data >> 16)
setupBytes[3] = byte(data >> 24)

data = d.EPxControl[usb.CONTROL_ENDPOINT].Out.Get()
setupBytes[4] = byte(data)
setupBytes[5] = byte(data >> 8)
setupBytes[6] = byte(data >> 16)
setupBytes[7] = byte(data >> 24)

return setupBytes[:]
}

func (d *usbDPSRAM) clear() {
for i := 0; i < len(d.EPxControl); i++ {
d.EPxControl[i].In.Set(0)
d.EPxControl[i].Out.Set(0)
d.EPxBufferControl[i].In.Set(0)
d.EPxBufferControl[i].Out.Set(0)
}
}

const (
// DPRAM : Endpoint control register
usbEpControlEnable = 0x80000000
usbEpControlDoubleBuffered = 0x40000000
usbEpControlInterruptPerBuff = 0x20000000
usbEpControlInterruptPerDoubleBuff = 0x10000000
usbEpControlEndpointType = 0x0c000000
usbEpControlInterruptOnStall = 0x00020000
usbEpControlInterruptOnNak = 0x00010000
usbEpControlBufferAddress = 0x0000ffff

usbEpControlEndpointTypeControl = 0x00000000
usbEpControlEndpointTypeISO = 0x04000000
usbEpControlEndpointTypeBulk = 0x08000000
usbEpControlEndpointTypeInterrupt = 0x0c000000

// Endpoint buffer control bits
usbBuf1CtrlFull = 0x80000000
usbBuf1CtrlLast = 0x40000000
usbBuf1CtrlData0Pid = 0x20000000
usbBuf1CtrlData1Pid = 0x00000000
usbBuf1CtrlSel = 0x10000000
usbBuf1CtrlStall = 0x08000000
usbBuf1CtrlAvail = 0x04000000
usbBuf1CtrlLenMask = 0x03FF0000
usbBuf0CtrlFull = 0x00008000
usbBuf0CtrlLast = 0x00004000
usbBuf0CtrlData0Pid = 0x00000000
usbBuf0CtrlData1Pid = 0x00002000
usbBuf0CtrlSel = 0x00001000
usbBuf0CtrlStall = 0x00000800
usbBuf0CtrlAvail = 0x00000400
usbBuf0CtrlLenMask = 0x000003FF

usbBufferLen = 64
)
Loading
Loading