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