make ctrl/datapath in phy vendor agnostics and simplify imports
[litex.git] / lib / sata / phy / ctrl.py
1 from math import ceil
2
3 from lib.sata.common import *
4
5 def us(t, clk_freq):
6 clk_period_us = 1000000/clk_freq
7 return ceil(t/clk_period_us)
8
9 class SATAPHYHostCtrlTimeout(Module):
10 def __init__(self, load):
11 self.load = Signal()
12 self.dec = Signal()
13 self.reached = Signal()
14
15 cnt = Signal(max=load+1)
16 self.sync += \
17 If(self.load,
18 cnt.eq(load)
19 ).Elif(self.dec & ~self.reached,
20 cnt.eq(cnt-1)
21 )
22 self.comb += self.reached.eq(cnt == 0)
23
24 class SATAPHYHostCtrl(Module):
25 def __init__(self, trx, crg, clk_freq):
26 self.ready = Signal()
27 self.sink = sink = Sink(phy_description(32))
28 self.source = source = Source(phy_description(32))
29
30 ###
31 self.comb += [
32 source.stb.eq(1),
33 sink.ack.eq(1)
34 ]
35
36 retry_timeout = SATAPHYHostCtrlTimeout(us(10000, clk_freq))
37 align_timeout = SATAPHYHostCtrlTimeout(us(873, clk_freq))
38 self.submodules += align_timeout, retry_timeout
39
40 align_detect = Signal()
41 non_align_cnt = Signal(4)
42
43 fsm = FSM(reset_state="RESET")
44 self.submodules += fsm
45
46 fsm.act("RESET",
47 trx.tx_idle.eq(1),
48 retry_timeout.load.eq(1),
49 align_timeout.load.eq(1),
50 If(crg.ready,
51 NextState("COMINIT")
52 ),
53 )
54 fsm.act("COMINIT",
55 trx.tx_idle.eq(1),
56 trx.tx_cominit_stb.eq(1),
57 If(trx.tx_cominit_ack & ~trx.rx_cominit_stb,
58 NextState("AWAIT_COMINIT")
59 ),
60 )
61 fsm.act("AWAIT_COMINIT",
62 trx.tx_idle.eq(1),
63 retry_timeout.dec.eq(1),
64 If(trx.rx_cominit_stb,
65 NextState("AWAIT_NO_COMINIT")
66 ).Else(
67 If(retry_timeout.reached,
68 NextState("RESET")
69 )
70 ),
71 )
72 fsm.act("AWAIT_NO_COMINIT",
73 trx.tx_idle.eq(1),
74 retry_timeout.load.eq(1),
75 If(~trx.rx_cominit_stb,
76 NextState("CALIBRATE")
77 ),
78 )
79 fsm.act("CALIBRATE",
80 trx.tx_idle.eq(1),
81 NextState("COMWAKE"),
82 )
83 fsm.act("COMWAKE",
84 trx.tx_idle.eq(1),
85 trx.tx_comwake_stb.eq(1),
86 If(trx.tx_comwake_ack,
87 NextState("AWAIT_COMWAKE")
88 ),
89 )
90 fsm.act("AWAIT_COMWAKE",
91 trx.tx_idle.eq(1),
92 retry_timeout.dec.eq(1),
93 If(trx.rx_comwake_stb,
94 NextState("AWAIT_NO_COMWAKE")
95 ).Else(
96 If(retry_timeout.reached,
97 NextState("RESET")
98 )
99 ),
100 )
101 fsm.act("AWAIT_NO_COMWAKE",
102 trx.tx_idle.eq(1),
103 If(~trx.rx_comwake_stb,
104 NextState("AWAIT_NO_RX_IDLE")
105 ),
106 )
107 fsm.act("AWAIT_NO_RX_IDLE",
108 trx.tx_idle.eq(0),
109 source.data.eq(0x4A4A4A4A), #D10.2
110 source.charisk.eq(0b0000),
111 If(~trx.rx_idle,
112 NextState("AWAIT_ALIGN"),
113 crg.reset.eq(1),
114 trx.pmarxreset.eq(1)
115 ),
116 )
117 fsm.act("AWAIT_ALIGN",
118 trx.tx_idle.eq(0),
119 source.data.eq(0x4A4A4A4A), #D10.2
120 source.charisk.eq(0b0000),
121 trx.rx_align.eq(1),
122 align_timeout.dec.eq(1),
123 If(align_detect & ~trx.rx_idle,
124 NextState("SEND_ALIGN")
125 ).Elif(align_timeout.reached,
126 NextState("RESET")
127 ),
128 )
129 fsm.act("SEND_ALIGN",
130 trx.tx_idle.eq(0),
131 trx.rx_align.eq(1),
132 source.data.eq(primitives["ALIGN"]),
133 source.charisk.eq(0b0001),
134 If(non_align_cnt == 3,
135 NextState("READY")
136 ),
137 )
138 fsm.act("READY",
139 trx.tx_idle.eq(0),
140 trx.rx_align.eq(1),
141 source.data.eq(primitives["SYNC"]),
142 source.charisk.eq(0b0001),
143 If(trx.rx_idle,
144 NextState("RESET")
145 ),
146 self.ready.eq(1),
147 )
148
149 self.comb += \
150 align_detect.eq(self.sink.stb & (self.sink.data == primitives["ALIGN"]))
151 self.sync += \
152 If(fsm.ongoing("SEND_ALIGN"),
153 If(sink.stb,
154 If(sink.data[0:8] == 0x7C,
155 non_align_cnt.eq(non_align_cnt + 1)
156 ).Else(
157 non_align_cnt.eq(0)
158 )
159 )
160 )
161
162 class SATAPHYDeviceCtrl(Module):
163 def __init__(self, trx, crg, clk_freq):
164 self.ready = Signal()
165
166 sink = Sink(phy_description(32))
167 source = Source(phy_description(32))
168
169 ###
170
171 self.comb += [
172 source.stb.eq(1),
173 sink.ack.eq(1)
174 ]
175
176 retry_timeout = SATAPHYHostCtrlTimeout(us(10000, clk_freq))
177 align_timeout = SATAPHYHostCtrlTimeout(us(873, clk_freq))
178 self.submodules += align_timeout, retry_timeout
179
180 fsm = FSM(reset_state="RESET")
181 self.submodules += fsm
182
183 fsm.act("RESET",
184 trx.tx_idle.eq(1),
185 retry_timeout.load.eq(1),
186 align_timeout.load.eq(1),
187 If(crg.ready,
188 NextState("AWAIT_COMINIT")
189 )
190 )
191 fsm.act("AWAIT_COMINIT",
192 trx.tx_idle.eq(1),
193 If(trx.rx_cominit_stb,
194 NextState("AWAIT_NO_COMINIT")
195 )
196 )
197 fsm.act("AWAIT_NO_COMINIT",
198 trx.tx_idle.eq(1),
199 If(~trx.rx_cominit_stb,
200 NextState("COMINIT")
201 )
202 )
203 fsm.act("COMINIT",
204 trx.tx_idle.eq(1),
205 trx.tx_cominit_stb.eq(1),
206 If(trx.tx_cominit_ack,
207 NextState("AWAIT_COMWAKE")
208 )
209 )
210 fsm.act("AWAIT_COMWAKE",
211 trx.tx_idle.eq(1),
212 retry_timeout.dec.eq(1),
213 If(trx.rx_comwake_stb,
214 NextState("AWAIT_NO_COMWAKE")
215 ).Else(
216 If(retry_timeout.reached,
217 NextState("RESET")
218 )
219 )
220 )
221 fsm.act("AWAIT_NO_COMWAKE",
222 trx.tx_idle.eq(1),
223 If(~trx.rx_comwake_stb,
224 NextState("CALIBRATE")
225 )
226 )
227 fsm.act("CALIBRATE",
228 trx.tx_idle.eq(1),
229 NextState("COMWAKE")
230 )
231 fsm.act("COMWAKE",
232 trx.tx_idle.eq(1),
233 trx.tx_comwake_stb.eq(1),
234 If(trx.tx_comwake_stb,
235 NextState("RESET_CRG"),
236 crg.reset.eq(1),
237 )
238 )
239 fsm.act("RESET_CRG",
240 trx.tx_idle.eq(0),
241 If(crg.ready,
242 NextState("SEND_ALIGN")
243 )
244 )
245 fsm.act("SEND_ALIGN",
246 trx.tx_idle.eq(0),
247 trx.rx_align.eq(1),
248 source.data.eq(primitives["ALIGN"]),
249 source.charisk.eq(0b0001),
250 align_timeout.dec.eq(1),
251 If(align_detect,
252 NextState("READY")
253 ).Elif(align_timeout.reached,
254 NextState("ERROR")
255 )
256 )
257 fsm.act("READY",
258 trx.tx_idle.eq(0),
259 NextState("READY"),
260 If(trx.rx_idle,
261 NextState("RESET")
262 ),
263 self.ready.eq(1)
264 )
265 fsm.act("ERROR",
266 trx.tx_idle.eq(1),
267 NextState("RESET")
268 )
269
270 self.comb += \
271 align_detect.eq(sink.stb & (sink.data == primitives["ALIGN"]))