2014-09-24 08:28:52 -04:00
|
|
|
from math import ceil
|
|
|
|
|
2014-09-23 18:01:01 -04:00
|
|
|
from migen.fhdl.std import *
|
|
|
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
|
|
|
from migen.genlib.fsm import FSM, NextState
|
|
|
|
|
2014-09-24 08:28:52 -04:00
|
|
|
from lib.sata.k7sataphy.std import *
|
|
|
|
|
2014-09-27 11:26:52 -04:00
|
|
|
def us(t, clk_freq):
|
|
|
|
clk_period_us = 1000000/clk_freq
|
2014-09-23 18:01:01 -04:00
|
|
|
return ceil(t/clk_period_us)
|
|
|
|
|
|
|
|
class K7SATAPHYHostCtrl(Module):
|
2014-09-29 07:02:11 -04:00
|
|
|
def __init__(self, gtx, crg, clk_freq):
|
2014-09-27 10:10:39 -04:00
|
|
|
self.ready = Signal()
|
2014-09-23 18:01:01 -04:00
|
|
|
|
2014-09-24 07:56:32 -04:00
|
|
|
self.txdata = Signal(32)
|
|
|
|
self.txcharisk = Signal(4)
|
|
|
|
|
|
|
|
self.rxdata = Signal(32)
|
|
|
|
|
2014-09-23 18:01:01 -04:00
|
|
|
align_detect = Signal()
|
2014-09-29 12:25:24 -04:00
|
|
|
align_timeout_cnt = Signal(32)
|
|
|
|
align_timeout = Signal()
|
|
|
|
|
|
|
|
retry_timeout_cnt = Signal(32)
|
|
|
|
retry_timeout = Signal()
|
|
|
|
|
2014-09-24 08:28:52 -04:00
|
|
|
non_align_cnt = Signal(4)
|
2014-09-23 18:01:01 -04:00
|
|
|
|
2014-09-24 05:07:36 -04:00
|
|
|
txcominit = Signal()
|
2014-09-24 08:28:52 -04:00
|
|
|
txcomwake = Signal()
|
2014-09-24 05:07:36 -04:00
|
|
|
|
2014-09-24 08:28:52 -04:00
|
|
|
fsm = FSM(reset_state="RESET")
|
2014-09-23 18:01:01 -04:00
|
|
|
self.submodules += fsm
|
|
|
|
|
|
|
|
fsm.act("RESET",
|
2014-09-27 10:10:39 -04:00
|
|
|
gtx.txelecidle.eq(1),
|
2014-09-29 07:02:11 -04:00
|
|
|
If(crg.ready,
|
2014-09-27 10:10:39 -04:00
|
|
|
NextState("COMINIT")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("COMINIT",
|
2014-09-23 18:01:01 -04:00
|
|
|
gtx.txelecidle.eq(1),
|
2014-09-27 11:26:52 -04:00
|
|
|
txcominit.eq(1),
|
2014-09-24 08:28:52 -04:00
|
|
|
If(gtx.txcomfinish & ~gtx.rxcominitdet,
|
2014-09-23 18:01:01 -04:00
|
|
|
NextState("AWAIT_COMINIT")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("AWAIT_COMINIT",
|
|
|
|
gtx.txelecidle.eq(1),
|
|
|
|
If(gtx.rxcominitdet,
|
|
|
|
NextState("AWAIT_NO_COMINIT")
|
|
|
|
).Else(
|
2014-09-29 12:25:24 -04:00
|
|
|
If(retry_timeout,
|
2014-09-23 18:01:01 -04:00
|
|
|
NextState("RESET")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("AWAIT_NO_COMINIT",
|
|
|
|
gtx.txelecidle.eq(1),
|
|
|
|
If(~gtx.rxcominitdet,
|
|
|
|
NextState("CALIBRATE")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("CALIBRATE",
|
|
|
|
gtx.txelecidle.eq(1),
|
|
|
|
NextState("COMWAKE")
|
|
|
|
)
|
|
|
|
fsm.act("COMWAKE",
|
|
|
|
gtx.txelecidle.eq(1),
|
2014-09-24 05:07:36 -04:00
|
|
|
txcomwake.eq(1),
|
|
|
|
If(gtx.txcomfinish,
|
2014-09-23 18:01:01 -04:00
|
|
|
NextState("AWAIT_COMWAKE")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("AWAIT_COMWAKE",
|
|
|
|
gtx.txelecidle.eq(1),
|
|
|
|
If(gtx.rxcomwakedet,
|
|
|
|
NextState("AWAIT_NO_COMWAKE")
|
|
|
|
).Else(
|
2014-09-29 12:25:24 -04:00
|
|
|
If(retry_timeout,
|
2014-09-23 18:01:01 -04:00
|
|
|
NextState("RESET")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("AWAIT_NO_COMWAKE",
|
|
|
|
gtx.txelecidle.eq(1),
|
|
|
|
If(~gtx.rxcomwakedet,
|
2014-09-29 11:12:02 -04:00
|
|
|
NextState("RESET_CRG")
|
2014-09-23 18:01:01 -04:00
|
|
|
)
|
|
|
|
)
|
2014-09-29 11:12:02 -04:00
|
|
|
fsm.act("RESET_CRG",
|
|
|
|
gtx.txelecidle.eq(0),
|
|
|
|
crg.reset.eq(1),
|
|
|
|
NextState("AWAIT_ALIGN")
|
|
|
|
)
|
2014-09-23 18:01:01 -04:00
|
|
|
fsm.act("AWAIT_ALIGN",
|
|
|
|
gtx.txelecidle.eq(0),
|
2014-09-29 12:25:24 -04:00
|
|
|
self.txdata.eq(0x4A4A4A4A), #D10.2
|
|
|
|
self.txcharisk.eq(0b0000),
|
2014-09-29 07:02:11 -04:00
|
|
|
gtx.rxalign.eq(1),
|
2014-09-23 18:01:01 -04:00
|
|
|
If(align_detect & ~align_timeout,
|
|
|
|
NextState("SEND_ALIGN")
|
|
|
|
).Elif(~align_detect & align_timeout,
|
|
|
|
NextState("RESET")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("SEND_ALIGN",
|
|
|
|
gtx.txelecidle.eq(0),
|
2014-09-24 07:56:32 -04:00
|
|
|
self.txdata.eq(ALIGN_VAL),
|
|
|
|
self.txcharisk.eq(0b0001),
|
2014-09-29 12:25:24 -04:00
|
|
|
If(non_align_cnt == 3,
|
2014-09-23 18:01:01 -04:00
|
|
|
NextState("READY")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("READY",
|
|
|
|
gtx.txelecidle.eq(0),
|
|
|
|
If(gtx.rxelecidle,
|
|
|
|
NextState("RESET")
|
|
|
|
),
|
2014-09-27 10:10:39 -04:00
|
|
|
self.ready.eq(1)
|
2014-09-23 18:01:01 -04:00
|
|
|
)
|
|
|
|
|
2014-09-24 05:07:36 -04:00
|
|
|
txcominit_d = Signal()
|
2014-09-24 05:37:28 -04:00
|
|
|
txcomwake_d = Signal()
|
2014-09-27 09:34:28 -04:00
|
|
|
self.sync += [
|
2014-09-25 08:52:16 -04:00
|
|
|
txcominit_d.eq(txcominit),
|
|
|
|
txcomwake_d.eq(txcomwake),
|
2014-09-24 05:07:36 -04:00
|
|
|
gtx.txcominit.eq(txcominit & ~txcominit_d),
|
2014-09-25 08:52:16 -04:00
|
|
|
gtx.txcomwake.eq(txcomwake & ~txcomwake_d),
|
2014-09-24 05:07:36 -04:00
|
|
|
]
|
|
|
|
|
2014-09-29 12:25:24 -04:00
|
|
|
self.comb += align_detect.eq(self.rxdata == ALIGN_VAL);
|
2014-09-27 09:34:28 -04:00
|
|
|
self.sync += \
|
2014-09-24 05:07:36 -04:00
|
|
|
If(fsm.ongoing("RESET"),
|
2014-09-27 11:26:52 -04:00
|
|
|
align_timeout_cnt.eq(us(873, clk_freq))
|
2014-09-24 05:07:36 -04:00
|
|
|
).Elif(fsm.ongoing("AWAIT_ALIGN"),
|
|
|
|
align_timeout_cnt.eq(align_timeout_cnt-1)
|
|
|
|
)
|
|
|
|
self.comb += align_timeout.eq(align_timeout_cnt == 0)
|
|
|
|
|
2014-09-27 09:34:28 -04:00
|
|
|
self.sync += \
|
2014-09-24 05:07:36 -04:00
|
|
|
If(fsm.ongoing("RESET") | fsm.ongoing("AWAIT_NO_COMINIT"),
|
2014-09-29 12:25:24 -04:00
|
|
|
retry_timeout_cnt.eq(us(10000, clk_freq))
|
2014-09-24 08:28:52 -04:00
|
|
|
).Elif(fsm.ongoing("AWAIT_COMINIT") | fsm.ongoing("AWAIT_COMWAKE"),
|
2014-09-29 12:25:24 -04:00
|
|
|
retry_timeout_cnt.eq(retry_timeout_cnt-1)
|
2014-09-24 05:07:36 -04:00
|
|
|
)
|
2014-09-29 12:25:24 -04:00
|
|
|
self.comb += retry_timeout.eq(retry_timeout_cnt == 0)
|
2014-09-24 05:07:36 -04:00
|
|
|
|
2014-09-27 09:34:28 -04:00
|
|
|
self.sync += \
|
2014-09-24 05:07:36 -04:00
|
|
|
If(fsm.ongoing("SEND_ALIGN"),
|
2014-09-29 07:02:11 -04:00
|
|
|
If(self.rxdata[0:8] == 0xBC,
|
2014-09-24 05:07:36 -04:00
|
|
|
non_align_cnt.eq(non_align_cnt + 1)
|
|
|
|
).Else(
|
|
|
|
non_align_cnt.eq(0)
|
|
|
|
)
|
2014-09-24 05:37:28 -04:00
|
|
|
)
|
2014-09-24 05:07:36 -04:00
|
|
|
|
2014-09-23 18:01:01 -04:00
|
|
|
class K7SATAPHYDeviceCtrl(Module):
|
2014-09-29 07:02:11 -04:00
|
|
|
def __init__(self, gtx, crg, clk_freq):
|
2014-09-27 10:10:39 -04:00
|
|
|
self.ready = Signal()
|
2014-09-24 05:37:28 -04:00
|
|
|
|
2014-09-24 07:56:32 -04:00
|
|
|
self.txdata = Signal(32)
|
|
|
|
self.txcharisk = Signal(4)
|
|
|
|
|
|
|
|
self.rxdata = Signal(32)
|
|
|
|
|
2014-09-24 05:37:28 -04:00
|
|
|
align_detect = Signal()
|
2014-09-29 12:25:24 -04:00
|
|
|
align_timeout = Signal()
|
|
|
|
align_timeout_cnt = Signal(32)
|
|
|
|
|
|
|
|
retry_timeout_cnt = Signal(32)
|
|
|
|
retry_timeout = Signal()
|
2014-09-24 05:37:28 -04:00
|
|
|
|
|
|
|
txcominit = Signal()
|
2014-09-24 08:28:52 -04:00
|
|
|
txcomwake = Signal()
|
2014-09-24 05:37:28 -04:00
|
|
|
|
2014-09-24 08:28:52 -04:00
|
|
|
fsm = FSM(reset_state="RESET")
|
2014-09-24 05:37:28 -04:00
|
|
|
self.submodules += fsm
|
|
|
|
|
|
|
|
fsm.act("RESET",
|
2014-09-27 10:10:39 -04:00
|
|
|
gtx.txelecidle.eq(1),
|
2014-09-29 07:02:11 -04:00
|
|
|
If(crg.ready,
|
2014-09-27 10:10:39 -04:00
|
|
|
NextState("AWAIT_COMINIT")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("AWAIT_COMINIT",
|
2014-09-24 05:37:28 -04:00
|
|
|
gtx.txelecidle.eq(1),
|
|
|
|
If(gtx.rxcominitdet,
|
2014-09-24 08:28:52 -04:00
|
|
|
NextState("COMINIT")
|
2014-09-24 05:37:28 -04:00
|
|
|
)
|
2014-09-27 10:10:39 -04:00
|
|
|
)
|
2014-09-24 05:37:28 -04:00
|
|
|
fsm.act("COMINIT",
|
|
|
|
gtx.txelecidle.eq(1),
|
2014-09-27 11:26:52 -04:00
|
|
|
txcominit.eq(1),
|
2014-09-24 05:37:28 -04:00
|
|
|
If(gtx.txcomfinish,
|
|
|
|
NextState("AWAIT_COMWAKE")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("AWAIT_COMWAKE",
|
|
|
|
gtx.txelecidle.eq(1),
|
2014-09-24 08:28:52 -04:00
|
|
|
If(gtx.rxcomwakedet,
|
2014-09-24 05:37:28 -04:00
|
|
|
NextState("AWAIT_NO_COMWAKE")
|
|
|
|
).Else(
|
2014-09-29 12:25:24 -04:00
|
|
|
If(retry_timeout,
|
2014-09-24 05:37:28 -04:00
|
|
|
NextState("RESET")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("AWAIT_NO_COMWAKE",
|
|
|
|
gtx.txelecidle.eq(1),
|
2014-09-24 08:28:52 -04:00
|
|
|
If(~gtx.rxcomwakedet,
|
2014-09-24 05:37:28 -04:00
|
|
|
NextState("CALIBRATE")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("CALIBRATE",
|
|
|
|
gtx.txelecidle.eq(1),
|
|
|
|
NextState("COMWAKE")
|
|
|
|
)
|
|
|
|
fsm.act("COMWAKE",
|
|
|
|
gtx.txelecidle.eq(1),
|
2014-09-24 08:28:52 -04:00
|
|
|
gtx.txcomwake.eq(1),
|
2014-09-24 05:37:28 -04:00
|
|
|
If(gtx.txcomfinish,
|
2014-09-29 11:12:02 -04:00
|
|
|
NextState("RESET_CRG")
|
2014-09-24 05:37:28 -04:00
|
|
|
)
|
|
|
|
)
|
2014-09-29 11:12:02 -04:00
|
|
|
fsm.act("RESET_CRG",
|
|
|
|
gtx.txelecidle.eq(0),
|
|
|
|
crg.reset.eq(1),
|
|
|
|
NextState("SEND_ALIGN")
|
|
|
|
)
|
2014-09-24 05:37:28 -04:00
|
|
|
fsm.act("SEND_ALIGN",
|
|
|
|
gtx.txelecidle.eq(0),
|
2014-09-29 07:02:11 -04:00
|
|
|
gtx.rxalign.eq(1),
|
2014-09-24 07:56:32 -04:00
|
|
|
self.txdata.eq(ALIGN_VAL),
|
|
|
|
self.txcharisk.eq(0b0001),
|
2014-09-24 05:37:28 -04:00
|
|
|
If(align_detect,
|
|
|
|
NextState("READY")
|
2014-09-24 08:28:52 -04:00
|
|
|
).Elif(align_timeout,
|
2014-09-24 05:37:28 -04:00
|
|
|
NextState("ERROR")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("READY",
|
|
|
|
gtx.txelecidle.eq(0),
|
|
|
|
NextState("READY"),
|
|
|
|
If(gtx.rxelecidle,
|
|
|
|
NextState("RESET")
|
|
|
|
),
|
2014-09-27 10:10:39 -04:00
|
|
|
self.ready.eq(1)
|
2014-09-24 05:37:28 -04:00
|
|
|
)
|
|
|
|
fsm.act("ERROR",
|
|
|
|
gtx.txelecidle.eq(1),
|
|
|
|
NextState("RESET")
|
|
|
|
)
|
|
|
|
|
|
|
|
txcominit_d = Signal()
|
|
|
|
txcomwake_d = Signal()
|
2014-09-27 09:34:28 -04:00
|
|
|
self.sync += [
|
2014-09-25 08:52:16 -04:00
|
|
|
txcominit_d.eq(txcominit),
|
|
|
|
txcomwake_d.eq(txcomwake),
|
2014-09-24 05:37:28 -04:00
|
|
|
gtx.txcominit.eq(txcominit & ~txcominit_d),
|
|
|
|
gtx.txcomwake.eq(txcomwake & ~txcomwake),
|
|
|
|
]
|
|
|
|
|
2014-09-29 12:25:24 -04:00
|
|
|
self.comb += align_detect.eq(self.rxdata == ALIGN_VAL);
|
2014-09-27 09:34:28 -04:00
|
|
|
self.sync += \
|
2014-09-24 05:37:28 -04:00
|
|
|
If(fsm.ongoing("RESET"),
|
2014-09-27 11:26:52 -04:00
|
|
|
align_timeout_cnt.eq(us(55, clk_freq))
|
2014-09-24 05:37:28 -04:00
|
|
|
).Elif(fsm.ongoing("AWAIT_ALIGN"),
|
|
|
|
align_timeout_cnt.eq(align_timeout_cnt-1)
|
|
|
|
)
|
2014-09-24 08:28:52 -04:00
|
|
|
self.comb += align_timeout.eq(align_timeout_cnt == 0)
|
2014-09-27 11:26:52 -04:00
|
|
|
|
|
|
|
self.sync += \
|
|
|
|
If(fsm.ongoing("RESET"),
|
2014-09-29 12:25:24 -04:00
|
|
|
retry_timeout_cnt.eq(us(10000, clk_freq))
|
2014-09-27 11:26:52 -04:00
|
|
|
).Elif(fsm.ongoing("AWAIT_COMWAKE"),
|
2014-09-29 12:25:24 -04:00
|
|
|
retry_timeout_cnt.eq(retry_timeout_cnt-1)
|
2014-09-27 11:26:52 -04:00
|
|
|
)
|
2014-09-29 12:25:24 -04:00
|
|
|
self.comb += retry_timeout.eq(retry_timeout_cnt == 0)
|