litex/lib/sata/k7sataphy/ctrl.py

277 lines
5.9 KiB
Python
Raw Normal View History

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 05:07:36 -04:00
# Todo:
# it's maybe better to run this module at half the frequency?
# (to have txdata/rxdata on 32 bits)
# direct control of txdata/txcharisk, need mux for user data
# rx does not use the same clock, need to resynchronize signals.
2014-09-23 18:01:01 -04:00
def us(self, t, speed="SATA3", margin=True):
clk_freq = {
"SATA3" : 300*1000000,
"SATA2" : 150*1000000,
"SATA1" : 75*1000000
}
clk_period_us = 1000000/clk_freq
if margin:
t += clk_period_us/2
return ceil(t/clk_period_us)
class K7SATAPHYHostCtrl(Module):
def __init__(self, gtx):
self.link_up = Signal()
2014-09-24 05:07:36 -04:00
self.speed = Signal(3)
2014-09-23 18:01:01 -04:00
align_timeout = Signal()
align_detect = Signal()
2014-09-24 05:07:36 -04:00
txcominit = Signal()
txcomwake = Signa()
txdata = Signal(32)
txcharisk = Signal(4)
2014-09-23 18:01:01 -04:00
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
fsm.act("RESET",
2014-09-24 05:07:36 -04:00
txcominit.eq(1),
2014-09-23 18:01:01 -04:00
gtx.txelecidle.eq(1),
2014-09-24 05:07:36 -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(
If(retry_cnt == 0,
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(
If(retry_cnt == 0,
NextState("RESET")
)
)
)
fsm.act("AWAIT_NO_COMWAKE",
gtx.txelecidle.eq(1),
If(~gtx.rxcomwakedet,
NextState("AWAIT_ALIGN")
)
)
fsm.act("AWAIT_ALIGN",
gtx.txelecidle.eq(0),
2014-09-24 05:07:36 -04:00
txdata.eq(0x4A4A4A4A), #D10.2
txcharisk.eq(0b0000),
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 05:07:36 -04:00
txdata.eq(ALIGN_VAL),
txcharisk.eq(0b0001),
2014-09-23 18:01:01 -04:00
If(non_align_cnt == 3,
NextState("READY")
)
)
fsm.act("READY",
gtx.txelecidle.eq(0),
2014-09-24 05:07:36 -04:00
txdata.eq(SYNC_VAL),
txcharisk.eq(0b0001),
2014-09-23 18:01:01 -04:00
If(gtx.rxelecidle,
NextState("RESET")
),
self.link_up.eq(1)
)
2014-09-24 05:07:36 -04:00
sel = Signal()
self.sync += sel.eq(~sel)
self.comb += [
If(sel,
gtx.txdata.eq(txdata[:16]),
gtx.txcharisk.eq(txcharisk[:2])
).Else(
gtx.txdata.eq(txdata[16:]),
gtx.txcharisk.eq(txcharisk[2:])
)
]
txcominit_d = Signal()
txcomwake_d = Signal()
2014-09-24 05:07:36 -04:00
self.sync += [
gtx.txcominit.eq(txcominit & ~txcominit_d),
gtx.txcomwake.eq(txcomwake & ~txcomwake),
]
self.comb += align_detect.eq(gtx.rxdata == ALIGN_VAL);
2014-09-24 05:07:36 -04:00
align_timeout_cnt = Signal(16)
self.sync += \
If(fsm.ongoing("RESET"),
If(speed == 0b100,
align_timeout_cnt.eq(us(873, "SATA3"))
).Elif(speed == 0b010,
align_timeout_cnt.eq(us(873, "SATA2"))
).Else(
align_timeout_cnt.eq(us(873, "SATA1"))
)
).Elif(fsm.ongoing("AWAIT_ALIGN"),
align_timeout_cnt.eq(align_timeout_cnt-1)
)
self.comb += align_timeout.eq(align_timeout_cnt == 0)
retry_cnt = Signal(16)
self.sync += \
If(fsm.ongoing("RESET") | fsm.ongoing("AWAIT_NO_COMINIT"),
If(speed == 0b100,
retry_cnt.eq(us(10000, "SATA3"))
).Elif(speed == 0b010,
retry_cnt.eq(us(10000, "SATA2"))
).Else(
retry_cnt.eq(us(10000, "SATA1"))
)
).Elif(fsm.ongoing("AWAIT_COMINIT") | fsm.ongoing("AWAIT_COMWAKE")
retry_cnt.eq(retry_cnt-1)
)
non_align_cnt = Signal(4)
self.sync += \
If(fsm.ongoing("SEND_ALIGN"),
If(gtx.rxdata[7:0] == K28_5,
non_align_cnt.eq(non_align_cnt + 1)
).Else(
non_align_cnt.eq(0)
)
)
2014-09-24 05:07:36 -04:00
2014-09-23 18:01:01 -04:00
class K7SATAPHYDeviceCtrl(Module):
def __init__(self, gtx):
self.link_up = Signal()
self.speed = Signal(3)
align_timeout = Signal()
align_detect = Signal()
txcominit = Signal()
txcomwake = Signa()
txdata = Signal(32)
txcharisk = Signal(4)
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
fsm.act("RESET",
gtx.txelecidle.eq(1),
If(gtx.rxcominitdet,
NextState("AWAIT_COMINIT")
)
)
fsm.act("COMINIT",
gtx.txelecidle.eq(1),
If(gtx.txcomfinish,
NextState("AWAIT_COMWAKE")
)
)
fsm.act("AWAIT_COMWAKE",
gtx.txelecidle.eq(1),
If(gtx.rxcomwake,
NextState("AWAIT_NO_COMWAKE")
).Else(
If(retry_cnt == 0,
NextState("RESET")
)
)
)
fsm.act("AWAIT_NO_COMWAKE",
gtx.txelecidle.eq(1),
If(~gtx.rxcomwake,
NextState("CALIBRATE")
)
)
fsm.act("CALIBRATE",
gtx.txelecidle.eq(1),
NextState("COMWAKE")
)
fsm.act("COMWAKE",
gtx.txelecidle.eq(1),
If(gtx.txcomfinish,
NextState("SEND_ALIGN")
).Elif(align_timeout,
NextState("ERROR")
)
)
fsm.act("SEND_ALIGN",
gtx.txelecidle.eq(0),
txdata.eq(ALIGN_VAL),
txcharisk.eq(0b0001),
If(align_detect,
NextState("READY")
).Elsif(align_timeout,
NextState("ERROR")
)
)
fsm.act("READY",
txdata.eq(SYNC_VAL),
txcharisk.eq(0b0001),
gtx.txelecidle.eq(0),
NextState("READY"),
If(gtx.rxelecidle,
NextState("RESET")
),
self.link_up.eq(1)
)
fsm.act("ERROR",
gtx.txelecidle.eq(1),
NextState("RESET")
)
txcominit_d = Signal()
txcomwake_d = Signal()
self.sync += [
gtx.txcominit.eq(txcominit & ~txcominit_d),
gtx.txcomwake.eq(txcomwake & ~txcomwake),
]
self.comb += align_detect.eq(gtx.rxdata == ALIGN_VAL);
align_timeout_cnt = Signal(16)
self.sync += \
If(fsm.ongoing("RESET"),
If(speed == 0b100,
align_timeout_cnt.eq(us(55, "SATA3"))
).Elif(speed == 0b010,
align_timeout_cnt.eq(us(55, "SATA2"))
).Else(
align_timeout_cnt.eq(us(55, "SATA1"))
)
).Elif(fsm.ongoing("AWAIT_ALIGN"),
align_timeout_cnt.eq(align_timeout_cnt-1)
)
self.comb += align_timeout.eq(align_timeout_cnt == 0)