litex/lib/sata/phy/ctrl.py

166 lines
3.5 KiB
Python
Raw Normal View History

from math import ceil
from lib.sata.common import *
def us(t, clk_freq):
clk_period_us = 1000000/clk_freq
return ceil(t/clk_period_us)
class SATAPHYHostCtrlTimeout(Module):
def __init__(self, load):
self.load = Signal()
self.dec = Signal()
self.reached = Signal()
cnt = Signal(max=load+1)
self.sync += \
If(self.load,
cnt.eq(load)
).Elif(self.dec & ~self.reached,
cnt.eq(cnt-1)
)
self.comb += self.reached.eq(cnt == 0)
class SATAPHYHostCtrl(Module):
def __init__(self, trx, crg, clk_freq):
self.ready = Signal()
self.need_reset = Signal()
self.sink = sink = Sink(phy_description(32))
self.source = source = Source(phy_description(32))
###
self.comb += [
source.stb.eq(1),
sink.ack.eq(1)
]
retry_timeout = SATAPHYHostCtrlTimeout(us(10000, clk_freq))
align_timeout = SATAPHYHostCtrlTimeout(us(873, clk_freq))
self.submodules += align_timeout, retry_timeout
align_detect = Signal()
non_align_cnt = Signal(4)
self.fsm = fsm = FSM(reset_state="RESET")
fsm.act("RESET",
trx.tx_idle.eq(1),
retry_timeout.load.eq(1),
align_timeout.load.eq(1),
If(crg.ready,
NextState("COMINIT")
),
)
fsm.act("COMINIT",
trx.tx_idle.eq(1),
trx.tx_cominit_stb.eq(1),
If(trx.tx_cominit_ack & ~trx.rx_cominit_stb,
NextState("AWAIT_COMINIT")
),
)
fsm.act("AWAIT_COMINIT",
trx.tx_idle.eq(1),
retry_timeout.dec.eq(1),
If(trx.rx_cominit_stb,
NextState("AWAIT_NO_COMINIT")
).Else(
If(retry_timeout.reached,
NextState("RESET")
)
),
)
fsm.act("AWAIT_NO_COMINIT",
trx.tx_idle.eq(1),
retry_timeout.load.eq(1),
If(~trx.rx_cominit_stb,
NextState("CALIBRATE")
),
)
fsm.act("CALIBRATE",
trx.tx_idle.eq(1),
NextState("COMWAKE"),
)
fsm.act("COMWAKE",
trx.tx_idle.eq(1),
trx.tx_comwake_stb.eq(1),
If(trx.tx_comwake_ack,
NextState("AWAIT_COMWAKE")
),
)
fsm.act("AWAIT_COMWAKE",
trx.tx_idle.eq(1),
retry_timeout.dec.eq(1),
If(trx.rx_comwake_stb,
NextState("AWAIT_NO_COMWAKE")
).Else(
If(retry_timeout.reached,
NextState("RESET")
)
),
)
fsm.act("AWAIT_NO_COMWAKE",
trx.tx_idle.eq(1),
If(~trx.rx_comwake_stb,
NextState("AWAIT_NO_RX_IDLE")
),
)
fsm.act("AWAIT_NO_RX_IDLE",
trx.tx_idle.eq(0),
source.data.eq(0x4A4A4A4A), #D10.2
source.charisk.eq(0b0000),
If(~trx.rx_idle,
NextState("AWAIT_ALIGN"),
crg.reset.eq(1),
trx.pmarxreset.eq(1)
),
)
fsm.act("AWAIT_ALIGN",
trx.tx_idle.eq(0),
source.data.eq(0x4A4A4A4A), #D10.2
source.charisk.eq(0b0000),
trx.rx_align.eq(1),
align_timeout.dec.eq(1),
If(align_detect & ~trx.rx_idle,
NextState("SEND_ALIGN")
).Elif(align_timeout.reached,
NextState("RESET")
),
)
fsm.act("SEND_ALIGN",
trx.tx_idle.eq(0),
trx.rx_align.eq(1),
source.data.eq(primitives["ALIGN"]),
source.charisk.eq(0b0001),
If(non_align_cnt == 3,
NextState("READY")
),
)
fsm.act("READY",
trx.tx_idle.eq(0),
trx.rx_align.eq(1),
source.data.eq(primitives["SYNC"]),
source.charisk.eq(0b0001),
If(trx.rx_idle,
NextState("RESET")
),
self.ready.eq(1),
)
self.reset_timeout = Timeout(clk_freq//16)
self.comb += [
self.reset_timeout.ce.eq(~self.ready),
self.need_reset.eq(self.reset_timeout.reached)
]
self.comb += \
align_detect.eq(self.sink.stb & (self.sink.data == primitives["ALIGN"]))
self.sync += \
If(fsm.ongoing("SEND_ALIGN"),
If(sink.stb,
If(sink.data[0:8] == 0x7C,
non_align_cnt.eq(non_align_cnt + 1)
).Else(
non_align_cnt.eq(0)
)
)
)