Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions luna/gateware/usb/usb2/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ def elaborate(self, platform):

reset_sequencer.vbus_connected .eq(~self.utmi.session_end),
reset_sequencer.line_state .eq(self.utmi.line_state),

reset_sequencer.disconnect .eq(~self.connect),
]


Expand Down
36 changes: 34 additions & 2 deletions luna/gateware/usb/usb2/reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class USBResetSequencer(Elaboratable):
be held in perpetual bus reset, and reset handshaking will be disabled.
line_state: Signal(2), input
The UTMI linestate signals; used to read the current state of the USB D+ and D- lines.
disconnect: Signal(), input
If set, the device will be switched into non-driving operating mode to force a host disconnect.

bus_reset: Signal(), output
Strobe; pulses high for one cycle when a bus reset is detected. This signal indicates that the
Expand Down Expand Up @@ -123,6 +125,8 @@ def __init__(self):
self.vbus_connected = Signal()
self.line_state = Signal(2)

self.disconnect = Signal()

self.bus_reset = Signal()
self.suspended = Signal()

Expand Down Expand Up @@ -166,7 +170,7 @@ def elaborate(self, platform):
with m.If(self.current_speed == USBSpeed.HIGH):
m.d.comb += bus_idle.eq(self.line_state == self._LINE_STATE_SQUELCH)

# Full and low-speed busses see a 'J' state when idle, due to the device pull-up restistors.
# Full and low-speed busses see a 'J' state when idle, due to the device pull-up resistors.
# (The line_state values for these are flipped between speeds.) [USB2.0: 7.1.7.4.1; USB2.0: Table 7-2].
with m.Elif(self.current_speed == USBSpeed.FULL):
m.d.comb += bus_idle.eq(self.line_state == self._LINE_STATE_FS_HS_J)
Expand Down Expand Up @@ -200,7 +204,9 @@ def elaborate(self, platform):
# potential reset. Keep our timer at zero.
with m.If(self.line_state != self._LINE_STATE_SE0):
m.d.usb += timer.eq(0)

# Enter forced disconnect when self.disconnect is high.
with m.If(self.disconnect):
m.next = "DISCONNECT"

# If VBUS isn't connected, don't go through the whole reset process;
# but also consider ourselves permanently in reset. This ensures we
Expand Down Expand Up @@ -242,6 +248,9 @@ def elaborate(self, platform):
# potential reset. Keep our timer at zero.
with m.If(self.line_state != self._LINE_STATE_SE0):
m.d.usb += timer.eq(0)
# Enter forced disconnect when self.disconnect is high.
with m.If(self.disconnect):
m.next = "DISCONNECT"

# If VBUS isn't connected, our device/host relationship is effectively
# a blank state. We'll want to present our detection pull-up to the host,
Expand Down Expand Up @@ -508,4 +517,27 @@ def elaborate(self, platform):
with m.Else():
m.next = 'START_HS_DETECTION'


# DISCONNECT -- our device has entered a forced USB disconnect; hold the device in
# NON_DRIVING operating mode for Tddis=0.25us and wait for self.disconnect to go low.
with m.State('DISCONNECT'):
m.d.usb += self.operating_mode.eq(UTMIOperatingMode.NON_DRIVING)

# A disconnect condition is indicated if the host or hub is not driving the data lines and an
# SE0 persists on a downstream facing port for more than Tddis.
# [USB2.0: 7.1.7.3].
tddis = Signal()
with m.If(timer == self._CYCLES_2P5_MICROSECONDS):
m.d.usb += tddis.eq(1)

# Exit DISCONNECT once the Tddis timer has expired and self.disconnect is low.
with m.If((~self.disconnect) & tddis):
m.d.usb += [
tddis.eq(0),
self.current_speed.eq(USBSpeed.FULL),
self.operating_mode.eq(UTMIOperatingMode.NORMAL),
self.termination_select.eq(1),
]
m.next = 'INITIALIZE'

return m