merge litesata
[litex.git] / misoclib / mem / litesata / phy / ctrl.py
1 from litesata.common import *
2
3 def us(t, clk_freq):
4 clk_period_us = 1000000/clk_freq
5 return math.ceil(t/clk_period_us)
6
7 class LiteSATAPHYCtrl(Module):
8 def __init__(self, trx, crg, clk_freq):
9 self.ready = Signal()
10 self.need_reset = Signal()
11 self.sink = sink = Sink(phy_description(32))
12 self.source = source = Source(phy_description(32))
13
14 ###
15 self.comb += [
16 source.stb.eq(1),
17 sink.ack.eq(1)
18 ]
19
20 retry_timeout = Timeout(us(10000, clk_freq))
21 align_timeout = Timeout(us(873, clk_freq))
22 self.submodules += align_timeout, retry_timeout
23
24 align_detect = Signal()
25 non_align_cnt = Signal(4)
26
27 self.fsm = fsm = FSM(reset_state="RESET")
28 self.submodules += fsm
29 fsm.act("RESET",
30 trx.tx_idle.eq(1),
31 retry_timeout.reset.eq(1),
32 align_timeout.reset.eq(1),
33 If(crg.ready,
34 NextState("COMINIT")
35 ),
36 )
37 fsm.act("COMINIT",
38 trx.tx_idle.eq(1),
39 trx.tx_cominit_stb.eq(1),
40 If(trx.tx_cominit_ack & ~trx.rx_cominit_stb,
41 NextState("AWAIT_COMINIT")
42 ),
43 )
44 fsm.act("AWAIT_COMINIT",
45 trx.tx_idle.eq(1),
46 retry_timeout.ce.eq(1),
47 If(trx.rx_cominit_stb,
48 NextState("AWAIT_NO_COMINIT")
49 ).Else(
50 If(retry_timeout.reached,
51 NextState("RESET")
52 )
53 ),
54 )
55 fsm.act("AWAIT_NO_COMINIT",
56 trx.tx_idle.eq(1),
57 retry_timeout.reset.eq(1),
58 If(~trx.rx_cominit_stb,
59 NextState("CALIBRATE")
60 ),
61 )
62 fsm.act("CALIBRATE",
63 trx.tx_idle.eq(1),
64 NextState("COMWAKE"),
65 )
66 fsm.act("COMWAKE",
67 trx.tx_idle.eq(1),
68 trx.tx_comwake_stb.eq(1),
69 If(trx.tx_comwake_ack,
70 NextState("AWAIT_COMWAKE")
71 ),
72 )
73 fsm.act("AWAIT_COMWAKE",
74 trx.tx_idle.eq(1),
75 retry_timeout.ce.eq(1),
76 If(trx.rx_comwake_stb,
77 NextState("AWAIT_NO_COMWAKE")
78 ).Else(
79 If(retry_timeout.reached,
80 NextState("RESET")
81 )
82 ),
83 )
84 fsm.act("AWAIT_NO_COMWAKE",
85 trx.tx_idle.eq(1),
86 If(~trx.rx_comwake_stb,
87 NextState("AWAIT_NO_RX_IDLE")
88 ),
89 )
90 fsm.act("AWAIT_NO_RX_IDLE",
91 trx.tx_idle.eq(0),
92 source.data.eq(0x4A4A4A4A), #D10.2
93 source.charisk.eq(0b0000),
94 If(~trx.rx_idle,
95 NextState("AWAIT_ALIGN"),
96 crg.reset.eq(1),
97 trx.pmarxreset.eq(1)
98 ),
99 )
100 fsm.act("AWAIT_ALIGN",
101 trx.tx_idle.eq(0),
102 source.data.eq(0x4A4A4A4A), #D10.2
103 source.charisk.eq(0b0000),
104 trx.rx_align.eq(1),
105 align_timeout.ce.eq(1),
106 If(align_detect & ~trx.rx_idle,
107 NextState("SEND_ALIGN")
108 ).Elif(align_timeout.reached,
109 NextState("RESET")
110 ),
111 )
112 fsm.act("SEND_ALIGN",
113 trx.tx_idle.eq(0),
114 trx.rx_align.eq(1),
115 source.data.eq(primitives["ALIGN"]),
116 source.charisk.eq(0b0001),
117 If(non_align_cnt == 3,
118 NextState("READY")
119 ),
120 )
121 fsm.act("READY",
122 trx.tx_idle.eq(0),
123 trx.rx_align.eq(1),
124 source.data.eq(primitives["SYNC"]),
125 source.charisk.eq(0b0001),
126 If(trx.rx_idle,
127 NextState("RESET")
128 ),
129 self.ready.eq(1),
130 )
131
132 reset_timeout = Timeout(clk_freq//16)
133 self.submodules += reset_timeout
134 self.comb += [
135 reset_timeout.ce.eq(~self.ready),
136 self.need_reset.eq(reset_timeout.reached)
137 ]
138
139 self.comb += \
140 align_detect.eq(self.sink.stb & (self.sink.data == primitives["ALIGN"]))
141 self.sync += \
142 If(fsm.ongoing("SEND_ALIGN"),
143 If(sink.stb,
144 If(sink.data[0:8] == 0x7C,
145 non_align_cnt.eq(non_align_cnt + 1)
146 ).Else(
147 non_align_cnt.eq(0)
148 )
149 )
150 )